디퓨전

순방향 과정: 노이즈가 지형을 뭉갠다

스코어(레이더)만 있으면 걸어갈 수 있다. 그런데 그 스코어를 누가 만들어 주는가? 우리 손에 있는 것은 이미지들, 다시 말해 봉우리 위에 놓인 점들뿐이고 지형 p는 모른다. 노이즈에서 이미지로 가는 과정(역방향 과정)을 알려면, 거꾸로 이미지가 노이즈가 되는 과정(순방향 과정)부터 알아야 하지 않을까? 순방향 과정은 이미지에 노이즈를 조금씩 더하기만 하면 되니 우리가 직접 만들 수 있다. 그러면 분포는 어떻게 변할까? 노이즈를 더할수록 봉우리가 뭉개지는데, 노이즈로 뭉개진 분포를 거꾸로 되돌리는 것이 생성이다.

순방향 디퓨전: 단계별로 노이즈가 쌓인다
순방향 디퓨전: 단계별로 노이즈가 쌓인다

노이즈 스케줄: 안개의 단계

대회는 새벽, 짙은 안개 속에서 시작하는데, 이 안개가 데이터에 더하는 노이즈다.

안개가 짙으면 레이더의 수신 범위가 넓어진다. 7개 볼의 신호가 뭉개져서 하나로 섞이고, 레이더는 어떤 볼인지 가리지 못한 채 일곱 볼의 대략적인 한가운데를 가리킨다. 해가 뜨면서 안개가 걷히면 수신 범위가 좁아진다. 가장 가까운 볼의 신호가 커지고, 레이더는 정밀해져서 특정 볼을 또렷하게 가리킨다. 멀리서는 숲을 보고, 가까이서는 나무를 본다. 안개, 곧 노이즈의 표준편차 σ를 시간에 따라 얼마나 빨리 키울지 정한 시간표를 노이즈 스케줄이라고 부른다.

SDE로 쓰기: 노이즈를 쌓는 순방향 과정

순방향 과정은 데이터 한 점 x₀에서 출발해 매 순간 작은 무작위 이동을 더하며, 데이터에 노이즈를 점점 더 쌓는 과정(안개를 짙게 하는 것)이다. 이 과정을 확률미분방정식(SDE, stochastic differential equation. 매 순간 무작위 항이 끼어드는 미분방정식)으로 쓴다.

시간 t의 방향부터 적어 두면, 이 장에서는 디퓨전 문헌의 관례를 따라 t = 0이 데이터이고 t가 커질수록 노이즈다. 문헌에 따라서는 방향이 반대(t = 0이 노이즈, t = 1이 데이터)인 경우도 있으니, 식을 옮겨 올 때 조심하자.

