Slide 1

Slide 1 text

CA 1day Youth Boot Camp - MLOps - AI Shift 干飯 啓太

Slide 2

Slide 2 text

2/111 本講義のテーマ 研究の機械学習から 運用可能な機械学習への入門

Slide 3

Slide 3 text

3/111 本講義のゴール Portableな実験環境を作れるようになる

Slide 4

Slide 4 text

4/111 扱うテーマ ●Docker ●実験管理(MLflow)

Slide 5

Slide 5 text

5/111 今日の講義 MLOpsを本格的に始めるための 前段階の話をします

Slide 6

Slide 6 text

1. MLOpsとは 2. Docker入門 3. 機械学習の実験管理 4. 終わりに

Slide 7

Slide 7 text

7/111 自己紹介 干飯 啓太(ほしい けいた) 職種: ML Engineer/Data Scientist 所属: AI Shift AI Messenger Summary 責任者 @hosimesi11_ @hosimesi

Slide 8

Slide 8 text

1. MLOpsとは 2. Docker入門 3. 機械学習の実験管理 4. 終わりに 講義 ハンズオン

Slide 9

Slide 9 text

MLOpsとは

Slide 10

Slide 10 text

10/111 MLOpsとは Machine Learning ✖ Operations 機械学習 運用

Slide 11

Slide 11 text

MLOpsの派生 LLMOps FMOps ※ 良くも悪くもバズワードになりやすいので、実態をちゃんと捉えるようにしましょう 11/111

Slide 12

Slide 12 text

12/111 MLOpsのGoogle Trends

Slide 13

Slide 13 text

13/111 MLOpsの立ち位置 DevOps for ML

Slide 14

Slide 14 text

なぜMLOpsが必要なのか? 大前提: ● DevOpsで必要なことはMLOpsでも必要 ML特有の課題 ● 機械学習モデルは入力に対して確率的な振る舞いをする ● 最新のデータで再学習しないとモデルが劣化する可能性がある ● モデルにはいくつかのハイパーパラメータがある ● コードのライフサイクルとモデルのライフサイクルが違う可能性がある 14/111

Slide 15

Slide 15 text

MLコードの立ち位置 機械学習システムに占めるMLコードはほんの一部 https://proceedings.neurips.cc/paper_files/paper/2015/file/86df7dcfd896fcaf2674f757a2463eba-Paper.pdf 15/111

Slide 16

Slide 16 text

16/20 MLOpsを構成する要素 Google CloudがまとめたMLOpsの構成要素 https://cloud.google.com/architecture/mlops-continuous -delivery-and-automation-pipelines-in-machine-learning

Slide 17

Slide 17 text

17/20 MLOpsを構成する要素 実験基盤 学習パイプライン 推論サーバ モデルのバージョン管理 データのバージョン管理 CI/CD 監視 継続的な学習 データ基盤 https://speakerdeck.com/nsakki55/mlops-basic?slide=34 実験基盤 学習パイプライン

Slide 18

Slide 18 text

ここまでの話 機械学習システム を作って運用するには ソフトウェアエンジニアリング のスキルは必須 ※ もちろん一人で全部できる必要はないので、チームで強みを補い合って進める https://speakerdeck.com/nsakki55/mlops-basic?slide=31 18/111

Slide 19

Slide 19 text

今日の講義 機械学習システムの構築・運用するためのベースとなる コンテナ技術・実験管理について のハンズオンを行いま す 19/111

Slide 20

Slide 20 text

20/20 今日扱うもの 実験基盤 学習パイプライン 推論サーバ モデルのバージョン管理 データのバージョン管理 CI/CD 監視 継続的な学習 データ基盤 https://speakerdeck.com/nsakki55/mlops-basic?slide=34 実験基盤

Slide 21

Slide 21 text

21/111 他の部分はこちらを参照 実験基盤 学習パイプライン 推論サーバ モデルのバージョン管理 データのバージョン管理 CI/CD 監視 継続的な学習 データ基盤

Slide 22

Slide 22 text

Docker入門

Slide 23

Slide 23 text

Prerequisites 1.Docker Desktop 2.Docker Hubユーザ登録 3.GitHubレポジトリ のClone ※ 次のページに具体的な方法を書いていますので参照してください 23/111

Slide 24

Slide 24 text

Docker Desktopのインストール homebrewが入っている方 $ brew install --cask docker 直接ダウンロードする方(Mac) こちらに沿ってインストール 直接ダウンロードする方(Windows) こちらに沿ってインストール 24/111

Slide 25

Slide 25 text

Docker Hubユーザ登録 25/111

Slide 26

Slide 26 text

レポジトリのClone レポジトリ: https://github.com/hosimesi/mlops-introduction 26/111

Slide 27

Slide 27 text

レポジトリのClone $ git clone https://github.com/hosimesi/mlops-introduction $ cd mlops-introduction https://github.com/CyberAgentAI/dsc-onboarding-mlops-2024 レポジトリのClone ディレクトリ移動 27/111 ※ macでgitが使えない場合、 xcodeのアップデートをしてください

Slide 28

Slide 28 text

