介绍
之前曾经写过一篇文章, 讲了一些深度学习训练的技巧, 其中包含了部分调参心得: 深度学习训练心得 [1]. 不过由于一般深度学习实验, 相比普通机器学习任务, 时间较长, 因此调参技巧就显得尤为重要. 同时个人实践中, 又有一些新的调参心得, 因此这里单独写一篇文章, 谈一下自己对深度学习调参的理解, 大家如果有其他技巧, 也欢迎多多交流.
好的实验环境是成功的一半
由于深度学习实验超参众多, 代码风格良好的实验环境, 可以让你的人工或者自动调参更加省力, 有以下几点可能需要注意:
将各个参数的设置部分集中在一起
. 如果参数的设置分布在代码的各个地方, 那幺修改的过程想必会非常痛苦.
可以输出模型的损失函数值以及训练集和验证集上的准确率.
可以考虑设计一个子程序, 可以根据给定的参数, 启动训练并监控和周期性保存评估结果. 再由一个主程序, 分配参数以及并行启动一系列子程序
.
画图
画图是一个很好的习惯, 一般是训练数据遍历一轮以后, 就输出一下训练集和验证集准确率. 同时画到一张图上
. 这样训练一段时间以后, 如果模型一直没有收敛, 那幺就可以停止训练, 尝试其他参数了, 以节省时间.
如果训练到最后, 训练集, 测试集准确率都很低, 那幺说明模型有可能 欠拟合
. 那幺后续调节参数方向, 就是增强模型的拟合能力. 例如增加网络层数, 增加节点数, 减少 dropout 值, 减少 L2 正则值等等.
如果训练集准确率较高, 测试集准确率比较低, 那幺模型有可能 过拟合
, 这个时候就需要向提高模型泛化能力的方向, 调节参数.
从粗到细分阶段调参
实践中, 一般先进行初步范围搜索, 然后根据好结果出现的地方, 再缩小范围进行更精细的搜索.
1. 建议先参考相关论文, 以论文中给出的参数作为初始参数
. 至少论文中的参数, 是个不差的结果.
2. 如果找不到参考, 那幺只能自己尝试了. 可以先从比较重要, 对实验结果影响比较大的参数开始
, 同时固定其他参数, 得到一个差不多的结果以后, 在这个结果的基础上, 再调其他参数. 例如学习率一般就比正则值, dropout 值重要的话, 学习率设置的不合适, 不仅结果可能变差, 模型甚至会无法收敛.
3. 如果实在找不到一组参数, 可以让模型收敛. 那幺就需要检查, 是不是其他地方出了问题
, 例如模型实现, 数据等等. 可以参考我写的深度学习网络调试技巧 [2]
提高速度
调参只是为了寻找合适的参数, 而不是产出最终模型. 一般在小数据集上合适的参数, 在大数据集上效果也不会太差. 因此可以尝试对数据进行精简
, 以提高速度, 在有限的时间内可以尝试更多参数.
对训练数据进行采样. 例如原来 100W 条数据, 先采样成 1W, 进行实验看看.
减少训练类别. 例如手写数字识别任务, 原来是 10 个类别, 那幺我们可以先在 2 个类别上训练, 看看结果如何.
超参数范围
建议优先在对数尺度上进行超参数搜索. 比较典型的是学习率和正则化项, 我们可以从诸如 0.001 0.01 0.1 1 10, 以 10 为阶数进行尝试. 因为他们对训练的影响是相乘的效果. 不过有些参数, 还是建议在原始尺度上进行搜索, 例如 dropout 值: 0.3 0.5 0.7).
经验参数
这里给出一些参数的经验值, 避免大家调参的时候, 毫无头绪.
Learning rate:1 0.1 0.01 0.001, 一般从 1 开始尝试. 很少见 learning rate 大于 10 的. 学习率一般要随着训练进行衰减. 衰减系数一般是 0.5. 衰减时机, 可以是验证集准确率不再上升时, 或固定训练多少个周期以后.
不过 更建议使用自适应梯度的办法
, 例如 adam,adadelta,rmsprop 等, 这些一般使用相关论文提供的默认值即可, 可以避免再费劲调节学习率. 对 RNN 来说
, 有个经验, 如果 RNN 要处理的序列比较长, 或者 RNN 层数比较多, 那幺 learning rate 一般小一些比较好, 否则有可能出现结果不收敛, 甚至 Nan 等问题.
网络层数: 先从 1 层开始.
每层结点数: 16 32 128, 超过 1000 的情况比较少见. 超过 1W 的从来没有见过.
batch size:128 上下开始. batch size 值增加, 的确能提高训练速度. 但是有可能收敛结果变差. 如果显存大小允许, 可以考虑从一个比较大的值开始尝试. 因为 batch size 太大, 一般不会对结果有太大的影响, 而 batch size 太小的话, 结果有可能很差.
clip c(梯度裁剪): 限制最大梯度
, 其实是 value = sqrt(w1^2+w2^2....), 如果 value 超过了阈值, 就算一个衰减系系数, 让 value 的值等于阈值: 5,10,15
dropout:0.5
L2 正则: 1.0, 超过 10 的很少见.
词向量 embedding 大小: 128,256
正负样本比例: 这个是非常忽视, 但是在很多分类问题上, 又非常重要的参数. 很多人往往习惯使用训练数据中默认的正负类别比例, 当训练数据非常不平衡的时候, 模型很有可能会偏向数目较大的类别, 从而影响最终训练结果. 除了尝试训练数据默认的正负类别比例之外, 建议对数目较小的样本做过采样, 例如进行复制. 提高他们的比例, 看看效果如何, 这个对多分类问题同样适用.
在使用 mini-batch 方法进行训练的时候, 尽量让一个 batch 内, 各类别的比例平衡
, 这个在图像识别等多分类任务上非常重要.
自动调参
人工一直盯着实验, 毕竟太累. 自动调参当前也有不少研究. 下面介绍几种比较实用的办法:
Gird Search.
这个是最常见的. 具体说, 就是每种参数确定好几个要尝试的值, 然后像一个网格一样, 把所有参数值的组合遍历一下. 优点是实现简单暴力, 如果能全部遍历的话, 结果比较可靠. 缺点是太费时间了, 特别像神经网络, 一般尝试不了太多的参数组合.
Random Search.
Bengio 在 Random Search for Hyper-Parameter Optimization 中指出, Random Search 比 Gird Search 更有效. 实际操作的时候, 一般也是先用 Gird Search 的方法, 得到所有候选参数, 然后每次从中随机选择进行训练.
Bayesian Optimization.
贝叶斯优化, 考虑到了不同参数对应的实验结果值, 因此更节省时间. 和网络搜索相比简直就是老牛和跑车的区别. 具体原理可以参考这个论文: Practical Bayesian Optimization of Machine Learning Algorithms , 这里同时推荐两个实现了贝叶斯调参的 Python 库, 可以上手即用:
jaberg/hyperopt, 比较简单.
fmfn/BayesianOptimization, 比较复杂, 支持并行调参.
总结
1. 合理性检查, 确定模型, 数据和其他地方没有问题.
2. 训练时跟踪损失函数值, 训练集和验证集准确率.
3. 使用 Random Search 来搜索最优超参数, 分阶段从粗 (较大超参数范围训练较少周期) 到细 (较小超参数范围训练较长周期) 进行搜索.
参考资料:
- https://zhuanlan.zhihu.com/p/20767428
- https://zhuanlan.zhihu.com/p/20792837
- Practical recommendations for gradient-based training of deep architectures by Yoshua Bengio (2012)
Efficient BackProp, by Yann LeCun, Léon Bottou, Genevieve Orr and Klaus-Robert Müller
Neural Networks: Tricks of the Trade, edited by Grégoire Montavon, Geneviève Orr, and Klaus-Robert Müller.
来源: http://www.tuicool.com/articles/AjqIFvf