MLOpsのためのソリューションを調査した

私は、AIシステム開発で、おもにクラウドや機械学習の基盤の構築や保守を担当しています。
たま～～に分析もします。世間一般でいうところの「データエンジニア」とか「機械学習エンジニア」的な仕事をしています。

# MLOpsって？

MLの開発運用においては、まずデータサイエンティストがデータを分析し、できた特徴量やモデルの成果を、本番システムに乗せ、オンライン予測やバッチ予測を稼働させる、というのが流れです。これには、データ分析以外にも、たとえば再現性の担保や、リリースされているモデルのバージョン管理、データのバージョン管理、データと学習/予測コードとモデルのバージョンの構成の管理、データドリフトの監視など、モデル成果を継続してカスタマーに届けるための取り組みが必要で、これを**MLOps**と呼んでいます。従来のソフトウェアにおける「DevOps」という概念に、「データ」と「モデル」という存在が加わった感じです。

# コードとリリース以外にバージョン管理するものがある

機械学習プロジェクトでバージョン管理するものは、「コード」だけではなく、前述した「データ」と「モデル」にもバージョンという概念があります。それぞれのバージョン管理が必要になる理由は、データは実験の再現性の担保やデータドリフトの検知、モデルは、学習コードやデータと関連付けて性能の比較を行ったり、KPIとの関係を追ったりするためだと思います。
そして、ここにデータリネージという概念も入ってきます。

* 「どのデータで」「どのバージョンのコードで」特徴量計算した結果が、「どのデータ」なのか
* 「どのデータで」「どのバージョンのコードで」学習を行った結果が「どのモデルなのか」
* 「どのデータで」「どのモデルで」予測した結果が「どのデータ」なのか
* 「いつから」「どのモデルが」リリースされているのか

こういったものをうまく紐づけるのが、難しいなと感じています。

## dvcでコードベースなMLOps

開発初期はこういった課題はExcelやナレッジベースに、リリース更新などのたびに紐づけ関係を書いていくなどの運用でカバーする方法はできるのですが、成果物の複雑な依存関係は、なるべく機械にやらせたいというのが人間の性。
この課題には[dvc (Data Version Control)](https://dvc.org/)というオープンソースツールが、[iterative](https://iterative.ai/)によって開発されており、GitHubで入力データやモデル出力物とコードの依存関係を、コードベースで管理できるようになっています。

### dvcでできること

* データのバージョン管理
    * データやモデルの中身が変わったら、ハッシュ変換値をファイルに記録して、実体は外部に保管
* パイプライン定義
    * パイプラインのステージと、入力依存や出力物のコードベースな定義
* パイプライン実行
    * `dvc repro`コマンド一つで、gitのコミットと紐づいたパイプライン実行
* メトリクス追跡


たとえば、[dvcのチュートリアルガイド](https://dvc.org/doc/start/data-pipelines)にある下記のコードですが、

```bash
dvc run -n prepare \
          -p prepare.seed,prepare.split \
          -d src/prepare.py -d data/data.xml \
          -o data/prepared \
          python src/prepare.py data/data.xml
```
実行するコマンド本体は一番最後の`python src/prepare.py data/data.xml`ですが、この処理が何に依存しているのかを上のオプションで定義しているイメージです。

* パイプラインのステージ名は`prepare`である
* このステージが依存するパラメータ(入力パラメータ)は `prepare.seed`と `prepare.split` (params.yamlに定義してある) である
* このステージが依存するデータ(入力データ)は `src/prepare.py`と `data/data.xml`である
* このステージの出力は`data/prepared`である

そして、これを実行すると、通常通りの処理が実行されると同時に、これらの依存関係が`dvc.yaml`というファイルに記録されます。

```yml
stages:
  prepare:
    cmd: python src/prepare.py data/data.xml
    deps:
      - src/prepare.py
      - data/data.xml
    params:
      - prepare.seed
      - prepare.split
    outs:
      - data/prepared
```
このようにステージの定義をつなげていって、一つのパイプラインを作っていくと、`dvc.yaml`にパイプライン内のステージの依存関係や、ステージ内のファイルやパラメータの依存関係が記録されていき、最終的には`dvc repro`を実行すると、パイプラインを実行することができます。

このパイプラインの入出力であるデータやモデルですが、`dvc add data/data.xml data/prepared`と実行すると、dvcによるバージョン管理下に入ります。
具体的には、これを実行すると

* データファイル(data/data.xmlやdata/prepared)がgit管理下から外れる
* `.dvc`というファイルに、データがmd5ハッシュ変換されて記録される
* データは、リポジトリ外のストレージや指定した外部ストレージにバックアップされる

ので、データの代わりにこの`.dvc`ファイルをgitでバージョン管理することで、データやモデル成果物のバージョンも管理できるということですね。

## KubeflowでワークフローによるMLOps

さて、dvcでデータ、コード、モデルのバージョンは紐づけられそうです。
しかし、本番に乗せた場合は、ほかの外部のシステムと連携しながら動く場合がほとんどで、

* パイプラインを「どのパラメータで」「いつ」実行したのか
* 「いつ」「どのモデルが」リリースされているか
* その結果はどこに出力・転送されているか、保管されているか
* ジョブの成否履歴

を管理したくなってきます。「いつ」に関する管理はdvcだとちょっと弱い気がしています。

これに関しては、KubeflowやApache Airflowといったワークフローエンジンがソリューションの選択肢に入ってきます。
Google Cloud Platformユーザであれば、**Vertex AI**をつかうことでKubeflowを**マネージド環境**で利用することができます。

私としては、

* パイプラインをGUIで組む(コードベースでもできる)
* **ダッシュボードUI**で日々の実行の成否を追跡する
* **Vertex AI Metadata**を使って、そのそれぞれの実行がどのパラメータで動いたのかが記録として残される

これがなかなかイケてると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2240999/bea1f875-023b-bd45-a9b8-6e82a83cc8ac.png)
https://lp.cloudplatformonline.com/rs/808-GJW-314/images/Ask_the_Expert_Session3.pdf より引用

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2240999/42943622-3248-cf32-e2e2-4c5b384137ab.png)
https://lp.cloudplatformonline.com/rs/808-GJW-314/images/Ask_the_Expert_Session3.pdf より引用

Vertex AIは割と新しいサービスで、GoogleCloudも開発にかなり力を入れているようです。
私はまだこのサービスに対する知識が乏しく、YouTubeに解説動画(英語)がたくさん上がっておりましたので、それを見て頑張って勉強しようと思います。
https://www.youtube.com/watch?v=gT4qqHMiEpA

# まとめ

・・・と、なんかちょっと中途半端な感じで終わってしまいそうになりましたが、
機械学習エンジニアリング(MLSE)は比較的新しい領域であり、大変そうだな～と思うと同時に「ワクワクする」ような仕事だと思います。
これからも「イケてる」機械学習基盤の構築のため努力していく所存ですので、またいつかのアドベントカレンダーでお会いしましょう。