時系列分析でのtf.data.datasetのバッチ処理
時系列LSTMモデルのパイプラインを作成することを検討しています。入力のフィードが2つあるので、それらをseries1
とと呼びましょうseries2
。
をtf.data
呼び出してオブジェクトを初期化しますfrom.tensor.slices
:
ds = tf.data.Dataset.from_tensor_slices((series1, series2))
それらを設定されたウィンドウサイズのウィンドウにさらにバッチ処理し、ウィンドウ間で1をシフトします。
ds = ds.window(window_size + 1, shift=1, drop_remainder=True)
この時点で、それらがどのように一緒にバッチ処理されるかを試してみたいと思います。例として、次のような特定の入力を生成したいと思います。
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]
したがって、各バッチはseries1の2つの要素を返し、次にseries2の2つの要素を返します。このコードスニペットは、それらを個別にバッチ処理するためには機能しません。
ds = ds.map(lambda s1, s2: (s1.batch(window_size + 1), s2.batch(window_size + 1))
データセットオブジェクトの2つのマッピングを返すためです。それらはオブジェクトであるため、添え字化できないため、これも機能しません。
ds = ds.map(lambda s1, s2: (s1[:2], s2[:2]))
解決策は.apply
、カスタムラムダ関数を利用することだと確信しています。どんな助けでも大歓迎です。
編集
シリーズの次の要素を表すレーベルの制作も検討しています。したがって、たとえば、バッチは次を生成します。
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]))
ここで[3]
、[4]
と[5]
の次の要素表すseries1
予測されることを。
回答
解決策は、2つのデータセットを別々にウィンドウ処理し、.zip()
それらを一緒にウィンドウ表示してから.concat()
、要素にラベルを含めることでした。
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]))
戻り値:
(<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>)
私はこれがあなたが見逃している行だと思います:
ds = ds.batch(2).map(lambda x, y: (tf.concat([x, y], axis=0)))
完全な例:
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)
これが時系列データを扱うときの私の解決策です。
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)
次の行は、ウィンドウをxsとysに分割するために重要です。
dataset.shuffle(shuffle_buffer).map(lambda window: (window[:-1], window[-1]))
シャッフルを使用することは重要ではありませんが、map関数を使用してウィンドウをxsとysに分割することしかできません。