ひとことで言うと
生成モデルは観測データ とラベル の同時分布 をモデル化し、識別モデルは入力からラベルへの条件付き分布 を直接モデル化します。前者は「データがどう生じたか」まで扱い、後者は「この入力をどのクラスに置くか」に計算を集中させます。
生成モデルは、料理の材料と完成品の出方を含むレシピ全体を覚える方法です。識別モデルは、完成品を見て料理名を当てる判定基準だけを覚えます。料理名を当てるだけなら判定基準のほうが軽く、材料の一部から完成品を推測するならレシピ全体が要ります。
なぜ必要か
同じ画像分類でも、設計の出発点は一つではありません。生成モデルなら同時分布を分解して
と表し、入力に対するクラスの確率を として計算できます。ここで はクラスの事前確率、 はクラスごとのデータ分布です。識別モデルはこの条件付き分布を最初から直接近似するので、画像全体の確率を説明する必要がありません。
この差は、必要な出力で選び分けます。
| 欲しいもの | 向く枠組み | 理由 |
|---|---|---|
| ラベル予測だけ | 識別モデル | 判別境界の学習に目的を絞れる |
| 新しいデータの生成 | 生成モデル | や を扱える |
| 一部が欠けた入力の補完 | 生成モデル | 観測部分から欠損部分の条件付き分布を求められる |
| 未知・外れ値の検出 | 生成モデル | データの尤度や整合性を評価できる |
もちろん実装では、識別モデルに別の再構成器や異常スコアを足すこともあります。ただし、それは だけを学習した結果として自然に得られる機能ではありません。
仕組み
生成モデルでは、ラベルを周辺化して入力の分布を
と求められます。連続潜在変数 を使うモデルなら、和の代わりに積分を使います。観測された特徴を 、欠損部分を とすると、欠損補完で必要なのは
です。分母は観測部分に合う全候補の確率を正規化する項です。このように、生成モデルは分類以外の問いにも同じ分布から答えを作れます。
一方、識別モデルはパラメータ で を表し、教師データに対する条件付き対数尤度
を最大化する形が基本です。 は訓練例数、 は 番目の入力とラベルです。不要な入力分布まで合わせないため、分類境界に利用できるラベル情報へ容量を使いやすい反面、入力そのものの確率はこの目的からは得られません。
| 観点 | 生成モデル | 識別モデル |
|---|---|---|
| 学習対象 | または | |
| 分類 | ベイズ則で導出 | 直接予測 |
| 生成・補完 | 分布から可能 | 目的に含まれない |
| 分類の効率 | 分布全体の学習が必要 | 境界に集中しやすい |
代表例を位置づけると、VAE は潜在変数を通じて尤度を近似する生成枠組み、GAN は生成器と識別器の対立でデータ生成を学ぶ枠組み、拡散モデルはノイズ除去過程を学ぶ生成枠組みです。これらは同じ分類器の別名ではなく、「データを生成する分布をどう表すか」の異なる実装です。
試験でどう問われるか
| 問われ方 | 正解に寄る条件 | 引っかけ |
|---|---|---|
| 2つの確率モデルを対応させる | 生成は 、識別は | 生成モデルも分類できるから識別モデルと同じ、とする |
| 分類問題での選択 | 分類だけなら識別モデルは目的を絞れて効率的 | 識別モデルは必ず精度が高い、と一般化する |
| 欠損値補完の可否 | 生成モデルは観測部分から欠損部分の分布を計算できる | 条件付き確率を直接学習する識別モデルだけで補完できるとする |
| 異常検知の根拠 | 正常データの尤度など、入力分布を評価する | クラス確率が低いことをそのまま異常度とみなす |
| 同じ分類を2通りで解く | 生成側は からベイズ則、識別側は を直接学習 | 生成モデルは分類に使えない、とする |
実装で確かめる
二値の1次元データについて、生成側はクラスごとのガウス分布から尤度を作り、識別側はロジスティック関数を直接計算します。どちらも分類確率を返しますが、生成側には入力の尤度も残ります。
import numpy as np
x = np.array([-2.0, -1.0, 0.0, 1.0, 2.0, 3.0])
y = np.array([0, 0, 0, 1, 1, 1])
prior = np.array([(y == 0).mean(), (y == 1).mean()])
mu = np.array([x[y == k].mean() for k in (0, 1)])
var = np.array([((x[y == k] - mu[k]) ** 2).mean() for k in (0, 1)])
def log_normal(z, m, v):
return -0.5 * (np.log(2 * np.pi * v) + (z - m) ** 2 / v)
log_joint = np.array([np.log(prior[k]) + log_normal(0.5, mu[k], var[k]) for k in (0, 1)])
generative_prob = np.exp(log_joint - np.logaddexp.reduce(log_joint))
discriminative_prob = 1 / (1 + np.exp(-(2.0 * 0.5)))
assert 0 < generative_prob[1] < 1 and 0 < discriminative_prob < 1
print(generative_prob[1], discriminative_prob)
生成側はクラス確率の計算途中に、入力 が各クラスの分布にどれだけ適合するかを使っています。識別側は重み と切片を含まない判定関数を直接評価しているだけです。実際のニューラルネットでは、どちらを損失関数と出力設計の中心に置くかが分岐点になります。
取り違えやすいもの
| 用語 | 切り分け |
|---|---|
| 分類器 | を当てる機能の総称。生成モデルでも識別モデルでも作れます |
| 識別器 | GAN では生成データと実データを見分けるネットワークを指す。識別モデル全般と同義ではありません |
| 自己符号化器 | 入力を復元する構造。復元だけでは、明示的な確率モデルとは限りません |
| 条件付き生成モデル | や を学習する生成モデル。条件を受けるので識別モデル、という意味ではありません |
| 異常検知 | 生成モデルの尤度を使えるが、尤度が低いことと意味的な異常が一致するとは限りません |
想起チェック
生成モデルと識別モデルが直接モデル化する確率は何か
生成モデルは 、識別モデルは です。
分類だけなら識別モデルが選ばれやすい理由は何か
入力分布全体を説明せず、条件付き分布または判定境界の学習に目的を絞れるためです。
生成モデルで欠損補完ができるのはなぜか
同時分布から を計算し、観測部分に整合する欠損部分の分布を得られるためです。
同じ分類問題を生成的にも識別的にも解くときの違いは何か
生成側は を学習してベイズ則で分類し、識別側は を直接学習します。