MLflowとJupyter Notebookを活用した機械学習環境構築

## はじめに
MLflowの環境構築はできましたが、機械学習関連の開発はNotebook上でインタラクティブに進める方が便利です。私もNotebookに慣れているため、今回は **MLflow＋Jupyter Notebook** の環境を構築しました。

---

## そもそも何が良いの？

MLflowとJupyter Notebookの統合により、以下のようなメリットがあります。

### 迅速なプロトタイピングとトラッキングの連携
**Jupyter Notebook** はインタラクティブなデータ解析やプロトタイピングに適しています。Notebookで実験しながら、**MLflow** のトラッキング機能で各実験のパラメータやメトリクスをリアルタイムに記録し、データやモデルの変化をすぐに確認することでフィードバックサイクルを加速できます。

### 容易なモデルのバージョン管理
Notebookで実験したモデルをMLflowに登録することで、バージョン管理が簡単になります。再トレーニングやリリース前のモデル比較が容易になり、生成された複数のモデルから最適なものを選ぶことができます。

### 自動化ワークフローへの統合が簡単
MLflowのトラッキング、モデルレジストリ、サービング機能により、Notebookで構築したモデルをそのままワークフローや自動化パイプラインに組み込むことが可能です。Notebookのプロトタイプがそのまま再現性のある形で本番運用できます。

### デプロイと評価のための一貫した環境
Jupyter Notebookでの開発とMLflowの統合により、デプロイ前にNotebookで行ったモデル評価をMLflowに記録・保存できます。再評価や他チームからのフィードバックが必要な場合にも過去の実験結果を活用でき、開発者間で情報を共有しやすくなります。

### 柔軟な可視化と解析
Notebook上で可視化ツールやライブラリを活用し、実験結果やログをMLflowに記録できます。これにより、実験のパラメータや評価指標の変動を簡単に可視化し、改善ポイントの発見やチームでの共有が容易になります。

---

## 実際のソース

### ディレクトリ構成

```plaintext
/mlops_project
│
├── docker-compose.yml  # 各コンテナを統合するDocker Composeファイル
│
├── /jupyter
│   ├── Dockerfile  # Jupyter Notebook用のDockerfile
│   ├── requirements_jupyter.txt  # Jupyter Notebook用の依存ライブラリ
│   ├── /notebooks  # Jupyterで使うノートブック
│   └── /data  # データセット（オプション）
│
├── /mlflow
│   ├── Dockerfile  # MLflow用のDockerfile
│   ├── requirements_mlflow.txt  # MLflow用の依存ライブラリ
│   ├── /mlruns  # MLflowのラン履歴保存用ディレクトリ
│   ├── /artifacts  # モデルのアーティファクト保存用ディレクトリ
│   ├── MLproject  # MLflowプロジェクト設定ファイル
│   └── conda.yaml  # MLflowプロジェクトのConda環境設定ファイル
│
├── /postgres
```

**ポイント**：機能ごとにコンテナを分けて管理することで、環境の分離やメンテナンスが簡単になります。

---

### docker-compose.yml
```yaml
version: '3.8'

services:
  jupyter:
    build: ./jupyter
    ports:
      - "8888:8888"
    environment:
      JUPYTER_ENABLE_LAB: "yes"
      MLFLOW_TRACKING_URI: http://mlflow:5000
    volumes:
      - ./jupyter/notebooks:/home/jovyan/work  # Jupyter用のノートブックの永続化
      - ./shared/data:/home/jovyan/data  # その他のデータファイルの永続化
    command: start-notebook.sh --NotebookApp.token=''  # トークン無効化
    depends_on:
      - mlflow
    networks:
      - mlops_network

  mlflow:
    build: ./mlflow
    ports:
      - "5002:5000"  # MLflowのポート
    volumes:
      - ./mlruns:/mlflow/mlruns  # MLflowのランやアーティファクトの永続化
      - ./mlartifacts:/mlflow/mlartifacts  # アーティファクトディレクトリの永続化
    environment:
      BACKEND_STORE_URI: postgresql://mlflow:mlflow_pass@postgres/mlflow_db
      ARTIFACT_ROOT: /mlflow/mlruns
      MLFLOW_TRACKING_URI: http://mlflow:5000
    depends_on:
      - postgres
    networks:
      - mlops_network

  postgres:
    image: postgres:13
    environment:
      POSTGRES_USER: mlflow
      POSTGRES_PASSWORD: mlflow_pass
      POSTGRES_DB: mlflow_db
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    networks:
      - mlops_network

networks:
  mlops_network:
    driver: bridge
```

