콘텐츠로 이동

Module 01 — LLM Fundamentals

학습 목표

이 모듈을 마치면:

  • Define Transformer 의 self-attention, position embedding, FFN 의 역할을 정의할 수 있다.
  • Explain "다음 토큰 확률 예측" 이 어떻게 임의 길이의 텍스트 생성으로 이어지는지 설명할 수 있다.
  • Apply 주어진 시나리오(코드 생성, 요약, 추론) 에 적합한 모델 크기/형태(MoE, Quantization) 를 선택할 수 있다.
  • Decompose Context window, KV cache, batch size 가 latency/throughput 에 미치는 영향을 분해할 수 있다.
  • Evaluate 제품 상황(클라우드 API vs on-prem) 에 맞는 LLM 배포 전략을 평가할 수 있다.

사전 지식

  • Python · NumPy 기본
  • 신경망의 기본 개념 (forward pass, gradient descent)
  • 토큰 / 임베딩 / softmax 라는 단어를 들어 본 적이 있어야 함

1. Why care? — LLM 을 "내부 구조" 로 이해해야 하는 이유

1.1 시나리오 — "왜 같은 모델인데 API 비용이 10 배 차이?"

당신은 같은 LLaMA-2 13B 모델을 두 사용자에게 서비스합니다:

  • 사용자 A: 500-token 요약 작업. 응답 시간 1 초.
  • 사용자 B: 32K-token long-document QA. 응답 시간 30 초, GPU 비용 80 배.

같은 모델인데 왜? 답은 KV cache — LLaMA-2 13B 의 KV cache 는 토큰 당 ~1 MB 입니다 [Introl 2025]. 32K context 면 32 GB 의 GPU 메모리한 sequence 에만. Batch=32 로 운영하면 1 TB.

이게 LLM API 의 가격이 토큰 수에 _제곱 비슷하게 늘어나는_ 정확한 이유:

Context KV cache GPU 1 개에서 batch 가능 수 토큰당 비용
2K 2 GB 16 $0.001
8K 8 GB 4 $0.004
32K 32 GB 1 (또는 multi-GPU) $0.04

비용 cliff 가 KV cache 의 크기에서 기계적으로 나옵니다. Magic 이 아닙니다.

1.2 그래서 이 모듈을 잡아야 한다

이후 모든 모듈 (Prompt / RAG / Agent / Strategy) 은 한 가정에서 출발합니다 — "LLM 은 magic box 가 아니라 자기회귀 토큰 생성기 다". KV cache 메모리가 왜 폭증하는지, context window 가 왜 비싼지, batch 가 왜 throughput 을 결정하는지, MoE 가 왜 "총 파라미터 ≠ 활성 파라미터" 인지 — 모두 이 한 가정의 파생입니다.

이 모듈을 건너뛰면 이후의 prompt/RAG 결정이 "그냥 외워야 하는 best practice" 가 됩니다. 반대로 이 가정을 정확히 잡으면 latency / 비용 / 품질 trade-off 를 만날 때마다 이유 가 보입니다.

🤔 잠깐 — KV cache 메모리는 그렇게 크나?

LLaMA-2 13B 의 토큰 당 1 MB KV cache. 어디에서 오는 수치인지 대략 계산해보세요.

힌트: hidden dim ≈ 5120, 40 layers, K + V 각각, 16-bit floats.

정답

토큰 당 KV cache = 2 × num_layers × hidden_dim × 2 byte = 2 × 40 × 5120 × 2 = 819 KB ≈ 1 MB.

("2 ×" 는 K 와 V 각각, 마지막 "2 byte" 는 fp16/bf16).

그래서 layer 수 + hidden dim + fp16 의 곱이 토큰당 메모리. 모델이 커지면 layer 와 hidden 이 같이 커지므로 KV cache 가 빠르게 늘어남.

이게 GQA / MLA / Flash Attention 같은 최근 모든 추론 최적화 가 "KV 줄이기" 에 집중하는 이유.


2. Intuition — "자기회귀 토큰 생성기" 와 한 장 그림

💡 한 줄 비유

LLM = 매우 빠른 추론 인턴 — 한 글자(토큰) 씩 "가장 likely 한 다음 글자" 를 결정하는 사람.
한 번 호출 = "다음 토큰 1개의 확률 분포 → 샘플링" 의 반복. 글이 자연스러운 이유는 attention 으로 이전 컨텍스트 전체 를 매 step 참조하기 때문.

한 장 그림 — RNN/LSTM 시대 vs Transformer 시대

RNN/LSTM (~2017) — 순차 처리Transformer (2017~) — 모든 쌍 직접 연결R1R2R3R4T1T2T3T4 hidden statehidden state ...
RNN/LSTM (~2017) — 순차 처리Transformer (2017~) — 모든 쌍 직접 연결R1R2R3R4T1T2T3T4 hidden statehidden state ...

