Как реализовать полиномиальную регрессию в Pytorch / Python - PullRequest
1 голос
/ 30 апреля 2019

Я хочу, чтобы моя нейронная сеть решала проблему полиномиальной регрессии, например, y = (x * x) + 2x -3.

Итак, сейчас я создал сеть с 1 входным узлом, 100 скрытыми узлами и 1 выходным узлом и дал ему много эпох для обучения с большим объемом тестовых данных. Проблема в том, что прогноз после примерно 20000 эпох вполне нормален, но намного хуже, чем прогноз линейной регрессии после тренировки.

import torch
from torch import Tensor
from torch.nn import Linear, MSELoss, functional as F
from torch.optim import SGD, Adam, RMSprop
from torch.autograd import Variable
import numpy as np


# define our data generation function
def data_generator(data_size=1000):
    # f(x) = y = x^2 + 4x - 3
    inputs = []
    labels = []

    # loop data_size times to generate the data
    for ix in range(data_size):
        # generate a random number between 0 and 1000
        x = np.random.randint(1000) / 1000

        # calculate the y value using the function x^2 + 4x - 3
        y = (x * x) + (4 * x) - 3

        # append the values to our input and labels lists
        inputs.append([x])
        labels.append([y])

    return inputs, labels


# define the model
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = Linear(1, 100)
        self.fc2 = Linear(100, 1)


    def forward(self, x):
        x = F.relu(self.fc1(x)
        x = self.fc2(x)
        return x


model = Net()
# define the loss function
critereon = MSELoss()
# define the optimizer
optimizer = SGD(model.parameters(), lr=0.01)

# define the number of epochs and the data set size
nb_epochs = 20000
data_size = 1000

# create our training loop
for epoch in range(nb_epochs):
    X, y = data_generator(data_size)
    X = Variable(Tensor(X))
    y = Variable(Tensor(y))


    epoch_loss = 0;


    y_pred = model(X)

    loss = critereon(y_pred, y)

    epoch_loss = loss.data
    optimizer.zero_grad()

    loss.backward()

    optimizer.step()

    print("Epoch: {} Loss: {}".format(epoch, epoch_loss))

# test the model
model.eval()
test_data = data_generator(1)
prediction = model(Variable(Tensor(test_data[0][0])))
print("Prediction: {}".format(prediction.data[0]))
print("Expected: {}".format(test_data[1][0]))

Есть ли способ добиться лучших результатов? Я задавался вопросом, должен ли я попытаться получить 3 выхода, назовите их a, b и c так, чтобы y = a (x * x) + b (x) + c. Но я понятия не имею, как реализовать это и обучить мою нейронную сеть.

1 Ответ

0 голосов
/ 30 апреля 2019

Для этой проблемы может быть намного проще, если вы рассматриваете Net() со слоем 1 Linear как Linear Regression с входными функциями, включающими [x^2, x].

Генерация данных

import torch
from torch import Tensor
from torch.nn import Linear, MSELoss, functional as F
from torch.optim import SGD, Adam, RMSprop
from torch.autograd import Variable
import numpy as np

# define our data generation function
def data_generator(data_size=1000):
    # f(x) = y = x^2 + 4x - 3
    inputs = []
    labels = []

    # loop data_size times to generate the data
    for ix in range(data_size):
        # generate a random number between 0 and 1000
        x = np.random.randint(2000) / 1000 # I edited here for you

        # calculate the y value using the function x^2 + 4x - 3
        y = (x * x) + (4 * x) - 3

        # append the values to our input and labels lists
        inputs.append([x*x, x])
        labels.append([y])

    return inputs, labels

Определите вашу модель

# define the model
class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = Linear(2, 1)

    def forward(self, x):
        return self.fc1(x)

model = Net()

Затем обучите ее, мы получим:

Epoch: 0 Loss: 33.75775909423828
Epoch: 1000 Loss: 0.00046704441774636507
Epoch: 2000 Loss: 9.437128483114066e-07
Epoch: 3000 Loss: 2.0870876138445738e-09
Epoch: 4000 Loss: 1.126847400112485e-11
Prediction: 5.355223655700684
Expected: [5.355224999999999]

Коэффициенты

Коэффициенты a, b,c Вы ищете, на самом деле вес и уклон self.fc1:

print('a & b:', model.fc1.weight)
print('c:', model.fc1.bias)

# Output
a & b: Parameter containing:
tensor([[1.0000, 4.0000]], requires_grad=True)
c: Parameter containing:
tensor([-3.0000], requires_grad=True)

Всего за 5000 эпох все сходятся: a -> 1, b -> 4,и c -> -3.

Модель такая легкая, всего 3 параметра вместо:

(100 + 1) + (100 + 1) = 202 parameters in the old model

Надеюсь, это поможет вам!

...