본문으로 이동
메뉴 여닫기
환경 설정 메뉴 여닫기
개인 메뉴 여닫기
로그인하지 않음
지금 편집한다면 당신의 IP 주소가 공개될 수 있습니다.
Normalizing flow; 노멀라이징 플로, 정규화 흐름
단순한 확률 분포에 되돌릴 수 있는(가역) 변환을 여러 번 적용해 복잡한 데이터 분포를 만들고, 변수 변환 공식으로 정확한 우도를 계산하는 생성 모델

노멀라이징 플로(normalizing flow, 정규화 흐름)는 표준 정규 분포 같은 기저 분포(base distribution)의 표본 z를 가역이고 미분 가능한 함수 f로 옮겨 데이터 x=f(z)를 만드는 생성 모델이다. 변환이 가역이므로 데이터 하나가 주어지면 거꾸로 z=f−1(x)를 구할 수 있고, 변수 변환 공식으로 log⁡p(x)를 근사 없이 계산할 수 있다. 그래서 학습은 최대 우도 추정 하나로 끝나고, 표본 추출도 기저 분포에서 뽑아 한 번 순방향으로 통과시키면 된다.

"normalizing"은 데이터를 정규 분포 쪽으로 되돌리는 방향(f−1)을, "flow"는 변환을 여러 겹 이어 확률 질량이 흘러가듯 모양이 바뀌는 모습을 가리킨다. 2015년 레젠더(Danilo Rezende)와 모하메드(Shakir Mohamed)가 변분 추론의 근사 사후 분포를 풍부하게 만드는 도구로 이 이름을 썼고,[1] 이후 NICE, RealNVP, Glow가 이미지 생성 모델로 발전시켰다. 생성 모델 문서의 계열 비교에서 다루는 개요보다 한 단계 들어가, 변환 설계와 구현을 정리한다.

변수 변환 공식

편집 원본 편집

z∼pZ이고 x=f(z), f가 미분 가능한 전단사 함수라면 다음이 성립한다.

pX(x)=pZ(f−1(x))|det⁡∂f−1(x)∂x|=pZ(z)|det⁡∂f(z)∂z|−1

변환을 f=fK∘⋯∘f1처럼 K개 쌓고 h0=x에서 거꾸로 hk=fK−k+1−1(hk−1)를 계산하면 로그 행렬식이 층마다 더해진다.

log⁡pX(x)=log⁡pZ(hK)+∑k=1Klog⁡|det⁡Jk|

여기서 Jk는 k번째 역변환의 야코비 행렬이다. 문제는 일반적인 D×D 행렬식 계산이 O(D3)이라는 점이다. 이미지 한 장의 차원이 수만~수십만이므로 그대로는 쓸 수 없다. 노멀라이징 플로 연구의 대부분은 "역변환을 쉽게 구할 수 있고, 야코비 행렬이 삼각 행렬이라 행렬식이 대각 원소의 곱이 되는" 변환을 설계하는 일이다.

같은 차원 사이의 전단사여야 하므로 잠재 공간 차원은 데이터 차원과 같다. 변분 오토인코더처럼 정보를 압축하는 병목이 없다는 점이 장점이자 비용이다.

레젠더와 모하메드가 쓴 초기 예는 평면 흐름(planar flow) f(z)=z+uh(w⊤z+b)이다. 행렬식 보조정리로 det⁡J=1+h′(w⊤z+b)u⊤w를 O(D)에 계산할 수 있지만, 역함수가 닫힌 꼴로 없어 표본의 밀도만 알면 되는 변분 추론용으로 쓰였다.[1]

결합층(coupling layer)은 입력을 두 부분 xa,xb로 나누고 한쪽은 그대로 통과시키며, 그 값으로 다른 쪽을 변환한다.

ya=xa,yb=xb⊙exp⁡(s(xa))+t(xa)

s,t는 임의의 신경망이어도 된다. 역변환은 xb=(yb−t(ya))⊙exp⁡(−s(ya))로 신경망을 뒤집지 않고 구할 수 있고, 야코비 행렬은 하삼각이라 log⁡|det⁡J|=∑jsj(xa)다.

  • NICE(2014)는 s=0인 덧셈 결합층(additive coupling)을 썼다. 부피를 보존하므로 행렬식이 1이고, 마지막에 대각 스케일링 층을 둔다.[2]
  • RealNVP(2016)는 스케일 s를 더한 아핀 결합층(affine coupling)으로 부피가 바뀌는(non-volume preserving) 변환을 만들었다. 이미지에서는 공간 체커보드 마스크와 채널 마스크를 번갈아 쓰고, 해상도를 반으로 줄이며 채널을 4배로 늘리는 스퀴즈 연산과 일부 차원을 일찍 잠재 변수로 빼는 다중 척도 구조를 도입했다. 배치 정규화도 결합층 안팎에 썼다.[3]

