요동-소산 정리: 마찰이 있으면 노이즈가 있다
지금까지는 관성을 뺐다. 물속의 작은 알갱이에서는 옳은 근사지만, HMC(Hamiltonian Monte Carlo, 해밀토니안 몬테카를로: 샘플에 무작위 운동량을 붙여 멀리 옮기는 샘플러)나 모멘텀 SGD처럼 운동량을 가진 계에서는 어떨까?
역사: 저항기의 노이즈
흔드는 것과 막는 것의 관계는 아인슈타인의 브라운 운동 논문이 나오고 20여 년 뒤 전기 회로에서 다시 나타났다. 1928년 벨 연구소의 존 존슨은 전류가 흐르지 않는 저항기의 양 끝에서도 전압이 쉬지 않고 흔들리며, 그 제곱 평균이 저항값과 절대온도에 비례함을 측정했다. 같은 연구소의 해리 나이퀴스트는 같은 해 이 노이즈를 열역학으로 설명했는데, 전하의 흐름을 막아 열을 내는 저항기가 곧 전하를 흔드는 원인이라는 것이다. 1951년 캘런과 웰턴은 에너지를 잃는 선형 계라면 어디서나 마찰의 크기와 온도가 노이즈의 크기를 정한다는 일반적인 관계를 증명했다.
조화 진동자에 마찰과 노이즈 넣기
운동량을 다루려면 관성을 되살려야 한다. 랑주뱅이 1908년에 처음 쓴 것도 질량이 있는 뉴턴 방정식이었고, 1930년 울렌벡과 오른스타인은 이 식으로 속도까지 넣은 브라운 운동을 풀었다. 먼저 숫자로 보자. 용수철에 매달린 추처럼 위치에너지가 U = q²/2인 조화 진동자(m = 1)를 q = 3에서 놓고, 운동량을 짧은 시간마다 세 가지로 바꾼다. 용수철의 힘으로 바뀌고, 마찰로 일정한 비율만큼 깎이고, 노이즈로 흔들린다. 시간 40 동안 돌린 뒤 운동량 제곱의 평균 ⟨p²⟩를 재면, 마찰(계수 0.5)만 있을 때는 0.000으로 멈추고, 단위 시간당 분산 1인 노이즈만 있을 때는 24.7로 불어나며, 둘을 함께 두면 1.000이 된다. 마찰은 그대로 두고 노이즈의 분산만 2로 키우면 1.99다. 노이즈의 분산이 마찰 계수의 두 배일 때만 온도 1의 볼츠만 분포가 주는 ⟨p²⟩ = 1에 이르는 듯하다. 이 관계를 식으로 적어 보자.
해밀턴 흐름 + 마찰 + 노이즈
위치 q와 운동량 p로 적으면 다음과 같다.
위치와 운동량을 함께 쓰는 식 dq = (p/m)dt, dp = −∇U dt − (ζ/m)p dt + √(2ζkT) dB를 언더댐프드 랑주뱅 방정식(관성을 남겨 둔 채 해밀턴 흐름에 마찰과 노이즈를 더한 식, underdamped Langevin equation)이라 한다. 마찰과 노이즈를 지우면 dq = (p/m)dt, dp = −∇U dt로 해밀턴 방정식 그대로여서, 언더댐프드 랑주뱅 방정식은 해밀턴 역학 + 마찰 + 노이즈다. 언더댐프드 랑주뱅 방정식을 따르는 (q, p)의 분포는 위상공간(위치와 운동량을 두 축으로 한 공간, phase space. 수학의 위상공간과 이름만 같다)의 볼츠만 분포 e^(−ℋ/kT)에 이른다.
그런데 노이즈 앞의 √(2ζkT)는 왜 하필 이 크기이고, 마찰과 노이즈가 서로 다른 크기이면 무슨 일이 생길까?
운동에너지가 들고 나는 셈
앞의 네 숫자는 운동에너지가 들어오고 나가는 셈으로 읽을 수 있다. 해밀턴 흐름은 운동에너지와 위치에너지를 서로 바꿀 뿐 전체 에너지를 바꾸지 않으므로, 전체 에너지를 바꾸는 것은 마찰과 노이즈뿐이다. 마찰은 운동량을 깎아 운동에너지를 빼내는데, 단위 시간에 빼내는 양은 마찰 계수와 지금의 운동에너지에 비례한다. 노이즈는 운동량을 흔들어 운동에너지를 넣는데, 단위 시간에 넣는 양은 노이즈 분산에 비례하고 지금의 운동에너지와는 상관없다. 마찰이 단위 시간에 빼내는 운동에너지와 노이즈가 넣는 운동에너지가 같아지는 곳을 계산하면 다음과 같다.
마찰 계수가 빼내는 쪽과 넣는 쪽에 똑같이 곱해져 있으므로, 단위 시간에 빼내는 양과 넣는 양이 같아지는 곳의 운동에너지는 ζ와 상관없이 kT/2다. 마찰을 키우면 노이즈도 같은 비율로 키워야 온도가 유지된다. 반대로 마찰만 있고 노이즈가 없으면 운동에너지가 0으로 빠져나가 계가 식고, 노이즈만 있고 마찰이 없으면 에너지가 들어오기만 해서 계가 한없이 뜨거워진다. 조화 진동자에서 잰 네 숫자(마찰만 0.000, 노이즈만 24.7, 노이즈 분산이 2ζkT로 맞으면 1.000, 노이즈 분산이 두 배면 1.99)가 바로 이 셈을 따른다. 에너지를 잃게 하는 마찰이 있는 계는 반드시 그 마찰과 온도로 크기가 정해진 노이즈를 받는다는 이 관계를 요동-소산 정리 (마찰로 에너지를 잃는 계가 받는 노이즈의 크기가 마찰 계수 × 온도로 정해진다는 관계, fluctuation-dissipation theorem)라 한다. 아인슈타인 관계 D = kT/ζ는 관성을 뺀 경우의 요동-소산 정리다.

