一、Sateful参数介绍
在Keras调用LSTM的参数中,有一个stateful参数,默认是False,也就是无状态模式stateless,为True的话就是有状态模式stateful,所以这里我们就归为两种模式:
有状态模型(stateful LSTM)
无状态模型(stateless LSTM)
那两者到底是什么区别呢,怎么使用呢?
二、区别
stateful LSTM
除了正常的单个sample内部时间步之间的状态互相传递外(这个是LSTM的基本功能),sample之间的状态还能互相传递。但是需要确定batch_size大小,传递的时候是前一个batch的第i个sample最终输出状态,传递给后一个batch的第i个sample,作为其状态的初始化值。以“解放军第72集团军某旅500名抗洪子弟兵撤离安徽铜陵枞阳县,赶赴合肥庐江县继续抗洪。当地百姓冒着大雨追着驶出的车辆,递上自家的莲蓬、葡萄、熟鸡蛋等食物,送别子弟兵。”为例子,第一句话为一个sample,第二句话为第二个sample,每个sample内部的word为一个时间步,很明显前后两个sample是相互关联的。如果设置batch_size=1,则第一句话最终输出状态(即最后一个word的状态输出),就可以传递给第二句话作为其初始状态值。
优点:后面的语句有了更合理的初始化状态值,显然会加快网络的收敛,所以需要更小的网络、更少的训练时间。
缺点:每一个epoch后,要重置一下状态,因为训练一遍了,状态不能循环使用,要从头开始。
使用注意事项:调用fit() 时指定 shuffle = False,要保证sample之间的前后顺序;可以使用 model.reset_states()来重置模型中所有层的状态,也可使用layer.reset_states()来重置指定有状态 RNN 层的状态。
stateless LSTM
stateless就是与stateful相反了,就是sample之间没有前后状态传递的关系,输入samples后,默认就会shuffle,可以说是每个sample独立,适合输入一些没有关系的样本。
三、问答
1、在Keras中stateless LSTM中的stateless指的是?
注意,此文所说的stateful是指的在Keras中特有的,是batch之间的记忆cell状态传递。而非说的是LSTM论文模型中表示那些记忆门,遗忘门,c,h等等在同一sequence中不同timesteps时间步之间的状态传递。假定我们的输入X是一个三维矩阵,shape = (nb_samples, timesteps, input_dim),每一个row代表一个sample,每个sample都是一个sequence小序列。X[i]表示输入矩阵中第i个sample。步长啥的我们先不用管。当我们在默认状态stateless下,Keras会在训练每个sequence小序列(=sample)开始时,将LSTM网络中的记忆状态参数reset初始化(指的是c,h而并非权重w),即调用model.reset_states()。
2、为啥stateless LSTM每次训练都要初始化记忆参数?
因为Keras在训练时会默认地shuffle samples,所以导致sequence之间的依赖性消失,sample和sample之间就没有时序关系,顺序被打乱,这时记忆参数在batch、小序列之间进行传递就没意义了,所以Keras要把记忆参数初始化。
四、代码举例
通过对cos函数的预测来分别对比stateless和stateful的差别
1、 单层无状态LSTM模型(序列长度为20)
importnumpy as npfrom keras.models importSequentialfrom keras.layers importDense, LSTM, Dropoutimportmatplotlib.pyplot as plt#创建数据集,每隔50个就是一个整Π,围绕Π的系数不断变化
dataset = np.cos(np.arange(1000)*(20*np.pi/1000))#dataset的值域再-1~1之间。
#转换数据为LSTM输入格式: dataset matrix
def create_dataset(dataset, look_back=1):
dataX, dataY=[], []for i in range(len(dataset)-look_back):
dataX.append(dataset[i:(i+look_back)])
dataY.append(dataset[i+look_back])returnnp.array(dataX), np.array(dataY)#20长度的滑动窗口进行预测
look_back = 20
#归一化,y值域为(0,1)
dataset = (dataset+1) / 2.#split into train and test sets
train_size = int(len(dataset) * 0.8)
test_size= len(dataset) -train_size
train, test=dataset[:train_size], dataset[train_size:]
trainX, trainY=create_dataset(train, look_back)
testX, testY=create_dataset(test, look_back)print(trainX.shape)print(trainY.shape)
trainX= np.reshape(trainX, (trainX.shape[0], trainX.shape[1], 1))
testX= np.reshape(testX, (testX.shape[0], testX.shape[1], 1))'''trainX.shape = (780, 20, 1)
testX.shape = (180, 20, 1)
trainY.shape = (780,)
testY.shape = (180,)'''
#构建无状态LSTM模型
batch_size = 1model=Sequential()
model.add(LSTM(32, input_shape=(20, 1)))
model.add(Dropout(0.2))
model.add(Dense(1))
model.compile(loss= 'mse', optimizer = 'adam')
model.fit(trainX,trainY,batch_size= batch_size,epochs=30, verbose=2)#从训练集的最后一个sample样本截取后面的19个+y值得1个,构成一个新的sample(20,1),来预测一个值,其实这个值就是测试集的第一个值,
x = np.vstack((trainX[-1][1:],(trainY[-1])))#vstack就是竖着拼起来
preds=[]
pred_num= 500
for i innp.arange(pred_num):#重新转换成适合lstm的格式,并进行预测
pred = model.predict(x.reshape((1,-1,1)),batch_size =batch_size)
preds.append(pred.squeeze())
x= np.vstack((x[1:],pred))#横坐标就是1~500
plt.figure(figsize=(12,5))
plt.plot(np.arange(pred_num),np.array(preds),'r',label='predctions')
cos_y= (np.cos(np.arange(pred_num)*(20*np.pi/1000))+1)/ 2.
plt.plot(np.arange(pred_num),cos_y,label='origin')
plt.legend()
plt.show()
2、单层有状态LSTM模型(序列长度为40)
#单层有状态 LSTM network#创建数据集,每隔50个就是一个整Π,围绕Π的系数不断变化
dataset = np.cos(np.arange(1000)*(20*np.pi/1000))#dataset的值域再-1~1之间。
#转换数据为LSTM输入格式: dataset matrix
def create_dataset(dataset, look_back=1):
dataX, dataY=[], []for i in range(len(dataset)-look_back):
dataX.append(dataset[i:(i+look_back)])
dataY.append(dataset[i+look_back])returnnp.array(dataX), np.array(dataY)#建立模型:双层stacked Stateful LSTM
look_back =40dataset= np.cos(np.arange(1000)*(20*np.pi/1000))#归一化,y值域为(0,1)
dataset = (dataset+1) / 2.#split into train and test sets
train_size = int(len(dataset) * 0.8)
test_size= len(dataset) -train_size
train, test=dataset[:train_size], dataset[train_size:]
trainX, trainY=create_dataset(train, look_back)
testX, testY=create_dataset(test, look_back)
trainX= np.reshape(trainX, (trainX.shape[0], trainX.shape[1], 1))
testX= np.reshape(testX, (testX.shape[0], testX.shape[1], 1))
batch_size= 1model2=Sequential()
model2.add(LSTM(32, batch_input_shape=(batch_size, look_back, 1), stateful=True))
model2.add(Dropout(0.2))
model2.add(Dense(1))
model2.compile(loss='mse', optimizer='adam')for i in range(30):
model2.fit(trainX, trainY, epochs=1, batch_size=batch_size, shuffle=False)
model2.reset_states()
x= np.vstack((trainX[-1][1:],(trainY[-1])))
preds=[]
pred_num= 500
for i innp.arange(pred_num):
pred= model2.predict(x.reshape((1,-1,1)),batch_size =batch_size)
preds.append(pred.squeeze())
x= np.vstack((x[1:],pred))
plt.figure(figsize=(12,5))
plt.plot(np.arange(pred_num),np.array(preds),'r',label='predctions')
cos_y= (np.cos(np.arange(pred_num)*(20*np.pi/1000))+1)/ 2.
plt.plot(np.arange(pred_num),cos_y,label='origin')
plt.legend()
plt.show()
3、双层有状态LSTM模型(序列长度为40)
#创建数据集,每隔50个就是一个整Π,围绕Π的系数不断变化
dataset = np.cos(np.arange(1000)*(20*np.pi/1000))#dataset的值域再-1~1之间。
#转换数据为LSTM输入格式: dataset matrix
def create_dataset(dataset, look_back=1):
dataX, dataY=[], []for i in range(len(dataset)-look_back):
dataX.append(dataset[i:(i+look_back)])
dataY.append(dataset[i+look_back])returnnp.array(dataX), np.array(dataY)#建立模型:双层stacked Stateful LSTM
look_back =40dataset= np.cos(np.arange(1000)*(20*np.pi/1000))#归一化,y值域为(0,1)
dataset = (dataset+1) / 2.#split into train and test sets
train_size = int(len(dataset) * 0.8)
test_size= len(dataset) -train_size
train, test=dataset[:train_size], dataset[train_size:]
trainX, trainY=create_dataset(train, look_back)
testX, testY=create_dataset(test, look_back)
trainX= np.reshape(trainX, (trainX.shape[0], trainX.shape[1], 1))
testX= np.reshape(testX, (testX.shape[0], testX.shape[1], 1))#建立模型:有状态
batch_size = 1model3=Sequential()
model3.add(LSTM(32, batch_input_shape=(batch_size, look_back, 1), stateful=True, return_sequences=True))
model3.add(Dropout(0.3))
model3.add(LSTM(32, batch_input_shape=(batch_size, look_back, 1), stateful=True))
model3.add(Dropout(0.3))
model3.add(Dense(1))
model3.compile(loss='mean_squared_error', optimizer='adam')for i in range(100):print(i)
model3.fit(trainX, trainY, epochs=1, batch_size=batch_size, verbose=0, shuffle=False)
model3.reset_states()#预测
x = np.vstack((trainX[-1][1:],(trainY[-1])))
preds=[]
pred_num= 500
for i innp.arange(pred_num):
pred= model3.predict(x.reshape((1,-1,1)),batch_size =batch_size)
preds.append(pred.squeeze())
x= np.vstack((x[1:],pred))#print(preds[:20])#print(np.array(preds).shape)
plt.figure(figsize=(12,5))
plt.plot(np.arange(pred_num),np.array(preds),'r',label='predctions')
cos_y= (np.cos(np.arange(pred_num)*(20*np.pi/1000))+1)/ 2.
plt.plot(np.arange(pred_num),cos_y,label='origin')
plt.legend()
plt.show()
参考连接: