私はLSTMについての私の理解を調整しようとしており、ここで指摘しています このChristopher Olahによる投稿 Kerasで実装されています。私は Jason Brownleeが書いた Kerasチュートリアル用のブログをフォローしています。私が主に混乱しているのは、
[samples, time steps, features]
に変換し、以下のコードを参考にして、上記の2つの質問に集中しましょう。
# reshape into X=t and Y=t+1
look_back = 3
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
# reshape input to be [samples, time steps, features]
trainX = numpy.reshape(trainX, (trainX.shape[0], look_back, 1))
testX = numpy.reshape(testX, (testX.shape[0], look_back, 1))
########################
# The IMPORTANT BIT
##########################
# create and fit the LSTM network
batch_size = 1
model = Sequential()
model.add(LSTM(4, batch_input_shape=(batch_size, look_back, 1), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
for i in range(100):
model.fit(trainX, trainY, nb_Epoch=1, batch_size=batch_size, verbose=2, shuffle=False)
model.reset_states()
注:create_datasetは長さNのシーケンスを取り、各エレメントがN-look_back
長のシーケンスであるlook_back
配列を返します。
ご覧のように、TrainXはTime_stepsとFeatureがそれぞれ最後の2つの次元(この特定のコードでは3と1)である3D配列です。下の画像に関して、これはピンクの箱の数が3であるmany to one
のケースを検討しているということですか?あるいはそれは文字通りチェーンの長さが3であることを意味しているのでしょうか(すなわち3つの緑色の枠のみが考慮されています)。
多変量級数を考えるとき、features引数は適切になりますか?例えば同時に2つの金融株をモデル化する?
ステートフルLSTMは、バッチ実行の間にセルメモリ値を保存するという意味ですか?この場合、batch_size
は1で、トレーニングの実行の間にメモリがリセットされるので、それがステートフルであると言うことのポイントでした。これはトレーニングデータがシャッフルされていないという事実に関連していると私は推測していますが、私はその方法がわかりません。
何かご意見は?画像参照: http://karpathy.github.io/2015/05/21/rnn-effectiveness/ /
赤と緑のボックスが等しいという@ vanのコメントについて少し混乱しています。確認のため、次のAPI呼び出しは展開された図に対応していますか?特に2番目の図に注意してください(batch_size
は任意に選択されたものです):
Udacityのディープラーニングコースをやってもtime_step引数についてまだ混乱している人は、以下の議論を見てください: https://discussions.udacity.com/t/rnn-lstm-use-implementation/163169
model.add(TimeDistributed(Dense(vocab_len)))
が私が探していたものであることがわかりました。例を示します。 https://github.com/sachinruk/ShakespeareBot
私はLSTMについての私の理解のほとんどをここにまとめました: https://www.youtube.com/watch?v=ywinX5wgdEU
まず第一に、あなたは素晴らしいチュートリアル( 1 、 2 )を選びます。開始。
タイムステップの意味:X.shapeのTime-steps==3
(データ形状の説明)は、ピンク色の枠が3つあることを意味します。 Kerasでは各ステップが入力を必要とするので、それ故に緑の箱の数は通常赤の箱の数に等しいはずです。構造をハックしない限り。
多対多対多対:ケラスでは、LSTM
やGRU
、SimpleRNN
を初期化するときにreturn_sequences
パラメータがあります。 return_sequences
が(デフォルトで)False
のとき、それは図に示すように多対一です。その戻り形状は最後の状態を表す(batch_size, hidden_unit_length)
です。 return_sequences
がTrue
のとき、それは多対多です。その戻り形状は(batch_size, time_step, hidden_unit_length)
です
features引数は適切になりますか:feature引数は「赤い四角形の大きさ」または各ステップの入力次元とは何ですか?たとえば8種類の市場情報から予測したい場合は、feature==8
を使用してデータを生成できます。
ステートフル:あなたは ソースコードを調べることができます 。状態を初期化するとき、もしstateful==True
なら、最後のトレーニングからの状態が初期状態として使われます、そうでなければそれは新しい状態を生成します。私はまだstateful
をオンにしていません。しかし、私はbatch_size
がstateful==True
の時に1にしかなれないことには同意しません。
現在、収集したデータを使用してデータを生成しています。あなたの株価情報がストリームとして来るのをイメージして、すべてのシーケンシャルを集める日を待つのではなく、あなたはネットワークでトレーニング/予測しながら入力データオンラインを生成したいです。同じネットワークを共有している400株がある場合は、batch_size==400
を設定できます。
受け入れられた答えを補完するものとして、この答えはケラス行動とそれぞれの絵を達成する方法を示します。
標準的なkerasの内部処理は、次の図のように常に多対多です(ここでは、例としてfeatures=2
、pressure、およびtemperatureを使用しました)。
この画像では、他の寸法との混同を避けるために、ステップ数を5に増やしました。
この例では:
入力配列は(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つのシーケンスしかありませんが、ウィンドウを作成するために多くのシーケンスに分割しています。
「シーケンスとは」という概念は抽象的です。重要な部分は以下のとおりです。
return_sequences=True
を使うと、単純なLSTMレイヤーで多対多を実現できます。
outputs = LSTM(units, return_sequences=True)(inputs)
#output_shape -> (batch_size, steps, units)
まったく同じ層を使っても、kerasはまったく同じ内部前処理を行いますが、return_sequences=False
を使うと(あるいは単にこの引数を無視すると)、kerasは自動的に最後までのステップを破棄します。
outputs = LSTM(units)(inputs)
#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned
現在、これはkeras LSTMレイヤだけではサポートされていません。あなたはステップを増やすためにあなた自身の戦略を作成しなければならないでしょう。 2つの良い方法があります。
stateful=True
を使用します(output_features == input_features
が必要)。Kerasの標準的な振る舞いに合わせるためには、段階的に入力する必要があります。そのため、必要な長さだけ入力を繰り返すだけです。
outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)
#output_shape -> (batch_size, steps, units)
今すぐstateful=True
の考えられる使用法の1つが来ます(あなたのコンピュータのメモリに一度に収まることができないデータをロードすることを避けること以外に)
ステートフルでは、シーケンスの「部分」を段階的に入力できます。違いは:
stateful=False
では、2番目のバッチに、最初のバッチとは別に、まったく新しいシーケンスが含まれています。stateful=True
では、2番目のバッチが最初のバッチを継続し、同じシーケンスを拡張します。これら2つの主な違いは、ウィンドウ内でシーケンスを分割するのと同じです。
stateful=True
は、これらのウィンドウが単一の長いシーケンスとして接続されているのを確認します。stateful=True
では、すべての新しいバッチは前のバッチを継続するものとして解釈されます(model.reset_states()
を呼び出すまで)。
入力例、バッチ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)
を使用してください。
ここでは、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()
さて、ここで、私たちはとてもいいアプリケーションを手に入れました。
上記の「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対多」のデコーダを持つ「オートエンコーダ」です。
エンコーダ:
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)
デコーダ:
"repeat"メソッドを使う
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を理解することに関する疑問
RNNの最後のレイヤーにreturn_sequenceがある場合は、代わりにTimeDistributedを使用して単純なDenseレイヤーを使用することはできません。
これは他の人に役立つかもしれないサンプルコードの一部です。
words = keras.layers.Input(batch_shape =(None、self.maxSequenceLength)、name = "input")
# Build a matrix of size vocabularySize x EmbeddingDimension
# where each row corresponds to a "Word embedding" vector.
# This layer will convert replace each Word-id with a Word-vector of size Embedding Dimension.
embeddings = keras.layers.embeddings.Embedding(self.vocabularySize, self.EmbeddingDimension,
name = "embeddings")(words)
# Pass the Word-vectors to the LSTM layer.
# We are setting the hidden-state size to 512.
# The output will be batchSize x maxSequenceLength x hiddenStateSize
hiddenStates = keras.layers.GRU(512, return_sequences = True,
input_shape=(self.maxSequenceLength,
self.EmbeddingDimension),
name = "rnn")(embeddings)
hiddenStates2 = keras.layers.GRU(128, return_sequences = True,
input_shape=(self.maxSequenceLength, self.EmbeddingDimension),
name = "rnn2")(hiddenStates)
denseOutput = TimeDistributed(keras.layers.Dense(self.vocabularySize),
name = "linear")(hiddenStates2)
predictions = TimeDistributed(keras.layers.Activation("softmax"),
name = "softmax")(denseOutput)
# Build the computational graph by specifying the input, and output of the network.
model = keras.models.Model(input = words, output = predictions)
# model.compile(loss='kullback_leibler_divergence', \
model.compile(loss='sparse_categorical_crossentropy', \
optimizer = keras.optimizers.Adam(lr=0.009, \
beta_1=0.9,\
beta_2=0.999, \
epsilon=None, \
decay=0.01, \
amsgrad=False))