콘텐츠로 이동

ML 수학 토대

분류: Layer 11 - AI 기초 & 머신러닝 | 선수지식: 학부 1학년 수준 선형대수/확률/미적분

ML 수학 토대 — 벡터, 확률, gradient

섹션 제목: “ML 수학 토대 — 벡터, 확률, gradient”

ML 수학 토대는 데이터를 표현하는 선형대수, 불확실성을 다루는 확률, 개선 방향을 알려주는 미적분의 세 갈래로 이뤄지며, 모델 학습의 모든 단계에 공통으로 깔린다.

LLM이든 분류 모델이든, 학습은 본질적으로 다음 세 가지의 반복이다.

  1. 입력을 벡터·행렬로 변환한다 — 선형대수
  2. 출력 분포를 추정한다 — 확률
  3. 손실의 기울기를 따라 가중치를 갱신한다 — 미적분

수학적 토대가 없으면 다음이 어렵다.

  • 모델 디버깅: 손실 발산(NaN, exploding gradient), 수렴 정체의 원인 추론
  • 비용 직관: 모델 차원·컨텍스트 길이가 메모리/비용에 어떻게 들어가는지
  • 출력 해석: logit · softmax · cross-entropy의 관계
  • 논문 흡수 속도: 새 기법이 수식으로 표현될 때 핵심 직관 빠르게 잡기

운영자 관점에서는 “이 모델이 왜 이렇게 비싼가/느린가”를 행렬 크기 단위로 분해할 수 있어야 한다. 후속 토픽 L11-50(트랜스포머)·L12-70(LLM 비용·지연)에서 같은 직관을 반복해 확장한다.

2.5 왜 이 세 갈래로 수렴했나 — 수학 토대의 등장 배경

섹션 제목: “2.5 왜 이 세 갈래로 수렴했나 — 수학 토대의 등장 배경”

선행 시기 (2012 이전): 컴퓨터 비전·자연어 처리는 hand-engineered feature(SIFT·HOG·n-gram TF-IDF) + SVM·Random Forest 같은 classical learner의 조합이 표준이었다. 이 시기 운영자에게 “모델 비용”이라는 개념은 거의 의미가 없었다 — 모델이 작고 inference가 CPU에서 끝났으며, feature 추출은 도메인 전문가의 손작업이었기 때문이다. 새 모델 도입은 점진적이었고 (ImageNet 2010~2011 top-5 error 28% → 26%) 운영 의사결정의 폭이 좁았다.

전환점 (2012 AlexNet): AlexNet이 ImageNet top-5 error를 26% → 15.3%로 한 번에 10.8%p 줄이면서 deep learning이 폭발했다 (AlexNet — Wikipedia). 이때부터 모델은 (a) GPU에서 행렬 곱으로 forward, (b) softmax로 분포 출력, (c) gradient descent로 학습이 표준이 됐다. 즉 운영자가 보는 모든 비용·정확도·실패 신호가 행렬 곱·확률·미분의 언어로 환원됐다 — feature 디자이너가 사라진 자리를 수학 직관이 대신한다.

이 토픽이 채우는 빈자리: 수학 직관 없이 LLM을 운영하면 세 가지 실패가 정기적으로 일어난다.

  1. KV cache 산정 오류 → num_kv_heads(GQA) 착각으로 GPU 용량이 4× 틀어진다 (§5)
  2. fp16 학습 NaN → softmax 안전화 누락으로 1~10k step 후 갑자기 loss 발산 (§3.3)
  3. 임베딩 차원·비용 결정 부재 → 1536d vs 256d trade-off를 정량화 못 해 storage·검색 비용 6× 과지출 (§3.1)

세 실패 모두 §3.1~§3.4의 같은 토대(행렬 곱·softmax·gradient)로 분해된다. 이 토픽이 사라지면 L11-50(트랜스포머)·L12-70(LLM 비용·지연)의 모든 권고가 “왜 그래야 하는지” 없는 마법이 된다.

다른 도메인에서도 같은 원리: 정보 검색(TF-IDF·BM25)의 코사인 유사도, 추천 시스템(item-item·SVD)의 inner product, 신호 처리(FFT는 본질적으로 unitary 행렬 곱)는 모두 §3.1의 벡터·내적이 다른 옷을 입은 것이다. ML 수학 토대를 잡으면 검색·추천 운영 결정도 같은 도구로 분해 가능하다.

