如何在GradientTape中使用Tensorflow BatchNormalization?

时间:2019-06-13 20:46:44

标签: python tensorflow

假设我们有一个使用BatchNormalization的简单Keras模型:

model = tf.keras.Sequential([
                     tf.keras.layers.InputLayer(input_shape=(1,)),
                     tf.keras.layers.BatchNormalization()
])

如何在GradientTape中实际使用它?以下内容似乎不起作用,因为它没有更新移动平均值?

# model training... we want the output values to be close to 150
for i in range(1000):
  x = np.random.randint(100, 110, 10).astype(np.float32)
  with tf.GradientTape() as tape:
    y = model(np.expand_dims(x, axis=1))
    loss = tf.reduce_mean(tf.square(y - 150))
  grads = tape.gradient(loss, model.variables)
  opt.apply_gradients(zip(grads, model.variables))

尤其是,如果您检查移动平均值,它们将保持不变(检查model.variables,平均值始终为0和1)。我知道可以使用.fit()和.predict(),但是我想使用GradientTape,但不确定如何执行此操作。该文档的某些版本建议更新update_ops,但这似乎在急切模式下不起作用。

尤其是,经过上述训练后,以下代码将不会输出接近150的任何内容。

x = np.random.randint(200, 210, 100).astype(np.float32)
print(model(np.expand_dims(x, axis=1)))

3 个答案:

答案 0 :(得分:1)

我只是放弃。我花了一些时间试图弄清楚一个看起来像这样的模型:

model = tf.keras.Sequential([
                     tf.keras.layers.BatchNormalization(),
])

我放弃,因为那件事看起来像这样: enter image description here

我的直觉是,如今的BatchNorm并不像以前那样简单明了,这就是为什么它可以扩展原始发行版,而不是扩展新发行版(这很可惜),但是没有人有时间这样做

编辑: 的原因是BN在训练过程中仅计算力矩并标准化批量。在训练过程中,它会保持均值和偏差的运行平均值,一旦您切换到评估,就将参数用作常数。即,评估不应该依赖于规范化,因为评估甚至可以用于单个输入,并且不能依赖批处理统计信息。由于常量是在不同的分布上计算的,因此在评估过程中会出现更高的误差。

答案 1 :(得分:1)

使用渐变磁带模式BatchNormalization层时,应使用参数training = True调用

示例:

inp = KL.Input( (64,64,3) )
x = inp
x = KL.Conv2D(3, kernel_size=3, padding='same')(x)
x = KL.BatchNormalization()(x, training=True)
model = KM.Model(inp, x)

然后正确地移动移动变量

>>> model.layers[2].weights[2]
<tf.Variable 'batch_normalization/moving_mean:0' shape=(3,) dtype=float32, numpy
=array([-0.00062087,  0.00015137, -0.00013239], dtype=float32)>

答案 2 :(得分:0)

在“渐变磁带”模式下,通常会找到类似以下的渐变:

    Dim conn As OleDbConnection
    Dim dta As OleDbDataAdapter
    Dim dts As DataSet = Nothing
    Dim mainDts As DataSet = Nothing
    Dim Excel As String
    Dim OpenFileDialog As New OpenFileDialog
    OpenFileDialog.InitialDirectory = "C:\Test"
    OpenFileDialog.Multiselect = True
    OpenFileDialog.Filter = "All Files (*.*)|*.*|Excel Files (*.xlsx)|*.xlsx|Xls Files (*.xls)|*.xls"
    If OpenFileDialog.ShowDialog(Me) = DialogResult.OK Then
        For Each fileName As String In OpenFileDialog.FileNames
            Dim fi As New IO.FileInfo(fileName)
            Excel = fi.FullName
            conn = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + Excel + "; 
            Extended Properties=Excel 12.0;")
            dta = New OleDbDataAdapter("select * from [Sheet$]", conn)
            dts = New DataSet
            dta.Fill(dts, "[Sheet$]")

            conn.Close()
            If mainDts Is Nothing Then
                mainDts = dts
            Else
                mainDts.Merge(dts)
            End If
        Next
        DataGridView1.DataSource = mainDts
        DataGridView1.DataMember = "[Sheet$]"
    End If

但是,如果您的模型包含with tf.GradientTape() as tape: y_pred = model(features) loss = your_loss_function(y_pred, y_true) gradients = tape.gradient(loss, model.trainable_variables) train_op = model.optimizer.apply_gradients(zip(gradients, model.trainable_variables)) BatchNormalization层(或具有不同训练/测试阶段的任何层),则tf将无法构建图形。

一个好的实践是从模型获取输出时显式使用Dropout参数。在优化使用trainable和预测使用model(features, trainable=True)时,为了在使用此类图层时明确选择训练/测试阶段。

对于model(features, trainable=False)PREDICT阶段,使用

EVAL

training = (mode == tf.estimator.ModeKeys.TRAIN) y_pred = model(features, trainable=training) 阶段,使用

TRAIN

请注意,除了需要手动为这些图层设置训练阶段之外,iperov的答案也适用。

with tf.GradientTape() as tape:
    y_pred = model(features, trainable=training)
    loss = your_loss_function(y_pred, y_true)
    gradients = tape.gradient(loss, model.trainable_variables)

train_op = model.optimizer.apply_gradients(zip(gradients, model.trainable_variables))

我建议使用一个x = BatchNormalization()(x, training=True) x = Dropout(rate=0.25)(x, training=True) x = BatchNormalization()(x, training=False) x = Dropout(rate=0.25)(x, training=False) 函数来返回模型,同时在调用模型时使用get_model参数更改相位。

注意:

如果在查找渐变时使用training,则会收到此警告

model.variables

这可以通过仅针对可训练变量计算梯度来解决。将Gradients do not exist for variables ['layer_1_bn/moving_mean:0', 'layer_1_bn/moving_variance:0', 'layer_2_bn/moving_mean:0', 'layer_2_bn/moving_variance:0'] when minimizing the loss. 替换为model.variables