고차원 심플렉스: 5만 면 주사위의 세계
삼각형 위에서는 어느 점이 가운데이고 어느 점이 가장자리인지 눈으로 보인다. 칸이 5만 개로 늘어나도 그 감각이 통할까?
실제 언어 모델의 “다음 토큰” 분포는 면이 수만~수십만 개인 주사위다. 어휘가 5만 개라면, 그 심플렉스는 49,999차원의 초삼각형이다. 합이 1이라는 약속 하나가 차원 하나를 가져간다.
안쪽은 얼마나 넓은가
눈에 보이는 세 칸짜리 삼각형에서 먼저 재 보자. 모든 칸이 균등값 1/3의 절반, 곧 1/6 이상인 점들을 "안쪽"이라고 부르자. 어느 칸도 유난히 작지 않은, 한가운데 근처의 분포들이다. 이 영역은 한가운데에 거꾸로 놓인 작은 삼각형이고, 넓이는 전체의 4분의 1이다. 삼각형 위에 점을 고르게 뿌리면 넷 가운데 하나꼴로 안쪽에 떨어진다.
칸이 n개여도 같은 셈을 할 수 있다.
모든 칸에서 1/(2n)을 덜어 내면 남은 몫의 합이 1/2이 되므로, 안쪽은 심플렉스를 가로세로 절반으로 줄인 모양이다. (n − 1)차원 도형을 절반으로 줄였으니 부피는 (1/2)n−1배다. 칸이 하나 늘 때마다 안쪽의 몫이 절반으로 준다. 칸이 넷이면 8분의 1, 다섯이면 16분의 1이고, 5만 칸이면 10−15051 정도다. 고르게 찍은 점은 거의 틀림없이 안쪽 밖, 곧 어느 한 칸이 유난히 작은 쪽에 떨어진다. 부피가 이렇게 한쪽 얇은 층에 쏠리는 현상을 측도(여기서는 부피)의 집중이라 부른다.
서울역 대합실을 떠올려 보자. 사람들은 한가운데가 아니라 벽을 따라, 기둥 옆에 서 있다. 그렇다면 사람들이 구석에 몰려 있다는 뜻일까? 벽 가까이 있는 것과 구석에 있는 것은 같은 일일까? 고차원 심플렉스에서 이 물음은 생각보다 까다롭다. 아래 문제에서 직접 재 본다.
파이썬
import numpy as np
rng = np.random.default_rng(0)
xy = rng.random((400_000, 2)) # 정사각형에 고르게 뿌린 뒤
xy = xy[xy.sum(axis=1) <= 1] # 대각선 아래 반쪽만 남기면 삼각형 위에 고르다
p = np.column_stack([xy, 1 - xy.sum(axis=1)]) # (p1, p2, p3), 합 1
inner = (p >= 0.5 / 3).all(axis=1) # 모든 칸이 균등값 1/3 의 절반 이상
print("점의 개수 :", len(p))
print("안쪽 영역의 비율 :", round(inner.mean(), 4), " (1/2)^(n-1) =", 0.5 ** 2)
print("5만 칸이면 : 10 의", round((50_000 - 1) * np.log10(0.5), 1), "제곱")
# 점의 개수 : 199935
# 안쪽 영역의 비율 : 0.2496 (1/2)^(n-1) = 0.25
# 5만 칸이면 : 10 의 -15051.2 제곱
세 칸에서는 정사각형의 반쪽을 삼각형으로 옮기는 간단한 방법으로 점을 고르게 뿌릴 수 있었고, 안쪽의 몫이 식대로 4분의 1이 나왔다. 칸이 많아지면 이 방법은 그대로 쓸 수 없다. 많은 칸에서 점을 고르게 뽑는 법은 아래 문제에서 따진다.
수확
“칸이 많아질수록 심플렉스의 부피는 거의 다 한가운데에서 멀리, 어느 한 칸이 유난히 작은 쪽에 있다.” 그 쪽이 어떤 가장자리인지는 따로 물어야 한다.
5만 차원의 삼각형 위에 점 하나를 찍었다. 점은 찍었다. 그런데 두 점이 “가깝다” 또는 "멀다"는 것은 어떻게 아는가? 삼각형 위에서 자를 대야 한다. 어떤 자를?
문제 9. 고르게 찍은 점의 가장 작은 칸 (킬러)
결과가 n개인 심플렉스 위에서 점을 고르게(균등하게) 하나 뽑는다. (가) 가장 작은 칸 min pᵢ의 기댓값이 n에 따라 어떻게 줄어드는지 구하라. (나) 이 결과를 "고차원 심플렉스의 점은 대부분 꼭짓점 근처에 있다"는 말과 비교하라. (다) numpy로 확인할 때 표본을 어떻게 뽑아야 하는가?
함께 풀기

