Machine Learning Design Patterns

Scaling

  • Min-max & clipping は一様分布に良い
  • Z-score は正規分布に良い。
  • input data によっては non-linear な変換の方が適切。例えば Wikipedia page views。これは正直意識してなかった。

この視点で圧力コンペのデータでやってみた(02-01-scaling.ipynb)

Categorical

入力が array of categorical である場合は考えたこともなかった。dummy と one hot encoding の違いを理解した。

Design Pattern 1: Hashed Feature

Kaggle では経験のないパターン。新しい ID や cold start にも対応できるのが良い。学習データにはない空港が建設された場合どうするか。というのはわかりやすい例だった。感覚的には hash が衝突して全く関係のない入力同士が同じ bucket に入るとうれしくないような。categorical_column_with_hash_bucket の使用例がなかったので書いてみた。 (https://github.com/higepon/Machine-Learning-Design-Patterns/blob/main/pattern-1-hashed-feature.ipynb

Design Pattern 2: Embeddings

Embeddings は散々使い倒してきたので実装はしない。Embedding size の目安の指標は知らなかったのでメモ。Image の auto encoder による dimension reduction は使ったことないので今度やる。

one rule of thumb is to use the fourth root of the total number of unique categorical elements while another is that the embedding dimension should be approximately 1.6 times the square root of the number of unique elements in the category, and no less than 600

Design Pattern 3: Feature Cross

Kaggle で行われている feature engineering の中で最もシンプルなもの。モデルには見えないものを作って見せる。もしくはモデルには見えるかもしれないが学習に時間がかかるものを直接見せる意味合いがある。Crossed feature の見つけ方を書いてくれたらもっと良かった。

Design Pattern 4: Multimodal Input

種々の feature を concatenate して feed するやつ。きちんとした名前がついているのは知らなかった。Kaggle でも多用されてる。別種の embeddings を concatenate するとか。

Design Pattern 5: Reframing

Reframing とは Machine Learning Model の Output の種類を変えること。例)Regression が自然なのに Classification にする(またはその逆)。

  • 例:降水量予測問題
    • 問題
      • Output は降水"量" なので実数を予測する regression タスクだろうか?
      • 実際にやってみると同じ feature に対して降水量が 0.3 cm のときも 0.5 cm の時もある。
    • 解法
      • そもそも降水は確率的な振る舞いをするので 1 つの実数値を予測する Regression モデルは合っていないのかも。
      • Classification model として Reframe する。
        • Classification 例: 離散確率分布として考える。
          • Single real value を予測するのではなく。ある範囲の降水量のどのクラスに属するかをそれぞれのクラスの確率を予測する。
          • この Classification model では異なる降水量の分布を得ることができるのが single value prediction の Regression model と大きく違う。Regression model だと分布のmeanをとってしまうことになる。
    • なぜ良いか?
      • bucketing により precision をある程度犠牲にしてしまうが離散化した classification の方が複雑な target を学習するのがうまいらしい。
      • 赤ちゃんの体重の確率分布の話はとても面白かった。best root mean square error が stddev に一致するのも納得。
  • 逆の例:ユーザーの過去見た video id とその raring (1-5) を入力に次に見る video を1つ recommend する classification problem。
    • Regression problem として video の user space での characteristics を output する

Design Pattern 6: Multilabel

  • 画像の中にいる複数の動物名を特定する。文章からふさわしい複数の tag を生成する。
  • 単純な classification なら softmax + argmax で選ぶ。dog, cat, rabbit から1つ選ぶなら [.89, .02, .09] で argmax。足すと1になることに注意。
  • 解法
    • sigmoid で [.92, .85, .11] のように各要素で 0-1 の確率を出す。
  • 各種 classification まとめ
    • binary classification
      • softmax は冗長なので sigmoid + binary cross entropy loss。
    • multilabel
      • sigmoid + binary cross entropy loss。
    • sigmoid 結果の parse 方法
      • softmax + argmax のようには行かない。各クラス label を採用するか threshold が必要。

Design Pattern 7: Ensembles

  • Model の Prediction に誤差がある。なぜか?
    • (1) 減らせない誤差:dataset にある noise、問題の framing、よくない訓練データなどに由来する誤差。
    • (2) bias=Underfit.
    • (3) vairiance=overfit.
  • Ensemble 手法
    • Bagging: high variance を解決する。k個のモデルに対して k 個の subsample された学習データを用意。各モデルの出力を aggregate する(mean / majority vote)
    • Boosting: Ensemble Model は各サブモデルよりも capacity を上げるので bias を減らす方向に動く。Gradient Boosting の boosting。
  • Dropout は bagging の一種と考えることもできるというのは目から鱗だった。

