Tensorflow tf slim批处理规范:训练/推理模式之间的不同行为
我试图训练一个基于流行的Tensorflow tf slim批处理规范:训练/推理模式之间的不同行为,tensorflow,machine-learning,deep-learning,batch-normalization,tf-slim,Tensorflow,Machine Learning,Deep Learning,Batch Normalization,Tf Slim,我试图训练一个基于流行的mobilenet_v2的tensorflow模型,并观察到与批处理规范化相关的(我认为)无法解释的行为 问题摘要 推理模式下的模型性能最初会有所提高,但经过很长一段时间后,会开始产生琐碎的推理(都接近于零)。在训练模式下运行时,即使在评估数据集上,也能保持良好的性能。评估性能受批次标准化衰减/动量率的影响。。。不知怎么的 下面是更广泛的实现细节,但我可能会因为文本墙而失去你们中的大多数人,所以这里有一些图片让你们感兴趣 下面的曲线来自一个模型,我调整了while tra
mobilenet_v2
的tensorflow模型,并观察到与批处理规范化相关的(我认为)无法解释的行为
问题摘要
推理模式下的模型性能最初会有所提高,但经过很长一段时间后,会开始产生琐碎的推理(都接近于零)。在训练模式下运行时,即使在评估数据集上,也能保持良好的性能。评估性能受批次标准化衰减/动量率的影响。。。不知怎么的
下面是更广泛的实现细节,但我可能会因为文本墙而失去你们中的大多数人,所以这里有一些图片让你们感兴趣
下面的曲线来自一个模型,我调整了while training的bn_decay
参数
0-370k:bn_衰减=0.997
(默认值)
370k-670k:bn_衰减=0.9
670k+:bn_衰减=0.5
(橙色)培训(在培训模式下)和(蓝色)评估(在推理模式下)的损失。低是好的
推理模式下评估数据集上模型的评估度量。高是好的
我试图给出一个最小的例子来说明问题——MNIST上的分类——但失败了(即分类工作正常,我遇到的问题没有显示出来)。我为不能进一步减少而道歉
实施细节
我的问题是2D姿势估计,目标是以关节位置为中心的高斯。它本质上与语义分割相同,不同的是,我使用tf.loss.l2\u loss(sigmoid(logits)-gaussian(label\u 2d\u points))
而不是使用softmax\u cross\u entropy\u和logits(标签,logits)
(我使用术语“logits”来描述我所学模型的未激活输出,尽管这可能不是最好的术语)
推理模型
在预处理我的输入之后,我的logits函数是对基本mobilenet_v2的作用域调用,然后是单个未激活的卷积层,以使过滤器的数量合适
from slim.nets.mobilenet import mobilenet_v2
def get_logtis(image):
with mobilenet_v2.training_scope(
is_training=is_training, bn_decay=bn_decay):
base, _ = mobilenet_v2.mobilenet(image, base_only=True)
logits = tf.layers.conv2d(base, n_joints, 1, 1)
return logits
训练操作
我尝试了tf.contrib.slim.learning.create_train_op
以及定制的培训op:
def get_train_op(optimizer, loss):
global_step = tf.train.get_or_create_global_step()
opt_op = optimizer.minimize(loss, global_step)
update_ops = set(tf.get_collection(tf.GraphKeys.UPDATE_OPS))
update_ops.add(opt_op)
return tf.group(*update_ops)
我正在使用tf.train.AdamOptimizer
和学习率=1e-3
训练回路
我正在使用tf.estimator.estimator
API进行培训/评估
行为
培训最初进行得很顺利,预期绩效会大幅提高。这与我的期望是一致的,因为最后一层经过快速训练,能够解释预训练基础模型输出的高级特征
但是,经过长时间(批量大小为8的60k步骤,GTX-1070上约8小时)后,当在推理模式下运行时,我的模型开始输出接近零值(~1e-11),即is_training=False
。在*training mode下运行时,完全相同的模型将继续得到改进,即即使在估值集上,
为_training=True`。我已经通过视觉验证了这一点
经过一些实验后,我将bn_衰减
(批量标准化衰减/动量率)从默认值0.997
更改为~370k步数下的0.9
(也尝试了0.99
,但没有太大区别),并观察到准确度的大幅提高。对推理模式下推理的目视检查显示,在预期位置,顺序为~1e-1
的推理值出现明显峰值,与训练模式下的峰值位置一致(尽管值要低得多)。这就是为什么准确率显著提高,但损失——尽管更为自由——并没有得到多大改善
经过更多的训练后,这些效应逐渐消失,并恢复为零推断
在步骤670k,我进一步将bn_衰减降至0.5。这导致了损失和准确性的改善。我可能要等到明天才能看到长期效果
损失和评估指标图如下所示。注:评估指标基于logits的argmax,高为好。损失基于实际值,低是好的。橙色在训练集中使用is_training=True
,而蓝色在评估集中使用is_training=False
。大约8的损耗与所有零输出一致
其他注释
- 我还尝试过关闭辍学(即始终使用
is_training=False
运行辍学层),没有观察到任何差异
- 我已经试用了从
1.7
到1.10
的所有tensorflow版本。没有区别
- 我从一开始就使用
bn_decay=0.99
从预先训练的检查点训练模型。与使用默认值的行为相同bn\u decay
- 其他批次大小为16的实验会导致定性相同的行为(尽管由于内存限制,我无法同时评估和训练,因此定量分析批次大小为8)
- 我使用相同的损耗和
tf.layers
API训练了不同的模型,并从头开始训练。他们工作得很好
- 从头开始的训练(而不是使用预先训练的检查点)会导致类似的行为,尽管需要更长的时间
总结/我的想法:
- 我相信这不是过度拟合/数据集问题。当使用
is_training=True
运行时,该模型在峰值位置和幅值方面对评估集做出合理推断
- 我相信这不是不运行更新操作的问题。我以前没有使用过
slim
,但是除了使用arg\u scope
之外,它看起来与我广泛使用的tf.layers
API没有太大区别。我还可以检查移动平均值,并观察它们随着训练的进行而变化
- 化学需氧量