Eva*_*van 3 python deep-learning tensorflow batch-normalization
我使用TensorFlow训练DNN。我了解到批处理规范化对DNN很有帮助,因此我在DNN中使用了它。
我使用“ tf.layers.batch_normalization”并按照API文档的说明构建网络:训练时,将其参数设置为“ 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)
Run Code Online (Sandbox Code Playgroud)
我的代码中有错误吗?如果我的代码正确,我想我会得到一个奇怪的结果:
当训练,我设置“ 培训=真 ”,当验证,一套“ 训练= 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
Run Code Online (Sandbox Code Playgroud)
然而,当我改变代码“ sess.run(train_step,feed_dict = {TF_X:train_feature,tf_Y:train_label,flag_training:真,dropout_rate:1}) ”,即:设定“ 训练=假 ”时训练,集“ 训练验证时为 “ = False ” 。结果很好。第一个时期的验证损失为
0.474313
0.391002
0.369357
0.366732
0.383477
0.346027
0.336518
0.368153
0.330749
0.322070
0.335551
Run Code Online (Sandbox Code Playgroud)
为什么会出现此结果?训练时是否需要设置“ training = True”,验证时是否需要设置“ training = False”?
TL; DR:对标准化层使用小于默认动量的值,如下所示:
tf.layers.batch_normalization( h1, momentum = 0.9, training=flag_training )
Run Code Online (Sandbox Code Playgroud)
TS; WM:
设置时training = False,表示批次归一化层将使用其内部存储的均值和方差平均值来对批次进行归一化,而不是批次自身的均值和方差。当为时training = False,这些内部变量也不会更新。由于将它们初始化为mean = 0,variance = 1这意味着批量标准化已有效关闭-该层减去零并将结果除以1。
因此,如果您training = False像这样进行训练和评估,那意味着您正在训练网络而无需进行任何批量标准化。它仍然会产生合理的结果,因为嘿,批次归一化之前还有生命,尽管诚然那不是那么迷人。
如果启用批次归一化training = True,则将开始对其内部的批次进行归一化,并收集每个批次的均值和方差的移动平均值。现在是棘手的部分。该均线是指数移动平均线,有一个默认的势头0.99的tf.layers.batch_normalization()。平均值从0开始,方差再次从1开始。但是,由于每次更新都以(1-动量)的权重应用,因此它将渐近地达到实际的均值和无穷大的方差。例如,以0.99 100为0.366,它将以100步达到实际值的约73.4%。。如果数值较大,则差异可能很大。
因此,如果您处理的批次数量相对较少,那么在运行测试时,内部存储的均值和方差仍然会显着下降。然后,对网络进行正确归一化数据的培训,然后对错误归一化的数据进行测试。
为了加快内部批处理规范化值的收敛,可以应用较小的动量,例如0.9:
tf.layers.batch_normalization( h1, momentum = 0.9, training=flag_training )
Run Code Online (Sandbox Code Playgroud)
(对所有批次归一化层重复此操作。)但是请注意,这样做有一个缺点。数据中的随机波动将以这样的小动量“拖”动您存储的均值和方差,这样,最终停止训练的位置会极大地影响结果值(后来用于推断),这显然不是最佳。具有尽可能大的动量是有用的。根据训练的步数,我们一般使用0.9,0.99,0.999为100,1000,万分别训练步骤。超过0.999毫无意义。
另一个重要的事情是训练数据的适当随机化。如果您首先使用整个数据集的较小数值进行训练,则归一化收敛速度会更慢。最好完全随机化训练数据的顺序,并确保您使用的批量大小至少为14(经验法则)。
旁注:众所周知,对值进行零偏置可以大大加快收敛速度,而ExponentialMovingAverage类具有此功能。但是批处理规范化层不具有此功能,如果您愿意为苗条的代码重组,则除了tf.slim的batch_norm之外。
小智 5
设置 Training = False 提高性能的原因是批量归一化有四个变量(beta、gamma、均值、方差)。当 Training = False 时,均值和方差确实不会更新。然而,gamma 和 beta 仍在更新。所以你的模型有两个额外的变量,因此具有更好的性能。
另外,我猜你的模型在没有批量归一化的情况下具有相对较好的性能。
| 归档时间: |
|
| 查看次数: |
5609 次 |
| 最近记录: |