Normalizing Flows
正規化フローは、可逆レイヤーを通じて単純なノイズを複雑なデータに変換するため、1つのモデルでサンプリングと厳密な尤度計算の両方を実行できます。仕組みを解説します。
Normalizing flowは、通常は標準ガウス分布である単純な基底分布を、可逆かつ微分可能な関数の列を通じて複雑なデータ分布に変換する生成AIモデルです。各層を逆方向に実行でき、体積への影響を正確に計算できるため、多くの生成モデルでは同時に実現できない2つの役割を1つのflowで果たせます。すなわち、ノイズを層に順方向に通して新しいサンプルを生成し、観測されたデータ点を基底分布まで逆方向に通して、その正確な尤度を計算します。Esteban Tabakらは2010年と2013年に密度推定のためのflowを定式化し、DeepMindのDanilo RezendeとShakir Mohamedが、ICML 2015のVariational Inference with Normalizing Flowsでこの名称をディープラーニングに導入しました。「Normalizing」はデータ分布をnormal、つまりガウス分布に変換することを指し、batch normalizationとは関係ありません。
変数変換公式#
可逆関数fがデータ点xを潜在点z = f(x)に写像するとき、データの対数尤度はlog p(x) = log p_z(f(x)) + log |det J|です。ここでJはfのヤコビ行列であり、行列式はfがxの周囲の体積をどれだけ伸縮させるかを表します。D変数の一般的な関数では、この行列式の計算におよそD³回の演算が必要となり、数十万次元の画像には遅すぎます。そのため、flow層は行列式が対角成分の積だけで求められる三角ヤコビ行列を持つように設計されます。このような層を重ねると変換が合成され、対数行列式が加算されます。学習では学習データの対数尤度を直接最大化します。
RealNVPのaffine coupling層は、代表的な設計です。入力の半分は変更せずに通し、小さなニューラルネットワークに入力して、残りの半分のスケールとシフトを決定します。以下はPyTorch層の例です:
import torch
from torch import nn
torch.manual_seed(0)
# Affine coupling layer (RealNVP): x1 passes through unchanged and sets the scale and shift for x2
net = nn.Sequential(nn.Linear(2, 32), nn.Tanh(), nn.Linear(32, 4))
def coupling(x):
"""Map data x to z and return log|det J|, which is just the sum of the log-scales."""
x1, x2 = x.chunk(2, dim=-1)
log_s, t = net(x1).chunk(2, dim=-1)
return torch.cat([x1, x2 * log_s.exp() + t], dim=-1), log_s.sum(dim=-1)
x = torch.randn(4)
z, log_det = coupling(x)
jacobian = torch.autograd.functional.jacobian(lambda v: coupling(v)[0], x)
print(f"log|det J|: {log_det:.4f} from the formula, {torch.logdet(jacobian):.4f} from the full 4x4 Jacobian")
# Inverse: z1 equals x1, so the same scale and shift can be recomputed and undone
z1, z2 = z.chunk(2)
log_s, t = net(z1).chunk(2)
x_rec = torch.cat([z1, (z2 - t) * (-log_s).exp()])
print(f"Largest reconstruction error: {(x_rec - x).abs().max():.1e}")簡易な公式と完全なヤコビ行列のどちらでも対数行列式は0.1489となり、逆変換では入力を1.2e-07以内の誤差で復元できます。これはfloat32の丸め誤差です。層内のネットワーク自体を逆変換する必要はないため、任意に複雑なネットワークを使用できます。
Flowアーキテクチャ#
- Coupling flow:Laurent DinhらのNICE(2014)とRealNVP(2016)は、変換する半分を交互に切り替えます。OpenAIのGlow(2018)は学習可能な可逆1 x 1畳み込みを追加し、リアルな256 x 256の顔画像を生成しました。サンプリングと密度評価のどちらも高速です。
- Autoregressive flow:各次元を、それより前の次元を条件として変換します。Masked autoregressive flowは1回の処理で密度を評価しますが、サンプリングは1次元ずつ行います。Inverse autoregressive flowはその逆です。AppleのTarFlow(2024)は、画像パッチに対して自己回帰Transformerブロックを積み重ねたもので、単独のflowとして初めて、拡散モデルに匹敵する品質のサンプルを生成しました。
- 連続フロー:変換を常微分方程式の解として定義し、層設計の制約をなくします。FFJORD(2018)は、確率的トレース推定器で対数密度の変化を追跡します。
用途#
- 異常検知:DifferNet(2021)、CFLOW-AD、FastFlowは、欠陥のない製品画像に対して事前学習済み畳み込みニューラルネットワークの特徴にflowを適合させ、尤度の低い画像を欠陥として検出します。FastFlowは2021年、MVTec AD産業検査ベンチマークの異常検知で99.4%のAUCを報告しました。
- 音声合成:NVIDIAのWaveGlow(2018)は、メルスペクトログラムから1回の並列処理で音声を生成しました。
- 科学的サンプリング:Frank NoéらのBoltzmann generator(2019)は、分子やタンパク質の平衡状態をサンプリングし、正確な尤度を使ってサンプルを真の物理分布に再重み付けします。
これらの検出器がピクセルではなく特徴をモデル化する理由は、Eric Nalisnickらが2019年に実証しました。CIFAR-10の写真で学習したGlowモデルは、未見のSVHNの家屋番号画像により高い尤度を割り当てます。この失敗は後に、flowが画像の内容よりも局所的なピクセル相関をモデル化していることに起因すると判明しました。欠陥検出では、flowへの入力に、任意の事前学習済みバックボーンから得た埋め込みを使用できます。Ultralytics YOLO26のembedメソッドは、デフォルトで検出ヘッドの直前の層から、画像ごとに1つの平均プーリング済み特徴ベクトルを返します。
Normalizing flowと関連用語#
- Flow matchingとrectified flow:速度場を回帰して連続フローを学習します。学習時に対数行列式を必要とせず、現在は大規模な画像生成モデルの基盤となっています。
- 変分オートエンコーダーと拡散モデル:尤度の下界を使って学習します。
- GAN:識別器をだますように学習し、尤度は一切出力しません。
- Generative flow network(GFlowNet):「flow」という語を共有していますが、報酬に比例する確率で離散オブジェクトを段階的に構築します。