ディレクトリの外観 https://github.com/CyberAgentAI/dsc-onboarding-mlops-2024 . ├── 1-notebook-in-docker │ ├── README.md │ ├── poetry.lock │ ├── pyproject.toml │ └── train.ipynb ├── 2-docker-mlflow │ ├── Dockerfile │ ├── README.md │ ├── poetry.lock │ ├── pyproject.toml │ └── train.ipynb ├── README.md └── train_data.zip $ tree 本章: Docker入門で使用 次章: 実験管理で使用 28/111

Slide 29

Slide 29 text

データとコードの前準備 $ unzip train_data.zip $ cp train_data 1-notebook-in-docker/train_data データの解凍 ファイルのコピー $ cp train_data 2-docker-mlflow/train_data 29/111

Slide 30

Slide 30 text

研究での環境構築 研究で使うコードや環境は どのように管理していますか? 30/111

Slide 31

Slide 31 text

コード管理 ローカルでコード管理なし 何かしらのクラウドストレージ Git 31/111

Slide 32

Slide 32 text

環境構築 pip poetry uv・rye anaconda venv pyenv 32/111

Slide 33

Slide 33 text

こんなことはありませんか? pip installが通らない 先輩から引き継がれたコードが動かない 環境構築で時間を溶かす 手元で動かしたコードがサーバでは動かない 33/111

Slide 34

Slide 34 text

34/20 Welcome to Container

Slide 35

Slide 35 text

Docker Docker is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly. With Docker, you can manage your infrastructure in the same ways you manage your applications. By taking advantage of Docker's methodologies for shipping, testing, and deploying code, you can significantly reduce the delay between writing code and running it in production. https://docs.docker.com/get-started/docker-overview/ 35/111

Slide 36

Slide 36 text

Why Docker? ● コードを動かすために必要なパッケージはDockerに全て含む ○ Dockerさえ入っていればどの環境でも動く状態に ■ pipやpyenvではダメ?? ● コード共有時や引き継ぎはどうする? ● OSへの直インストールなどはどう対応? ● 実験コードを動かすための手順をDockerで隠蔽 ○ Docker Commandの実行のみで完結 ● クラウドのコンテナサービスに機械学習アプリケーションをそのままデプロイ可能 ○ 2024年現在だとMLに限らず、アプリケーション運用の業界標準 https://speakerdeck.com/chck/container-for-mlops?slide=12 36/111

Slide 37

Slide 37 text

コンテナと仮想マシンの違い https://www.docker.com/ja-jp/resources/what-container/ コンテナ: アプリレイヤーの抽象化でOS カーネルを他のコンテナーと共有し、それぞれが ユーザー空間で分離されたプロセスとして実行 仮想マシン: 物理ハードウェアの抽象化したものでOSレベルで分離可能だが起動が遅い 37/111

Slide 38

Slide 38 text

コンテナ実行手順 ※ Dockerfileを書かずとも、ビルド済みイメージを引っ張ってきて実行することも可能 38/111

Slide 39

Slide 39 text

より良い研究開発環境を作る いきなり全部変更するのはハードルが高いと思うので段階的に導入 してみましょう pythonを直インストールしている方 → uvやpyenv + poetry 直接環境構築している方 → Docker コード管理していない方 → Git Linter・Formatterを設定していない方 → Ruff + mypyやpysen 39/111

Slide 40

Slide 40 text

余談: 最近のPython事情 Rust製ツールが人気 uv: ● https://astral.sh/blog/uv ● package manager rye: ● https://rye-up.com/ ● package manager ruff: ● https://github.com/astral-sh/ruff ● linter & formatter 40/111

Slide 41

Slide 41 text

余談: 最近のPython事情 ● pytest ● mypy ● black ● flake8 ● isort ● pytest ● mypy ● ruff Pythonプロジェクトの開始時に入れるべきライブラリ群がアップデート 41/111

Slide 42

Slide 42 text

PythonのNotebookをDocker化する 1. 既にあるPythonのNotebookをDocker化する ※ ライブラリのインストールはpoetryで行なっているとします ステップ 1. 既存のPython環境の依存を含んだDocker Imageの作成 2. Jupyter NotebookをDockerコンテナ内で実行 42/111

Slide 43

Slide 43 text

Notebookで行っていること オンライン広告のクリックスルー率 (CTR)を予測するモデルの作成 やっていること ● データの読み込み ● データの前処理 ● モデルの学習 ○ SGD Classifier ● 評価 https://github.com/nsakki55/aws-mlops-handson/blob/main/analyse.ipynb 43/111

Slide 44

Slide 44 text

使用しているデータ Avazu CTRデータ オンライン広告のCTRを予測する問題 44/111

Slide 45

Slide 45 text

ベースイメージを決める python docker で検索 ※ 最新のDockerfileの書き方はこちらの記事が参考になります 45/111

Slide 46

Slide 46 text

ベースイメージを決める 46/111

Slide 47

Slide 47 text

ベースイメージを決める 注目 47/111

Slide 48

Slide 48 text