일상 사례: 앰프의 「쉬」 소리
오디오 앰프의 볼륨을 끝까지 올리면 음악을 틀지 않아도 「쉬」 하는 소리가 나는데, 그 소리의 일부는 회로 속 저항기에서 온다. 저항기는 전하의 흐름을 막아 전기 에너지를 열로 바꾸는 마찰이므로, 전류가 흐르지 않아도 저항기 양 끝에는 그 저항값과 온도로 크기가 정해진 노이즈 전압이 생긴다.
저항기 양 끝에 생기는 이 노이즈 전압이 존슨–나이퀴스트 노이즈다. 실온(300 K)의 1 MΩ(메가옴, Ω는 그리스 문자 오메가) 저항기를 주파수 폭 10 kHz로 재면 노이즈 전압의 제곱평균제곱근은 약 12.9 μV다. 마찰(저항값)이 클수록, 온도가 높을수록 노이즈가 커서, 아주 약한 신호를 재는 전파 망원경의 수신기는 극저온으로 식힌다.
코드로 확인하기
조화 진동자에 언더댐프드 랑주뱅 방정식을 쓰고, 마찰만, 노이즈만, 노이즈 분산이 2ζkT로 맞는 마찰과 노이즈, 맞지 않는 마찰과 노이즈를 비교하는 코드다. 이어서 위치에너지 없이 마찰을 키워 가며 위치의 확산 계수가 kT/ζ로 가는지 본다.
import numpy as np
rng = np.random.default_rng(1)
# 언더댐프드 랑주뱅: 해밀턴 흐름 + 마찰 + 노이즈. U(q) = q²/2, 질량 m = 1, kT = 1
def run(zeta, noise, T=40.0, dt=0.01, n=20000, q0=3.0, p0=0.0):
q = np.full(n, q0); p = np.full(n, p0)
for _ in range(int(T / dt)):
p = p - q * dt - zeta * p * dt + noise * np.sqrt(dt) * rng.standard_normal(n) # 힘, 마찰, 노이즈
q = q + p * dt # 위치는 운동량으로
return q, p
kT = 1.0
for label, zeta, noise in (("마찰만 (모멘텀 SGD)", 0.5, 0.0),
("노이즈만", 0.0, np.sqrt(2 * 0.5 * kT)),
("마찰 + 짝이 맞는 노이즈", 0.5, np.sqrt(2 * 0.5 * kT)),
("마찰 0.5 + 마찰 1에 맞춘 노이즈", 0.5, np.sqrt(2 * 1.0 * kT))):
q, p = run(zeta, noise)
print(f"{label:22s}: ⟨p²⟩ = {np.mean(p**2):7.3f}, ⟨q²⟩ = {np.mean(q**2):7.3f}, 노이즈²/(2ζ) = "
f"{(noise**2 / (2 * zeta) if zeta > 0 else float('inf')):.2f}")
# 마찰이 크면: 운동량은 금방 열평형이 되고, 위치만 보면 확산 계수 kT/ζ인 브라운 운동 (위치에너지 없이)
for zeta in (0.5, 5.0, 50.0):
q = np.zeros(20000); p = np.sqrt(kT) * rng.standard_normal(20000); dt = min(0.01, 0.1 / zeta)
T = 20.0
for _ in range(int(T / dt)):
p = p - zeta * p * dt + np.sqrt(2 * zeta * kT * dt) * rng.standard_normal(q.size)
q = q + p * dt
print(f"ζ = {zeta:4}: 시간 {T:.0f} 뒤 ⟨q²⟩/(2T) = {np.mean(q**2) / (2 * T):.4f}, kT/ζ = {kT / zeta:.4f}")
# 마찰만 (모멘텀 SGD) : ⟨p²⟩ = 0.000, ⟨q²⟩ = 0.000, 노이즈²/(2ζ) = 0.00
# 노이즈만 : ⟨p²⟩ = 24.714, ⟨q²⟩ = 24.398, 노이즈²/(2ζ) = inf
# 마찰 + 짝이 맞는 노이즈 : ⟨p²⟩ = 1.000, ⟨q²⟩ = 1.001, 노이즈²/(2ζ) = 1.00
# 마찰 0.5 + 마찰 1에 맞춘 노이즈 : ⟨p²⟩ = 1.989, ⟨q²⟩ = 2.023, 노이즈²/(2ζ) = 2.00
# ζ = 0.5: 시간 20 뒤 ⟨q²⟩/(2T) = 1.8120, kT/ζ = 2.0000
# ζ = 5.0: 시간 20 뒤 ⟨q²⟩/(2T) = 0.1963, kT/ζ = 0.2000
# ζ = 50.0: 시간 20 뒤 ⟨q²⟩/(2T) = 0.0201, kT/ζ = 0.0200
마찰만 있으면 식어서 멈추고, 노이즈만 있으면 한없이 뜨거워지며, 노이즈의 분산이 2ζkT일 때만 ⟨p²⟩ = ⟨q²⟩ = kT에 이른다. 노이즈 분산이 2ζkT와 다르면 노이즈²/(2ζ)가 새 온도가 되고, 마찰이 크면 위치의 확산 계수가 아인슈타인 관계 kT/ζ로 간다.
마찰 계수의 양 끝
노이즈 분산 = 2ζkT를 지키면서 마찰 계수를 0이나 아주 큰 값으로 보내면 어떻게 될까? 양 끝에서 익숙한 두 방정식이 나오는데, ζ = 0이면 마찰도 노이즈도 사라져 해밀턴 방정식만 남는다. 에너지를 지키며 등고선을 따라 도는 이 흐름에 HMC는 궤적 사이마다 운동량을 새로 뽑아 무작위성을 넣는데, 운동량을 모두 새로 뽑는 것은 아주 큰 마찰과 그에 맞는 노이즈(분산 2ζkT)가 한순간에 작용해 운동량을 열평형으로 되돌리는 것과 같다. 반대로 ζ가 크면 운동량은 m/ζ의 시간 안에 열평형에 이르고, 그보다 긴 시간 동안 위치만 보면 확산 계수가 kT/ζ인 오버댐프드 랑주뱅 방정식이 된다. 위치에너지 없이 돌려 보면 ζ = 5, 50에서 ⟨q²⟩/(2t)가 0.1963, 0.0201로 kT/ζ = 0.2, 0.02에 가깝다. ζ = 0.5에서는 1.812로 kT/ζ = 2보다 작은데, 운동량을 잊는 시간 1/ζ = 2가 재는 시간 20에 비해 짧지 않아서다. 그리고 노이즈를 0으로 두고 마찰만 남기면 계는 에너지가 가장 낮은 한 점에 멈추는데, 이것이 모멘텀 SGD다. HMC, SGLD, 모멘텀 SGD는 한 방정식에서 마찰과 노이즈를 어떻게 두느냐가 다를 뿐이다.

