我已经在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)的情况下获得中间概率-请参见下面的动画。
python - 有状态LSTM和流预测-LMLPHP
我的一个想法是用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/

10-11 22:48
查看更多