「DeepAR」の「カスタム時系列機能」を試してみた

概要

こんにちは、yoshimです。
今回はSageMakerの「DeepAR」アルゴリズムで「カスタム時系列機能」を試してみました。
この機能は「ターゲットとなる時系列について有用な情報を提供」することで、「カスタムの季節性パターン、因果効果などをモデル化する」ことができる機能です。

この機能を使うと、例えば「過去のプロモーションの情報」も学習に利用して「よりデータの内容を反映したモデリング」が可能となり、更に「今後、1週間プロモーションすると売上はどうなるか?」といった予測ができるようになります。

何らかのプロモーション(ex.メルマガ配信)をするか否かで悩んだ際に、「プロモーションをした場合、しなかった場合それぞれの需要予測」ができると嬉しいパターンもあるのではないでしょうか?

今回は「この機能でどんなことができるのか」、「必要なデータの形式と学習処理の概要」、「私がハマった点」についてご紹介しようと思います。

目次

1.「カスタム時系列機能」でどんなことができるのか

まずは、「カスタム時系列機能」でどんなことができるのか、について「モデルの学習処理時」、「推論時」の2つに分けてご紹介します。

モデルの学習処理時

まず、「カスタム時系列機能」では、「推論に影響を与えそうな情報(以下、「dynamic_feat」)」を学習に利用することができるので、「より実態を反映したモデル」を学習することが可能です。
これは直感的にも理解がしやすいかと思いますので特に言及しません。

また、「カスタム時系列機能」を使う場合でも「学習・推論時のINPUTデータ」が変わるだけなので、学習のコードの修正は殆ど必要ありません。

推論時

推論時に「dynamic_feat」を色々変更して推論できるようになります。
「時系列での推論」といったら、「a月b日の予測値はcです」のようなものが一般的に想像されるかと思いますが、「カスタム時系列機能」を使うと、「dynamic_feat」変数を変更することで、もっと柔軟な推論ができるようになります。
例えば、下記のような試行錯誤をすることが可能です。

「a月b日のPV数はどれくらいになりそうかな?」
          
    「10,000という予測結果がでた」
          
「じゃあ、この日にメルマガを50,000通送ったらどれくらいかな?」
          
    「15,000という予測結果がでた」
          
「じゃあ、100,000通にしてみたらどれくらいかな?」
          
    「17,000という予測結果がでた」
          
      「じゃあ、次は....」
          
          
          
          

上記のような試行錯誤を、「単一のモデル」で「推論時に渡す値を変更する」ことで実現できるのは嬉しいですね。

試しに適当な時系列データで「dynamic_feat」を色々変更して推論処理をしてみましょう。
青色が予測の中央値、黄色い部分が80%信頼区間です。

2015年1月4日〜10日のデータで推論しています。
まずは、「1月10日にポジティブなイベントが発生した場合の需要予測」ということで1月10日の「dynamic_feat」を変更して推論をしてみました。
若干予測値が上方修正されていることがわかります。
また、続いて1月10日の「dynamic_feat」を元に戻して、「1月4日にネガティブなイベントが発生した場合の需要予測」ということで、「dynamic_feat」を修正して推論をしてみました。

1月4日の予測値が下方修正されていることがわかるかと思います。  

2.データの形式と学習処理の概要

続いて、「学習・推論時のデータの形式」、「DeepARの学習処理の概要」について記述します。

学習時におけるデータの形式

学習時に利用するデータは「start」、「target」、「cat」、「dynamic_feat」の4項目です。
「start」、「target」の2項目は必須ですが、「cat」、「dynamic_feat」の2項目はオプションです。
もし「カスタム時系列機能」を使う場合は「dynamic_feat」も必須となります。

start:'YYYY-MM-DD HH:MM:SS'形式。文字型。「target」で渡す値の開始時点のtimestamp。  
target:実数値の配列。小数点、整数、もしくは欠損値を含んでも良い。  
cat:カテゴリー。配列で渡す。  
dynamic_feat:「カスタム時系列機能」を使って予測する際に付与する「特徴量」。「target」と同じ長さ。欠損値は許されない。  

引用:Input/Output Interface for the DeepAR Algorithm

ドキュメントには、Json形式の例として下記のように紹介されています。

{"start": "2009-11-01 00:00:00", "target": [4.3, "NaN", 5.1, ...], "cat": [0, 1], "dynamic_feat": [[1.1, 1.2, 0.5, ..]]}
{"start": "2012-01-30 00:00:00", "target": [1.0, -5.0, ...], "cat": [2, 3], "dynamic_feat": [[1.1, 2.05, ...]]}
{"start": "1999-01-30 00:00:00", "target": [2.0, 1.0], "cat": [1, 4], "dynamic_feat": [[1.3, 0.4]]}

