🎓 レベル:標準 | 重要度:A(必須)
📎 前提:特徴量エンジニアリングのパイプライン化 | 関連:データドリフトとコンセプトドリフトの検知
要点(BLUF)
- 学習/推論スキュー(training-serving skew)とは、学習時と推論時で特徴量の作り方・統計量がずれること。「オフラインでは高精度なのに本番で崩れる」最頻出の事故です。
- 主因は3つ:(1)変換ロジックの二重実装(学習はSQL、推論はPython等で別実装)、(2)統計量の取り違え(推論で学習時の平均でなく推論データの平均を使う)、(3)鮮度・欠損挙動の差(学習時と推論時で特徴量の更新タイミングや欠損補完が違う)。
- 防止の本質は変換を1つだけにして学習と推論で共有すること(特徴量エンジニアリングのパイプライン化・特徴量ストア)。ドリフト(データドリフトとコンセプトドリフトの検知)が「時間で入力が変わる」のに対し、スキューは「同じ時点でも学習と推論で違う」問題です。
1. スキューとは何か
モデルは「学習時に見た特徴量の分布」を前提に予測します。推論時に特徴量の作り方がわずかでも違えば、モデルは未知の入力を見せられたのと同じで、精度が落ちます。厄介なのは、オフライン評価(学習データの一部)では完璧に見えること。学習と同じ経路で特徴量を作るので問題が顕在化せず、本番の別経路で初めて崩れます。
2. スキューの3類型
flowchart TB S["学習推論スキュー"] --> A["1 変換ロジックの二重実装"] S --> B["2 統計量の取り違え"] S --> C["3 鮮度と欠損挙動の差"] A --> A1["学習はバッチSQL 推論はAPIで別実装 -> 微妙にずれる"] B --> B1["推論で学習時平均でなく推論データ平均で標準化"] C --> C1["学習は完全な履歴 推論は遅延した最新値や別の欠損補完"]
| 類型 | 何が起きるか | 防ぎ方 |
|---|---|---|
| 二重実装 | 学習と推論で別コードがじわじわずれる | 変換を1つに統一・共有(特徴量エンジニアリングのパイプライン化) |
| 統計量取り違え | 推論で fit し直して別の標準化 | 学習時統計量を保存・再利用(推論は transform のみ) |
| 鮮度・欠損差 | 更新遅延や欠損補完が学習と違う | 特徴量ストアで一貫供給(特徴量ストア) |
3. 動く最小例:スキューが精度を落とすことを実証する
学習と本番を**同じ分布(ドリフトなし)**にして、違いを「推論で変換を共有したか」だけに絞ります。推論経路が標準化を取りこぼす(二重実装で片方が抜ける)と何が起きるかを測ります。
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
rng = np.random.default_rng(0)
# 学習・本番は同じ分布(ドリフトなし)。違いは変換の共有有無だけ
Xtr = rng.normal(5.0, 2.0, (800, 3))
ytr = (Xtr[:, 0] + Xtr[:, 1] - Xtr[:, 2] > 5.0).astype(int)
Xte = rng.normal(5.0, 2.0, (400, 3))
yte = (Xte[:, 0] + Xte[:, 1] - Xte[:, 2] > 5.0).astype(int)
# 学習時の統計量を固定して学習
mu, sd = Xtr.mean(0), Xtr.std(0)
model = LogisticRegression().fit((Xtr - mu) / sd, ytr)
# (A) 正しい:推論も学習時の mu, sd で標準化(変換を共有)
acc_correct = accuracy_score(yte, model.predict((Xte - mu) / sd))
# (B) スキュー:推論経路で標準化を取りこぼし、生の特徴量を渡す
acc_skew = accuracy_score(yte, model.predict(Xte))
print(f"(A) 学習時の変換を共有(正しい) 精度 = {acc_correct:.3f}")
print(f"(B) 推論で標準化を取りこぼし(スキュー)精度 = {acc_skew:.3f}")
print(f"スキューによる精度低下 = {acc_correct - acc_skew:.3f}")
出力:
(A) 学習時の変換を共有(正しい) 精度 = 0.990
(B) 推論で標準化を取りこぼし(スキュー)精度 = 0.578
スキューによる精度低下 = 0.412
出力の意味:学習データと本番データは完全に同じ分布(ドリフトなし)です。それでも、推論経路が標準化変換を取りこぼしただけで精度が 0.990 → 0.578 へ 約41ポイントも崩落しました。モデルは標準化された尺度(平均0・分散1)を前提に係数を学んでいるのに、生のスケール(平均5付近)の入力を渡されたためです。コードの各部分は「正しく」動いていて、ただ学習経路と推論経路で変換が食い違っただけ。オフライン評価では(A)の経路しか通らないので、この崩落は本番で初めて露見します。
4. 運用の勘所
- 変換器をモデルと一体で保存・登録する:
Pipeline(変換器+モデル)を1アーティファクトに(モデルレジストリとモデルのライフサイクル)。 - 学習と推論の特徴量を突き合わせる:同じ入力に対し学習経路と推論経路で特徴量が一致するかを定期テスト(スキュー検査)。
- 欠損・カテゴリ未知値の挙動を固定する:補完値・未知カテゴリの扱いを
fitで決め、推論で再利用する。 - 特徴量ストアで一貫供給する:規模が大きいなら特徴量ストアに時間整合と一貫供給を任せる。
なぜそうするのか
スキューは「コードは正しいのにシステムが間違う」典型で、テストをすり抜けやすい最危険の事故です。防止策がすべて「変換を1つにして共有する」に集約されるのは、ずれの原因が常に「学習用と推論用で別の実体を使ったこと」だからです。実体を1つに保てば、ずれる物理的余地が消えます。
⚠️ よくある落とし穴
- オフライン評価だけ見て安心する:オフラインは学習経路しか通らずスキューが見えない。本番経路でのテストが必須。
- 推論で変換を取りこぼす・
fitし直す:推論経路が学習時の変換を共有しないと崩落する(§3)。学習時の変換器・統計量をそのまま再利用する。 - 学習はSQL・推論はアプリで特徴量を別実装する:必ずじわじわずれる。共有変換にする。
- ドリフトと混同する:ドリフトは時間で入力が変わること(データドリフトとコンセプトドリフトの検知)、スキューは同時点で学習と推論が食い違うこと。対処が違う。
対応 lab
- なし(概念ノート)。スキューの精度影響は本文 §3 で実証済み。
関連ノート
- 特徴量エンジニアリングのパイプライン化(共有変換が防止の核)
- 特徴量ストア(一貫供給で構造的に防ぐ)
- モデルレジストリとモデルのライフサイクル(変換器ごと登録)
- データドリフトとコンセプトドリフトの検知(時間方向の変化)
- 第2章 データと特徴量の基盤 目次
- MLOps・AI基盤 全体目次