如何向PyTorch NN模型添加L1正则化?

4
当我在寻找在PyTorch模型中实现L1正则化的方法时,我发现了这个问题,它已经两年了,所以我想知道这个主题上是否有新的进展?
我还发现了这种最近的方法来处理缺失的l1函数。然而,我不知道如何将其用于下面显示的基本NN。
class FFNNModel(nn.Module):
    def __init__(self, input_dim, output_dim, hidden_dim, dropout_rate):
        super(FFNNModel, self).__init__()
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.hidden_dim = hidden_dim
        self.dropout_rate = dropout_rate
        self.drop_layer = nn.Dropout(p=self.dropout_rate)
        self.fully = nn.ModuleList()
        current_dim = input_dim
        for h_dim in hidden_dim:
            self.fully.append(nn.Linear(current_dim, h_dim))
            current_dim = h_dim
        self.fully.append(nn.Linear(current_dim, output_dim))

    def forward(self, x):
        for layer in self.fully[:-1]:
            x = self.drop_layer(F.relu(layer(x)))
        x = F.softmax(self.fully[-1](x), dim=0)
        return x

我希望只需在训练之前放置这个即可:

model = FFNNModel(30,5,[100,200,300,100],0.2)
regularizer = _Regularizer(model)
regularizer = L1Regularizer(regularizer, lambda_reg=0.1)

使用

out = model(inputs)
loss = criterion(out, target) + regularizer.__add_l1()

有人知道如何应用这些“即用型”类吗?


1
你可能想考虑将你的“编辑/简单解决方案”作为答案添加到问题中,而不是将其包含在问题主体中。 - iacob
这个回答解决了你的问题吗?Pytorch:如何给激活函数添加L1正则化? - iacob
1
请勿在问题中包含答案;请单独发布答案。 - desertnaut
4个回答

8
我还没有运行相关的代码,如果有什么问题请回头联系我。一般来说,我认为你提供的代码过于复杂(可能是因为它试图变得通用并允许所有以下种类的正则化)。我想它的使用方式应该是:
model = FFNNModel(30,5,[100,200,300,100],0.2)
regularizer = L1Regularizer(model, lambda_reg=0.1)

然后

out = model(inputs)
loss = criterion(out, target) + regularizer.regularized_all_param(0.)

你可以检查regularized_all_param函数将仅迭代模型参数,如果它们的名称以weight结尾,则将累加其绝对值之和。由于某种原因,需要手动初始化缓冲区,这就是为什么我们传入0.的原因。
但如果你希望高效地正则化L1并且不需要任何花哨的功能,那么类似于你第一个链接的更手动的方法将更易读。它会像这样进行。
l1_regularization = 0.
for param in model.parameters():
    l1_regularization += param.abs().sum()
loss = criterion(out, target) + l1_regularization

这实际上是两种方法的核心。您使用 Module.parameters 方法遍历所有模型参数,并总结它们的L1范数,然后将其作为损失函数中的一个项。就是这样。您提供的代码库使用一些花哨的机制来将其抽象化,但根据您的问题,似乎失败了 :)

1

如果你在这方面遇到问题,这里有一个简单的解决方案:

上面链接中的 Regularizer_ 类一直存在一些问题,所以我使用了常规函数来解决这个问题,并添加了一个正交的正则化器:

def l1_regularizer(model, lambda_l1=0.01):
    lossl1 = 0
    for model_param_name, model_param_value in model.named_parameters():
            if model_param_name.endswith('weight'):
                lossl1 += lambda_l1 * model_param_value.abs().sum()
    return lossl1    
        
def orth_regularizer(model, lambda_orth=0.01):
    lossorth = 0
    for model_param_name, model_param_value in model.named_parameters():
            if model_param_name.endswith('weight'):
                param_flat = model_param_value.view(model_param_value.shape[0], -1)
                sym = torch.mm(param_flat, torch.t(param_flat))
                sym -= torch.eye(param_flat.shape[0])
                lossorth += lambda_orth * sym.sum()
    return lossorth  

在训练期间执行以下操作:
loss = criterion(outputs, y_data)\
      +l1_regularizer(model, lambda_l1=lambda_l1)\
      +orth_regularizer(model, lambda_orth=lambda_orth)   

0
您可以使用以下代码将L1正则化应用于损失函数:
loss = loss_fn(outputs, labels)
l1_lambda = 0.001
l1_norm = sum(p.abs().sum() for p in model.parameters())

loss = loss + l1_lambda*l1_norm

来源:{{link1:使用PyTorch进行深度学习}}(8.5.2)


0

相当于您引用模块中过于复杂的正则化器代码:

l1_loss = lambda_reg * sum([weight.abs().sum()
  for name, weight in model.named_parameters()
   if name.endswith('weight')])
loss = criterion(out, target) + l1_loss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接