벡터는 가장 단순하게 보면 number[]다. 다만 ML에서 벡터는 단순 배열이 아니라 방향과 크기를 함께 가지는 좌표다. 임베딩 모델은 단어·문장·이미지·사용자 같은 객체를 고차원 벡터로 변환하고, 모델은 이 벡터의 거리·각도를 계산해 의미를 다룬다.

"고양이" -> [ 0.21, -0.18, 0.55, ..., 0.07] # 1536차원 임베딩
"강아지" -> [ 0.19, -0.20, 0.58, ..., 0.05] # 비슷한 위치
"비행기" -> [-0.42, 0.71, 0.03, ..., -0.31] # 멀리 떨어진 위치
  • L1 norm: 절댓값의 합. |x_1| + |x_2| + ... + |x_n|
  • L2 norm (유클리드 노름): 제곱합의 제곱근. sqrt(x_1^2 + x_2^2 + ... + x_n^2)
  • 유클리드 거리: 두 벡터 차의 L2 norm
  • 코사인 유사도: 두 벡터의 내적을 두 노름의 곱으로 나눈 값. 방향만 보고 크기는 무시한다
cos(a, b) = (a · b) / (||a||_2 * ||b||_2)
범위: -1 ~ 1 (1: 같은 방향, 0: 직교, -1: 반대 방향)

ML에서 코사인 유사도가 자주 쓰이는 이유: 벡터 크기가 다른 두 임베딩(긴 문장 vs 짧은 문장)이라도 의미 방향을 비교할 수 있기 때문이다.

  • 계산적 의미: 같은 자리 곱의 합. a · b = sum(a_i * b_i)
  • 기하학적 의미: 두 벡터 길이의 곱 × 두 벡터가 이루는 각의 코사인. a · b = ||a|| * ||b|| * cos(theta)

이 둘이 같은 값이라는 사실이 attention의 핵심 직관 중 하나다. attention은 본질적으로 query와 key의 내적이고, 이는 “둘이 얼마나 같은 방향을 보는가”의 측정값이다.

벡터의 길이 = 차원. 임베딩 차원이 클수록 표현력은 늘지만 메모리·연산 비용도 같이 늘어난다.

모델 예시임베딩 차원
OpenAI text-embedding-3-small1536
OpenAI text-embedding-3-large3072
Cohere embed-v31024
BGE-large1024

차원 1을 늘리는 비용 = (벡터 1개당 바이트 × 벡터 개수). fp32(4바이트) 가정 시 1억 개 임베딩에서 차원 1을 늘리면 약 400MB 추가. fp16(2바이트)이나 int8(1바이트) 저장이면 비례해 줄어든다. text-embedding-3-large는 dimensions 파라미터로 256~3072 사이 임의 차원 축소가 가능하다 (Matryoshka representation — 앞부분 차원만 잘라도 의미가 보존되도록 학습됨). OpenAI 공식 발표에 따르면 256차원으로 줄여도 ada-002의 풀 1536차원보다 MTEB 점수가 높다 (OpenAI, 2024). 운영 결정으로 환산하면, 같은 의미 품질을 6× 작은 storage·6× 빠른 ANN 검색으로 얻을 수 있다는 뜻.

벡터가 점이라면, 행렬은 벡터를 다른 벡터로 변환하는 함수다. 다만 이 함수는 선형이라는 제약이 있다 — 입력에 비례해서 출력이 변한다.

y = W x
x: 입력 벡터 (n차원)
W: 가중치 행렬 (m × n)
y: 출력 벡터 (m차원)

신경망의 한 층은 본질적으로 y = W x + b 다. JavaScript로 풀어쓰면:

function denseLayer(x: number[], W: number[][], b: number[]): number[] {
const y = new Array(W.length).fill(0);
for (let i = 0; i < W.length; i++) {
for (let j = 0; j < x.length; j++) {
y[i] += W[i][j] * x[j];
}
y[i] += b[i];
}
return y;
}

GPU는 이 이중 for문을 수천~수만 개 코어가 동시에 처리하고, tensor core가 같은 가중치 데이터를 재사용해 메모리 트래픽을 줄인다. ML에서 GPU가 압도적인 이유는 단순 병렬성만이 아니라 데이터 재사용·메모리 계층 최적화의 결합이다.

  • Transpose (전치): 행과 열을 바꾼다. W^T[i][j] = W[j][i]
  • 역행렬: W * W^(-1) = I. 단 모든 행렬에 존재하지는 않는다 (정방행렬 + 가역).

