들어가며
학습이 끝난 모델은 한 번 만들어지지만, 추론은 모델이 살아 있는 내내 매일 수십억 번 일어납니다. 2026년 들어 업계에서 추론 capex가 학습 capex를 처음으로 추월했다는 보고가 나오는 이유가 여기에 있습니다. 모델을 더 크고 똑똑하게 만드는 일과, 그 모델을 싸고 빠르게 서빙하는 일은 이제 완전히 다른 엔지니어링 문제로 분리되었습니다.
이 글은 "추론을 빠르게 만든다"는 목표를 하드웨어 관점에서 분해합니다. 핵심 주장은 단순합니다. 현대 추론은 대부분 연산이 부족해서 느린 것이 아니라, 데이터를 옮기느라 느립니다. 그래서 양자화로 데이터를 작게 만들고, 희소성으로 데이터를 적게 만들고, dataflow 설계로 데이터를 덜 옮기는 세 가지 전략이 서로 맞물립니다. 여기에 연산자 융합, 배칭, KV 캐시, 컴파일러 최적화가 더해지면 같은 칩에서 몇 배의 처리량 차이가 납니다.
존댓말로 차분하게, 그러나 숫자와 코드로 단단하게 풀어가겠습니다.
추론 비용의 구조 — 왜 메모리가 병목인가
먼저 비용 구조를 정확히 봅시다. GPU의 성능을 가르는 두 가지 숫자는 연산 처리량(FLOPS)과 메모리 대역폭(byte/s)입니다. 이 둘의 비율을 연산 강도(arithmetic intensity)라고 부르며, 단위는 "메모리에서 1바이트를 읽을 때마다 몇 번의 연산을 하는가"입니다.
루프라인(roofline) 모델은 이 관계를 한눈에 보여줍니다.
성능
(FLOPS)
^
| ___________________ 연산 한계 (compute-bound)
| /
| /
| / <- 이 기울기가 메모리 대역폭
| /
| / 메모리 한계 (memory-bound)
| /
+-------------+--------------------------> 연산 강도 (FLOP/byte)
임계점
연산 강도가 낮으면(왼쪽) 대역폭이 성능을 결정하고, 높으면(오른쪽) 연산이 성능을 결정합니다. 문제는 LLM 추론의 디코딩 단계가 극단적으로 메모리 바운드라는 점입니다.
LLM 추론은 두 단계로 나뉩니다.
- **프리필(prefill)**: 입력 프롬프트 전체를 한 번에 처리. 행렬-행렬 곱이 많아 연산 강도가 높고 연산 바운드에 가깝습니다.
- **디코딩(decode)**: 토큰을 하나씩 생성. 매 스텝마다 모델 가중치 전체를 읽어 행렬-벡터 곱을 합니다. 배치가 작으면 연산 강도가 1 근처로 떨어져 철저히 메모리 바운드가 됩니다.
숫자로 느껴봅시다. 700억 파라미터 모델을 FP16으로 저장하면 약 140GB입니다. 토큰 하나를 디코딩하려면 이 가중치를 한 번 읽어야 합니다. 메모리 대역폭이 약 3.35TB/s라면 가중치를 한 번 훑는 데만 약 42밀리초가 걸립니다. 즉 배치가 1이면 초당 약 24토큰이 이론적 상한입니다. 연산 유닛은 거의 놀고 있습니다.
여기서 메모리 월(memory wall)이라는 표현이 등장합니다. 지난 10여 년간 연산 성능은 메모리 대역폭보다 훨씬 빠르게 늘었습니다. 그 결과 대부분의 추론 워크로드에서 칩의 연산 능력은 남아돌고, 데이터를 공급하는 능력이 부족합니다. 데이터를 옮기는 데 드는 에너지가 연산 자체보다 한 자릿수 이상 크다는 점도 중요합니다. 칩 내부 레지스터 접근 대비, HBM에서 데이터를 가져오는 비용은 대략 수백 배에 달합니다.
이 한 가지 사실에서 이 글의 나머지 전략이 모두 따라 나옵니다. 데이터를 작게(양자화), 적게(희소성), 덜 옮기게(dataflow) 만들면 됩니다.
양자화 — 데이터를 작게 만들기
양자화는 가중치와 활성값을 더 적은 비트로 표현하는 기법입니다. FP16(16비트)을 INT8(8비트)로 바꾸면 메모리 사용량과 대역폭 요구량이 절반이 됩니다. 메모리 바운드 워크로드에서 이는 거의 그대로 2배 속도로 이어집니다.
정밀도 포맷의 풍경
2026년 현재 실무에서 마주치는 주요 포맷을 정리하면 다음과 같습니다.
| 포맷 | 비트 | 주 용도 | 하드웨어 지원 |
| --- | --- | --- | --- |
| FP16 / BF16 | 16 | 학습, 고정밀 추론 | 광범위 |
| FP8 (E4M3 / E5M2) | 8 | 추론, 일부 학습 | Hopper 이후, TPU |
| INT8 | 8 | 추론(PTQ/QAT) | 매우 광범위 |
| FP4 (MXFP4 등) | 4 | 추론 | Blackwell 2세대 TE |
| INT4 | 4 | 가중치 전용 양자화 | 광범위(커널 의존) |
NVIDIA Blackwell(GTC 2026 발표)의 2세대 Transformer Engine은 FP4 연산을 네이티브로 지원합니다. FP4는 4비트로 부동소수를 표현하는데, 단독으로는 표현 범위가 너무 좁아 정확도가 무너집니다. 그래서 마이크로스케일링(microscaling) 기법을 씁니다. 작은 블록(예: 16개 또는 32개 값)마다 공유 스케일 팩터를 따로 두어, 블록 단위로 동적 범위를 맞추는 방식입니다.
대칭/비대칭, PTQ/QAT
양자화의 기본 수식은 다음과 같습니다.
양자화: q = round(x / scale) + zero_point
역양자화: x_hat = (q - zero_point) * scale
대칭 양자화는 zero_point를 0으로 고정합니다. 비대칭은 분포가 한쪽으로 치우친 활성값(예: ReLU 이후 항상 양수)에 유리합니다.
적용 시점에 따라 두 방식으로 나뉩니다.
- **PTQ(Post-Training Quantization)**: 학습된 모델을 그대로 양자화. 소량의 보정(calibration) 데이터로 스케일만 정합니다. 빠르고 간단하지만 4비트 이하에서는 정확도가 떨어질 수 있습니다.
- **QAT(Quantization-Aware Training)**: 학습 과정에서 양자화 오차를 흉내 내어 모델이 적응하게 합니다. 비용이 크지만 저비트에서 정확도가 잘 유지됩니다.
간단한 PTQ 보정 예시
def collect_quant_scale(weight: torch.Tensor, n_bits: int = 8):
"""대칭 양자화 스케일을 채널별로 계산한다."""
qmax = 2 ** (n_bits - 1) - 1 # int8이면 127
출력 채널(행)별 최댓값
per_channel_max = weight.abs().amax(dim=1, keepdim=True)
scale = per_channel_max / qmax
scale = scale.clamp(min=1e-8)
return scale
def fake_quantize(weight: torch.Tensor, scale: torch.Tensor, n_bits: int = 8):
qmax = 2 ** (n_bits - 1) - 1
qmin = -qmax - 1
q = torch.clamp(torch.round(weight / scale), qmin, qmax)
return q * scale # 역양자화로 오차를 본다
w = torch.randn(4096, 4096)
scale = collect_quant_scale(w, n_bits=8)
w_hat = fake_quantize(w, scale, n_bits=8)
err = (w - w_hat).abs().mean().item()
print(f"평균 절대 오차: {err:.6f}")
채널별(per-channel) 스케일은 텐서 전체에 하나의 스케일을 쓰는 것보다 오차가 작습니다. 한 채널의 이상치가 다른 채널까지 망치지 않기 때문입니다. 실무에서는 SmoothQuant처럼 활성값의 이상치를 가중치 쪽으로 옮겨 양자화 난이도를 균형 맞추는 기법, 또는 AWQ처럼 중요한 채널만 정밀도를 보존하는 기법이 널리 쓰입니다.
무엇을 양자화할 것인가
- **가중치 전용(weight-only)**: 가중치만 INT4/INT8로, 연산은 FP16으로. 메모리 바운드 디코딩에 효과적입니다. 가중치를 읽는 대역폭이 줄어드니까요.
- **가중치+활성(W8A8 등)**: 둘 다 양자화해 연산 자체를 정수/저정밀 텐서코어로 돌립니다. 프리필처럼 연산 바운드 구간에서 추가 이득이 있습니다.
희소성 — 데이터를 적게 만들기
양자화가 각 값을 작게 만든다면, 희소성은 0인 값을 아예 건너뛰어 값의 개수 자체를 줄입니다.
문제는 비정형(unstructured) 희소성이 하드웨어에 친화적이지 않다는 점입니다. 가중치의 90%가 0이라도, 0의 위치가 제멋대로면 GPU의 정규화된 메모리 접근 패턴과 텐서코어의 밀집 연산 구조를 활용하기 어렵습니다. 인덱스를 따라다니는 오버헤드가 절약분을 잡아먹습니다.
그래서 등장한 것이 구조적 희소성(structured sparsity)입니다. NVIDIA Ampere 이후 텐서코어가 지원하는 **2:4 희소성**이 대표적입니다. 규칙은 단순합니다. 연속한 4개 값 중 정확히 2개를 0으로 만듭니다.
밀집: [ 0.8, 0.1, -0.3, 0.5 ]
2:4: [ 0.8, 0.0, 0.0, 0.5 ] <- 4개 중 2개만 비영(非零)
저장: 비영 값 2개 + 2비트 인덱스(어느 위치였는지)
이 패턴은 하드웨어가 좋아합니다. 비영 값의 개수가 고정(4분의 2)이라 메모리 접근이 규칙적이고, 텐서코어가 인덱스를 따라 짝을 골라내는 회로를 내장해 곱셈을 절반만 수행합니다. 이상적으로는 행렬곱 처리량이 약 2배가 됩니다.
2:4 희소 마스크를 만드는 개념 코드
def make_2to4_mask(weight: torch.Tensor):
"""행 방향으로 연속 4개마다 절댓값 작은 2개를 0으로."""
out, in_dim = weight.shape
assert in_dim % 4 == 0
w = weight.view(out, in_dim // 4, 4)
각 그룹에서 절댓값 상위 2개 위치만 유지
idx = w.abs().argsort(dim=-1, descending=True)
mask = torch.zeros_like(w)
keep = idx[..., :2]
mask.scatter_(-1, keep, 1.0)
return (w * mask).view(out, in_dim)
w = torch.randn(1024, 1024)
w_sparse = make_2to4_mask(w)
print("0의 비율:", (w_sparse == 0).float().mean().item()) # 약 0.5
실무에서는 단순히 작은 값을 0으로 만들면 정확도가 떨어지므로, 희소화 후 미세조정(fine-tuning)으로 회복하는 절차를 거칩니다. 양자화와 결합하면(예: 2:4 + INT8) 메모리와 연산을 동시에 줄일 수 있지만, 두 오차원이 겹치므로 정확도 검증을 더 신중히 해야 합니다.
활성값 희소성도 있습니다. ReLU 계열에서 많은 활성값이 0이 되는 점, MoE(Mixture of Experts)에서 토큰마다 일부 전문가만 활성화되는 점이 모두 희소성의 변형입니다. MoE는 사실상 동적 구조적 희소성으로, 전체 파라미터는 크지만 토큰당 실제 연산은 일부만 일어납니다.
Dataflow 아키텍처 — 데이터를 덜 옮기기
세 번째 축은 칩 안에서 데이터가 흐르는 방식입니다. 핵심 통찰은 한 번 가져온 데이터를 최대한 재사용하라는 것입니다. HBM에서 데이터를 한 번 읽는 비용이 칩 내부 연산보다 훨씬 비싸기 때문에, 데이터를 칩 안에 붙들어두고 여러 번 쓰는 설계가 결정적입니다.
시스톨릭 어레이와 데이터 재사용
Google TPU가 대표적으로 채택한 시스톨릭 어레이(systolic array)는 이 철학의 결정체입니다. 곱셈-누산기(MAC)를 격자로 배열하고, 데이터를 한쪽에서 밀어 넣으면 셀에서 셀로 흘러가며 연산이 파이프라인처럼 진행됩니다. 한 번 로드한 가중치가 격자 안에 머무르며 여러 입력에 재사용되므로 메모리 접근이 극적으로 줄어듭니다.
시스톨릭 어레이 (가중치 고정형)
입력 → [w][w][w][w]
입력 → [w][w][w][w] 각 [w]는 곱셈-누산 셀
입력 → [w][w][w][w] 가중치는 셀에 머물고
입력 → [w][w][w][w] 입력/부분합만 흘러간다
↓
출력(부분합 누적)
dataflow 설계는 무엇을 칩에 고정하느냐로 분류됩니다.
- **가중치 고정(weight stationary)**: 가중치를 셀에 두고 입력을 흘림. 가중치 재사용이 큼.
- **출력 고정(output stationary)**: 부분합을 셀에 누적. 출력 재사용이 큼.
- **입력/행 고정(row stationary)**: 입력 행을 재사용. 에너지 효율을 노린 절충형(Eyeriss 등 연구).
타일링 — 메모리 계층을 의식한 분할
GPU에서도 같은 원리가 타일링(tiling)으로 구현됩니다. 큰 행렬곱을 작은 블록으로 쪼개, 한 블록을 빠른 온칩 메모리(공유 메모리/레지스터)에 올린 뒤 거기서 최대한 많은 연산을 끝냅니다. 느린 HBM 왕복을 줄이는 것이 목적입니다.
C = A x B 를 타일로 분할
A B C
[A00 A01] [B00 B01] [C00 C01]
[A10 A11] [B10 B11] [C10 C11]
C00 = A00*B00 + A01*B10 <- 타일 단위로 누적
한 타일은 공유 메모리에 올려두고 재사용
타일 크기를 고르는 것은 트레이드오프입니다. 타일이 크면 재사용이 늘지만 온칩 메모리에 안 들어가고, 작으면 들어가지만 HBM 왕복이 늘어납니다. 이 지점을 자동으로 탐색하는 것이 뒤에 나올 컴파일러의 역할입니다.
연산자 융합 — 중간 결과를 메모리에 쓰지 않기
딥러닝 그래프는 작은 연산이 길게 이어집니다. 행렬곱 → 바이어스 덧셈 → 활성함수 → 정규화 같은 식입니다. 각 연산을 따로 실행하면, 매 단계마다 중간 텐서를 HBM에 썼다가 다음 단계에서 다시 읽습니다. 메모리 바운드 관점에서 이는 낭비의 연속입니다.
연산자 융합(operator fusion)은 이 연속된 연산을 하나의 커널로 합쳐, 중간 결과를 온칩 레지스터/공유 메모리에 둔 채로 이어서 처리합니다. HBM 왕복이 사라집니다.
융합 전: MatMul -> [HBM] -> Bias -> [HBM] -> GELU -> [HBM]
융합 후: MatMul + Bias + GELU (한 커널, 중간값은 칩 안에)
가장 유명한 사례가 FlashAttention입니다. 어텐션의 거대한 중간 행렬(점수 행렬)을 통째로 HBM에 만들지 않고, 블록 단위로 흘려보내며 소프트맥스를 온라인으로 누적합니다. 메모리 사용량을 줄이는 동시에 대역폭 병목을 풀어 긴 컨텍스트 추론을 실용적으로 만들었습니다. 융합은 컴파일러가 자동으로 찾아주기도 하고, 핵심 경로는 사람이 직접 커널을 작성하기도 합니다.
배칭과 KV 캐시 — 처리량과 지연의 줄다리기
디코딩이 메모리 바운드인 핵심 이유는 배치가 1일 때 가중치를 한 번 읽어 토큰 하나만 만들기 때문입니다. 그렇다면 여러 요청을 묶어(batch) 가중치 한 번 읽기로 여러 토큰을 만들면 연산 강도가 올라가 칩이 제대로 일합니다.
문제는 실제 서빙에서 요청이 제각각 다른 시점에 도착하고 길이도 다르다는 점입니다. 이를 해결하는 것이 **연속 배칭(continuous batching)**입니다. 고정된 배치를 기다리지 않고, 토큰 생성 스텝마다 끝난 요청을 빼고 새 요청을 끼워 넣어 GPU를 쉬지 않게 합니다.
KV 캐시
트랜스포머는 이전 토큰들의 key/value를 다시 계산하지 않기 위해 KV 캐시에 저장합니다. 이 캐시는 시퀀스가 길어질수록, 배치가 클수록 선형으로 커지며 빠르게 메모리를 잠식합니다.
KV 캐시 크기(바이트)
= 2(K,V) x layers x heads x head_dim
x seq_len x batch x bytes_per_elem
13B급 모델에서 컨텍스트가 길어지면 KV 캐시가 수십 GB에 이르기도 합니다. 그래서 다음 기법들이 쓰입니다.
- **PagedAttention**: KV 캐시를 운영체제의 페이징처럼 작은 블록으로 관리해 메모리 단편화를 줄임(vLLM의 핵심).
- **KV 캐시 양자화**: 캐시를 INT8/FP8로 저장해 용량과 대역폭을 절반으로.
- **GQA/MQA**: 여러 어텐션 헤드가 key/value를 공유해 캐시 크기를 줄임.
배칭과 KV 캐시 관리는 결국 처리량(throughput)과 지연(latency) 사이의 줄다리기입니다. 배치를 키우면 처리량은 오르지만 개별 요청의 응답이 느려질 수 있습니다. 챗봇처럼 첫 토큰 지연(TTFT)이 중요한 워크로드와, 대량 배치 처리처럼 총 처리량이 중요한 워크로드는 다른 지점에서 균형을 잡아야 합니다.
컴파일러 최적화 — 사람 대신 탐색하기
지금까지 본 타일 크기 선택, 융합 결정, 메모리 배치는 손으로 일일이 튜닝하면 끝이 없습니다. 그래서 딥러닝 컴파일러가 이 탐색을 자동화합니다.
대표적으로 다음 계층이 있습니다.
- **그래프 수준 IR**: 연산 그래프를 받아 융합, 상수 접기, 레이아웃 변환 등을 적용(예: TVM, XLA, TorchInductor의 그래프 단계).
- **타일/스케줄 탐색**: 연산을 하드웨어에 맞춰 타일링하고 루프 순서를 정하는 단계. Triton이 대표적으로, 파이썬에 가까운 문법으로 GPU 커널을 쓰면 컴파일러가 메모리 배치와 병렬화를 처리합니다.
- **자동 튜닝**: 여러 타일 크기/스케줄 후보를 실제로 돌려보고 가장 빠른 것을 고름.
Triton 스타일 의사 커널 (개념 설명용)
@triton.jit 데코레이터가 붙으면 GPU 커널로 컴파일된다고 가정
def fused_add_relu(x_ptr, y_ptr, out_ptr, n, BLOCK: int):
pid = program_id(0) # 블록 인덱스
offs = pid * BLOCK + arange(0, BLOCK)
mask = offs < n
x = load(x_ptr + offs, mask=mask)
y = load(y_ptr + offs, mask=mask)
z = x + y
z = where(z > 0, z, 0.0) # ReLU를 같은 커널에서 융합
store(out_ptr + offs, z, mask=mask)
핵심은 "무엇을 계산할지"(수학)와 "어떻게 계산할지"(스케줄)를 분리하는 것입니다. 같은 행렬곱이라도 칩마다, 형상마다 최적 스케줄이 다릅니다. 컴파일러는 이 거대한 탐색 공간을 사람보다 빠르게 훑습니다.
정확도-효율 트레이드오프 — 공짜 점심은 없다
지금까지의 모든 기법은 정확도를 대가로 효율을 삽니다. 중요한 것은 그 환율을 측정하는 일입니다.
| 기법 | 얻는 것 | 잃을 수 있는 것 | 완화책 |
| --- | --- | --- | --- |
| INT8 양자화 | 대역폭/메모리 절반 | 소폭 정확도 저하 | 채널별 스케일, 보정 |
| FP4/INT4 | 대역폭 4분의 1 | 저비트일수록 큰 저하 | QAT, 마이크로스케일링, 혼합 정밀도 |
| 2:4 희소성 | 연산 약 2배 | 표현력 손실 | 희소화 후 미세조정 |
| KV 캐시 양자화 | 캐시 절반 | 긴 컨텍스트에서 누적 오차 | FP8 사용, 민감 레이어 보존 |
실무 원칙 몇 가지입니다.
- 한 번에 한 가지 기법만 적용하고 정확도를 측정합니다. 여러 개를 동시에 켜면 어디서 무너졌는지 알 수 없습니다.
- 평균 지표뿐 아니라 꼬리(tail) 사례를 봅니다. 양자화는 평균 정확도는 멀쩡한데 특정 입력에서만 무너지는 경우가 흔합니다.
- 모든 레이어를 같은 정밀도로 다루지 않습니다. 어텐션 출력이나 첫/마지막 레이어처럼 민감한 부분은 정밀도를 높게 둡니다(혼합 정밀도).
하드웨어-소프트웨어 공동설계 — 큰 그림
여기까지 보면 한 가지가 분명해집니다. 양자화 포맷, 희소성 패턴, dataflow, 컴파일러는 따로 노는 기술이 아니라 함께 설계됩니다.
- Blackwell의 2세대 Transformer Engine이 FP4를 네이티브로 지원하기 때문에, 소프트웨어가 마이크로스케일링 양자화를 채택할 가치가 생깁니다.
- 텐서코어가 2:4 패턴을 회로로 이해하기 때문에, 프레임워크가 그 패턴에 맞춰 희소화합니다.
- HBM 대역폭과 NVLink/UALink 인터커넥트의 한계가 타일 크기와 배칭 전략을 결정합니다.
2026년 흐름도 이 공동설계의 연장선입니다. NVIDIA는 차세대 Vera Rubin에서 HBM4와 함께 perf/watt를 약 10배 끌어올리는 것을 목표로 내세웠고, Google은 TPU v6 Trillium(전세대 대비 peak 약 4.7배)과 추론 특화 7세대 Ironwood로 추론 효율을 정조준했습니다. 클라우드 사업자들의 자체 추론 ASIC 비중이 빠르게 늘어(2024년 약 15%에서 2026년 40% 전망) 추론 워크로드에 칩을 맞춤 설계하는 흐름이 가속됩니다. NVIDIA가 여전히 가속기 시장의 약 75~80%를 쥐고 있지만, AMD MI350X를 비롯한 경쟁과 자체 ASIC의 부상으로 추론 시장의 지형이 다층화되고 있습니다.
요점은, 추론 최적화를 한 기법으로 보지 말고 하드웨어 세대와 함께 움직이는 스택으로 보아야 한다는 것입니다.
실무 적용 — 어디서부터 손댈까
새 모델을 서빙해야 한다고 가정하고 순서를 제안합니다.
1. **측정부터.** 워크로드가 프리필 중심인지 디코딩 중심인지, 메모리 바운드인지 연산 바운드인지 프로파일링합니다. 병목을 모른 채 최적화하면 헛수고입니다.
2. **검증된 서빙 엔진을 먼저.** vLLM, TensorRT-LLM 같은 엔진은 연속 배칭, PagedAttention, 융합 커널을 이미 갖췄습니다. 바닥부터 만들 일이 거의 없습니다.
3. **가중치 양자화부터.** 디코딩이 메모리 바운드라면 INT8/INT4 가중치 양자화가 가장 큰 즉효를 냅니다. 정확도를 측정해 합격선을 확인합니다.
4. **KV 캐시를 관리.** 긴 컨텍스트라면 PagedAttention과 KV 캐시 양자화로 메모리를 확보합니다.
5. **그다음 희소성/저비트.** 여기까지 부족하면 2:4 희소성, FP4 같은 더 공격적인 기법으로 넘어갑니다. 반드시 미세조정과 검증을 동반합니다.
6. **칩 세대를 활용.** 최신 칩의 FP4/FP8 텐서코어를 쓰려면 그에 맞는 컴파일러/런타임 버전이 필요합니다. 하드웨어와 소프트웨어 버전을 함께 맞춥니다.
흔한 함정도 정리합니다.
- 정확도 검증 없이 양자화를 프로덕션에 올렸다가 특정 입력에서만 품질이 무너지는 사례.
- 비정형 희소성에 기대했다가 실제로는 속도가 안 나는 사례(구조적 희소성이 아니면 하드웨어 이득이 거의 없음).
- 배치를 무작정 키워 처리량은 좋아졌는데 첫 토큰 지연이 사용자 체감을 망치는 사례.
추론과 학습 워크로드는 무엇이 다른가
지금까지의 모든 최적화가 "추론"에 초점을 맞춘 데는 이유가 있습니다. 추론과 학습은 같은 모델을 다루지만 하드웨어가 마주하는 부하의 성격이 전혀 다릅니다.
| 항목 | 학습 | 추론 |
| --- | --- | --- |
| 방향 | 순전파 + 역전파 | 순전파만 |
| 정밀도 | BF16/FP8 위주, 수치 안정성 중요 | INT8/FP4까지 공격적 양자화 가능 |
| 메모리 | 활성값·옵티마이저 상태로 폭증 | 가중치 + KV 캐시 중심 |
| 배치 | 크게 잡아 처리량 극대화 | 지연 제약으로 작게 쪼개지기도 |
| 지표 | 수렴 속도, 총 처리량 | 지연(TTFT/토큰당), 처리량, 비용 |
학습은 한 번 잘 끝내면 되는 일이라 처리량이 거의 전부입니다. 반면 추론은 끝없이 반복되며, 사용자가 기다리는 지연이 직접적인 품질이 됩니다. 그래서 추론 최적화는 "평균 처리량"과 "꼬리 지연"을 동시에 만족시켜야 하는 더 까다로운 문제입니다.
이 차이가 칩 설계에도 반영됩니다. 학습용 칩은 높은 정밀도와 거대한 메모리, 빠른 칩 간 인터커넥트를 중시하지만, 추론 특화 칩(예: TPU Ironwood, 각종 추론 ASIC)은 저정밀 연산 밀도와 와트당 효율, 낮은 지연을 우선합니다. 추론 capex가 학습을 추월한 2026년에 추론 전용 칩이 쏟아지는 배경입니다.
작은 사례 연구 — 숫자로 따라가기
앞의 개념들을 하나의 가상 시나리오로 묶어 봅시다. 70B 모델을 단일 GPU에서 챗봇으로 서빙한다고 가정합니다.
출발점 (FP16, 배치 1)
가중치 약 140GB -> 단일 GPU 메모리 초과, 일부 오프로딩 필요
토큰당 가중치 1회 읽기 -> 약 24 토큰/초 (대역폭 한계)
GPU 연산 유닛 활용률: 매우 낮음
1단계: INT8 가중치 양자화
가중치 약 70GB -> 메모리 여유, 대역폭 절반
토큰당 속도 약 2배 -> 약 45~48 토큰/초
정확도: 채널별 스케일로 거의 무손실
2단계: 연속 배칭 (동시 요청 16개)
가중치 1회 읽기로 16개 토큰 생성
연산 강도 상승 -> GPU 활용률 크게 개선
총 처리량 수 배, 개별 지연은 소폭 증가
3단계: KV 캐시 양자화 + PagedAttention
긴 컨텍스트에서도 메모리 단편화 억제
더 많은 동시 요청 수용 -> 비용/요청 하락
이 시나리오의 교훈은 분명합니다. 어떤 단일 기법도 마법이 아니지만, 병목을 따라 순서대로 쌓으면 같은 칩에서 처리량이 수 배로 뛰고 요청당 비용이 크게 떨어집니다. 그리고 매 단계마다 반드시 정확도와 지연을 측정해 "공짜로 보이지만 사실은 대가가 있는" 변화를 걸러내야 합니다.
핵심은 측정 → 가장 큰 병목 해소 → 재측정의 반복입니다. 화려한 기법 목록을 외우는 것보다, 내 워크로드의 루프라인 위 어디에 점이 찍혀 있는지를 아는 것이 먼저입니다.
마치며
추론을 빠르게 만드는 일은 결국 하나의 문장으로 압축됩니다. 데이터를 작게(양자화), 적게(희소성), 덜 옮기게(dataflow와 융합) 만들고, 그것을 칩이 실제로 활용하도록 배칭과 컴파일러로 연결하는 것입니다. 이 모든 전략은 메모리 월이라는 같은 뿌리에서 자라났습니다.
2026년의 칩들은 점점 더 추론을 1순위로 두고 설계됩니다. FP4가 회로에 들어오고, 추론 전용 ASIC이 늘고, 컴파일러가 더 똑똑해질수록, 엔지니어의 역할은 "어떤 마법의 기법을 켜느냐"에서 "내 워크로드의 병목을 정확히 진단하고 올바른 트레이드오프를 고르느냐"로 옮겨갑니다. 측정하고, 한 번에 하나씩 적용하고, 정확도를 지키는 규율 — 그것이 빠른 추론의 진짜 비결입니다.
참고 자료
- NVIDIA Blackwell 아키텍처: [https://www.nvidia.com/en-us/data-center/technologies/blackwell-architecture/](https://www.nvidia.com/en-us/data-center/technologies/blackwell-architecture/)
- NVIDIA Transformer Engine 문서: [https://docs.nvidia.com/deeplearning/transformer-engine/](https://docs.nvidia.com/deeplearning/transformer-engine/)
- Google Cloud TPU: [https://cloud.google.com/tpu](https://cloud.google.com/tpu)
- vLLM (PagedAttention): [https://docs.vllm.ai/](https://docs.vllm.ai/)
- NVIDIA TensorRT-LLM: [https://github.com/NVIDIA/TensorRT-LLM](https://github.com/NVIDIA/TensorRT-LLM)
- OpenAI Triton: [https://triton-lang.org/](https://triton-lang.org/)
- FlashAttention 논문(arXiv): [https://arxiv.org/abs/2205.14135](https://arxiv.org/abs/2205.14135)
- 양자화/희소성 관련 일반 검색(arXiv): [https://arxiv.org/list/cs.LG/recent](https://arxiv.org/list/cs.LG/recent)
- SemiAnalysis(업계 분석): [https://www.semianalysis.com/](https://www.semianalysis.com/)
현재 단락 (1/202)
학습이 끝난 모델은 한 번 만들어지지만, 추론은 모델이 살아 있는 내내 매일 수십억 번 일어납니다. 2026년 들어 업계에서 추론 capex가 학습 capex를 처음으로 추월했다는...