Python “设置”;培训=假“;“的;tf.层.批量“U标准化”;什么时候培训会得到更好的验证结果

Python “设置”;培训=假“;“的;tf.层.批量“U标准化”;什么时候培训会得到更好的验证结果,python,tensorflow,deep-learning,batch-normalization,Python,Tensorflow,Deep Learning,Batch Normalization,我使用TensorFlow来训练DNN。我了解到批量规范化对DNN非常有用,所以我在DNN中使用了它 我使用“tf.layers.batch_normalization”并按照API文档的说明构建网络:当训练时,设置其参数“training=True”,当验证时,设置“training=False”。并添加tf.get\u集合(tf.GraphKeys.UPDATE\u OPS) 这是我的密码: # -*- coding: utf-8 -*- import tensorflow as tf im

我使用TensorFlow来训练DNN。我了解到批量规范化对DNN非常有用,所以我在DNN中使用了它

我使用“tf.layers.batch_normalization”并按照API文档的说明构建网络:当训练时,设置其参数“training=True”,当验证时,设置“training=False”。并添加tf.get\u集合(tf.GraphKeys.UPDATE\u 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)
我的代码有错误吗? 如果我的代码是正确的,我想我会得到一个奇怪的结果:

训练时,我设置了“训练=真”,当验证时,设置了“训练=假”,结果不好。我每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\u step,feed\u dict={tf\u X:train\u feature,tf\u Y:train\u label,flag\u training:True,droop\u rate:1})”时,,当培训时设置“培训=False,当验证时设置“培训=False。结果是好的。第一个历元的有效损耗为

 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”;DR
:对规范化层使用小于默认动量的动量,如下所示:

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

tf.layers.batch_normalization( h1, momentum = 0.9, training=flag_training )
当您设置
training=False
时,这意味着批次标准化层将使用其内部存储的平均值和方差来标准化批次,而不是批次自身的平均值和方差。当
training=False
时,这些内部变量也不会得到更新。由于它们被初始化为
mean=0
variance=1
,这意味着批量标准化被有效地关闭-层减去0,结果除以1

因此,如果您使用
training=False
进行训练,并进行这样的评估,则意味着您正在训练您的网络,而没有任何批量标准化。它仍然会产生合理的结果,因为嘿,在批量正常化之前就有生命,尽管无可否认没有那么迷人

如果使用
training=True
启用批次标准化,则将开始标准化批次本身,并收集每个批次的平均值和方差的移动平均值。现在是棘手的部分。移动平均线是指数移动平均线,默认动量为0.99。平均值从0开始,方差又从1开始。但由于每次更新应用的权重为(1-动量),因此它将逐渐达到无穷大的实际均值和方差。例如,在100步骤中,它将达到实际值的约73.4%,因为0.991000.366。如果数值较大,差异可能很大

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

为了加快内部批次标准化值的收敛速度,可以应用较小的动量,如0.9

tf.layers.batch_normalization( h1, momentum = 0.9, training=flag_training )
(对所有批次标准化层重复上述操作。)但是,请注意,这有一个缺点。数据中的随机波动会对存储的平均值和方差产生更大的“拖拽”,像这样的小动量,结果值(稍后用于推理)可能会受到您确切停止训练的位置的很大影响,这显然不是最优的。拥有尽可能大的动量是有用的。根据训练步骤的数量,我们通常分别使用0.90.990.999进行100100010000训练步骤。没有必要超过0.999

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



旁注:众所周知,值的零减法可以显著加快收敛速度,并且具有此功能。但是,如果您愿意为slim重新构造代码,则批处理规范化层没有此功能(除了s)。

将Training=False设置为提高性能的原因是批处理规范化有四个变量(beta、gamma、mean、variance)。当Training=False时,均值和方差确实不会得到更新。然而,gamma和beta仍然得到更新。因此,您的模型有两个额外的变量,因此具有更好的性能


此外,我猜您的模型在没有批量标准化的情况下具有相对良好的性能。

您的批量大小有多大?@Ishamael我用于培训的数据是实时生成的。每个生成数据的批次大小不是固定的,每个批次通常有300到500个样本。(我还有一个问题:在一般DNN培训中,通常会将批次大小设置为固定值,例如,将批次大小设置为1000,则每个批次有1000个样本。我想知道DNN培训是否必须确保批次大小固定?例如,第一批有300个样本,第二批有500个样本,第三批有h作为400个样本…这种方法与DNN理论一致吗?)应采用可变批量