ML에서는 역행렬을 직접 계산하는 일이 드물다. 가중치 행렬은 보통 정방이 아니고, 역행렬 계산은 비싸다(O(n^3)). 대신 gradient 기반 학습으로 접근한다.

트랜스포머 self-attention은 본질적으로 다음 행렬 곱이다.

Attention(Q, K, V) = softmax(Q K^T / sqrt(d_k)) V
Q: query 행렬 (n × d_k)
K: key 행렬 (n × d_k)
V: value 행렬 (n × d_v)

Q K^T는 모든 query·key 쌍의 내적이다. 즉 “각 토큰이 다른 모든 토큰과 얼마나 같은 방향을 보는가”의 표를 만든다. 이 표를 softmax로 정규화하면 attention weight가 된다.

sqrt(d_k)로 나누는 이유: Q와 K 원소의 평균이 0·분산이 1이라면 Q K^T의 분산은 d_k에 비례해 커진다. 분산이 크면 softmax가 saturate(거의 0/1로 수렴)해 gradient가 사라진다. sqrt(d_k)로 나누면 분산이 1 근처로 정규화되어 학습이 안정된다. 이게 d_head를 너무 크게 만들지 않는 이유다.

이 한 식이 LLM 비용·메모리의 절반을 결정한다. n(시퀀스 길이)이 늘면 Q K^T의 크기는 n²로 커지고, 이게 KV cache·long-context 비용의 출처다.

확률은 모델 출력의 언어다. 분류 모델이 “고양이 80%, 강아지 15%, 그 외 5%“라고 말할 때, 이 숫자들은 합이 1인 확률 분포다. LLM이 다음 토큰을 예측할 때도 어휘 전체에 대한 확률 분포를 출력한다.

  • Bernoulli: 두 결과 중 하나 (성공/실패). p 하나로 결정
  • Categorical: 여러 결과 중 하나. LLM 다음 토큰 예측이 여기 해당
  • Normal (Gaussian): 종 모양. 가중치 초기화·노이즈 모델링에 흔히 등장
  • Uniform: 모든 값이 같은 확률. 무작위 초기화의 한 형태
  • 기댓값: 분포의 “평균 위치”. E[X] = sum(x * P(x))
  • 분산: 분포의 “퍼진 정도”. Var[X] = E[(X - E[X])^2]
  • 표준편차: 분산의 제곱근. 단위가 X와 같아 해석이 직관적

ML에서 자주 쓰이는 곳:

  • batch normalization: 미니배치의 평균·분산을 정규화한다
  • gradient 분산이 크면: 학습이 불안정. 학습률을 줄이거나 gradient clipping을 적용한다

조건부 확률은 다음 LLM 식의 핵심이다.

P(다음 토큰 | 지금까지의 컨텍스트)

LLM은 본질적으로 이 조건부 확률을 추정하는 거대한 함수다. 학습 과정에서 모델은 다음 토큰의 분포를 잘 맞히도록 가중치를 조정한다.

분류 모델 출력층에 흔히 쓰이는 함수.

softmax(z_i) = exp(z_i) / sum_j exp(z_j)

특징:

  • 모든 출력이 양수 (exp 덕분)
  • 합이 1 (정규화)
  • 큰 값을 강조 (지수 함수의 효과)

LLM 샘플링에서 자주 보는 temperature 파라미터는 softmax 입력을 나눈다.

softmax(z / T)
T가 작을수록 (T=0.1 등): 분포가 뾰족 → 결정적 출력
T가 클수록 (T=2.0 등): 분포가 평평 → 다양성 증가

Softmax 안전 구현 — Log-Sum-Exp trick

섹션 제목: “Softmax 안전 구현 — Log-Sum-Exp trick”

exp(z_i)는 큰 logit에서 overflow를 일으킨다. fp16의 표현 가능 최댓값은 65,504인데 exp(11) ≈ 59,874, exp(12) ≈ 162,754라 z > 11이면 inf가 된다. 표준 트릭은 모든 logit에서 최댓값을 빼고 시작한다.

softmax(z_i) = exp(z_i - max_z) / sum_j exp(z_j - max_z)

수학적으로 같은 값이지만 수치 안정성이 크게 좋아진다. fp16/bf16 학습에서 NaN이 뜨는 흔한 원인 중 하나가 이 안전화 누락이다. Flash Attention 같은 구현은 한 단계 더 나아가 chunk별로 max를 갱신해 메모리도 줄인다 (log-sum-exp 표준 구현, Jay Mody).

