AWS Startup ブログ

【開催報告&資料公開】ML@Loft #9 Deep Learning フレームワークと推論

こんにちは、AWS ソリューションアーキテクトの辻です。第9回目の ML@Loft は Deep Learning フレームワークと推論をテーマに12月に開催しました。
ML@Loft は機械学習のお悩み相談イベントで、目黒の AWS Loft Tokyo で2019年4月より毎月開催しています。AWS をお使いのお客様がサービスの中に機械学習を取り入れて開発・運用していく際のお悩みを相談できる場が欲しい、ということで始まったコミュニティイベントです。登壇者(相談役)が自己紹介を兼ねた10分ほどの Lighting Talk (LT) を順番に行った後、テーブルに分かれて具体的な相談・ディスカッションを行う、という二部構成で開催されています。過去の様子は登壇者のスライド付きでブログにまとまっています。
毎回登壇者の希望をもとにテーマを決めており、第9回となる今回のテーマは「Deep Learning フレームワークと推論」です。今回登壇・相談役をお願いしたのは 梅澤 慶介 氏(chug (Chainer User Group))、瀬尾 直利 氏(株式会社ZOZOテクノロジーズ)、三條 智史 氏(クックパッド株式会社研究開発部)、松岡 玲音 氏(株式会社メルカリ AIチーム)の四名です。当日の流れに沿って内容を振り返りたいと思います。

LT セッション

前半の LT セッションでは登壇者の方々から、フレームワークに関する思いや実際に推論をプロダクションで運用する場合の知見などを発表いただきました。

「Chainerを使ってプロダクション環境上で推論するには」梅澤 慶介 氏(chug)

機械学習に限らずフレームワークの選定は、開発における重要な要素です。梅澤さんからは深層学習フレームワークである Chainer のプロダクション環境での推論に関する発表です。元々 Chainer の紹介が中心の発表の予定していたそうですが、急遽、Chainer から PyTorch へのマイグレーション方法に変更されました。
ML@Loft#9 の開催日時が2019年12月の中旬ということから変更理由の予想の付く方もいるかもしれません。ちょうどイベント開催の時期に Preferred Networks (PFN) さんから公式で Chainer をメンテナンスフェーズに移行することが発表されました。こちらの発表では PFN さんが深層学習の研究開発基盤を Chainer から PyTorch に移行することを決定し、同時に Chainer の開発が現在のバージョンの bug fix 及びメンテナンスのみになりました。梅澤さんもこちらの発表を受けて内容を変更したとのことです。会場にもご存知の方が多かったようで、大きなリアクションがありました。
いままで Chainer を使っていたユーザ向けに PFN さんは PyTorch への移行を簡単にするためのツールやドキュメントを公開しています。発表内で触れられていたのが、次の二つの資料です。

1つ目がドキュメントで2つ目 Python のツールです。ドキュメントには Chainer と PyTorch のモジュールの対応関係の表などが書かれており、モデルの書き換え、スクリプトの書き換えが非常に簡単に行えるようになっています。ドキュメント内では移行における推奨の順序が書かれています。

  1. 訓練用スクリプト(optimizer/updater/evaluator/trainer…)
  2. Dataset / preprocessing
  3. モデル定義

実際に梅澤さんが MNIST のコードをドキュメントを参考にしながら移行した記事が Qiita に公開されているので、サンプルが見たい方などは参考になると思います。Chainer と PyTorch のコード上の違いというのはほとんどなく、簡単に移行することができると感じたそうです。他のフレームワークも Chainer から影響を受けた部分も多分にあり、良いコード設計はどのソフトウェアにも取り込まれるものと実感できました。
すでに Chainer で学習済のコードがあるユーザ向けに、Chainer のモデルをプロダクションで使うときの選択肢として以下の2つが挙げられます。

  1. Chainer 形式でモデルを保存し、Chainer で推論する
  2. ONNX (Open Neural Network Exchange) 形式でモデルを保存し、ONNX Runtime 等で推論する(Chainer で ONNX モデルへ保存する方法はこちらに書かれています。)

ONNX 形式でモデルを保存することで、Python 以外の言語が扱え、フレームワークに依存しない推論が可能となります。今後のメンテナンス性も含めると ONNX 形式でモデルを保存することをおすすめします。

Chainerを使ってプロダクション環境上で推論するには

「ZOZO 画像検索における Chainer の本番運用」瀬尾 直利 氏(株式会社 ZOZO テクノロジーズ)