세 개의 빨간 원이 Transformer 에서는 모두 사라지고, 대신 attention 행렬 이 토큰 쌍의 관계를 직접 잡습니다.

왜 이렇게 설계됐는가 — 두 순진한 시도가 실패한 결과

Transformer 도 하늘에서 떨어진 게 아닙니다. 두 순진한 시도가 구체적으로 어디서 막혔는지 의 결과물입니다.

시도 1 — "RNN/LSTM 으로 sequence 처리" (1997-2017)

순차적으로 처리하면 자연스럽다. 결과: - Vanishing/exploding gradient: 100+ 토큰 시퀀스에서 학습 불가능 → BPTT 가 깊은 timestep 의 gradient 를 잃거나 폭주. - GPU 병렬화 불가: tᵢ₊₁ 계산이 tᵢ 결과를 기다림 → GPU 의 수천 코어 활용 못함 → 학습 속도 cap. - 장거리 의존성 손실: "100 토큰 전의 그 단어가 지금 토큰을 결정한다" 같은 패턴 학습 어려움.

시도 2 — "Convolution 으로 local window 처리" (ByteNet, ConvS2S 등 ~2017)

각 토큰이 주변 N 개 토큰 만 본다. 결과: - 장거리 의존성 더 손실: window 밖 토큰을 보려면 layer 를 쌓아야 → 표현력 제한. - 고정 receptive field: 동적으로 "이 토큰은 100 토큰 전 그 단어를 봐야" 같은 결정 불가.

해법 — Attention "모든 쌍 점수 한 번에"

세 요구가 동시에 풀려야 했습니다:

  1. Gradient 가 깊은 sequence 에도 흐르도록 → attention 의 직접 path (모든 토큰이 다른 모든 토큰을 한 step 으로 봄).
  2. GPU 병렬화 가능Q @ Kᵀ큰 행렬곱 한 번이 모든 쌍을 계산.
  3. 장거리 의존성 직접 학습 → attention weight 가 어느 쌍이 중요한지 를 학습.

이 세 요구의 교집합이 self-attention + multi-head + residual + LayerNorm 의 패키지입니다.

GPU 는 행렬곱에 최적화되어 있습니다. 토큰을 "순차" 로 처리하면 tᵢ₊₁ 계산이 tᵢ 결과를 기다려야 하므로 GPU 병렬화가 막힙니다. Transformer 는 "토큰 쌍의 점수를 한 번의 Q @ Kᵀ 행렬곱으로 계산" 하는 자세를 잡아 학습 단계의 병렬화를 풀었습니다. 그 대가로 추론 단계에서는 여전히 한 토큰씩 생성해야 하고, 그래서 KV cache · GQA · Flash Attention 같은 추론 최적화가 모두 필요해진 것입니다.

이 한 줄 — "학습은 병렬, 추론은 순차" — 이 LLM 비용 구조 전체의 출발점입니다.

실패 모드 — 세 축이 빠지면 정확히 무엇이 일어나는가

빠진 축 시스템 증상 측정 가능한 metric
KV cache 없음 (매 토큰마다 전체 시퀀스 재계산) latency 가 시퀀스 길이의 제곱 으로 증가 32K 시퀀스에서 토큰 당 latency 1000×
Multi-head 없음 (single head) 다양한 관계 (syntax + semantic + position) 동시 표현 못함 downstream 성능 -5~10%
Position encoding 없음 토큰 순서 무관 (bag-of-tokens) "I love you" vs "you love I" 구분 불가

3. 작은 예 — "Write a UVM" 한 호출의 내부를 step-by-step

가장 단순한 시나리오. 사용자 입력 "Write a UVM" 을 받아 LLM 이 다음 토큰 하나 (" test") 를 예측해 응답하는 한 사이클을 8단계로 추적합니다.