Glow: 1×1 가역 합성곱

편집 원본 편집

결합층은 매번 절반만 바꾸므로 층 사이에 차원 순서를 섞어야 한다. RealNVP는 채널 순서를 뒤집거나 고정된 무작위 순열을 썼는데, 킹마(Diederik Kingma)와 다리왈(Prafulla Dhariwal)의 Glow(2018)는 이를 학습되는 c×c 가중치 행렬 W의 1×1 합성곱으로 일반화했다. h×w 크기 특성맵에서 로그 행렬식은 h⋅w⋅log⁡|det⁡W|이며, W=PL(U+diag⁡(s))로 LU 분해해 두면 계산량이 O(c3)에서 O(c)로 준다. 한 단계는 actnorm(데이터로 초기화하는 채널별 아핀 정규화), 1×1 가역 합성곱, 아핀 결합층 순서다.[4]

Glow는 CelebA-HQ 256×256 얼굴을 생성하고 잠재 공간에서 "웃음", "금발" 같은 속성 벡터를 더해 얼굴을 편집하는 시연으로 알려졌다. 논문은 256×256 이미지 한 장 생성에 GTX 1080 Ti 한 장에서 약 130ms가 걸린다고 밝혔다. 기저 분포의 표준편차를 줄이는 온도(temperature) 표본 추출을 쓰면 품질이 좋아지고 다양성은 준다.[4]

자기회귀 플로

편집 원본 편집

i번째 차원의 변환 매개변수를 앞선 차원들로 정하는 방식이다. 야코비 행렬이 삼각이 되는 가장 일반적인 구조이며, 결합층은 그 특수한 경우다.

  • MAF(Masked Autoregressive Flow, 2017): xi=uiexp⁡(αi)+μi, (μi,αi)=g(x1:i−1). 마스크로 자기회귀 조건을 지키는 신경망 MADE 한 번으로 모든 차원의 밀도를 동시에 계산하므로 밀도 평가와 학습이 빠르지만, 표본 추출은 D번 순차 계산이 필요하다. 논문은 MAF가 RealNVP의 일반화라고 설명한다.[5]
  • IAF(Inverse Autoregressive Flow, 2016): 조건을 x가 아니라 기저 잡음 u1:i−1에 건다. 표본 추출은 한 번에 되지만 외부 데이터의 밀도 평가는 순차적이다. 그래서 VAE의 근사 사후 분포처럼 자기가 뽑은 표본의 밀도만 필요한 곳에 맞는다.[6]
  • 뉴럴 스플라인 플로(2019)는 원소별 아핀 변환 대신 단조 유리 2차 스플라인을 써서, 역변환을 해석적으로 유지하면서 결합층과 자기회귀층의 표현력을 높였다.[7]

연속 정규화 흐름

편집 원본 편집

층을 무한히 잘게 쪼개면 변환은 상미분 방정식 dzdt=vθ(z,t)가 되고, 로그 밀도의 변화는 행렬식 대신 대각합으로 주어진다.

dlog⁡p(z(t))dt=−tr⁡(∂vθ∂z(t))

신경 ODE(2018)가 이 연속 정규화 흐름(CNF)을 제안했고,[8] FFJORD(2018)는 허치슨 대각합 추정량으로 대각합을 비편향 추정해 신경망 구조 제약을 없앴다.[9] 다만 학습할 때마다 ODE를 풀어야 해서 느렸다. 2022년 플로 매칭은 ODE를 풀지 않고 속도장 vθ를 회귀로 바로 학습하는 방법을 내놓아 CNF를 대규모 이미지·영상 생성 모델의 뼈대로 만들었다.

방식 대표 모델 밀도 평가 표본 추출 로그 행렬식 특징
덧셈 결합층 NICE 1회 통과 1회 통과 0(부피 보존) 가장 단순, 표현력 낮음
아핀 결합층 RealNVP, Glow 1회 통과 1회 통과 ∑s 이미지 생성의 표준 구성
자기회귀(MAF) MAF, 뉴럴 스플라인 플로 1회 통과 D회 순차 대각 원소 합 밀도 추정 성능 우수
역자기회귀(IAF) IAF D회 순차 1회 통과 대각 원소 합 VAE 사후 분포, 빠른 생성
연속(CNF) 신경 ODE, FFJORD ODE 적분 ODE 적분 대각합 적분 구조 제약 없음, 학습이 느림

