秦皇岛城乡住房建设厅网站,如何做自己的播报网站,腾讯企业邮箱入口网页版,设计网站app经过了大量炼丹的同学都知道#xff0c;超参数是一个非常玄乎的东西#xff0c;比如batch size#xff0c;学习率等#xff0c;这些东西的设定并没有什么规律和原因#xff0c;论文中设定的超参数一般都是靠经验决定的。但是超参数往往又特别重要#xff0c;比如学习率超参数是一个非常玄乎的东西比如batch size学习率等这些东西的设定并没有什么规律和原因论文中设定的超参数一般都是靠经验决定的。但是超参数往往又特别重要比如学习率如果设置了一个太大的学习率那么loss就爆了设置的学习率太小需要等待的时间就特别长那么我们是否有一个科学的办法来决定我们的初始学习率呢
在这篇文章中我会讲一种非常简单却有效的方法来确定合理的初始学习率。
学习率的重要性
目前深度学习使用的都是非常简单的一阶收敛算法梯度下降法不管有多少自适应的优化算法本质上都是对梯度下降法的各种变形所以初始学习率对深层网络的收敛起着决定性的作用下面就是梯度下降法的公式 这里 α 就是学习率如果学习率太小会导致网络loss下降非常慢如果学习率太大那么参数更新的幅度就非常大就会导致网络收敛到局部最优点或者loss直接开始增加如下图所示。 学习率的选择策略在网络的训练过程中是不断在变化的在刚开始的时候参数比较随机所以我们应该选择相对较大的学习率这样loss下降更快当训练一段时间之后参数的更新就应该有更小的幅度所以学习率一般会做衰减衰减的方式也非常多比如到一定的步数将学习率乘上0.1也有指数衰减等。
这里我们关心的一个问题是初始学习率如何确定当然有很多办法一个比较笨的方法就是从0.0001开始尝试然后用0.001每个量级的学习率都去跑一下网络然后观察一下loss的情况选择一个相对合理的学习率但是这种方法太耗时间了能不能有一个更简单有效的办法呢
一个简单的办法
Leslie N. Smith 在2015年的一篇论文“Cyclical Learning Rates for Training Neural Networks”中的3.3节描述了一个非常棒的方法来找初始学习率同时推荐大家去看看这篇论文有一些非常启发性的学习率设置想法。
这个方法在论文中是用来估计网络允许的最小学习率和最大学习率我们也可以用来找我们的最优初始学习率方法非常简单。首先我们设置一个非常小的初始学习率比如1e-5然后在每个batch之后都更新网络同时增加学习率统计每个batch计算出的loss。最后我们可以描绘出学习的变化曲线和loss的变化曲线从中就能够发现最好的学习率。
下面就是随着迭代次数的增加学习率不断增加的曲线以及不同的学习率对应的loss的曲线。 从上面的图片可以看到随着学习率由小不断变大的过程网络的loss也会从一个相对大的位置变到一个较小的位置同时又会增大这也就对应于我们说的学习率太小loss下降太慢学习率太大loss有可能反而增大的情况。从上面的图中我们就能够找到一个相对合理的初始学习率0.1。
之所以上面的方法可以work因为小的学习率对参数更新的影响相对于大的学习率来讲是非常小的比如第一次迭代的时候学习率是1e-5参数进行了更新然后进入第二次迭代学习率变成了5e-5参数又进行了更新那么这一次参数的更新可以看作是在最原始的参数上进行的而之后的学习率更大参数的更新幅度相对于前面来讲会更大所以都可以看作是在原始的参数上进行更新的。正是因为这个原因学习率设置要从小变到大而如果学习率设置反过来从大变到小那么loss曲线就完全没有意义了。
实现
上面已经说明了算法的思想说白了其实是非常简单的就是不断地迭代每次迭代学习率都不同同时记录下来所有的loss绘制成曲线就可以了。下面就是使用PyTorch实现的代码因为在网络的迭代过程中学习率会不断地变化而PyTorch的optim里面并没有把learning rate的接口暴露出来导致显示修改学习率非常麻烦所以我重新写了一个更加高层的包mxtorch借鉴了gluon的一些优点在定义层的时候暴露初始化方法支持tensorboard同时增加了大量的model zoo包括inceptionresnetv2resnext等等提供预训练权重model zoo参考于Cadene的repo。目前这个repo刚刚开始欢迎有兴趣的小伙伴加入我。
下面就是部分代码近期会把找学习率的代码合并到mxtorch中。这里使用的数据集是kaggle上的dog breed使用预训练的resnet50ScheduledOptim的源码点这里。 criterion torch.nn.CrossEntropyLoss()net model_zoo.resnet50(pretrainedTrue)net.fc nn.Linear(2048, 120) with torch.cuda.device(0): net net.cuda() basic_optim torch.optim.SGD(net.parameters(), lr1e-5)optimizer ScheduledOptim(basic_optim) lr_mult (1 / 1e-5) ** (1 / 100)lr []losses []best_loss 1e9for data, label in train_data: with torch.cuda.device(0): data Variable(data.cuda()) label Variable(label.cuda()) # forward out net(data) loss criterion(out, label) # backward optimizer.zero_grad() loss.backward() optimizer.step() lr.append(optimizer.learning_rate) losses.append(loss.data[0]) optimizer.set_learning_rate(optimizer.learning_rate lr_mult) if loss.data[0] best_loss: best_loss loss.data[0] if loss.data[0] 4 best_loss or optimizer.learning_rate 1.: break plt.figure()plt.xticks(np.log([1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1]), (1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1))plt.xlabel(‘learning rate’)plt.ylabel(‘loss’)plt.plot(np.log(lr), losses)plt.show()plt.figure()plt.xlabel(‘num iterations’)plt.ylabel(‘learning rate’)plt.plot(lr) one more thing
通过上面的例子我们能够有一个非常有效的方法寻找初始学习率同时在我们的认知中学习率的策略都是不断地做decay而上面的论文别出心裁提出了一种循环变化学习率的思想能够更快的达到最优解非常具有启发性推荐大家去阅读阅读。