训练 LSTM 以跟踪正弦波

数据挖掘 Python 深度学习 喀拉斯 lstm
2021-10-11 14:47:22

我正在 Keras 上试验(阅读:玩耍)LSTM。我想训练一个 LSTM 网络,以便它“跟踪”正弦波,也就是说,给定具有不同波长、相位和长度的正弦波,它会输出其余的波。从某种意义上说,一个多对多的问题。

我决定网络需要同时“跟踪” 5 个正弦波。我会生成随机正弦波并使用最后的 50 个数据点作为 NN 的所需输出。

我的代码如下:

from keras.models import Sequential
from keras.layers import LSTM, Dense, TimeDistributed,Lambda, Dropout
import numpy as np

model = Sequential()

model.add(LSTM(32, return_sequences=True, input_shape=(None, 5)))
model.add(Dropout(0.2))
model.add(LSTM(32, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(32, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(32, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(32, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(5, return_sequences=True))
model.add(Lambda(lambda x: x[:, -50:, :])) # Grab only the last 50 values



print(model.summary())

model.compile(loss='mean_squared_error',
              optimizer='adam')


def make_line(length):
    shift= np.random.random()
    wavelength = 5+10*np.random.random()
    a=np.arange(length)
    answer=np.sin(a/wavelength+shift)
    return answer




def make_data(seq_num,seq_len,dim):
    data=np.array([]).reshape(0,seq_len,dim)
    for i in range (seq_num):
        mini_data=np.array([]).reshape(0,seq_len)
        for j in range (dim):
            line = make_line(seq_len)
            line=line.reshape(1,seq_len)            
            mini_data=np.append(mini_data,line,axis=0)
        mini_data=np.swapaxes(mini_data,1,0)
        mini_data=mini_data.reshape(1,seq_len,dim)      
        data=np.append(data,mini_data,axis=0)
    return (data)



def train_generator():
    while True:
        sequence_length = np.random.randint(50, 150)+50     
        data=make_data(1000,sequence_length,5)
        x_train = data[:,:-50,:] # all but last 50      
        y_train = (data[:, -50:, :]) # last 50      
        yield x_train, y_train


model.fit_generator(train_generator(), steps_per_epoch=30, epochs=100, verbose=1,validation_data=train_generator(),validation_steps=30)
model.save('vi2h_model.h5')

然后我尝试生成数据并使用模型来预测正弦波的延续:

def data_generator():
    while True:
        sequence_length = np.random.randint(50, 150)+50
        data=make_data(1000,sequence_length,5)
        x_train = data[:,:-50,:]    
        y_train = (data[:, -50:, :])                
        return x_train, y_train


x,y= data_generator()   

model = load_model('vi2h_model.h5')
pred=model.predict (x)
np.save ('pred.npy',pred)
np.save ('y.npy',y)
np.save ('x.npy',x)

在检查网络预测正弦波延续的能力时(例如,比较 y[0,:,0] 和 pred[0,:,0],以便比较第一个生成数据的第一个正弦波),看到我的网络表现非常糟糕:

样本正弦波中预测的与实际的 50 个最后点,放置在用作 NN 输入的波形部分之后

(编辑:图例:样本正弦波(分别为蓝色和橙色)中预测的与实际的 50 个最后点,放置在用作 NN 输入的波部分之后)

我做错了什么?我的代码应该如何正确跟踪正弦波?非常感谢!

1个回答

我在网络中添加了一个密集层:

模型=顺序()

model.add(LSTM(32, return_sequences=True, input_shape=(None, 5)))
model.add(Dropout(0.2))
model.add(LSTM(32, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(32, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(32, return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(32, return_sequences=True))
model.add(Dropout(0.2))
model.add(TimeDistributed(Dense(5)))  # <--- This is new :)
model.add(Activation('linear')) 
model.add(Lambda(lambda x: x[:, -50:, :])) # Grab only the last 50 values

这提供了一些改进:

在此处输入图像描述

这是两个正弦波以及它们最后 50 个数据点的预测。可以看出,结果有所改善,其中一些是正弦波的近似值。其他时候……没那么多。

还是比之前的成绩好很多。

然后我尝试了另一种方法:我没有使用一个(多层)LSTM,在其中我忽略了除 50 个输入之外的所有输入(从某种意义上说,试图从最后 50 个值中的每一个中预测位于它之后 50 个位置的值......可能不是一种理想的方法)我将网络分成 2 个 LSTM,其中一个接收输入并通过密集层将其结果“注入”到生成输出的第二个 LTSM 层。

features_num=5 

model.add(LSTM(40, return_sequences=True, input_shape=(None, 5)))
model.add(LSTM(40, return_sequences=False))

model.add(Dense(80))
model.add(Activation('tanh')) 
model.add(RepeatVector(50)) # 50 output points

model.add(LSTM(40, return_sequences=True))
model.add(LSTM(40, return_sequences=True))

model.add(TimeDistributed(Dense(features_num)))
model.add(Activation('linear')) 

在大多数情况下,结果会更好: 在此处输入图像描述