J'essaie actuellement de construire un modèle simple pour prédire les séries chronologiques. L'objectif serait de former le modèle avec une séquence afin que le modèle soit capable de prédire les valeurs futures.
J'utilise des cellules tensorflow et lstm pour ce faire. Le modèle est entraîné avec une rétropropagation tronquée dans le temps. Ma question est de savoir comment structurer les données pour la formation.
Par exemple, supposons que nous voulons apprendre la séquence donnée:
[1,2,3,4,5,6,7,8,9,10,11,...]
Et nous déroulons le réseau pour num_steps=4
.
Option 1
input data label
1,2,3,4 2,3,4,5
5,6,7,8 6,7,8,9
9,10,11,12 10,11,12,13
...
Option 2
input data label
1,2,3,4 2,3,4,5
2,3,4,5 3,4,5,6
3,4,5,6 4,5,6,7
...
Option
input data label
1,2,3,4 5
2,3,4,5 6
3,4,5,6 7
...
Option 4
input data label
1,2,3,4 5
5,6,7,8 9
9,10,11,12 13
...
Toute aide serait appréciée.
Après avoir lu plusieurs blogs d'introduction à LSTM, par ex. Jakob Aungiers ' , l'option 3 semble être la bonne pour les LSTM apatrides.
Si vos LSTM doivent se souvenir de données antérieures à votre num_steps
, vous pouvez vous entraîner de manière dynamique - pour un exemple Keras voir Article de blog de Philippe Remy "Stateful LSTM in Keras" . Philippe ne montre cependant pas d'exemple de taille de lot supérieure à un. Je suppose que dans votre cas, une taille de lot de quatre avec LSTM avec état pourrait être utilisée avec les données suivantes (écrites comme input -> label
):
batch #0:
1,2,3,4 -> 5
2,3,4,5 -> 6
3,4,5,6 -> 7
4,5,6,7 -> 8
batch #1:
5,6,7,8 -> 9
6,7,8,9 -> 10
7,8,9,10 -> 11
8,9,10,11 -> 12
batch #2:
9,10,11,12 -> 13
...
Par cela, l'état de par ex. le 2ème échantillon du lot # 0 est correctement réutilisé pour continuer la formation avec le 2ème échantillon du lot # 1.
Ceci est en quelque sorte similaire à votre option 4, mais vous n'utilisez pas toutes les étiquettes disponibles là-bas.
Mise à jour:
Dans le prolongement de ma suggestion où batch_size
est égal à num_steps
, Alexis Huet donne une réponse pour le cas de batch_size
étant un diviseur de num_steps
, qui peut être utilisé pour de plus grandes num_steps
. Il le décrit bien sur son blog.
Je suis sur le point d'apprendre les LSTM dans TensorFlow et d'essayer d'implémenter un exemple qui (heureusement) essaie de prédire des séries chronologiques/séries de nombres générées par une simple math-fuction.
Mais j'utilise une manière différente de structurer les données pour la formation, motivée par Apprentissage non supervisé de représentations vidéo à l'aide de LSTM :
Option 5:
input data label
1,2,3,4 5,6,7,8
2,3,4,5 6,7,8,9
3,4,5,6 7,8,9,10
...
À côté de cet article, j'ai (essayé) de m'inspirer des exemples TensorFlow RNN donnés. Ma solution complète actuelle ressemble à ceci:
import math
import random
import numpy as np
import tensorflow as tf
LSTM_SIZE = 64
LSTM_LAYERS = 2
BATCH_SIZE = 16
NUM_T_STEPS = 4
MAX_STEPS = 1000
LAMBDA_REG = 5e-4
def ground_truth_func(i, j, t):
return i * math.pow(t, 2) + j
def get_batch(batch_size):
seq = np.zeros([batch_size, NUM_T_STEPS, 1], dtype=np.float32)
tgt = np.zeros([batch_size, NUM_T_STEPS], dtype=np.float32)
for b in xrange(batch_size):
i = float(random.randint(-25, 25))
j = float(random.randint(-100, 100))
for t in xrange(NUM_T_STEPS):
value = ground_truth_func(i, j, t)
seq[b, t, 0] = value
for t in xrange(NUM_T_STEPS):
tgt[b, t] = ground_truth_func(i, j, t + NUM_T_STEPS)
return seq, tgt
# Placeholder for the inputs in a given iteration
sequence = tf.placeholder(tf.float32, [BATCH_SIZE, NUM_T_STEPS, 1])
target = tf.placeholder(tf.float32, [BATCH_SIZE, NUM_T_STEPS])
fc1_weight = tf.get_variable('w1', [LSTM_SIZE, 1], initializer=tf.random_normal_initializer(mean=0.0, stddev=1.0))
fc1_bias = tf.get_variable('b1', [1], initializer=tf.constant_initializer(0.1))
# ENCODER
with tf.variable_scope('ENC_LSTM'):
lstm = tf.nn.rnn_cell.LSTMCell(LSTM_SIZE)
multi_lstm = tf.nn.rnn_cell.MultiRNNCell([lstm] * LSTM_LAYERS)
initial_state = multi_lstm.zero_state(BATCH_SIZE, tf.float32)
state = initial_state
for t_step in xrange(NUM_T_STEPS):
if t_step > 0:
tf.get_variable_scope().reuse_variables()
# state value is updated after processing each batch of sequences
output, state = multi_lstm(sequence[:, t_step, :], state)
learned_representation = state
# DECODER
with tf.variable_scope('DEC_LSTM'):
lstm = tf.nn.rnn_cell.LSTMCell(LSTM_SIZE)
multi_lstm = tf.nn.rnn_cell.MultiRNNCell([lstm] * LSTM_LAYERS)
state = learned_representation
logits_stacked = None
loss = 0.0
for t_step in xrange(NUM_T_STEPS):
if t_step > 0:
tf.get_variable_scope().reuse_variables()
# state value is updated after processing each batch of sequences
output, state = multi_lstm(sequence[:, t_step, :], state)
# output can be used to make next number prediction
logits = tf.matmul(output, fc1_weight) + fc1_bias
if logits_stacked is None:
logits_stacked = logits
else:
logits_stacked = tf.concat(1, [logits_stacked, logits])
loss += tf.reduce_sum(tf.square(logits - target[:, t_step])) / BATCH_SIZE
reg_loss = loss + LAMBDA_REG * (tf.nn.l2_loss(fc1_weight) + tf.nn.l2_loss(fc1_bias))
train = tf.train.AdamOptimizer().minimize(reg_loss)
with tf.Session() as sess:
sess.run(tf.initialize_all_variables())
total_loss = 0.0
for step in xrange(MAX_STEPS):
seq_batch, target_batch = get_batch(BATCH_SIZE)
feed = {sequence: seq_batch, target: target_batch}
_, current_loss = sess.run([train, reg_loss], feed)
if step % 10 == 0:
print("@{}: {}".format(step, current_loss))
total_loss += current_loss
print('Total loss:', total_loss)
print('### SIMPLE EVAL: ###')
seq_batch, target_batch = get_batch(BATCH_SIZE)
feed = {sequence: seq_batch, target: target_batch}
prediction = sess.run([logits_stacked], feed)
for b in xrange(BATCH_SIZE):
print("{} -> {})".format(str(seq_batch[b, :, 0]), target_batch[b, :]))
print(" `-> Prediction: {}".format(prediction[0][b]))
Un exemple de sortie de ceci ressemble à ceci:
### SIMPLE EVAL: ###
# [input seq] -> [target prediction]
# `-> Prediction: [model prediction]
[ 33. 53. 113. 213.] -> [ 353. 533. 753. 1013.])
`-> Prediction: [ 19.74548721 28.3149128 33.11489105 35.06603241]
[ -17. -32. -77. -152.] -> [-257. -392. -557. -752.])
`-> Prediction: [-16.38951683 -24.3657589 -29.49801064 -31.58583832]
[ -7. -4. 5. 20.] -> [ 41. 68. 101. 140.])
`-> Prediction: [ 14.14126873 22.74848557 31.29668617 36.73633194]
...
Le modèle est un LSTM-autoencoder ayant 2 couches chacune.
Malheureusement, comme vous pouvez le voir dans les résultats, ce modèle n'apprend pas correctement la séquence. Je pourrais être le cas que je fais juste une mauvaise erreur quelque part, ou que les étapes de formation 1000-10000 sont juste beaucoup trop peu pour un LSTM. Comme je l'ai dit, je commence également à comprendre/utiliser correctement les LSTM. Mais j'espère que cela peut vous donner une inspiration concernant la mise en œuvre.
Je pense que l'option 1 est la plus proche de l'implémentation de référence dans /tensorflow/models/rnn/ptb/reader.py
def ptb_iterator(raw_data, batch_size, num_steps):
"""Iterate on the raw PTB data.
This generates batch_size pointers into the raw PTB data, and allows
minibatch iteration along these pointers.
Args:
raw_data: one of the raw data outputs from ptb_raw_data.
batch_size: int, the batch size.
num_steps: int, the number of unrolls.
Yields:
Pairs of the batched data, each a matrix of shape [batch_size, num_steps].
The second element of the Tuple is the same data time-shifted to the
right by one.
Raises:
ValueError: if batch_size or num_steps are too high.
"""
raw_data = np.array(raw_data, dtype=np.int32)
data_len = len(raw_data)
batch_len = data_len // batch_size
data = np.zeros([batch_size, batch_len], dtype=np.int32)
for i in range(batch_size):
data[i] = raw_data[batch_len * i:batch_len * (i + 1)]
Epoch_size = (batch_len - 1) // num_steps
if Epoch_size == 0:
raise ValueError("Epoch_size == 0, decrease batch_size or num_steps")
for i in range(Epoch_size):
x = data[:, i*num_steps:(i+1)*num_steps]
y = data[:, i*num_steps+1:(i+1)*num_steps+1]
yield (x, y)
Cependant, une autre option consiste à sélectionner un pointeur dans votre tableau de données au hasard pour chaque séquence d'apprentissage.