Итак, я пытаюсь обучить простую рекуррентную сеть для обнаружения "взрыва" во входном сигнале.На следующем рисунке показан входной сигнал (синий) и требуемый (классификационный) выход RNN, показанный красным.
Итак, выходсеть должна переключаться с 1 на 0 всякий раз, когда пакет обнаружен, и оставаться таким же, как на этом выходе.Единственное, что изменяется между входными последовательностями, используемыми для обучения RNN, - это то, на каком временном шаге происходит взрыв.
После обучения на https://github.com/MorvanZhou/PyTorch-Tutorial/blob/master/tutorial-contents/403_RNN_regressor.py, Я не могу заставить RNN учиться.Изученный RNN всегда работает «без памяти», т. Е. Не использует память для своих предсказаний, как показано в следующем примере поведения:
Зеленая линия показывает прогнозируемый выход сети. Что я делаю неправильно в этом примере, так что сеть не может быть изучена правильно? Разве сетевая задача не так проста?
Я использую:
- torch.nn.CrossEntropyLoss как функция потерь
- Оптимизатор Adam для обучения
- 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()