LIVESENSE Data Analytics Blog

リブセンスのデータ分析、機械学習、分析基盤に関する取り組みをご紹介するブログです。

機械学習システムの信頼性エンジニアリング

こんにちは、データプラットフォームグループの田中 (@yubessy) です。機械学習基盤のプロダクトマネージャをしています。

いきなりの質問で恐縮ですが、機械学習(ML)システムの開発プロジェクトでこんな経験をされた方はいらっしゃいますか?

  • MLエンジニア: Webエンジニアに「コードの品質が低くシステムを本番運用できない」と言われた
  • Webエンジニア: MLエンジニアに「開発と本番でデータが違って精度検証ができない」と言われた

どちらかに心当たりがあるなら、同じチームにもう一方に当てはまる人がいるかもしれません。 MLシステム開発には様々な経験をもつメンバーが関わるため、システムの信頼性について重視する観点が分かれることは珍しくありません。

システム開発において信頼性は重要な要素です。 特にMLシステムには高い不確実性がつきまとうため、通常にくらべて信頼性の実現がより困難になります。 この記事では、MLシステムが安定して価値を提供するために求められる信頼性と、それに対するシステム開発・運用の観点からの扱いについて考察し、実際にリブセンスで行っている取り組みをご紹介します。

MLシステムの信頼性をどう捉えるか

システムの信頼性についてはサイト信頼性エンジニアリング (SRE) の考え方がとても参考になります。 SREの原則の中でもサービスレベルの概念は特に有用です。 サービスレベルに基づく信頼性エンジニアリングでは、信頼性をサービスレベル指標 (SLI) によって定義し、保証すべきサービスレベル目標 (SLO) を定め、SLIとSLOに基づいて方法論を展開します。 例えばWebサービスならリクエストに対するレイテンシやエラー率、バッチジョブならスループットや復旧時間などでSLIを定義し、その目標値をSLOとして設定します。 この手法はWeb開発で注目されていますが、広く一般のシステムにも適用できると考えられます。

MLシステムにサービスレベルの概念を導入するには、まずその信頼性を定義する必要があります。 通常のシステムでは人が書くコードが入出力を決定する関数となりますが、MLシステムではデータを入力とする学習アルゴリズムがこの関数(モデル)を生成します。 このためシステムに変更がなく正常に動作しているように見えても、データの変化により内部的に精度が下がっている、といったことがMLでは起こり得ます。 このようにMLシステムはデータに強い依存性をもつため、通常と異なる種類の信頼性についても考慮する必要があります。 私自身の経験から、MLシステムの信頼性は次のように区分すると捉えやすいと考えています。

  1. 通常と同じ指標で定義でき、同じ手段で実現できるもの
    • システムを構成するML以外のコンポーネントの信頼性
    • アプリケーションやインフラのセキュリティ
  2. 通常と同じ指標で定義できるが、ML特有の手段が必要なもの
    • 予測モデルを内包するWeb APIのレイテンシやモデル学習のジョブの復旧時間
    • MLを利用する機能のエンドポイントに対するリクエストのエラー率
  3. ML特有の指標と手段が必要なもの
    • 分類モデルの誤り率や回帰モデルの誤差などの精度指標
    • ノイズに対する頑健性や学習を繰り返した場合の結果再現性

このうち2については1と同一視されがちなため、特に注意が必要です。 簡単な例としてWeb APIのレイテンシの向上を図る場合、一般的なアプリケーションならばI/O処理の効率化などが有効ですが、MLモデルではパラメータ数の調整による計算量の削減といった手段が必要なこともあります。

MLシステムの信頼性が問題になるとき

さて、これらの信頼性はどんなときに問題になるのでしょうか? その説明のため、個人的な経験をもとに架空のケースを考えてみました。 以下では求人情報サービスにおける次のようなシステムを想定としています。

  • 各求人のCTRをロジスティック回帰で予測し、求人の検索結果の並び替えに利用する
  • モデルの学習と結果の予測は一連のバッチジョブとして1日1回夜間に実行される
  • 出力データはアプリケーションのDBに格納され、最後に成功したジョブの結果が常に利用される

ケース1: エラーに対する過剰な反応

ある日、予測精度の改善のためにパラメータの調整を行いました。 オフライン検証ではこの調整により平均的な精度は向上するものの安定性が多少低下することがわかりました。 そこでジョブの学習ステップの後に検証ステップを追加し、精度が以前のモデルより低い場合にはジョブを途中終了させて予測とデータ更新が行われないようにしました。

