web-dev-qa-db-ja.com

Kerasによる多変量マルチタスクLSTMの構築

プリアンブル

私は現在、機械学習の問題に取り組んでおり、今後の販売量を予測するために(販売店が在庫をより適切に計画できるようにするため)製品の販売に関する過去のデータを使用する必要があります。基本的に時系列データがあり、製品ごとに、どの日に何台販売されたかがわかります。また、天候や祝日の有無、商品の販売状況などもお知らせしています。

密なレイヤーを備えたMLPを使用し、スライディングウィンドウアプローチを使用して周囲の日の販売量を含めることで、これをある程度成功させることができました。ただし、LSTMなどの時系列アプローチを使用すると、はるかに優れた結果を得ることができると考えています。

データ

私たちが持っているデータは基本的に次のとおりです。

enter image description here

EDIT:明確にするために、上の図の「時間」列は正しくありません。入力は1か月に1回ではなく、1日1回です。構造は同じです!)

したがって、Xデータは次のようになります。

(numProducts, numTimesteps, numFeatures) = (50 products, 1096 days, 90 features)

そしてYデータは形です:

(numProducts, numTimesteps, numTargets) =  (50 products, 1096 days, 3 binary targets)

enter image description here

したがって、3年間(2014年、2015年、2016年)のデータがあり、2017年の予測を行うためにこれについてトレーニングしたいと考えています。(もちろん、実際には2017年10月までのデータがあるので、100%正しいわけではありませんが、今は無視してください)

問題

これらの予測を可能にするLSTMをケラスで構築したいと思います。私が行き詰まっているところがいくつかあります。だから私は6つの具体的な質問があります(Stackoverflowの投稿を1つの質問に制限しようとするはずですが、これらはすべて絡み合っています)。

まず、バッチのデータをどのようにスライスしますか?私には3年間あるので、サイズが1年ごとに3つのバッチを単純にプッシュすることは理にかなっていますか?または、より小さなバッチ(たとえば30日間)を作成し、スライディングウィンドウを使用する方が理にかなっていますか?つまり各30日の36バッチの代わりに、各30日の36 * 6バッチを使用し、毎回5日ずつスライドしますか?それとも、これは実際にはLSTMの使用方法ではありませんか? (データにはかなりの季節性があることに注意してください。そのような長期的な傾向も把握する必要があるためです)。

次に、使用するのは理にかなっていますかreturn_sequences=Trueここですか?つまり、Yデータを(50, 1096, 3)のままにして、ターゲットデータに対して損失を計算できるすべてのタイムステップで(私が理解している限り)予測があるようにしますか?または、return_sequences=Falseを使用して損失を評価するために各バッチの最終値のみを使用する方がよいでしょう(つまり、年次バッチを使用する場合、製品1の2016では、2016年12月の値に対して評価します(1,1,1))。

第3に50の異なる製品をどのように扱うべきですか?それらは異なりますが、それでも強い相関関係があり、他のアプローチ(MLPなど)で見てきました単純な時間枠を使用して)、すべての製品を同じモデルで検討すると、結果が良くなります。現在検討中のアイデアは次のとおりです。

  • ターゲット変数を3つの変数だけでなく、3 * 50 = 150に変更します。つまり、各製品には3つのターゲットがあり、すべてが同時にトレーニングされます。
  • lSTM層の後の結果を50の高密度ネットワークに分割します。これは、LSTMからの出力と、各製品に固有のいくつかの機能を入力として使用します。つまり、50の損失関数を持つマルチタスクネットワークを取得し、それを最適化します。一緒。それはクレイジーでしょうか?
  • 製品を単一の観察と見なし、LSTMレイヤーにすでにある製品固有の機能を含めます。この1つのレイヤーだけを使用し、その後にサイズ3の出力レイヤーを使用します(3つのターゲットの場合)。各製品を個別のバッチでプッシュします。

第4に、検証データの扱い方?通常、無作為に選択されたサンプルを除外して検証しますが、ここでは時間の順序を維持する必要があります。だから私は、数ヶ月だけ脇に置くのが最善だと思いますか?

第5に、これはおそらく私にとって最も不明瞭な部分です-実際の結果を使用して予測を実行するにはどうすればよいですかreturn_sequences=Falseを使用して、次の値(2014年12月、2015年12月、2016年12月)を予測するモデルのトレーニングを目的として、3バッチすべて(それぞれ11月まで)でトレーニングしたとします。これらの結果を2017年に使用したい場合、これは実際にはどのように機能しますか?私がそれを正しく理解した場合、このインスタンスで実行できる唯一のことは、モデルに2017年1月から11月までのすべてのデータポイントをフィードすることです。これにより、2017年12月の予測が返されます。それは正しいですか。ただし、return_sequences=Trueを使用し、2016年12月までのすべてのデータでトレーニングした場合、2017年1月に観測された機能をモデルに与えるだけで、2017年1月の予測を取得できますか?それとも、2017年1月の12か月前にそれを与える必要がありますか? 2017年2月についてはどうですか?さらに、2017年の値に加えて、さらにその11か月前に値を与える必要がありますか? (私が混乱しているように聞こえるなら、それは私がいるからです!)

