почему моя модель Pytorch не соответствует данным должным образом? - PullRequest
0 голосов
/ 20 октября 2019

Я использую Pytorch для решения простой задачи регрессии. то, что я пытаюсь сделать, может показаться немного сложным. Итак, у меня есть две модели: грубая модель и модель разности. Я знаю, что моя простая проблема регрессии может быть решена с использованием только одной модели, но я изучаю, как уменьшить ошибку моделей регрессии нейронной сети, и именно поэтому я использую эту сложную архитектуру. Архитектура состоит из двух MLP, первая называется грубая модель и предназначена для изучения отношений ввода-вывода, и ее на самом деле должно быть достаточно для изучения и подгонки данных, а также для создания хороших прогнозов, но я добавляю дополнительную нейронную сеть, называемую моделью различий. который должен изучить отношение ошибок входных данных и добавить эти дополнительные знания обратно в грубую модель. Я знаю, что это может быть сложно понять, поэтому я напишу несколько шагов здесь, как работает моя Архитектура:

1. Обучите грубую Модель
2. Получите предсказания грубой Модели, назовем ее y_coarse

3. Рассчитать грубую ошибку модели (не MSE. Я просто вычисляю здесь отклонения прогнозов модели по истинным целевым значениям), другими словами, я делаю y_true - coarse_predictions

4. Обучите модель разности (входные данные - те же входные данные, что и у грубой модели, но здесь вывод - ошибка, которую я вычислил на шаге 3

. 5. Получите прогнозы модели разности, назовем ее y_diff * 1010. *

6. окончательные прогнозы были бы y_coarse + y_diff

смысл всего этого - получить более точные прогнозы в конце, добавив отклонение, полученное с помощью разностной модели, к предсказаниям грубой моделиПреимущество заключается в том, что такая архитектура может обеспечить лучшие прогнозы для зашумленных данных, но у меня была проблема с реализациейОб этом в Pytorch. Тренировка грубой модели хороша, и я получаю хорошие результаты, но тренировка модели различий дает странные результаты, модель разности nn не соответствует данным об ошибках. Я пытался настроить гиперпараметры, но без шансов. вот мой код:

from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.utils.data import TensorDataset, DataLoader

# create random dataset for regression

dataset = make_regression(n_samples=1000, n_features=1, noise=3, random_state=0)
X, y = dataset
# implementation using pytorch

# transform data to Tensors and split testset and validation set
y = y.reshape(-1, 1)
print(X.shape, y.shape)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, test_size=0.2)
X_train_torch = torch.from_numpy(X_train.astype(np.float32))
y_train_torch = torch.from_numpy(y_train.astype(np.float32))
X_test_torch = torch.from_numpy(X_test.astype(np.float32))
y_test_torch = torch.from_numpy(y_test.astype(np.float32))

# normalize data
X_train_torch = (X_train_torch - torch.mean(X_train_torch)) / torch.std(X_train_torch)
X_test_torch = (X_test_torch - torch.mean(X_test_torch)) / torch.std(X_test_torch)

print(X_train_torch.shape, y_train_torch.shape)


# create a TensorDataset from the actual dataset
coarse_trainset = TensorDataset(X_train_torch, y_train_torch)
coarse_testset = TensorDataset(X_test_torch, y_test_torch)

# create the loader of the dataset
coarse_train_loader = DataLoader(coarse_trainset, batch_size=32, shuffle=True)
coarse_test_loader = DataLoader(coarse_testset, batch_size=32, shuffle=False)


# definition of the Coarse Model
class CoarseModel(nn.Module):
    """main neural network to learn input/position relationship"""
    def __init__(self, n_features, n_hidden, n_out):
        super().__init__()
        self.fc1 = nn.Linear(n_features, n_hidden)
        self.fc2 = nn.Linear(n_hidden, n_out)

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

# definition of the Difference Model
class DifferenceModel(nn.Module):
    """difference model to enhance accuracy via predicting input/error relationship"""
    def __init__(self, n_features, n_hidden, n_out):
        super().__init__()
        self.fc1 = nn.Linear(n_features, n_hidden)
        self.fc2 = nn.Linear(n_hidden, n_out)

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


coarse_model = CoarseModel(X.shape[1], 10, 1)


# training function => will perform a single training step given a batch
def training_func(model, criterion, optimizer):
    def train_step(sample, target):
        model.train()
        optimizer.zero_grad()
        out = model(sample)
        loss = criterion(out, target)
        loss.backward()
        optimizer.step()
        return loss.item()
    return train_step


