点击小眼睛开启蜘蛛网特效

浅谈深度学习中超参数调整策略

《浅谈深度学习中超参数调整策略》前言

深度学习中,设计模型以及保证模型的正确性是首要需要考虑的。当模型设置完成时,理论上模型不存在问题,实现效果也通过计算可以复现出来。一切准备就绪后,那么接下来需要操作的就是——调参了。

《浅谈深度学习中超参数调整策略》

正文

为什么很多人都称深度学习为炼丹?为什么丹药那么难炼?为什么为什么,因为炼丹的调料放多少不知道啊?得一个一个去尝试啊。

很多时候,模型搭建好了,但是随之而来的就是参数选择问题。参数选择我们一般大概分为两种方式,手动选择和自动选择。

  • 手动选择就是我们利用对模型的理解和对结果的分析进行调参,手动选择参数,这样准确率稍高一些,但是时间长了我们会受不了,有时候真的会怀疑人生。
  • 自动选择就是设计一个自动调参工具,让程序自己跑就行了,当然这个对机子的要求高一些,相同情况下用GPU调参速度是用CPU的几十倍。

接下来主要说一下自动选择的几个方式,程序利用pytorch代码说明。

手动选择

手动选择就是自个儿看,自己根据对模型的理解和对结果的分析进行,最好是可视化卷积层进行分析,这样可以观察并慢慢寻找到一些迭代时隐藏的规律。

关于如何可视化可以看一下,知乎上相关问题的回答

自动选择

自动选择说白了就是让代码一直跑,然后用你提供的不同超参数一遍一遍尝试然后得到比较满意的结果。

《浅谈深度学习中超参数调整策略》

Photo by SigOpt

如上图,假设我们有2个超参数(n_estimatorsmax_depth),每个超参数的取值的不同组合所得到的score结果也不同。取值越合适score越高,当然上面的图只是展示了二维的超参数,如果是3个或3个以上的超参数,我们可以想象一个超平面,最合适的参数组合得到的分数在最高点。

网格搜索

网格搜索是我们最常用的超参数调参策略。我们把每个可能的超参数组合都写下来,进行尝试:

style_weights = [0.1, 0.5, 1, 1.5, 2.5, 5, 10, 15, 20, 50, 100, 150, 200, 500, 1000,
                 5000, 10000, 50000, 100000, 500000, 1000000]
content_weights = [1, 5, 10, 100]

比如上面的代码,我们有两个超参数,分别是style_weightcontent_weight,我们列出这些参数可能的值,然后进行训练:

for i in range(len(content_weights)):
    for j in range(len(style_weights)):
        output = run_painterly_transfer(cnn, cnn_normalization_mean, cnn_normalization_std, style_img=style_image,
                                        content_img=content_image, mask_img=mask_image, tmask_img=tmask_image,
                                        style_weight=int(style_weights[j]), content_weight=int(content_weights[i]))

代码很简单,通过循环将你觉得可能的参数都尝试了一遍,我们可以在程序执行的过程中把你觉得需要的中间结果和最终结果都保存到一个文件夹中,当训练完成后去查看分析即可。

整个过程就像下面的动图:

《浅谈深度学习中超参数调整策略》

Photo by SigOpt

一个一个找,尝试就行了,可能某一天你睡觉起来,就会发现惊喜。

随机搜索

随机搜索就是利用分布函数来模拟随机数,然后利用随机数生成的参数来进行训练:

# 我们利用numpy中的随机数生成器来生成随机数
style_weights_rd = list(np.random.randint(0, 1000, size=20))
content_weights_rd = list(np.random.randint(0, 10, size=5))

同上面的参数一样,只不过换成了在特定范围的随机值,当然这个范围是我们自己定的。

然后将下面list换成随机list即可:

for i in range(len(content_weights_rd)):
    for j in range(len(style_weights_rd)):
        output = run_painterly_transfer(cnn, cnn_normalization_mean, cnn_normalization_std, style_img=style_image,
                                        content_img=content_image, mask_img=mask_image, tmask_img=tmask_image,
                                        style_weight=int(style_weights_rd[j]), content_weight=int(content_weights_rd[i]))

整个过程动图分析如下:

《浅谈深度学习中超参数调整策略》

Photo by SigOpt

在《Random Search for Hyper-Parameter Optimization》这篇论文中提高了为什么我们经常使用随机搜索而不是用网格,其实上面的图很形象了,那就是实际中适合的参数往往在一个完整分布中的一小块部分,我们使用网络搜索并不能保证直接搜索到合适的超参数中,而随机搜索则大大提高了找到合适参数的可能性。

《浅谈深度学习中超参数调整策略》

Photo by Bergstra, 2012

上图则表明重要参数和不重要的参数在不同方法下的搜索情况,我们给了两个超参数,网格搜索只能在我们设定的一小组范围内进行,而随机搜索中的每个超参数是独立的。也就是说网格搜索因为我们的设定,超参数之间是有些许联系的,并不是独一无二。研究表明随机搜索能够更快地减少验证集的误差。

下面的代码中,加入content_weight中的1和5对结果的影响不大,但是我们通过for循环组合,和style_weights中的所有值都进行了尝试了,显然浪费了时间。

style_weights = [0.1, 0.5, 1, 1.5, 2.5, 5, 10, 15, 20, 50, 100, 150, 200, 500, 1000,
                   5000, 10000, 50000, 100000, 500000, 1000000]
content_weights = [1, 5, 10, 100]

贝叶斯优化

这个优化方法,说白了就是让优化算法来对超参数进行优化,也就是说,这个优化算法的对象是超参数,然后结果是loss损失,通过求超参数对损失的梯度来实现对超参数的更新,呃,这个计算量真的很大很大,个人几乎不用这个方法,一般都是大企业才会用。通过学习来调节参数,这个结果真的是更加不可预知的。

《浅谈深度学习中超参数调整策略》

Photo by SigOpt

上面这个图大概描述了这个过程,当然这只是“好的那一面”的过程。

后记

复现、调参并不容易,其实很多论文中实现的效果看起来不错,但是实际上如果自己去复现是很难的。而且也有很多论文其实自身并没有复现,只是理论上的实现就可以发表,神经网络在调参中不确定性因素太多,玄学深度学习名副其实。最后再强调一遍,如果超参数足够多,训练一两个月都是有可能的。

所以说,路道阻且长。

Further reading

Hyperparameter optimization libraries (free and open source):

Hyperparameter optimization libraries (everybody’s favorite commerial library):

Implementation examples:

参考文献:

深度学习圣经

https://www.jeremyjordan.me/hyper-parameter-tuning/

  点赞
本篇文章采用 署名-非商业性使用-禁止演绎 4.0 国际 进行许可
转载请务必注明来源: https://oldpan.me/archives/hyper-parameters-tune-guide

   关注Oldpan博客微信公众号,你最需要的及时推送给你。


 猜你喜欢

  1. L
    LBA说道:

    你好!结果可视化的动态图和静态图程序能分享下吗 :lol: 感觉有点强人所难。我调了很久的参数,但是给老师讲解的时候调参结果没有说服力,之前只是将结果最好的参数展现出来,没有保存过程参数。为了节省时间,先粗调再微调的

    1. O
      Oldpan说道:

      这些图标了出处,并不是我画的。不过我知道这些图可以使用matplotlib来画,在随机搜索的时候,记录下相关的数据就行。