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

Posted

技术标签:

【中文标题】如何将 L1 正则化添加到 PyTorch NN 模型?【英文标题】:How to add L1 Regularization to PyTorch NN Model? 【发布时间】:2020-01-30 00:02:47 【问题描述】:

在寻找在 PyTorch 模型中实现 L1 正则化的方法时,我遇到了 this question,它现在已经 2 岁了,所以我想知道这个主题是否有什么新东西?

我还发现this recent approach 处理丢失的 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()

有人了解如何应用这些“即用型”类吗?

【问题讨论】:

您可能需要考虑将您的 "EDIT / SIMPLE SOLUTION" 添加为问题的答案,而不是将其包含在问题正文中。 这能回答你的问题吗? Pytorch: how to add L1 regularizer to activations? 请不要在问题中包含答案;而是发布一个单独的答案。 【参考方案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)   

【讨论】:

【参考方案2】:

您可以使用以下代码将 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

来源:Deep Learning with PyTorch (8.5.2)

【讨论】:

【参考方案3】:

我还没有运行有问题的代码,所以如果有问题,请回复。通常,我会说您链接的代码不必要地复杂(可能是因为它试图通用并允许以下所有类型的正则化)。我想它的使用方式是

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 是否将仅iterate 覆盖您模型的参数,如果它们的名称以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 范数,然后成为损失函数中的一个术语。而已。您链接的 repo 提供了一些花哨的机制来抽象它,但是从您的问题来看,它失败了:)

【讨论】:

以上是关于如何将 L1 正则化添加到 PyTorch NN 模型?的主要内容,如果未能解决你的问题,请参考以下文章

如何在pytorch中获取自定义损失函数的权重?

正则化之L1和L2已经dropout的一些理解和pytorch代码实现与效果证明

Tensorflow:批归一化和l1l2正则化

Tensorflow:批归一化和l1l2正则化

Tensorflow:批归一化和l1l2正则化

Tensorflow:批归一化和l1l2正则化