# fit function will train the given Model over defined epochs 
def fit(epochs, model, lr, train_loader, test_loader):
    criterion = nn.MSELoss()
    optimizer = optim.SGD(model.parameters(), lr=lr, momentum=0.9)
    train_losses, test_losses, accuracy_list = ([] for _ in range(3))
    train = training_func(model=model, criterion=criterion, optimizer=optimizer)
    for e in range(epochs):
        for x, y in train_loader:
            loss_val = train(x, y)
            train_losses.append(loss_val)

        else:
            with torch.no_grad():
                model.eval()
                for x_test, y_test in test_loader:
                    pred = model(x_test)
                    loss = criterion(pred, y_test)
                    test_losses.append(loss.item())
                    accuracy = r2_score(y_test.numpy(), pred.numpy())
                    accuracy_list.append(accuracy)

        print(f"Epoch: {e} => average training loss= {sum(train_losses)/ len(train_losses)} average test losses= {sum(test_losses)/ len(test_losses)} and accuracy={sum(accuracy_list)/ len(accuracy_list)}")

    return train_losses, test_losses, accuracy_list


# plot the results of the training and testing loss values over the iterations
def plot_results(train_losses, test_losses, accs):
    plt.plot(train_losses, color="b")
    plt.title("train losses over time")
    plt.show()
    plt.plot(test_losses, color= "b")
    plt.title("test losses over time")
    plt.show()
    plt.plot(accs, color= "b")
    plt.title("accuracy over time")
    plt.show()


# train the Coarse Model
train_losses, test_losses, accs = fit(epochs=1000, 
                                      model=coarse_model, 
                                      lr=1e-4, 
                                      train_loader=coarse_train_loader, 
                                      test_loader=coarse_test_loader)

plot_results(train_losses, test_losses, accs)
print("final train loss value = ", train_losses[-1])
print("final test loss value = ", test_losses[-1])
print("final accuracy of the model => ", accs[-1])

#### and now I train the difference Model, My problem is that this Model is not fitting the data #####
# training process of the Difference Model: => the desired value is the difference between the desired output and the the coarse Model Predictions
diff_model = DifferenceModel(X.shape[1], 10, 1)
y_coarse =  coarse_model(X_train_torch)  
y_coarse = y_coarse.detach()     # y_coarse: predictions of the Coarse Model
d_coarse = y_train_torch.detach()    # d_coarse: desired Coarse Model output
d_diff_train = d_coarse - y_coarse    # d_diff: desired difference Model output

y_coarse_test =  coarse_model(X_test_torch)  
y_coarse_test = y_coarse_test.detach()     # y_coarse: predictions of the Coarse Model
d_coarse_test = y_test_torch.detach()    # d_coarse: desired Coarse Model output
d_diff_test = d_coarse_test - y_coarse_test    # d_diff: desired difference Model output


diff_trainset = TensorDataset(X_train_torch, d_diff_train)
diff_testset = TensorDataset(X_test_torch, d_diff_test)

diff_train_loader = DataLoader(diff_trainset, batch_size=32, shuffle=True)
diff_test_loader = DataLoader(diff_testset, batch_size=32, shuffle=False)

train_losses, test_losses, accs = fit(epochs=1000, model=diff_model, lr=1e-3, train_loader=diff_train_loader, test_loader=diff_test_loader)
plot_results(train_losses, test_losses, accs)
print("final train loss value = ", train_losses[-1])
print("final test loss value = ", test_losses[-1])
print("final accuracy = ", accs[-1])

Я также использую этот код для тестирования всей Модели и сравнения целых прогнозов с грубым прогнозом модели:

with torch.no_grad():
    coarse_model.eval()
    diff_model.eval()
    criterion = nn.MSELoss()
    coarse_preds = coarse_model(X_test_torch)
    diff_model_preds = diff_model(X_test_torch)
    y_final = coarse_preds + diff_model_preds

    coarse_loss = criterion(coarse_preds, y_test_torch)
#     diff_model_loss = criterion(diff_model_preds, y_test_torch)
    y_final_loss = criterion(y_final, y_test_torch)

    print(f"coarse Model loss = {coarse_loss.item()} / Final Loss = {y_final_loss.item()}")
    coarse_score = r2_score(y_test_torch.detach().numpy(), coarse_preds.numpy())
    y_final_score = r2_score(y_test_torch.detach().numpy(), y_final.numpy())

    print(f"coarse Model score = {coarse_score} / y_final score = {y_final_score}")

, который вы можете запуститькод на google colab , чтобы вы могли получить то, что я точно хочу сделать. Самое странное, что если я прокомментирую coarse_model, модель различий сможет соответствовать данным и даст хорошие прогнозы, но когда я раскомментирую coarse_model, тогда модель различий потеряет способность соответствовать данным. как вы видите, я сначала нормализовал данные, поэтому не знаю, почему это происходит. Когда я использую каждую модель по отдельности, она работает как шарм, но если я объединю их таким образом, то модель различий не может соответствовать данным. кто-нибудь знает почему? Я надеюсь, что объяснил это достаточно хорошо, я знаю, что это немного сложно обойти, я надеюсь, что кто-то здесь может помочь мне с этим. Заранее спасибо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...