ML에서: SGHMC
모멘텀 SGD에 노이즈를 더하면 언더댐프드 랑주뱅 방정식이 된다. 첸·폭스·게스트린(2014)은 HMC의 그래디언트를 미니배치로 어림하는 자연스러운 구현이 「제멋대로 나빠질 수 있다」고 보였다. 미니배치 그래디언트의 오차가 운동량에 노이즈로 들어가는데 그 노이즈를 상쇄할 마찰이 없으니, 에너지가 들어오기만 해서 계가 뜨거워지는 것이다. 그들의 처방이 논문 요약의 「노이즈 섞인 그래디언트의 효과를 상쇄하는 마찰 항을 넣은 2차 랑주뱅 동역학」이고, 이 방법을 SGHMC(stochastic gradient Hamiltonian Monte Carlo)라 부른다. 노이즈가 있는 곳에는 그 노이즈 크기에 맞는 마찰이 있어야 한다는 요동-소산 정리를 알고리즘 설계에 그대로 쓴 것이다.
문제 16. 헬스장 회원은 몇 명에서 멈추나
헬스장 회원을 30명 안팎으로 두고 싶은데, 이 헬스장은 매달 회원의 10%가 그만둔다. 한 달권만 파는 옆 헬스장(매달 모두 그만둠)은 매달 30명씩 새로 받아 30명을 유지한다. (가) 옆 헬스장 규칙대로 매달 30명씩 받으면 회원 수는 어디서 멈추는가? (나) 30명을 유지하려면 매달 몇 명을 받아야 하는가?