最後に、使用する構造に応じて、Kerasでこれを行う方法を教えてください。私が現時点で考えているのは、次のようなものです(これは1つの製品のみを対象としているため、すべての製品を同じモデルに含めることは解決しません)。

Kerasコード

trainX = trainingDataReshaped #Data for Product 1, Jan 2014 to Dec 2016
trainY = trainingTargetReshaped
validX = validDataReshaped #Data for Product 1, for ??? Maybe for a few months?
validY = validTargetReshaped    

numSequences = trainX.shape[0]
numTimeSteps = trainX.shape[1]
numFeatures = trainX.shape[2]

numTargets = trainY.shape[2]

model = Sequential()
model.add(LSTM(100, input_shape=(None, numFeatures), return_sequences=True)) 
model.add(Dense(numTargets, activation="softmax"))    

model.compile(loss=stackEntry.params["loss"],
      optimizer="adam",
      metrics=['accuracy'])

history = model.fit(trainX, trainY,
            batch_size=30,
            epochs=20,
            verbose=1,
            validation_data=(validX, validY))               

predictX  = predictionDataReshaped #Data for Product 1, Jan 2017 to Dec 2017

prediction=model.predict(predictX)
24
Karl

そう:

まず、バッチのデータをどのようにスライスしますか?私には3年間あるので、サイズが1年ごとに3つのバッチを単純にプッシュすることは理にかなっていますか?または、より小さなバッチ(たとえば30日間)を作成し、スライディングウィンドウを使用する方が理にかなっていますか?つまり各30日の36バッチの代わりに、各30日の36 * 6バッチを使用し、毎回5日ずつスライドしますか?それとも、これは実際にはLSTMの使用方法ではありませんか? (データにはかなりの季節性があることに注意してください。そのような長期的な傾向も把握する必要があるためです)。

正直なところ、そのようなデータをモデル化することは本当に難しいことです。まず、LSTMsは少し異なる種類のデータ(例:NLPや音声ではなく、長期的な依存関係をモデル化することが重要であり、季節性ではない)をキャプチャするように設計されているため、使用をお勧めしません。 )そして学習するには多くのデータが必要です。 GRU または SimpleRNN のどちらかを使用することをお勧めします。どちらの方法も学習しやすく、タスクに適しています。

バッチ処理については、固定ウィンドウテクニックを使用することをお勧めします。これは、1年または1か月を供給するよりもはるかに多くのデータポイントを生成することになるためです。日数をメタパラメータとして設定し、トレーニングでさまざまな値を使用して最適な日を選択することで最適化されます。

季節性に関しては-もちろん、これは事実ですが:

  • シーズンの傾向を適切に推定するには、収集するデータポイントと年が少なすぎる可能性があります。
  • あらゆる種類のリカレントニューラルネットワークを使用してこのような季節性を捉えることは、本当に悪いアイデアです。

代わりに行うことをお勧めします:

  • 季節的な機能を追加してみてください(例:月変数、日変数、その日に特定の休日がある場合にtrueに設定される変数、または次の重要な休日までの日数-これはあなたが本当にいることができる部屋です)クリエイティブ)
  • 昨年の集計データを機能として使用します。たとえば、昨年の結果またはそれらの集計を、昨年の結果の移動平均、最大、最小などのようにフィードできます。

次に、ここでreturn_sequences = Trueを使用することは理にかなっていますか?言い換えると、Yデータを(50、1096、3)のままにして、ターゲットデータに対して損失を計算できるすべてのタイムステップで(私が理解している限り)予測があるようにしますか?または、return_sequences = Falseを使用して、各バッチの最終値のみを使用して損失を評価する方がよいでしょう(つまり、年次バッチを使用する場合、製品1の2016では、2016年12月の値(1 、1、1))。

return_sequences=Trueを使用すると便利な場合がありますが、次の場合に限られます。

  1. 指定されたLSTM(または別の再帰レイヤー)の後に、さらに別の再帰レイヤーが続く場合。
  2. シナリオ-異なる時間枠でモデルを同時に学習しているものなどによって、シフトされた元のシリーズを出力としてフィードする場合など。

2番目のポイントで説明した方法は興味深いアプローチかもしれませんが、生産結果を得るためにモデルを書き直す必要があるため、実装が少し難しい場合があることを覚えておいてください。さらに難しいのは、多くのタイプの時間不安定性に対してモデルをテストする必要があることです。そのようなアプローチでは、これを完全に実行不可能にする可能性があります。

