将数据提供给训练算法

我们尝试修改以前的代码来实现小批量梯度下降(Mini-batch Gradient Descent)。 为此,我们需要一种在每次迭代时用下一个小批量替换XY的方法。 最简单的方法是使用占位符(placeholder)节点。 这些节点是特别的,因为它们实际上并不执行任何计算,只是输出您在运行时输出的数据。 它们通常用于在训练期间将训练数据传递给 TensorFlow。 如果在运行时没有为占位符指定值,则会收到异常。

要创建占位符节点,您必须调用placeholder()函数并指定输出张量的数据类型。 或者,您还可以指定其形状,如果要强制执行。 如果指定维度为None,则表示“任何大小”。例如,以下代码创建一个占位符节点A,还有一个节点B = A + 5。当我们求出B时,我们将一个feed_dict传递给eval()方法并指定A的值。注意,A必须具有 2 级(即它必须是二维的),并且必须有三列(否则引发异常),但它可以有任意数量的行。

  1. >>> A = tf.placeholder(tf.float32, shape=(None, 3))
  2. >>> B = A + 5
  3. >>> with tf.Session() as sess:
  4. ... B_val_1 = B.eval(feed_dict={A: [[1, 2, 3]]})
  5. ... B_val_2 = B.eval(feed_dict={A: [[4, 5, 6], [7, 8, 9]]})
  6. ...
  7. >>> print(B_val_1)
  8. [[ 6. 7. 8.]]
  9. >>> print(B_val_2)
  10. [[ 9. 10. 11.]
  11. [ 12. 13. 14.]]

您实际上可以提供任何操作的输出,而不仅仅是占位符。 在这种情况下,TensorFlow 不会尝试求出这些操作;它使用您提供的值。

要实现小批量渐变下降,我们只需稍微调整现有的代码。 首先更改XY的定义,使其定义为占位符节点:

  1. X = tf.placeholder(tf.float32, shape=(None, n + 1), name="X")
  2. y = tf.placeholder(tf.float32, shape=(None, 1), name="y")

然后定义批量大小并计算总批次数:

  1. batch_size = 100
  2. n_batches = int(np.ceil(m / batch_size))

最后,在执行阶段,逐个获取小批量,然后在求出依赖于Xy的值的任何一个节点时,通过feed_dict提供Xy的值。

  1. def fetch_batch(epoch, batch_index, batch_size):
  2. [...] # load the data from disk
  3. return X_batch, y_batch
  4. with tf.Session() as sess:
  5. sess.run(init)
  6. for epoch in range(n_epochs):
  7. for batch_index in range(n_batches):
  8. X_batch, y_batch = fetch_batch(epoch, batch_index, batch_size)
  9. sess.run(training_op, feed_dict={X: X_batch, y: y_batch})
  10. best_theta = theta.eval()

在求出theta时,我们不需要传递X和y的值,因为它不依赖于它们。