언제 깨지는가 (silent failure): 안전화 빠진 커스텀 softmax/loss를 fp16/bf16 학습에 그대로 넣으면, 학습 초기엔 logit이 작아 정상 동작하지만 1k~10k step 이후 logit 분산이 커지면서 갑자기 loss가 NaN으로 튄다. 에러 메시지엔 “loss became NaN”만 남고 위치는 안 알려준다 — 데이터·LR·init를 차례로 의심하다 며칠을 날리는 흔한 패턴이다.

# 진단 — fp16 학습 시 매 100 step마다 logit 범위 모니터
if step % 100 == 0:
print(f"step {step}: logit max={logits.max().item():.1f}, min={logits.min().item():.1f}")
# logit max가 8~10에 도달하기 시작하면 NaN까지 1~2k step 남았다는 신호
# 회복 — 직접 softmax+log를 쓰지 말고 log-sum-exp 안전화된 PyTorch 표준 함수 사용
loss = torch.nn.functional.cross_entropy(logits, target) # log-softmax 내장, 안전
log_probs = torch.nn.functional.log_softmax(logits, dim=-1) # 직접 구현이라면 이걸 쓰기
# 다음 단계: 그래도 NaN이면 mixed precision의 loss scaling 점검 (fp16 underflow 가능성)

두 분포가 얼마나 다른지를 재는 함수. 분류 손실의 표준이다.

H(p, q) = -sum_i p_i * log(q_i)
p: 정답 분포 (보통 one-hot)
q: 모델 예측 분포

직관: 정답이 1로 표시된 곳에서 모델이 낮은 확률을 줬다면 -log(낮은 값)이 큰 값이 되어 손실이 커진다. 정확히 맞췄다면 -log(1) = 0.

LLM 학습 손실은 본질적으로 next-token prediction의 cross-entropy다.

LLM 평가에서 자주 보는 지표. 본질은 exp(평균 cross-entropy)다.

PPL = exp(-1/N * sum_i log P(token_i | context_i))

PPL이 낮을수록 모델이 다음 토큰을 잘 맞힌다는 뜻. PPL=1이면 100% 정확, 어휘 크기 V에 대한 uniform 분포라면 PPL=V (무작위 추측 상한). L11-80(평가/데이터 품질)에서 다시 깊이 다룬다.

미분은 변화율이다. f(x)에서 x를 살짝 늘렸을 때 f(x)가 얼마나 변하는가.

df/dx = lim_{h -> 0} [f(x+h) - f(x)] / h

ML에서 f는 손실 함수이고, x는 가중치다. 즉 “이 가중치를 살짝 늘리면 손실이 얼마나 증가하는가”. 이 정보가 있으면 손실을 줄이는 방향을 안다 — 미분 부호의 반대 방향이다.

다변수 함수 f(x, y, z)에서 한 변수만 미분.

df/dx: y, z를 고정하고 x만 변화

신경망 가중치가 수십억 개라도, 각 가중치는 손실에 대한 부분 미분으로 갱신된다.

모든 부분 미분을 모은 벡터.

∇f = [df/dx_1, df/dx_2, ..., df/dx_n]

기하학적 의미: 함수가 가장 빠르게 증가하는 방향.

학습은 이 방향의 반대로 가중치를 옮기는 과정이다.

w_new = w_old - η * ∇L
η: learning rate (학습률)
∇L: 손실의 gradient

이게 gradient descent의 한 줄 정의다.

  • η가 너무 크면: 손실이 발산 (overshoot)
  • η가 너무 작으면: 학습이 느림
  • 실무 기본값: Adam 계열 일반 학습 1e-4 ~ 1e-3, LLM pre-training peak LR 1e-4 ~ 6e-4, fine-tuning은 더 작게 1e-6 ~ 5e-5

L11-30(ML 패러다임)·L11-90(post-training)에서 SGD/Adam/AdamW의 차이를 다룬다.

함수 합성의 미분 공식.

f(g(x))의 미분 = f'(g(x)) * g'(x)

ML 신경망은 본질적으로 함수 합성이다. y = f3(f2(f1(x))). backprop는 이 체인을 거꾸로 따라가며 각 층의 gradient를 계산한다.

JavaScript 비유:

const a = f1(x);
const b = f2(a);
const c = f3(b);
// 손실 L이 c에서 계산됨
// backprop:
// dL/dc 계산
// -> dL/db = dL/dc * df3/db
// -> dL/da = dL/db * df2/da
// -> dL/dx = dL/da * df1/dx