노멀라이징 플로는 우도를 정확히 계산하므로 차원당 비트(bits/dim)로 비교한다. 낮을수록 좋다.

모델 CIFAR-10 ImageNet 32×32 ImageNet 64×64
RealNVP 3.49 4.28 3.98
Glow 3.35 4.09 3.81

수치는 Glow 논문 표 2의 값이다.[4] 같은 시기의 자기회귀 모델(PixelCNN 계열)은 우도에서 더 좋은 값을 냈고, 표본의 시각적 품질은 GAN에 뒤졌다. 2020년대 들어 이미지 생성의 주류가 확산 모델로 넘어가면서 연구가 줄었으나, 2024년 애플 연구진의 TarFlow는 패치 단위 자기회귀 트랜스포머 블록을 쌓은 MAF 변형에 학습 시 가우스 잡음 증강, 학습 후 잡음 제거, 가이던스를 더해 이미지 우도에서 기존 최고 기록을 크게 넘고 확산 모델에 견줄 표본 품질을 냈다고 보고했다.[10]

2차원 두 반달(two moons) 데이터를 RealNVP 아핀 결합층 6개로 학습하는 예다. 마스크를 번갈아 써서 두 좌표가 차례로 변환되게 하고, s는 tanh로 범위를 제한해 학습을 안정시켰다. PyTorch 2.5에서 실행해 역변환 오차가 1e-7 수준인 것을 확인했다.

import math, torch, torch.nn as nn

class AffineCoupling(nn.Module):
    """mask가 1인 차원은 그대로 두고, 그 값으로 나머지 차원을 아핀 변환"""
    def __init__(self, dim, mask, hidden=128):
        super().__init__()
        self.register_buffer("mask", mask)
        self.net = nn.Sequential(nn.Linear(dim, hidden), nn.ReLU(),
                                 nn.Linear(hidden, hidden), nn.ReLU(),
                                 nn.Linear(hidden, 2 * dim))
    def forward(self, x):                      # x -> z, log|det J|
        xa = x * self.mask
        s, t = self.net(xa).chunk(2, dim=-1)
        s = torch.tanh(s) * (1 - self.mask)
        t = t * (1 - self.mask)
        z = xa + (1 - self.mask) * (x * torch.exp(s) + t)
        return z, s.sum(-1)
    def inverse(self, z):                      # z -> x (표본 추출)
        za = z * self.mask
        s, t = self.net(za).chunk(2, dim=-1)
        s = torch.tanh(s) * (1 - self.mask)
        t = t * (1 - self.mask)
        return za + (1 - self.mask) * ((z - t) * torch.exp(-s))

class RealNVP(nn.Module):
    def __init__(self, n_layers=6):
        super().__init__()
        masks = [torch.tensor([1., 0.]) if i % 2 == 0 else torch.tensor([0., 1.])
                 for i in range(n_layers)]
        self.layers = nn.ModuleList(AffineCoupling(2, m) for m in masks)
    def log_prob(self, x):
        logdet = 0.0
        for layer in self.layers:
            x, ld = layer(x)
            logdet = logdet + ld
        log_pz = -0.5 * (x ** 2).sum(-1) - math.log(2 * math.pi)  # 2차원 표준 정규
        return log_pz + logdet                 # 변수 변환 공식
    @torch.no_grad()
    def sample(self, n):
        z = torch.randn(n, 2)
        for layer in reversed(self.layers):
            z = layer.inverse(z)
        return z

def two_moons(n):
    t = torch.rand(n) * math.pi
    upper = torch.stack([torch.cos(t), torch.sin(t)], 1)
    lower = torch.stack([1 - torch.cos(t), 0.5 - torch.sin(t)], 1)
    x = torch.where(torch.rand(n, 1) < 0.5, upper, lower)
    return x + 0.05 * torch.randn_like(x)

model = RealNVP()
opt = torch.optim.Adam(model.parameters(), lr=1e-3)
for step in range(3000):
    loss = -model.log_prob(two_moons(512)).mean()   # 음의 로그 우도
    opt.zero_grad(); loss.backward(); opt.step()
samples = model.sample(1000)