リリースから数日後のジョブ実行で、精度が以前のモデルを下回りジョブが途中終了しました。 これをジョブ管理システムが異常終了として検知し、運用担当者にアラートが通知されました。 運用担当者は直ちにジョブの再実行を試みましたが、ジョブは再び途中終了しました。 最終的に運用担当者はシステムを開発したMLエンジニアに連絡を取り、アプリケーションからは前回の予測結果が利用されるため数日間ジョブが失敗しても問題ないことを知らされました。

ケース2: 効果的でない手段の適用

ある日、開発環境で精度検証を行ったところ、本番環境と全く異なる異常な予測値が得られました。 このままではモデルの改善に支障をきたします。 開発用DBの主なデータは日次で本番用DBと同期されていたためデータに大きな問題はないと考え、コードの中で環境条件が影響する箇所を確認することにしました。 しかしコードの中では到るところでデバッグ出力のON/OFFなどに環境情報が使用されていました。 そこで数日間かけて大規模なリファクタリングと単体テストの追加を行い、環境差異を局所化した上で再度精度検証を実行しましたが、やはり結果は異常なままでした。

後日改めて精度検証を実行してみると、今度は本番との差異が全く見られませんでした。 そこで改めてデータの同一性を厳密に確認したところ、次のことが判明しました。 開発用DBの初期化と本番からのデータ同期は毎朝行われ、その直後に精度検証を実行すれば本番と同じ結果が得られます。 ただし開発用DBはアプリケーション開発と共用であり、開発中に不自然なダミーデータが混じりこむと、それが学習データの中の外れ値となってモデルに破壊的な影響を及ぼすようです。

MLシステムの信頼性エンジニアリング

上のようなケースはMLシステムの開発に関わった方ならある程度馴染みがあるかと思います。 では、こうしたケースはどんな原因から発生し、どうすれば解決できるでしょうか? 様々な方策が考えられますが、私自身は以下のような方針を重視しています。

サービスレベルについての認識を関係者間で一致させる

信頼性エンジニアリングにおいては、過度の可用性や耐久性を追求するのではなく、求められる水準に対して必要十分な手段をとることが大切です。 特にMLシステムでは、信頼性を通常と同じ指標で定義できても、通常と同等の水準を保証するのが困難なこともあります。 このような場合にMLシステムを通常と同じように扱おうとして過度のコストをかけてしまわないよう、開発・運用に関わるメンバーが必要十分なサービスレベルを認識しておく必要があります。 場合によっては前述のような信頼性についてSLI/SLOを明示することも有効と考えられます。

ケース1では、MLエンジニアと運用担当者の間でサービスレベルの認識が一致していなかったと思われます。 MLエンジニアはモデルの安定性が低いことを考慮した上で、実際のCTRは数日では大きく変動しないため過去の予測結果が使われても問題ないと考えたかもしれません。 一方運用担当者はMLジョブのサービスレベルを売上計上ジョブなどと同じよう捉え、ジョブの途中終了がサービス上の損失に繋がると考えたかもしれません。 結果的にはアラートの仕組みやそれに対する対応は過剰なものでしたが、根本的な問題はジョブの復旧要否や復旧時間について共通認識を築けていなかったことです。

システムに求める信頼性に応じた手段を適用する

システムの信頼性を実現するには、そのシステムの性質に合った手段を選ぶ必要があります。 通常のシステムでは可読性やテスタビリティのようなコード品質が信頼性の実現に大きな役割を果たします。 MLシステムでもコード品質は重要ですが、前述の2,3番目のような信頼性をコード品質だけで担保するのは困難です。 例えばコードレビューが「人の目を利用して信頼性を実現する」手段だとすれば、MLシステムではオフライン検証などの「データを利用して信頼性を実現する」手段が有効になります。

ケース2では、コードのバグが原因であるという誤った仮説に基づいて、リファクタリングや単体テストの追加といったコード品質の向上に多くの労力が割かれました。 もちろん元々のコード品質が良好なら他の原因にいち早く気づけた可能性もあるため、これは決して無駄な行為ではありません。 しかし一度問題が発生した後では、数日間かけてコード品質を向上させるよりも、まずデータの同一性をより厳密にチェックするべきだったと考えられます。 特にMLの場合、通常の開発では問題にならない小さなデータの差異がモデルに大きな影響を及ぼすことがあるため、大部分のデータが一致しているだけでなく件数・値域・分布などあらゆる面からデータを検証することが必要です。

信頼性の実現手段を適用できる仕組みを整備する

目的に応じて手段を適用すべきとわかっていても、それが簡単にできるわけではありません。 複数のMLシステムが継続的に開発・運用されるような現場では、手段の適用を支える仕組みの構築にも注力すべきです。 例えばモデル開発に利用するデータは、一元的に管理され開発者が簡単に利用できることが理想的です。 さらに、同じシステムの一部であっても、MLモデルとデータ入出力のような各機能には異なる性質の信頼性が求められます。 これらを疎結合化し、独立して実行できるようにすれば、コードレビューの分担やモデルの精度検証もやりやすくなります。

ケース2でも、モデル検証に利用するDBとアプリケーション開発に利用するDBが異なっていれば問題自体が起きなかったかもしれません。 またMLモデルの部分が他と独立化されていれば、モデル学習の実行前にデータの異常を検知する処理を導入するなどの手段が取れたかもしれません。

リブセンスでの取り組み

実際のMLシステム開発の現場では、それぞれの環境に応じて試行錯誤が行われていると思います。 リブセンスでのMLシステム開発においても、数年間にわたり成功と失敗が積み重ねられてきました。 そのような経験をもとに、現在社内で実践しているいくつかの取り組みについてご紹介します。

システムの開発段階に応じたフェーズの導入

サービスレベルの認識を合わせることはとても重要ですが、ひとつひとつのシステムに細かく運用上のルールを定めるのもそれはそれで手間がかかります。 そこでMLチームでは、システムに対して求められる信頼性と試行錯誤の自由度を把握しやすいよう、実環境で運用されるMLシステムを次のいずれかのフェーズに区分しています。

フェーズ 開発・運用の目的 サービスレベル 信頼性エンジニアリングの注力点
コンセプト検証 コンセプトの実現性の検証 SLI/SLOを定めない インフラやデータの整備と提供
技術検証 最適な技術手段の検証 個別に判断 システム設計やトラブル対応の協力
実運用 継続的な価値提供 SLI/SLOを定める 安定性・メンテナンス性の維持

例えば前述の予測システムならば、「CVRによる検索結果の並び替えがユーザ行動に影響するか」といった検証を目的とする段階では、コンセプト検証フェーズとしてSLI/SLOを定めず一部のユーザ・求人に限定してリリースすることが考えられます。 コンセプト検証がうまくいったとしても、精度が安定せずユーザへの価値提供に懸念があるような場合、技術検証フェーズではフェールオーバー方式の導入など運用課題の解決を目的とした検証と改善を行います。 こうして継続的に価値を提供できるようになれば、実運用フェーズに移行してSLI/SLOを設定し、ジョブの復旧体制やアラートルールを整備するといった要領です。

細かい条件にはまだ考慮の余地がありますが、目安としてのフェーズを決めることで、個別にルールを定める手間を省きつつサービスレベルの共通認識を形成しやすくなります。 これにより運用負荷を抑えつつ試行錯誤のプロセスを効率化しやすくなると感じています。

データ分析基盤・ML基盤を活用した再現性の担保

リブセンスでは全社データ分析基盤としてLivesense Analyticsを開発・運用しており、MLシステムの入力ソースは本番・開発ともできる限りここに一元化しています。 このため環境毎にデータが異なり再現性が担保できないといった問題は起こりにくくなっています。

また最近ではML基盤をGoogle Kubernetes Engine (GKE)上に構築し、各MLシステムを移行・集約しています。 この基盤では開発環境でも本番と同スペックのプリエンプティブルインスタンスを活用するなど、コンピューティング環境の差異もなるべく小さくなるよう工夫しています。

この話題については以下の記事でも解説しています。 analytics.livesense.co.jp

コンテナ技術によるコンポーネント化の推進

リブセンスでは現在、新しいシステムや既存システムのリプレース実装を開発する際に、MLのモデル部分をアプリケーションから独立したコンポーネントとして切り出すようにしています。 各コンポーネントは単一のコンテナとして動作するよう設計しており、データはファイルとして共有ボリュームやクラウドストレージを経由して受け渡しています。

この話題については以下の記事でも解説しています。 analytics.livesense.co.jp

各コンポーネントが独立していると、それらをまとめるワークフローエンジンが必要になります。 そこで最近ではKubernetesのCustom Resourceとして動作するワークフローエンジンであるArgo Workflowを試験的に導入しています。 Argo Workflowを用いると複数コンテナから構成されるワークフローが構築しやすく、上記のような構成の利点を活かせると考えています。 この話題については今後機会があればご紹介したいと思います。

Open source container-native workflow engine for Kubernetes | Argo

さいごに

リブセンスでは数年前に機械学習をサービスに導入し始めました。 初期の模索の段階を経て、現在ではMLシステムの信頼性を支える仕組みが徐々に整ってきています。 今後もこの中で得られた知見を共有していきたいと思います。

参考資料