체인룰은 L11-40(신경망과 backprop)의 수학적 토대다.

신경망 학습에서는 스칼라 손실을 벡터/행렬에 대해 미분한다. 이때 등장하는 것이 야코비안.

야코비안 J: 벡터 함수의 모든 부분 미분을 행렬로 정리한 것
f: R^n -> R^m
J[i][j] = df_i / dx_j

ML 실전에서 자주 쓰는 공식:

y = W x -> dL/dW = (dL/dy) x^T (outer product, W와 같은 모양)
L = y^T y -> dL/dy = 2y
softmax + CE -> dL/dz = q - p (놀랍도록 간단)

마지막 식이 분류 손실의 backprop이 효율적인 이유다 — 복잡해 보이는 두 함수의 합성이 결국 예측 - 정답 한 줄로 떨어진다.

이 수준 이상은 PyTorch가 자동 미분으로 처리한다. 그러나 어떤 식이 어떤 모양을 갖는지 직관이 있으면 모델 디버깅과 새로운 손실 설계에서 큰 도움이 된다.

3.6 새 ML 기법 분석 4질문 체크리스트

섹션 제목: “3.6 새 ML 기법 분석 4질문 체크리스트”

새 ML 알고리즘·LLM 기법을 만났을 때 다음 4질문이 빠른 분석 도구가 된다 — 수학 토대 위에서 작동.

  1. 어떤 벡터·행렬 공간에서 작동하는가? (입력·출력·hidden dim, sparse vs dense)
  2. 어떤 손실·확률 분포를 가정하는가? (MSE/CE/contrastive/preference, Gaussian/categorical)
  3. 어떤 gradient 흐름이 학습을 결정하는가? (체인룰 경로, vanishing/exploding 위험점)
  4. 어떤 행렬 곱이 비용을 결정하는가? (attention O(n²), KV cache, MoE active params)

이 4질문은 logistic regression부터 트랜스포머·LLM 신기법(LoRA, MoE, DPO, GRPO)까지 그대로 적용된다.

§3.2 self-attention에 적용한 결과 (체크리스트 본문 통합 — 추상 도구가 아닌 실제 분해):

  1. 공간: Q·K (n×d_k), V (n×d_v). dense 행렬, 시퀀스 길이 n에 비례
  2. 손실·분포: attention 자체엔 손실 없음. softmax(Q K^T / √d_k)는 categorical 분포 — 각 query마다 n개 key 위 정규화
  3. gradient 경로: softmax → V 곱 → 후속 layer로. softmax saturate 시 vanishing 위험 → 그래서 √d_k scaling이 필수 (§3.2의 분산 정규화 논리와 같은 이유)
  4. 비용 결정 행렬 곱: Q K^T (n × n) — n²로 폭발. 이게 long-context 비용·KV cache(§5)의 출처

같은 4질문을 §3.4 gradient descent에 적용하면 (1) 가중치 공간 차원·sparsity, (2) 손실 함수 종류(MSE/CE/…), (3) 깊이별 vanishing/exploding 위험점, (4) 어떤 행렬 곱이 forward·backward의 병목인지가 자동으로 드러난다. 새 기법(예: LoRA의 low-rank 분해)을 만나면 4질문을 차례로 던지는 게 첫 단계다.

3.7 정량 운영 권장 (자주 쓰는 기준값)

섹션 제목: “3.7 정량 운영 권장 (자주 쓰는 기준값)”
항목권장 시작값깨지는 조건
Adam·AdamW LR1e-4 ~ 3e-4 (LLM pretrain)spike 빈발 시 ↓, 안 떨어지면 warmup ↑
AdamW weight decay0.01 ~ 0.1작으면 overfit, 크면 underfit
Gradient clip norm1.0norm > 1e3 빈번 시 ↓
Mixed precisionbf16 (H100/A100) > fp16bf16 미지원 GPU(예: T4)에선 fp16 + loss scaling
임베딩 차원384 ~ 1024 (검색 default)도메인 좁으면 256으로 충분 (Matryoshka)
Cosine 임계 유사도0.7 (검색 컷오프)도메인·모델별. anisotropy 확인 후 조정

이 기준값은 시작점이지 정답 아님. validation curve로 sweep하는 게 표준.

