受け入れられた回答を補足するものとして、この回答はケラスの振る舞いと各画像を達成する方法を示しています。
Kerasの一般的な動作
標準的なケラスの内部処理は、常に次の図のように多対多です(ここではfeatures=2
、例として、圧力、温度を使用しています)。
この画像では、他のディメンションとの混乱を避けるために、ステップ数を5に増やしています。
この例では:
- N個のオイルタンクがあります
- 1時間ごとに5時間かけて対策を講じました(タイムステップ)
- 2つの特徴を測定しました。
入力配列は、次のような形になります(N,5,2)
。
[ Step1 Step2 Step3 Step4 Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
....
Tank N: [[Pn1,Tn1], [Pn2,Tn2], [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
]
スライディングウィンドウの入力
多くの場合、LSTMレイヤーはシーケンス全体を処理することになっています。ウィンドウを分割することは最善の方法ではありません。レイヤーには、シーケンスが前進するにつれてどのように進化するかについての内部状態があります。ウィンドウは、長いシーケンスを学習する可能性を排除し、すべてのシーケンスをウィンドウサイズに制限します。
ウィンドウでは、各ウィンドウは長い元のシーケンスの一部ですが、Kerasではそれらはそれぞれ独立したシーケンスと見なされます。
[ Step1 Step2 Step3 Step4 Step5
Window A: [[P1,T1], [P2,T2], [P3,T3], [P4,T4], [P5,T5]],
Window B: [[P2,T2], [P3,T3], [P4,T4], [P5,T5], [P6,T6]],
Window C: [[P3,T3], [P4,T4], [P5,T5], [P6,T6], [P7,T7]],
....
]
この場合、最初はシーケンスが1つしかありませんが、ウィンドウを作成するためにそれを多くのシーケンスに分割していることに注意してください。
「シーケンスとは」の概念は抽象的です。重要な部分は次のとおりです。
- 多くの個別のシーケンスを持つバッチを持つことができます
- シーケンスをシーケンスにするのは、シーケンス(通常は時間ステップ)で進化するということです。
「単一層」で各ケースを達成する
多対多の標準を達成する:
以下を使用して、単純なLSTMレイヤーで多対多を実現できますreturn_sequences=True
。
outputs = LSTM(units, return_sequences=True)(inputs)
#output_shape -> (batch_size, steps, units)
多対1の達成:
まったく同じレイヤーを使用すると、kerasはまったく同じ内部前処理を行いますが、使用するreturn_sequences=False
(または単にこの引数を無視する)と、kerasは最後の前のステップを自動的に破棄します。
outputs = LSTM(units)(inputs)
#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned
1対多の達成
現在、これはkeras LSTMレイヤーだけではサポートされていません。ステップを増やすには、独自の戦略を作成する必要があります。2つの適切なアプローチがあります。
- テンソルを繰り返すことで一定の多段階入力を作成する
- a
stateful=True
を使用して、1つのステップの出力を繰り返し取得し、次のステップの入力として機能させます(必要output_features == input_features
)
1対多の繰り返しベクトル
ケラスの標準的な動作に合わせるために、段階的に入力が必要なので、必要な長さだけ入力を繰り返します。
outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)
#output_shape -> (batch_size, steps, units)
ステートフルを理解する= True
の可能な使用法の1つになりました stateful=True
(コンピューターのメモリに一度に収まらないデータの読み込みを回避する以外に)
ステートフルを使用すると、シーケンスの「部分」を段階的に入力できます。違いは次のとおりです。
- では
stateful=False
、2番目のバッチには、最初のバッチとは無関係に、まったく新しいシーケンスが含まれています。
- では
stateful=True
、2番目のバッチが最初のバッチを続行し、同じシーケンスを拡張します。
シーケンスをウィンドウで分割するようなものですが、次の2つの主な違いがあります。
- これらのウィンドウは重なりません!!
stateful=True
これらのウィンドウが単一の長いシーケンスとして接続されているのがわかります
ではstateful=True
、新しいバッチはすべて、前のバッチを継続するものとして解釈されます(を呼び出すまでmodel.reset_states()
)。
- バッチ2のシーケンス1は、バッチ1のシーケンス1を続行します。
- バッチ2のシーケンス2は、バッチ1のシーケンス2を続行します。
- バッチ2のシーケンスnは、バッチ1のシーケンスnを続行します。
入力の例、バッチ1にはステップ1と2が含まれ、バッチ2にはステップ3から5が含まれます。
BATCH 1 BATCH 2
[ Step1 Step2 | [ Step3 Step4 Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], | [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], | [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
.... |
Tank N: [[Pn1,Tn1], [Pn2,Tn2], | [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
] ]
バッチ1とバッチ2のタンクの配置に注意してください!これが必要な理由ですshuffle=False
(もちろん、シーケンスを1つだけ使用している場合を除きます)。
無制限に、任意の数のバッチを持つことができます。(各バッチで可変長にする場合は、を使用しますinput_shape=(None,features)
。
stateful = Trueの1対多
ここでは、1つの出力ステップを取得してそれを入力にしたいので、バッチごとに1つのステップのみを使用します。
画像の動作は「原因」ではないことに注意してくださいstateful=True
。以下の手動ループでその動作を強制します。この例でstateful=True
は、シーケンスを停止し、必要なものを操作し、停止したところから続行できるようにします。
正直なところ、このケースではおそらく繰り返しアプローチがより良い選択です。しかし、を調べているstateful=True
ので、これは良い例です。これを使用する最良の方法は、次の「多対多」の場合です。
層:
outputs = LSTM(units=features,
stateful=True,
return_sequences=True, #just to keep a nice output shape even with length 1
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length
#output_shape -> (batch_size, steps, units)
ここで、予測のための手動ループが必要になります。
input_data = someDataWithShape((batch, 1, features))
#important, we're starting new sequences, not continuing old ones:
model.reset_states()
output_sequence = []
last_step = input_data
for i in steps_to_predict:
new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step
#end of the sequences
model.reset_states()
stateful = Trueの多対多
ここで、非常に優れたアプリケーションを取得します。入力シーケンスを指定して、その将来の未知のステップを予測してみます。
上記の「1対多」と同じ方法を使用していますが、次の点が異なります。
- シーケンス自体をターゲットデータとして使用します。
- シーケンスの一部がわかっている(したがって、結果のこの部分は破棄する)。
レイヤー(上記と同じ):
outputs = LSTM(units=features,
stateful=True,
return_sequences=True,
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length
#output_shape -> (batch_size, steps, units)
トレーニング:
モデルをトレーニングして、シーケンスの次のステップを予測します。
totalSequences = someSequencesShaped((batch, steps, features))
#batch size is usually 1 in these cases (often you have only one Tank in the example)
X = totalSequences[:,:-1] #the entire known sequence, except the last step
Y = totalSequences[:,1:] #one step ahead of X
#loop for resetting states at the start/end of the sequences:
for epoch in range(epochs):
model.reset_states()
model.train_on_batch(X,Y)
予測:
予測の最初の段階には、「国家の調整」が含まれます。これが、シーケンスのこの部分をすでに知っていても、シーケンス全体を再度予測する理由です。
model.reset_states() #starting a new sequence
predicted = model.predict(totalSequences)
firstNewStep = predicted[:,-1:] #the last step of the predictions is the first future step
次に、1対多の場合と同様にループに進みます。ただし、ここで状態をリセットしないでください。。モデルにシーケンスのどのステップにあるかを知らせたい(そして、先ほど行った予測のために、モデルが最初の新しいステップにあることを知っている)
output_sequence = [firstNewStep]
last_step = firstNewStep
for i in steps_to_predict:
new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step
#end of the sequences
model.reset_states()
このアプローチはこれらの回答とファイルで使用されました:
複雑な構成の実現
上記のすべての例で、「1つのレイヤー」の動作を示しました。
もちろん、必ずしも同じパターンに従っている必要はなく、多くのレイヤーを積み重ねて、独自のモデルを作成することもできます。
登場している興味深い例の1つは、「多対1のエンコーダ」とそれに続く「1対多」のデコーダを持つ「オートエンコーダ」です。
エンコーダ:
inputs = Input((steps,features))
#a few many to many layers:
outputs = LSTM(hidden1,return_sequences=True)(inputs)
outputs = LSTM(hidden2,return_sequences=True)(outputs)
#many to one layer:
outputs = LSTM(hidden3)(outputs)
encoder = Model(inputs,outputs)
デコーダ:
「繰り返し」メソッドを使用します。
inputs = Input((hidden3,))
#repeat to make one to many:
outputs = RepeatVector(steps)(inputs)
#a few many to many layers:
outputs = LSTM(hidden4,return_sequences=True)(outputs)
#last layer
outputs = LSTM(features,return_sequences=True)(outputs)
decoder = Model(inputs,outputs)
オートエンコーダ:
inputs = Input((steps,features))
outputs = encoder(inputs)
outputs = decoder(outputs)
autoencoder = Model(inputs,outputs)
トレーニング fit(X,X)
追加説明
LSTMでのステップの計算方法の詳細、またはstateful=True
上記のケースの詳細が必要な場合は、この回答で詳細を読むことができます。「Keras LSTMの理解」に関する疑問