~15 min · llm-physics, prefill, decode, arithmetic-intensity, compute-bound, bandwidth-bound
Level 0스펙 시트 훑는 사람
0 XP0/91 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete
"언어 모델은 같은 가중치로 두 가지 일을 하고, 하드웨어는 그걸 서로 다른 두 프로그램으로 겪어."
엔터를 누르면 일어나는 일
언어 모델의 모든 응답엔 두 단계가 있어. 프리필은 네 프롬프트 전체를 한꺼번에 읽어. 그 안의 모든 토큰이 함께 모든 레이어를 지나가. 활성값의 큰 행렬 하나를 가중치 행렬에 곱하는 거야. 일은 행렬-행렬 곱이고, 출력은 첫 생성 토큰과 프롬프트에 대해 모델이 계산한 걸 담은 KV 캐시야. 그다음 디코드가 나머지를 한 번에 토큰 하나씩 만들어. 토큰 하나의 활성값, 그러니까 벡터 하나가 모든 레이어를 지나며 같은 가중치 행렬에 곱해지고, KV 캐시는 항목 하나만큼 자라. 일은 행렬-벡터 곱이고, 토큰마다 반복돼.
가중치는 두 단계 모두 메모리에서 읽혀. 차이는 읽기 한 번이 얼마만큼의 산술을 값 치르느냐야. 프리필에서 가중치 행렬은 한 번 읽혀서 수백, 수천 토큰에 쓰여. GPU는 가져온 바이트당 계산할 게 충분하고, 이 단계는 얼마나 빨리 곱할 수 있느냐에 묶여. 연산 제약. 디코드에선 같은 행렬이 한 번 읽혀서 토큰 하나에 쓰여. 바이트당 계산할 게 거의 없고, 이 단계는 바이트가 얼마나 빨리 도착하느냐에 묶여. 대역폭 제약. NVIDIA 자체 추론 가이드가 같은 용어로 설명해. 프리필은 "고도로 병렬화되는 행렬-행렬 연산"이고, 디코드에선 "데이터(가중치, 키, 값, 활성값)가 메모리에서 GPU로 전송되는 속도가 지연을 지배하지, 계산이 실제로 얼마나 빠른지는 아니다."
사다리에서 실측
실험 트랙은 모든 실험실 맥에서 모든 모델의 두 속도를 기록했어. 프리필 나누기 디코드는 각 단계가 가중치 읽기 한 번당 몇 토큰을 처리하느냐의 비율이야.
모델 (4비트)
office 프리필 / 디코드 tok/s
비율
pro2023 프리필 / 디코드
비율
air 프리필 / 디코드
비율
증거
Qwen3.5-0.8B
6,312 / 338
19
4,017 / 417
10
1,707 / 168
10
실측 2026-09-15
Qwen3.5-9B
1,043 / 95
11
642 / 73
9
172 / 19
9
실측
Qwen3.5-27B
315 / 33
10
195 / 23
8
49 / 6
8
실측
읽을 게 둘. 첫째, 209토큰 프롬프트에서 모든 기계에서 프리필이 토큰당 디코드보다 대략 열 배 빨라. 작은 프롬프트야. 천 토큰 프롬프트면 비율이 더 커져. 프리필은 더 잘 상각하고 디코드는 아예 상각을 못 하니까. 둘째, 기계 사이에서 뭐가 바뀌는지 봐. M3 Max에서 M3 Ultra로 가면 27B의 프리필은 62% 오르고(195 → 315), GPU 코어 두 배야. 디코드는 41% 올라(23 → 33). 달성 대역폭 비율(391 → 638 GB/s, 63%)에서 오버헤드를 뺀 만큼 따라가. 실험 트랙의 GPU 세대 레슨은 같은 갈림을 반대편에서 본 거야. M3 Ultra는 M2 Ultra보다 프리필이 35% 앞서고 디코드는 오히려 뒤져(32.6 대 35.3).
이게 왜 레슨 하나에 담은 퀘스트 전체인지
1번 트랙의 모든 벤더 주장은 프리필 주장이거나 피크 연산 주장이었어. 모델이 '느리게 느껴지는' 이 집의 모든 경험은 디코드 경험이거나 첫 토큰까지 시간 경험이고, 둘은 처방이 달라. GPU 코어 추가, Neural Accelerator, 더 좋은 행렬 유닛. 그건 프리필을 움직여. 디코드를 움직이는 건 대역폭과 토큰당 바이트 감소뿐이야. 애플이 M5가 프롬프트 처리는 '최대 4배' 빠르고 생성은 '더 큰 메모리 대역폭 덕분에' '19-27%' 빠르다고 할 때, 자기 숫자로 정확히 이 갈림을 설명하는 거야. 다음 레슨은 디코드 반쪽을 아무것도 다운로드하기 전에 계산할 수 있는 상한으로 바꿔.
Code
two_workloads.py — 실험 JSONL에서 프리필과 디코드 속도, 그리고 둘의 비율·python
#!/usr/bin/env python3
"""Read silicon_lab.py ladder records and print prefill vs decode per model per
machine. The ratio is how many more tokens prefill handles per weight read."""
import glob
import json
from collections import defaultdict
rows = defaultdict(dict)
for path in glob.glob("results/ladder-*.jsonl"):
for line in open(path):
r = json.loads(line)
rows[r["model"].split("/")[-1]][r["alias"]] = (r["prompt_tps"], r["generation_tps"])
for model, per_alias in sorted(rows.items()):
print(model)
for alias, (pre, dec) in sorted(per_alias.items()):
print(f" {alias:8} prefill {pre:8.1f} tok/s decode {dec:7.2f} tok/s ratio {pre/dec:5.1f}x")
# office, 2026-09-15 (prompt 209 tokens):
# Qwen3.5-9B-4bit prefill 1042.6 decode 95.06 ratio 11.0x
# Qwen3.5-27B-4bit prefill 315.4 decode 32.60 ratio 9.7x
mlx-lm의 스트리밍 API로 두 단계를 직접 지켜보기·python
import time
from mlx_lm import load, stream_generate
model, tok = load("mlx-community/Qwen3.5-9B-4bit")
prompt = tok.apply_chat_template([{"role": "user", "content": "Explain unified memory in 300 words."}],
add_generation_prompt=True)
t0 = time.perf_counter(); first = None
for r in stream_generate(model, tok, prompt, max_tokens=200):
if first is None:
first = time.perf_counter() - t0 # time to first token = prefill
print(f"prefill: {r.prompt_tokens} tokens at {r.prompt_tps:.0f} tok/s (TTFT {first:.2f}s)")
print(f"decode: {r.generation_tokens} tokens at {r.generation_tps:.1f} tok/s")
# GenerationResponse carries prompt_tps and generation_tps separately — the
# library measures the two phases as two phases, because they are.
네 맥에서 스트리밍 블록을 30단어 프롬프트로 한 번, 600단어 프롬프트(아무 기사나 붙여 넣어)로 한 번 돌려. 둘의 TTFT, 프리필 tok/s, 디코드 tok/s를 기록해서 카드에 추가해. 그다음 디코드 tok/s는 거의 안 바뀌고 TTFT는 오른 이유를 설명하고, 요청마다 파일 전체를 붙여 넣는 워크로드에 그게 뭘 예측하는지 써.
Hint
프리필 비용은 프롬프트 길이에 비례해. 토큰당 디코드 비용은 거의 안 그래(캐시가 크게 자라기 전까진. 네 번째 레슨). 매 턴 긴 컨텍스트를 다시 보내는 워크로드는 매 턴 프리필 청구서를 내. 로컬 코딩 에이전트가 긴 파일에서 느리게 느껴지는 이유고, 엣지 시대 트랙이 코딩을 잘못된 엣지 워크로드라고 부르는 이유야.
Progress
Progress is local-only — sign in to sync across devices.