**ポイント**：
- 各サービス（Jupyter, MLflow, PostgreSQL）を個別のコンテナで管理することで、環境の独立性とスケーラビリティが向上します。
- `mlops_network`でコンテナ同士を接続し、ネットワーク分離を管理します。

---

### jupyter/Dockerfile
```Dockerfile
FROM jupyter/scipy-notebook

USER root

# 必要なライブラリをインストール
COPY requirements_jupyter.txt /tmp/
RUN pip install --no-cache-dir -r /tmp/requirements_jupyter.txt

USER $NB_UID
```

**ポイント**：  
Jupyter Notebook環境に必要なライブラリをインストールしています。

---

### mlflow/Dockerfile
```Dockerfile
# ベースイメージにMinicondaを使用
FROM continuumio/miniconda3

# 必要なライブラリをインストール
RUN apt-get update && apt-get install -y \
    libssl-dev \
    libpq-dev \
    gcc \
    python3-dev \
    && apt-get clean

# conda-forgeチャンネルを追加
RUN conda config --add channels conda-forge

# Python環境とMLflow、Jupyter Notebook、その他必要なパッケージをインストール
RUN conda create -n mlflow_jupyter_env python=3.11 mlflow jupyterlab scikit-learn pandas numpy matplotlib seaborn

# 作業ディレクトリを設定
WORKDIR /app

# start.shをコピーして実行権限を付与
COPY start.sh /app/start.sh
RUN chmod +x /app/start.sh

# Conda環境をアクティベートして、MLflowとJupyter Notebookを起動
CMD ["bash", "-c", "source activate mlflow_jupyter_env && /app/start.sh"]
```

**ポイント**：  
Minicondaベースの環境に必要なライブラリをインストールし、MLflowとJupyter Notebookが同時に動作するように設定しています。

---

### mlflow/MLproject
```yaml
name: CaliforniaHousingModel

conda_env: conda.yaml

entry_points:
  main:
    parameters:
      n_estimators: {type: int, default: 100}
      max_depth: {type: int, default: 10}
    command: >
      python your_script.py --n_estimators {n_estimators} --max_depth {max_depth}
```

**ポイント**：  
この`MLproject`ファイルは、MLflowでプロジェクトを実行するための設定です。`entry_points`に指定されたコマンドで、モデルのトレーニングが実行されます。

---

### mlflow/conda.yaml
```yaml
name: california_housing_env
channels:
  - defaults
dependencies:
  - python=3.11.6
  - scikit-learn=1.3.1
  - numpy=1.24.4
  - cloudpickle=3.0.0
  - lz4=4.3.2
  - psutil=5.9.5
  - pyyaml=6.0.1
  - scipy=1.14.1
  - pip
  - pip:
      - boto3
```

**ポイント**：  
`conda.yaml`ファイルはプロジェクトで必要な依存関係を定義しており、環境の再現性を確保します。これにより、同じ環境を他の開発者も再現しやすくなります。

---

## 終わりに
これで環境の構築は完了です。この環境は、データ分析コンペや本番環境でも応用可能で、柔軟なモデル開発と管理に役立ちます。今後、実際のデータ分析やモデル開発についても試して記事にしていきたいと思います。