Client(app + tokenizer)Inference Server(GPU) ① 'Write a UVM'(raw text)② BPE 토크나이즈[W, rite, ' ', a, ' ', U, VM]③ embedding lookup[v₁, v₂, ..., v₇] (d_model)④ + RoPE position 주입⑤ N × Transformer block(Q@Kᵀ → softmax → @V)→ hidden state h₇ (마지막 위치)⑥ output headvocab_size 확률 분포⑦ argmax / samplingnext_token = ' test' ⑧ ' test' 반환(K₁..K₇, V₁..V₇ KV cache 보관)
Client(app + tokenizer)Inference Server(GPU) ① 'Write a UVM'(raw text)② BPE 토크나이즈[W, rite, ' ', a, ' ', U, VM]③ embedding lookup[v₁, v₂, ..., v₇] (d_model)④ + RoPE position 주입⑤ N × Transformer block(Q@Kᵀ → softmax → @V)→ hidden state h₇ (마지막 위치)⑥ output headvocab_size 확률 분포⑦ argmax / samplingnext_token = ' test' ⑧ ' test' 반환(K₁..K₇, V₁..V₇ KV cache 보관)
Step 누가 무엇을 의미
client raw text 전송 HTTP / gRPC / local stdin — 모델은 raw text 그대로 못 받음
tokenizer BPE 로 sub-word 분할 "UVM" 도 어휘에 없으면 [U, VM] 등으로 쪼개짐
embedding layer token id → d_model 차원 벡터 vocab_size × d_model lookup 행렬
position 모듈 위치 신호 주입 (RoPE: Q/K 회전) Transformer 는 순서 모름 — 별도 주입 필수
N 개 Transformer block self-attention + FFN, residual + LayerNorm LLaMA-70B = 80 layer, GPT-3.5 ≈ 96 layer
output head (LM head) 마지막 hidden → vocab 확률 어휘 100K 면 d_model × 100K 행렬곱
sampler greedy / top-p / temperature 코드 생성은 보통 T=0 (deterministic)
server next_token 반환 + K,V cache 저장 다음 호출에서 step ⑤ 의 K/V 재계산 회피
# Step ⑦ 의 단순화 예시 — Greedy 디코딩
import torch
import torch.nn.functional as F

logits = model_forward(input_ids)         # (1, seq_len, vocab_size)
next_token_logits = logits[:, -1, :]      # 마지막 위치만 사용
next_token = torch.argmax(next_token_logits, dim=-1)  # (1,)

# Top-p (nucleus) sampling 의 경우
probs = F.softmax(next_token_logits / temperature, dim=-1)
sorted_probs, sorted_idx = torch.sort(probs, descending=True)
cumulative = torch.cumsum(sorted_probs, dim=-1)
mask = cumulative <= top_p
# mask 된 토큰 중에서만 multinomial sampling

여기서 잡아야 할 두 가지

(1) "한 번의 호출 = 한 토큰" 이 본질 — 응답이 길수록 step ⑤~⑦ 을 그만큼 반복. 그래서 latency 는 출력 길이에 거의 선형 비례.
(2) KV cache 가 메모리 폭주의 주범 — step ⑧ 에서 매 step 마다 K/V 가 누적. context 가 길어지면 KV cache 가 모델 가중치보다 클 수 있음 (§5.4 참조).


4. 일반화 — Transformer, Self-Attention, 그리고 축소 기법들

4.1 Transformer 블록의 골격

입력: 'The cat sat on the'Token Embedding'The' → [0.1, -0.3, ...] (d_model 차원)Positional EncodingToken Emb + Position Emb(Transformer 는 순서를 모름)Transformer Block × N (32 / 80 / 128 ...)Output Head벡터 → 어휘 크기 확률 분포argmax → 'mat'Multi-Head Self-Attention(각 토큰이 다른 모든 토큰 참조)Feed-Forward Network (FFN)(비선형 변환)+ Residual Connection + LayerNorm
입력: 'The cat sat on the'Token Embedding'The' → [0.1, -0.3, ...] (d_model 차원)Positional EncodingToken Emb + Position Emb(Transformer 는 순서를 모름)Transformer Block × N (32 / 80 / 128 ...)Output Head벡터 → 어휘 크기 확률 분포argmax → 'mat'Multi-Head Self-Attention(각 토큰이 다른 모든 토큰 참조)Feed-Forward Network (FFN)(비선형 변환)+ Residual Connection + LayerNorm

4.2 Self-Attention 의 핵심 수식

Attention(Q, K, V) = softmax(QKᵀ / √d_k) × V

Q (Query):  "이 토큰이 알고 싶은 것"
K (Key):    "각 토큰이 제공할 수 있는 정보의 인덱스"
V (Value):  "각 토큰이 실제로 제공하는 정보"

이 한 식이 (1) 모든 토큰 쌍의 관련성을 계산하고 (2) 관련성에 비례해 정보를 가중합산합니다. √d_k 로 나누는 것은 dot-product 가 너무 커져서 softmax 가 saturate 되는 것을 막는 안전장치.

4.3 직관 — 문장 안에서 attention

"The cat sat on the mat because it was tired"

"it" 이 참조해야 할 토큰은?
  → "cat"   (높은 Attention Score)
  → "mat"   (낮은 Score — 의미적으로 "it" 은 "cat" 을 지칭)

Attention Score (예시):
  it → cat:    0.65   ← 가장 높음
  it → mat:    0.10
  it → sat:    0.08
  it → tired:  0.12

4.4 Multi-Head Attention — 한 관점이 아니라 여러 관점

Head 1: 문법적 관계 (주어-동사)
Head 2: 의미적 관계 (대명사-선행사)
Head 3: 위치적 관계 (인접 토큰)
...

MultiHead(Q, K, V) = Concat(head_1, ..., head_h) × W_O
head_i = Attention(Q × W_Q_i, K × W_K_i, V × W_V_i)