どのイメージを使うか? おすすめはSlimイメージ python:3.12 python:3.12-slim python:3.12-alpine フルパッケージ(サイズが大きい) 軽量版(ちょうど良い) 最軽量版(必要なものが入っていないこともあり) $ docker pull python:tag $ docker images | grep python python 3.12-slim cec3038ab647 6 days ago 254MB python 3.12-alpine aeff64320ffb 6 days ago 86.2MB python 3.12 3c085580c5f2 6 days ago 1.46GB 48/111

Slide 49

Slide 49 text

Dockerfileを書く 49/111 $ $EDITOR Dockerfile Dockerfileの作成 EDITORはvscodeやvimなど自身が使いたいものでOK $ cd path/to/1-notebook-in-docker ディレクトリの移動

Slide 50

Slide 50 text

Dockerfileを書く FROM python:3.12-slim AS base RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /app ENV PYTHONPATH=/app COPY pyproject.toml poetry.lock ./ RUN pip install --upgrade pip \ && pip install poetry=="1.8.3" \ && poetry export --with app --without-hashes -f requirements.txt -o requirements.txt \ && pip install -r requirements.txt COPY train.ipynb /app ENTRYPOINT ["jupyter", "lab", "--port", "8080", "--ip=0.0.0.0", "--no-browser", "--allow-root", "--NotebookApp.token=''"] EXPOSE 8080 50/111

Slide 51

Slide 51 text

Dockerfileを書く FROM python:3.12-slim AS base RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /app ENV PYTHONPATH=/app COPY pyproject.toml poetry.lock ./ RUN pip install --upgrade pip \ && pip install poetry=="1.8.3" \ && poetry export --with app --without-hashes -f requirements.txt -o requirements.txt \ && pip install -r requirements.txt COPY train.ipynb /app ENTRYPOINT ["jupyter", "lab", "--port", "8080", "--ip=0.0.0.0", "--no-browser", "--allow-root", "--NotebookApp.token=''"] EXPOSE 8080 ベースイメージの指定 51/111

Slide 52

Slide 52 text

Dockerfileを書く FROM python:3.12-slim AS base RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /app ENV PYTHONPATH=/app COPY pyproject.toml poetry.lock ./ RUN pip install --upgrade pip \ && pip install poetry=="1.8.3" \ && poetry export --with app --without-hashes -f requirements.txt -o requirements.txt \ && pip install -r requirements.txt COPY train.ipynb /app ENTRYPOINT ["jupyter", "lab", "--port", "8080", "--ip=0.0.0.0", "--no-browser", "--allow-root", "--NotebookApp.token=''"] EXPOSE 8080 環境構築の依存コマンドの実行 52/111

Slide 53

Slide 53 text

Dockerfileを書く FROM python:3.12-slim AS base RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /app ENV PYTHONPATH=/app COPY pyproject.toml poetry.lock ./ RUN pip install --upgrade pip \ && pip install poetry=="1.8.3" \ && poetry export --with app --without-hashes -f requirements.txt -o requirements.txt \ && pip install -r requirements.txt COPY train.ipynb /app ENTRYPOINT ["jupyter", "lab", "--port", "8080", "--ip=0.0.0.0", "--no-browser", "--allow-root", "--NotebookApp.token=''"] EXPOSE 8080 Image内での実行ディレクトリ指定 53/111

Slide 54

Slide 54 text

Dockerfileを書く FROM python:3.12-slim AS base RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /app ENV PYTHONPATH=/app COPY pyproject.toml poetry.lock ./ RUN pip install --upgrade pip \ && pip install poetry=="1.8.3" \ && poetry export --with app --without-hashes -f requirements.txt -o requirements.txt \ && pip install -r requirements.txt COPY train.ipynb /app ENTRYPOINT ["jupyter", "lab", "--port", "8080", "--ip=0.0.0.0", "--no-browser", "--allow-root", "--NotebookApp.token=''"] EXPOSE 8080 環境変数の指定 54/111

Slide 55

Slide 55 text

Dockerfileを書く FROM python:3.12-slim AS base RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /app ENV PYTHONPATH=/app COPY pyproject.toml poetry.lock ./ RUN pip install --upgrade pip \ && pip install poetry=="1.8.3" \ && poetry export --with app --without-hashes -f requirements.txt -o requirements.txt \ && pip install -r requirements.txt COPY train.ipynb /app ENTRYPOINT ["jupyter", "lab", "--port", "8080", "--ip=0.0.0.0", "--no-browser", "--allow-root", "--NotebookApp.token=''"] EXPOSE 8080 Image内へのファイルのコピー local://{pwd}/file_name docker://app/file_name 55/111

Slide 56

Slide 56 text

Dockerfileを書く FROM python:3.12-slim AS base RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /app ENV PYTHONPATH=/app COPY pyproject.toml poetry.lock ./ RUN pip install --upgrade pip \ && pip install poetry=="1.8.3" \ && poetry export --with app --without-hashes -f requirements.txt -o requirements.txt \ && pip install -r requirements.txt COPY train.ipynb /app ENTRYPOINT ["jupyter", "lab", "--port", "8080", "--ip=0.0.0.0", "--no-browser", "--allow-root", "--NotebookApp.token=''"] EXPOSE 8080 コンテナ実行時の実行コマンド 56/111

Slide 57

Slide 57 text

