Batching in tf.data.dataset nell'analisi di serie temporali
Sto cercando di creare una pipeline per un modello LSTM di serie temporali. Ho due feed di input, chiamiamoli series1
e series2
.
Inizializzo l' tf.data
oggetto chiamando from.tensor.slices
:
ds = tf.data.Dataset.from_tensor_slices((series1, series2))
Li lotto ulteriormente in finestre di una dimensione di finestre impostata e sposto 1 tra le finestre:
ds = ds.window(window_size + 1, shift=1, drop_remainder=True)
A questo punto voglio giocare con come sono raggruppati insieme. Voglio produrre un certo input come il seguente come esempio:
series1 = [1, 2, 3, 4, 5]
series2 = [100, 200, 300, 400, 500]
batch 1: [1, 2, 100, 200]
batch 2: [2, 3, 200, 300]
batch 3: [3, 4, 300, 400]
Quindi ogni batch restituirà due elementi di serie1 e quindi due elementi di serie2. Questo snippet di codice non funziona per raggrupparli separatamente:
ds = ds.map(lambda s1, s2: (s1.batch(window_size + 1), s2.batch(window_size + 1))
Perché restituisce due mapping di oggetti del set di dati. Poiché sono oggetti non sono abbonabili, quindi non funziona neanche:
ds = ds.map(lambda s1, s2: (s1[:2], s2[:2]))
Sono sicuro che la soluzione sia un utilizzo .apply
con una funzione lambda personalizzata. Ogni aiuto è molto apprezzato.
modificare
Sto anche cercando di produrre un'etichetta che rappresenti il prossimo elemento della serie. Quindi, ad esempio, i lotti produrranno quanto segue:
batch 1: (tf.tensor([1, 2, 100, 200]), tf.tensor([3]))
batch 2: (tf.tensor([2, 3, 200, 300]), tf.tensor([4]))
batch 3: (tf.tensor([3, 4, 300, 400]), tf.tensor([5]))
Dove [3]
, [4]
e [5]
rappresentano i prossimi elementi series1
da prevedere.
Risposte
La soluzione è stata quella di visualizzare separatamente i due set di dati .zip()
, quindi .concat()
gli elementi per includere l'etichetta.
ds = tf.data.Dataset.from_tensor_slices(series1)
ds = ds.window(window_size + 1, shift=1, drop_remainder=True)
ds = ds.flat_map(lambda window: window.batch(window_size + 1))
ds = ds.map(lambda window: (window[:-1], window[-1]))
ds2 = tf.data.Dataset.from_tensor_slices(series2)
ds2 = ds2.window(window_size, shift=1, drop_remainder=True)
ds2 = ds2.flat_map(lambda window: window.batch(window_size))
ds = tf.data.Dataset.zip((ds, ds2))
ds = ds.map(lambda i, j: (tf.concat([i[0], j], axis=0), i[-1]))
Ritorna:
(<tf.Tensor: shape=(7,), dtype=int32, numpy=array([ 1, 2, 3, 100, 200, 300])>, <tf.Tensor: shape=(), dtype=int32, numpy=4>)
(<tf.Tensor: shape=(7,), dtype=int32, numpy=array([ 2, 3, 4, 200, 300, 400])>, <tf.Tensor: shape=(), dtype=int32, numpy=5>)
(<tf.Tensor: shape=(7,), dtype=int32, numpy=array([ 3, 4, 5, 300, 400, 500])>, <tf.Tensor: shape=(), dtype=int32, numpy=6>)
Penso che questa sia la linea che ti manca:
ds = ds.batch(2).map(lambda x, y: (tf.concat([x, y], axis=0)))
Esempio completo:
import tensorflow as tf
series1 = tf.range(1, 16)
series2 = tf.range(100, 1600, 100)
ds = tf.data.Dataset.from_tensor_slices((series1, series2))
ds = ds.batch(2).map(lambda x, y: (tf.concat([x, y], axis=0)))
for row in ds:
print(row)
tf.Tensor([ 1 2 100 200], shape=(4,), dtype=int32)
tf.Tensor([ 3 4 300 400], shape=(4,), dtype=int32)
tf.Tensor([ 5 6 500 600], shape=(4,), dtype=int32)
tf.Tensor([ 7 8 700 800], shape=(4,), dtype=int32)
tf.Tensor([ 9 10 900 1000], shape=(4,), dtype=int32)
tf.Tensor([ 11 12 1100 1200], shape=(4,), dtype=int32)
tf.Tensor([ 13 14 1300 1400], shape=(4,), dtype=int32)
Ecco la mia soluzione quando si tratta di dati di serie temporali.
dataset = tf.data.Dataset.from_tensor_slices(series)
dataset = dataset.window(window_size + 1, shift=1, drop_remainder=True)
dataset = dataset.flat_map(lambda window: window.batch(window_size + 1))
dataset = dataset.shuffle(shuffle_buffer).map(lambda window: (window[:-1], window[-1]))
dataset = dataset.batch(batch_size).prefetch(1)
La riga seguente è importante per dividere la finestra in xs e ys.
dataset.shuffle(shuffle_buffer).map(lambda window: (window[:-1], window[-1]))
Sebbene non sia importante usare shuffle, puoi usare solo la funzione map per dividere la finestra in xs e ys.