I see several problems with your code. Your value for look_back is 1, which means that LSTM sees only one pattern at a time, which is clearly not enough to learn anything about the sequence.
You probably did it so that in the end you could make the final prediction, submitting the prediction from the previous step as a new input. To fix this, you need to train with a lot of timestamps, and then switch to the network on LSTM with one type of time.
In addition, when you make the final prediction, you need to show the network more than one sample of the first truth. Otherwise, the position on the sine is ambiguous. (does it go up or down in the next step?)
I hit quickly. This is how I created the data:
import numpy as np numSamples = 1000 numTimesteps = 50 width = np.pi/2.0 def getRandomSine(numSamples = 100, width = np.pi): return np.sin(np.linspace(0,width,numSamples) + (np.random.rand()*np.pi*2)) trainX = np.stack([getRandomSine(numSamples = numTimesteps+1) for _ in range(numSamples)]) valX = np.stack([getRandomSine(numSamples = numTimesteps+1) for _ in range(numSamples)]) trainX = trainX.reshape((numSamples,numTimesteps+1,1)) valX = valX.reshape((numSamples,numTimesteps+1,1)) trainY = trainX[:,1:,:] trainX = trainX[:,:-1,:] valY = valX[:,1:,:] valX = valX[:,:-1,:]
Here I trained the model:
import keras from keras.models import Sequential from keras import layers model = Sequential() model.add(layers.recurrent.LSTM(32,return_sequences=True,input_shape=(numTimesteps, 1))) model.add(layers.recurrent.LSTM(32,return_sequences=True)) model.add(layers.wrappers.TimeDistributed(layers.Dense(1,input_shape=(1,10)))) model.compile(loss='mean_squared_error', optimizer='adam') model.summary() model.fit(trainX, trainY, nb_epoch=50, validation_data=(valX, valY), batch_size=32)
And here I modified the trained model to continue the prediction:
# serialize the model and get its weights, for quick re-building config = model.get_config() weights = model.get_weights() config[0]['config']['batch_input_shape'] = (1, 1, 1) config[0]['config']['stateful'] = True config[1]['config']['stateful'] = True from keras.models import model_from_config new_model = Sequential().from_config(config) new_model.set_weights(weights)
Here is the result. Prediction errors add up and diverge very quickly from the input sine. But he clearly recognized the general shape of the sinuses. Now you can try to improve this by trying different levels, activating functions, etc. 