プロダクション環境で実行されることを想定されていないアプリケーションを安定運用させるには多くの困難があります。瀬尾さんからは ZOZOTOWNWEAR などのアプリケーションで使用されているシステム、「ZOZO 画像検索」で Chainer を安定運用することに関する発表です。ZOZO 画像検索とは、選択したアイテムの類似アイテムを表示する機能で、類似アイテム値段の比較などが行えます。
さっそくアーキテクチャについて説明がありました。大きな分類は以下のようになっています。

  • 深層学習を利⽤して画像からアイテムを抽出(detection) → Chainer を利⽤
    深層学習を利⽤してアイテム画像の特徴ベクトルを取得(metric learning) → Chainer を利⽤
  • 取得した特徴ベクトルを予め構築しておいた Approximate Nearest Neighbor (ANN) index から類似検索 → annoy を利用

推論は Kubernetes 上のコンテナで実行されており、API を叩くことで推論結果を返します。この API の裏側では上記3つのマイクロサービスのコンポーネントが動作しています。推論の実行には Chainer を利用しているとのことですが、瀬尾さん曰く実行は「驚くことに安定している」とのことでした。常駐プロセスでも安定し、メモリリークがなく、速度が一定とのことです。
Chainer 開発者の一人でもある瀬尾さんがおっしゃるには、Chainer の開発自体はこのような常駐プロセスとして実行することは想定していなかったそうです。それにも関わらず、非常に安定しており、驚いていた様子でした。瀬尾さん自身が Chainer の開発者ということで、開発者視点から安定していた理由をいくつか挙げていました。
本番運用での工夫として瀬尾さんが強調していたのが、コンテナイメージに機械学習のモデルは含めないことです。元々は含めてイメージをビルドしていたそうなのですが、ビルドに1時間ほどかかり開発者の Developer Experience が下がってしまい含めない運用にしたそうです。
コンテナの運用の工夫以外にも、Approximate Nearest Neighbor のライブラリである annoy の運用の工夫についても技術的に説明していただきました。詳しい内容はスライドをご覧いただくことで確認できます。

「Rust で作る機械学習を用いた画像クロッピングシステム」三條 智史 氏(クックパッド株式会社研究開発部)