실제 이미지 모델에서는 이산 픽셀값에 균등 잡음을 더하는 역양자화(dequantization)를 해야 연속 밀도의 우도가 무한대로 발산하지 않는다. 라이브러리로는 PyTorch 기반 nflows, normflows, 확률 프로그래밍 라이브러리 Pyro의 변환 모듈 등이 있다.

장단점과 쓰임

편집 원본 편집
  • 장점
    • 정확한 로그 우도: 모델 비교와 이상 탐지에 쓸 수 있는 진짜 밀도 값을 준다.
    • 정확한 역변환: 데이터마다 잠재 벡터가 하나로 정해지므로 보간과 속성 편집이 자연스럽다.
    • 표본 추출이 한 번의 순전파(결합층 기준)로 끝나 반복 계산이 필요한 확산 모델보다 빠르다.
  • 단점
    • 가역성과 같은 차원 제약 때문에 같은 품질을 내려면 매개변수와 메모리가 많이 든다. Glow도 고해상도에서 GPU당 미니배치 1과 그래디언트 체크포인팅을 썼다.[4]
    • 위상 제약: 연속 전단사 함수는 공간의 위상을 바꿀 수 없어 서로 떨어진 여러 모드를 표현할 때 경계가 번진다.
    • 우도가 높다고 표본 품질이 좋은 것은 아니다. 또 CIFAR-10으로 학습한 플로 모델이 집 번지수 사진(SVHN)에 더 높은 우도를 주는 현상이 보고되어, 우도만으로 분포 밖 데이터를 가려내는 데는 주의가 필요하다.[11]
  • 쓰임: 변분 추론의 사후 분포 근사(IAF), 단백질 같은 다체계의 평형 상태를 한 번에 뽑는 볼츠만 생성기,[12] 멜 스펙트로그램에서 파형을 자기회귀 없이 만드는 음성 합성 보코더 WaveGlow,[13] 그리고 확산 모델과 플로 매칭의 이론적 바탕(연속 정규화 흐름).
  1. ↑ 1.0 1.1 Danilo Jimenez Rezende, Shakir Mohamed, 〈Variational Inference with Normalizing Flows〉, ICML 2015. arXiv:1505.05770
  2. ↑ Laurent Dinh, David Krueger, Yoshua Bengio, 〈NICE: Non-linear Independent Components Estimation〉, ICLR 2015 워크숍. arXiv:1410.8516
  3. ↑ Laurent Dinh, Jascha Sohl-Dickstein, Samy Bengio, 〈Density estimation using Real NVP〉, ICLR 2017. arXiv:1605.08803
  4. ↑ 4.0 4.1 4.2 4.3 Diederik P. Kingma, Prafulla Dhariwal, 〈Glow: Generative Flow with Invertible 1x1 Convolutions〉, NeurIPS 2018. arXiv:1807.03039
  5. ↑ George Papamakarios, Theo Pavlakou, Iain Murray, 〈Masked Autoregressive Flow for Density Estimation〉, NeurIPS 2017. arXiv:1705.07057
  6. ↑ Diederik P. Kingma 외, 〈Improving Variational Inference with Inverse Autoregressive Flow〉, NeurIPS 2016. arXiv:1606.04934
  7. ↑ Conor Durkan, Artur Bekasov, Iain Murray, George Papamakarios, 〈Neural Spline Flows〉, NeurIPS 2019. arXiv:1906.04032
  8. ↑ Ricky T. Q. Chen 외, 〈Neural Ordinary Differential Equations〉, NeurIPS 2018. arXiv:1806.07366
  9. ↑ Will Grathwohl 외, 〈FFJORD: Free-form Continuous Dynamics for Scalable Reversible Generative Models〉, ICLR 2019. arXiv:1810.01367
  10. ↑ Shuangfei Zhai 외, 〈Normalizing Flows are Capable Generative Models〉, ICML 2025. arXiv:2412.06329
  11. ↑ Eric Nalisnick 외, 〈Do Deep Generative Models Know What They Don't Know?〉, ICLR 2019. arXiv:1810.09136
  12. ↑ Frank Noé 외, 〈Boltzmann Generators: Sampling Equilibrium States of Many-Body Systems with Deep Learning〉, Science 365, 2019. arXiv:1812.01729
  13. ↑ Ryan Prenger, Rafael Valle, Bryan Catanzaro, 〈WaveGlow: A Flow-based Generative Network for Speech Synthesis〉, ICASSP 2019. arXiv:1811.00002