Рекуррентная сеть (RNN) не изучит очень простую функцию (графики показаны в вопросе) - PullRequest
0 голосов
/ 17 октября 2018

Итак, я пытаюсь обучить простую рекуррентную сеть для обнаружения "взрыва" во входном сигнале.На следующем рисунке показан входной сигнал (синий) и требуемый (классификационный) выход RNN, показанный красным.

Then end of the sine-shaped input signal burst should be detected.

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

После обучения на https://github.com/MorvanZhou/PyTorch-Tutorial/blob/master/tutorial-contents/403_RNN_regressor.py, Я не могу заставить RNN учиться.Изученный RNN всегда работает «без памяти», т. Е. Не использует память для своих предсказаний, как показано в следующем примере поведения:

The same plot as before, but this time with the output behavior of the network.

Зеленая линия показывает прогнозируемый выход сети. Что я делаю неправильно в этом примере, так что сеть не может быть изучена правильно? Разве сетевая задача не так проста?

Я использую:

  1. torch.nn.CrossEntropyLoss как функция потерь
  2. Оптимизатор Adam для обучения
  3. RNN с 16 внутренними / скрытыми узлами и 2 выходными узлами.Они используют функцию активации по умолчанию класса torch.RNN.

Эксперимент был повторен пару раз с разными случайными начальными числами, но разница в результатах незначительна.Я использовал следующий код:

import torch
import numpy, math
import matplotlib.pyplot as plt

nofSequences = 5
maxLength = 130

# Generate training data
x_np = numpy.zeros((nofSequences,maxLength,1))
y_np = numpy.zeros((nofSequences,maxLength))
numpy.random.seed(1)
for i in range(0,nofSequences):
    startPos = numpy.random.random()*50
    for j in range(0,maxLength):
        if j>=startPos and j<startPos+10:
            x_np[i,j,0] = math.sin((j-startPos)*math.pi/10)
        else:
            x_np[i,j,0] = 0.0
        if j<startPos+10:
            y_np[i,j] = 1
        else:
            y_np[i,j] = 0


# Define the neural network
INPUT_SIZE = 1
class RNN(torch.nn.Module):
    def __init__(self):
        super(RNN, self).__init__()

        self.rnn = torch.nn.RNN(
            input_size=INPUT_SIZE,
            hidden_size=16,     # rnn hidden unit
            num_layers=1,       # number of rnn layer
            batch_first=True,
        )
        self.out = torch.nn.Linear(16, 2)

    def forward(self, x, h_state):
        r_out, h_state = self.rnn(x, h_state)

        outs = []    # save all predictions
        for time_step in range(r_out.size(1)):    # calculate output for each time step
            outs.append(self.out(r_out[:, time_step, :]))
        return torch.stack(outs, dim=1), h_state

# Learn the network
rnn = RNN()
optimizer = torch.optim.Adam(rnn.parameters(), lr=0.01)
h_state = None      # for initial hidden state

x = torch.Tensor(x_np)    # shape (batch, time_step, input_size)
y = torch.Tensor(y_np).long()

torch.manual_seed(2)
numpy.random.seed(2)

for step in range(100):

    prediction, h_state = rnn(x, h_state)   # rnn output

    # !! next step is important !!
    h_state = h_state.data        # repack the hidden state, break the connection from last iteration

    loss = torch.nn.CrossEntropyLoss()(prediction.reshape((-1,2)),torch.autograd.Variable(y.reshape((-1,))))         # calculate loss
    optimizer.zero_grad()                   # clear gradients for this training step
    loss.backward()                         # backpropagation, compute gradients
    optimizer.step()                        # apply gradients

    errTrain = (prediction.max(2)[1].data != y).float().mean()
    print("Error Training:",errTrain.item())

Для тех, кто хочет воспроизвести эксперимент, график рисуется с использованием следующего кода (с использованием блокнота Jupyter):

steps = range(0,maxLength)
plotChoice = 3

plt.figure(1, figsize=(12, 5))
plt.ion()           # continuously plot

plt.plot(steps, y_np[plotChoice,:].flatten(), 'r-')
plt.plot(steps, numpy.argmax(prediction.detach().numpy()[plotChoice,:,:],axis=1), 'g-')
plt.plot(steps, x_np[plotChoice,:,0].flatten(), 'b-')

plt.ioff()
plt.show()

1 Ответ

0 голосов
/ 24 октября 2018