Design Pattern 8: Cascade

  • 問題
    • usual(よく起きる)とunusual(滅多に起きない)の両方に対して値を予測したい。モデルは滅多に起きないことを無視する方向で学習してしまう。
    • unusualの方をoverweightする方法もあるがusualの方が精度が落ちてしまう
    • 直感的には以下のCascade Design Patternを思いつくだろう
      • usualかunusualかを予測するモデルを作る
      • usualケースを予測するモデルを作る
      • unusualケースを予測するモデルを作る
      • 本番時のpredictionでは1つ目のモデルの出力に応じて1つ目もしくは2つ目のモデルを呼び出して予測
    • 上記の問題は。1つ目のモデルのtrue labelがないこと。1つ目のモデルが間違った場合、2つ目3つ目のモデルは今まで見たことのないような入力で予測をする羽目になる。
  • 解法
    • usualかunusualかを予測するモデルを作る
    • usualケースを予測するモデルを作る
    • unusualケースを予測するモデルを作る
    • 2つ目と3つ目のモデルの出力を入力にするモデルを作る(これが最終出力)
  • 注意点:他のパターンと違いこのパターンはベストプラクティスとは限らない。複雑である。パフォーマンス悪くなるかも。MLの問題を分割するのは一般的に良くない。なぜならばMLは複数の要素が絡んだものを学習する能力が備わっているから。

Design Pattern 9: Neutral Class

薬処方でイブプロフェンアセトアミノフェンどちらを処方するか?というbinary classificationではなく。どちらでも良いというneutralなクラスを追加するという話。全然関係ないけど null object pattern を思い出した。

Design Pattern 10: Rebalancing

  • 問題: 特定のクラスのデータが少ないとモデルがそのクラスの分類を学習してくれない。
  • 解法
    • 適切なevaluation metricを選ぶ
      • F-measureとか。test set はオリジナルデータセットと同じバランスでなければいけない。
    • Downsampling
      • majority class のデータ数を学習時に減らす。
      • ensembleと組み合わせることが多い。その場合はmedianをとる。減らす majority クラスをその度にランダムに変えてモデルを学習すれば良い。
    • Weighted classes
    • Kerasならclass_weight で特定のクラスが重要だよとモデルに教えることができる。=> よく効いた
    • Output Layer Bias
      • class weightに追加してモデルのoutput layerのbiasをimbalanceを加味してセットする。=> 効いた
    • Upsampling
      • 特定のクラスのデータを複製して増やしたり、生成する。down samplingと合わせて行われる。
      • SMOTE は生成を自動でやってくれるアルゴリズム
    • Cascade パターンも使える
    • down sampling と class weightを組み合わせることもできる。down sampling 後のバランスに合わせてclass weightを設定する。
    • SMOTE を利用したover sampling も試して効いた。

Design Pattern 11: Useful Overfitting

  • 意図的に training data に overfit して利益を得る。
  • 以下のような場合には overfitting が望ましい
    • input が物理ベースのもので数式で precise state が計算できる場合など。それを模倣するように model に学習させる場合は overfitting させるべき。
    • Distilling bigger model の場合も。小さなモデルは bigger モデルが生成した training data に overfit すべき。

Design Pattern 12: Checkpoints

  • 学習時間が伸びるにつれてエラーで止まった時のコストが高い。checkpoint を保存しておけば途中からトレーニングを再開できる。
  • 作者も書いていたがこれは実は簡単ではなくて、learning rate とか optimizer なども復元しないといけない。Colab がもっと弱かった頃はかなり頑張って resume できるようにしていたが最近はサボってる。

Design Pattern 13: Transfer Learning

  • pretrained model の final output layer を取り除き(正確には flatten 以降)モデルを nontrainable にする。final layer をすげ替えて学習すれば完成。以前 Kaggle のコンペの public notebook でこの方法を学んだが。なぜうまくいくのか?を直感的に理解していなかったので良い学びがあった。著者らが公開しているnotebookは必ず実行してみるべき。驚くほど短い training でそれなりの精度が出る。
  • fine-tuning は完全に nontrainable にするのではなくて一部のlayersをtrainable にする。
    • その分学習に時間がかかる
    • train data が多く。元のモデルと同じ種類のデータの場合はこちらの方が効くかも。
  • Transfer learning は text & image がメインだが TabNet は tabular data で良い結果を残しつつある。

