ひとことで言うと
汎化誤差(generalization error)は、訓練に使っていない新しい入力に対する損失の期待値です。データ生成分布 に従う について、
と定義されます。 は原理的に手に入らないので、この値そのものは計算できません。 測れるのは、手元の有限サンプルで計算した訓練誤差やテスト誤差だけです。
模試の成績と本番の実力の関係に近いです。本番の実力( 全体での期待損失)は誰にも観測できません。観測できるのは特定の模試(有限サンプル)の点数だけで、しかもその模試で解いた問題を復習して同じ模試を再受験すれば点は上がりますが、それは実力が上がった証拠にはなりません。
なぜ必要か
訓練誤差(訓練集合上の平均損失)は、モデル選択の基準として使えません。 モデルは訓練誤差を下げるように選ばれるため、訓練誤差はモデルの実力を系統的に良く見せます。この「良く見せる度合い」が大きいほど、実運用に出したときの性能とのズレが大きくなります。
問題は、知りたいのは未知データ上の性能なのに、手元にあるのは既知データだけという非対称です。
| 量 | 何を使って計算するか | モデル選択に使われたか |
|---|---|---|
| 訓練誤差 | 学習に使った訓練集合 | 使われた(だから下に偏る) |
| テスト誤差 | 学習に使っていないテスト集合 | 使われていない |
| 汎化誤差 | 全体(観測不能) | — |
この非対称を扱う枠組みが必要で、それが i.i.d. 仮定とテスト誤差による推定です。
仕組み
i.i.d. 仮定とテスト誤差の不偏性
訓練集合とテスト集合が、互いに独立に、同一の分布 から生成されたと仮定します(i.i.d. 仮定)。この仮定のもとで、あるモデル を固定してその期待訓練誤差と期待テスト誤差を比べると、両者は等しくなります。訓練集合・テスト集合とも同じサンプリング過程から生まれているためです。
この等式が成り立つのは「 を訓練集合とは無関係に固定した場合」だけです。 実際の学習では を訓練集合そのものを使って選ぶため、訓練誤差の期待値はテスト誤差の期待値以下に偏ります。これがテスト誤差は汎化誤差の不偏推定量だが、訓練誤差はそうではないという非対称の根拠です。テスト誤差を使う限り、標本平均は大数の法則で真の期待値へ収束していきます。
訓練誤差とのギャップ、容量との関係
学習の性能は次の2つで決まります。
| 課題 | 内容 |
|---|---|
| 訓練誤差を小さくする | モデルが訓練データにどれだけ適合できるか |
| 汎化ギャップを小さくする | 訓練誤差と汎化誤差の差をどれだけ抑えられるか |
統計的学習理論の代表的な結果は、このギャップの上限が、モデルの容量(capacity)が増えるほど大きくなり、訓練サンプル数が増えるほど小さくなることを示しています。容量が低すぎれば訓練誤差自体が下がらず(未学習)、容量を上げていくと訓練誤差は下がり続ける一方でギャップが開いていき(過学習)、汎化誤差は両者の和としてU字型の曲線を描きます。
ここで扱っているのはギャップが「どこから生まれるか」(容量と i.i.d. 仮定の関係)であり、ギャップの中身をバイアスとバリアンスに割って分析するのは別の観点です。 そちらは別ノート(バイアス・バリアンス分解)の主題になります。
試験でどう問われるか
| 問われ方 | 正解に寄る条件 | 引っかけ |
|---|---|---|
| 汎化誤差の定義を選ばせる | 未知データ( 全体)に対する損失の期待値 | 「訓練データに対する平均損失」=訓練誤差の定義とすり替え |
| なぜテスト誤差を使うのか | i.i.d. 仮定のもとテスト誤差は汎化誤差の不偏推定量になる | 「訓練誤差を使えば十分」(モデル選択に使った分だけ偏る) |
| 訓練誤差とテスト誤差の期待値の関係 | モデルを固定すれば両者は等しい。学習で選ぶと訓練誤差側が下に偏る | 「常に訓練誤差 < テスト誤差」と無条件で覚える |
| 容量と汎化ギャップの関係 | ギャップの上限は容量とともに増え、訓練サンプル数とともに減る | 「容量を上げれば汎化誤差も単調に下がる」 |
| 汎化誤差そのものを直接計算できるか | できない。有限サンプルの誤差でしか近似できない | 「解析的に厳密な汎化誤差を計算する」選択肢 |
実装で確かめる
大きなテスト集合上の誤差は、汎化誤差の良い近似になります。多項式回帰の次数(=容量)を上げていくと、訓練誤差は下がり続ける一方でテスト誤差はU字を描くことを確認します。
import numpy as np
rng = np.random.default_rng(0)
def sample(n): # 真のデータ生成過程 p_data
x = rng.uniform(-3, 3, n)
y = np.sin(x) + rng.normal(0, 0.3, n)
return x, y
x_train, y_train = sample(15) # 訓練集合は小さく固定
x_test, y_test = sample(20000) # 汎化誤差の近似に十分大きなテスト集合
for degree in [1, 3, 9, 14]: # 容量を上げていく
w = np.polyfit(x_train, y_train, degree)
train_err = np.mean((np.polyval(w, x_train) - y_train) ** 2)
test_err = np.mean((np.polyval(w, x_test) - y_test) ** 2)
print(f"degree={degree:2d} train={train_err:.4f} test={test_err:.4f}")
実行すると次のようになります。
degree= 1 train=0.1521 test=0.3569
degree= 3 train=0.0431 test=0.0994
degree= 9 train=0.0229 test=1.7982
degree=14 train=0.0000 test=436224959.0954
訓練誤差(train)は次数を上げるほど単調に下がり、degree=14 では0に張り付きます。一方でテスト誤差(test=汎化誤差の近似)はdegree=3で最小になったあと急激に悪化しています。訓練誤差だけを見ていたら「degree=14が最良」と誤読しますが、汎化誤差を近似するテスト誤差は真逆を示しています。
ここでのテスト集合(2万点)は汎化誤差を近似するために意図的に大きくしています。実務やコンペで使う実際のテスト集合はもっと小さく、テスト誤差自体にもサンプリング由来のばらつきが乗ります。「テスト誤差=汎化誤差そのもの」ではなく、あくまで有限サンプルによる推定値です。
取り違えやすいもの
| 用語 | 汎化誤差との関係 |
|---|---|
| 訓練誤差 | 訓練集合上の平均損失。モデル選択に使われる分だけ汎化誤差より系統的に低く偏る |
| テスト誤差 | テスト集合上の平均損失。i.i.d.仮定のもとで汎化誤差の不偏推定量として使う、実際に計算できる量 |
| バイアス・バリアンス分解 | 汎化誤差(の期待2乗誤差)を要因分解する別の観点。ギャップの出どころではなく中身の内訳を見る |
| 過学習・未学習 | 汎化ギャップが大きい状態/訓練誤差自体が下がらない状態という、容量が引き起こす症状の呼び名 |
| モデルの容量(capacity) | 汎化誤差そのものではなく、汎化ギャップの上限を左右する要因の1つ |
想起チェック
汎化誤差はどう定義されるか、なぜ直接計算できないか
データ生成分布 に従う未知の入力に対する損失の期待値として定義されます。 自体が手に入らないため、値そのものは計算できず、有限サンプル(テスト集合)上の誤差で推定するしかありません。
テスト誤差が汎化誤差の不偏推定量になるのはどんな仮定のもとか
訓練集合とテスト集合が独立に同一分布から生成されるという i.i.d. 仮定のもとです。モデルを固定すれば、期待訓練誤差と期待テスト誤差はどちらも汎化誤差に一致します。
「訓練誤差の期待値は常にテスト誤差の期待値より小さい」は正しいか
モデルを訓練集合と無関係に固定した場合は両者は等しく、どちらが小さいとも言えません。実際の学習ではモデルを訓練集合で選ぶため、その結果として訓練誤差の期待値がテスト誤差の期待値以下に偏ります。
モデルの容量を上げ続けると汎化誤差はどう変化するか
訓練誤差は下がり続けますが、訓練誤差と汎化誤差のギャップの上限は容量とともに増えるため、汎化誤差自体は下がりきらずU字型になり、ある容量を超えると悪化します。