全く同じ料理の画像でも、どの部分を写すかによって人に与える印象は大きく変化します。三條さんの発表では、「美味しそう」に見える画像のクロッピングを機械学習によって処理するシステムの高速化に関する発表です。クックパッドは多くのユーザが利用しており、同時にアップロードされている画像も多くあります。ユーザの体験を損なわずに大量の画像をクロッピングするために、高速に処理できるシステムが必要です。システムの要件としては、既存の画像配信システムの上に、パフォーマンスを維持したまま、画像をレシピごとに「いい感じ」にクロッピングをするというものでした。
アプリケーションやシステムのパフォーマンスを考える場合、まずすべき事はプロファイルを取得してどのような処理がどれほど時間かかっているか計測することです。Python で実装したシステムの推論時間を計測したところ、1枚で 120ms ほどかかったそうです。スケーリングなどを考慮するとシステムとしては容認できない性能でした。
三條さんのチームは、Python から Rust への言語の変更、キャッシュの利用、そしてクロッピングを部分的に諦めることによって、最終的に許容できる性能を達成しました。最終的なシステムに落ち着く前に事前にバッチ処理するなど、いくつかの案を試したそうですが、問題が多く採用できませんでした。
性能獲得のために Python ではなく Rust を言語として採用したことがシステムの特徴として挙げられます。Rust ではライブラリなどが足りないのでは?、という疑問が浮かぶ方もおられるかもしれません。Python と同等とは行かないまでも、Rust でも機械学習を扱えるライブラリも充実しており、三條さんのチームもほとんど不便はしなかったそうです。例えば TensorFlow では Rust のバインディングが公式で公開されています(https://github.com/tensorflow/rust)。特殊な性能の最適化はせず Rust に書き換えたコードと Python のコードを比較したところ、処理速度が 20% 短くなったとのことです。
三條さんのメッセージとして、推論に限定した場合、Rust でも機械学習のシステムは簡単に実現できる、とのことでした。

Rustで作る機械学習を用いた画像クロッピングシステム

「Istio Meets MLOps」松岡 玲音 氏(株式会社メルカリ AIチーム)

サービスがマイクロサービスで構成されていると全体のオーケストレーションが大きな問題になります。松岡さんの発表では、Istio を利用することでマイクロサービスの運用管理が効率化したことを紹介する発表でした。メルカリさんでは多種多様の機械学習のサービスがあり、各サービスがマイクロサービスで開発されています。各サービスは使用しているツールなどは異なるもののすべて同じ Kubernetes クラスタで動作しています。
機械学習サービスと特性として、松岡さんは計算負荷が高いことと複数コンポーネントを組み合わせた複雑なアーキテクチャになりやすい、ことを挙げていました。具体的に後者は、

などのツールがアーキテクチャに含まれます。メルカリさんの AI チームえは運用コストが高くなりがちな複雑なシステムを、Istio によって効率化させました。
まず Istio とはどのようなツールなのでしょうか。Istio の理解にはマイクロサービスやサービスメッシュといった概念の理解が求められます。ここで詳細に説明はしません。マイクロサービスであるサービス同士の連携を効率化するために生まれた概念がサービスメッシュであり、Istio はサービスメッシュの構築のために利用されるツールです。Istio の主な機能として、トラフィック制御、通信内容やメトリクスの取得・監視、認証・アクセス制御・暗号化、などがあります。メルカリさん AI チームでは前半2つが特に役に立ったそうです。具体的にどのように役に立ったのか見ていきましょう。
まずは負荷やレイテンシのモニタリングをアプリケーションから切り離して application agnostic にできたことがことがよかったそうです。Istio では Envoy というツールがモニタリングなどのプロキシとなり、control plane と通信します。これによって、data plane で動作しているアプリケーションコードを変更することなくモニタリングができます。さらに取得したメトリクスに応じて自動でスケーリングさせています。
アプリケーションに依存しないモニタリングとその自動化によって運用コストが下がりました。他に運用コストを下がったものとしてモデルのデプロイがあります。通常の Kubernetes では Pod 単位の Blue/Green デプロイしかできませんが、Istio によって簡単にカナリアデプロイを実現することができます。また Istio のミラーリング機能を利用することでデプロイ前に安全に動作の検証が可能になります。特に機械学習システムでは、開発環境で想定していなかったデータがプロダクション環境で入力されることによって、システム全体が落ちる場合があり、実際のデータでテストできることは大きな利点です。
一方で Istio の導入によって管理すべき Kubernetes のマニフェストが増大し、認証周りのトラブルが生じたなども問題もあったそうです。しかし、総合的に見て Istio の導入に恩恵は大きかったそうです。

Istio Meets ML Ops – ML@Loft#9

RT ディスカッション

イベント後半はラウンドテーブルでのディスカッションです。4つのテーブルに分かれて、4人の登壇者が相談役としてそれぞれのテーブルにつき、お悩み相談会という形でディスカッションを行いました。

  • 梅澤さんのテーブル
    • なぜ PFN は Chainer から PyTorch に移行したのか?
      • PFN さんの会社として判断なので、はっきりとしたことはわからない。ただ、コミュニティなどを考慮して会社として OSS に貢献するモチベーションが減ったことは要因としてあると思う。しかしどんな理由であれ Chainer で得た技術は今後 PyTorch に取り込まれていくと思うので期待は大きい。
    • Chainer Family は今後どうなる?
      • Chainer Family も今回の変更に従うと発表している。https://chainer.org/announcement/2019/12/05/released-v7-ja.html
      • ChainerMN と ChainerRL は使いやすかったとの声が多く、PyTorch で使用できたらユーザとして嬉しい。chug として貢献できるところはしていきたい。
    • TensorFlow のモデルを ONNX 形式にエクスポートしようと思っているのだが、どうすれば良いか?
      • ONNX の GitHub オーガナイゼーションに tf2onnxkeras2onnx などのツールがある。これらを利用すれば良いと思う。
    • ONNX Runtime で実行したモデルが正しく動作しないだが、デバッグの方法で良い方法はないか?
      • ONNX Runtime の version が古かったりすると特定の operator が実行できなかったりするので、確認した方がよい。
      • 実行先のデバイスなどによって、対応している・対応していない、が異なるので注意が必要。
      • ニューラルネットネットワークの定義にテンソルの resize 処理があると、学習したフレームワーク(TensorFlow, PyTorch, Chainer)によって挙動が異なるので、正しく推論ができない場合がある。
  • 瀬尾さんのテーブル
    • 画像検索の評価指標はどのようになっているのか?
      • 研究所に任せているため詳しくは知らないが、主観にもよるので難しいというのは聞いている。
    • ユーザの impression を取り込みたいときに、作っている⼈たちへのフィードバックはどうしているのか?
      • ログは取れているが、機械学習のモデルよりも UI の影響の⽅が⼤きいため、機械学習モデルへのフィードバックというと難しい。むしろ UI や見せ方を工夫しているフェーズ。
    • ChainerX はプロダクションで使ったことがあるか?
      • 使ったことはない、Chainer 自体、今回のアナウンスを受けて TensorFlow に書き換えなければいけないと考えている。
    • GPU をクラウドで使って学習させるとコストが⾼くないか?
      • デスクトップマシンを買っても使っていない時間が無駄になっていることや複数台に増やしづらいことを考えるとそうでもない。新しいGPUを使えるようになるメリットもある。
    • コンテナイメージとモデルは分けた⽅が良い?
      • ビルドに時間がかかるため、分けた⽅が良いと考えている。モデルが軽量な場合ならいいかもしれないが、だいたいは重くなるので分けたほうが良い。
    • MLOps に移ってどう感じているか?
      • まだ発展途上で考えながらやらなければならないことが多い。
  • 三條さんのテーブル
    • Rust への移植は大変ではなかったか?
      • 確かに辛い部分はあった。
      • 画像処理などは OpenCV のラッパーを利用できるが、Rust では Python ほど簡単にいかない。
      • Python の OpenCV で書いたコードを Rust で再現するのが特に大変だった。
    • モデルの精度検証は大丈夫?
      • クロッピングの場合は目で見て大丈夫で OK
    • Rust への移行ではなく、モデルの軽量化で対応することは検討しなかったのか?
      • 開発者リソースの都合で、モデルの改善・再学習は避けたかった。
    • うまくクロッピングできない場合はあるのか?
      • デコレーションケーキ、くまのぬいぐるみが乗っている場合などの画像はつらい
      • そういうのにも本気で対応しようとすると、モデルの再学習が必要
    • なぜ C++ にしなかったのか?
      • 書けるエンジニアがいなかった、言語としては Go か Rust で悩んだ
    • 機械学習で難しいのが、正しく動いていることを定量化する方法だと思うが、どうか?
      • そのとおりで、クロッピングのモデルも、ユーザからの意見ベースでしかモデルの「望んだ動作」の課題は対応できていない
    • TensorFlow.js でクライアント側でモデルを推論するのはどうか?
      • 今回はそのような方法は検討していなかった。
      • その方法では、クライアントで推論が失敗したとき気づけない可能性があるので、難しい気がする。
    • Rust で推論するという発想がなかった、なぜ選んだ?
      • 画像を大量に扱えて、レイテンシを低くする、となると選択肢として出てくる。
      • TensorFlow で色々な言語を提供しているが、その中で Go と Rust が候補になった。
      • OpenCV と TensorFlow でデータを扱うのに、メモリ効率が良かったのが Rust だった。
    • Rust を選択した後悔はあるか?
      • Rust は言語のコミュニティが Python ほど成熟していないため、ライブラリが不安定だったり性能がいまいちだったりして、ライブラリの吟味が難しい。
    • Python の実装でクロッピングが 120ms かかると言っていたが、それは遅いのか?
      • 本番環境の request/sec を考えると厳しい。並列化すれば対応はできるが、代わりにコストがかかってしまうので避けたかった。
    • モニタリングは?
      • Envoy がいて Grafana で可視化している。
  • 松岡さんのテーブル
    • システムの最適化とモデルを作る人は別なのか?
      • いまは別になっているが、理想はモデルから一気通貫してシステムまで構築できること。
    • Human in the loop のシステムはどう作るか?
      • Customer Support の方などが違反などは検知し、その後モデルの再学習をする。
    • ML のパイプラインはどう作っていくのが良いと思うか?
      • Kubeflow が個人的に良いと思う、PoC から書いていき徐々に大きくする。
      • ビジネス要件の定義、KPI 定義が重要。それらの定義を PoC を行う人が責任を持つ必要がある。
      • パフォーマンスを出すためにはシステム全体を考え直す必要があるので、大変である。
    • モデルのバージョン管理はどうしている?
      • パイプラインは GitHub で管理している。
      • モデルそのものは学習データが変化するが、meta store をバージョン管理している。
    • 今日は話はサーバサイドの話だったが、モバイル側の推論はどうしている?
      • モバイルの推論はしている。
      • TFLite を用いている。

ご登壇・ご参加頂いた皆様、改めてありがとうございました。

このブログの著者

辻 陽平 (Yohei Tsuji)

AWS のソリューションアーキテクト(機械学習・HPC担当)です。好きなサービスは Amazon SageMaker と AWS CDK です。