Design Pattern 14: Distribution Strategy

  • データ量とモデルのサイズは大きくなるばかり。シングルGPUだと学習時間が14 daysとかも。
  • 方法は2つ
    • data parallelism
      • 各ワーカーが training data のサブセットに対して処理をする
      • synchronous training
        • 各ワーカーはモデルのコピーを持っていて forward 後 gradient を計算。各ワーカーの gradient を集約して中央サーバーが gradient step してモデルパラメータを更新。最新のモデルを各ワーカーに渡す。
        • 待ち合わせやワーカー同士のコミュニケーションで overhead がある。
        • 1つのマシン+ multiple GPUs だと速くできる。
        • overhead があるので batch size を可能な限り大きくするべき。ただし val_loss が急激に大きくなる場合があるので注意。
      • asynchronous training
        • 各ワーカーの gradient を集約せず、asynchronous でパラメータを更新するのでスループットが高い。
    • model parallelism
      • model が分割され各ワーカーはモデルの一部を担当する

Design Pattern 15: Hyperparameter Tuning

  • 全ての組み合わせを試すのは無理。
  • keras-tuner library (Baysian optimization)

Design Pattern 16: Stateless Serving Function

  • 問題
    • train したモデルをそのまま production に deploy するといくつか問題がある
    • (1) Model をメモリにロードしなければならないがとても大きい(embedding layers, deep なモデルなど)
    • (2) train 時は Python で書かれていたが、Serving 時は違う言語でという要求がある
    • (3) Model の input/output の形式は training に最適化されているが user friendly とは言えない。例えば serialized binary より JSON の方がうれしいとか。
  • 解法
    • Model export: learning rate, drop-out など不要なものを取り除いて model の数学的なコアのみを export する
    • Inference: serving_fn として取り出して実行する
    • Web endpoint: Cloud function などで stateless に export する

仕事でMLしたことがないので。production deployment の話は面白い。Web フレームワークという成熟した技術基盤に乗せてしまい。監視・スケーラビリティなどを任せようというすっきりした解法であった。

Design Pattern 17: Batch Serving

  • 問題: 1つのリクエストで全ユーザーのプレイリストを作るようなユースケースではどうすれば良いか?
  • 解法
    • Distributed Data Processing (BiqQueryなど) で簡単にできるよ。

Design Pattern 18: Continued Model Evaluation

  • 問題: Model を deploy して終わりではない。production でも意図通り動いているか?もし動かなくなったら検出できる?
  • 解法
    • モデル性能悪化をモニタリングする。そのためには raw_data, ground truth, prediction が必要。
    • Serving 時にサンプリングして raw_data, prediction を保存。ground truth は通常遅れて入手されることが多い。
  • これも Kaggle では学べないもの。継続的にモニタリングして性能が意図通りか確認することは予想できていたが、ground truth の入手は serving 時よりかなり遅れることがある。などの課題には気づいてなかった。counterfactual も考えると難しいね。

Design Pattern 19: Two-Phase Predictions

  • 問題: ユーザーの device で prediction したい時がある(フィットネスアプリとか)。その場合はモデルのサイズなどトレードオフがある。
  • 解法: 問題を2つに分ける。シンプルで edge で実行するもの。それを引き継いでクラウド側でやるもの。例: Google Home

Design Pattern 20: Keyed Predictions

  • 問題: 大量の入力に対する出力は分散して predict される。分割された output を元の input に対応する形で整える必要あり。
  • 解法: client に入力とともに key を指定させる。

Design Pattern 21: Transform

  • 問題: Model への input は実際に model が計算に使う形式とは限らない。入力は text だが計算に使うのは embedding vectorとか。training 時とprediction時の何らかの入力の違いによるミスは大問題。
  • 解法: input を feature にする部分をきちんと認識して分ける(Transform)
    • 驚くべきはBigQuery がTransform句をサポートしていること。こういう間違いが起きない強制力は素晴らしいと思う。prediction 時だけ特定の feature engineering 忘れるとかなくなる。
    • Tensorflow は feature engineering をグラフに含める方法をサポートしている。tf.keras.layers.Lambda でやるやつ。
      • cons: feature engineering とモデルを分けられないので、別モデルを試しづらい。feature engineering のキャッシュが難しい。feature engineering の結果のデータ分析が難しい。

Design Pattern 22: Repeatable Splitting

test, train, valid のデータ分割の話。Kaggle で実地で学んだので略。

