【Need Help!】深層強化学習(DQNもどき)のNNにLSTMを組み込むもうまくいかず

※記事最下部に追記あり

DQNもどき*1でFXシステムトレードシミュレーションというのをやっているのですが(下の記事からはまた幾分変化しています)、
 
qiita.com

これに、LSTMを導入してみましたが、残念ながうまくいっていません。
以下はその問題についての記述です。
 
学習時は学習データである時系列データを1足ずつなめながら何周もして、一足ごとにランダムreplayをしていたのですが、当該replayの処理をいじって、要素数32で、過去の時系列上で連続した [state, reward, 他] を memory から引っ張ってきて、特徴量データのリストと、教師データのリストを同じ要素数で作るようにして、epoch=1、batch_size=32 で fit するってな感じにしたんですが、全然収束しません。。。
(元々バッチサイズ32で1epoch fitするというような実装でした)

LSTM導入前は、一分もしたら0.0xxxぐらいのlossになっていたのですが(今のパラメータだと、1イテレーション、つまりテストデータを一周なめるのに15分ぐらいかかってる感じです)、LSTM版は6時間ぐらい経ってもlossは30から20ぐらいをうろちょとするばかり。
 なお、loss functionは huber損失関数。オプティマイザはAdam。学習率は小さすぎると時間かかるかと思って0.01とかにしています*2
 
で、気になっているのはネットワーク構成の話と入力データ(特徴量、outputに対する教師データの両方を含む)で、そこの実装を説明すべく、少しコードも交えつつ今の実装について整理すると以下のような感じなのですが、

■前提
入力データは、 特徴量10個のリストを一要素とするリスト、教師データ: 3つのアクションの報酬値(実数値)のリストを一要素とするリスト

■ネットワーク構成
        self.model = Sequential()
        self.model.add(LSTM(32, activation='relu', input_shape=(state_size, 1))
        self.model.add(RepeatVector(1))
        self.model.add(LSTM(32, activation='relu', return_sequences=True))
        self.model.add(TimeDistributed(Dense(action_size, activation='linear'))
        self.optimizer = Adam(lr=learning_rate)
        self.model.compile(optimizer=self.optimizer, loss=huberloss)

■fitの呼び出し(batch_sizeは32)
self.model.fit(x, y, epochs=1, verbose=1, batch_size=batch_size)
xとyはfitに渡す前によろしくreshapeして

x -> (32, 10, 1)
y -> (32, 3, 1)

にしている。
シェイプから分かる通り、xとyの要素数は同じにしてある


replay時の1バッチで見ると、データは時系列で並んでいるのですが、ランダムreplayをベースに実装したのもあって、次のreplay(次の足で行われる)では、違う時点での時系列上で連続なデータという形になっています。
 
もしかして、そもそもLSTMって、このようなやり方ではダメで、(学習データの期間の終わりに到達しない限り)ずっと連続なデータを渡す必要があるという話があったりするのでしょうか?


LSTMのKerasでの実装としては、手元には↓のページを参考にさせて頂いて実装した、
sweng.web.fc2.com

 
為替データを使った予測プログラムがあり、そのコードは期待通りの動作をすることを確認しており、このプログラムでの実装を取り込んだという形です。
github.com


ただ、FXシステムトレードシミュレーションのプログラムは単純に、時系列データをずらして、よろしくするといった類のものではないである点と、出力が複数要素になっている点(参考記事を参照してもらうと分かるのですが、ベースとしているコードは、複数データが出力されはしますが、個々の要素はスカラか、スカラ 1個を含む1次元リスト)、ネットワーク構成はこれでいいのか・・・という感じで悩んでいます。
 
現状のコードはこんな感じです。
github.com
 
environmentが返す stateは 32 x 10(2次元配列のリストとしては data[0-31][0-9] 的な感じ)のリストになっていて、memoryに格納する際は、その処理の前の時点で、

state = np.reshape(state, [32, 10])

と reshapeしてあります。
 
fitするためのデータを作っている箇所は以下の行のあたりです。
github.com
 
また、学習がうまくいくかどうか以前に、一番腑に落ちないのは、今のネットワークだと、10個の特徴量が32個並んだリストを与えて predict すると1個の出力(3要素のリスト)が得られるだけなのですが、学習時には32個の出力に対応する教師データを渡していて(そうでないと、fitを呼び出したときに入力と出力の array の要素数が違うぞ、とエラーになる)、そうすると、どうやってlossを計算してるのか、というのが良く分からない点。
 
そこで、ネットワーク構成のパラメータをいじって、32個出力がされるようにしたろ、と思っていろいろ試したものの、Keras(Tensorflowバックエンド)がエラーを吐いてうまくいかず。。。
唯一、RepeatVectorの引数を 1 から、出力1つの要素数である 3 にした時だけは動作して3個の出力(action数3に対応する3要素のリストが3個)が出るようになりましたが、それもおかしな話だ、と思い、実装としては採用していません。
 
=========================

以上、つらつら書いてみました。
 
根本的にLSTMの理解が誤っている可能性も大ではあるのですが、識者の方のアドバイスが頂ければ幸いです。
よろしくお願いいたします。●刀乙

追記 (2020/02/24):
Reshpeレイヤを最後に追加して、テンソルのshapeをよろしく合わせてやることで、RepeatVectorの引数をバッチサイズにして、出力されるpredictの結果を入力した教師データの数と一致させることができました。学習結果も順調です!
fx_systrade/dqn_fx_trade_tensorflow_lstm.py at 9f43ae89002cfc773ace17c788271296b554384f · ryogrid/fx_systrade · GitHub
fx_systrade/agent_fx_environment_lstm.py at 9f43ae89002cfc773ace17c788271296b554384f · ryogrid/fx_systrade · GitHub

*1:Actionによる遷移先でのMax報酬を時間割引率ガンマをかけて、足すという、更新式を使わずに、脇から別の方法で未来の報酬を過去に波及させていくというようなことをしている

*2:0.001等のLSTM採用前に用いていたパラメータでは少なくとも数十分待っても収束してく気配がなかったので