训练深度神经网络时调参经验
训练深度神经网络时调参经验
1.如果损失一直比较大,且降不下去,就是说模型在训练集和测试集上的结果都比较差
可以尝试从以下三个方面入手:
(1)损失函数
如果是回归任务的损失函数有:
优先选择SmoothL1Loss
函数
下面公式中的N
可以看做是batch size
一般是传入数据的第一个纬度,n
可以看做是一个batch size
中的元素个数,可以看下面的代码更为清晰
SmoothL1 损失函数 |
---|
torch.nn.SmoothL1Loss (size_average=None, reduce=None, reduction='mean', beta=1.0) 在某些情况下可以防止梯度爆炸 |
![]() |
L1Loss 损失函数 |
![]() |
MSELoss 损失函数 |
二范数的平方 |
![]() |
关于损失函数中的reduction
参数有三个选择:
import torch.nn as nn
loss1 = nn.MSELoss(reduction='sum')
loss2 = nn.L1Loss(reduction='none')
loss3 = nn.SmoothL1Loss() # 默认是mean
input = torch.ones(2, 2, 2)*2
input.requires_grad = True
target = torch.zeros(2, 2, 2)
output1 = loss1(input, target)
output2 = loss2(input, target)
output3 = loss3(input, target)
print('sum:{}\nnone:{}\nmean:{}'.format(output1, output2, output3))
"""
sum:32.0
none:tensor([[[2., 2.],
[2., 2.]],
[[2., 2.],
[2., 2.]]], grad_fn=<L1LossBackward>)
mean:1.5 ## 由于2-0大于1,所以计算结果是|2-0|-0.5*1=1.5,一共8个元素,均值也是1.5
"""
(2)优化器 optimizer
优化器是用来更新传入的网络参数的(根据计算出来的参数梯度),注意如果参数需要放在GPU
上,应该在构建优化器前,就将参数放到GPU
上
一般选择Adam优化器,有时候会比SGD好很多
Adam |
---|
torch.optim.Adam (params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False, *, foreach=None, maximize=False) |
![]() |
SGD |
torch.optim.SGD (params, lr= |
![]() |
(3)网络模型的复杂度
有可能是欠拟合引起的,也就是说模型复杂度不够,可以增加网络深度。比如刚开始用的torchvision.models.resnet18(pretrained=True)
,可以增加到resnet101
或者152
等等,就是这样一个思路。
2.训练损失为nan
很有可能是梯度爆炸引起的网络输出值超出可控范围,导致输出值很离谱,这样损失函数计算时就为nan
可以尝试通过减小学习率来解决,这样梯度很大时,我们的参数变化也不会那么大