Регулятор L1 Pytorch действует противоположно тому, что я ожидаю - PullRequest
1 голос
/ 18 марта 2020

Я пытаюсь добавить штраф L1 к указанному c слою нейронной сети, и у меня есть код ниже (в котором я пытаюсь добавить штраф l1 к первому слою). Если я запускаю его для лямбда = 0 (то есть без штрафа), результат будет очень близок к ожидаемому весу, который равен [10, 12, 2, 11, -0,25]), и если я бегу в течение достаточного количества эпох или уменьшаю размер пакета, его получит его точно так, как показано ниже:

mlp.0.weight

Параметр, содержащий:

тензор ([[9.8657, -11.8305, 2.0242 , 10.8913, -0.1978]], require_grad = True)

Затем, когда я запускаю его для большой лямбды, скажем, 1000, я ожидаю, что эти веса уменьшатся до нуля, поскольку существует большой штраф быть добавленным к потере, которую мы пытаемся минимизировать. Однако происходит обратное, и веса взрываются, как показано ниже (для lam = 1000)

mlp.0.weight

Параметр, содержащий:

тензор ([[- 13,9368, 9,9072, 2,2447, -11,6870, 26,7293]], require_grad = True)

Если бы кто-нибудь мог мне помочь, это было бы здорово. Я новичок в pytorch (но не в идее регуляризации), поэтому я предполагаю, что проблема в моем коде.

Спасибо

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
import numpy as np
from sklearn.linear_model import LinearRegression


class TrainDataset(Dataset):
    def __init__(self, data):
        self.data = data
    def __len__(self):
        return self.data.shape[0]
    def __getitem__(self, ind):
        x = self.data[ind][1:]
        y = self.data[ind][0]
        return x, y


class TestDataset(TrainDataset):
    def __getitem__(self, ind):
        x = self.data[ind]
        return x


torch.manual_seed(94)

x_train = np.random.rand(1000, 5)
y_train = x_train[:, 0] * 10 - x_train[:, 1] * 12 + x_train[:, 2] * 2 + x_train[:, 3] * 11 - x_train[:, 4] * 0.25
y_train = y_train.reshape(1000, 1)
x_train.shape
y_train.shape
train_data = np.concatenate((y_train, x_train), axis=1)



train_set = TrainDataset(train_data)




batch_size = 100
train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True)


class MLP(nn.Module):
    def __init__(self):
        super(MLP, self).__init__()
        self.mlp = nn.Sequential(nn.Linear(5, 1, bias=False))

    def forward(self, x_mlp):
        out = self.mlp(x_mlp)
        return out


device = 'cpu'

model = MLP()

optimizer = torch.optim.SGD(model.parameters(), lr=0.02, momentum=0.82)

criterion = nn.MSELoss()

epochs = 5
lam = 0
model.train()

for epoch in range(epochs):
    losses = []
    for batch_num, input_data in enumerate(train_loader):
        optimizer.zero_grad()

        x, y = input_data
        x = x.to(device).float()
        y = y.reshape(batch_size, 1)
        y = y.to(device)

        output = model(x)
        for name, param in model.named_parameters():
            if name == 'mlp.0.weight':
                l1_norm = torch.norm(param, 1)

        loss = criterion(output, y) + lam * l1_norm
        loss.backward()

        optimizer.step()
        print('\tEpoch %d | Batch %d | Loss %6.2f' % (epoch, batch_num, loss.item()))


for name, param in model.named_parameters():
    if param.requires_grad:
        print(name)
        print(param)

1 Ответ

0 голосов
/ 18 марта 2020

Я обнаружил, что если я использую Adagrad в качестве оптимизатора вместо SGD, он будет работать как положено. Нужно будет разобраться в разнице тех, кто сейчас, но это можно считать ответом.

...