recurrent neural network machine learning implement example ejemplos adventures python-3.x keras lstm recurrent-neural-network variable-length

python-3.x - machine - recurrent neural network python



¿Cómo creo una entrada LSTM de longitud variable en Keras? (3)

Estoy tratando de hacer un reconocimiento de patrón de vainilla con un LSTM usando Keras para predecir el siguiente elemento en una secuencia.

Mis datos se ven así:

donde la etiqueta de la secuencia de entrenamiento es el último elemento de la lista: X_train[''Sequence''][n][-1] .

Como mi columna Sequence puede tener un número variable de elementos en la secuencia, creo que un RNN es el mejor modelo para usar. Debajo está mi intento de construir un LSTM en Keras:

# Build the model # A few arbitrary constants... max_features = 20000 out_size = 128 # The max length should be the length of the longest sequence (minus one to account for the label) max_length = X_train[''Sequence''].apply(len).max() - 1 # Normal LSTM model construction with sigmoid activation model = Sequential() model.add(Embedding(max_features, out_size, input_length=max_length, dropout=0.2)) model.add(LSTM(128, dropout_W=0.2, dropout_U=0.2)) model.add(Dense(1)) model.add(Activation(''sigmoid'')) # try using different optimizers and different optimizer configs model.compile(loss=''binary_crossentropy'', optimizer=''adam'', metrics=[''accuracy''])

Y así es como trato de entrenar a mi modelo:

# Train the model for seq in X_train[''Sequence'']: print("Length of training is {0}".format(len(seq[:-1]))) print("Training set is {0}".format(seq[:-1])) model.fit(np.array([seq[:-1]]), [seq[-1]])

Mi salida es esta:

Length of training is 13 Training set is [1, 3, 13, 87, 1053, 28576, 2141733, 508147108, 402135275365, 1073376057490373, 9700385489355970183, 298434346895322960005291, 31479360095907908092817694945]

Sin embargo, me sale el siguiente error:

Exception: Error when checking model input: expected embedding_input_1 to have shape (None, 347) but got array with shape (1, 13)

Creo que mi paso de entrenamiento está configurado correctamente, por lo que la construcción de mi modelo debe ser incorrecta. Tenga en cuenta que 347 es max_length .

¿Cómo puedo construir correctamente una entrada LSTM de longitud variable en Keras? Prefiero no rellenar los datos. No estoy seguro de si es relevante, pero estoy usando el backend de Theano.


No tengo claro el procedimiento de incrustación. Pero aún así hay una forma de implementar una entrada LSTM de longitud variable. Simplemente no especifique la dimensión de la ventana de tiempo cuando construya LSTM.

import keras.backend as K from keras.layers import LSTM, Input I = Input(shape=(None, 200)) # unknown timespan, fixed feature size lstm = LSTM(20) f = K.function(inputs=[I], outputs=[lstm(I)]) import numpy as np data1 = np.random.random(size=(1, 100, 200)) # batch_size = 1, timespan = 100 print f([data1])[0].shape # (1, 20) data2 = np.random.random(size=(1, 314, 200)) # batch_size = 1, timespan = 314 print f([data2])[0].shape # (1, 20)


El truco para entrenar y clasificar secuencias es entrenar con enmascaramiento y clasificación usando una red con estado. Aquí hay un ejemplo que hice que clasifica si una secuencia de longitud variable comienza con cero o no.

