深度学习调参笔记#1-正则化(weight decay)

本文最后更新于:2022年7月21日 下午

深度学习调参笔记#1-正则化(weight decay)

在模型过拟合的时候,总是会想着添加正则化,在PyTorch中常用的添加正则化的方法,就是在优化器中添加weight_decay参数,然而,调参过程中也有一些细节需要注意。

首先要弄明白正则化的目的,《深度学习》书的第七章中提到,正则化旨在减少泛化误差而不是训练误差,其中最常用的一个方式就是参数范数惩罚。这个方法简单来说就是在损失函数中添加一项αΩ(θ)\alpha\Omega(\theta)α\alpha表示惩罚强度、Ω(θ)\Omega(\theta)表示模型的复杂度。添加这个之后,就会倾向于学习更简单的网络。

要注意的点就是,通常只对权重(weight)做惩罚而不对偏置(bias)做正则惩罚。过拟合实际上是模型对于轻微的输入改变,产生剧烈的输出改变,而输出结果主要取决于权重而不是偏置,所以权重的L2更能起到表示模型复杂度的作用。偏置对模型复杂度贡献较低,但是对最终结果有一定影响,假如惩罚了偏置,可能会导致欠拟合。

Overfitted_Data

那么在PyTorch中如何只对权重做惩罚呢?

参考yolov5代码,下面为了排版有部分删减:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
g = [], [], []  # optimizer parameter groups
bn = tuple(v for k, v in nn.__dict__.items() if 'Norm' in k) # normalization layers, i.e. BatchNorm2d()
for v in model.modules():
if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter):
g[2].append(v.bias) # 所有偏置不decay
if isinstance(v, bn):
g[1].append(v.weight) # 权重中Normalization层不decay
elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter):
g[0].append(v.weight) # 除此以外的才decay

if opt.optimizer == 'Adam': # adjust beta1 to momentum
optimizer = Adam(g[2], lr=hyp['lr0'], betas=(hyp['momentum'], 0.999))
elif opt.optimizer == 'AdamW': # adjust beta1 to momentum
optimizer = AdamW(g[2], lr=hyp['lr0'], betas=(hyp['momentum'], 0.999))

optimizer.add_param_group({'params': g[0], 'weight_decay':hyp['weight_decay']}) # add g0 with weight_decay
optimizer.add_param_group({'params': g[1]}) # add g1 (BatchNorm2d weights)

也可以参考MAE代码,使用timm库的一个函数来设置(新版本有改动,没对应函数了)

1
2
3
4
5
6
import timm
assert timm.__version__ == "0.3.2" # version check
import timm.optim.optim_factory as optim_factory
# following timm: set wd as 0 for bias and norm layers
param_groups = optim_factory.add_weight_decay(model_without_ddp, args.weight_decay)
optimizer = torch.optim.AdamW(param_groups, lr=args.lr, betas=(0.9, 0.95))

timm中每一层的weight_decay还不一样:pytorch-image-models/optim_factory.py at master · rwightman/pytorch-image-models (github.com)

参考资料:

《深度学习》

深度学习里面的偏置为什么不加正则? - 知乎 (zhihu.com)