用tensorflow做实验

在做上一篇论文的实验时由于不善于总结,曾遇到的错误在这一次实验中又发生了不少,为了避免一而再的踩坑,记录一下这次实验总结出的用tensorflow训练的技巧。

关于loss

做深度学习实验,通过loss值的收敛情况观察训练效果是最直接的方法,以下有几种可能遇到的loss值不收敛问题,通过观察loss值和准确率的改变进行区分:

loss值持续变化(但不收敛),准确率不提高

a.网络复杂度不够,需要增加网络的参数数量:
致命伤,说明你模型的拟合能力不够呗,怎么办,增加模型层数!或者全连接层数!
b.参数初始化问题
对weights和bias进行初始化再测试试试
c.优化器选择
我实验中使用的一直是tf.train.AdamOptimizer,基本不会在优化器上出错
d.数据预处理
图像去均值和数据归一化normalization!很重要
e.激活函数和损失函数
激活函数的本质是非线性函数,通过加入激活函数使得神经网络表达特征能力更强,即将线性函数转换为非线性函数具有更强的拟合能力,这也是一种增加你模型表达能力的方式,常用的sigmoid、tanh、ReLU函数
损失函数,很多人在用交叉熵的Softmax这里挂掉了原因是没有区分好两种交叉熵损失函数的用法:

 tf.nn.softmax_cross_entropy_with_logits(labels=self.Y, logits=logits)

第一种交叉熵函数是针对标签格式为one-hot形式的, 0, 1, 0, 0, 0

tf.nn.sparse_softmax_cross_entropy_with_logits(labels=self.Y, logits=logits)

第二种交叉熵函数是针对标签格式为1,2,3,4,5形式的,即非one-hot的多分类标签
另,这里的logits是网络直接输出的概率,不需要进行softmax因为交叉熵函数会进行一次softmax的!

loss值保持一个数值不变,准确率改变

a. 降低学习率,以0.1的倍率降低学习率再进行测试
b. 归一化问题
如果你的模型用到了预训练后的模型,再加载预训练权重后发现loss一直不变的话,很可能是因为特征提取后没有进行数据归一化操作,导致梯度下降过大。利用下述归一化函数对特征进行一下归一化就好了。

    def _batch_norm(self, x, mode='train', name=None):
        return tf.contrib.layers.batch_norm(inputs=x,
                                            decay=0.95,
                                            center=True,
                                            scale=True,
                                            is_training=(mode=='train'),
                                            updates_collections=None,
                                            scope=(name+'batch_norm'))
loss值保持一个数值不变,且准确率不变

检查输入数据吧!一定是数据问题。

关于学习率

一个合适的学习率会促进模型收敛,学习率的设定可参考以下原则:
1)初始学习率可根据数据的batch_size设定
CVPR2019的一篇论文 Bag of Tricks for Image Classification with Convolutional Neural Networks 建议大家可以初始值可以参考这个公式 0.1xb/256(b=batch_size),然后可以根据自己模型或者数据的大小、以及模型的初始训练结果在这个基础上调整。我实验的初始学习率基本都遵循这个公式,都可行。
ps:这篇论文真的挺不错,很实用,感兴趣的可以去看一下。
2)模型训练过程中,学习率应随训练epoch增加而减缓。
减缓机制有a)轮数减缓,如训练10个epoch学习率乘以0.1;b)指数减缓,即学习率按训练轮数增长指数差值递减
我在实验中基本用第一种,即训练10个epoch学习率乘以0.1

分层训练及加载部分权重

特征提取模型(vgg16, Resnet, autoencoder等)常作为整个模型框架的第一部分,也是很重要的一部分,为了在特征空间中搜索正确的结果,首要条件是构建好的特征空间。所以特征提取常常是第一步。
在实验中我发现,将特征提取模型和后面的模型合起来训练效果并不好,正确的方式是先进行特征提取模型的训练,再进行后面的模型训练,等两部分模型都接近拟合后再连接起来进行end-to-end训练,这时候就需要固定某些层数进行训练,以及加载部分权重。
关于分层训练,使用不同的train_op,每个tran_op负责训练不同的scope,代码如下:

optimizer = tf.train.AdamOptimizer(self.learning_rate)
 var1 = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='feat_extract')
 var2 = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='model')
 trainop = optimizer.minimize(oss, global_step=global_step, var_list=var1 + var2)
 all_trainop = optimizer.minimize(self.total_loss, global_step=global_step)

关于加载部分权重

pretrained_var = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='conv_layer')
pre_saver = tf.train.Saver(var_list=pretrained_var)
pre_saver.restore(sess, 'model')

定义tensorflow训练变量

tf.get_variable和tf.Variable

推荐使用tf.get_variable,因为如果定义的变量名称在之前已被定义过,则TensorFlow 会引发异常。如果变量存在,函数tf.get_variable( ) 会返回现有的变量。如果变量不存在,会根据给定形状和初始值创建变量。
两者的用法

var1 = tf.get_variable(name='var1',shape = [1], initializer = tf.constant_initializer(1.0))
var2 = tf.Variable(tf.constant(1.0,shape = [1]),name = 'var2')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值