gpt4 book ai didi

python - 训练时设置 "training=False"of "tf.layers.batch_normalization"会得到更好的验证结果

转载 作者:行者123 更新时间:2023-11-28 20:01:49 24 4
gpt4 key购买 nike

我使用 TensorFlow 训练 DNN。我了解到 Batch Normalization 对 DNN 非常有帮助,所以我在 DNN 中使用了它。

我使用“tf.layers.batch_normalization”并按照API文档的说明构建网络:training时,设置其参数“training=True” ,并在验证时设置“training=False”。并添加 tf.get_collection(tf.GraphKeys.UPDATE_OPS)

这是我的代码:

# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np

input_node_num=257*7
output_node_num=257

tf_X = tf.placeholder(tf.float32,[None,input_node_num])
tf_Y = tf.placeholder(tf.float32,[None,output_node_num])
dropout_rate=tf.placeholder(tf.float32)
flag_training=tf.placeholder(tf.bool)
hid_node_num=2048

h1=tf.contrib.layers.fully_connected(tf_X, hid_node_num, activation_fn=None)
h1_2=tf.nn.relu(tf.layers.batch_normalization(h1,training=flag_training))
h1_3=tf.nn.dropout(h1_2,dropout_rate)

h2=tf.contrib.layers.fully_connected(h1_3, hid_node_num, activation_fn=None)
h2_2=tf.nn.relu(tf.layers.batch_normalization(h2,training=flag_training))
h2_3=tf.nn.dropout(h2_2,dropout_rate)

h3=tf.contrib.layers.fully_connected(h2_3, hid_node_num, activation_fn=None)
h3_2=tf.nn.relu(tf.layers.batch_normalization(h3,training=flag_training))
h3_3=tf.nn.dropout(h3_2,dropout_rate)

tf_Y_pre=tf.contrib.layers.fully_connected(h3_3, output_node_num, activation_fn=None)

loss=tf.reduce_mean(tf.square(tf_Y-tf_Y_pre))

update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):
train_step = tf.train.AdamOptimizer(1e-4).minimize(loss)

with tf.Session() as sess:
sess.run(tf.global_variables_initializer())

for i1 in range(3000*num_batch):
train_feature=... # Some processing
train_label=... # Some processing
sess.run(train_step,feed_dict={tf_X:train_feature,tf_Y:train_label,flag_training:True,dropout_rate:1}) # when train , set "training=True" , when validate ,set "training=False" , get a bad result . However when train , set "training=False" ,when validate ,set "training=False" , get a better result .

if((i1+1)%277200==0):# print validate loss every 0.1 epoch
validate_feature=... # Some processing
validate_label=... # Some processing

validate_loss = sess.run(loss,feed_dict={tf_X:validate_feature,tf_Y:validate_label,flag_training:False,dropout_rate:1})
print(validate_loss)

我的代码有什么错误吗?如果我的代码是正确的,我想我会得到一个奇怪的结果:

训练时,我设置“training = True”,当验证时,设置“training = False ”,结果不好。我每 0.1 个时期打印一次验证损失,第 1 到第 3 个时期的验证损失是

 0.929624
0.992692
0.814033
0.858562
1.042705
0.665418
0.753507
0.700503
0.508338
0.761886
0.787044
0.817034
0.726586
0.901634
0.633383
0.783920
0.528140
0.847496
0.804937
0.828761
0.802314
0.855557
0.702335
0.764318
0.776465
0.719034
0.678497
0.596230
0.739280
0.970555

但是,当我更改代码“sess.run(train_step,feed_dict={tf_X:train_feature,tf_Y:train_label,flag_training:True,dropout_rate:1})”时,即:设置“training=False”在training时,设置“training=False”在validate时。结果很好。第一个 epoch 的验证损失为

 0.474313
0.391002
0.369357
0.366732
0.383477
0.346027
0.336518
0.368153
0.330749
0.322070
0.335551

为什么会出现这个结果?是否需要在训练时设置“training=True”,在验证时设置“training=False”?

最佳答案

TL;DR:使用小于默认动量的标准化层,如下所示:

tf.layers.batch_normalization( h1, momentum = 0.9, training=flag_training )

TS;WM:

当您设置 training = False 时,这意味着批归一化层将使用其内部存储的均值和方差的平均值来归一化批处理,而不是批处理本身的均值和方差。当 training = False 时,这些内部变量也不会更新。由于它们被初始化为 mean = 0variance = 1 这意味着批量归一化实际上被关闭了 - 该层减去零并将结果除以 1。

因此,如果您使用 training = False 进行训练并像那样进行评估,那仅意味着您正在训练您的网络,而没有任何批量归一化。它仍然会产生合理的结果,因为嘿,批归一化之前还有生命,尽管不可否认不是那么迷人......

如果您使用 training = True 打开批归一化,这将开始对批处理本身进行归一化,并收集每个批处理的均值和方差的移动平均值。现在这是棘手的部分。移动平均线是指数移动平均线tf.layers.batch_normalization() 的默认动量为0.99 .均值从 0 开始,方差再次从 1 开始。但由于每次更新都应用了 ( 1 - momentum ) 的权重,它将逐渐达到无穷大的实际均值和方差。例如,在 100 步中,它将达到实际值的大约 73.4%,因为 0.991000.366。如果您的数值很大,则差异可能会很大。

因此,如果您处理的批处理数量相对较少,那么在您运行测试时,内部存储的均值和方差仍可能有很大差异。然后,您的网络将在正确规范化的数据上进行训练,并在错误规范化的数据上进行测试。

为了加快内部批量归一化值的收敛,您可以应用较小的动量,例如 0.9:

tf.layers.batch_normalization( h1, momentum = 0.9, training=flag_training )

(对所有批量归一化层重复。)但是请注意,这有一个缺点。数据中的随机波动会“拖拽”你存储的均值和方差,像这样的小动量会更大,结果值(稍后用于推理)可能会受到你确切停止训练的位置的很大影响,这显然不是最佳的。拥有尽可能大的动量是有用的。根据训练步数的不同,我们一般使用0.90.990.999 1001,00010,000分别训练步骤。超过 0.999 没有意义。

另一个重要的事情是训练数据的适当随机化。如果您首先使用整个数据集的较小数值进行训练,那么规范化会收敛得更慢。最好完全随机化训练数据的顺序,并确保使用至少 14 的批量大小(经验法则)。


旁注:众所周知,零偏差值可以显着加快收敛速度​​,ExponentialMovingAverage class有这个功能。但是批归一化层没有这个功能,除了tf.slim。的 batch_norm ,如果您愿意为 slim 重构您的代码。

关于python - 训练时设置 "training=False"of "tf.layers.batch_normalization"会得到更好的验证结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50047653/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com