바로 돌렸어요. p = rng.random(n) 뽑아서 합으로 나누고 min을 평균냈어요. n = 3이면 0.153이고, n = 1000이면 2.0 × 10⁻⁶이에요. n² 곱하면 2쯤 되니까 1/n²에 비례하는 것 같아요. 답은 2/n²?

나는 손으로 했는데 1/n²이 나왔어. 계수가 달라.

둘 중 하나는 “고르게” 뽑지 않았어요. 민준 학생, n = 3에서 칸 세 개를 따로 0과 1 사이에서 뽑고 합으로 나누면, 삼각형 위에 점이 고르게 뿌려질까요?

음… 정육면체 안의 점을 원점에서 대각선 쪽으로 쏘아서 삼각형에 찍는 거니까, 그 방향으로 정육면체가 얼마나 긴지에 따라 밀도가 달라지겠네요. 가운데 방향이 제일 길어요.

그래서 가운데가 진하고 변 근처가 옅어요. min이 부풀려진 거예요.

심플렉스 위에 점을 뿌리는 디리클레 분포, rng.dirichlet(np.ones(n))로 다시 뽑으니까 n = 3에서 0.111, n = 1000에서 n² 곱한 값이 1.00이에요. 정확히 1/n²이네요.

설문지 표본을 역 앞에서만 받아 놓고 "국민 여론"이라고 보고서 쓴 거랑 같은 실수였어요. 뽑는 방법이 이미 답을 기울여 놨어요.

서연 학생은 어떻게 1/n²을 얻었어요?

서로 독립인 지수분포 n개를 뽑아서 합으로 나누면 심플렉스에서 균등한 점이 돼요. 지수분포는 기다리는 시간처럼 밀도가 e−x 꼴로 줄어드는 분포예요. 지수분포 n개의 최솟값은 평균이 1/n인 지수분포고, 합은 평균이 n이에요. 그래서 대략 (1/n)/n = 1/n²이에요.

"대략"이라고 했는데, 정확히는요?

나눗셈의 기댓값을 기댓값끼리 나누면 보통은 안 되는데… 여기서는 돼요. 합으로 나눈 벡터 p는 합 자체와 독립이라서, E[뽑은 값의 최솟값] = E[min pᵢ] × E[합]이 정확히 성립해요. 1/n = E[min pᵢ] × n이니까 정확히 1/n²이에요. 민준이 디리클레 결과랑도 맞고요.

좋아요. 그럼 (나)는요?

가장 작은 칸이 1/n²으로 0에 붙으니까, 점이 거의 늘 가장자리에 있다는 뜻이에요. 그러니까 "꼭짓점 근처"라는 말이 맞아요.

꼭짓점에 가깝다는 건 어떤 분포예요?

한 칸이 거의 1인 분포요.

민준 학생, 가장 큰 칸의 평균도 찍어 봐요.

n = 1000에서 0.0075예요. 1이 아니라 1000분의 7.5요.

가장 큰 칸도 1/n의 몇 배 수준이에요. 꼭짓점 근처가 전혀 아니에요.

가장자리가 두 종류였어요. 한 칸이 0에 가까우면 “면” 근처고, 한 칸만 빼고 다 0이어야 “꼭짓점” 근처예요. 고르게 뽑은 점은 모든 칸이 1/n 정도인데 그중 몇 칸이 아주 작아서, 면에는 붙어 있지만 꼭짓점과는 멀어요.