표가 본문 결정으로 어떻게 쓰이는가 (Adam LR 사례):

  • 8B fine-tuning을 LR=1e-3으로 시작 → step 200쯤 loss spike가 100 step당 4회, gradient norm 50 → 800 점프 관측
  • 표의 “spike 빈발 시 ↓” 규칙 → LR을 1e-4로 내려 재시작 + gradient clip 1.0 유지 + warmup 200 step 추가
  • 결과: 같은 step 수에서 spike 0회, val loss는 5% 더 낮음
  • 표 없이 이 결정이 안 이뤄지면: spike를 데이터 품질 문제로 오진해 데이터 클렌징·필터링에 며칠을 쓴다. 표의 가치는 “먼저 LR을 의심하라”는 우선순위 신호 자체.
  • 임베딩 검색: 코사인 유사도로 가까운 문서 찾기 (L12-30 vector ops)
  • Attention: 트랜스포머의 핵심 행렬 곱 (L11-50)
  • Softmax & Cross-Entropy: 분류 손실, LLM 다음 토큰 예측
  • Gradient Descent: 모든 학습의 기본 알고리즘
  • Batch Normalization / Layer Normalization: 학습 안정화. 트랜스포머는 시퀀스 길이 가변·작은 batch 환경이라 BN이 아니라 LN(또는 LLaMA 계열의 RMSNorm)을 쓴다. inference batch=1에서도 같은 결과가 나오는 이유다
  • Quantization 직관: 행렬을 적은 비트로 표현해 메모리 절감 (L12-70 LLM 비용)
  • Cost 견적: 모델 차원·시퀀스 길이로 메모리/연산량 추정

운영 시나리오 — 한국어 챗봇 팀 (사고실험)

섹션 제목: “운영 시나리오 — 한국어 챗봇 팀 (사고실험)”

주의: 아래 시나리오는 사고실험이다. 비용·지연 개선 폭은 실측이 아니라 출처 있는 단가·토큰 비율로부터의 추산이며, 실제 도입 시 측정 항목으로 검증해야 한다. 검증된 수치와 추산을 명시적으로 분리한다.

상황: 사내 챗봇 운영, 월 100만 호출, 한국어 80% / 영어 20%
사용 모델: GPT-4o, context 32k, input 평균 4k token
§3.6 4질문으로 분해:
Q1 (공간): 임베딩 1536d (vector store), context 32k 시퀀스
Q2 (분포): 다음 토큰 categorical, system prompt 캐시 적중률이 분포 안정성에 영향 없음(상수)
Q3 (gradient): inference 단계라 학습 gradient 무관. 단, 모델 fine-tune 시 다시 등장
Q4 (비용 행렬 곱): O(n²) attention — n(token 수) 줄이는 게 비용 핵심
검증된 사실 (출처):
- 한국어→영어 토큰 비율 ≈ 2.36× (Anthony Shaw, CJK guide)
- text-embedding-3-large 256d > ada-002 1536d on MTEB (OpenAI, 2024)
- Llama-3-8B 32k KV cache ≈ 4GB (LMCache calculator)
추산 (실측 아님 — 도입 시 검증 필요):
- 영어 system + 한국어 user 전환 시 system 영역 토큰 ~50% 절감 (system 분량 비중·캐시 적중률에 따라 가변)
- 임베딩 256d 전환 시 vector store 메모리·ANN 검색 시간 ~6× ↓ (인덱스 종류·재구축 비용 별도)
- prompt caching 도입 시 cached input 토큰은 GPT-4o 가격표에서 50% 할인 (출처: OpenAI pricing 페이지)
도입 시 측정 항목 (수치 대신 명령):
- tiktoken으로 영어/한국어 system prompt 토큰 카운트 차이 측정
- vector store storage 1536d vs 256d 직접 비교 (`SHOW TABLE STATUS` 등)
- response.usage.prompt_tokens_details.cached_tokens / prompt_tokens 비율 모니터
- p95 latency를 영어 system 적용 전후 A/B

이 시나리오에 §3.1~§3.7 모든 수학 직관과 §3.6 4질문이 모두 작동한다 — 실제 도입을 위해선 위 측정 항목으로 추산을 검증해야 한다.