4.5 추론 비용을 줄이는 세 갈래

축소 기법 무엇을 줄임 대가 위치
KV Cache 동일 prefix 의 K/V 재계산 GPU 메모리 ↑ 추론 시
GQA / MQA KV head 수 (h → g 또는 1) 미세 품질 손실 모델 학습 시
Quantization 가중치/활성치 비트 폭 (FP16 → INT4) 미세 정확도 손실 배포 시
Flash Attention HBM ↔ SRAM IO (없음, 알고리즘 등가) 학습/추론 모두
MoE 활성 파라미터 수 (모든 expert ≠ active expert) 라우팅 오버헤드, 메모리 ↑ 모델 설계 시

이 다섯 축이 §5 의 디테일에 모두 등장합니다.


5. 디테일 — Tokenization, RoPE, Flash Attention, MoE, Quantization, Scaling Laws

5.1 Tokenization — 텍스트를 숫자로

방식 예시 특징
Word-level "playing" → [playing] 어휘가 매우 커짐, OOV 문제
Character-level "playing" → [p,l,a,y,i,n,g] 어휘 작지만 시퀀스 길어짐
BPE (Byte-Pair Encoding) "playing" → [play, ing] 가장 일반적, 빈도 기반 서브워드
SentencePiece "playing" → [▁play, ing] 언어 독립적 BPE
BPE 동작 원리:
1. 초기: 모든 문자를 개별 토큰으로 시작
   "l o w e r" → [l, o, w, e, r]

2. 가장 빈번한 인접 쌍을 병합
   (l, o) → lo    →  [lo, w, e, r]
   (lo, w) → low  →  [low, e, r]
   (e, r) → er    →  [low, er]
   (low, er) → lower → [lower]

3. 설정된 어휘 크기까지 반복
   GPT-4: ~100K 토큰, Claude: ~100K 토큰
LLM API 비용 = 입력 토큰 수 + 출력 토큰 수

  영어:    ~1 토큰 ≈ 4글자 ≈ 0.75 단어
  한국어:  ~1 토큰 ≈ 1-2글자 (비효율적 → 비용 높음)
  코드:    변수명, 키워드 등 → 영어와 유사

  Context Window = 최대 처리 토큰 수
  GPT-4o: 128K, Claude: 200K, Gemini: 1M+

  DV 적용 시:
  - SystemVerilog 파일 전체를 Context 에 넣을 수 있는가?
  - 대규모 IP 스펙 문서를 처리할 수 있는가?
  → Context 한계 = RAG 가 필요한 이유 중 하나

5.2 Positional Encoding 발전사

Transformer 는 입력 순서를 모른다 (순열 불변):
  "cat sat on mat" 와 "mat on sat cat" 을 동일하게 처리
  → 위치 정보를 별도로 주입해야 함
세대 방식 원리 한계
1세대 Sinusoidal (Transformer 원논문) sin/cos 함수로 절대 위치 인코딩 학습된 위치 관계 표현 불가
2세대 Learned Absolute (GPT-2, BERT) 위치 임베딩을 학습 파라미터로 학습 길이 초과 시 성능 급락
3세대 RoPE (Rotary Position Embedding) Q, K 벡터를 위치에 따라 회전 현재 가장 널리 사용
4세대 ALiBi (Attention with Linear Biases) Attention Score 에 거리 비례 페널티 별도 임베딩 불필요, 외삽 강점
RoPE (현재 표준 — LLaMA, Claude, GPT-4 계열):

핵심 아이디어:
  Q, K 벡터를 2D 평면에서 위치(m)에 비례하여 회전
  f(q, m) = q × e^(imθ)  (복소수 회전)

  → 두 토큰의 Attention Score 가 "상대 위치 (m-n)" 에만 의존
  → 절대 위치가 아닌 상대 위치를 자연스럽게 인코딩

왜 강력한가:
  1. 상대 위치 인코딩 → "3번째 뒤의 토큰" 이라는 관계를 직접 표현
  2. 외삽 가능 → 학습 시 4K 토큰이어도 추론 시 더 긴 시퀀스 처리 가능
     (NTK-aware scaling, YaRN 등으로 Context 확장)
  3. 구현 간결 → Q, K 에만 적용, V 는 그대로

DV 적용 관점:
  긴 SystemVerilog 파일(수천 줄) 을 처리할 때 위치 외삽이 중요
  → RoPE 기반 모델이 긴 코드 파일에서 더 안정적

5.3 Attention 복잡도와 Flash Attention

Self-Attention 연산량:
  Q × Kᵀ = (n × d) × (d × n) = n × n 행렬

  n = 시퀀스 길이일 때:
    n = 4K   →   16M 연산
    n = 32K  → 1,024M 연산  (64배 증가)
    n = 128K → 16,384M 연산 (1024배 증가)

  메모리도 O(n²): Attention Score 행렬 전체를 메모리에 유지해야 함
  → Context Window 가 길어질수록 비용이 제곱으로 증가
  → 이것이 긴 Context 처리의 근본적 병목