그래요. 안쪽의 몫이 (1/2)n−1이라고 했죠. 그것도 확인해 봐요.

n = 10이면 0.00195예요. 디리클레로 백만 개 뽑아 세어 보니 0.00201이고요. 열 칸만 돼도 안쪽은 거의 비어 있어요.

그래서 서울역 사람들이 벽을 따라 서 있어도 구석에 몰린 건 아니었군요. 수업에서 고차원 공의 부피가 거의 다 껍질에 있다는 걸 배웠을 때도, 그게 "북극점 근처"라는 뜻은 아니었어요. 껍질은 넓고 북극점은 좁으니까요.

두 사람이 다른 곳에서 넘어졌어요. 민준 학생은 "고르게"를 코드로 옮기다가, 서연 학생은 "가장자리"를 말로 옮기다가요. 고차원에서는 이 두 옮김이 모두 위험해요. 그래서 우리는 자가 필요해요. 가깝다, 멀다를 말로 하지 않고 재기 위해서요.
문제 10. 첫 loss로 보는 출발점
어휘가 5만 개인 언어 모델의 출력은 n = 50,000칸 심플렉스의 점이다. (가) 학습 전 모델의 로짓이 모두 0이면 출력은 심플렉스의 어디이고, 첫 loss(정답 토큰에 준 확률의 −ln)는 몇 nat인가? (나) 마지막 층을 잘못 초기화해 로짓이 표준편차 5인 정규분포처럼 흩어졌더니, 첫 loss가 평균 22 nat쯤으로 나왔다. 이 출발점은 심플렉스의 어디쯤인가? (다) 로짓 0, 표준편차 5, 문제 9처럼 고르게 뽑은 점, 이 세 출발점을 한가운데·면 근처·한 꼭짓점 쪽으로 가르고, 가장 큰 칸으로 확인하라.
함께 풀기

(가)는 소프트맥스에 0을 넣으면 모든 칸이 1/50,000이니까 한가운데예요. loss는 ln 50,000 ≈ 10.82 nat이고요.

(나)는요?

로짓을 무작위로 뽑았으니까 문제 9에서 고르게 뽑은 점이랑 같겠죠. 면 근처요.

고르게 뽑은 점이면 첫 loss가 몇이 나와요? 문제 9에서 쓴 방법으로 뽑아 봐요.

디리클레로 뽑아서 재 보니 11.4쯤이에요. 22가 아니네요. 로짓을 무작위로 뽑는 것과 심플렉스에서 고르게 뽑는 건 다른 일이었어요.

그러면 표준편차 5인 로짓은 점을 어디에 찍죠? 가장 큰 칸을 봐요.

여러 번 뽑아 평균을 내니 가장 큰 칸이 0.38쯤이에요. 5만 칸 가운데 한 칸이 38%를 가져가요.

지수를 씌우니까 로짓 차이가 조금만 벌어져도 확률은 한 칸으로 몰려요. 로짓이 5만 개면 가장 큰 것은 표준편차의 네 배쯤 위에 있고, e를 씌우면 그 칸 하나가 나머지를 압도해요. 한가운데도 면 근처도 아니고, 아무 토큰 하나의 꼭짓점 쪽으로 기울어진 점이에요. 정답이 하필 그 토큰일 리가 거의 없으니 loss가 커요.

(다)로 정리해 봐요.

로짓 0은 가장 큰 칸이 1/n = 0.00002라서 한가운데, 고르게 뽑은 점은 0.00023쯤이라서 면 근처, 표준편차 5는 0.38쯤이라서 한 꼭짓점 쪽이에요.

그래요. 그래서 학습을 돌리기 전에 첫 loss가 ln(부류 수) 근처인지부터 보라는 조언이 널리 쓰여요(카파시(Andrej Karpathy)가 2019년 글에 적은 조언이 잘 알려져 있어요). 출발점이 한가운데에 있는지 확인하는 거예요.

조교님이 채점 스크립트를 돌리기 전에 빈 답안지부터 넣어서 0점이 나오는지 확인하던 거랑 같네요.