플랫폼 엔지니어가 LLM 앱을 운영할 때 수학 직관이 다음에 도움이 된다.

  • KV cache 메모리 추정 (GQA 가정): 2 * num_layers * batch * num_kv_heads * seq_len * d_head * bytes. Llama-3-8B는 GQA로 query head는 32개지만 num_kv_heads=8이므로 KV cache 식엔 8을 넣어야 한다 (Meta Llama-3 model card, LMCache KV calculator 검증). 예: num_layers=32, num_kv_heads=8, d_head=128, fp16(2바이트), batch=1 → per-token 128KB, seq_len=2,048이면 약 256MB/요청, seq_len=32,768이면 약 4GB/요청. MHA로 착각해 num_kv_heads=32를 넣으면 4× 큰 값이 나와 GPU 용량 산정이 틀어진다 (silent failure — 코드는 동작하지만 batch 한도가 비현실적으로 적게 산정됨).

    진단·회복은 모델 config을 직접 읽어 확인한다:

    Terminal window
    # 모델 config에서 실제 num_kv_heads 확인 (HuggingFace transformers 필요)
    python -c "from transformers import AutoConfig; \
    c = AutoConfig.from_pretrained('meta-llama/Meta-Llama-3-8B'); \
    print(f'num_attention_heads={c.num_attention_heads}, num_key_value_heads={c.num_key_value_heads}')"
    # 기대 출력: num_attention_heads=32, num_key_value_heads=8
    # 두 값이 다르면 GQA. KV cache 식엔 num_key_value_heads를 넣어야 한다

    같은 산정 오류가 long-context 운영 사고로 이어진다 — 70B 모델 8k context는 요청당 ~20GB, batch 32면 ~640GB의 KV cache가 필요하다 (Introl — KV Cache Optimization). MHA 착각으로 num_kv_heads를 4배 넣으면 단일 H100에서 batch 4만 돌 거라 결론짓지만, 실제론 16까지 가능 — 캐파 4배를 그냥 버리는 사고.

  • 모델 비용 비교: 7B vs 70B의 10배 차이가 단순 파라미터 수가 아니라 추론 시 메모리·연산에 어떻게 미치는지

  • 임베딩 모델 선택: 1536 vs 3072차원의 비용·성능 trade-off

  • 장애 대응: 손실 NaN, gradient explosion 같은 키워드가 fine-tuning 로그에 등장할 때

  • LLM 추론은 memory-bound: forward pass의 산술 연산보다 가중치 행렬을 GPU 메모리에서 읽는 시간이 더 크다. 그래서 GPU 활용률이 낮게 나오기도 한다. 토큰 throughput을 늘리는 가장 빠른 방법이 batching·KV cache·quantization인 이유 — 모두 메모리 트래픽을 줄이는 기법이다

수학을 깊이 다루지 않더라도, “행렬 크기 = 메모리·비용”이라는 한 줄을 외우는 것만으로도 LLM 운영 의사결정의 절반을 잡는다.

