Mímisbrunnr知恵の泉

← MLOps 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:MLOpsとMLライフサイクル | 関連:学習データの管理とデータバージョニング

要点(BLUF)

1. モデルは「3つの入力」の関数

モデル = f(コード, データ, 環境, 乱数シード)

研究で「結果が再現しない」とき、犯人はたいていこの4つのどれかが固定されていないことです。MLOps では、この関数の全入力をバージョン管理下に置くことを再現性と呼びます。コードだけ Git に入れても、データが上書きされていたり、ライブラリのマイナー更新で挙動が変わっていれば再現しません。

2. それぞれの固定手段

入力固定手段具体例
コードバージョン管理Git のコミットハッシュ
データデータバージョニング内容ハッシュ、スナップショット、DVC/lakeFS等 → 学習データの管理とデータバージョニング
環境依存の固定requirements.txt+ロックファイル、Dockerイメージタグ → モデルのパッケージングとコンテナ化
乱数シード固定np.random.default_rng(seed)、フレームワークのseed設定
構成設定管理ハイパーパラメータを設定ファイルに → ハイパーパラメータ管理と再現

データバージョニングの実装そのもの(DVC・lakeFS・データレイク)は学習データの管理とデータバージョニングとデータエンジニアリング分野へ。ここでは「学習を再現するには3つ全部のバージョンが要る」という MLOps の原則を押さえます。

3. 図解:再現可能な学習実行

flowchart LR
  A["コード(Gitハッシュ)"] --> D["学習実行"]
  B["データ(内容ハッシュ)"] --> D
  C["環境(イメージタグ)"] --> D
  S["乱数シード"] --> D
  D --> M["モデル成果物"]
  M --> R["メタデータに3つのバージョンを記録"]

成果物 M に「どのコード・データ・環境・シードで生まれたか」を刻む——これがあれば、半年後でも同じモデルを再現でき、障害時に「いつ何が変わったか」を追えます。

4. 動く最小例:データのハッシュ固定で同一モデルを再現する

データを内容ハッシュで識別し、同じハッシュなら同じモデルが再現することを確認します。

import hashlib
import numpy as np
from sklearn.tree import DecisionTreeClassifier

def data_hash(X, y):
    h = hashlib.sha256()
    h.update(np.ascontiguousarray(X).tobytes())
    h.update(np.ascontiguousarray(y).tobytes())
    return h.hexdigest()[:12]

def make_dataset(seed):
    rng = np.random.default_rng(seed)
    X = rng.normal(0, 1, (200, 4))
    y = (X[:, 0] + X[:, 1] > 0).astype(int)
    return X, y

def fingerprint(X, y, seed=42):
    model = DecisionTreeClassifier(random_state=seed).fit(X, y)
    # 木の構造を指紋化(再現したか判定)
    return hashlib.sha256(model.tree_.threshold.tobytes()).hexdigest()[:12]

X1, y1 = make_dataset(seed=0)
X2, y2 = make_dataset(seed=0)   # 同じデータ
X3, y3 = make_dataset(seed=1)   # 違うデータ

print(f"データハッシュ A = {data_hash(X1, y1)}")
print(f"データハッシュ B = {data_hash(X2, y2)}  (同一データ)")
print(f"データハッシュ C = {data_hash(X3, y3)}  (別データ)")
print(f"モデル指紋 A = {fingerprint(X1, y1)}")
print(f"モデル指紋 B = {fingerprint(X2, y2)}")
print(f"モデル指紋 C = {fingerprint(X3, y3)}")
print(f"A と B は同一モデル? {fingerprint(X1, y1) == fingerprint(X2, y2)}")
print(f"A と C は同一モデル? {fingerprint(X1, y1) == fingerprint(X3, y3)}")

出力:

データハッシュ A = 7705ee9fb80b
データハッシュ B = 7705ee9fb80b  (同一データ)
データハッシュ C = 1bfa3f8b78fd  (別データ)
モデル指紋 A = fa5dc805c4d8
モデル指紋 B = fa5dc805c4d8
モデル指紋 C = c7df2c1287de
A と B は同一モデル? True
A と C は同一モデル? False

出力の意味:同じ内容のデータはハッシュが一致し、結果として学習モデル(木構造の指紋)も完全一致しました。データが変わればハッシュもモデルも変わります。つまりデータのハッシュを記録しておけば、後から「このモデルはどのデータで作られたか」を厳密に照合でき、再現性を機械的に検証できるということです。

5. 運用の勘所

なぜそうするのか

再現性は学術的な潔癖さのためではなく、運用の生命線です。本番モデルが壊れたとき、「直前と何が変わったか」を特定できなければ復旧できません。コード・データ・環境を固定しておけば、障害時に過去の正常なモデルへ即座にロールバックでき、再学習の比較対象(ベースライン)も確保できます。

⚠️ よくある落とし穴

対応 lab

関連ノート