3番目に、50の異なる製品をどのように処理すればよいですか?それらは異なりますが、それでも強い相関関係があり、他のアプローチ(たとえば、単純な時間枠を持つMLP)で、すべての製品を同じモデルで検討すると、結果が良くなることがわかりました。現在検討中のアイデアは次のとおりです。

  • ターゲット変数を3つの変数だけでなく、3 * 50 = 150に変更します。つまり、各製品には3つのターゲットがあり、すべてが同時にトレーニングされます。
  • lSTM層の後の結果を50の高密度ネットワークに分割します。これは、LSTMからの出力と、各製品に固有のいくつかの機能を入力として使用します。つまり、50の損失関数を持つマルチタスクネットワークを取得し、それを最適化します。一緒。それはクレイジーでしょうか?
  • 製品を単一の観察と見なし、LSTMレイヤーにすでに存在する製品固有の機能を含めます。この1つのレイヤーだけを使用し、その後にサイズ3の出力レイヤーを使用します(3つのターゲットの場合)。各製品を個別のバッチでプッシュします。

私は間違いなく最初の選択肢を選びますが、詳細な説明をする前に、2番目と3番目の欠点を説明します。

  • 2番目のアプローチ:怒ることはありませんが、製品ターゲット間の多くの相関関係が失われます。
  • 3番目のアプローチでは、異なる時系列間の依存関係で発生する多くの興味深いパターンが失われます。

私の選択に入る前に-データセットの冗長性-さらに別の問題について説明しましょう。私はあなたが3種類の機能を持っていると思います:

  • 製品固有のもの(それらの「m」があるとしましょう)
  • 一般的な機能-それらの「n」があるとしましょう。

これでサイズ(timesteps, m * n, products)のテーブルができました。一般的な機能はすべての製品で同じであるため、これを形状テーブル(timesteps, products * m + n)に変換します。これにより多くのメモリが節約され、リカレントネットワークへのフィードが可能になります(kerasのリカレントレイヤーにはフィーチャディメンションが1つしかないのに対し、productfeature ones)。

では、なぜ私の最初のアプローチが最善だと思いますか?データから多くの興味深い依存関係を利用しているためです。もちろん、これはトレーニングプロセスに害を及ぼす可能性がありますが、これを克服する簡単な方法があります:次元削減。たとえば、 150次元ベクトルでPCAをトレーニングし、そのサイズをはるかに小さいものに減らします。依存関係がPCAでモデル化されているため、出力ははるかに適切なサイズになります。

4番目に、検証データをどのように処理しますか?通常、無作為に選択されたサンプルを除外して検証しますが、ここでは時間の順序を維持する必要があります。だから私は、数ヶ月だけ脇に置くのが最善だと思いますか?

これは本当に重要な質問です。私の経験から-ソリューションが正常に機能することを確認するには、さまざまな種類の不安定性に対してソリューションをテストする必要があります。覚えておくべきいくつかのルール:

  • トレーニングシーケンスとテストシーケンスの間にオーバーラップがない必要があります。そのような場合は、トレーニング中にモデルに供給されたテストセットからの有効な値があります。
  • 多くの種類の時間依存性に対してモデル時間の安定性をテストする必要があります。

最後の点は少し曖昧かもしれません-いくつか例を挙げましょう:

  • 年の安定性-2年の可能な各組み合わせを使用してモデルをトレーニングし、ホールドアウト1年でモデルを検証します(例:2015、2016、2017、 2015、2017、2016など)-年の変更がモデルにどのように影響するかを示します。
  • 将来の予測の安定性-週/月/年のサブセットでモデルをトレーニングし、次の週/月/年の結果を使用してテストします(例:トレーニング) 2015年1月、2016年1月、2017年1月に、2015年2月、2016年2月、2017年2月のデータなどを使用してテストします)。
  • 月の安定性-テストセットで特定の月を維持するときにモデルをトレーニングします。

もちろん-あなたはさらに別のホールドアウトを試すことができます。

第5に、これがおそらく最も不明瞭な部分です。実際の結果を使用して予測を実行するにはどうすればよいですか。 return_sequences = Falseを使用して、次の値(2014年12月、2015年12月、2016年12月)を予測するモデルをトレーニングすることを目的として、3バッチすべて(それぞれ11月まで)でトレーニングしたとします。これらの結果を2017年に使用したい場合、これは実際にはどのように機能しますか?私がそれを正しく理解した場合、このインスタンスで実行できる唯一のことは、モデルに2017年1月から11月までのすべてのデータポイントをフィードすることです。これにより、2017年12月の予測が返されます。それは正しいですか。ただし、return_sequences = Trueを使用し、2016年12月までのすべてのデータでトレーニングした場合、2017年1月に観測された機能をモデルに与えるだけで、2017年1月の予測を取得できますか?それとも、2017年1月の12か月前にそれを与える必要がありますか? 2017年2月についてはどうですか?さらに、2017年の値に加えて、さらにその11か月前に値を与える必要がありますか? (私が混乱しているように聞こえるなら、それは私がいるからです!)