개념 A개념 B차이점
L1 normL2 normL1은 절댓값 합 (sparse 유도), L2는 제곱합 제곱근 (smooth)
내적 (dot product)행렬 곱 (matrix product)내적은 두 벡터 → 스칼라, 행렬 곱은 행렬 → 행렬
도함수편미분도함수는 1변수 함수, 편미분은 다변수 중 1개에 대한 미분
GradientJacobiangradient는 스칼라 함수의 1차 편미분 벡터, Jacobian은 벡터 함수의 부분 미분 행렬
logitprobabilitylogit은 임의 실수 (softmax 입력), probability는 [0,1] 정규화 결과
Cross-entropyKL divergenceCE = H(p) + KL(p‖q). 학습 시 H(p)는 상수라 CE 최소화 = KL 최소화
VarianceStandard deviation분산은 제곱 단위, 표준편차는 원래 단위와 같아 해석이 쉬움
  • 임베딩이 왜 “벡터”인지, 코사인 유사도가 무엇을 재는지 설명할 수 있다
  • 신경망 한 층에서 행렬 곱 y = W x + b가 왜 등장하는지 설명할 수 있다
  • Softmax가 어떤 성질(양수, 합 1)을 만족하는지, temperature가 왜 분포를 평평하게 만드는지 설명할 수 있다
  • Cross-entropy가 무엇을 재는지, 왜 분류 손실의 표준인지 설명할 수 있다
  • Gradient가 왜 “가장 빠른 증가 방향”이고, 왜 그 반대로 가는지 설명할 수 있다
  • 체인룰이 backprop의 핵심인 이유를 함수 합성 관점에서 설명할 수 있다
  • Attention의 Q K^T가 어떤 의미를 갖는지 내적 관점에서 설명할 수 있다
  • 선형대수: SVD, eigendecomposition, rank, null space, tensor
  • 확률: Bayes 정리, MLE, MAP, KL divergence, Jensen 부등식, entropy
  • 미적분: Taylor 전개, Hessian, 2차 최적화 (L-BFGS), convex/non-convex
  • ML 특화: gradient clipping, learning rate schedule, mixed precision, AdamW, Lion
  • numpy로 두 임베딩 벡터의 코사인 유사도 계산. 예상: 같은 의미 단어쌍은 0.7+, 무관쌍은 0.3 이하
  • PyTorch에서 nn.Linear(10, 5)의 가중치 shape이 (5, 10)인 이유를 행렬 곱 관점에서 설명. 예상: y = W·x에서 출력 5 = 행, 입력 10 = 열
  • 손으로 2-2-1 신경망 forward pass를 행렬 곱으로 풀이. PyTorch 결과와 매치 확인
  • PyTorch에서 loss.backward() 호출 후 param.grad shape 출력. 예상: 가중치와 같은 모양
  • OpenAI 임베딩 API로 단어 5개 임베딩 → 코사인 유사도 행렬. 예상: 동의어쌍 > 반의어쌍 > 무관쌍

    풀 실행 스크립트 (Python 3.10+, pip install openai numpy, OPENAI_API_KEY 환경변수 필요):

    import os
    import numpy as np
    from openai import OpenAI
    client = OpenAI()
    words = ["고양이", "강아지", "비행기", "자동차", "기차"]
    resp = client.embeddings.create(
    model="text-embedding-3-small",
    input=words,
    )
    vecs = np.array([d.embedding for d in resp.data]) # shape: (5, 1536)
    # L2 정규화 후 dot product = cosine similarity
    vecs = vecs / np.linalg.norm(vecs, axis=1, keepdims=True)
    sim = vecs @ vecs.T # (5, 5)
    print(" " + " ".join(f"{w:>4}" for w in words))
    for i, w in enumerate(words):
    print(f"{w:>4} " + " ".join(f"{sim[i, j]:+.2f}" for j in range(len(words))))

    예상 출력 (대각선은 1.00, 같은 카테고리쌍이 0.4+, 무관쌍은 0.2 근방):

    고양이 강아지 비행기 자동차 기차
    고양이 +1.00 +0.55 +0.18 +0.21 +0.20
    강아지 +0.55 +1.00 +0.20 +0.23 +0.21
    비행기 +0.18 +0.20 +1.00 +0.46 +0.43
    자동차 +0.21 +0.23 +0.46 +1.00 +0.51
    기차 +0.20 +0.21 +0.43 +0.51 +1.00

    결과 해석 가이드:

    • 모두 0.9+로 동질하게 나옴 → anisotropy 의심. text-embedding-3-large 또는 contrastive 학습된 모델로 교체
    • 동물·교통수단 클러스터 경계가 흐림 → dimensions=256으로 줄여 noisy 차원 제거 후 재실행
    • 다음 단계: dimensions 파라미터를 256·512·1024로 바꿔가며 동일 행렬 출력 → 의미 분리도가 어디서 무너지는지 sweep
  • LLaMA-3-8B context 2k/8k/32k에서 KV cache 메모리(torch.cuda.memory_allocated()) 비교 — §5의 0.125MB/token 식과 일치하는지 (예상: 2k≈0.25GB, 32k≈4GB)

  • gradient norm을 매 step 출력. 예상: 정상 학습은 0.1~10 범위, 1e3 넘으면 explosion 신호 → clip 작동 확인

  • 코사인 유사도가 모두 0.9+로 비슷 → anisotropy. 임베딩 모델 변경 또는 contrastive 학습된 모델 사용
  • KV cache 메모리가 식보다 큼 → batch size 또는 num_kv_heads 잘못 (GQA 미반영) 점검
  • gradient norm 폭주 → learning rate↓, gradient clip↓, warmup 길이↑ (3.7 정량 표 참고)
  1. 선형대수는 데이터를 벡터·행렬로 표현하고, 신경망의 한 층은 본질적으로 행렬 곱이다.
  2. 확률은 모델 출력의 언어다 — softmax로 분포를 만들고 cross-entropy로 손실을 잰다.
  3. 미분은 학습의 방향을 알려준다 — gradient의 반대로 가는 것이 학습이다.
  4. 체인룰은 함수 합성의 미분 공식이고, backprop의 수학적 토대다.
  5. 이 셋이 없으면 ML은 검은 상자, 있으면 디버깅 가능한 시스템이다.

최종 수정: 2026-04-26