Простая модель Pytorch не улучшается - PullRequest
2 голосов
/ 22 сентября 2019

Я делаю простую нейронную сеть PyTorch для аппроксимации функции синуса на x = [0, 2pi].Это простая архитектура, которую я использую с различными библиотеками глубокого обучения, чтобы проверить, понимаю ли я, как ее использовать или нет.Нейронная сеть, если она не обучена, всегда создает прямую горизонтальную линию, а при обучении - прямую линию при y = 0. В общем, она всегда вырабатывает прямую линию при y = (среднее значение функции).Это приводит меня к мысли, что с передней частью пропора что-то не так, поскольку граница не должна быть просто прямой линией, когда она не обучена.Вот код для сети:

class Net(nn.Module):
    def __init__(self):
      super(Net, self).__init__()
      self.model = nn.Sequential(
      nn.Linear(1, 20),
      nn.Sigmoid(),
      nn.Linear(20, 50),
      nn.Sigmoid(),
      nn.Linear(50, 50),
      nn.Sigmoid(),
      nn.Linear(50, 1)
      )

    def forward(self, x):
        x = self.model(x)
        return x

Вот тренировочный цикл

def train(net, trainloader, valloader, learningrate, n_epochs):
    net = net.train()
    loss = nn.MSELoss()
    optimizer = torch.optim.SGD(net.parameters(), lr = learningrate)

    for epoch in range(n_epochs):

        for X, y in trainloader:
            X = X.reshape(-1, 1)
            y = y.view(-1, 1)
            optimizer.zero_grad()

            outputs = net(X)

            error   = loss(outputs, y)
            error.backward()
            #net.parameters()  net.parameters() * learningrate
            optimizer.step()

        total_loss = 0
        for X, y in valloader:
            X = X.reshape(-1, 1).float()
            y = y.view(-1, 1)
            outputs = net(X)
            error   = loss(outputs, y)
            total_loss += error.data

        print('Val loss for epoch', epoch, 'is', total_loss / len(valloader) )

он называется:

net = Net()
losslist = train(net, trainloader, valloader, .0001, n_epochs = 4)

Где Trainloader и Valloader являютсяобучение и валидация грузчиков.Может кто-нибудь помочь мне понять, что с этим не так?Я знаю, что это не скорость обучения, поскольку я использую ее в других средах, и я знаю, что я не использую функции активации SGD или сигмоида, хотя у меня есть подозрение, что ошибка в функциях активации где-то.

Кто-нибудь знает, как это исправить?Спасибо.

Ответы [ 2 ]

1 голос
/ 22 сентября 2019

Как правило, он всегда выдает прямую линию при y = (среднее значение функции).

Обычно это означает, что NN успешно обучил только последний слой, поэтомудалеко.Вам нужно тренировать его дольше или с лучшими оптимизациями, как показывает ViniciusArruda.

Редактировать: Чтобы объяснить дальше. Когда обучен только последний слой, NN эффективно пытается угадать выход y сничего не известно о входных данных X. В этом случае наилучшим предположением, которое он может сделать, является среднее значение.Таким образом, он может минимизировать потери MSE.

1 голос
/ 22 сентября 2019

Через некоторое время, играя с некоторыми гиперпараметрами, модифицируя сеть и меняя оптимизатор (следуя этому отличному рецепту), я закончил с изменением строки optimizer = torch.optim.SGD(net.parameters(), lr = learningrate) на optimizer = torch.optim.Adam(net.parameters()) ( по умолчанию)* Использовался параметр оптимизатора , для 100 эпох и размера пакета, равного 1.

Использовался следующий код (проверено только на процессоре):

import torch
import torch.nn as nn
from torch.utils import data
import numpy as np
import matplotlib.pyplot as plt

# for reproducibility
torch.manual_seed(0)
np.random.seed(0)

class Dataset(data.Dataset):

    def __init__(self, init, end, n):

        self.n = n
        self.x = np.random.rand(self.n, 1) * (end - init) + init
        self.y = np.sin(self.x)

    def __len__(self):

        return self.n

    def __getitem__(self, idx):

        x = self.x[idx, np.newaxis]
        y = self.y[idx, np.newaxis]

        return torch.Tensor(x), torch.Tensor(y)


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.model = nn.Sequential(
        nn.Linear(1, 20),
        nn.Sigmoid(),
        nn.Linear(20, 50),
        nn.Sigmoid(),
        nn.Linear(50, 50),
        nn.Sigmoid(),
        nn.Linear(50, 1)
        )

    def forward(self, x):
        x = self.model(x)
        return x

def train(net, trainloader, valloader, n_epochs):

    loss = nn.MSELoss()
    # Switch the two following lines and run the code
    # optimizer = torch.optim.SGD(net.parameters(), lr = 0.0001)
    optimizer = torch.optim.Adam(net.parameters())

    for epoch in range(n_epochs):

        net.train()
        for x, y in trainloader:
            optimizer.zero_grad()
            outputs = net(x).view(-1)
            error   = loss(outputs, y)
            error.backward()
            optimizer.step()

        net.eval()
        total_loss = 0
        for x, y in valloader:
            outputs = net(x)
            error   = loss(outputs, y)
            total_loss += error.data

        print('Val loss for epoch', epoch, 'is', total_loss / len(valloader) )    

    net.eval()

    f, (ax1, ax2) = plt.subplots(1, 2, sharey=True)

    def plot_result(ax, dataloader):
        out, xx, yy = [], [], []
        for x, y in dataloader:
            out.append(net(x))
            xx.append(x)
            yy.append(y)
        out = torch.cat(out, dim=0).detach().numpy().reshape(-1)
        xx = torch.cat(xx, dim=0).numpy().reshape(-1)
        yy = torch.cat(yy, dim=0).numpy().reshape(-1)
        ax.scatter(xx, yy, facecolor='green')
        ax.scatter(xx, out, facecolor='red')
        xx = np.linspace(0.0, 3.14159*2, 1000)
        ax.plot(xx, np.sin(xx), color='green')

    plot_result(ax1, trainloader)
    plot_result(ax2, valloader)
    plt.show()


train_dataset = Dataset(0.0, 3.14159*2, 100)
val_dataset = Dataset(0.0, 3.14159*2, 30)

params = {'batch_size': 1,
          'shuffle': True,
          'num_workers': 4}

trainloader = data.DataLoader(train_dataset, **params)
valloader = data.DataLoader(val_dataset, **params)

net = Net()
losslist = train(net, trainloader, valloader, n_epochs = 100)        

Результат с Адамомоптимизатор: enter image description here

Результат с оптимизатором SGD: enter image description here

...