在Pytorch中,如何将L1正则化器添加到激活中?

时间:2017-06-20 00:39:12

标签: python pytorch

(pytorch初学者)

我想将L1正则化器添加到ReLU的激活输出中。 更一般地说,如何仅将规则化器添加到网络中的特定层?

这篇文章可能有关:    Adding L1/L2 regularization in PyTorch? 然而要么它没有关联,要么我不明白答案:

它指的是在优化中应用的L2正则化器,这是另一回事。 换句话说,如果总体期望损失是

crossentropy + lambda1*L1(layer1) + lambda2*L1(layer2) + ...

我相信提供给torch.optim.Adagrad的参数仅适用于交叉熵损失。 或者它可能适用于整个网络的所有参数(权重)。但无论如何 它似乎不允许将正则化器应用于单层激活, 并且不提供L1损失。

另一个相关主题是nn.modules.loss,其中包含L1Loss()。 从文档中,我还不知道如何使用它。

最后,有一个模块https://github.com/pytorch/pytorch/blob/master/torch/legacy/nn/L1Penalty.py似乎最接近目标,但它被称为" legacy"。那是为什么?

5 个答案:

答案 0 :(得分:9)

以下是您执行此操作的方法:

  • 在模块的正向返回最终输出和要为其应用L1正则化的图层输出
  • loss变量将是输出w.r.t的交叉熵损失之和。目标和L1处罚。

这是一个示例代码

import torch
from torch.autograd import Variable
from torch.nn import functional as F


class MLP(torch.nn.Module):
    def __init__(self):
        super(MLP, self).__init__()
        self.linear1 = torch.nn.Linear(128, 32)
        self.linear2 = torch.nn.Linear(32, 16)
        self.linear3 = torch.nn.Linear(16, 2)

    def forward(self, x):
        layer1_out = F.relu(self.linear1(x))
        layer2_out = F.relu(self.linear2(layer1_out))
        out = self.linear3(layer2_out)
        return out, layer1_out, layer2_out

batchsize = 4
lambda1, lambda2 = 0.5, 0.01

model = MLP()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-4)

# usually following code is looped over all batches 
# but let's just do a dummy batch for brevity

inputs = Variable(torch.rand(batchsize, 128))
targets = Variable(torch.ones(batchsize).long())

optimizer.zero_grad()
outputs, layer1_out, layer2_out = model(inputs)
cross_entropy_loss = F.cross_entropy(outputs, targets)

all_linear1_params = torch.cat([x.view(-1) for x in model.linear1.parameters()])
all_linear2_params = torch.cat([x.view(-1) for x in model.linear2.parameters()])
l1_regularization = lambda1 * torch.norm(all_linear1_params, 1)
l2_regularization = lambda2 * torch.norm(all_linear2_params, 2)

loss = cross_entropy_loss + l1_regularization + l2_regularization
loss.backward()
optimizer.step()

答案 1 :(得分:3)

所有(其他当前)响应在某种程度上都不正确。 This one最接近,因为它建议对输出的范数求和,这是正确的,但是代码对权重的范数求和,这是不正确的。

正确的方法不是修改网络代码,而是像mkdir foo && cd $_ 类一样,通过前向挂钩捕获输出。从那里开始,对输出范数的求和很简单,但是每次迭代都需要注意清除捕获的输出。

OutputHook

答案 2 :(得分:2)

@Sasank Chilamkurthy 正则化应该是模型每一层的加权参数,而不是每一层的输出。请看下面: Regularization

import torch
from torch.autograd import Variable
from torch.nn import functional as F


class MLP(torch.nn.Module):
    def __init__(self):
        super(MLP, self).__init__()
        self.linear1 = torch.nn.Linear(128, 32)
        self.linear2 = torch.nn.Linear(32, 16)
        self.linear3 = torch.nn.Linear(16, 2)
    def forward(self, x):
        layer1_out = F.relu(self.linear1(x))
        layer2_out = F.relu(self.linear2(layer1_out))
        out = self.linear3(layer2_out)
        return out

batchsize = 4
lambda1, lambda2 = 0.5, 0.01

model = MLP()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-4)

inputs = Variable(torch.rand(batchsize, 128))
targets = Variable(torch.ones(batchsize).long())
l1_regularization, l2_regularization = torch.tensor(0), torch.tensor(0)

optimizer.zero_grad()
outputs = model(inputs)
cross_entropy_loss = F.cross_entropy(outputs, targets)
for param in model.parameters():
    l1_regularization += torch.norm(param, 1)
    l2_regularization += torch.norm(param, 2)

loss = cross_entropy_loss + l1_regularization + l2_regularization
loss.backward()
optimizer.step()

答案 3 :(得分:2)

我认为原始帖子希望对ReLU的输出进行正则化,因此正则化器应位于输出中,而不是网络的权重。他们不一样!

  • 具有l1范数的正则化权重正在训练具有稀疏权重的神经网络

  • 使用l1-norm规范化层的输出正在训练网络具有该特定层的稀疏输出。

以上这些答案(包括已接受的答案)都没有提出要点,或者我误解了最初的帖子问题。

答案 4 :(得分:1)

您可以使用以下代码将模型单层权重的 L1 正则化 my_layer 应用于损失函数:

def l1_penalty(params, l1_lambda=0.001):
    """Returns the L1 penalty of the params."""
    l1_norm = sum(p.abs().sum() for p in params)
    return l1_lambda*l1_norm

loss = loss_fn(outputs, labels) + l1_penalty(my_layer.parameters())