Dockerfileを書く FROM python:3.12-slim AS base RUN apt-get update && apt-get install -y --no-install-recommends \ && apt-get clean && rm -rf /var/lib/apt/lists/* WORKDIR /app ENV PYTHONPATH=/app COPY pyproject.toml poetry.lock ./ RUN pip install --upgrade pip \ && pip install poetry=="1.8.3" \ && poetry export --with app --without-hashes -f requirements.txt -o requirements.txt \ && pip install -r requirements.txt COPY train.ipynb /app ENTRYPOINT ["jupyter", "lab", "--port", "8080", "--ip=0.0.0.0", "--no-browser", "--allow-root", "--NotebookApp.token=''"] EXPOSE 8080 コンテナのポートを公開 57/111

Slide 58

Slide 58 text

Docker Imageの作成 $ docker build . -t notebook-in-docker:1.0 58/111

Slide 59

Slide 59 text

Docker Imageの作成 $ docker build . -t notebook-in-docker:1.0 ビルドコンテキスト: COPYの起点になる部分で基本的にDockerfileのある位置 イメージ名 タグ: 運用時はcommit hashをつけるのが一般的 59/111

Slide 60

Slide 60 text

Docker Imageの作成 $ docker images | grep notebook-in-docker notebook-in-docker 1.0 b37964265132 56 seconds ago 380MB 60/111

Slide 61

Slide 61 text

Docker Containerの実行 $ docker run -p 8080:8080 --rm notebook-in-docker:1.0 61/111

Slide 62

Slide 62 text

Docker Containerの実行 $ docker run -p 8080:8080 --rm notebook-in-docker:1.0 実行コマンド コンテナポートをホストマシン側に ポートフォワード 起動後コンテナは破棄 イメージ名 [I 2024-09-07 14:44:20.730 ServerApp] jupyter_lsp | extension was successfully linked. [I 2024-09-07 14:44:20.731 ServerApp] jupyter_server_terminals | extension was successfully linked. [W 2024-09-07 14:44:20.732 LabApp] 'token' has moved from NotebookApp to ServerApp. This config will be passed to ServerApp. Be sure to update your config before our next release : :. 62/111 ※ -–rm: 不要なコンテナがシステムのリソースを占有するのを防ぐ

Slide 63

Slide 63 text

Tips: Docker Containerの中に入るには? 63/111 $ docker exec -it {container_id} bash コンテナ内に入ってデバッグしたい時 実行コマンドは上書き可能 コンテナの中に入る $ docker ps コンテナ一覧確認

Slide 64

Slide 64 text

Tips: Docker Imageの調査 脆弱性の調査 $ docker scout ~~ local://notebook-in-docker:1.0 $ docker scout recommendations local://notebook-in-docker:1.0 脆弱性の減少やイメージ サイズの縮小の調査 Docker Imageの調査 $ docker scout cves local://notebook-in-docker:1.0 例 64/111 ※ docker scoutはinstallが必要(https://docs.docker.com/scout/install/)

Slide 65

Slide 65 text

Tips: コンテナ内での編集を元ファイルに反映したい 今のままだとcontainer内でnotebookを編集したとしても、containerを落とした場合に元々のファイルは変更されていない local コンテナ内 コピー 同期されない $ docker run -p 8080:8080 -v $PWD/train.ipynb:/app/train.ipynb --rm notebook-in-docker:1.0 Volumeを使ってマウントする 65/111

Slide 66

Slide 66 text

Tips: モデルなど大きなファイルを扱いたい時 機械学習で使うデータをそのままコンテナ内に入れるとイメージサイズが大きくなる $ docker run -p 8080:8080 -v $PWD/train_data:/app/train_data --rm notebook-in-docker:1.0 Volumeを使う volumeでsyncすることでイメージサイズを小さくする 66/111

Slide 67

Slide 67 text

モデルの学習(データ読み込み) 67/109 PandasのDataFrame形式で読み込み

Slide 68

Slide 68 text

モデルの学習(前処理) 68/109

Slide 69

Slide 69 text

モデルの学習(学習) 69/109

Slide 70

Slide 70 text

Jupyterの実行 http://localhost:8080/ にアクセス train.ipynbをopen Run All Cells Grid Search| alpha: 1e-05, score: 0.3974486898518637 Grid Search| alpha: 0.0001, score: 0.3933346694988594 Grid Search| alpha: 0.001, score: 0.4020087564820292 Grid Search| alpha: 100.0, score: 0.6864819640382058 Grid Search| alpha: 0.1, score: 0.43974074906133426 test logloss: 0.40316918447397815 AUC: 0.721722629994545 Accuracy: 0.8375670929283435 70/111 終わったらコンテナを終了

Slide 71

Slide 71 text

実験管理

Slide 72

Slide 72 text

実験管理とは Experiment management in the context of machine learning is a process of tracking experiment metadata like: ● code versions, ● data versions, ● hyperparameters, ● environment, ● metrics, organizing them in a meaningful way and making them available to access and collaborate on within your organization . In the next sections, you will see exactly what that means with examples and implementations. https://neptune.ai/blog/experiment-management 72/111

Slide 73

Slide 73 text

よくあるユースケース1 先輩が残したコード 再現実験 動かない 研究室にて先輩の研究の引き継ぎ 73/111

Slide 74

Slide 74 text

よくあるユースケース2 PoC 設定が見つからない PoCの結果と実験設定の提示 受注 PoCの実験設定教えて! 74/111

Slide 75

Slide 75 text

実験管理ができていない場合 https://speakerdeck.com/nsakki55/mlops-basic?slide=36 実験基盤が整備されていないと ○ 再現性の低下 ○ バグの頻発 ○ データサイエンティストのサイロ化 75/111

Slide 76

Slide 76 text

実験の何を管理するのか ● インフラ ○ 実験に使用したマシン・ソフトウェアバージョン ● コードのバージョン ○ どのような実験コードを使用したか ● データの設定 ○ データをどのような設定で行ったか ● モデルのパラメータ ○ ハイパーパラメータの実験設定 ● メトリクス ○ モデルの評価 76/111

Slide 77

Slide 77 text

MLflowとは A Tool for Managing the Machine Learning Lifecycle MLflow is an open-source platform , purpose-built to assist machine learning practitioners and teams in handling the complexities of the machine learning process. MLflow focuses on the full lifecycle for machine learning projects , ensuring that each phase is manageable , traceable , and reproducible . https://mlflow.org/docs/latest/index.html 77/111

Slide 78

Slide 78 text

Docker Compose Docker Compose is a tool for defining and running multi-container applications . It is the key to unlocking a streamlined and efficient development and deployment experience. Compose simplifies the control of your entire application stack, making it easy to manage services, networks, and volumes in a single , comprehensible YAML configuration file. Then, with a single command, you create and start all the services from your configuration file. https://docs.docker.com/compose/ 78/111

Slide 79

Slide 79 text

Why Docker Compose? 複数のContainer(application, DB, etc..)を立てる時、一つずつdocker runするのは大変 docker composeを使うと 単一のYAMLで複数のコンテナアプリケーションの定義と管理が可能 Docker: $ docker run ~~ Docker Compose:(compose.yamlがあるディレクトリで) $ docker compose up 79/111

Slide 80

Slide 80 text

compose.yamlの作成 services: jupyter: container_name: jupyter_container build: context: . dockerfile: Dockerfile volumes: - ./:/app ports: - 8080:8080 command: jupyter lab --port 8080 --ip=0.0.0.0 --no-browser --allow-root --NotebookApp.token='' restart: always tty: true environment: - TZ=Asia/Tokyo mlflow: container_name: mlflow_container build: context: . dockerfile: Dockerfile volumes: - ./mlflow:/app/.mlflow depends_on: - jupyter ports: - 5000:5000 command: mlflow server --backend-store-uri /app/.mlflow --host 0.0.0.0 --port 5000 restart: always tty: true environment: - TZ=Asia/Tokyo $ $EDITOR compose.yaml 80/111 $ cd path/to/2-docker-mlflow ディレクトリ移動 compose.yaml

Slide 81

Slide 81 text

compose.yamlの作成 services: jupyter: container_name: jupyter_container build: context: . dockerfile: Dockerfile volumes: - ./:/app ports: - 8080:8080 command: jupyter lab --port 8080 --ip=0.0.0.0 --no-browser --allow-root --NotebookApp.token='' restart: always tty: true environment: - TZ=Asia/Tokyo mlflow: container_name: mlflow_container build: context: . dockerfile: Dockerfile volumes: - ./mlflow:/app/.mlflow depends_on: - jupyter ports: - 5000:5000 command: mlflow server --backend-store-uri /app/.mlflow --host 0.0.0.0 --port 5000 restart: always tty: true environment: - TZ=Asia/Tokyo コンテナごとの定義 81/111

Slide 82

Slide 82 text

compose.yamlの作成 services: jupyter: container_name: jupyter_container build: context: . dockerfile: Dockerfile volumes: - ./:/app ports: - 8080:8080 command: jupyter lab --port 8080 --ip=0.0.0.0 --no-browser --allow-root --NotebookApp.token='' restart: always tty: true environment: - TZ=Asia/Tokyo mlflow: container_name: mlflow_container build: context: . dockerfile: Dockerfile volumes: - ./mlflow:/app/.mlflow depends_on: - jupyter ports: - 5000:5000 command: mlflow server --backend-store-uri /app/.mlflow --host 0.0.0.0 --port 5000 restart: always tty: true environment: - TZ=Asia/Tokyo コンテナ名 82/111

Slide 83

Slide 83 text

compose.yamlの作成 services: jupyter: container_name: jupyter_container build: context: . dockerfile: Dockerfile volumes: - ./:/app ports: - 8080:8080 command: jupyter lab --port 8080 --ip=0.0.0.0 --no-browser --allow-root --NotebookApp.token='' restart: always tty: true environment: - TZ=Asia/Tokyo mlflow: container_name: mlflow_container build: context: . dockerfile: Dockerfile volumes: - ./mlflow:/app/.mlflow depends_on: - jupyter ports: - 5000:5000 command: mlflow server --backend-store-uri /app/.mlflow --host 0.0.0.0 --port 5000 restart: always tty: true environment: - TZ=Asia/Tokyo ビルド設定 83/111

Slide 84

Slide 84 text

compose.yamlの作成 services: jupyter: container_name: jupyter_container build: context: . dockerfile: Dockerfile volumes: - ./:/app ports: - 8080:8080 command: jupyter lab --port 8080 --ip=0.0.0.0 --no-browser --allow-root --NotebookApp.token='' restart: always tty: true environment: - TZ=Asia/Tokyo mlflow: container_name: mlflow_container build: context: . dockerfile: Dockerfile volumes: - ./mlflow:/app/.mlflow depends_on: - jupyter ports: - 5000:5000 command: mlflow server --backend-store-uri /app/.mlflow --host 0.0.0.0 --port 5000 restart: always tty: true environment: - TZ=Asia/Tokyo volumeのsync 84/111

Slide 85

Slide 85 text

compose.yamlの作成 services: jupyter: container_name: jupyter_container build: context: . dockerfile: Dockerfile volumes: - ./:/app ports: - 8080:8080 command: jupyter lab --port 8080 --ip=0.0.0.0 --no-browser --allow-root --NotebookApp.token='' restart: always tty: true environment: - TZ=Asia/Tokyo mlflow: container_name: mlflow_container build: context: . dockerfile: Dockerfile volumes: - ./mlflow:/app/.mlflow depends_on: - jupyter ports: - 5000:5000 command: mlflow server --backend-store-uri /app/.mlflow --host 0.0.0.0 --port 5000 restart: always tty: true environment: - TZ=Asia/Tokyo コンテナの立ち上げ順序の依存の設定 85/111

Slide 86

Slide 86 text

compose.yamlの作成 services: jupyter: container_name: jupyter_container build: context: . dockerfile: Dockerfile volumes: - ./:/app ports: - 8080:8080 command: jupyter lab --port 8080 --ip=0.0.0.0 --no-browser --allow-root --NotebookApp.token='' restart: always tty: true environment: - TZ=Asia/Tokyo mlflow: container_name: mlflow_container build: context: . dockerfile: Dockerfile volumes: - ./mlflow:/app/.mlflow depends_on: - jupyter ports: - 5000:5000 command: mlflow server --backend-store-uri /app/.mlflow --host 0.0.0.0 --port 5000 restart: always tty: true environment: - TZ=Asia/Tokyo ポートフォワード 86/111

Slide 87

Slide 87 text

compose.yamlの作成 services: jupyter: container_name: jupyter_container build: context: . dockerfile: Dockerfile volumes: - ./:/app ports: - 8080:8080 command: jupyter lab --port 8080 --ip=0.0.0.0 --no-browser --allow-root --NotebookApp.token='' restart: always tty: true environment: - TZ=Asia/Tokyo mlflow: container_name: mlflow_container build: context: . dockerfile: Dockerfile volumes: - ./mlflow:/app/.mlflow depends_on: - jupyter ports: - 5000:5000 command: mlflow server --backend-store-uri /app/.mlflow --host 0.0.0.0 --port 5000 restart: always tty: true environment: - TZ=Asia/Tokyo コンテナの実行コマンド もし、Dockerfileにもコマンド書かれている時は compose.yamlのコマンドで上書きされる 87/111

Slide 88

Slide 88 text

compose.yamlの作成 services: jupyter: container_name: jupyter_container build: context: . dockerfile: Dockerfile volumes: - ./:/app ports: - 8080:8080 command: jupyter lab --port 8080 --ip=0.0.0.0 --no-browser --allow-root --NotebookApp.token='' restart: always tty: true environment: - TZ=Asia/Tokyo mlflow: container_name: mlflow_container build: context: . dockerfile: Dockerfile volumes: - ./mlflow:/app/.mlflow depends_on: - jupyter ports: - 5000:5000 command: mlflow server --backend-store-uri /app/.mlflow --host 0.0.0.0 --port 5000 restart: always tty: true environment: - TZ=Asia/Tokyo リスタート設定と標準出力設定 88/111

Slide 89

Slide 89 text

compose.yamlの作成 services: jupyter: container_name: jupyter_container build: context: . dockerfile: Dockerfile volumes: - ./:/app ports: - 8080:8080 command: jupyter lab --port 8080 --ip=0.0.0.0 --no-browser --allow-root --NotebookApp.token='' restart: always tty: true environment: - TZ=Asia/Tokyo mlflow: container_name: mlflow_container build: context: . dockerfile: Dockerfile volumes: - ./mlflow:/app/.mlflow depends_on: - jupyter ports: - 5000:5000 command: mlflow server --backend-store-uri /app/.mlflow --host 0.0.0.0 --port 5000 restart: always tty: true environment: - TZ=Asia/Tokyo 環境変数 89/111

Slide 90

Slide 90 text

MLflowの立ち上げ 90/111 $ docker compose up --build http://localhost:5000/ にアクセス 強制的にbuild ※ もし、portが被って立ち上がらない場合 ポート: 5000 -> 5001

Slide 91

Slide 91 text

Jupyter Labの立ち上げ 先ほどのdocker composeでjupyter serverも一緒に立ち上がる http://0.0.0.0:8080/ にアクセス 91/111

Slide 92

Slide 92 text

実装の追加 import pandas as pd from sklearn.linear_model import SGDClassifier from sklearn.feature_extraction import FeatureHasher from sklearn.model_selection import train_test_split import warnings from sklearn import metrics warnings.filterwarnings('ignore') ### 追加 ### import mlflow import mlflow.sklearn from mlflow.models.signature import infer_signature mlflow.set_tracking_uri("http://mlflow_container:5000") mlflow.set_experiment("ca24-mlops-introduction") 92/111 train.ipynb(1の実装とほぼ同じ)への追加

Slide 93

Slide 93 text

実装の追加 train.ipynb(1の実装とほぼ同じ)への追加 import pandas as pd from sklearn.linear_model import SGDClassifier from sklearn.feature_extraction import FeatureHasher from sklearn.model_selection import train_test_split import warnings from sklearn import metrics warnings.filterwarnings('ignore') ### 追加 ### import mlflow import mlflow.sklearn from mlflow.models.signature import infer_signature mlflow.set_tracking_uri("http://mlflow_container:5000") mlflow.set_experiment("ca24-mlops-introduction") MLflowライブラリのインポート 93/111

Slide 94

Slide 94 text

実装の追加 train.ipynb(1の実装とほぼ同じ)への追加 import pandas as pd from sklearn.linear_model import SGDClassifier from sklearn.feature_extraction import FeatureHasher from sklearn.model_selection import train_test_split import warnings from sklearn import metrics warnings.filterwarnings('ignore') ### 追加 ### import mlflow import mlflow.sklearn from mlflow.models.signature import infer_signature mlflow.set_tracking_uri("http://mlflow_container:5000") mlflow.set_experiment("ca24-mlops-introduction") 実験名をつける(なんでもOK) MLflowのURIを指定 Docker Composeで同じネットワークにたてた場合、 http://{container_name}:{port}でアクセス可能 mlflow: container_name: mlflow_container build: context: . dockerfile: Dockerfile : ports: - 5000:5000 : 94/111

Slide 95

Slide 95 text

ハイパラチューニング def grid_search(X_train, y_train, X_valid, y_valid): best_score = 1e10 best_alpha = 100 for alpha in [1e-5, 1e-4, 1e-3, 1e-2, 1e-1]: : : if best_score > valid_score: best_score = valid_score best_alpha = alpha ### 追加 ### # Log parameter and metrics with mlflow.start_run(run_name=f"Grid Search alpha={alpha}"): mlflow.log_param("alpha", alpha) mlflow.log_metric("train_score", train_score) mlflow.log_metric("valid_score", valid_score) mlflow.log_param("train_size", X_train.shape[0]) mlflow.log_param("valid_size", X_valid.shape[0]) return best_alpha ハイパラチューニングのメトリクスを送信 95/111

Slide 96

Slide 96 text

ハイパラチューニング def grid_search(X_train, y_train, X_valid, y_valid): best_score = 1e10 best_alpha = 100 for alpha in [1e-5, 1e-4, 1e-3, 1e-2, 1e-1]: : : if best_score > valid_score: best_score = valid_score best_alpha = alpha ### 追加 ### # Log parameter and metrics with mlflow.start_run(run_name=f"Grid Search alpha={alpha}"): mlflow.log_param("alpha", alpha) mlflow.log_metric("train_score", train_score) mlflow.log_metric("valid_score", valid_score) mlflow.log_param("train_size", X_train.shape[0]) mlflow.log_param("valid_size", X_valid.shape[0]) return best_alpha ハイパラチューニングのメトリクスを送信 新たな実行の開始 この中で送られるメトリクスは全て同一runとして 紐づけられる 96/111

Slide 97

Slide 97 text

ハイパラチューニング def grid_search(X_train, y_train, X_valid, y_valid): best_score = 1e10 best_alpha = 100 for alpha in [1e-5, 1e-4, 1e-3, 1e-2, 1e-1]: : : if best_score > valid_score: best_score = valid_score best_alpha = alpha ### 追加 ### # Log parameter and metrics with mlflow.start_run(run_name=f"Grid Search alpha={alpha}"): mlflow.log_param("alpha", alpha) mlflow.log_metric("train_score", train_score) mlflow.log_metric("valid_score", valid_score) mlflow.log_param("train_size", X_train.shape[0]) mlflow.log_param("valid_size", X_valid.shape[0]) return best_alpha ハイパラチューニングのメトリクスを送信 メトリクスの送信 パラメータはパラメータとして、 メトリクスはメトリクスとして送信 ● alpha ● trainのlogloss ● validのlogloss ● trainデータのサイズ ● validデータのサイズ 97/111

Slide 98

Slide 98 text

最終結果の送信 best_alpha = grid_search(X_train_preprocessed, y_train, X_valid_preprocessed, y_valid) : : print("test logloss: {}".format(logloss)) print("AUC: {}".format(auc)) print("Accuracy: {}".format(accuracy)) ### 追加 ### with mlflow.start_run(run_name="Model Evaluation") as run: mlflow.log_metric("test_logloss", logloss) mlflow.log_metric("AUC", auc) mlflow.log_metric("Accuracy", accuracy) mlflow.log_param("best_alpha", best_alpha) run_id = run.info.run_id sig = infer_signature(X_train_preprocessed, best_model.predict(X_train_preprocessed)) mlflow.sklearn.log_model(best_model, "sgd_classifier", signature=sig, input_example=X_test_preprocessed[0]) mlflow.register_model(f"runs:/{run_id}/sgd_classifier", "sgd_classifier") 最終結果のメトリクスを送信 98/111

Slide 99

Slide 99 text

最終結果の送信 best_alpha = grid_search(X_train_preprocessed, y_train, X_valid_preprocessed, y_valid) : : print("test logloss: {}".format(logloss)) print("AUC: {}".format(auc)) print("Accuracy: {}".format(accuracy)) ### 追加 ### with mlflow.start_run(run_name="Model Evaluation") as run: mlflow.log_metric("test_logloss", logloss) mlflow.log_metric("AUC", auc) mlflow.log_metric("Accuracy", accuracy) mlflow.log_param("best_alpha", best_alpha) run_id = run.info.run_id sig = infer_signature(X_train_preprocessed, best_model.predict(X_train_preprocessed)) mlflow.sklearn.log_model(best_model, "sgd_classifier", signature=sig, input_example=X_test_preprocessed[0]) mlflow.register_model(f"runs:/{run_id}/sgd_classifier", "sgd_classifier") 最終結果のメトリクスを送信 新たな実行の開始 99/111

Slide 100

Slide 100 text

最終結果の送信 best_alpha = grid_search(X_train_preprocessed, y_train, X_valid_preprocessed, y_valid) : : print("test logloss: {}".format(logloss)) print("AUC: {}".format(auc)) print("Accuracy: {}".format(accuracy)) ### 追加 ### with mlflow.start_run(run_name="Model Evaluation") as run: mlflow.log_metric("test_logloss", logloss) mlflow.log_metric("AUC", auc) mlflow.log_metric("Accuracy", accuracy) mlflow.log_param("best_alpha", best_alpha) run_id = run.info.run_id sig = infer_signature(X_train_preprocessed, best_model.predict(X_train_preprocessed)) mlflow.sklearn.log_model(best_model, "sgd_classifier", signature=sig, input_example=X_test_preprocessed[0]) mlflow.register_model(f"runs:/{run_id}/sgd_classifier", "sgd_classifier") 最終結果のメトリクスを送信 メトリクスの送信 パラメータはパラメータとして、 メトリクスはメトリクスとして送信 ● best_alpha ● testのlogloss ● AUC ● Accuracy 100/111

Slide 101

Slide 101 text

最終結果の送信 best_alpha = grid_search(X_train_preprocessed, y_train, X_valid_preprocessed, y_valid) : : print("test logloss: {}".format(logloss)) print("AUC: {}".format(auc)) print("Accuracy: {}".format(accuracy)) ### 追加 ### with mlflow.start_run(run_name="Model Evaluation") as run: mlflow.log_metric("test_logloss", logloss) mlflow.log_metric("AUC", auc) mlflow.log_metric("Accuracy", accuracy) mlflow.log_param("best_alpha", best_alpha) run_id = run.info.run_id sig = infer_signature(X_train_preprocessed, best_model.predict(X_train_preprocessed)) mlflow.sklearn.log_model(best_model, "sgd_classifier", signature=sig, input_example=X_test_preprocessed[0]) mlflow.register_model(f"runs:/{run_id}/sgd_classifier", "sgd_classifier") 最終結果のメトリクスを送信 モデルの登録 学習済みモデルをインターフェイスとともに保存 101/111

Slide 102

Slide 102 text

結果の確認 http://localhost:5000にアクセス Experiments Notebook指定した名前で作成 Run Name Runごとのメトリクスが表示 102/111

Slide 103

Slide 103 text

モデルのメトリクス 103/111

Slide 104

Slide 104 text

ハイパーパラメータのメトリクス 104/111

Slide 105

Slide 105 text

モデルの登録 105/111

Slide 106

Slide 106 text

Tips: 他の用途 106/109

Slide 107

Slide 107 text

最後に

Slide 108

Slide 108 text

コンテナ技術 コンテナ技術は現代のクラウドアプリケーションのスタンダード技術 依存を閉じこめ再配布可能な形で環境を作る リリースまでを意識して、Portableな環境を作る 少しずつ自身の環境を運用可能な状態に移行していきましょう 108/111

Slide 109

Slide 109 text

実験管理 MLflowを使いこなして欲しいわけではなく、実験管理の一例を示した 他の実験管理ツール(Weights & Biasesなど)もあるので、自分たちにあった ものを選択する 実験管理し、共有可能な実験をする ※ MLflowには他にもいろんな機能があるので気になる方は色々見てみてください 109/111

Slide 110

Slide 110 text

110/111 他の部分はこちらを参照 実験基盤 学習パイプライン 推論サーバ モデルのバージョン管理 データのバージョン管理 CI/CD 監視 継続的な学習 データ基盤

Slide 111

Slide 111 text

参考 ● https://speakerdeck.com/szma5a/container-for-mlops ● https://speakerdeck.com/chck/container-for-mlops ● https://speakerdeck.com/nsakki55/mlops-basic ● https://future-architect.github.io/articles/20240726a/ 111/111