引用:DeepAR Forecasting Algorithm

上記のように、「cat」ごとにデータを区分けして投入していく必要があります。
学習時に「cat」、「dynamic_feat」をデータに含めておいた場合は、推論時にも「cat」、「dynamic_feat」を指定する必要があります。
「target」の時間感覚(月・日・時間等)は学習時にハイパーパラメータである「time_freq」で指定したものと合わせる必要があります。

学習処理の概要

続いて「モデルの学習」の流れについて確認します。
基本的にHow the DeepAR Algorithm Worksの内容を大雑把に意訳したものです。

1.特徴量の自動生成

上記の形式で投入したデータの「start」に指定したタイムスタンプを用いて、「DeepAR」では「月」、「日」、「曜日」等の特徴量を生成します。
また、「過去のtargetの値」も利用します。
(ex.時間単位のデータの場合、1日前、2日前、3日前のtargetの値を利用しています)
これらの特徴量を自動生成し、学習に利用することで「DeepAR」では季節性や周期性を学習することができます。

上記の詳細については、How the DeepAR Algorithm Worksの「How Feature Time Series Work in the DeepAR Algorithm」をご参照ください。

2.学習

続いて、「データの一部をサンプリングして学習を実行」します。
この時サンプリングしてくるデータセットの長さは、それぞれ「過去のどれくらいの期間のデータを参照するか(context_length)」、「どれくらい未来まで予測するか(prediction_length)」を合計した長さです。

また、これは補足なのですが「学習に反映させたい情報が少なすぎないか」、に注意してください。
例えば、「プロモーション施策をした日、していない日」を区別するために「dynamic_feat」を「0,1」の2種類で指定しようとしており、「1」となる日が割合的にとても少ない場合は、十分に反映されない可能性があります。

推論時におけるデータの形式

続いて、推論処理の際のデータ形式について確認します。
「学習処理」時に指定した項目は、推論処理時にも指定する必要があります。
データ型については学習時と同じですが、意味合いが若干異なります。

start:予測を開始するtimestamp。「start」から、学習時に指定した「prediction_length」まで予測される。  
target:「start」から「context_length」に指定した過去分までの、「target」。  
cat:カテゴリー。  
dynamic_feat:「predict_length」+「context_length」の長さ分の「特徴量」。  

また、推論処理時には「configuration」という項目もオプションで指定することができます。
具体的な推論処理時に利用するデータの形式としては、下記のようなイメージになります。

{
    "instances": [
        {
            "start": "2009-11-01 00:00:00",
            "target": [4.0, 10.0, "NaN", 100.0, 113.0],
            "cat": [0, 1],
            "dynamic_feat": [[1.0, 1.1, 2.1, 0.5, 3.1, 4.1, 1.2, 5.0, ...]]
        },
        {
            "start": "2012-01-30",
            "target": [1.0],
            "cat": [2, 1],
            "dynamic_feat": [[2.0, 3.1, 4.5, 1.5, 1.8, 3.2, 0.1, 3.0, ...]]
        },
        {
            "start": "1999-01-30",
            "target": [2.0, 1.0],
            "cat": [1, 3],
            "dynamic_feat": [[1.0, 0.1, -2.5, 0.3, 2.0, -1.2, -0.1, -3.0, ...]]
        }
    ],
    "configuration": {
         "num_samples": 50,
         "output_types": ["mean", "quantiles", "samples"],
         "quantiles": ["0.5", "0.9"]
    }
}

引用:DeepAR JSON要求フォーマット

3.私がハマった点

「カスタム時系列機能」を使う際は各時点ごとの「dynamic_feat」を指定する必要があります。
この「dynamic_feat」の数値をどうするか、については少し検討が必要です。

例えば、「メルマガ配信をしたか、しなかったか」といった情報を使いたかった場合に、「0 or 1」のFLG形式にしてしまうと、「プロモーション施策の強弱の程度」という情報が欠損してしまいます。

なのでこういった場合は、「0 or 1」ではなく「メルマガ配信通数」に応じて「dynamic_feat」の値を指定する、等の調整をしてあげるとより良い予測ができるかと思います。
(当然ですがこの「dynamic_feat」の値は「学習」と「推論」の際にスケールを合わせる必要がある点にはご注意ください。)

4.まとめ

長くなりましたが、「DeepAR」の「カスタム時系列機能」のご紹介を終わります。
どちらかというと備忘録的なものになってしまった気もしますが、どなたかの参考になれば幸いです。