Flash Attention (Tri Dao, 2022):

핵심: Attention 연산을 타일(tile) 단위로 분할하여 GPU SRAM 에서 처리

기존:
  전체 QKᵀ 행렬(O(n²)) 을 GPU HBM 에 저장 → 느린 메모리 접근

Flash Attention:
  블록 단위로 Q, K, V 를 SRAM 에 로드 → 부분 Attention 계산 → 결합
  → IO 복잡도 O(n²d / M) (M = SRAM 크기)
  → 실측 2-4x 속도 향상, 메모리 O(n) 으로 감소

  결과:
  - 같은 GPU 에서 더 긴 시퀀스 처리 가능
  - 현재 거의 모든 LLM 학습/추론에 사용
  - Flash Attention 2/3 으로 지속 최적화
MQA / GQA (Attention Head 최적화):

Multi-Head Attention (MHA):
  Head 수 = h일 때, 각 Head마다 별도 Q, K, V
  KV Cache 크기: h × n × d_k  → 메모리 부담

Multi-Query Attention (MQA):
  Q는 h개 Head, K/V는 1개만 공유
  KV Cache: 1 × n × d_k  → h배 절약
  단점: 품질 약간 하락

Grouped-Query Attention (GQA) — 현재 표준:
  Q는 h개 Head, K/V는 g개 그룹으로 공유 (1 < g < h)
  예: h=32, g=8 → 4개 Q Head 가 1개 KV 그룹 공유
  KV Cache: g × n × d_k  → MHA 대비 h/g배 절약

  LLaMA 2 70B: GQA 사용 (h=64, g=8)
  → MHA 대비 KV Cache 8배 절약, 품질 거의 동일

  +--------+--------+--------+
  |  MHA   |  GQA   |  MQA   |
  | Q K V  | Q K V  | Q K V  |
  | Q K V  | Q     | Q      |
  | Q K V  | Q K V  | Q      |
  | Q K V  | Q      | Q      |
  +--------+--------+--------+
  KV: h개   KV: g개  KV: 1개

5.4 KV Cache — 추론 속도의 핵심

Autoregressive 생성에서의 비효율:

  Step 1: "Write"           → Q,K,V 계산 → "a"
  Step 2: "Write a"         → Q,K,V 전부 재계산 → "UVM"
  Step 3: "Write a UVM"     → Q,K,V 전부 재계산 → "test"

  → 이전 토큰의 K, V 를 매번 다시 계산 = 낭비

KV Cache:
  Step 1: K₁,V₁ 계산 → 캐시 저장 → "a"
  Step 2: K₂,V₂만 새로 계산 → 캐시에 추가 → "UVM"
  Step 3: K₃,V₃만 새로 계산 → 캐시에 추가 → "test"

  → 새 토큰의 Q 만 전체 KV 캐시와 Attention → O(n) per step
  → KV Cache 없이는 O(n²) per step
KV Cache 메모리 계산:

KV Cache 크기 = 2 × n_layers × n_kv_heads × seq_len × d_head × dtype_bytes

예: LLaMA 2 70B (GQA)
  n_layers = 80, n_kv_heads = 8, d_head = 128, FP16 (2 bytes)
  seq_len = 4096일 때:
  = 2 × 80 × 8 × 4096 × 128 × 2 = ~1.3 GB per request

  seq_len = 128K일 때:
  = 2 × 80 × 8 × 131072 × 128 × 2 = ~41 GB per request
  → Context 가 길어지면 KV Cache 가 모델 가중치보다 클 수 있음

DV 관점:
  긴 SystemVerilog 파일을 Context 에 넣을 때 KV Cache 메모리가 급증
  → 필요한 부분만 RAG 로 검색하여 주입하는 것이 효율적인 이유

5.5 MoE (Mixture of Experts) 아키텍처

기존 (Dense Model): 모든 입력이 모든 파라미터를 통과 → 파라미터 수 = 연산량 (비례). MoE: 입력마다 일부 Expert 만 활성화 (Sparse Activation) → 총 파라미터는 크지만 토큰당 연산량은 적음.

INRE1E2E3E4E8OUT 선택 안 됨선택 안 됨선택 안 됨
INRE1E2E3E4E8OUT 선택 안 됨선택 안 됨선택 안 됨

→ 8개 Expert 중 2개만 활성화 = 파라미터 8x, 연산 ~2x.

