TPU가 토큰당 비용이 더 저렴함에도 불구하고 인기가 없는 이유
요약
TPU와 Trainium이 GPU 대비 비용과 전력 효율 면에서 우수함에도 불구하고 NVIDIA가 시장을 점유하는 이유를 아키텍처 관점에서 분석합니다. 시스톨릭 어레이 기반의 정적 형태(static shapes) 제약이 실시간 추론 환경에서 발생하는 운영상의 어려움을 설명합니다.
핵심 포인트
- TPU/Trainium은 시스톨릭 어레이 구조로 컴파일 시 데이터 형태가 고정됨
- NVIDIA GPU는 동적 스케줄링을 통해 런타임 입력 변화에 유연하게 대응
- 정적 형태 제약은 입력 크기 변경 시 새로운 컴파일을 요구하는 '아키텍처 세금' 발생
- NVIDIA는 Python처럼 유연하고, TPU는 Java처럼 엄격한 동작 모델을 가짐
사양서(spec sheet)만 본다면 TPU의 이야기는 압도적입니다. 더 낮은 토큰당 비용(cost-per-token), 극적으로 개선된 토큰당 전력 효율(watts-per-token), 그리고 결정론적 지연 시간(deterministic latency)을 제공합니다. Trainium 역시 같은 이야기를 합니다. 하지만 ChatGPT와 Claude의 웹 UI 뒤에서 작동하는 추론(inference) 트래픽을 포함하여 업계의 대부분은 여전히 NVIDIA 위에서 구동됩니다. "서류상으로는 더 저렴한 것"과 "사람들이 실제로 배포하는 것" 사이의 격차는 마케팅의 실패가 아닙니다. 그것은 시스톨릭 어레이(systolic-array) 실리콘이 코드, 파이프라인, 그리고 조직 구조를 통해 부과하는 아키텍처 세금(architectural tax)입니다. 이 포스트는 그 세금이 어디에서 오는지, 그리고 왜 오직 소수의 기업만이 그 세금을 감당할 여력이 있는지에 대해 다룹니다.
모든 것을 설명하는 단 하나의 아키텍처적 사실: 정적 형태 (static shapes)
NVIDIA GPU는 SIMT (Single Instruction, Multiple Threads) 프로세서입니다. 이들은 런타임(runtime)에 스레드를 동적으로 스케줄링하고 필요에 따라 메모리를 페이징(page memory)합니다. TPU와 AWS Trainium은 GPU가 아닙니다. 이들은 **시스톨릭 어레이 (systolic arrays)**입니다. 즉, 이웃한 유닛들과 직접 연결된 곱셈-누산(multiply-accumulate) 유닛의 그리드이며, 사전 컴파일러(TPU의 경우 XLA, Trainium의 경우 Neuron 컴파일러)에 의해 데이터를 공급받습니다.
시스톨릭 어레이는 흐르는 데이터의 형태(shape)가 **컴파일 시점에 고정(fixed at compile time)**될 때만 최대 활용도(peak utilization)에 도달합니다. 가중치(Weights)는 한 번 로드되면 프로세싱 엘리먼트(processing elements) 내에 정지 상태로 머물고, 활성화 값(activations)은 양동이 릴레이(bucket brigade)처럼 미끄러지듯 통과합니다. 시퀀스 길이(sequence length)나 배치 크기(batch size)를 단 하나의 토큰이라도 변경하면 데이터 경로와 메모리 주소를 다시 계산해야 하며, 이는 컴파일러가 *새로운 바이너리(new binary)*를 생성해야 함을 의미합니다.
그 단 하나의 제약 조건이 모든 하류(downstream) 고통의 근원입니다. 이것이 추론(inference) 시점에 여러분에게 강요하는 사항은 다음과 같습니다:
| 런타임 입력 (Runtime input) | NVIDIA (동적/dynamic) | TPU / Trainium (정적/static) |
|---|---|---|
| 컴파일된 버킷보다 큰 경우 | 동적 할당(dynamic allocation)으로 처리 | 형태 불일치 충돌 (Shape-mismatch crash) |
| ... | ... | ... |
따라서 어떤 토큰이 칩에 도달하기 전에, 여러분은 다음 질문에 대한 답을 가지고 있어야 합니다: "이것의 형태(shape)는 무엇이며, 어떤 사전 컴파일된 바이너리로 라우팅해야 하는가?" NVIDIA에서는 결코 그런 질문을 던질 필요가 없습니다.
동적 vs 정적 비유: Python vs Java
가장 깔끔한 사고 모델(Mental model): NVIDIA는 Python이고, TPU/Trainium은 Java입니다.
- NVIDIA = Python. 동적 타이핑 (Dynamic typing) ≈ 동적 형상 (Dynamic shapes). 런타임 (Runtime)이 혼란을 흡수합니다. 100개 토큰의 프롬프트든 50,000개 토큰의 프롬프트든 동일한
forward에 던져 넣으면, 컴파일 단계(Compile step)를 거칠 필요 없이
xm.mark_step()이 실제 실행 트리거입니다. CUDA의 Eager mode와 달리, XLA에서model(x)를 호출하는 것은 단지 *그래프를 축적(accumulate)*할 뿐입니다.mark_step()이 축적된 그래프를 하나의 고정된 바이너리로 컴파일하여 전송하기 전까지는 칩 위에서 아무것도 실행되지 않습니다. 새로운 형태(Shape)가 나타나면 → 새로운 컴파일이 발생합니다.masked_fill(..., -1e9)는 최적화가 아니라 해킹(hack)입니다. NVIDIA의varlen경로는 사용자 간의 곱셈을 완전히 건너뜁니다(skips). 반면 시스톨릭 어레이(Systolic array)는 건너뛸 수 없습니다. 0을 포함하여 직사각형의 모든 셀을 반드시 곱해야 하며, 그 후 Softmax 단계에서 수학적으로 해당 값들을 무효화해야 합니다. 전력을 소모한 뒤, 그 결과를 그냥 버리는 셈입니다.
"가장 작은 입력"의 함정
오버플로우(Overflow)로 인한 충돌 사례는 직관적입니다. 1,024개로 컴파일된 바이너리에 1,025개의 토큰을 입력하면 형태 불일치(Shape mismatch)가 발생합니다. 더 까다로운 사례는 언더플로우(Underflow), 즉 1,024개 시스템에 100개 토큰의 요청이 들어오는 경우입니다:
- 그대로 통과시킬 경우: XLA는 새로운 형태(Shape)를 감지하고 JIT 재컴파일(recompile)을 트리거합니다. 프로덕션 환경에서는 이는 몇 분간의 프리징(freeze)을 의미합니다. 정지(Stall) 상태가 되는 것이죠.
- 1,024로 패딩(Pad)할 경우: 어레이는 약 90%의 셀에 대해 충실하게
0 × 0 + 0을 수행하며, 아무것도 계산하지 않으면서 전체 전력을 소비합니다. 이용률(Utilization)이 붕괴됩니다.
탈출구는 **패킹(Packing)**입니다. 버킷(Bucket)당 한 명의 사용자를 배치하는 대신, 테트리스처럼 여러 사용자의 요청을 고정된 직사각형 안에 타일링(tile)하고, 어텐션(Attention)이 사용자 간에 번지지 않도록 세그먼트 ID 마스크(segment-ID mask)를 생성하는 방식입니다.
고정 버킷 [ 8192 tokens ]
├─ 사용자 A 쿼리 (3000)
├─ 사용자 B 쿼리 (4000)
...
"직사각형"이 물리적으로 무엇인지 구체적으로 이해하는 것이 도움이 됩니다. BATCH_SIZE = 4, STATIC_SEQ_LEN = 8192로 컴파일할 때, XLA는 TPU의 HBM 내에 **하나의 연속적인 [4, 8192] 정적 영역(static region)**을 예약합니다. 이는 네 개의 독립된 "방"이 아니라, 컴파일러가 어레이 경로를 하드와이어링(hard-wires)하는 하나의 커다란 시트(sheet)와 같습니다. 단일 사용자가 8,192개의 레인(lane)을 다 채우는 경우는 드물기 때문에, 서빙 레이어는 네 개의 레인 전체에 걸쳐 여러 사용자를 한꺼번에 패킹합니다:
[ 하나의 TPU 프로세서: 하나의 정적 [4 x 8192] 시트 ]
lane[0] (8192): [ A(2000) + B(5000) + C(1000) + pad(192) ]
...
물리적으로는 4개의 레인(32K의 공간)이 존재하지만, 논리적으로 프록시는 단지 **9명의 불규칙한 사용자(A–I)**를 그 안에 쑤셔 넣었을 뿐입니다. 애플리케이션 측면에서는 하나의 TPU가 병렬로 많은 작은 요청을 동시에 처리하는 것처럼 보이지만, 그 내부에서는 세그먼트 마스크(segment mask)가 그려진 하나의 경직된 시트(sheet)일 뿐입니다. 하드웨어가 미리 나누어진 작은 방들 대신 하나의 커다란 시트를 원하는 이유는 순수하게 시스톨릭 어레이 (systolic-array) 물리 법칙 때문입니다. 행렬이 커질수록 어레이의 채우기 비율 (fill rate)이 높아지고, 데이터 공급 사이의 유휴 사이클 (idle cycles)이 줄어듭니다.
제대로 구현된다면, MFU (Model FLOPs Utilization, 모델 연산 효율)는 100%에 근접합니다. 하지만 방금 당신이 무엇을 만들었는지 주목하십시오. 클러스터 앞에 불규칙한 입력을 받아 실시간으로 직사각형 형태로 채워 넣는 역할만을 수행하는 고처리량 (high-throughput) Go/C++ 프록시를 구축한 것입니다. NVIDIA에서는 이 전체 계층이 존재하지 않습니다.
하나의 기능이 아니라, 전체 파이프라인이 갈라집니다
사람들은 xm.xla_device()가 TPU와 Trainium을 모두 투명하게 타겟팅하기 때문에 (공유된 OpenXLA/PJRT 런타임 덕분 — TPU의 경우 libtpu.so, Neuron의 경우 libneuronpjrt.so), torch_xla가 하드웨어를 추상화한다고 가정합니다. 이는 model.to(device)와 기본적인 연산(ops)에는 해당되는 이야기입니다. 하지만 중요한 부분들에 대해서는 결코 그렇지 않습니다.
forward 시그니처(signature) 자체부터 갈라집니다:
# NVIDIA forward: 불규칙한 데이터(ragged data) + 경계 인덱스(boundary index). 호출할 때마다 길이는 임의적임.
def forward(self, input_ids, cu_seqlens, max_seqlen):
return self.flash_attn_func(input_ids, cu_seqlens, max_seqlen)
...
그리고 이는 아래로 끝까지 연쇄적으로 이어집니다:
| 구성 요소 | NVIDIA 파이프라인 | Trainium 파이프라인 |
|---|---|---|
| 추론 엔진 (Inference engine) | vLLM (CUDA), TensorRT-LLM | NxD / vllm-neuron |
| ... |
완전히 평행한 두 세계입니다. 당신의 CUDA 컨테이너, 평가 스크립트, 오토스케일링 트리거 등 그 어떤 것도 그대로 넘어오지 않습니다. vLLM의 하드웨어 플러그인 메커니즘은 비즈니스 로직 계층에서
데이터 타입(data-type) 측면의 이야기 또한 대칭적이지 않습니다. BF16(Google의 TPU가 개척한 방식)은 양측 모두에서 안정적입니다. BF16의 FP32 범위 지수(exponent)는 -1e9 마스크 값에서도 NaN(Not a Number)으로 변하지 않고 살아남습니다. 하지만 현재 처리량(throughput)을 높이기 위한 핵심인 FP8은 NVIDIA에 유리합니다. FP8 어텐션(attention) 점수는 변동 폭이 매우 커서, 클리핑(clipping)을 방지하기 위해 런타임 시 **동적 스케일링 (dynamic scaling)**이 필요합니다. 정적 컴파일러(static compiler)는 컴파일 시점에 고정된 스케일 인자를 구워 넣어야 하므로, TPU나 Trainium에서 공격적으로 FP8 어텐션을 사용하면 모델 품질을 저하시키는 클리핑 위험이 발생합니다. NVIDIA에서는 "그냥 FP8로 바꾸세요"라고 한 줄로 끝날 일이, 정적 실리콘(static silicon) 환경에서는 하나의 연구 프로젝트가 됩니다.
숨겨진 비용: 조직 구조의 붕괴
이것이 채택을 가로막는 부분이며, 아무도 슬라이드에 담지 않는 내용입니다. NVIDIA에서는 깔끔한 추상화 경계(abstraction boundary)가 존재합니다:
[ AI 엔지니어 / 데이터 사이언티스트 ]
아키텍처, 하이퍼파라미터, 평가
│
...
데이터 사이언티스트는 메모리 레이아웃(memory layout)에 대해 전혀 고민하지 않습니다. MLOps 엔지니어는 어텐션 수학식을 읽지 않습니다. 그들은 깔끔한 인터페이스를 통해 결과물(artifacts)을 전달할 뿐입니다.
TPU에서는 모델 구조가 물리적 제약 조건과 직접 결합되어 있기 때문에 그 장벽이 사라집니다:
- 패킹 방식(MLOps)과
forward내부의 세그먼트 마스크(segment-mask) 로직(AI 엔지니어)은 하나의 설계를 이루는 두 절반입니다. 배치 전략(batching strategy)을 변경하면 수학식도 발맞추어 변경되어야 합니다. 이를 사양서(spec doc)로 분리할 수 없습니다. - AI 엔지니어가 무심코
if분기를 추가하거나 레이어 수를 변경하면 컴파일된 그래프 토폴로지(graph topology)가 변경되며, 이는 운영 환경에서 JIT 스톨(JIT stalls)이나 OOM(Out of Memory)을 유발합니다. 이를 디버깅하려면 XLA HLO 그래프를 덤프해야 하며, 이는 AI 엔지니어를 "인프라" 장애 상황으로 끌어들입니다. - "처리량을 2배로 높이기 위해 BF16 → FP8로 전환(MLOps)"은 "FP8 정적 스케일링이 특정 작업에서 환각(hallucinations)을 유발함(데이터 사이언티스트)"과 정면으로 충돌합니다. NVIDIA에서는 런타임이 이를 대신 협상해 줍니다. TPU에서는 두 사람이 직접 얼굴을 맞대고 협상해야 합니다.
TPU에서 성공을 거둔 조직들 — Google의 Gemini 팀, Anthropic의 Claude 팀, Meta의 Llama-on-TPU 그룹 — 은 "데이터 과학 부서 / 인프라 부서"라는 수평적 분리를 완전히 포기했습니다. 이들은 어텐션 수학 (attention math)과 컴파일러 내부 구조 (compiler internals) 모두에 능통한 인력들로 구성된 단일 수직 통합 팀을 운영합니다. 대부분의 기업은 그런 인력을 배치할 수 없으며, 기존의 분업 방식을 유지하려는 프로젝트들은 컴파일 에러 (compile errors)와 OOM (Out of Memory)의 더미 속에서 사멸합니다.
그렇다면 왜 사람들은 TPU를 사용하는가? 입력이 고정되어 있기 때문이다
입력 채널을 제어하여 텐서 형태 (shapes)를 예측할 수 있게 되면 모든 계산 방식이 뒤바뀝니다. 두 가지 명확한 사례가 있습니다:
- Google / YouTube 요약. Google은 비디오를 다시 시청하지 않습니다. 업로드 시점에 (남는 TPU 사이클을 활용한) 비동기 배치 작업 (async batch job)이 ASR (자동 음성 인식)을 실행하고, 타임스탬프가 찍힌 텍스트를 Bigtable과 같은 저장소에 저장합니다. 사용자가 요약을 요청할 때, 정확한 텍스트 길이는 _이미 토큰 단위까지 알고 있는 상태_입니다. 따라서 라우터 (router)가 딱 맞는 버킷 (bucket)을 선택하여 낭비되는 패딩 (packing waste)을 거의 제로에 가깝게 줄이며, Gemini Flash와 같은 가벼운 모델이 미리 계산된 텍스트를 스캔합니다. "2시간짜리 영상을 즉시 요약한다"는 마법은 사실 "몇 달 전에 거의 공짜로 구축해 둔 아주 작은 텍스트 인덱스를 스캔한다"는 의미입니다.
- Anthropic / Claude Code. CLI 코딩 에이전트는 저장소 구조, 도구 정의, git diff, 시스템 프롬프트 등 거의 완전히 결정된 입력을 가집니다. 컨텍스트 (context)의 처음 약 90%는 불변하며, 이는 정적 컴파일 (static compilation)과 프롬프트 캐싱 (prompt caching)이 가장 선호하는 환경입니다. 실제로 Anthropic은 프로덕션 서빙을 Trainium (
neuronx-distributed, 실시간 패킹을 수행하는 Go/C++ 프록시 포함)으로 옮겼으며, Claude Code는 — 냉소적으로 읽자면 — Java 스타일의 칩을 사용할 만한 가치가 있게 만드는 완벽한 입력 고정 채널입니다. 긴 컨텍스트 (long-context) 워크로드 또한 도움이 됩니다. 200K 토큰의 프리필 (prefill)은 32K 버킷을 패딩 거의 없이 채우므로, 정적 배열 (static array)의 약점이 Claude가 가장 강력한 지점에서 정확히 사라집니다.
그 반대의 경우도 마찬가지로 논리적이며, 이는 왜 채팅 (chat) UI들이 NVIDIA를 계속 사용하는지를 설명해 줍니다. ChatGPT와 Claude.ai의 웹 프론트엔드(web frontends)는 임의의 텍스트, 갑작스러운 이미지 업로드, 그리고 대화 도중 주제 전환을 허용합니다. 시스템은 사용자가 전송 버튼을 누르기 전까지는 그 형태를 예측할 수 없습니다. 그러한 혼돈이야말로 바로 동적 SIMT와 PagedAttention이 만들어진 목적입니다.
핵심 요약 (Takeaways)
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기