【論文】Machine Learning: The High Interest Credit Card of Technical Debt (D. Sculley et al., Google, 2014)
https://research.google.com/pubs/pub43146.html
概要
Googleによる論文。機械学習を安易にシステムに取り込むのは大きな技術的負債を抱え込む恐れがあるという内容。リスクの要因としては、境界の浸食、もつれ、隠れたフィードバック、想定外利用、データ依存関係、外界の変化などがある。
詳細
【技術的負債 (technical debt)】
不完全なソースコードをリリースするのは借金をするようなもので、不完全ゆえにメンテナンスなどが発生するのは借金の利子を払っているのと同じこと、という考え方。ただし利子が十分に小さければ払い続けても問題ないので、技術的負債は100%悪ではなく、プロダクトのリリースまでの期間を短縮できたりするなど借金にもメリットはある。一方で、いくら利子を返しても元本は減らないので、もし利子を払い続けるのが嫌ならリファクタリングやテストケースの追加で元々のソースを大幅改修する必要がある。でもそれには大きなコストがかかることが多いので、利子の支払いとどっちが得かで判断する。特に機械学習パッケージの場合はシステムレベルの複雑性のおかげで隠れた負債を生み出す可能性が高いので注意が必要、というのが本論文の主旨。
【複雑なモデルは境界を侵食する】
・もつれ
利用する複数の特徴量の分布がどれか一つでも変化すると、他の全ての特徴量の重要性や重みなども変化する (CACE principle: Cange Anything Changes Everything)。ハイパーパラメータについても同じこと。緩和策は、モデルを複数に分けて変化の影響を局所化する、モデルの挙動を可視化する、予測精度を変化させることが目的関数のコストとなるよう学習する、など。
・隠れたフィードバックループ
外界の挙動から学習するシステムは、フィードバックループの一部となる。例えば CTR (Click Through Rate) を予測するシステムを考えると、これはユーザのクリックを学習ラベルとして利用するが、そのユーザのクリックはこのシステムの以前の予測に依存する。こうしたフィードバックループはシステムの性能評価などの際に問題を引き起こすため、ループの発見に努め、可能な限り削除すべきである。
・想定外のデータ利用
機械学習モジュールが出した結果を知らない間に他のモジュールが利用しているような場合、機械学習モジュールの変更が想定外の場所に影響を及ぼすこととなる。設計段階でしっかりとアクセスコントロールを設けておく必要がある。
【コードの依存性よりもデータの依存性の方が厄介】
・不安定なデータの依存性
他モジュールの出力を利用することはよくあることだが、モジュールによっては出力が時間と共に変化し不安定であることがある。リスク軽減策としては、時間と共に学習を行い絶えず出力を変化させるのではなく、あるタイミングで学習結果の凍結コピーを作成して以降はそれを使うようにするということが挙げられる。
・使われないデータの依存性
実際には意味のない特徴量のせいで、不要なデータ依存性が生まれシステムが脆弱になる場合がある。以下のような特徴量がその例である。
- 古い特徴量:開発の初期段階では使われていたが、現在ではほとんど不要となっている特徴量。
- バンドル特徴量:複数の特徴量を含んでおり、それら全体では効果があるものの、内部に不要なものを持つ可能性がある特徴量。
- イプシロン特徴:精度向上への寄与は極めてわずかだが、少しでも精度が向上すればよいとの考えで用いられる特徴量。
定期的に各特徴の効果を評価し、不要なものは削除すればこうしたリスクは軽減できる。
・データ依存性の静的解析
Google では、データ依存を解析できる静的解析ツールを開発して導入している。
・補正のカスケード
問題Aに対してモデルaが適用されている時に、若干異なる問題A'に対してモデルaをわずかに補正したa'(a)を適用することで迅速にA'を解く、ということがよく行われる。しかし、これはaへのデータ依存を生むこととなり、さらには問題A''に対してa'を補正したものを適用する、などといったカスケード型の補正を引き起こしかねない。したがってaを補正して用いるのではなく、aを根本的に修正してA'に適用するようにすべきである。
【システムレベルでの難読性】
・糊コード
汎用的なAPIを使うことで開発を効率化しようとする試みはよく行われるが、実際にはそれをシステムに組み込むために大量の“糊”コードを書かなければならないことがある。機械学習システムの中で実際に機械学習を行なっているコードは全体の5%ほどで、95%は糊コードであるとも言われている。APIをそのまま使うのではなく、自分たちのシステムに合わせて再実装した方がテストや保守がやりやすくなる。
・パイプラインジャングル
糊コードの特殊ケースとして、入力データを適切な形式に合わせるのにデータの抽出や結合、サンプリングなどのステップが大量に必要になる場合がある。こうしたパイプラインの管理やエラーの発見、不具合からのリカバリには多大なコストを要する。パイプラインのジャングルの発生を防ぐには、データの収集と特徴抽出について総体的な視点から設計を行うしかない。
・死んだ実験用コード
実験用のコードを記述したブランチが大量に残っていると、それらが想定外に作用し合ってシステムが指数関数的に複雑になってしまう場合がある。定期的に実験用のブランチを調べて不要なものは削除するべきである。
・設定項目が引き起こす負債
大規模な機械学習システムには、用いる特徴量の種類、データの選択方法、学習アルゴリズムに特有の学習パラメータ、前処理・後処理、検証方法など、大量の設定オプションが存在する。こうした設定オプションは、その重要性を軽視されがちであるものの、設定オプションのミスは時間や計算資源の無駄につながるなど大きなコストを伴う。アサーションを使うことは設定のミス対策として有効だが、どのようなアサーションが適切なのかをよく考えなければならない。また、二つの設定ファイルを見比べて差分を可視化できるようにすることも有効な方法である。
【外界の変化への対応】
・動的なシステムにおける固定的閾値
何かを決定するために閾値を設けることはよくあるが、これを手動で設定してしまうと、新たなデータに対するモデル更新が発生した場合にその閾値が使えなくなるという問題が発生する。検証用のデータセットを保持しておいて、そこから閾値を適応的に決定するなどの方策が有効である。
・特徴量の相関関係の変化
ある2つの特徴量が相関しており、実際にはその一方だけが重要である場合、それらが相関しているうちは両方を利用していても問題はないが、外界の変化により相関が失われた場合、システムの予測性能に大きな変化が現れる。
・監視とテスト
単体テストと結合テストは重要だが、外界が変化する場合にはそうしたテストだけでは不十分であり、リアルタイムにシステムを監視することが極めて重要である。何を監視すべきかはよく考える必要があるが、手始めに以下の2つを監視するとよい。
- 予測バイアス:想定通りに動いているシステムでは、予測ラベルの分布は観測ラベルの分布と一致するはずである。これは総括的な試験ではないが、驚くほど効果的な診断方法であり、注意を払うべき問題の発見に有効である。
- アクション制限:システムが何らかのアクションを起こすものである場合は、そのアクションに対してリミットをかけることが有効である。もしそのリミットにかかるようなアクションが起きた場合には警報を発して人間の介入を促すようにすべきである。