Проблема с Pytorch и полиномиальной линейной регрессией

Я изменил код, который я нашел в Pytorch github, в соответствии с моими данными, но мои результаты потерь огромны, и с каждой итерацией они становятся больше, а затем становятся nan. Код не дает мне никаких ошибок, ни результатов потерь, ни предсказания. У меня есть другой код, который работает с простой линейной регрессией, и все работает нормально. Думаю, мне здесь не хватает чего-то простого, но я не вижу этого. любая помощь будет оценена.

Код:

import sklearn.linear_model as lm
from sklearn.preprocessing import PolynomialFeatures
import torch
import torch.autograd
import torch.nn.functional as F
from torch.autograd import Variable


train_data = torch.Tensor([
   [40,  6,  4],
   [44, 10,  4],
   [46, 12,  5],
   [48, 14,  7],
   [52, 16,  9],
   [58, 18, 12],
   [60, 22, 14],
   [68, 24, 20],
   [74, 26, 21],
   [80, 32, 24]])
test_data = torch.Tensor([
    [6, 4],
    [10, 5],
    [4, 8]])

x_train = train_data[:,1:3]
y_train = train_data[:,0]

POLY_DEGREE = 3
input_size = 2
output_size = 1

poly = PolynomialFeatures(input_size * POLY_DEGREE, include_bias=False)
x_train_poly = poly.fit_transform(x_train.numpy())


class Model(torch.nn.Module):

    def __init__(self):
        super(Model, self).__init__()
        self.fc = torch.nn.Linear(poly.n_output_features_, output_size)
                
    def forward(self, x):
        return self.fc(x)
            
model = Model()    
criterion = torch.nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.001)

losses = []

for i in range(10):
    optimizer.zero_grad()
    outputs = model(Variable(torch.Tensor(x_train_poly)))
    print(outputs)
    loss = criterion(outputs, Variable(y_train))
    print(loss.data[0])
    losses.append(loss.data[0])
    loss.backward()    
    optimizer.step()
    if loss.data[0] < 1e-4:
        break    

print('n_iter', i)
print(loss.data[0])
plt.plot(losses)
plt.show()

вывод:

[393494300459008.0, inf, inf, inf, nan, nan, nan, nan, nan, nan]

n_iter

9 нан


person kuatroka    schedule 14.03.2017    source источник


Ответы (1)


Есть несколько вещей, которые усугубляют проблему. Изменение некоторых или всех из них даст вам разумные результаты и сделает обучение возможным.

  1. Некоторые из ваших (полиномиальных) характеристик имеют огромную дисперсию и принимают очень большие значения. Проверьте np.max(x_train_poly). Когда ваша весовая матрица инициализируется случайным образом, это приводит к тому, что первоначальные прогнозы в значительной степени ошибаются, а потери быстро приближаются к бесконечности. Чтобы противодействовать этому, вы можете сначала стандартизировать свои функции (т.е. сделать среднее значение 0 и дисперсию 1 для каждой функции). Обратите внимание, что в очень глубоких сетях используется аналогичная идея, называемая «Пакетная нормализация». Если вам интересно, вы можете прочитать больше здесь: https://arxiv.org/abs/1502.03167 Вы можете сделать следующее, чтобы исправить свой пример:

    means = np.mean(x_train_poly,axis=0,keepdims=True)
    std = np.std(x_train_poly,axis=0,keepdims=True)
    x_train_poly = (x_train_poly - means) / std
    
  2. Ваша текущая модель не имеет скрытых слоев, что является своего рода точкой нейронной сети и построением нелинейного регрессора / классификатора. Что вы делаете прямо сейчас, так это применяете линейное преобразование к 27 входным функциям, чтобы получить что-то, что близко к выходным. Вы можете добавить такой дополнительный слой:

    hidden_dim = 50
    
    class Model(torch.nn.Module):
        def __init__(self):
            super(Model, self).__init__()
            self.layer1 = torch.nn.Linear(poly.n_output_features_, hidden_dim)
            self.layer2 = torch.nn.Linear(hidden_dim, output_size)
    
        def forward(self, x):
            return self.layer2(torch.nn.ReLU()(self.layer1(x)))
    

    Обратите внимание, что я добавил нелинейность после первого линейного преобразования, потому что иначе нет смысла иметь несколько слоев.

  3. Проблема исходных прогнозов, которые вначале сильно ошибочны и приводят к приближающимся к бесконечности потерям. Вы используете квадрат потерь, который по существу удваивает порядок вашей начальной «ошибки» в функции потерь. И как только потеря станет бесконечной, вы не сможете убежать, потому что обновления градиента, по сути, также бесконечны, поскольку вы используете квадрат потерь. Простое исправление, которое иногда бывает полезно, - использовать вместо этого плавные потери L1. По сути, MSE на интервале [0, 1] и потеря L1 за пределами этого интервала. Измените следующее:

    criterion = torch.nn.SmoothL1Loss()
    
  4. Это уже приводит вас к чему-то разумному (то есть к исчезновению информации), но теперь подумайте о настройке скорости обучения и введении weight_decay. Вы также можете изменить оптимизатор. Некоторые предложения, которые работают нормально:

    optimizer = torch.optim.SGD(model.parameters(), lr=0.01, weight_decay=1)
    optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=0.1)
    
person mbpaulus    schedule 10.06.2017