import numpy as np np.random.seed(1) import tensorflow as tf tf.set_random_seed(1) from keras import models from keras.layers import Dense, Masking, LSTM import matplotlib.pyplot as plt def stateful_model(): hidden_units = 256 model = models.Sequential() model.add(LSTM(hidden_units, batch_input_shape=(1, 1, 1), return_sequences=False, stateful=True)) model.add(Dense(1, activation=''relu'', name=''output'')) model.compile(loss=''binary_crossentropy'', optimizer=''rmsprop'') return model def train_rnn(x_train, y_train, max_len, mask): epochs = 10 batch_size = 200 vec_dims = 1 hidden_units = 256 in_shape = (max_len, vec_dims) model = models.Sequential() model.add(Masking(mask, name="in_layer", input_shape=in_shape,)) model.add(LSTM(hidden_units, return_sequences=False)) model.add(Dense(1, activation=''relu'', name=''output'')) model.compile(loss=''binary_crossentropy'', optimizer=''rmsprop'') model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.05) return model def gen_train_sig_cls_pair(t_stops, num_examples, mask): x = [] y = [] max_t = int(np.max(t_stops)) for t_stop in t_stops: one_indices = np.random.choice(a=num_examples, size=num_examples // 2, replace=False) sig = np.zeros((num_examples, max_t), dtype=np.int8) sig[one_indices, 0] = 1 sig[:, t_stop:] = mask x.append(sig) cls = np.zeros(num_examples, dtype=np.bool) cls[one_indices] = 1 y.append(cls) return np.concatenate(x, axis=0), np.concatenate(y, axis=0) def gen_test_sig_cls_pair(t_stops, num_examples): x = [] y = [] for t_stop in t_stops: one_indices = np.random.choice(a=num_examples, size=num_examples // 2, replace=False) sig = np.zeros((num_examples, t_stop), dtype=np.bool) sig[one_indices, 0] = 1 x.extend(list(sig)) cls = np.zeros((num_examples, t_stop), dtype=np.bool) cls[one_indices] = 1 y.extend(list(cls)) return x, y if __name__ == ''__main__'': noise_mag = 0.01 mask_val = -10 signal_lengths = (10, 15, 20) x_in, y_in = gen_train_sig_cls_pair(signal_lengths, 10, mask_val) mod = train_rnn(x_in[:, :, None], y_in, int(np.max(signal_lengths)), mask_val) testing_dat, expected = gen_test_sig_cls_pair(signal_lengths, 3) state_mod = stateful_model() state_mod.set_weights(mod.get_weights()) res = [] for s_i in range(len(testing_dat)): seq_in = list(testing_dat[s_i]) seq_len = len(seq_in) for t_i in range(seq_len): res.extend(state_mod.predict(np.array([[[seq_in[t_i]]]]))) state_mod.reset_states() fig, axes = plt.subplots(2) axes[0].plot(np.concatenate(testing_dat), label="input") axes[1].plot(res, "ro", label="result", alpha=0.2) axes[1].plot(np.concatenate(expected, axis=0), "bo", label="expected", alpha=0.2) axes[1].legend(bbox_to_anchor=(1.1, 1)) plt.show()


No estoy seguro de qué tan aplicables son las redes recurrentes para sus secuencias, es decir, qué tan fuertemente dependiente es cada elemento en su secuencia anterior en comparación con otros factores. Una vez dicho esto (que no ayuda un poco por supuesto), si no desea rellenar su entrada con algún valor malo, un modelo con estado que procesa un solo paso de tiempo a la vez es la única alternativa para secuencias de longitud variable en mi humilde opinión . Si no te importa tomar un enfoque alternativo a la codificación:

import numpy as np import keras.models as kem import keras.layers as kel import keras.callbacks as kec import sklearn.preprocessing as skprep X_train, max_features = {''Sequence'': [[1, 2, 4, 5, 8, 10, 16], [1, 2, 1, 5, 5, 1, 11, 16, 7]]}, 16 num_mem_units = 64 size_batch = 1 num_timesteps = 1 num_features = 1 num_targets = 1 num_epochs = 1500 model = kem.Sequential() model.add(kel.LSTM(num_mem_units, stateful=True, batch_input_shape=(size_batch, num_timesteps, num_features), return_sequences=True)) model.add(kel.Dense(num_targets, activation=''sigmoid'')) model.summary() model.compile(loss=''binary_crossentropy'', optimizer=''adam'') range_act = (0, 1) # sigmoid range_features = np.array([0, max_features]).reshape(-1, 1) normalizer = skprep.MinMaxScaler(feature_range=range_act) normalizer.fit(range_features) reset_state = kec.LambdaCallback(on_epoch_end=lambda *_ : model.reset_states()) # training for seq in X_train[''Sequence'']: X = seq[:-1] y = seq[1:] # predict next element X_norm = normalizer.transform(np.array(X).reshape(-1, 1)).reshape(-1, num_timesteps, num_features) y_norm = normalizer.transform(np.array(y).reshape(-1, 1)).reshape(-1, num_timesteps, num_targets) model.fit(X_norm, y_norm, epochs=num_epochs, batch_size=size_batch, shuffle=False, callbacks=[reset_state]) # prediction for seq in X_train[''Sequence'']: model.reset_states() for istep in range(len(seq)-1): # input up to not incl last val = seq[istep] X = np.array([val]).reshape(-1, 1) X_norm = normalizer.transform(X).reshape(-1, num_timesteps, num_features) y_norm = model.predict(X_norm) yhat = int(normalizer.inverse_transform(y_norm[0])[0, 0]) y = seq[-1] # last put = ''{0} predicts {1:d}, expecting {2:d}''.format('', ''.join(str(val) for val in seq[:-1]), yhat, y) print(put)

que produce algo como:

1, 2, 4, 5, 8, 10 predicts 11, expecting 16 1, 2, 1, 5, 5, 1, 11, 16 predicts 7, expecting 7

con una pérdida ridícula, sin embargo.