Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Machine learning CI/CD with OSS

Machine learning CI/CD with OSS

shibuiwilliam

March 17, 2022
Tweet

More Decks by shibuiwilliam

Other Decks in Technology

Transcript

  1. 自己紹介 shibui yusuke • 自動運転スタートアップのティアフォー所属 • バックエンドエンジニア & インフラエンジニア &

    データエンジニア & 雑用 • Github: @shibuiwilliam • Qiita: @cvusk • FB: yusuke.shibui • 最近やってること: IstioとGoとARとデータ分析 cat : 0.55 dog: 0.45 human : 0.70 gorilla : 0.30 物体検知
  2. • 機械学習の有用性を試す PoCから次の段階に行くためには機械学習の DevOpsが必要 • 機械学習を含むプロダクトの価値を継続的に引き出すのが MLOps 0->1の次を目指す PoCの数々 ようやく成功した

    プロダクト 成長するには なにが足りない? →機械学習の成果を素早く実用化する →実用化の効果を素早く機械学習に取り込む →機械学習とソフトウェアを連携した  フィードバックループを実現する
  3. 機械学習を使ったプロダクト例 画像処理 写真を撮る タイトル入力 説明入力 登録する 自然言語処理 違反検知 登録情報から違反を フィルタリング

    入力情報から 入力補助 超解像による 画質改善 ねこ 検索 協調フィルタリングや ランク学習による 並べ替え あるコンテンツ登録アプリ 画像分類と 検索
  4. 機械学習を使ったプロダクトの課題例 画像処理 写真を撮る タイトル入力 説明入力 登録する 自然言語処理 違反検知 登録情報から違反を フィルタリング

    入力情報から 入力補助 超解像による 画質改善 ねこ 検索 協調フィルタリングや ランク学習による 並べ替え あるコンテンツ登録アプリ 画像分類と 検索タグ どう学習する? →定期的 →不定期 →評価が悪くなったとき いつ推論する? →検索時 →データ登録時 →1時間ごとにまとめて どう評価する? →Accuracy, Confusion Matrix →検索数、CTR、いいね数
  5. 機械学習を使ったプロダクトのシステム例 写真を撮る タイトル入力 説明入力 登録する ねこ あるコンテンツ登録アプリ ログ DB Storage

    監視 学習 モデル proxy 画像 API 推論 API batch BI デプ ロイ 認証 認可 ID 検索 API Item API 推薦 API Text API
  6. 開発段階とチームの規模で分類する 機械学習 導入開始 実用化 開発自動化 リリース 自動化 機械学習 エンジニア一人 機械学習

    エンジニア複数 機械学習エンジニア + バックエンドエンジニア プロダクト別チーム 頑張れ! 一番自由な時期! 阿吽の呼吸で わいわい楽しい♪ 軋轢が生まれ始める 運用品質 vs Jupyter 各チームの独自運用 他チームは知らない スーパーエンジニア レガシー企業は 実はこのステージが多い
  7. 開発段階とチームの規模で分類する 機械学習 導入開始 実用化 開発自動化 リリース 自動化 機械学習 エンジニア一人 機械学習

    エンジニア複数 機械学習エンジニア + バックエンドエンジニア プロダクト別チーム 頑張れ! 一番自由な時期! 阿吽の呼吸で わいわい楽しい♪ 軋轢が生まれ始める 運用品質 vs Jupyter 各チームの独自運用 他チームは知らない スーパーエンジニア レガシー企業は 実はこのステージが多い 採用を頑張ろう ♪ - 開発環境: エンジニア次第 - must: GitHub - good to have: DVC, テスト - 開発環境: エンジニア次第 - must: GitHub - good to have: DVC, テスト - 開発環境: エンジニア次第 - must: DVC, レビューと評価 - good to have: レポート - 開発環境: チーム次第 - must: リアルタイム BI連携 - good to have: チーム間 コラボレーション - 開発環境: 共通基盤, 開発環境の GitHub管 理 - must: レポート基盤 , MLFlow or KubeFlow - good to have: 共通基盤による CI/CD, QA
  8. 小規模チームにおける機械学習開発 学習 コード 学習 データ 学習 評価 モデル 推論 コード

    テスト データ 評価 コード システム 負荷 試験 ログ 収集 データ ユニット テスト
  9. チーム開発が進んだ頃の機械学習CI/CD 学習 コード 学習 データ 学習 評価 モデル レポート 推論

    コード CI テスト データ 評価 コード CD システム 負荷 試験 ログ 収集 評価 データ ユニット テスト ユニット テスト
  10. A/Bテストを見据えた機械学習CI/CD 学習 コード 学習 データ 学習 評価 モデル レポート 推論

    コード CI テスト データ 評価 コード CD システム A A/B テスト システム B 負荷 試験 ログ 収集 評価 データ ユニット テスト ユニット テスト
  11. 学習のユニットテスト 学習 コード 学習 データ 学習 評価 モデル レポート 推論

    コード CI テスト データ 評価 コード CD システム A A/B テスト システム B 負荷 試験 ログ 収集 評価 データ ユニット テスト
  12. 取得したデータが正しい • Data validation ◦ データの形式が正しい ▪ データ型が正しい: intになる値にfloatやstrが含まれていない ▪

    データの範囲が正しい:身長データに 3cmや300cmのようなありえない値が含まれていない ◦ データの分布が正しい ▪ 単位が正しい:cmで登録している身長データに mやmmによる身長が含まれていない ▪ 分布が偏っていない:平均 170cm, 中央値169cmのデータを分割した結果、平均、中央値が乖離して いない
  13. 取得したデータが正しい import pandas import pandera schema = pa.DataFrameSchema({ "gender": pa.Column(str,

    checks=pa.Check(lambda x: x in _genders , element_wise=True, error=f"gender must be {_genders}"), ), "height_cm": pa.Column(float, checks=[ pa.Check(lambda x: 130 <= x <= 210 , element_wise=True, error=f"height must be between [130, 210]", ), pa.Hypothesis.two_sample_ttest( sample1="male", sample2="female", groupby="gender", relationship="greater_than", alpha=0.01, equal_var=True, ), ], ), }) df = pd.DataFrame(data = {"gender": genders, "height_cm": heights}) df = schema(df) • PythonのPandasとPanderaによるdata validation。 • カラムごとにdata schemaを定義し、 チェックを挟むことで取得したデータの 正しさを検証する。 • Hypothesis testingを活用することで複数 カラム間の妥当性をテストすることが 可能。
  14. 取得したデータが正しい import pytest import math import collections import numpy as

    np # 学習ラベルとテストラベルの偏りをテスト def test_labels_distribution(y_train, y_test): tr_counter = collections.Counter(y_train) te_counter = collections.Counter(y_test) for (trk, trv), (tek, tev) in zip(tr_counter.items(), te_counter.items()): assert math.isclose(trv, tev, rel_tol=0.01, abs_tol=0.0) # 画像データの色の偏りをテスト def kl_divergence(a: np.ndarray, b: np.ndarray, bins=10, epsilon=0.00001): a_hist, _ = np.histogram(a, bins=bins) b_hist, _ = np.histogram(b, bins=bins) a_hist = (a_hist+epsilon) / np.sum(a_hist) b_hist = (b_hist+epsilon) / np.sum(b_hist) return np.sum([ai * np.log(ai / bi) for ai, bi in zip(a_hist, b_hist)]) def test_image_bias(train_image: np.ndarray, test_image: np.ndarray): assert kl_divergence(train_image, test_image) < 0.1 • 学習時のデータの偏りをテストする • 学習データとテストデータで傾向が異なる状態 を防ぐ目的 • 研究開発時にはTensorBoardやKnow Your Dataが便利 https://knowyourdata.withgoogle.com/ • CI/CDや学習の自動化を進める際は、 Data Validation同様にデータの異常を検知 するためのユニットテストを書く
  15. 機械学習開発のテスト • ソフトウェア開発ではプログラムを通してロジックをテストする • 機械学習ではコードを通してデータで確率をテストする YES or NO 0 ~

    1 ソフトウェア開発のテスト 機械学習のテスト 入力 正解 出力 assert 関数 指標 推論 evaluate モデル 関数 テスト通過率:95/100 Accuracy:0.99 Precision:0.95 Recall:0.60 23 データ
  16. # 少量データで学習が動く&進むことをテスト @pytest.mark.parametrize( (“model”, "train_path", “test_path” “epochs”), [(model, “/tmp/small_train/”, “/tmp/small_test/”,

    10)], ) def test_train( model: nn.Module, train_path: str, test_path: str, epochs: int, ): trainloader = make_dataloader(train_path) testloader = make_dataloader(test_path) init_accuracy = evaluate(model, testloader) losses = train(model, epochs, trainloader) assert losses[0] > losses[-1] trained_accuracy = evaluate(model, testdata) assert init_accuracy < trained_accuracy 機械学習開発のテスト def make_dataloader(data_path: str) -> DataLoader: return dataloader(data_path) def train( model: nn.Module, epochs: int, trainloader: DataLoader, ) -> List[float]: losses = [] for epoch in range(epochs): average_loss = train_once(model, trainloader) losses.append(average_loss) model.save() return losses def evaluate( model_path: str, testloader: DataLoader, ) -> List[float]: predictor = Model(model_path) evaluations = predictor.evaluate(testloader) return evaluations
  17. モデルの評価 学習 コード 学習 データ 学習 評価 モデル レポート 推論

    コード CI テスト データ 評価 コード CD システム A A/B テスト システム B 負荷 試験 ログ 収集 評価 データ ユニット テスト ユニット テスト
  18. DVCの仕組み • Data Version Control • 機械学習で使用するデータをGitと連携してバー ジョン管理する。 • データはハッシュとともにリモート

    ストレージ(S3やGCS等)に保存。 • データの変更を記録してハッシュのみGitで管理 する。
  19. DVCの仕組み # dvcを初期化; git initと同様 $ dvc init # リモートストレージを追加

    $ dvc remote add -d remote_s3 s3://example/path # データを記録 $ dvc add ./data/train.csv # dvcデータとコードを記録 $ dvc commit && git add . && git commit # リモートストレージにデータを追加 $ dvc push # コードとデータをチェックアウト $ git checkout ${commit} && dvc checkout # git pullと同様 $ dvc pull Git DVC Data Remote dvc init dvc remote add dvc add git add git commit dvc push git checkout dvc checkout dvc pull dvc commit
  20. 学習と評価のバージョンコントロール # 学習 $ dvc add ./data/train.csv ./params.json $ python

    -m src.train -d ./data/train.csv -p ./params.json saved model to ./model/model.onnx $ dvc add ./model/model.onnx # 評価実施 $ dvc add ./data/test.csv $ python -m src.evaluate -d ./data/test.csv saved evaluation to ./evaluation/evaluations.json # 評価レポート作成 $ python -m src.report -d ./evaluate/evaluations.json Saved report to ./report/report.md $ dvc add ./evaluation/evaluations.json ./report/report.md # 評価およびレポートの記録 $ dvc commit && git add . && git commit -m “evaluated” # push $ git push && dvc push Git DVC Data Remote git add git commit dvc commit dvc add python evaluate python report dvc add dvc push git push dvc add python train
  21. MLFlowによる学習とアーティファクト管理 import mlflow # 自動ログ mlflow.sklearn.autolog() with mlflow.start_run() as run:

    x_train, x_test, y_train, y_test = load_dataset() params = define_params() model = load_model(params) model.fit(x_train, y_train) metrics = model.evaluate(x_test, y_test) model.save_onnx(“/tmp/model.onnx”) # ハイパーパラメータ記録 mlflow.log_params(params) # メトリクス記録 mlflow.log_metrics(metrics) # アーティファクト管理 mlflow.log_artifact(“/tmp/model.onnx”)
  22. 機械学習のCI 学習 コード 学習 データ 学習 評価 モデル レポート 推論

    コード CI テスト データ 評価 コード CD システム A A/B テスト システム B 負荷 試験 ログ 収集 評価 データ ユニット テスト ユニット テスト
  23. 機械学習のCI • コードの正常性テスト、学習の妥当性テスト、インフラの堅牢性を分ける ◦ コードの正常性テスト ▪ Data Validation • 選択肢1.

    汎用的にデータパイプラインで実行する • 選択肢2. 個別に学習のデータ取得時に実行する ▪ コードが正しく動く ◦ 学習の妥当性テスト ▪ 学習したモデルが実用化レベルの品質を持っている ▪ モデルをシステムに組み込むことができる ◦ インフラの堅牢性テスト ▪ 負荷テスト ▪ パフォーマンスに対するコスト評価 • 上記を連続して実行してテスト・評価ともに通過する
  24. 機械学習のCI Repo Code DVC CI データ取得 前処理 学習 評価 リリース

    data validation data to be used test code data to be used model small data evaluating code serving infra model & test dataset model training code
  25. DVCとCML • Data Version Control • データ分析や機械学習で使ったデータを バージョン管理する • Gitみたいに使う

    • https://dvc.org/doc • Continuous Machine Learning • GitHub ActionとDVCと組み合わせて データを管理したCI/CDが可能 • Git+CI+CML • https://github.com/iterative/cml
  26. GitHub Actionsでワークフローを書く jobs: run: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2

    - uses: iterative/setup-cml@v1 - name: ci env: REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | dvc pull pytest tests -s -v docker build test:${commit} . docker run test:${commit} \ python -m src.integrate -m model/model.onnx -o report.md cat report/report.md >> report.md cml-publish report/confusion_matrix.png --md >> report.md cml-send-comment report.md Remote DVC CML Git dvc pull pytest docker build docker run cml-publish cml-send- comment
  27. 機械学習のCDと負荷テスト 学習 コード 学習 データ 学習 評価 モデル レポート 推論

    コード CI テスト データ 評価 コード CD システム A A/B テスト システム B 負荷 試験 ログ 収集 評価 データ ユニット テスト ユニット テスト
  28. サーバサイドにモデルをリリースする • モデルインイメージパターン ◦ 推論器のイメージにモデルを含めてビルドするパターン。 Dockerイメージサイズは大きくなるため、 Docker pullに時間を要する。 ベースイメージを共通化することで pull時間を短縮することが可能。

    • モデルロードパターン ◦ モデルファイルと推論器イメージを別に管理するパターン。 Dockerイメージを共通かつ軽量に保つことが可能。 学習時と推論イメージでソフトウェアのバージョン不一致が発生する可能性が残る。 学習環境と推論イメージでバージョニングする必要がある。
  29. サーバサイドのモデルリリース 推論用 Dockerイメージ ランタイム モデル 学習 Docker イメージビルダー モデル管理 推論器

    推論器 推論用Docker ベースイメージ ランタイム Dockerレジストリ 保存 モデルファイル モデルを含めて Dockerビルド モデルインイメージパターン モデル管理 保存 モデルファイル 推論用Docker ベースイメージ ランタイム デプロイ モデルロードパターン デプロイ時に モデルをロード
  30. モデルインイメージ jobs: run: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 -

    uses: iterative/setup-cml@v1 - name: ci run: | # 学習済みモデルを取得 dvc pull # モデルを指定してビルド docker build \ --build-arg MODEL=/models /model.onnx \ ml_serving:${commit} . # Docker Registryにプッシュ docker push ml_serving:${commit} # デプロイ kubectl -n ml_serving apply -f manifests/ml_serving.yaml Git Remote Docker Reg Server dvc pull docker build docker push kubectl apply
  31. モデルロード jobs: run: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 -

    uses: iterative/setup-cml@v1 - name: ci run: | # 推論サーバをビルド docker build ml_serving:${commit} . # Docker Registryにプッシュ docker push ml_serving:${commit} # デプロイ; init_containerでモデルを取得 kubectl -n ml_serving apply -f manifests/ml_serving.yaml Git Remote Docker Reg Server docker build docker push kubectl set env
  32. 負荷テスト Load tester LB Load tester • 推論器を本番同様のリソースで稼働させて レイテンシーを測り、ボトルネックを発見、 チューニングする。

    • Too bigなモデルでない限り、モデルは変更せずに 実行環境で高速化や可用性強化を図る。 • 推論器のボトルネックは推論モデル。 Webサーバに組み込んで計測する前に、 モデル単体をサーバ内部で連続して 推論させ、推論の平均所要時間を計測する。 • 学習コストの高いディープラーニングモデルを 使う場合、学習前にモデルだけで負荷テストを 実行して遅延を確認しておく。 Profile 入力 前処理 推論 後処理 出力 レイテンシー( ms) 計測時間 計測時間 リクエスト数/秒
  33. 負荷テスト • 負荷テスト ◦ 外部から連続してリクエストを送信。 入力がサイズ不特定の画像やテキストの場合、 ランダムなサイズのデータを用意。 ◦ CPU使用率が上がらず遅延が発生する場合、 ワーカー数や通信方法を調整する。

    NumpyやSklearnであればIntel MKLを使用する ことも選択肢。 ◦ メモリリークが発生して根本解決が困難な場合、 Gunicornのmax_requestsパラメータで、一定数の リクエスト後にワーカープロセスを再起動する ことで緩和可能。 jitterやgraceful-timeoutと組み合わせる。 ◦ TensorflowやPytorchであれば前処理含めて 計算グラフに組み込むことで遅延短縮可能。 ◦ 推論用GPUはコスト対効果次第。 Load tester LB Load tester 計測時間 リクエスト数/秒 計測時間 リソース RAM CPU
  34. 負荷テスト Load tester LB ML ML ML 計測時間 リソース RAM

    CPU x 画像データで負荷テストするために クライアント側がボトルネックになる x リソースを使い切らずに パフォーマンス低下 計測時間 リソース RAM CPU x プロキシが通信量を 裁ききれずにOOM 経過時間 リクエスト レスポンス x リクエストデータよりも 推論結果が大きくて遅延 リソース CPU 計測時間 異なるサイズでテストする
  35. 負荷テストツール Locust Python純正の負荷テストツール。 Pythonでテスト方法を定義し実行。 Web画面を用意し、レイテンシーやエラー率の把握や アクセス数の変更が可能。 アクセスクライアントやワーカー数を調整可能で、 様々な負荷状況を再現可能。 それなりに重い。 Vegeta

    Attack Golang製の負荷テストツール。 コマンドラインで実行可能。 軽量に高負荷を掛けることができる。 $ vegeta attack -duration=300s -rate=10000 \ -timeout=10ms -targets=target \ | vegeta report -type='hist[0,2ms,4ms,6ms]' Bucket # % Histogram [0s, 2ms] 2964541 98.82% ##################### [2ms, 4ms] 31232 1.04% # [4ms, 6ms] 2266 0.08% [6ms, +Inf] 1961 0.07%
  36. 推論のA/Bテスト 学習 コード 学習 データ 学習 評価 モデル レポート 推論

    コード CI テスト データ 評価 コード CD システム A A/B テスト システム B 負荷 試験 ログ 収集 評価 データ ユニット テスト ユニット テスト
  37. サーバサイド機械学習のA/Bテスト 商品A キャンペーン 商品B 商品A キャンペーン 商品B 商品A キャンペーン 商品B

    商品D キャンペーン 商品C 新モデル 現モデル UIのA/Bテスト 機械学習のA/Bテスト UIの違い→CTRを比較 ロジックの違い→CTRを比較
  38. IstioによるランダムA/Bテスト 新モデル 現モデル apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: iris

    namespace: online-ab spec: host: iris trafficPolicy: loadBalancer: simple: ROUND_ROBIN subsets: - name: svc labels: version: svc - name: rf labels: version: rf apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: iris namespace: online-ab spec: hosts: - iris http: - route: - destination: host: iris subset: svc weight: 60 - destination: host: iris subset: rf weight: 40
  39. headerで分割するA/Bテスト 新モデル 現モデル apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: iris

    namespace: online-ab spec: host: iris trafficPolicy: loadBalancer: simple: ROUND_ROBIN subsets: - name: svc labels: version: svc - name: rf labels: version: rf apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: iris namespace: online-ab spec: hosts: - iris http: - match: - headers: - cookie: test_group route: - destination: host: iris subset: svc - route: - destination: host: iris subset: rf header
  40. 本を出版しました! • AIエンジニアのための 機械学習システムデザインパターン • 2021年5月17日発売 • https://www.amazon.co.jp/dp/4798169447/ • 機械学習と銘打ってるのに

    KubernetesとIstioに 詳しくなれる一冊です! • Amazon.co.jp 情報学・情報科学部門  1位! 人工知能部門 1位! • 増刷決定! • 韓国語版と中国語版(台湾)も出るらしい!