class L1(torch.nn.Module):
def __init__(self, module, weight_decay):
super().__init__()
self.module = module
self.weight_decay = weight_decay
# Backward hook is registered on the specified module
self.hook = self.module.register_full_backward_hook(self._weight_decay_hook)
# Not dependent on backprop incoming values, placeholder
def _weight_decay_hook(self, *_):
for param in self.module.parameters():
# If there is no gradient or it was zeroed out
# Zeroed out using optimizer.zero_grad() usually
# Turn on if needed with grad accumulation/more safer way
# if param.grad is None or torch.all(param.grad == 0.0):
# Apply regularization on it
param.grad = self.regularize(param)
def regularize(self, parameter):
# L1 regularization formula
return self.weight_decay * torch.sign(parameter.data)
def forward(self, *args,**kwargs):
# Simply forward and args and kwargs to module
return self.module(*args,**kwargs)
阅读更多关于钩子in this answer或相应的PyTorch文档(如果需要)。 用法也很简单(应适用于梯度累积和PyTorch层):
7条答案
按热度按时间f1tvaqid1#
使用
weight_decay > 0
进行L2正则化:fgw7neuy2#
请参阅文档。将
weight_decay
参数添加到优化器以进行L2正则化。ifsvaxew3#
以前的答案虽然在技术上是正确的,但在性能方面效率低下,而且模块化程度不高(很难按层应用,例如
keras
层)。PyTorch L2实现
为什么PyTorch在
torch.optim.Optimizer
示例中实现了L2
?让我们来看一下
torch.optim.SGD
的源代码(目前作为函数优化程序),特别是这部分:d_p
(参数梯度的导数)被修改并重新分配,以加快计算速度(不保存临时变量)O(N)
的复杂性,而没有任何类似pow
的复杂数学运算*它不涉及
autograd
扩展图,无需任何需要将其与
O(n)
**2
操作进行比较,加法和反向传播也参与其中。数学
让我们看看
alpha
正则化因子的L2
方程(对于L1 ofc也可以这样做):如果我们对具有
L2
正则化的任何损失对参数w
求导(它与损失无关),我们得到:**因此,它只是一个简单的添加
alpha * weight
梯度的每一个权重!**这正是PyTorch所做的上面!L1规则化层
使用这个函数(以及一些PyTorch魔法),我们可以得到非常通用的L1正则化层,但让我们先看一下
L1
的一阶导数(sgn
是正负号函数,对于正输入返回1
,对于负输入返回-1
,对于0
返回0
):带有
WeightDecay
接口的完整代码位于torchlayers第三方库中,提供仅对权重/偏差/特定命名参数进行正则化等内容(免责声明:我是作者),但其思想的实质概述如下(见注解):阅读更多关于钩子in this answer或相应的PyTorch文档(如果需要)。
用法也很简单(应适用于梯度累积和PyTorch层):
便笺
此外,作为一个侧记,
L1
正则化没有实现,因为它实际上不会导致稀疏(丢失引用,这是PyTorch repo上的一些GitHub问题,我想,如果有人有,请编辑),正如权重等于零所理解的。更常见的情况是,如果权重值达到某个较小的预定义幅度(例如
0.001
),则对权重值设置阈值(简单地为其分配零值)xytpbqjk4#
对于L2正则化,
参考文献:
l5tcr1uw5#
现成的L2正则化
是的,pytorch optimizers有一个称为
weight_decay
的参数,它对应于L2正则化因子:L1正则化实现
L1没有类似的参数,但手动实现起来很简单:
L2的等效手动实现为:
数据源:Deep Learning with PyTorch(8.5.2)
ykejflvf6#
对于L1正则化,仅包括
weight
:krugob8w7#
有趣的是,与直接方法相比,
torch.norm
在CPU上速度较慢,在GPU上速度较快。输出:
另一方面:
输出: