目次
5月にPyData.Tokyo Meetup #23 MLOps〜AIを社会に届ける技術がオンラインで開催されました。
https://pydatatokyo.connpass.com/event/210654/
PyData.TokyoがテーマにMLOpsを扱うのは2年ぶり1で、個人的に期待が高かったです。
今回はサイバーエージェント(CA社)のMLOpsにまつわるご発表2件でした。
トピックはML実験管理基盤、プロダクト化にあたってのパフォーマンス向上やトラブルシューティングでした。
Ops関係の直接的な話題はなかったものの、現場ならではのノウハウが豊富にふくまれていました。
私は勉強のために、スピーカーごとにメモ(個人的所感含む)を取っていました。 スライドや動画が公開されているので、そちらをご覧いただいた方がいいというのは百も承知の上、以下で共有します。
スポンサードリンク
1人目『CyberAgent AI Labを支えるCloud実験環境』
概要: CyberAgent AI Labでは、Computer Vision・NLP・経済学・ハイパーパラメータ最適化・Human Computer Interactionなど分野の異なるResearcherが広く在籍しています。このような分野違いのデータや実験を一元管理するために、AI Labで開発・運用しているデータローダーやモデルサーバーを通じて、高速かつパワフルなCloud実験環境をご紹介します。
スライド: CyberAgent AI Labを支えるCloud実験環境 - Speaker Deck https://speakerdeck.com/chck/cyberagent-ai-labwozhi-erucloudshi-yan-huan-jing
動画: https://www.youtube.com/watch?v=E2s5NP6B8cs
本題
- 所属組織であるAI Lab
- 人数35人。Researcher 31名、Research Engineer 4名(岩崎さんはこちら)。リサーチャーが多い。
- OKR: 学会発表がメイン。
- プロダクト側ではないので、顧客データを貯めていない。しかし実験で使用したい時はプロダクト側と連携する。
- AI Labのエコシステム
- 課題、仮説、アイディア
- データ選定し、収集する
- 前処理
- 解きたいタスクに対するモデリング
- 評価(実験結果のレポート作成)
- 論文、プロダクション化
- 研究生産性にまつわる課題
- 使うライブラリは、リサーチャーや分野によってばらつく。
- → そこで岩崎さんはR&Dを加速させるために、実験の共通部分を洗い出して実験サポートツールを作った。
- 使うライブラリは、リサーチャーや分野によってばらつく。
- 今回の報告内容は、エコシステムにおけるサポートツール3つの紹介
データ選択: ailab-datasets
- 前提知識: tensorflow-datasets
- private(社内)なデータを扱う上での課題
- この課題を解決するのがailab-datasetsという社内ツール
モデリング部分でのサポート: ailab-model-zoo
- privateなmodelにおける課題
- 異なるタスクで似たようなモデルの再発明が起きている
- リサーチャー間でpretrain済みモデルのシェアしたい場合がある
- 社内データでpretrainした重みがほしい。
- しかし、誰がどんなモデルを作成しているか把握しづらい
- ailab-model-zoo(WIP)
実験管理部分でのサポート: ailab-mlflow
- 実験管理ツールにおける課題
- MLflowはサーバ構築が面倒。セキュリティのことを考える必要がある。
- SaaS(Nepture.ai, Comet.mlなど)は無料枠を越えると高コスト
- MLflowでの実験管理
- 1つの共用のMLflowサーバをたててチームで利用という案はやりたくない
- アクセス制御ができない
- 個人の実験管理を制限してしまう
- ailab-mlflow
- AILab内で共通で使えるMLflow ClusterをGCP上にGKEで構築
- 実験バッチからどう、MLflowサーバへログを飛ばすのか
- リサーチャーがMLflowの使用申請をailab-mlflow管理者に出す。管理者は新しいMLflow podを立ち上げる。
- リサーチャーは予め持っているクライアントidをキーに、MLflowへアクセスするためのOAuth Tokenを発行する
- 環境変数
MLFLOW_TRACKING_TOKEN
にTokenをセットすると、MLflowクライアントはこれをつかって、MLFlowサーバにアクセスしてくれる。 - あとは、普通のMLflowの使い方と一緒
- 構築方法はAIlabのテックブログにて公開予定
- 1つの共用のMLflowサーバをたててチームで利用という案はやりたくない
おわりに
- 今後の課題
- 論文執筆後のコード、デモページのジェネレータの開発
- ツールをリサーチャーにどう布教させるか
- ツールのチュートリアルを開催
- 地道に一人ひとり使用者を増やしていく
- 共著で入るときに、こっそりツールが使える環境を用意してしまう
- 研究の仕組み全体を支援するpipelineよりも、要所要所で使えるモジュールを開発をし、リサーチャーに使うモジュールを取捨選択してもらったほうがよい
質疑
- privateなデータセットの認証周りはどうしているのか
- ailab-model-zooをリサーチャーに使ってもらう時のインセンティブはあるか
- ない。強いて言うならば、ailab-model-zooで実験負荷を軽減できたり、モデルを公開したことで思わぬバグを発見できたという成功体験をしてもらうこと。
- ailab-mlflowのインフラ管理は誰が行っているのか
- 岩崎さん+もう1名
- ailabの研究成果をCA社のプロダクト内で使用することはあるか。使用するならば、どこの部隊がMLコードを運用管理するか。
- 使用する。プロダクト側が実運用を担当する。理由は、AIlabの目的が研究なので、プロダクトの目的(売上を伸ばす)とギャップがあるため。
個人メモ
- 基盤の設計。あまり意識されない部分にしっかり生産性を上げる機能を提供しているという印象でした。
- 実験ツールの標準化 と 研究の自由 のトレードオフ
- 岩崎さんは以前会社ブログやPyConJPで『小さく始めて大きく育てるMLOps2020』 https://cyberagent.ai/blog/research/12898/という発表をしていましたが、私はこれを読んだ当時これに沿って社内の実験手順を統一しているのかと思ってました。しかし、実際には研究者の個人のやりかたは自由ということでした。
- 社内ツールを開発しても、使ってもらえないということは私にもあるので、いかに相手に使用を強制させずに普及させていくかは参考になりました。
- プロダクト側への実験成果物(モデルなど)の引き継ぎはどのように行っているのだろう
- 関数I/Oは共通化できるものの、内部ロジックはリサーチャーが実装しているはず。そこはおそらく実験のコードのままだと思うのでプロダクト側にわたすとき、どう品質を担保するのか、誰が今後メンテを行うのかというのは気になりました。
- (補記)その話題に関しては、CA社の方が技術記事『データサイエンティストはどこまでエンジニアリングをすべきか?』でメリット・デメリットを論じていますが、境界を確定しているわけではなさそうですね。
- 関数I/Oは共通化できるものの、内部ロジックはリサーチャーが実装しているはず。そこはおそらく実験のコードのままだと思うのでプロダクト側にわたすとき、どう品質を担保するのか、誰が今後メンテを行うのかというのは気になりました。
スポンサードリンク
2人目 『サイバーエージェントにおけるMLOpsに関する取り組み』
スピーカー: 芝田 将(Masashi Shibata)
概要: サイバーエージェント社内の3つのプロダクトのMLシステム構成を紹介しながら、そのプロダクトで行ってきたMLOps周りの取り組みをお話します。
スライド https://www.slideshare.net/c-bata/mlops-248545368
動画 https://www.youtube.com/watch?v=oluIfLSsq8w
芝田さんは社内の(高度な)技術サポートの仕事を行っており、今回は社内プロダクトの改良やトラブルシューティングに関して3点報告されました。
- DynalystにおけるMLモデルの推論の高速化
- AirTrackにおけるMLモデル学習の高速化
- AI Messanger Voicebotにおいてシステムが固まる問題の調査
1. Dynalystにおける機械学習
- Dynalyst:CA社のプロダクト。スマートフォンアプリに特化したダイナミックリターゲティング広告をしてくれるDemand Side Platform。
- C++実装でCLIのみを提供している。 そのままだとPythonで実行できない。サードパーティのpythonバインディングもあるが、自前でpythonバインディングを実装した。
以下では高速化したlibffmのpythonバインディングを開発した際のtipsを説明する。
Cythonによる推論サーバの高速化
- Cython
- CythonにおけるGILの解放
- 安全性を犠牲にした高速化もおこなっている
- CとPythonで異なる部分に対してPython/C APIがチェックが呼ばれてしまう
- 例えばゼロ除算チェック、配列に負値のインデックス-1を与えることなど
- 高速化のために、Compiler directivesの設定でチェックを切る
- CとPythonで異なる部分に対してPython/C APIがチェックが呼ばれてしまう
- 推論処理をCythonに直した効果
- 推論時間が改善前の10%に短縮
- 推論サーバの全体のレスポンスが元の60%に短縮
- スループットが1.35倍なったため、稼働させておくサーバを減らしコスト削減にもつながる。
LIBFFMバインディングの実装 参照カウントとNumPy C-API
Pythonコードの高速化をしたいだけならば、Cythonに書き直せばOK。これはお手軽。しかし、Cythonを使ってPythonバインディングを作るにはCython, C/C++の深い理解が必要。その一例としてメモリ管理にまつわる話をする。
- Cライブラリをラップするには
- Cython側から参照したいCの関数や構造体の宣言をする
- 関数の引数に与えるオブジェクトを生成する
- やってることは構造体のメモリ領域の確保
- 関数の呼び出し
- 使用したメモリ領域の解放
- Pythonと連動したメモリ管理がしたい
- CPythonのメモリ管理機構は参照カウント
- 参照カウントが0になるとPythonオブジェクトのメモリ領域は解放される
- どうやって連動させるか
- ラップしたNumpy配列に対してBaseObjectを指定する
- このBaseObjectは、Numpy配列の実体となるCの配列のポインタを所有するオブジェクト。雛形のクラスには
__dealloc__
メソッドを定義し、このクラスのオブジェクトが破棄されたときは、実体となるCの配列のメモリ領域を解放する処理を書く。
- このBaseObjectは、Numpy配列の実体となるCの配列のポインタを所有するオブジェクト。雛形のクラスには
- これにより、Numpy配列が破棄されると、連動してBaseObjectも破棄され、BaseObjectが破棄されるときにCの領域が解放される。
- ラップしたNumpy配列に対してBaseObjectを指定する
- 以上のように、Cで確保したメモリ領域をPythonで触れるようにするのは一苦労。pythonで操作する必要がない (Cython内でメモリ領域の操作が閉じている場合は型付きメモリビューを使うことを推奨する。
2. AirTrackの事例紹介 OptunaとMLflowを使ったハイパーパラメータ最適化の転移学習
- AirTrackとは
- MLモデル学習のパイプライン
- メトリクス、アーティファクトの管理にMLflowを利用
- ハイパーパラメータの探索にはOptunaを使用
- 学習バッチを実行するごとに毎回ハイパパラメータも探索しているとのこと
- この時、ハイパラ探索の工夫をしている。それについて説明する。
Optunaの基礎知識とWarm Starting CMA-ES
- Optunaの強み
- Optunaのデフォルトのアルゴリズム: 単変量TPE
- 欠点: ハイパラ間の相関関係を考慮しない
- Optunaで使える、相関関係を考慮した探索アルゴリズム
- 多変量TPE
- CMA Evolution Strategy(CMA-ES)
- AirTrackのモデル学習で使用
- Warm Starting CMA-ES でハイパラ探索を高速化
- イメージとしては、前回の探索結果を初期値としてハイパラ探索をする。いわばハイパパラメータ版の転移学習を行っている。
- Warm Starting CMA-ESの解説は手法発明者である野村さん(AILab所属)の発表の方が詳しい
- このアルゴリズムはOptunaにも組み込んでいる。
3. AI Messanger Voicebotの事例紹介 軽量スレッドとWebSocket
- AI Messanger Voicebot
- AIによる電話自動応対サービス
- システム構成
- トラブル
- 開発初期、WebSocketサーバ(Flaskで実装)が特定の条件下で固まって動かなくなるという相談が芝田さんに寄せられたので原因を調査した
WSGIと軽量スレッド
- PythonでWebsocketを扱うことについて
- 工夫してWebsockets通信を行おうとする方式の問題点(WSGIの制限について)
- WSGIアプリケーションを呼び出したスレッドは、そのアプリケーションの処理が終わるまで別の処理を行えないこと。Websocketのコネクションが張られているうちは処理を離せない。
- 対応策としてはマルチスレッドが考えられるが、OSが管理するスレッド(
threading.Thread
)を使うのは避けたい- 理由はパフォーマンスが悪いため
- コンテキストスイッチが重たい
- スレッドのスタックサイズが大きく(2MBなど)、1つスレッドを作るだけでもコストがかかる
- したがって、user landで動作するスレッドのようなもの(軽量スレッド)を使ってマルチスレッドを実現する
- (個人メモ: アプリケーション側で生成した仮想的なスレッドだから生成が早いということだろうか)
- 理由はパフォーマンスが悪いため
- 先述のFlask-socketsはGevent-websocketを内部で使用しており、これが軽量スレッドを用いたマルチスレッド処理を実現してくれる
Gevent-websocketの仕組み
- Geventのmonkeyというモジュール
monkey.patch_all()
を 呼び出すとPythonの標準ライブラリに対してモンキーパッチを当てる。通常ならばスレッドをブロックするような操作をGevent用のものに置き換える。置き換えると軽量スレッドベースで動作させることができる。- この状態でthreading.Thread(本来は、OS経由でのスレッド生成)を呼び出すと、内部的にはGeventの軽量スレッドを生成する操作(gevent.Greenlet)に置き換わっており、シングルスレッドでありながら仮想的に並列処理を行うことができる。
- Flask-socketsはGevent-websocketを利用して1つのスレッドで複数のWebSocketのコネクションをさばいている
- ただし、
monkey.patch_all()
が置換できないものがコードの中に含まれていて、そこを呼び出してしまうとブロックが発生。 Gevent(イベント駆動)のイベントループがそこで止まってしまうためプログラム全体が固まってしまう - 【余談】ASGI(Asynchronous Server Gateway Interface)
- 上の問題は同期処理を想定しているWSGIで無理やりWebsocket通信と非同期処理をやろうとしたことが起因
- WebSocketもサポートできるような非同期インタフェースの仕様を策定(中)
質疑
- Cythonのコードアノテーションのハイライト(Python/C API呼び出し)部分はどうやっているのか
- メモリ確保したい時、PyMem_Mallocで確保するのとC++のスマートポインタで確保するのでは何が違うか
- メモリをどこで管理したいかの違い。PyMem_MallocはCythonでメモリ管理したい場合に使う。
- (コメント) Cythonを使った実装のパートについて、話は理解できるけど自分で実装できる気がしない
- Optunaに関して、ハイパラ探索時、過去のbestハイパラより悪くなることはないか。
- 悪くなる場合がある。それを見越して、探索パラメータ候補に過去のbestハイパラを追加しておくことで精度の下界を保証する。
- Warm Starting CMA-ESによって、どれだけ学習効率が上がったか
- オフライン性能検証の結果では、単変量TPEに比べて評価回数が半減した
- 単変量TPEだと100回評価してたどり着けるハイパパラメータがあるとして、Warm Starting CMA-ESだと50回でたどり着ける。
- オフライン性能検証の結果では、単変量TPEに比べて評価回数が半減した
- SageMakerではなくMLflowを使っている理由は
- 自分はサポートとしてぱっと入っただけで、プロダクトの設計には関わっていない。したがってMLflowを選定した細かい背景はわからない。
- 他のプロダクトでシステム設計のディスカッションをした時の話になるが、MLflowがむかないケースが結構あると思っている。メトリクス集めたい時、MLflowのTracking APIを使うせいで柔軟性が減ることがある。
- AI Messanger Voicebotに関してpythonで非同期処理を扱うのは大変そうだが、何でPythonで実装したのか。
個人メモ
- Dynalystの事例紹介に関して
- AirTrackの事例紹介に関して
- AI Messanger Voicebotの事例紹介に関して
- 問題は複雑。
- 強いエンジニアが高度な技術的課題を解決して現場を救ったという見方はできるものの、最下流で尻ぬぐいした感じもする。もう少し設計段階で芝田さんが加わっていた方がトラブル解決にかかった工数が少なかったかもしれない。
- とはいえ、GeventとgRPCの相性が起因であると予見するのはさすがに難しいか。
- そもそもの問題はPythonでプロダクトを開発しようとしたことだが、MLエンジニアがプロダクトを全部設計しようとすると技術選定がPython中心になってしまうのは仕方がない。
- 別にMLエンジニアもスキル不足というわけではないだろう。MLエンジニアはGoも実装できるようにならないといけないかというと違うわけで。
- 未来に同じようなことが起きたときにまた強いエンジニアが必要になってしまう事態をどう避けるか。結論出ない。MLOpsの責任境界問題の議論のケーススタディとしては面白い。
- 強いエンジニアが高度な技術的課題を解決して現場を救ったという見方はできるものの、最下流で尻ぬぐいした感じもする。もう少し設計段階で芝田さんが加わっていた方がトラブル解決にかかった工数が少なかったかもしれない。
- 問題は複雑。
- その他
- 内容が高度だった。発表内容を理解するために、数多くの参考文献にあたる必要があったが、いい勉強になった。
- 岩崎さんはAI Labはプロダクト部隊ではないと言っていたが、今回の芝田さんの取り組みはどのような位置づけなのだろう
- スペルを大文字含めて正確に書いていて丁寧なスライド。
- 私は面倒なので、pythonのように 表記の正確さを若干サボって書くのですが、スライドを見る限り、全て正確だったので驚きました。
おわりに
最後になりますが、改めてPyData.Tokyoの運営の皆様、会をアレンジしていただきありがとうございました。
おかげ様でまた1つ勉強になりました。
参考文献
スポンサードリンク