使用 LSTM 预测具有非零特征值的步长比例

数据挖掘 分类 喀拉斯 lstm rnn 顺序
2022-02-16 17:34:19

我正在尝试对序列进行简单的回归。每个输入Xi是一个n=2000由 1 个矩阵,格式化为ni0-s 后跟(nni)1秒。输出yi应该ni/n,即具有非零特征值的步长的比例。

生成数据的代码

ns = [1087, 280, 1013, 300, 311, 260, 960, 281, 417, 311, 102, 251, 748, 428, 802, 512, 61, 80, 1700, 693, 147, 577, 280, 196, 377, 281, 88, 359, 250, 330, 679, 201, 284, 1129, 151, 285, 722, 1014, 153, 202, 256, 99, 661, 415, 134, 269, 196, 137, 436, 617]
Xs = np.array([[[0] for i in range(2000-x)]+[[1] for i in range(x)] for x in ns])
Ys = np.mean(Xs,axis=(1,2))
trainX, testX, trainY, testY = Xs[:45], Xs[45:], Ys[:45], Ys[45:]

我尝试使用 LSTM 和输出层进行预测,即

model = Sequential()
model.add(Masking(mask_value=0.00, input_shape=(trainX.shape[1],trainX.shape[2])))
model.add((LSTM(10,activation='tanh',unit_forget_bias=True,input_shape=(trainX.shape[1],trainX.shape[2]))))
model.add(Dense(1,activation='relu'))
model.compile(optimizer=adam(),loss='mse',metrics=['mae'],)
model.fit(trainX,trainY,epochs=50,validation_data=(testX,testY),verbose=1)

然而我发现该模型无法预测我想要什么,而是预测每个序列几乎相同y价值。只是想知道是否有任何解决方案可以解决这个问题?

1个回答

首先,您的数据太少50 个样品。想想看。在所有可能的 2001 种此类序列中,您只喂了 50 个(不到 2.5%)。您的问题实际上是一个很好的案例,可以说明大数据对于训练神经网络的重要性。

其次,这是Uber 员工发表的这篇 arxiv 文章中所述的问题——即使是具有非线性单元的深度神经网络也常常无法泛化为简单线性问题的解决方案。

您的问题仍然可以通过以下方式大致解决

  1. 减少批量大小

众所周知,增加批量大小会导致更快但更差的收敛。特别是在您的情况下,您应该使用以下行:

model.fit(trainX,trainY,epochs=50,validation_data=(testX,testY),verbose=1,
    batch_size=1,
    shuffle=True)

代替

model.fit(trainX,trainY,epochs=50,validation_data=(testX,testY),verbose=1)

即使知道它会slooooow...

  1. 修改 LSTM 层:删除和添加具有小增益unit_forget_bias=True的正交初始化器-在本文中进行了解释
from keras.initializers import orthogonal
model.add(LSTM(10, activation='tanh', #unit_forget_bias=True,
    kernel_initializer=orthogonal(gain=.01),
))
  1. 增加所有可能样本空间的覆盖率

在下面的代码中SEQ_LEN=2000N_SAMPLES=50是您的情况。在这里,我们生成随机序列,就像您上面的代码一样(尽管与您的序列不同)。现在,尝试使用值SEQ_LEN=200N_SAMPLES=80然后SEQ_LEN=200N_SAMPLES=130看看N_SAMPLES<SEQ_LEN/2你的网络是否完全收敛,而在第二种情况下它会!


import numpy as np

SEQ_LEN = 2000
N_SAMPLES = 50
n_test_samples = int(.1*N_SAMPLES)
if N_SAMPLES>SEQ_LEN+1: raise ValueError("Can't create more samples of this type than SEQ_LEN+1 is.")
ns = np.random.randint(0,SEQ_LEN,size=(N_SAMPLES,))
all_Xs = np.triu ( np.ones(shape=(SEQ_LEN+1,SEQ_LEN)) )
np.random.shuffle(all_Xs)

Xs = all_Xs[:N_SAMPLES, ...]
Ys = Xs.mean(axis=1)
Xs = Xs.reshape(N_SAMPLES, SEQ_LEN, -1)
trainX, testX, trainY, testY = Xs[:-n_test_samples], Xs[-n_test_samples:], Ys[:-n_test_samples], Ys[-n_test_samples:]

import tensorflow # To prevent
import tensorflow as tf # to declarations to prevent cryptic errors on my Windows laptop

from keras import Sequential
from keras.layers import Masking, LSTM, Dense
from keras.optimizers import adam
from keras.initializers import orthogonal
from keras.layers import Flatten

model = Sequential()
model.add(Masking(mask_value=0.00, input_shape=(trainX.shape[1],trainX.shape[2])))
model.add(LSTM(10, activation='tanh', #unit_forget_bias=True,
    input_shape=(trainX.shape[1],trainX.shape[2]),
    kernel_initializer=orthogonal(gain=.01),
))
model.add(Dense(1,activation='relu'))
model.compile(optimizer=adam(),loss='mse',metrics=['mae'])
model.fit(trainX,trainY,epochs=50,validation_data=(testX,testY),verbose=1,
    batch_size=1,
    shuffle=True)

testY_PRED = model.predict(testX)
print (np.concatenate(( testY_PRED, testY.reshape(-1,1)), axis=1) )

我还测试了 300 个样本和 500 个序列长度(收敛)的案例。但是,测试网络是否会收敛是相当长SEQ_LEN=2000的时间,比如说N_SAMPES=1200(不要希望它会收敛N_SAMPLES=50)——这取决于你 :)