옆 헬스장이 30명씩 받아서 30명이니까 우리도 30명씩 받으면 30명이죠.

옆은 매달 전부 나가니까 들어온 30명이 곧 회원 수지. 여긴 10%만 나가. 나가는 수 0.1M이 들어오는 30명과 같아야 멈추니까 M = 300이야.

돌려 보니 1년 뒤 215명, 2년 뒤 276명… 300명으로 가네요. 10배예요.

멈추는 곳은 들어오는 수와 나가는 비율로 정해지네요. 그럼 30명을 지키려면 매달 몇 명을 받아야 할까요?

나가는 수 0.1 × 30 = 3명이 들어오는 수와 같아야 하니까 매달 3명이에요. 멈추는 곳은 들어오는 수 ÷ 나가는 비율이고, 나가는 비율이 10분의 1이 되면 들어오는 수도 10분의 1이어야 해요.

선배 과제 코드를 조건이 다른 줄도 모르고 그대로 돌린 셈이네요.
문제 17. 마찰과 노이즈의 짝
손실 U(θ) = θ²/2에 모멘텀 SGD p ← μp − η∇U + (노이즈), θ ← θ + p를 쓴다. μ = 0.9, η = 0.01이다. (가) 표준정규분포에서 샘플을 얻으려고 SGLD처럼 운동량에 √(2η)z를 더하면 θ의 분산은? (나) 맞는 노이즈의 크기는? (다) 미니배치로 어림한 그래디언트에 표준편차 3인 오차가 스텝마다 독립으로 섞여 있다면, 운동량에 더할 노이즈는 얼마여야 하는가? (라) 마찰이 0인 HMC는 어떻게 온도를 맞추는가? (마) 연속 시간의 언더댐프드 랑주뱅 방정식에서 마찰 계수를 ζ = 20(m = kT = 1)으로 키우면, 위치만 보았을 때 확산 계수는 얼마이고 무엇이 되는가?

SGLD에서 √(2η)였으니까 모멘텀 버퍼에 √(2η)z를 더했어요. 목표 분산이 1인데… 10.0이 나왔어요. 온도가 10배예요!

모멘텀이 있으면 마찰이 달라지잖아. μ = 0.9면 한 스텝마다 운동량의 10%만 깎이니까 마찰이 0.1이야. SGLD는 한 스텝마다 운동량이 한 번에 모두 사라지는, 마찰이 1인 경우고.

헬스장이랑 같네. 한 스텝에 10%만 빠지는데 전부 빠지는 SGLD 규칙대로 넣었으니 10배가 된 거야.

운동에너지가 들고 나는 셈으로 따져 보세요.

운동에너지가 들고 나는 거면… 마찰이 빼내는 양은 마찰에 비례하고, 노이즈가 넣는 양은 노이즈의 분산에 비례하겠네요.