모델 총 파라미터 활성 파라미터 Expert 수 Top-K
Mixtral 8x7B 46.7B 12.9B 8 2
Mixtral 8x22B 176B 39B 8 2
GPT-4 (추정) ~1.8T ~220B 16 2
DeepSeek-V2 236B 21B 160 6
트레이드오프:
  장점: 적은 연산으로 큰 모델의 성능 → 추론 비용 대비 고품질
  단점: 총 파라미터가 크므로 GPU 메모리 많이 필요 (로딩)
       Expert 간 불균형 (load balancing) 문제
       학습 불안정성

DV 관점:
  로컬 배포 시 MoE 모델(Mixtral) 은 Dense 모델 대비
  적은 연산으로 높은 성능 → DV 파이프라인 통합에 유리

5.6 Quantization — 모델 경량화

원래 모델: FP32 (32-bit 부동소수점)
  7B 모델 = 7 × 10⁹ × 4 bytes = 28 GB

양자화:
  FP32 → FP16 → INT8 → INT4
  정밀도를 낮춰 모델 크기와 연산량 감소

  7B 모델 메모리:
  FP32: 28 GB
  FP16: 14 GB  ← 학습 표준
  INT8:  7 GB  ← 추론 최적화
  INT4:  3.5 GB ← 소비자 GPU에서 실행 가능
방법 원리 정밀도 손실 속도
RTN (Round-to-Nearest) 단순 반올림 높음 즉시
GPTQ 레이어별 최적 양자화 낮음 수 시간
AWQ (Activation-aware) 중요 가중치 보존 매우 낮음 수 시간
GGUF (llama.cpp) CPU 추론 최적화 포맷 낮음 즉시
DV 적용 시:
  - 사내 서버(GPU 제한): INT4/INT8 양자화 모델로 배포
  - 예: Llama 3 70B INT4 → ~35GB → A100 1장에서 실행 가능
  - 코드 생성 품질: INT4 에서도 FP16 대비 95%+ 유지
  - 보안 + 성능 균형의 현실적 해법

5.7 Scaling Laws — 모델 크기와 성능의 관계

Chinchilla Scaling Law (2022):

최적 학습 조건:
  모델 파라미터 수(N) 와 학습 토큰 수(D) 를 동시에 늘려야 함
  최적 비율: D ≈ 20 × N

  예: 70B 모델 → 최소 1.4T 토큰으로 학습해야 최적
      7B 모델 → 최소 140B 토큰

이전 접근 (GPT-3): 큰 모델 + 적은 데이터
Chinchilla 접근: 적절한 모델 + 충분한 데이터
  → 같은 연산 예산으로 더 좋은 성능

결과:
  Chinchilla 70B > Gopher 280B (4배 작지만 더 우수)
  → 이후 LLaMA, Mistral 등 "효율적 학습" 트렌드
Emergent Abilities (창발 능력):

모델 크기가 특정 임계점을 넘으면 갑자기 나타나는 능력:

  ~10B: 기본 언어 이해, 간단한 코드
  ~50B: CoT 추론, 복잡한 코드 생성
  ~100B+: 수학 추론, 멀티스텝 계획, 도구 사용

  DV 적용 시:
  - SystemVerilog 코드 생성 → ~50B+ 모델에서 의미 있는 품질
  - UVM 패턴 이해 + 적용 → ~70B+ 권장
  - 작은 모델은 RAG/Few-shot 으로 보완 필수

5.8 LLM 의 학습 단계

Phase 1: Pre-training (사전 학습)
  - 대규모 텍스트 코퍼스 (수 TB)
  - Next Token Prediction (자기지도 학습)
  - 수천 GPU × 수 주~수 개월
  - 결과: 언어의 일반적 패턴 학습
  - 비용: 수백만~수천만 달러

Phase 2: SFT (Supervised Fine-Tuning)
  - 사람이 작성한 고품질 (질문, 답변) 쌍
  - 수만~수십만 예시
  - 결과: 지시 따르기(Instruction Following) 능력

Phase 3: RLHF / DPO (Human Alignment)
  - 사람이 선호하는 출력을 학습
  - 안전성, 유용성, 정확성 강화
  - 결과: 실용적인 AI 어시스턴트

5.9 추론 (Inference) 디코딩 전략

Autoregressive Generation:

입력: "Write a UVM"

Step 1: "Write a UVM" → P(next) → " test"
Step 2: "Write a UVM test" → P(next) → "bench"
Step 3: "Write a UVM testbench" → P(next) → " for"
...

한 번에 하나의 토큰만 생성 → 순차적 (병렬화 불가)
→ 이것이 LLM 추론이 느린 근본 이유
전략 동작 특징
Greedy 매 step 최고 확률 토큰 선택 빠르지만 단조로운 출력
Top-k 확률 상위 k개 중 샘플링 다양성 + 품질 균형
Top-p (Nucleus) 누적 확률 p 이내에서 샘플링 동적 후보 크기
Temperature 확률 분포를 sharp/flat 조절 T<1: 보수적, T>1: 창의적
Temperature 효과:

  T = 0.0: 항상 같은 출력 (Greedy 와 동일) → 코드 생성, 정확성 필요 시
  T = 0.3: 약간의 변동 → 일반적 코드/분석
  T = 0.7: 적당한 다양성 → 문서 생성
  T = 1.0: 원래 분포 → 창의적 작문

  DV 적용 시: T = 0.0~0.3 권장 (코드 정확성 중요)

