参考:
1
技巧链接一!重要
技巧链接二!重要
技巧链接三!重要
模型训练技巧最直接的就是几个超参数的设置
根据图片大小来选择网络和超参数
如果图片不是很大比如3030,这种情况下做分类就不能用VGG和Resnet这样的网络。此时要么把图像变大要么就是选择小的网络,或者把VGG里pooling的步长设置为1试试,如果类别不多(没有上千),那么直接使用小网络,如果是100100这样的大图片就采用VGG和Resnet这样的大网络。
根据图片类别数和数量来选择batch_size
如果训练样本少,少于1000,那么直接使用全梯度下降,不需要用批梯度下降。用批梯度的目的是为了加快训练速度,所以当训练样本少的时候是没有必要使用批梯度下降的。只是用全梯度下降反向传播一次需要很久的时间,训练起来很慢。若训练类别很多,那么bacth_size一定不要太小,例如若是上千的类别数,那么bacth_size值就设置为为128,否则震荡会很严重。
根据网络规模和loss下降速率来选择学习率
学习率的选择一般是0.001 0.0001 0.00001 0.000001等中的一个值,选择哪个值的最根本的依据是网络很复杂的时候学习率不能太低,否则传到后面的时候就会基本没梯度了。三五层的网络学习率基本要小于1*e^(-5),不然会下降过快导致震荡。初始学习率可以随意选择来尝试试探,如果发现loss下降得过快,那么要减少学习率。如果发现loss降低不下去,就适当增加学习率。
深度学习的训练过程
深度学习的训练过程大同小异,一般可以分为如下几步:
- 定义算法公式,也就是神经网络的前向算法,一般使用现成的网络,例如inceptionV4,mobilenet等。
- 定义loss,选择优化器,让loss最小。
- 对数据迭代训练,让loss最小。
- 在测试集或者验证集上对准确率评估
深度学习模型训练过程中常遇到的问题
问题一:收敛速度慢,训练时间长
- 深度学习训练过程就是一个不断调参的过程,收敛速度慢、训练时间长会使得相同总训练时间内迭代次数少,从而影响准确率。另外训练次数变少,使得尝试超参数的次数变少。
解决办法一:设置合理的初始化权重和偏置
- 深度学习通过前向计算和反向传播,不断调整参数,来提取最优特征。调整的参数就是权重和偏置。根据奥卡姆剃刀法则,模型越简单越好,以线性函数这种最简单的表达式来提取特征。即f(x)=wx+b。深度学习训练时几乎所有的工作量都是用来求解w和b。训练本质也就是调整w和b的过程。
- 一般使用截断的正态分布(也叫作高斯分布)来初始化w。
如下
# 权重weight,标准差0.1。truncated_normal截断的正态分布来初始化weight。权重初始化很有讲究的,会决定学习的快慢
def weight_variable(shape, vname):
initial = tf.truncated_normal(shape, stddev=0.1, name=vname)
return tf.Variable(initial)
tf.truncated_normal定义如下
tf.truncated_normal(
shape, # 正态分布输出数据结构,1维tensor
mean=0.0, # 平均值,默认为0.我们一般取默认值0
stddev=1.0, # 标准差
dtype=tf.float32, # 输出数据类型
seed=None, # 随机分布都会有一个seed来决定分布
name=None
)
- 下图左图为标准正态分布,也叫作高斯分布。利用TensorFlow中的tf.random_normal()可以得到x取值范围从负无穷到正无穷的值。所以的y值加起来为1。初始化w时,没必要将其初始化为很大或者很小的值,所以更倾向于使用截断正态分布,如下图中的右图。截断正态分布和标准正态分布的区别是:限制了x取值必须在[-2 x stddev, 2 x stddev]之间。
- f(x)=wx+b,b由于是加和关系,对收敛速度影响不大,一般初始化为0.如下所示
# 偏置量bias,初始化为0,偏置可直接使用常量初始化
def bias_variable(shape, vname):
initial = tf.constant(0, shape=shape, name=vname)
return tf.Variable(initial)
解决办法二:优化学习率
- ,模型训练就是不断尝试和调试w和b,每次调整的幅度是多少,关系到学习率。w和b是在一定范围内调整的,增大学习率就减少了迭代次数,但学习率太大,也容易越过局部最优点,降低准确率。
- 所以,一般采用,一开始学习率大,从而加速收敛,训练后期学习率小一点,从而稳定地落入局部最优点。使用Adam,Adagrad等自适应优化算法,就可以实现学习率的自适应调整。从而保证准确率的同时加快收敛速度。
解决办法三:网络节点输入值正则化batch normalization(批标准化)
- 神经网络训练时,每一层的输入分布都在变化,不论输入值是大还是小,学习率都是相同的,这是很浪费效率的,当输入值很小时,为了保证精细调整,学习率不能设置太大,如果让输入值标准化落到某一个范围内,如[0,1]之间,这样就不用为太小的输入值犯愁。
- 学习的是输入的特征分布,而不是绝对值,所以可以对每一个mini-batch数据内部进行标准化,使它们规范化到[0,1]之间。这就是bacth normalization正则化。
- inceptionV2在每个卷积层后,使用一个BN层,从而使得学习率可以设定为一个较大的值,使用了BN之后的inceptionV2,只需要以前的1/14的迭代次数就能达到之前的准确值,加快了收敛速度。
- Normalization时,选的平均值跟标准差希望它代表的是整个training set全体。但是实际上统计整个training set全体的statistics是非常耗费时间的。所以实际上算平均值和标准差的时候,只会在batch里面算。所以batch size一定要够大,如果太小的话Batch Normalization的性能就会很差,因为你没有办法从一个batch里面估测整个data集,可以想象极端case,如果batch size=1,则不能apply BN想法。
解决办法四:采用更先进的网络结构,减少参数量
- 训练速度慢,归根结底是网络结构参数多,减少参数量,可以大大加快收敛速度。采用先进的网络结构可以可以用更少的参数数量达到更高的精度。如何用更少的参数数量达到更高的精度,有如下几种方法:
方法一: 使用小卷积核代替大卷积核
VGGNet全部使用33的小卷积核,来代替AlexNet中的1111和55等大卷积核。小卷积核虽然参数量少,但也会带来特征面积捕获过小的问题。inception net认为越往后的卷积层,应该捕获更多更高阶的抽象特征。因此它在靠后的卷积层中使用的55等大面积的卷积核的比率较高,而在前面几层卷积层中,更多使用的是11和33的卷积核。
方法二: 使用两个串联小卷积核来代替大卷积核
inceptionV2中提出两个33的卷积核代替一个55的卷积核,在效果相同的情况下,参数量仅为原先的332/5*5=18/25
方法三: 1 * 1卷积核的使用
1 * 1卷积核是性价比最高的卷积,它在参数量为1的情况下,同样能够提供线性变换、relu激活、输入输出channel变换。是VGGNet提出的1 * 1卷积核。
方法四: 非对称卷积核的使用
inceptionV3中将一个7 * 7的卷积拆分成了一个1 * 7和一个7 * 1的卷积核,卷积效果相同的情况下,参数量大大减小,而且还提高了卷积的多样性。
方法五: depthwise卷积的使用
mobileNet中将一个3 * 3的卷积拆分成了串联的一个3 * 3 depthwise卷积和一个1 * 1正常卷积。对于输入channel为M,输出为N的卷积,正常情况下,每个输出channel均需要M个卷积核对输入的每个channel进行卷积、并叠加。也就是需要M * N个卷积。而在depthwise卷积中,输出channel和输入相同,每个输入channel仅需要一个卷积核,而将channel变换的工作交给了1 * 1卷积核。这个方法在参数量减少到之前的1/9的情况下,精度仍能达到80%。
方法六:全局平均池化代替全连接层
AlexNet和VGGNet中,全连接层几乎占据了90%的参数量,inceptionV1使用全局平均池化来代替最后的全连接层。使得其在