CI/CD for ML
田中VPoE「学習パイプラインの設計ができた。次はこれをCI/CDに組み込む。MLのCI/CDは通常のソフトウェアとは少し違う。コードだけでなく、データやモデルのテストも含まれる。」
あなた「GitHub Actionsで自動化するんですね。プルリクエストでモデルのテストが走るイメージですか?」
田中VPoE「その通り。コード変更、データ変更、モデル変更のそれぞれでトリガーが異なるのがポイントだ。」
ML CI/CDの特殊性
従来のソフトウェアCI/CDとML CI/CDの違いを理解しましょう。
| 観点 | 通常のCI/CD | ML CI/CD |
|---|---|---|
| テスト対象 | コード | コード + データ + モデル |
| ビルド成果物 | バイナリ/コンテナ | モデルアーティファクト |
| テスト基準 | 全テスト通過 | 全テスト通過 + 精度閾値 |
| トリガー | コード変更 | コード変更 + データ変更 + スケジュール |
| 実行時間 | 数分 | 数分〜数時間 |
ML CI/CDの3つのパイプライン
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ CI │ → │ CT │ → │ CD │
│ Continuous │ │ Continuous │ │ Continuous │
│ Integration │ │ Training │ │ Delivery │
│ │ │ │ │ │
│ コードテスト │ │ モデル学習 │ │ モデルデプロイ│
│ データバリデ │ │ モデル評価 │ │ サービング │
│ ーション │ │ レジストリ │ │ モニタリング │
└─────────────┘ └─────────────┘ └─────────────┘
CI(Continuous Integration)
GitHub Actionsでの実装
# .github/workflows/ml-ci.yml
name: ML CI Pipeline
on:
pull_request:
branches: [main]
paths:
- 'src/**'
- 'tests/**'
- 'config/**'
- 'requirements.txt'
jobs:
code-quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install dependencies
run: pip install -r requirements.txt -r requirements-dev.txt
- name: Lint
run: |
ruff check src/
mypy src/
- name: Unit tests
run: pytest tests/unit/ -v --cov=src --cov-report=xml
data-validation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: pip install -r requirements.txt
- name: Validate training data schema
run: python tests/data/test_schema.py
- name: Check data quality
run: python tests/data/test_quality.py
model-test:
runs-on: ubuntu-latest
needs: [code-quality, data-validation]
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: pip install -r requirements.txt
- name: Model smoke test
run: python tests/model/test_smoke.py
- name: Model performance test (sample data)
run: python tests/model/test_performance.py --sample-size 1000
- name: Comment PR with results
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const results = fs.readFileSync('test_results.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: results
});
データバリデーションテスト
# tests/data/test_schema.py
import pandas as pd
import great_expectations as gx
def test_training_data_schema():
"""学習データのスキーマチェック"""
df = pd.read_parquet("data/training_data.parquet")
# 必須カラムの存在確認
required_columns = [
"customer_id", "age", "tenure_days",
"order_count_30d", "avg_order_amount", "churn"
]
for col in required_columns:
assert col in df.columns, f"Missing column: {col}"
# データ型の確認
assert df["customer_id"].dtype in ["int64", "int32"]
assert df["churn"].dtype in ["int64", "int32"]
assert df["churn"].isin([0, 1]).all()
def test_training_data_quality():
"""学習データの品質チェック"""
df = pd.read_parquet("data/training_data.parquet")
# 最低行数
assert len(df) >= 1000, f"Too few rows: {len(df)}"
# Null率
for col in df.columns:
null_rate = df[col].isnull().mean()
assert null_rate < 0.1, f"{col} null rate: {null_rate:.2%}"
# クラスバランス
churn_rate = df["churn"].mean()
assert 0.05 < churn_rate < 0.95, f"Extreme class imbalance: {churn_rate:.2%}"
CT(Continuous Training)
自動学習パイプライン
# .github/workflows/ml-ct.yml
name: ML CT Pipeline
on:
# スケジュール実行(毎週月曜日)
schedule:
- cron: '0 3 * * 1'
# 手動トリガー
workflow_dispatch:
inputs:
model_name:
description: 'Model to retrain'
required: true
default: 'churn_predictor'
# データ変更トリガー
repository_dispatch:
types: [data-updated]
jobs:
train:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run training pipeline
run: python src/pipelines/training_pipeline.py
env:
MLFLOW_TRACKING_URI: ${{ secrets.MLFLOW_TRACKING_URI }}
- name: Model evaluation gate
run: python src/pipelines/evaluation_gate.py
# 精度が閾値を下回った場合、ここでfail
CD(Continuous Delivery)
モデルデプロイパイプライン
# .github/workflows/ml-cd.yml
name: ML CD Pipeline
on:
# モデルレジストリでProductionに昇格された時
repository_dispatch:
types: [model-promoted]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Pull model from registry
run: |
python -c "
import mlflow
model = mlflow.pyfunc.load_model('models:/churn_predictor@production')
mlflow.pyfunc.save_model(model, 'deploy/model')
"
- name: Build Docker image
run: |
docker build -t churn-predictor:${{ github.sha }} -f Dockerfile.serving .
- name: Push to ECR
run: |
aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_URI
docker tag churn-predictor:${{ github.sha }} $ECR_URI/churn-predictor:${{ github.sha }}
docker push $ECR_URI/churn-predictor:${{ github.sha }}
- name: Deploy to ECS (Canary)
run: |
python scripts/canary_deploy.py \
--image $ECR_URI/churn-predictor:${{ github.sha }} \
--canary-percentage 10
トリガー設計のまとめ
| トリガー | パイプライン | 実行内容 |
|---|---|---|
| PR作成/更新 | CI | コードテスト、データバリデーション、スモークテスト |
| mainマージ | CI + CT | フルテスト + モデル学習 |
| スケジュール(週次) | CT | 定期再学習 |
| データ更新イベント | CT | データ駆動の再学習 |
| モデル昇格イベント | CD | モデルデプロイ |
| ドリフト検知 | CT | 自動再学習 |
まとめ
| 項目 | ポイント |
|---|---|
| ML CI/CDの特殊性 | コード + データ + モデルの3つをテスト |
| CI | コード品質 + データバリデーション + モデルスモークテスト |
| CT | スケジュール/イベント駆動の自動学習 |
| CD | モデルのコンテナ化とデプロイ自動化 |
チェックリスト
- ML CI/CDの3つのパイプライン(CI/CT/CD)を説明できる
- GitHub ActionsでCI パイプラインを定義できる
- データバリデーションテストを書ける
- トリガー設計の使い分けを理解している
次のステップへ
CI/CD for ML を学びました。次は、MLシステム特有のテスト戦略を学びましょう。
推定読了時間:30分