一、概述
神经网络训练好之后,只有通过优化才能达到我们想要的效果,也就是我们说的调参,使参数更加准确的更新。
神经网络训练过程一般为两个阶段:
- 第一个阶段先通过前向传播算法计算得到预测值,并将预测值与真实值作比较,得出两者之间的差距。
- 第二个阶段通过反向传播算法计算损失函数对每一个参数的梯度,再根据梯度和学习率使用梯度下降算法更新每一个参数。
二、优化网络的方法
1、学习率的优化
每一个参数对目标函数的依赖不同,有的参数已经优化到了极小值附近,有的参数仍然有很大的梯度,所以不能使用统一学习率,学习率太小,会有一个很慢的收敛速度,学习率很大,会使已经优化的差不多的参数不稳定,一般合理的做法是对每一个参数设置不同的学习率。有三种不同自适应学习率优化算法
- AdaGrad
AdaGrad算法,独立地适应所有模型参数的学习率,缩放每个参数反比于其所有梯度历史平均值总和的平方根。具有代价函数最大梯度的参数相应地有个快速下降的学习率,而具有小梯度的参数在学习率上有相对较小的下降。 - RMSProp
RMSProp算法修改了AdaGrad的梯度积累为指数加权的移动平均,使得其在非凸设定下效果更好。 - Adam
学习率的独立设置
指数衰减的学习率
指数衰减学习率是先使用较大的学习率来快速得到一个较优的解,然后随着迭代的继续,逐步减小学习率,使得模型在训练后期更加稳定。
tf.train.exponential_decay(learning_rate,global_step,decay_steps,decay_rate,staircase=False,name=None)
参数
初始学习率learning_rate
衰减系数decay_rate
decay_steps控制衰减速度
global_steps当前训练的轮数
staircase:布尔值。如果True,decay_steps代表了迭代多少轮后再更新学习率参数,最终学习函数会成为一个阶梯函数
2、梯度下降的优化
https://blog.csdn.net/itchosen/article/details/77200322
总体思想:
梯度下降是指沿着损失函数的下坡方向(导数增大的反方向)迭代更新参数的方法称为梯度下降法,目的是为了寻找一个参数,使得损失函数值最小。还需要定义一个学习率,是指每次参数移动的幅度,梯度下降法并不能保证被优化的非凸函数达到全局最优点,因为梯度下降最后的结果收到参数初始值的影响,或者只有当损失函数为凸函数时可以达到全局最优点。梯度下降分为以下三个,主要区别在于选取样本的数量
- 批量梯度下降法(Batch Gradient Descent)
在更新参数时使用所有的样本来进行更新
- 随机梯度下降法(Stochastic Gradient Descent)
随机梯度下降法,其实和批量梯度下降法原理类似,区别在与求梯度时没有用所有样本的数据,而是仅仅选取一个样本来求梯度
- 小批量梯度下降法(Mini-batch Gradient Descent)
小批量梯度下降法是批量梯度下降法和随机梯度下降法的折衷,选取一部分样本来更新梯度
随机梯度下降法和批量梯度下降法对比
- 对于训练速度来说,随机梯度下降法由于每次仅仅采用一个样本来迭代,训练速度很快,而批量梯度下降法在样本量很大的时候,训练速度不能让人满意。
- 对于准确度来说,随机梯度下降法用于仅仅用一个样本决定梯度方向,导致解很有可能不是最优。SGD通常训练时间更长,但是在好的初始化和学习率调度方案的情况下,结果更可靠。
- 对于收敛速度来说,由于随机梯度下降法一次迭代一个样本,导致迭代方向变化很大,不能很快的收敛到局部最优解。SGD容易收敛到局部最优,并且在某些情况下可能被困在鞍点(不是最小点也不是最大点)
在使用梯度下降时,进行调优的要点
-
算法的学习率选择。在前面的算法描述中,我提到取学习率为1,但是实际上取值取决于数据样本,可以多取一些值,从大到小,分别运行算法,看看迭代效果,如果损失函数在变小,说明取值有效,否则要增大学习率。前面说了。学习率太大,会导致迭代过快,甚至有可能错过最优解。学习率太小,迭代速度太慢,很长时间算法都不能结束。所以算法的学习率需要多次运行后才能得到一个较为优的值。
-
算法参数的初始值选择。 初始值不同,获得的最小值也有可能不同,因此梯度下降求得的只是局部最小值;当然如果损失函数是凸函数则一定是最优解。由于有局部最优解的风险,需要多次用不同初始值运行算法,关键损失函数的最小值,选择损失函数最小化的初值。
-
归一化。由于样本不同特征的取值范围不一样,可能导致迭代很慢,为了减少特征取值的影响,可以对特征数据归一化,这样特征的新期望为0,新方差为1,迭代次数可以大大加快。
一般tensorflow使用优化器来完成梯度下降和自适应学习率,learning_rate学习率,loss损失函数。详见网页1,网页2介绍
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss)
##梯度下降,使用全部样本更新参数
train_step = tf.train.AdagradOptimizer(learning_rate).minimize(loss)
##实现Adagrad优化器
train_step = tf.train.RMSPropOptimizer(learning_rate)).minimize(loss)
##实现RMSProp优化器
train_step = tf.train.AdamOptimizer(learning_rate)).minimize(loss)
##实现Adam优化器
3、欠拟合和过拟合的优化
一般有三种方法,详见欠拟合过拟合优化方法1,欠拟合过拟合优化方法2。
-
Dropout
为了防止神经网络的过拟合。它的主要思想是让隐藏层的节点在每次迭代时(包括正向和反向传播)有一定几率(keep-prob)失效,这样来预防过拟合。它主要避免对某个节点的强依赖,让反向传播的修正值可以更加平衡的分布到各个参数上
(1)Dropout只发生在模型的训练阶段,预测、测试阶段则不用Dropout
(2)Dropout随机删除神经元后,网络变得更小,训练阶段也会提速
(3)有了dropout,网络不会为任何一个特征加上很高的权重(因为那个特征的输入神经元有可能被随机删除),最终dropout产生了收缩权重平方范数的效果
(4)Dropout的一大缺点就是损失函数不再被明确定义,所以在训练过程中,损失函数的值并不是单调递减的
(5)使用时,先关闭Dropout,设置keep-prob为1,使损失函数的值单调递减,然后再打开Dropout -
Bagging 详见集成学习介绍
-
正则化方法
(1)L1正则化
(2)L2正则化#在权重参数上实现L2正则化 regularizer = tf.contrib.layers.l2_regularizer(0.01) regularization = regularizer(weight1)+regularizer(weight2)+regularizer(weight3) tf.add_to_collection("losses",regularization) #加入集合的操作 #get_collection()函数获取指定集合中的所有个体,这里是获取所有损失值 #并在add_n()函数中进行加和运算 loss = tf.add_n(tf.get_collection("losses"))#损失包括误差和正则项 tf.add_to_collection("losses", error_loss) #加入集合的操作
-
数据和特征方面
1)重新清洗数据,导致过拟合的一个原因也有可能是数据不纯导致的,如果出现了过拟合就需要我们重新清洗数据。
2)增大数据的训练量,还有一个原因就是我们用于训练的数据量太小导致的,训练数据占总数据的比例过小。
3)对于欠拟合,需要添加其他特征项,有时候我们模型出现欠拟合的时候是因为特征项不够导致的,可以添加其他特征项来很好地解决。例如,“组合”、“泛化”、“相关性”三类特征是特征添加的重要手段。添加多项式特征,例如将线性模型通过添加二次项或者三次项使模型泛化能力更强。对于过拟合,需要删掉特征
4)欠拟合也可以降低正则化约束,过拟合也可以增加正则化约束