我已经在7个样品的多个批次上培训了LSTM模型(用Keras和TF构建),每个样品具有3个特征,形状如下样品(以下数字只是用于解释的占位符),每个批次标记为0或1:
数据:
[
[[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
[[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
[[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3]]
...
]
即:M序列批,每批长度为7,元素为三维向量(因此批具有形状(m*7*3))。
目标:
[
[1]
[0]
[1]
...
]
在我的生产环境中,数据是具有3个功能的示例流(
[1,2,3],[1,2,3]...
)。我想在每个样本到达我的模型时对其进行流式处理,并在不等待整个批次(7)的情况下获得中间概率-请参见下面的动画。我的一个想法是用0填充批次中丢失的样本,
但这似乎效率低下。
如果您能帮助我找到正确的方向,既能以持久的方式保存LSTM中间状态,又能在等待下一个样本的同时预测针对特定批量大小的模型,并提供部分数据,我将不胜感激。
更新,包括型号代码:
opt = optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=10e-8, decay=0.001)
model = Sequential()
num_features = data.shape[2]
num_samples = data.shape[1]
first_lstm = LSTM(32, batch_input_shape=(None, num_samples, num_features), return_sequences=True, activation='tanh')
model.add(
first_lstm)
model.add(LeakyReLU())
model.add(Dropout(0.2))
model.add(LSTM(16, return_sequences=True, activation='tanh'))
model.add(Dropout(0.2))
model.add(LeakyReLU())
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer=opt,
metrics=['accuracy', keras_metrics.precision(), keras_metrics.recall(), f1])
模型摘要:
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
lstm_1 (LSTM) (None, 100, 32) 6272
_________________________________________________________________
leaky_re_lu_1 (LeakyReLU) (None, 100, 32) 0
_________________________________________________________________
dropout_1 (Dropout) (None, 100, 32) 0
_________________________________________________________________
lstm_2 (LSTM) (None, 100, 16) 3136
_________________________________________________________________
dropout_2 (Dropout) (None, 100, 16) 0
_________________________________________________________________
leaky_re_lu_2 (LeakyReLU) (None, 100, 16) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 1600) 0
_________________________________________________________________
dense_1 (Dense) (None, 1) 1601
=================================================================
Total params: 11,009
Trainable params: 11,009
Non-trainable params: 0
_________________________________________________________________
最佳答案
我认为有一个更简单的解决方案。
如果您的模型没有卷积层或任何其他作用于长度/台阶维度的层,您可以简单地将其标记为stateful=True
警告:您的模型具有作用于长度维度的层!!Flatten
层将长度尺寸转换为特征尺寸。这将完全阻止你实现你的目标。如果Flatten
层需要7个步骤,则始终需要7个步骤。
因此,在应用下面的答案之前,请先将您的模型修复为不使用Flatten
层。相反,它可以只删除最后一个lstm层的return_sequences=True
。
下面的代码修复了这个问题,并准备了一些要与下面的答案一起使用的东西:
def createModel(forTraining):
#model for training, stateful=False, any batch size
if forTraining == True:
batchSize = None
stateful = False
#model for predicting, stateful=True, fixed batch size
else:
batchSize = 1
stateful = True
model = Sequential()
first_lstm = LSTM(32,
batch_input_shape=(batchSize, num_samples, num_features),
return_sequences=True, activation='tanh',
stateful=stateful)
model.add(first_lstm)
model.add(LeakyReLU())
model.add(Dropout(0.2))
#this is the last LSTM layer, use return_sequences=False
model.add(LSTM(16, return_sequences=False, stateful=stateful, activation='tanh'))
model.add(Dropout(0.2))
model.add(LeakyReLU())
#don't add a Flatten!!!
#model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
if forTraining == True:
compileThisModel(model)
有了这个,你就可以用7个步骤来训练,用一个步骤来预测。否则就不可能了。
使用状态模型作为问题的解决方案
首先,再次训练这个新模型,因为它没有平坦层:
trainingModel = createModel(forTraining=True)
trainThisModel(trainingModel)
现在,使用这个经过训练的模型,您可以简单地创建一个新模型,方法与创建经过训练的模型完全相同,但是在所有LSTM层中标记
stateful=True
。我们应该从训练过的模型中复制权重。由于这些新层需要一个固定的批处理大小(keras规则),我假设它是1(一个单独的流将要出现,而不是M流),并将其添加到上面的模型创建中。
predictingModel = createModel(forTraining=False)
predictingModel.set_weights(trainingModel.get_weights())
瞧。只需一步预测模型的输出:
pseudo for loop as samples arrive to your model:
prob = predictingModel.predict_on_batch(sample)
#where sample.shape == (1, 1, 3)
当您决定到达您认为是连续序列的末尾时,请调用
predictingModel.reset_states()
,这样您就可以安全地开始一个新序列,而不需要模型认为它应该在上一个序列的末尾进行修正。保存和加载状态
只需获取并设置它们,用h5py保存:
def saveStates(model, saveName):
f = h5py.File(saveName,'w')
for l, lay in enumerate(model.layers):
#if you have nested models,
#consider making this recurrent testing for layers in layers
if isinstance(lay,RNN):
for s, stat in enumerate(lay.states):
f.create_dataset('states_' + str(l) + '_' + str(s),
data=K.eval(stat),
dtype=K.dtype(stat))
f.close()
def loadStates(model, saveName):
f = h5py.File(saveName, 'r')
allStates = list(f.keys())
for stateKey in allStates:
name, layer, state = stateKey.split('_')
layer = int(layer)
state = int(state)
K.set_value(model.layers[layer].states[state], f.get(stateKey))
f.close()
保存/加载状态的工作测试
import h5py, numpy as np
from keras.layers import RNN, LSTM, Dense, Input
from keras.models import Model
import keras.backend as K
def createModel():
inp = Input(batch_shape=(1,None,3))
out = LSTM(5,return_sequences=True, stateful=True)(inp)
out = LSTM(2, stateful=True)(out)
out = Dense(1)(out)
model = Model(inp,out)
return model
def saveStates(model, saveName):
f = h5py.File(saveName,'w')
for l, lay in enumerate(model.layers):
#if you have nested models, consider making this recurrent testing for layers in layers
if isinstance(lay,RNN):
for s, stat in enumerate(lay.states):
f.create_dataset('states_' + str(l) + '_' + str(s), data=K.eval(stat), dtype=K.dtype(stat))
f.close()
def loadStates(model, saveName):
f = h5py.File(saveName, 'r')
allStates = list(f.keys())
for stateKey in allStates:
name, layer, state = stateKey.split('_')
layer = int(layer)
state = int(state)
K.set_value(model.layers[layer].states[state], f.get(stateKey))
f.close()
def printStates(model):
for l in model.layers:
#if you have nested models, consider making this recurrent testing for layers in layers
if isinstance(l,RNN):
for s in l.states:
print(K.eval(s))
model1 = createModel()
model2 = createModel()
model1.predict_on_batch(np.ones((1,5,3))) #changes model 1 states
print('model1')
printStates(model1)
print('model2')
printStates(model2)
saveStates(model1,'testStates5')
loadStates(model2,'testStates5')
print('model1')
printStates(model1)
print('model2')
printStates(model2)
数据方面的考虑
在第一个模型中(如果它是
stateful=False
),它认为m
中的每个序列都是独立的,并且没有连接到其他序列。它还认为每个批次包含唯一的序列。如果不是这样,您可能希望训练有状态模型(考虑到每个序列实际上都连接到了前一个序列)。然后你需要1个序列的批次。->
m
。关于python - 有状态LSTM和流预测,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53190253/