🎓 レベル:標準 | 重要度:A(必須)
📎 前提:再現性とバージョニング | 関連:データエンジニアリング 全体目次(データエンジニアリング)
要点(BLUF)
- 学習データはコードと同じくバージョン管理の対象です。「どのデータで学習したか」を後から厳密に特定できなければ、再現もロールバックも障害解析もできません。
- 鍵は内容ベースの識別:ファイル名や更新日時でなく、中身のハッシュでデータを一意に識別します(同じ中身=同じID、変わればIDも変わる)。
- データにはメタデータ(スキーマ・統計・系譜=どこから来たか)を添え、コードの Git コミットとデータのバージョンを紐付けて、学習実行を一意に再現できるようにします。汎用のデータレイク・ETL基盤はデータエンジニアリング分野へ。
1. なぜデータを版管理するのか
ML の再現性は再現性とバージョニングで見たとおりコード・データ・環境の三位一体です。このうちデータは最も管理が雑になりがちです。train_v2.csv を上書きしてしまえば、過去のモデルがどのデータで作られたかは永遠に失われます。データバージョニングは「学習に使ったデータの瞬間を凍結保存する」仕組みです。
2. 内容ベースの識別(content-addressable)
ファイル名は嘘をつきます(finalが最終でない)。信頼できるのは中身そのもの。中身のハッシュを ID にすると:
- 同じ中身は必ず同じ ID → 重複を自動排除できる
- 1バイトでも変われば ID が変わる → 改変を検知できる
- ID で「このモデルはこのデータ」と機械照合できる
これは Git がファイルをハッシュで管理するのと同じ発想で、DVC・lakeFS などのデータバージョニングツールの基礎です。
3. 図解:データレジストリと学習の紐付け
flowchart LR S["生データソース"] --> H["内容ハッシュを計算"] H --> R["データレジストリ(ハッシュとメタデータ)"] G["コード(Gitコミット)"] --> T["学習実行"] R --> T T --> M["モデル+出自(コード版とデータ版)"]
学習実行にコード版(Gitハッシュ)とデータ版(内容ハッシュ)の両方を入力として記録すれば、モデルから「いつのコードといつのデータで作られたか」を逆引きできます。
4. 動く最小例:ハッシュベースのデータレジストリ
データを内容ハッシュで登録し、メタデータを添え、同一データの再登録を検知する最小レジストリです。
import hashlib
import numpy as np
class DataRegistry:
def __init__(self):
self.store = {} # hash -> metadata
@staticmethod
def _hash(arr):
return hashlib.sha256(np.ascontiguousarray(arr).tobytes()).hexdigest()[:12]
def register(self, name, arr):
h = self._hash(arr)
if h in self.store:
return h, "既存(同一内容)"
self.store[h] = {
"name": name,
"shape": arr.shape,
"mean": round(float(arr.mean()), 4),
"n_null": int(np.isnan(arr).sum()),
}
return h, "新規登録"
rng = np.random.default_rng(0)
v1 = rng.normal(0, 1, (1000, 5))
v1_copy = v1.copy() # 同じ中身
v2 = v1.copy(); v2[0, 0] += 0.5 # 1要素だけ変更
reg = DataRegistry()
h1, s1 = reg.register("train", v1)
h1c, s1c = reg.register("train", v1_copy)
h2, s2 = reg.register("train", v2)
print(f"v1 : hash={h1} -> {s1}")
print(f"v1_copy : hash={h1c} -> {s1c}")
print(f"v2 : hash={h2} -> {s2}")
print(f"v1とv2は同一データ? {h1 == h2}")
print(f"レジストリ登録数 : {len(reg.store)}")
print(f"v1のメタデータ : {reg.store[h1]}")
出力:
v1 : hash=7a82c1a6b301 -> 新規登録
v1_copy : hash=7a82c1a6b301 -> 既存(同一内容)
v2 : hash=d180a6268cd5 -> 新規登録
v1とv2は同一データ? False
レジストリ登録数 : 2
v1のメタデータ : {'name': 'train', 'shape': (1000, 5), 'mean': -0.0045, 'n_null': 0}
出力の意味:同一内容(v1 と v1_copy)はハッシュが一致して重複登録されず、1要素だけ変えた v2 は別 ID として登録されました。これで「このモデルはハッシュ 7a82… のデータで学習した」と機械的に固定でき、データの取り違えや知らぬ間の改変を検知できます。メタデータ(形状・平均・欠損数)を添えることで、後からデータの素性も追えます。
5. 運用の勘所
- 大きなデータは実体とポインタを分ける:レジストリにはハッシュとメタデータ(軽量)を、実体はオブジェクトストレージに(DVC/lakeFS の発想)。
- 系譜(lineage)を記録する:そのデータがどのソース・どの変換から来たかを残す。障害時に汚染源を遡れる。
- スキーマと統計を毎回検証する:登録時にスキーマ・分布をチェックし、想定外のデータを早期に弾く(本番モデルの監視の入力監視と同じ発想)。
- PII に注意:個人情報を含むデータの版管理は保持期間・アクセス制御とセットで設計する。
なぜそうするのか
データを版管理しない最大の代償は「障害が起きても原因を切り分けられない」ことです。本番モデルが急に劣化したとき、データが変わったのかコードが変わったのか分からなければ復旧できません。データに不変の ID を与えておけば、「直前まで正常だったデータ版」へ即座に戻れ、再学習の比較基準も保てます。
⚠️ よくある落とし穴
- ファイル名・タイムスタンプで管理する:
data_final.csvは再現性ゼロ。内容ハッシュで識別する。 - データを上書きする:過去版を失えばロールバック不能。追記・スナップショット方式にする。
- メタデータを残さない:ハッシュだけでは中身が分からない。スキーマ・統計・系譜を添える。
- 汎用データ基盤の責務をここに抱え込む:ETL・データレイク・カタログはデータエンジニアリング分野へ。ここは「ML学習との紐付け」に集中する。
対応 lab
- なし(概念ノート)。ハッシュレジストリは本文 §4 に同梱。
関連ノート
- 再現性とバージョニング(三位一体の土台)
- 特徴量エンジニアリングのパイプライン化(次のステージ)
- 学習推論スキューの防止(データ供給の一貫性)
- 本番モデルの監視(入力データの監視)
- データエンジニアリング 全体目次(汎用データ基盤)
- 第2章 データと特徴量の基盤 目次
- MLOps・AI基盤 全体目次