Keras中的批量归一化

4

如何在keras BatchNormalization中更新移动均值和移动方差?

我在tensorflow文档中找到了这个,但我不知道在哪里放置train_op或如何与keras模型一起使用:

update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
        with tf.control_dependencies(update_ops):
            train_op = optimizer.minimize( loss )

我没有找到任何帖子说明如何处理 train_op 以及是否可以在 model.compile 中使用它。


你想做什么?通常情况下,在Keras中使用BatchNormalization时,你不需要做任何事情。 - Dr. Snoopy
我只是想使用BatchNormalization。让我困惑的是Tensorflow和Keras之间的差异,所以我不确定除了确保在验证期间关闭BatchNormalization之外是否真的不需要做任何其他事情,或者是否必须手动更新移动平均值和方差。 - A. Hendry
optimizer.minimize(loss) 看来,他似乎正在尝试手动执行梯度下降步骤(而不是使用更高级别的 API 来驱动拟合)。optimizer.minimize()(例如使用 'AdamOptimizer' 或 'GradientDescentOptimizer')将使用梯度下降来更新常规权重一步,但它不会对批量归一化的均值和方差做任何事情。 - Joshua Chia
对我而言,如果我使用batch_normed = tf.keras.layers.BatchNormalization()(hidden, training=True),那么update_ops是空的。因此似乎没有移动平均值(例如batch_normalization/moving_mean)的更新发生。 - Ivan
3个回答

1
如果您使用BatchNormalization层,则无需手动更新移动平均值和方差。Keras会在训练期间负责更新这些参数,并通过使用model.predict和model.evaluate函数(与model.fit_generator等一样)在测试期间保持它们固定。Keras还跟踪学习阶段,因此在训练和验证/测试期间运行不同的代码路径。

如果您正在使用model.fit_generator进行训练和验证集,会发生什么? - A. Hendry
一样,我只是忘了提到它。 - Dr. Snoopy
2
@MatiasValdenegro 我怀疑这样做行不通。在我的训练循环中,我打印出变量 batch_normalization/moving_mean 的前两个元素,同时也使用了 optimizer.minimize(loss),但它们从未改变过。我正在使用 tensorflow.train.AdamOptimizer 并手动运行 optimizer.minimize(loss) 来反向传播权重更新。我怀疑更高级别的 API(例如 tensorflow.keras.models.Model.fit())除了反向传播之外还做了一些更新批量归一化统计数据的操作,而仅使用 optimizer.minimize(loss) 是缺少这种“某些操作”的。 - Joshua Chia
@Syncopated,我不知道你在说什么,我的回答是关于使用Keras的,似乎你没有使用纯Keras。 - Dr. Snoopy
@MatiasValdenegro 看到这个问题标记了“tensorflow”和“keras”,我在谈论在tensorflow中使用keras,但是看到作者似乎已经接受了答案,也许他并不是真的在谈论tensorflow。 - Joshua Chia
@Syncopated 作者在询问您是否需要在使用Keras时执行tensorflow风格的BN参数更新,我只是指出这并不必要。 - Dr. Snoopy

0
如果您只需要使用一些新值更新现有模型的权重,则可以执行以下操作:
w = model.get_layer('batchnorm_layer_name').get_weights()
# Order: [gamma, beta, mean, std]
for j in range(len(w[0])):
    gamma = w[0][j]
    beta = w[1][j]
    run_mean = w[2][j]
    run_std = w[3][j]
    w[2][j] = new_run_mean_value1
    w[3][j] = new_run_std_value2

model.get_layer('batchnorm_layer_name').set_weights(w)

0

这个问题有两种解释:第一种是假设目标是使用高级训练API,这个问题已经被Matias Valdenegro回答了。

第二种解释 - 如评论中所讨论的 - 是是否可以像在keras a simplified tensorflow interface和“Collecting trainable weights and state updates”中讨论的那样,使用标准的tensorflow优化器来进行批量归一化。正如在那里提到的,更新操作可以在layer.updates中访问,而不是在tf.GraphKeys.UPDATE_OPS中,实际上,如果你在tensorflow中有一个keras模型,你可以像这样使用标准的tensorflow优化器和批量归一化。

update_ops  = model.updates
with tf.control_dependencies(update_ops):
     train_op = optimizer.minimize( loss )

然后使用tensorflow会话来获取train_op。为了区分批量归一化层的训练和评估模式,您需要提供keras引擎的学习阶段状态(请参见上面给出的同一tutorial page中的“训练和测试期间的不同行为”)。例如,这可以像这样工作

... 
# train
lo, _ = tf_sess.run(fetches=[loss, train_step],
                    feed_dict={tf_batch_data: bd,
                               tf_batch_labels: bl,
                               tensorflow.keras.backend.learning_phase(): 1})

...

# eval
lo = tf_sess.run(fetches=[loss],
                    feed_dict={tf_batch_data: bd,
                               tf_batch_labels: bl,
                               tensorflow.keras.backend.learning_phase(): 0})

我在tensorflow 1.12中尝试了这个方法,并且它适用于包含批量归一化的模型。鉴于我现有的tensorflow代码和即将到来的tensorflow 2.0版本,我很想自己使用这种方法,但是由于tensorflow文档中没有提到这种方法,我不确定长期是否支持它,最终我决定不使用它,并投入更多的时间改变代码以使用高级API。


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