둘이 같아지는 곳이 평형이죠. 그때 온도는요?

노이즈 분산 ÷ (2 × 마찰 × η)예요. (가)에 넣으면 2η ÷ (2 × 0.1 × η) = 10, 딱 맞아요.

그럼 노이즈를 얼마로 줄여야 해?

마찰에 맞추려면 노이즈의 분산이 2 × 0.1 × η여야 하니까, 표준편차가 √(2(1 − μ)η) = 0.0447이야.

0.0447로 바꾸면… 1.008이에요! 모멘텀을 쓰면서도 샘플러가 되네요. 모멘텀 SGD에서 한 스텝마다 넓이가 0.9배로 줄던 게 수렴하는 이유였는데, 이번엔 그만큼을 노이즈로 채워 줘야 하는 거네요.

(다)로 가 볼까요? 미니배치 그래디언트의 오차도 η배 되어 운동량에 들어가요.

오차 표준편차 3에 η를 곱하면 0.03, 분산 9 × 10⁻⁴가 스텝마다 운동량에 이미 들어가요.

그럼 노이즈는 얼마나 더 넣어야 하죠?

마찰 0.1에 맞는 노이즈의 분산은 2 × 0.1 × 0.01 = 0.002니까, 더 넣을 것은 0.002 − 0.0009 = 0.0011, 표준편차 0.0332예요.

미니배치 노이즈를 빼지 않고 0.0447을 그대로 넣었더니 분산이 1.45예요. 0.0332로 바꾸니 1.002고요. 들어오는 노이즈는 어디서 오든 다 세어야 하네요. 첸·폭스·게스트린이 SGHMC에서 맞춘 게 바로 이거였구나.

물탱크 같네요. 수도꼭지로 물이 일정하게 들어오고, 바닥 구멍으로는 물 높이에 비례해서 빠지는 거요. 구멍을 키우면 수도꼭지도 같은 비율로 더 열어야 물 높이가 그대로고요.

그래요. 물 높이가 온도, 구멍이 마찰, 수도꼭지가 노이즈예요. 저항기의 열잡음도 같아요. 저항값이 크면 전하의 흐름을 더 많이 막고, 그만큼 노이즈 전압의 분산도 커요. (라)로 가 볼까요? HMC는 궤적을 따라가는 동안 마찰이 0이에요.

운동량을 새로 뽑잖아요. 아, 볼츠만 분포 배울 때 운동량을 온도 4짜리 정규분포에서 뽑았더니 위치 분산이 3.95로 운동량 쪽 온도를 따라갔던 거!

운동량을 새로 뽑는 건 마찰이 무한대인 한순간이야. 옛 운동량은 모두 사라지고 그 마찰에 맞는 노이즈로 새 운동량이 채워지는 거지. 그러니까 새로 뽑는 분포의 온도가 곧 노이즈의 온도고, 위치는 그 온도를 따라가.

HMC는 궤적 사이에서만 마찰과 노이즈가 한꺼번에 작용하는 언더댐프드 랑주뱅이에요. 궤적 동안에는 마찰이 없으니 에너지를 지키며 멀리 가고요. (마)는요?

마찰이 크면 운동량은 m/ζ = 0.05 만에 열평형이 되겠네요. 그보다 긴 시간 동안 위치는…

위치만 보면 어떻게 퍼지죠? 확산 계수로 말해 봐요.

확산 계수 kT/ζ = 0.05로 퍼져요.

돌려 보니 0.0495예요.

그럼 오버댐프드 랑주뱅인 SGLD가 이 극한이네요. 문제 7의 알갱이도 m/ζ가 58나노초라 마찰이 큰 끝, 곧 오버댐프드 쪽에 있었고요.

그럼 마찰 하나로 전부 줄 세울 수 있겠네요. 마찰 0에 가끔 운동량을 새로 뽑으면 HMC, 적당하면 SGHMC, 크면 SGLD, 노이즈를 0으로 두면 모멘텀 SGD랑 경사하강이요.

모두 한 방정식이에요. 그리고 어느 자리에 있든, 노이즈를 넣으면 그에 맞는 마찰이, 마찰이 있으면 그에 맞는 노이즈가 있어야 원하는 온도가 나와요.