5.10 핵심 파라미터 정리

파라미터 의미 대표값
d_model 토큰 임베딩 차원 4096~12288
n_layers Transformer Block 수 32~128
n_heads Attention Head 수 32~128
d_ff FFN 히든 차원 4 × d_model
vocab_size 어휘 크기 32K~128K
context_length 최대 입력 토큰 수 4K~1M+
params 총 파라미터 수 7B~405B+

6. 흔한 오해 와 DV 디버그 체크리스트

흔한 오해

❓ 오해 1 — 'LLM 은 답을 안다'

실제: LLM 은 학습된 분포에서 다음 토큰 확률 을 매기는 패턴 매칭기. lookup 이 아니라 generate 입니다. 따라서 학습 데이터에 없는 사실을 "그럴듯하게" 만들어 내는 hallucination 이 본질적으로 발생합니다.
왜 헷갈리는가: 답이 자주 정확해서 "외워서 알고 있다" 는 인상을 줌. + 마케팅 문구 ("AI 가 알고 있다").

❓ 오해 2 — '모델이 크면 다 해결된다'

실제: Frontier 모델조차 hallucination, context 한계, KV cache 폭주로 실패. "task 분해 + RAG 품질 + Agent guard" 가 모델 크기보다 ROI 가 높은 경우가 많습니다.
왜 헷갈리는가: 매년 모델 크기 뉴스만 보고 "크기 = 능력" 으로 단순화.

❓ 오해 3 — 'Context window 는 길수록 좋다'

실제: 길이의 제곱 으로 attention 비용이 증가하고, KV cache 가 모델 가중치보다 커질 수도 있습니다. 또한 긴 context 의 중간 정보는 "lost in the middle" 현상으로 무시되기 쉽습니다.
왜 헷갈리는가: spec sheet 에 "200K context" 같은 숫자만 보임.

❓ 오해 4 — 'MoE = 더 큰 모델이라 더 비싸다'

실제: MoE 는 파라미터는 크지만 활성 파라미터만 연산. Mixtral 8x7B 는 47B 가중치를 가지지만 토큰당 13B 만 활성. 다만 GPU 메모리에는 47B 전체가 올라가야 함.
왜 헷갈리는가: "총 파라미터" 만 보고 비용을 계산.

❓ 오해 5 — 'Quantization 은 정확도가 무조건 떨어진다'

실제: AWQ / GPTQ 같은 현대 양자화는 INT4 에서도 FP16 대비 95%+ 정확도를 유지. 어떤 양자화를 쓰느냐가 결정적이고, RTN 같은 단순 양자화만 가지고 일반화하면 안 됩니다.

DV 디버그 체크리스트 (LLM 추론을 직접 운용할 때 자주 보는 실패)

증상 1차 의심 어디 보나
time-to-first-token 이 길이에 제곱 비례 KV cache 비활성화 (use_cache=False) 추론 서버 설정, 응답의 cached_tokens 카운트
OOM (Out of Memory) at long context KV cache 가 모델 가중치보다 커짐 n_layers × n_kv_heads × seq_len × d_head × 2 계산
같은 prompt 인데 답이 매번 다름 Temperature > 0 또는 seed 미고정 temperature, seed, top_p 파라미터
응답이 한 글자씩 끊겨 나옴 streaming 모드 + tokenizer encoding 문제 tokenizer 가 multi-byte (한글) 를 한 token 단위로 가르고 있는지
한국어 응답이 영어보다 훨씬 비쌈 tokenizer 가 한국어를 1-2 글자씩 자름 tiktoken/BPE 로 직접 토큰 수 측정
INT4 양자화 후 출력 이상 RTN 단순 양자화 사용 AWQ/GPTQ/GGUF 로 교체 후 평가
긴 prompt 의 중간 정보를 무시 "lost in the middle" 현상 중요한 지시는 prompt 의 시작/끝에 배치
MoE 모델인데 추론 throughput 이 dense 보다 낮음 router 가 expert 사이를 자주 뜀 + GPU 간 통신 Top-K, expert 분포, batch size 점검

7. 핵심 정리 (Key Takeaways)

  • LLM = 자기회귀 토큰 생성기 — 한 호출 = 한 토큰. 응답 길이가 곧 latency.
  • Transformer = Self-Attention + Position + FFN — 모든 토큰 쌍을 한 번의 행렬곱으로.
  • 추론 비용의 주범은 KV cache — context 길이의 제곱으로 메모리 폭증. GQA · Flash Attention · MoE · Quantization 이 이를 감쇄하는 네 갈래.
  • 모델 크기보다 task 설계 — 큰 모델로도 prompt/RAG/agent 를 잘못 짜면 망한다.
  • DV 관점: 보안 (로컬 INT4) + 비용 (KV cache) + 정확성 (T=0, 검증 파이프라인) 의 세 축이 항상 함께.