dx=f(x,t) dt+g(t) dWd\textcolor{#6f8fa6}{x} = \textcolor{#d07a12}{f}(\textcolor{#6f8fa6}{x}, \textcolor{#007800}{t})\, d\textcolor{#007800}{t} + \textcolor{#0068c0}{g}(\textcolor{#007800}{t})\, d\textcolor{#8a7fb0}{W}
x시각 t 의 위치 xtf표류항: 무작위 없이 끌려가는 방향g(t)확산 계수: 노이즈가 쌓이는 빠르기dW브라운 운동의 증분 (작은 무작위 이동)t시간 (클수록 노이즈)\begin{array}{ll} \textcolor{#6f8fa6}{x} & \text{시각 } t \text{ 의 위치 } x_t \\ \textcolor{#d07a12}{f} & \text{표류항: 무작위 없이 끌려가는 방향} \\ \textcolor{#0068c0}{g}(\textcolor{#007800}{t}) & \text{확산 계수: 노이즈가 쌓이는 빠르기} \\ d\textcolor{#8a7fb0}{W} & \text{브라운 운동의 증분 (작은 무작위 이동)} \\ \textcolor{#007800}{t} & \text{시간 (클수록 노이즈)} \end{array}

dW는 매 순간 더해지는 작은 무작위 이동으로, 평균 0, 분산 dt인 정규분포를 따른다. 가장 단순한 선택은 표류 없이(f = 0) 노이즈만 쌓는 것이다. 그러면 시간 t의 점은 xt = x₀ + σt z, z ~ N(0, I) 이고, σt² 는 그때까지 쌓인 g² 의 합이다. 표류 f = −½β(t)x 를 넣어 원점 쪽으로 줄이면서 노이즈를 더하는 DDPM(denoising diffusion probabilistic model, 디노이징 디퓨전 확률 모델. 호(Jonathan Ho) 외 2020) 방식도 같은 틀 안에 있다. β(그리스 문자 베타)(t)는 시각 t에 노이즈를 얼마나 빨리 넣는지 정하는 양수다.

점 하나가 아니라 분포 전체를 보자. x₀ ~ p 에 독립인 가우시안 노이즈를 더했으니, xt의 밀도는 p와 가우시안 커널의 합성곱이다. 커널은 점 하나를 번지게 하는 모양(여기서는 종 모양의 정규분포 밀도)이고, 합성곱은 데이터의 점마다 그 종을 하나씩 씌워 모두 더하는 계산이다. 점이 있던 자리마다 잉크 방울이 번진 그림을 떠올리면 된다.

데이터가 −1 과 +1 두 점(반반)일 때, 표준편차 σ = 0.3, 0.6, 1.2 인 노이즈를 더한 밀도 p_σ. 노이즈가 작으면 두 봉우리가 또렷하고, σ 가 봉우리 사이 거리의 절반쯤인 1 을 넘으면 한가운데가 솟아 하나의 언덕이 된다
데이터가 −1 과 +1 두 점(반반)일 때, 표준편차 σ = 0.3, 0.6, 1.2 인 노이즈를 더한 밀도 p_σ. 노이즈가 작으면 두 봉우리가 또렷하고, σ 가 봉우리 사이 거리의 절반쯤인 1 을 넘으면 한가운데가 솟아 하나의 언덕이 된다
pt(x)=∫p(x0) N(x; x0,σt2I) dx0\textcolor{#d6479f}{p}_t(\textcolor{#6f8fa6}{x}) = \int \textcolor{#d6479f}{p}(\textcolor{#6f8fa6}{x}_0)\, \mathcal{N}(\textcolor{#6f8fa6}{x};\, \textcolor{#6f8fa6}{x}_0, \textcolor{#0068c0}{\sigma}_t^2 I)\, d\textcolor{#6f8fa6}{x}_0
pt노이즈 레벨 t 의 주변분포p데이터 분포=p0x0노이즈 없는 데이터 점x노이즈가 섞인 점σt시간 t 까지 쌓인 노이즈의 표준편차\begin{array}{ll} \textcolor{#d6479f}{p}_t & \text{노이즈 레벨 } t \text{ 의 주변분포} \\ \textcolor{#d6479f}{p} & \text{데이터 분포} = p_0 \\ \textcolor{#6f8fa6}{x}_0 & \text{노이즈 없는 데이터 점} \\ \textcolor{#6f8fa6}{x} & \text{노이즈가 섞인 점} \\ \textcolor{#0068c0}{\sigma}_t & \text{시간 } t \text{ 까지 쌓인 노이즈의 표준편차} \end{array}

pt를 주변분포라고 부르는 것은, 원래 점 x₀가 무엇이었는지라는 조건을 모두 합쳐 버린 분포이기 때문이다. 데이터가 드래곤볼 지형(정규분포의 혼합)이면 계산이 간단하다. 정규분포와 정규분포의 합성곱은 분산이 더해진 정규분포여서, 표준편차가 s₀였던 봉우리는 표준편차가 √(s₀² + σt²)인 봉우리가 된다. 볼들 사이 간격보다 봉우리의 표준편차 √(s₀² + σt²)가 커지면 일곱 봉우리가 하나의 언덕으로 합쳐진다.

노이즈를 충분히 더하면 데이터의 흔적이 사라진 순수한 정규분포(완전한 안개)가 된다. 정보기하학으로 보면 분포를 넓게 섞는 방향, 엔트로피가 커지는 방향이어서 가능성이 넓어지고 불확실성이 커진다.

직접 움직여 보기

불러오는 중…

트위디 공식: 노이즈 낀 분포의 스코어가 가리키는 곳

노이즈를 더한 분포 pt의 스코어 ∇log pt가 무엇을 가리키는지 물으면, 답은 놀랍도록 깔끔하다.

E[x0∣xt=x]=x+σt2 ∇xlog⁡pt(x)\mathbb{E}[\textcolor{#6f8fa6}{x}_0 \mid \textcolor{#6f8fa6}{x}_t = \textcolor{#6f8fa6}{x}] = \textcolor{#6f8fa6}{x} + \textcolor{#0068c0}{\sigma}_t^2\, \textcolor{#b0892a}{\nabla_{x} \log p_t}(\textcolor{#6f8fa6}{x})
E[ ⋅∣⋅ ]조건부 기댓값x0노이즈 없는 원래 점xt노이즈 낀 관측 (여기서는 값 x)σt노이즈의 표준편차∇xlog⁡pt노이즈를 더한 분포의 스코어\begin{array}{ll} \mathbb{E}[\,\cdot \mid \cdot\,] & \text{조건부 기댓값} \\ \textcolor{#6f8fa6}{x}_0 & \text{노이즈 없는 원래 점} \\ \textcolor{#6f8fa6}{x}_t & \text{노이즈 낀 관측 (여기서는 값 } x \text{)} \\ \textcolor{#0068c0}{\sigma}_t & \text{노이즈의 표준편차} \\ \textcolor{#b0892a}{\nabla_{x} \log p_t} & \text{노이즈를 더한 분포의 스코어} \end{array}

트위디 공식이다. 허버트 로빈스(Herbert Robbins)가 1956년 논문에서 모리스 트위디(Maurice Tweedie)와 주고받은 편지에 공을 돌리며 소개했고, 브래들리 에프론(Bradley Efron)이 2011년 논문 「Tweedie’s Formula and Selection Bias」로 다시 널리 알렸다. 노이즈 낀 점 x에서 스코어 방향으로 σt² 만큼 걸어가면, "노이즈를 걷어 냈을 때 원래 데이터 점이 있었을 법한 위치의 평균"에 닿는다. 스코어는 노이즈를 걷어 낸 추정치를 가리키고 있다. (표류가 있는 DDPM식 xt = αtx₀ + σtz 이면 좌변이 αt E[x₀ | xt]로 바뀔 뿐이다.)

증명은 한 줄이다. pt(x) = ∫ p(x₀) N(x; x₀, σt²) dx₀ 를 x로 미분하면 가우시안 커널의 미분 −(x − x₀)/σt² 가 적분 안으로 들어오고, pt로 나누면 사후 평균 E[x₀ − x | x] / σt² 가 남는다.

매니폴드 가설과의 연결

노이즈가 완전히 걷힌 상태에서 샘플(참가자)이 도달하는 곳, 드래곤볼의 위치가 데이터 매니폴드다. 노이즈가 섞여 있는 동안에는 매니폴드를 벗어나 있었지만, 스코어를 따라 걷는 과정이 매니폴드 위로 되돌려 준다.

순방향 과정 = 매니폴드를 떠남 (노이즈 추가)
역방향 과정 = 매니폴드로 귀환 (스코어를 따라 이동)

장 첫머리의 물음, 곧 넓은 공간 아무 데나 떨어진 점이 좁은 곳을 어떻게 찾아가는가에 대한 답의 모양이 순방향·역방향 두 줄이다. 남은 일은 역방향 과정을 식으로 실제로 적는 것이다.

파이썬

트위디 공식을 샘플로 확인해 보자. 데이터는 봉우리가 둘인 가장 단순한 분포, −1과 +1 두 점이 반반인 분포로 잡는다. 이 데이터에 노이즈를 더한 분포의 스코어는 (tanh(y/σ²) − y)/σ² 로 손으로 적힌다. 노이즈 낀 점 y 근처에 떨어진 샘플만 모아 원래 점의 평균을 내고, 그 평균을 트위디 공식의 값과 비교한다.

import numpy as np
rng = np.random.default_rng(0)

# 데이터: 두 점 ±1 (반반).  노이즈: x_σ = x + σ z
sigma, n = 0.5, 4_000_000
x = rng.choice([-1.0, 1.0], n)
xs = x + sigma * rng.normal(size=n)

def score(y):            # p_σ = ½N(−1,σ²) + ½N(1,σ²) 의 스코어
    return (np.tanh(y / sigma**2) - y) / sigma**2

for y in [0.3, 0.8, 1.5]:
    near = np.abs(xs - y) < 0.01
    print(f"y={y}:  E[x|y] 샘플 {x[near].mean():.3f}   트위디 y+σ²∇log p {y + sigma**2 * score(y):.3f}")
# y=0.3:  E[x|y] 샘플 0.832   트위디 y+σ²∇log p 0.834
# y=0.8:  E[x|y] 샘플 0.997   트위디 y+σ²∇log p 0.997
# y=1.5:  E[x|y] 샘플 1.000   트위디 y+σ²∇log p 1.000

노이즈 낀 점 0.3을 본 사람은 "원래 +1이었을 가능성이 크지만 확신은 못 한다"고 말한다. 그 망설임까지 담은 사후 평균 0.83을 스코어 한 번으로 얻는다면, 생성도 이것으로 끝나는 것 아닐까? 노이즈가 큰 점에서 출발해, 트위디 공식이 알려 주는 평균 위치로 한 번에 뛰면 되지 않을까?

이 절의 결론

“노이즈를 더하면 데이터 분포는 가우시안 커널과 합성곱된다. 노이즈를 더한 분포 pt의 스코어는 트위디 공식대로 '노이즈를 걷어 낸 평균 위치’를 가리킨다.”

문제 4. 운이 섞인 시험 점수

어느 반 학생들의 실력(운이 섞이지 않은 점수)은 평균 70점, 표준편차 10점으로 퍼져 있다. 시험 점수는 실력에 운이 더해진 것이고, 운은 평균 0점, 표준편차 10점이며 실력과 무관하다. 한 학생이 시험에서 90점을 받았다. 이 학생의 실력을 하나의 숫자로 추정하면 얼마인가?

반 학생들의 실력 분포(평균 70점, 표준편차 10점, 실선)와 실력에 운(표준편차 10점)이 더해진 시험 점수의 분포(점선), 그리고 한 학생이 받은 90점
반 학생들의 실력 분포(평균 70점, 표준편차 10점, 실선)와 실력에 운(표준편차 10점)이 더해진 시험 점수의 분포(점선), 그리고 한 학생이 받은 90점

함께 풀기

김민준 M01
김민준

90점이요. 시험이 실력을 재려고 보는 거니까 받은 점수가 제일 좋은 추정값이죠.

선생님 T01
선생님

이 반에서 90점을 받은 학생들만 모아 다음 시험을 보게 하면, 그 학생들의 평균은 또 90점 근처일까요?

김민준 M07
김민준

아… 아닐 것 같아요. 90점을 받은 학생 중에는 실력이 80점인데 운이 좋았던 학생이 많을 거예요. 실력이 90점 넘는 학생은 원래 드무니까요.

이서연 S01
이서연

그럼 얼마나 깎아야 할까요. 실력의 분산이 100, 운의 분산도 100이니까 점수의 분산 200은 반이 실력, 반이 운이에요.

선생님 T01
선생님

그럼 평균 70에서 벗어난 20점은 어떻게 읽어요?

이서연 S01
이서연

그 가운데 100/(100 + 100) = 절반만 실력으로 믿어요. 70 + 10 = 80점이에요.

선생님 T01
선생님

점수 분산에서 운이 차지하는 비율(여기서는 절반)만큼 반 평균 쪽으로 당겨 추정하는 거예요. 운이 클수록 더 많이 당겨요.

이서연 S01
이서연

확률론 수업에서 배운 「평균으로의 회귀」네요. 둘째 시험에서 1등 학생의 점수가 대개 내려오는 것도 그 회귀 때문이에요.

문제 5. 노이즈를 더한 정규분포

데이터가 x₀ ~ N(0, 1)이고, 표준편차 σ = 2인 노이즈를 더해 x = x₀ + 2z를 관측했다. (가) 노이즈를 더한 분포의 스코어를 구하라. (나) 트위디 공식으로 x = 3일 때 E[x₀ | x]를 구하고, 베이즈 정리로 직접 구한 값과 비교하라.

데이터 분포 N(0, 1)(분홍 실선)과 더하는 노이즈 2z의 분포 N(0, 4)(보라 점선), 그리고 관측값 x = 3
데이터 분포 N(0, 1)(분홍 실선)과 더하는 노이즈 2z의 분포 N(0, 4)(보라 점선), 그리고 관측값 x = 3

함께 풀기

이서연 S01
이서연

데이터가 N(0, 1)이니까 스코어는 −x예요. 트위디에 넣으면 E[x₀ | x = 3] = 3 + 4 × (−3) = −9예요.

선생님 T01
선생님

관측이 +3인데 원래 값의 평균이 −9라고요?

이서연 S01
이서연

…그러네요. 데이터는 거의 [−3, 3] 안에 사는데 −9는 말이 안 돼요. 공식은 맞게 썼는데요.

김민준 M01
김민준

나는 시뮬레이션으로 뽑아서 x가 3 근처인 것만 모아 x₀ 평균을 냈는데 0.60이 나왔어.

선생님 T01
선생님

트위디 공식의 스코어는 어느 분포의 스코어였어요?

이서연 S08
이서연

pt, 노이즈를 더한 분포요. 저는 데이터 p₀의 스코어를 넣었어요.

선생님 T01
선생님

그럼 pt는 어떤 분포예요?

이서연 S01
이서연

데이터에 노이즈를 더했으니까… N(0, 1)과 N(0, 4)의 합성곱이라 N(0, 5)예요. 스코어는 −x/5, x = 3에서 −0.6이에요. 그러면 3 + 4 × (−0.6) = 0.6이에요.

이서연 S01
이서연

베이즈로 해도 사후평균은 1/(1 + 4) × 3 = 0.6이에요. 세 값이 다 맞아요.

김민준 M01
김민준

시험 점수 문제에서 실력의 분산을 전체 분산으로 나눠 반 평균 쪽으로 당겼던 거랑 같은 계산이네. 여기선 실력 분산 1, 운 분산 4라서 3의 5분의 1만 믿는 거고.

선생님 T01
선생님

분산이 더해진다는 것은 노이즈 위젯에서 봉우리 폭이 √(s₀² + σ²)로 커지던 것과 같은 계산이에요.

이서연 S01
이서연

확률론 수업에서 독립 합의 분산을 계산할 때는 절대 안 틀리는데, 기호가 pt로 바뀌니까 t를 떼어 먹었어요. 해석학에서 f와 f∘g의 도함수를 섞는 실수랑 같은 종류예요.

문제 6. 한 번에 뛰어 보기

이미지 디퓨전 모델은 노이즈 낀 이미지를 받아 「원래 이미지의 평균 위치」, 곧 트위디 공식의 E[x₀ | xt]를 내놓도록 학습할 수 있다. 그렇다면 노이즈가 큰 이미지를 한 번만 넣어 트위디 평균으로 곧장 뛰면 이미지가 나올까? 데이터가 두 점 ±1(반반)인 장난감으로 확인하는데, 이 데이터에서는 E[x₀ | xσ = y] = tanh(y/σ²)이다. (가) 노이즈가 큰 σ = 2에서 y = 0.3에 선 점은 어디로 뛰는가? (나) 노이즈 낀 점을 모두 한 번에 뛰게 하면, 도착점 가운데 데이터 ±1 근처(거리 0.1 안)에 닿는 비율은 얼마인가? 노이즈가 작은 σ = 0.5이면?

데이터 두 점 ±1(반반)에 σ = 2(위)와 σ = 0.5(아래)의 노이즈를 더한 분포. 노란 띠는 데이터 ±1에서 거리 0.1 안의 구간이고, 위 그림에 출발점 y = 0.3을 표시했다
데이터 두 점 ±1(반반)에 σ = 2(위)와 σ = 0.5(아래)의 노이즈를 더한 분포. 노란 띠는 데이터 ±1에서 거리 0.1 안의 구간이고, 위 그림에 출발점 y = 0.3을 표시했다

함께 풀기

김민준 M01
김민준

(가)는 tanh(0.3/4) = 0.075예요. 트위디 공식이 원래 점을 알려 주니까, 모델이 몇백 스텝씩 걷는 건 낭비 같은데요. 한 번이면 되잖아요.

선생님 T01
선생님

0.075라는 점은 데이터에 있어요?

김민준 M01
김민준

데이터는 −1이랑 +1뿐이에요. 0.075는 그 사이 데이터가 없는 빈 구간이고요.

김민준 M05
김민준

(나)를 백만 개로 돌렸더니 σ = 2에서는 ±1 근처에 닿은 게 0.7%뿐이에요. 67%는 −0.5와 0.5 사이에 떨어졌어요. σ = 0.5에서는 90%가 닿아요.

이서연 S01
이서연

트위디가 주는 건 평균이지 샘플이 아니야.

김민준 M01
김민준

평균이면 왜 하필 한가운데야?

이서연 S01
이서연

σ = 2에서는 −1과 +1 가운데 어디서 왔는지 거의 모르니까, 두 점을 반반 섞은 평균인 한가운데를 내놓는 게 제곱 오차로는 최선이고. σ = 0.5에서는 원래 점이 거의 하나로 정해져서 평균이 그 점과 같아지는 거고.

선생님 T01
선생님

이미지로 옮기면 무슨 일이 생길까요?

김민준 M07
김민준

짙은 노이즈에서 한 번에 뛰면 고양이 여러 마리를 겹쳐 평균 낸 흐릿한 그림이 나오겠네요. 그래서 노이즈를 조금 걷고, 그 노이즈 레벨에 맞는 평균 쪽으로 조금 움직이고, 다시 조금 걷고… 여러 스텝으로 나누는 거구나. 원래 점이 정해질 때까지는 평균 쪽으로 조금씩만 가야 해요.

선생님 T01
선생님

그 「조금씩」을 정확히 적은 식이 무엇인지, 이제 찾아볼 차례예요.