Из документации tourch.nn.RNN , RNN на самом деле является сетью Элмана, и имеют следующие свойства здесь .Выход сети Эльмана зависит только от скрытого состояния, в то время как скрытое состояние зависит от последнего входа и предыдущего скрытого состояния.

Поскольку мы установили «h_state = h_state.data», мы фактическииспользуйте скрытое состояние последней последовательности, чтобы предсказать первое состояние новой последовательности, что приведет к выводу, сильно зависящему от последнего вывода предыдущей последовательности (которое было 0).Сеть Элмана не может разделиться, если мы находимся в начале последовательности или в конце, она только «видит» состояние и последний ввод.

Чтобы исправить это, мы можем установить set «h_state = None»,Теперь каждая новая последовательность начинается с пустого состояния.Это приводит к следующему прогнозу (где зеленая линия снова показывает прогноз). enter image description here Теперь мы начинаем с 1, но быстро снижаемся до 0, прежде чем импульсы снова поднимают его вверх.Сеть Элмана может учитывать некоторую зависимость от времени, но она плохо запоминает долгосрочные зависимости и сходится к «наиболее распространенному выходу» для этого входа.

Поэтому, чтобы исправить эту проблему, я предлагаю использоватьсеть, которая хорошо известна благодаря хорошей обработке долгосрочных зависимостей, а именно, rnn Long краткосрочной памяти (LSTM), для получения дополнительной информации см. torch.nn.LSTM .Оставьте "h_state = None" и замените torch.nn.RNN на torch.nn.LSTM.

для получения полного кода и графика см. Ниже

import torch
import numpy, math
import matplotlib.pyplot as plt

nofSequences = 5
maxLength = 130

# Generate training data
x_np = numpy.zeros((nofSequences,maxLength,1))
y_np = numpy.zeros((nofSequences,maxLength))
numpy.random.seed(1)
for i in range(0,nofSequences):
    startPos = numpy.random.random()*50
    for j in range(0,maxLength):
        if j>=startPos and j<startPos+10:
            x_np[i,j,0] = math.sin((j-startPos)*math.pi/10)
        else:
            x_np[i,j,0] = 0.0
        if j<startPos+10:
            y_np[i,j] = 1
        else:
            y_np[i,j] = 0


# Define the neural network
INPUT_SIZE = 1
class RNN(torch.nn.Module):
    def __init__(self):
        super(RNN, self).__init__()

        self.rnn = torch.nn.LSTM(
            input_size=INPUT_SIZE,
            hidden_size=16,     # rnn hidden unit
            num_layers=1,       # number of rnn layer
            batch_first=True,
        )
        self.out = torch.nn.Linear(16, 2)

    def forward(self, x, h_state):
        r_out, h_state = self.rnn(x, h_state)

        outs = []    # save all predictions
        for time_step in range(r_out.size(1)):    # calculate output for each time step
            outs.append(self.out(r_out[:, time_step, :]))
        return torch.stack(outs, dim=1), h_state

# Learn the network
rnn = RNN()
optimizer = torch.optim.Adam(rnn.parameters(), lr=0.01)
h_state = None      # for initial hidden state

x = torch.Tensor(x_np)    # shape (batch, time_step, input_size)
y = torch.Tensor(y_np).long()

torch.manual_seed(2)
numpy.random.seed(2)

for step in range(100):

    prediction, h_state = rnn(x, h_state)   # rnn output

    # !! next step is important !!
    h_state = None        

    loss = torch.nn.CrossEntropyLoss()(prediction.reshape((-1,2)),torch.autograd.Variable(y.reshape((-1,))))         # calculate loss
    optimizer.zero_grad()                   # clear gradients for this training step
    loss.backward()                         # backpropagation, compute gradients
    optimizer.step()                        # apply gradients

    errTrain = (prediction.max(2)[1].data != y).float().mean()
    print("Error Training:",errTrain.item())


###############################################################################
steps = range(0,maxLength)
plotChoice = 3

plt.figure(1, figsize=(12, 5))
plt.ion()           # continuously plot

plt.plot(steps, y_np[plotChoice,:].flatten(), 'r-')
plt.plot(steps, numpy.argmax(prediction.detach().numpy()[plotChoice,:,:],axis=1), 'g-')
plt.plot(steps, x_np[plotChoice,:,0].flatten(), 'b-')

plt.ioff()
plt.show()

enter image description here

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