실무 주의점 — KV Cache 미활성화 시 추론 지연 폭증

현상: 동일 프롬프트를 반복 호출하거나 스트리밍 응답 중에 KV Cache 가 비활성화되면, 매 토큰 생성마다 전체 컨텍스트를 재계산해 latency 가 수십 배 증가한다.

원인: 추론 서버 설정에서 use_cache=False 가 디버그 목적으로 설정된 채 운영에 배포되거나, 배치 크기가 급증할 때 캐시 메모리 부족으로 자동 비활성화되는 경우가 있다.

점검 포인트: 추론 서버 응답 헤더 또는 로그에서 cached_tokens 카운트가 0 인지 확인. time-to-first-tokentotal_tokens × generation_time 에 비례하면 KV Cache 미작동 의심. 배포 설정 파일의 max_cache_size 항목이 모델 레이어 수 × batch × context 에 충분한지 검토.

7.1 자가 점검 — 이 모듈을 진짜로 이해했는지

🤔 Q1 — KV cache 비용 계산 (Bloom: Analyze)

LLaMA-2 70B 모델 (80 layers, hidden 8192, fp16) 의 8K context 한 sequence 의 KV cache 메모리는? 그리고 batch 32 라면? GPU 1 개 (H100 80GB) 에서 batch 가능 수 는?

정답
  • 토큰당: 2 × 80 × 8192 × 2 byte ≈ 2.6 MB.
  • 8K seq: 2.6 × 8192 ≈ 21 GB.
  • Batch 32: 21 × 32 ≈ 672 GB → H100 80 GB 한 개로 불가능. Multi-GPU 또는 batch 축소 필요.
  • H100 80GB 의 KV 가용량 (모델 130GB 의 대부분이 weight, ~40GB 만 KV): batch ≈ 1~2.

이게 70B 모델의 long-context 서비스가 비싼 정확한 이유. PagedAttention / MLA 같은 최적화가 이 cap 을 push out 함.

🤔 Q2 — Greedy vs Sampling 선택 (Bloom: Apply)

당신은 LLM 으로 SystemVerilog 모듈을 생성한다. T=0 (greedy) 와 T=0.7 (sampling) 중 어느 것 선택해야 하나?

정답

T=0 (greedy). 이유: - SV 코드는 문법적 정확성 이 결정적 — T=0.7 면 always_ffalways 로 됐다거나 미세한 흔들림이 컴파일 에러 가 됨. - 또한 재현 가능성 이 중요 — 같은 prompt 가 같은 결과를 내야 디버그 가능. - 단점: 다양성 0 — 한 시도 실패하면 다른 시도 도 동일 결과. 그래서 다양성 필요할 때만 T=0.3~0.5 권장.

🤔 Q3 — Context window 확장 trade-off (Bloom: Evaluate)

당신은 4K → 32K context 로 확장하고 싶다. 두 가지 옵션: - (a) Retraining 으로 32K 학습. - (b) RoPE 기반 외삽 (YaRN / NTK-aware).

두 옵션의 trade-off 를 3 차원으로 비교하시오.

정답
차원 (a) 32K Retrain (b) RoPE 외삽
비용 매우 큼 (수 주의 GPU 학습) 0 (코드 한 줄)
성능 32K 에서 최적 32K 에서 성능 저하 가능 (8K 학습 기반)
안정성 검증된 hallucination 증가 가능

실무: (b) 로 시작 → 성능 부족 시 (a) 로 escalate.

7.2 출처

Internal (Confluence) - Understanding LLMs: A Comprehensive Overview from Training to Inference (id=910786585) - Literature Reviews: LLM Infrastructure and Systems (id=958005272) - MoE (id=964100206) - LLM | Inference (id=996769852) - Cache basic (id=941817928)

External - KV Caching Explained — Hugging Face blog, 2025 - KV Cache Optimization — Introl Blog, 2025 (LLaMA-2 70B 토큰당 ~2.6 MB) - KV Cache Optimization via Multi-Head Latent Attention — PyImageSearch, 2025 (8× MLA 축소) - Attention is All You Need — Vaswani et al., 2017 (Transformer 원논문) - RoFormer: Enhanced Transformer with Rotary Position Embedding — Su et al., 2021 (RoPE) - FlashAttention — Dao et al., NeurIPS 2022


다음 모듈

Module 02 — Prompt Engineering & In-Context Learning: 같은 모델로도 결과를 바꾸는 입력 설계 기법.

퀴즈 풀어보기 →