これは、モデルの構築方法によって異なります。

  • return_sequences=Trueを使用した場合は、return_sequence=Falseを使用するように書き直すか、出力を取得して、結果の最後のステップのみを考慮する必要があります。
  • 固定ウィンドウを使用した場合-モデル化する予測の前にウィンドウをフィードする必要があります、
  • さまざまな長さを使用した場合-必要な予測期間を経過する任意のタイムステップをフィードできます(ただし、少なくとも7日間をフィードすることをお勧めします)。

    最後に、使用する構造に応じて、Kerasでこれをどのように行うのですか?私が現時点で考えているのは、次のようなものです(これは1つの製品のみを対象としているため、すべての製品を同じモデルに含めることで解決するわけではありません)。

ここに-あなたが選んだモデルの種類に関する詳細情報が必要です。

13
Marcin Możejko

質問1

この問題にはいくつかのアプローチがあります。あなたが提案するのはスライディングウィンドウのようです。

しかし、実際には時間ディメンションをスライスする必要はなく、一度に3年すべてを入力できます。バッチがメモリと速度に対して大きすぎる場合は、製品ディメンションをスライスできます。

形状(products, time, features)の単一の配列で作業できます

質問2

はい、return_sequences=Trueを使用するのは理にかなっています。

私があなたの質問を正しく理解した場合、あなたは毎日yの予測を持っていますよね?

質問3

それは本当に未解決の問題です。すべてのアプローチには利点があります。

ただし、すべての製品機能をまとめることを検討している場合、これらの機能が異なる性質であるため、すべての製品のすべての機能を考慮した大きなワンホットベクトルがあるかのように、可能なすべての機能を拡張する必要があります。

各製品にそれ自体にのみ適用される独立した機能がある場合、製品ごとに個別のモデルを作成するという考えは私にはめちゃくちゃに思えません。

また、製品IDをワンホットベクトル入力にして、単一のモデルを使用することもできます。

問題4

選択するアプローチに応じて、次のことができます。

  • 一部の製品を検証データとして分割します
  • タイムステップの最後の部分を検証データとして残す
  • トレーニングとテストに異なる長さを残して相互検証メソッドを試してください(ただし、テストデータが長いほどエラーは大きくなりますが、このテストデータを固定長にトリミングすることをお勧めします)。

問題5

多くのアプローチがあるかもしれません。

スライディングウィンドウを使用する方法があります。モデルを固定時間の長さでトレーニングします。

また、LSTMレイヤー全体をトレーニングするアプローチもあります。この場合、最初に既知の部分全体を予測し、次に未知の部分の予測を開始します。

私の質問:Xデータは、Yを予測する必要がある期間についてわかっていますか?この期間ではXも不明であるため、Xも予測する必要がありますか?

質問6

この質問とその回答をご覧になることをお勧めします: ケラスの多変量LSTMでのマルチステップ時系列予測の扱い方

このアイデアをうまく​​管理しているこのノートブックも参照してください。 https://github.com/danmoller/TestRepo/blob/master/TestBookLSTM.ipynb

ただし、このノートブックでは、XとYを入力として使用するアプローチを使用しました。そして、将来のXとYを予測します。

Xを予測するためだけにモデルを作成できます(その場合)。次に、XからYを予測するための2番目のモデル。

別のケース(すべてのXデータが既にあり、Xを予測する必要がない場合)は、XからYのみを予測するモデルを作成できます(ノートブックのメソッドの一部に従います。最初に、既知のYを使用して、モデルをシーケンス内のどこに調整するかを決定し、不明なYを予測します)-これは、単一の全長X入力(最初にトレーニングXを含み、最後にXをテストします)。

ボーナス回答

どのアプローチとどの種類のモデルを選択するかを知ることは、おそらく競争に勝つための正確な答えです...したがって、この質問に対する最良の答えはありません。すべての競合他社がこの答えを見つけようとしています。

4
Daniel Möller

すでに提供されている2つの回答に続いて、LSTMを使用した売上予測に関するAmazon Researchのこの記事を見て、言及された問題を処理する方法を確認する必要があると思います。

https://arxiv.org/abs/1704.0411

さらに、リカレントネットワークを使用する場合は、適切に正則化することが非常に重要であることも指摘しておきます。この記事で説明されている「変分再発性ドロップアウト」をご覧になることをお勧めします

https://arxiv.org/abs/1512.05287

注:これはすでにTensorflowに実装されています。

0
Martin Keller