【课程笔记】神经网络学习相关的技巧

1. 参数的更新
a. 参数更新涉及三个方面:初始值,更新方向,更新步长
i. 初始值:考虑到局部最小现象,不同的初始值开始,进行梯度下降,收敛的结果会不一样。
ii. 更新方向:不一定总是沿着负梯度方向更新就最好,这取决于目标函数的形状
iii. 更新步长:涉及到搜索效率和搜索的准确性(有没有遗漏极小值)的权衡
b. 与更新方向相关的策略:随机梯度下降(Stochastic Gradient Descent, SGD)
i. 当函数的形状非均向时,梯度的方向就没有指向最小值的方向。此时沿着负梯度方向做参数更新,路径非常曲折,很低效。
ii. 改进的办法:Momentum, AdaGrad, Adam
1) Momentum:每次梯度下降,都会有一个之前的“速度”在发挥作用(相当于阻尼器/惯性)
a) 如果这次的方向和之前相同,则会因为之前的速度继续加速
b) 如果这次的方向和之前相反,则会由于之前存在速度的作用不会产生一个"急转弯",而是有沿着之前的路线前进的趋势
2) AdaGrad:学习率衰减(learning rate decay)的方法,即随着学习的进行,使学习率逐渐减小(相当于“全体”参数的学习率值仪器降低)
a) 思路:一个一个地记录过去所有梯度的平方和(梯度能量),并将平方和的根号去除固定步长,来让实际步长越来越小
b) AdaGrad的缺陷:如果无止境地学习,更新量就会变为0,完全不再更新。为了改善这一问题,提出了RMSProp方法
c) 改进方案,RMSProp:在AdaGrad的基础上,采用“指数移动平均”的思路逐渐地“遗忘”过去的梯度,将新梯度的信息更多地反映出来
d) (有不少在步长上做改进的方法)
3) Adam:融合AdaGrad和Momentum方法,目前选优化器的时候,用的最多的就是Adam
2. 权重的初始值(优化初始值)
a. 隐藏层激活值的分布:
i. 采样方差为1的高斯分布:效果不太好→可以看隐藏层节点的激活值画出来,做统计。发现大部分激活值在0或者1附近。考虑到Sigmoid函数的函数值在接近0或者接近1附近时,导数值是接近0的。因此,偏向0和1的数据分布会造成反向传播中梯度的值不断变小,最后消失。这个问题被称为“梯度消失(gradient vanishing)”
1) 历史:很早人们就会意识到,深层的神经网络效果更好。但是也是由于梯度消失问题,很长的时间内,没有人能训练出深层的神经网络
ii. 采用方差为0.01的高斯分布:效果也不太好→隐藏层节点的激活值聚焦在0.5附近,这说明几乎所有神经元都输出几乎相同的值,那么也可以由1个神经元来表达相同的事情。因此,激活值在分布式有所偏向会出现“表现力受限”的问题
1) 其实:各层的激活值的分布需要有适当的广度;最好的情况:隐藏层激活值能够是均匀分布
iii. 经验上的Trick:
1) 针对Sigmoid函数和Tanh函数:Xavier初始值——使用标准差为1/sqrt(n)是高斯分布进行初始化
a) 是根据前人的实验提出来的经验性方法,很有可能炼丹失败
2) 针对ReLU函数:He初始值——使用标准差为1/sqrt(2/n)的高斯分布(当前一层节点为n时)
3. Batch Normalizatin (BN,批正则)
a. 思路:强制把激活值的分布拉平
b. 问题:怎么抹平?→减去均值,除以方差(正规化)
c. 方法:(相当于加了一个BN层)
i. 步骤1:以学习时的mini-batch为单位,按mini-batch进行正规化;使得数据分布的均值为0,方差为1
1) 注意:如果要用BN策略,必须一个batch一个batch地去做(batch级优化);而不能一个样本一个样本地去做(sample by sample,样本级优化)
ii. 步骤2:对正规化后的数据进行缩放和平移的变换:乘以放缩系数,加上平移系数(系数初值:放缩系数为1,平移系数0;后续通过学习调整)
d. BN层可以放在仿射变换层和ReLU层(激活层)之间;也有文章将BN层放在ReLU层(激活层)之后
i. 不要教条,实用主义原则
e. 初始化对于模型训练的效果是很敏感的;BN层的引入,能够降低一些模型训练对参数初始化的敏感性 → 拓展了能够训练成功的初始参数的范围
4. 正则化
a. 过拟合问题:只能拟合训练数据,但不能很好地拟合测试数据的状态
i. 过拟合的原因:模型拥有大量参数、表现力强(这是相对而言的原因:过于强大的模型,遇到了很少的数据,容易在实际上还没有训练好的情况下,认为自己训练好了(准确率极高),于是之后就不再调整自己的参数了);训练数据少(根本原因)
ii. 判断过拟合:训练精度和测试精度的差异特别大,就需要怀疑是不是过拟合的情况
iii. 两个思路:简化模型或者增加训练数据。实际当中最有效的是增加训练数据,但通常而言,这也很可能是贵到自己无法负担的
b. 正则化:面对过拟合问题时,一种可能会有效,但是也可能没有效果的方式
i. 权值衰减:在原有损失函数的基础上,加上权重的平方范数(L2范数)(也被称为能量项)
1) 在过拟合现象中,权值衰减方法在测试集上的精度可能不能抬多少,但是能够把训练集上的精度压下来:防止自己误以为训练出的模型,已经可以适应所有的情况了
ii. Dropout方法:
1) 训练时,随机选出隐藏层的神经元,然后将其删除。被删除的神经元不再进行信号的传递;
2) 测试时,虽然会传递所有的神经元信号,但是对于各个神经元的输出,要乘上训练时删除的比例相关的项后再输出
3) 有很多理论来分析这个方法为什么好。一个很不严谨的理解就是,它在训练时产生了很多小的网络,来一定程度上抑制过拟合效果。如果感兴趣,可以读一些关于Dropout的纯理论的文章
5. 超参数的验证
a. 模型里面的参数分为两块:一部分叫模型参数(连接权,阈值);另一部分就叫超参数(网络有几层,每一层有几个节点…)
i. Model parameter:用BP算法学习得到
ii. Hyper parameter:一开始是猜出来的(Pre-defined)
1) 预先定义的超参数,往往都不是很好
b. 跑程序的思路:调通简单的模型 → 把模型变得表达能力更强一些(调超参数)
c. 数据集的划分:训练集,测试集和验证集
i. 训练集:用于参数(权重和偏置)的学习
ii. 测试集:确认泛化能力,要在最后使用(比较理想的是只用一次)
iii. 验证集:用于超参数性能的评估(通常是在训练集中再划分一个出来)
d. 验证集的使用:穷举法
i. 给一个超参数可能的范围
ii. 对范围内的每一个取值,在训练集上训练,然后在验证集上测试
iii. 测试结果最好的,就是该范围内要找的最优的超参数
e. 超参数的组合会造成穷举的工作量几何级增长,需要采用新的策略
i. 设置超参数的范围(不要取得太大了)
ii. 从设定的超参数范围中随机采样
iii. 使用采样到的超参数的值进行学习,通过验证数据评估识别精度(但是要将epoch设置得很小)
iv. 重复上面两个步骤(100次等),根据它们识别精度的结果,缩小超参数的范围(←类似于邻域搜索的思路,先粗粒度地筛,再细粒度地筛)