TensorFlow训练

27

假设我有一个非常简单的神经网络,比如多层感知器。每个层的激活函数都是sigmoid,网络是全连接的。

在TensorFlow中,这可能会被定义为:

    sess = tf.InteractiveSession()

    # Training Tensor
    x = tf.placeholder(tf.float32, shape = [None, n_fft])
    # Label Tensor
    y_ = tf.placeholder(tf.float32, shape = [None, n_fft])

    # Declaring variable buffer for weights W and bias b
    # Layer structure [n_fft, n_fft, n_fft, n_fft]
    # Input -> Layer 1
    struct_w = [n_fft, n_fft]
    struct_b = [n_fft]
    W1 = weight_variable(struct_w, 'W1')
    b1 = bias_variable(struct_b, 'b1')
    h1 = tf.nn.sigmoid(tf.matmul(x, W1) + b1)

    # Layer1 -> Layer 2
    W2 = weight_variable(struct_w, 'W2')
    b2 = bias_variable(struct_b, 'b2')
    h2 = tf.nn.sigmoid(tf.matmul(h1, W2) + b2)

    # Layer2 -> output
    W3 = weight_variable(struct_w, 'W3')
    b3 = bias_variable(struct_b, 'b3')
    y = tf.nn.sigmoid(tf.matmul(h2, W3) + b3)

    # Calculating difference between label and output using mean square error
    mse = tf.reduce_mean(tf.square(y - y_))

    # Train the Model
    # Gradient Descent
    train_step = tf.train.GradientDescentOptimizer(0.3).minimize(mse)
这个模型的设计目标是将一个包含n_fft个点的fft频谱图映射到另一个n_fft目标频谱图。假设训练数据和目标数据都是[3000,n_fft]大小的。它们存储在变量spec_trainspec_target中。

现在问题来了,对于TensorFlow,这两种训练方式有什么区别吗?

训练1:

for i in xrange(200):
        train_step.run(feed_dict = {x: spec_train, y_: spec_target})

第二阶段训练:

for i in xrange(200):
        for j in xrange(3000):
            train = spec_train[j, :].reshape(1, n_fft)
            label = spec_target[j, :].reshape(1, n_fft)
            train_step.run(feed_dict = {x: train, y_: label})

非常感谢!

2个回答

36
在第一个训练版本中,您一次训练整个训练数据批次,这意味着spec_train的第一和第3000个元素将在同一步骤中使用相同的模型参数进行处理。这被称为(批量)梯度下降。
在第二个训练版本中,您一次从训练数据中训练一个示例,这意味着自从最近处理第一个元素以来,已经更新了2999次模型参数,因此将使用这些参数处理spec_train的第3000个元素。如果选择的元素是随机的,则称之为随机梯度下降。
通常,TensorFlow用于太大而无法一次处理的数据集,因此喜欢使用小批量随机梯度下降(在一步中处理其中的一部分示例)。理论上,每次处理单个元素都是理想的,但它本质上是顺序的,并且具有高固定成本,因为矩阵乘法和其他操作不是计算密集型的。因此,通常方法是同时处理一小批(例如32或128)示例,多个副本并行训练不同的批次。
有关何时使用一种方法而不是另一种方法的更多理论讨论,请参见此统计StackExchange问题

这是我从你的帖子中得到的信息。在版本1中,只有当程序将整个数据批次馈送到模型中时,权重和偏差才会被更新。这意味着3000个数据点将产生一个大的权重调整。而对于版本2,就像我使用那些3000个数据点来更新权重3000次,进行3000个小的权重调整。这正确吗?谢谢。 - yc2986
1
是的,如果您进行3000个单独的更新,后续更新将使用更加最新的参数版本,这往往会改善收敛性(每个训练数据点)。 - mrry
通过逐个元素处理,您可以更频繁地更新权重,因此后续计算可以利用更“进化”的网络权重,从而可能导致更好的收敛(更高的准确性)。然而,单元素处理会导致GPU计算的低占用率,从而导致计算吞吐量差,因此训练时间更长。相比之下,更大的批次有利于快速训练,但缺点是收敛较差(准确性较低)。 - Robert Wang
1
嗨,我想知道更新是如何详细进行的。如果我批量运行训练数据,它们是否按顺序逐个计算,然后计算梯度并处理更新?还是在并行处理中,批处理中的数据同时在多个线程中处理,直到可以计算梯度(并同步更新)?如果我在每个训练数据之后更新模型,我假设这是同步完成的? - LaLa
@Robert 我认为你犯了一个错误。当你尝试更新参数时,逐个元素进行操作会导致更多的波动下降。但是如果网络在一次迭代中处理所有示例并像第一种情况一样取平均损失,则您的情况是正确的。 - Shamane Siriwardhana
显示剩余4条评论

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接