前 言
话不多说!
在这篇文章中,我将介绍一些最常用的做法,从训练数据的质量的重要性,到超参数的选择,以及更快的DNN原型设计技巧。
大多数这些实践经过了学术界和工业界的研究的验证,并在研究论文中提出了数学和实验证明,如Efficient BackProp(Yann LeCun等人)[http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf]和[Deep Architectures的实践建议(Yoshua Bengio)][https://arxiv.org/pdf/1206.5533v2.pdf]。
在这篇文章中我没有提到任何数学证明,这里提出的所有要点多是概括DNN训练的最佳实践。为了更深入的了解,强烈建议您阅读最后提供的参考资料---研究论文和参考文献。
训练数据
许多ML从业者习惯直接把原始训练数据扔进DNN模型,DNN大多会(可能)给出好的结果,对吗?
大多数人也知道 “考虑到正确的数据类型,相对简单的模型可能会比复杂的DNN有更好更快的结果”(尽管这可能有例外)。
因此,无论您是使用计算机视觉,自然语言处理,统计建模等尝试预处理原始数据。可以采取一些措施获得更好的训练数据:
尽可能大的数据集(DNN对数据那是相当饥渴的:越多越好,得数据者得天下)
删除损坏数据的任何训练样本(短文本,高度失真的图像,假输出标签,数据预处理)
数据增强 - 创建新的示例(在图像的情况下 - 重新调整比例,增加噪音等)
选择适当的激活函数
任何神经网络的重要组成部分之一是激活函数。激活在模型中引入了非常理想的非线性。多年来,sigmoid激活功能一直是首选。
但是,一个sigmoid函数本质上有这两个缺点:
在尾部饱和S形(进一步导致消失梯度问题)
sigmoids不是以零为中心的。
更好的选择是一个tanh函数,tanh仅仅是一个重新调整和转移sigmoid,tanh(x) = 2*sigmoid(x) - 1。
虽然tanh依旧存在渐变梯度的问题,但 tanh以零为中心,因此,使用tanh激活函数会导致更快的收敛。我发现使用tanh作为激活一般比sigmoid更好。
可以根据具体任务进一步探索其他替代方案,例如ReLU,SoftSign等,这些函数已经证明可以改善一些问题。
隐藏单元和图层的数量
保持比最佳数量更多的隐藏单位,一般会得到更好的结果。因为,任何正则化方法都得考虑多余的激活单元;另一方面,在保持较少数量的隐藏单位个数(而不是最佳数量)的同时,模型不足的可能性较大。
而且,在采用无监督的预训练(在后面的章节中描述)时,隐藏单元的最佳数量通常保持更大。因为,预训练的表示可能在这些表示中包含大量不相关的信息(针对特定的监督任务)。通过增加隐藏单元的数量,模型将具有所需的灵活性,从这些预训练的结果中筛选出最合适的信息。
选择最佳层数是相对直接的。正如[@ Yoshua-Bengio][https://www.quora.com/profile/Yoshua-Bengio]在Quora上提到的那样 - “您只需继续添加层数,直到测试错误率不再增加”。)
权重初始化
始终用小random numbers来初始化权重以打破不同‘神经元’之间的对称性。
但权重应该小到多少?建议的上限是多少?什么概率分布用于生成随机数?此外,当使用sigmoid激活函数时,如果权重初始化为非常大的数字,则S形将饱和(尾部区域),那么会出现“死亡神经元”。如果权重非常小,那么渐变也会很小。因此,最好在中间范围内选择权重,以使这些权重均匀分布在平均值附近。
有关初始权重的适当值的研究很多,这对于有效收敛非常重要。要初始化均匀分布的权重,a uniform distribution可能是最佳选择之一。此外,如论文([Glorot和Bengio,2010][http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf])所示,具有更多传入连接(fan_in)的神经元应该具有相对较小的权重。
由于有了这一系列的前人探索实验,这里总结出一个测试公式,我们可以直接使用权重初始化;
即从~ Uniform(-r, r)何处开始r=sqrt(6/(fan_in+fan_out))为tanh激活而绘制的权重,以及r=4*(sqrt(6/fan_in+fan_out))用于sigmoid激活的权重,其中fan_in前一层fan_out的大小和下一层的大小。(这个法则不错)
学习率
这可能是控制学习过程的最重要的超参数之一。
设置学习率太小,你的模型可能需要很长时间才能收敛,使其过于庞大,并且在最初的几个训练样例中,你的损失可能会飞上天空。
一般来说,学习率设置为0.01,当然这不是固定的; 毕竟不同的学习任务学习率是不同的。
相比固定的学习率,在每个迭代之后逐渐降低学习率是个不错的的选择,比如每个时迭代后的学习速率可以减半,也可以滴。
现在也有[momentum based methods][http://cs231n.github.io/optimization-2/#intro]根据误差函数的倒数来改变学习速率。它也可能有助于为模型中的各个参数设置不同的学习率; 因为一些参数可能以相对较慢或较快的速率学习。
许多对优化方法有大量的研究,其实就是adaptive learning rates。比如:Momentum Method来Adagrad,Adam(个人最喜欢的;)),RMSProp等等。像方法Adagrad或者Adam,有效地节约了我们从手动选择一个initial learning rate,该模型将开始收敛相当顺利。
超参数调整:顺序网格搜索 - 随机搜索
网格搜索在传统的机器学习中一直盛行。但是,网格搜索在为DNN寻找最佳超参数方面效率并不高。主要是由于DNN在尝试使用不同的超参数组合时花费的时间。随着超参数的数量不断增加,网格搜索所需的计算也呈指数增长。
学习方法
一般来说,之前的 随机梯度下降可能不会像DNN那样高效,最近已经有很多研究开发更灵活的优化算法。对于如:Adagrad,Adam,AdaDelta,RMSProp,等。
除了提供自适应学习率,这些复杂的方法对于不同的模型,也使用不同的学习率,这通常可以达到平滑衔接,收敛。将这些考虑为超参数是很好的,并且应该总是在一部分训练数据上尝试其中的一些。
保持指数权重为2的权重维度
即使在使用最新的硬件资源处理最先进的深度学习模型时,内存管理仍然在字节级完成; 所以,将参数的大小保持为64,128(512,1024所有的权力2)更好。这可能有助于分解矩阵,权重等,从而轻微提高学习效率。尤其是处理GPU时。
小批量与随机学习
训练模型的主要目标是学习适当的参数,从而得到从输入到输出的最佳映射。无论您决定使用批次,小批量还是随机学习,这些参数都会根据每个训练样本进行调整。
在采用随机学习方法时,在每次训练样本之后调整权重梯度,将噪音引入梯度(因此“随机”一词)。这具有非常理想的效果; 即 - 在训练期间引入噪音,模型变得不太容易过度拟合。
但是,通过随机学习方法可能效率相对较低; 如果我们能够计算矩阵 - 矩阵乘法,那么为什么我们应该限制自己,遍历各对矢量的乘法?因此,为了获得更高的吞吐量/更快的学习速度,建议使用小批量而不是随机学习。
但是,选择合适的批量大小同样重要; 这样我们仍然可以保留一些噪音(通过不使用大量批次),同时更有效地利用机器的计算能力。通常,16到128,是一个不错的选择(指数的2)。
通常情况下,一旦您已经找到更重要的超参数(通过手动搜索或随机搜索),就会选择批量大小。尽管如此,在模型将流训练数据视为流(在线学习)的情况下,采用随机学习是一个不错的选择。
打乱训练数据
这来自信息理论 - “学习一个不太可能发生的事件比知道可能事件发生的信息更丰富”。类似地,随机化训练样例的顺序(在不同的时期或小批次)将导致更快的收敛。当模型没有看到很多相同顺序的例子时,总会注意到一点点提升。
正则化的dropout
考虑到,要学习数百万个参数,正规化成为防止DNN中过度拟合的必要条件。您可以继续使用L1 / L2正则化,但Dropout更适合检查DNN中的过度拟合,并通常可以更快的训练网络。虽然这取决于具体的任务,默认值0.5是一个不错的选择。如果模型不太复杂,那么辍学0.2也许就足够了。
可视化
有一种方法可能会导致深度学习模式的训练出错。当模型被训练几个小时或几天,并且只有在训练结束后,我们才意识到出了问题。在这种情况下(这可能是非常合理的))
始终可视化训练过程。你可以采取最明显的一步是打印/保存日志的loss值,train error或test error等。
除此之外,另一个良好的做法是使用一个可视化库来绘制几个训练样例或时代之间的权重直方图。这可能有助于跟踪深度学习模型中的一些常见问题,如梯度消失、梯度爆炸等。
多核机器,GPU
GPU的出现,提供向量化操作的库,计算能力更强的机器,可能是深度学习成功的一些最重要的因素。GPU已经彻底改变了深度学习的研究(难怪Nvidia的股票正在飙升;)),主要是因为它们能够以更大规模执行Matrix Operations。
因此,这些并行化技术不是在普通机器上花费数周,而是将训练时间缩短到几天,甚至几小时。
使用GPU和具有自动求导框架
值得庆幸的是,快速原型,我们有像一些真正的标准框架Theano,Tensorflow,Keras等几乎所有这些DL库提供用于GPU计算的支持和自动分化。所以,你不必深入核心的GPU编程;
这完全不是一个详尽的实践清单。为了只包含最常见的做法,我排除了一些概念,如输入规范化,批量/图层标准化,梯度检查等。
参考文献:
高效BackProp(Yann LeCun等人)
[深度网络构建的实践建议(Yoshua Bengio)]
(https://arxiv.org/pdf/1206.5533v2.pdf)
[了解深度前馈神经网络的训练有多难(Glorot and Bengio,2010)]
(http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf)
[Dropout:一种防止神经网络过拟合的简单方法]
(https://www.cs.toronto.edu/~hinton/absps/JMLRdropout.pdf)
作者:机器学习算法工程师
链接:https://www.jianshu.com/p/732a3fe2e1b3
來源:
著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。