- 要理解学习率是什么,首先得弄明白神经网络参数更新的机制-梯度下降+反向传播,这里默认读者已经有这些概念基础了。
- 学习率是一个非常非常重要的超参数,这个参数呢,面对不同规模、不同batch-size、不同优化方式、不同数据集,其最合适的值都是不确定的,我们无法光凭经验来准确地确定lr的值,我们唯一可以做的,就是在训练中不断寻找最合适当前状态的学习率。
-
比如下图利用fastai中的lr_find()函数寻找合适的学习率,根据下方的学习率-损失曲线得到此时合适的学习率为1e-1。
他是通过在训练的过程中将不同的学习率得到的损失loss的值记录下来,可视化展示之后纵轴是训练的loss,横轴是学习率,于是可以直观的看到 最佳的学习率为1e-1。
寻找学习率函数
#寻找学习率
def find_lr(init_value = 1e-8, final_value=10., beta = 0.98):
num = len(trn_loader)-1
mult = (final_value / init_value) ** (1/num)
lr = init_value
optimizer.param_groups[0]['lr'] = lr
avg_loss = 0.
best_loss = 0.
batch_num = 0
losses = []
log_lrs = []
for data in trn_loader:
batch_num += 1
#As before, get the loss for this mini-batch of inputs/outputs
inputs,labels = data
inputs, labels = Variable(inputs), Variable(labels)
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
#Compute the smoothed loss
avg_loss = beta * avg_loss + (1-beta) *loss.item()
smoothed_loss = avg_loss / (1 - beta**batch_num)
#Stop if the loss is exploding
if batch_num > 1 and smoothed_loss > 4 * best_loss:
return log_lrs, losses
#Record the best loss
if smoothed_loss < best_loss or batch_num==1:
best_loss = smoothed_loss
#Store the values
losses.append(smoothed_loss)
log_lrs.append(math.log10(lr))
#Do the SGD step
loss.backward()
optimizer.step()
#Update the lr for the next step
lr *= mult
optimizer.param_groups[0]['lr'] = lr
return log_lrs, losses
定义网络:
- 这个地方用选取的最佳学习率重新进行计算会发现比原本的第一轮训练正确率更高
logs,losses = find_lr()
plt.plot(logs[10:-5],losses[10:-5])
net = SimpleNeuralNet(28*28,100,10)
optimizer = optim.SGD(net.parameters(),lr=1e-1)
>>
Epoch 1:
Loss: 0.5872366683165232 Accuracy: 85.20333099365234
Epoch 1:
Loss: 0.2632665414134661 Accuracy: 92.31999969482422
learning-rate与batch-size的关系
- 一般来说,越大的batch-size使用越大的学习率。
原理很简单,越大的batch-size意味着我们学习的时候,收敛方向的confidence越大,我们前进的方向更加坚定,而小的batch-size则显得比较杂乱,毫无规律性,因为相比批次大的时候,批次小的情况下无法照顾到更多的情况,所以需要小的学习率来保证不至于出错。 - 在显存足够的条件下,最好采用较大的batch-size进行训练,找到合适的学习率后,可以加快收敛速度。另外,较大的batch-size可以避免batch normalization出现的一些小问题