Design Pattern 23: Bridged Schema

  • 問題: デリバリーのチップ額を予測するモデル。支払いタイプが現金とカードで予測するモデルがある。データ元の改善によりカードの詳細が取れるようになった(gift, debit, credit) 。今すぐにでもこの有用なデータでモデルと学習し直したいがまだデータが少ない。どうするか?
  • 解法
    • 古いデータの schema を新しいデータにマッチするようにブリッジする。新しいデータは可能な限り全て、古いデータは augment してモデルを学習する。
    • スキーマをブリッジするとは?古いデータの支払いタイプカードは本当は新しいデータタイプの gift, debit, credit のどれかだったはずだがそれは記録されていない。これを probalistically or statically にブリッジできる。
      • Probabilistic method: 新しいデータではカード種別の割合が分かっているので(例: 10%, 30%, 60%)古いデータをロードするたびに一様分布から0-100数値を取り出す。それに応じて古いデータのカード種別を設定する。
      • おすすめStatic method: カテゴリカル変数は one-hot encodingされることが多いので。古いデータの支払いタイプは [0, .1, .3, .6] とする。新しいデータの方はそのまま [0, 0, 1, 0] などとする。
    • 他にやること
      • まず新しいデータから十分な evaluation データをとっておく。件数は evaluation metrics が安定するくらいに。
      • bridge する古いデータの件数を決める。

Design Pattern 24: Windowed Inference

  • 問題: 空港の発着の遅れについて。「通常より遅れているか?」を判定したい。時間帯によって遅れの傾向は違うので2時間のタイムウィンドウの中で異常値加判定する。prediction 時にはどうすれば良いのか?
  • 解法
    • モデルの state を時間に沿って保存する stream processing を実行する
      • フライト到着時間のスライディングウインドウを作る。ウィンドウは2時間で終わるが10分ごとに閉じる。つまり10分毎に過去2時間の集約値を計算する。
      • モデルの内部stateは新しいフライト情報が入り次第更新される。
      • ウィンドウが閉じるたび(この例では10分毎)に time series ML モデルが2時間のフライトリスト情報で学習を行う。そしてこのモデルはこれから未来のpredictionに使われる。
      • time series モデルパラメータは状態変数として外に保存される。LSTMの場合model weightがこれに当たる。
      • このシンプルな例ではモデルパラーメタは2時間ウィンドウの平均遅延時間と偏差になる。

        Design Pattern 25: Workflow Pipeline

  • end to end の model deploy運用をコンテナ化で行うという。もっともな内容。まあそうですよね。

Design Pattern 26: Feature Store

  • 問題: Feature engineering はad hocかつone offになりがちなのでプロジェクトや組織をまたいだ共有が難しい。
  • 解法: 一箇所にコードとドキュメントをまとめてそこを使うようにする。オープンソースの実装もいくつかある。

Design Pattern 27: Model Versioning

  • 問題: モデルを更新したいが後方互換性も維持したい
  • 解法: 新しいモデルは別のRest API endpointにデプロイする

Design Pattern 28: Heuristic Benchmark

  • 問題: 自転車レンタル使用時間の予測モデルのtest set に対する MAE が 1200 秒である。これはビジネスの観点から良いか悪いのか?特にこれが初めて作ったモデルだと比較対象がない
  • 解法: 直感的に理解でき、比較的簡単に計算できるmetricsを定義する。 Table 7-1の例がとても良い。

Design Pattern 29: Explainable Predictions

  • 問題: test set に対する MAE などの指標が分かってもそれだけではユーザーからの信頼は得られない。なぜその結果になったのか説明してほしい。もしかしたら意図しないbiasをもとに判断しているかも。
  • 解法: feature attributions。各々のfeatureがどの程度出力に寄与したかを求める。
    • Instance level attributions: 各予測に対して attribution を求める。例)特定の決済がなぜ承認されたか?
    • Global attributions: モデル全体として attribution を求める。instance level の平均と言っても良い。例)飛行機の遅延時間予測では天候が一番原因となっている。
    • ここで SHAP 登場。

Design Pattern 30: Fairness Lens

  • 問題: 学習データやパイプラインのどこかで問題のあるバイアスが入り込むことがある。
  • 解法: 学習前にバイアスを特定し、学習したモデルを Fairness Lens を通して評価する。モデルとデータで全てのユーザーグループを平等に扱う。
    • Training 前
      • Data Analysis をして Data bias を見つける。例) race, gender などが balanced かどうか。classification problem なら label が balanced かどうか?data label をする人の主観 bias はないか?
      • 上記 balance を維持したまま train, test, valid のデータ分割を行う。
      • What if tool が便利そう
    • Training 後
      • model に bias が入り込むことがある。原因はデータにあった未発見のbias、モデルアーキテクチャ、optimization metrics など。
      • training 後の model を What if tool に渡して test set に対する prediction を見てみる