Deep Dive원 논문 arXiv v2·공식 DeepSeek-V3 코드와 config·공식 weight 문서·Python 3.9 직접 계산

DeepSeek-V3 Technical Report 해부: 671B인데 토큰마다 37B만 쓰는 MoE 시스템

DeepSeek-V3 Technical Report를 MoE 라우팅, MLA KV cache 압축, MTP, FP8 학습, 분산 통신, 사후학습과 배포까지 연결해 읽는다. 671B/37B라는 숫자가 제품의 비용·지연 시간·운영 복잡도에 뜻하는 바를 직접 계산으로 확인한다.

0단계 두 번째 논문. 이 글은 DeepSeek-V3 Technical Report arXiv v2(2025-02-18)를 읽고 정리한 기록이다. 논문이 보고한 DeepSeek-V3와 당시 비교 모델의 결과를 설명한다. 2026년 현재의 "최신 최고 모델" 순위를 주장하는 글이 아니다.

이 글에서 얻을 답과 범위

첫 글의 Llama 3 Herd가 dense Transformer(밀집 Transformer)를 큰 데이터·큰 규모·안정적 운영으로 만드는 법을 보여 줬다면, 이 글의 질문은 반대편에 가깝다.

671B 파라미터를 저장하면서도, 한 토큰에 약 37B 파라미터만 계산하려면 모델·메모리·네트워크를 어떻게 함께 설계해야 할까?

이 글을 읽고 다음을 설명할 수 있으면 된다.

  1. MoE(Mixture of Experts, 전문가 혼합)에서 총 파라미터 671B활성 파라미터 37B는 무엇이 다른가?
  2. router(라우터)는 토큰을 expert(전문가)에게 어떻게 보내며, 왜 load balancing(부하 균형)이 모델 품질 문제이자 분산 시스템 문제인가?
  3. MLA(Multi-head Latent Attention, 다중 헤드 잠재 어텐션)는 KV cache(Key-Value cache, 키-값 캐시)를 왜 크게 줄이는가?
  4. MTP(Multi-Token Prediction, 다중 토큰 예측)는 실제 답변을 두 토큰씩 항상 출력하는 기능인가?
  5. FP8, DualPipe, expert parallelism(전문가 병렬화), redundant expert(중복 배치 전문가)는 왜 논문 바깥의 "구현 세부"가 아니라 모델의 실현 조건인가?
  6. RAG·AI 백엔드·데이터 파이프라인을 만드는 나는 이 논문에서 무엇을 가져오고, 무엇은 당장 하지 말아야 하는가?

범위: 논문의 언어 모델, 학습, 사후학습, 배포를 다룬다. H800 클러스터를 재현하거나 671B 가중치를 실행하지는 않는다. 이 컴퓨터에는 NVIDIA GPU와 DeepSeek-V3 가중치가 없으므로, 본문 후반의 직접 검증은 공개된 configuration(설정값)으로 MLA cache와 router 원리를 계산한 것이다.

먼저 외울 한 문장

DeepSeek-V3는 토큰마다 필요한 8개 routed expert(경로 선택 전문가)와 1개 shared expert(공유 전문가)만 실행하는 671B MoE Transformer이며, MLA로 KV cache를 압축하고, router 부하·GPU 통신·FP8 수치 오차를 동시에 다뤄야 실제로 저렴해지는 모델이다.

왜 필요한가: 큰 모델은 계산보다 "놀고 있는 자원" 때문에 비싸진다

LLM(Large Language Model, 대규모 언어 모델)의 비용을 처음 배울 때는 보통 이렇게 생각한다.

파라미터가 671B다
→ 671B만큼 계산하니 매우 느리고 비싸다

절반만 맞다. dense 모델에서는 각 토큰이 각 층의 큰 FFN(Feed-Forward Network, 토큰별 비선형 변환 층)을 통과한다. 반면 MoE는 토큰의 성격에 맞는 expert 일부만 통과시킨다. 코드 토큰은 코드에 익숙한 expert 쪽으로, 수학 토큰은 다른 expert 쪽으로 보내는 식이다.

하지만 "몇 개만 고르니 공짜"가 아니다. 다음 실패가 바로 생긴다.

  • 대부분의 토큰이 인기 expert 하나에 몰리면 그 GPU만 기다리게 된다. 이것이 routing collapse(라우팅 붕괴) 또는 load imbalance(부하 불균형)다.
  • expert가 여러 GPU·여러 node(노드, 서버 묶음)에 있으면 토큰 activation(활성값)을 all-to-all(모든 참여자가 서로 데이터를 교환하는 통신)로 보내고 다시 받아야 한다.
  • 긴 문맥에서는 모델 가중치보다 KV cache가 GPU 메모리를 먼저 잠식할 수 있다.
  • 8-bit 부동소수점(FP8)으로 계산을 줄이면 빠르지만, 숫자 범위가 작아 overflow(표현 가능한 최대값을 넘음)·underflow(너무 작아 0처럼 사라짐)·누적 오차가 생길 수 있다.
  • 학습 때의 expert 부하 분포와 실제 서비스 요청 분포가 다르면, 학습에서 균형이던 라우터가 운영에서 특정 expert를 과부하시킬 수 있다.

이 논문의 핵심은 "MoE를 썼다"가 아니다. 희소한 계산(sparse compute), 캐시 압축, 정밀도, 통신, 배포 재배치가 서로 맞물려야 MoE가 비용 이점으로 바뀐다는 점이다.

무엇인가: 671B와 37B를 절대 같은 숫자로 읽지 않기

논문과 공식 DeepSeek-V3 README는 다음을 보고한다.

수치잘못된 해석
671B total parameters모든 expert, attention, embedding, output head를 합친 저장 가중치 수요청마다 671B 전체를 계산한다.
37B activated parameters한 토큰 처리에서 실제 경로에 참여하는 가중치의 대략적 규모모델 전체가 37B라서 37B 모델처럼 배포가 쉽다.
256 routed expertsMoE 층에서 router가 후보로 보는 전문가 수매 토큰이 256개를 전부 실행한다.
8 activated routed expertsrouter가 토큰마다 고르는 routed expert 수shared expert도 포함한 숫자다.
1 shared expert모든 토큰이 항상 함께 통과하는 expertrouter가 선택할 때만 실행된다.
128K context한 요청에서 지원하는 최대 문맥 토큰 길이128K 문서의 모든 사실을 정확히 회수한다.

37 / 671 = 약 5.51%다. 이 비율은 계산에 참여하는 파라미터 비율의 감각을 줄 뿐, 서비스 비용이 정확히 5.51%라는 뜻은 아니다. 671B 가중치를 GPU 여러 대에 올려 둬야 하고, attention·KV cache·통신·메모리 대역폭·batch 크기·router 편향도 비용에 들어간다.

이 차이를 데이터베이스로 비유해 보자.

671B total
  = 전체 shard와 모든 index를 포함한 데이터 플랫폼 크기

37B activated
  = 특정 요청이 실제 읽은 shard·index·실행 연산의 규모

요청이 일부 shard만 읽는다고 해서, 나머지 shard를 저장·복제·장애 복구하지 않아도 되는 것은 아니다. MoE도 같다.

선행 개념: Transformer, FFN, expert, router를 12살 말로 풀기

Transformer block은 두 종류의 일을 반복한다

LLM의 한 Transformer block(변환기 블록)은 크게 두 가지를 한다.

1. attention(어텐션)
   → 지금 토큰이 앞 문맥의 어느 토큰 정보를 얼마나 가져올지 계산한다.

2. FFN(Feed-Forward Network, 피드포워드 네트워크)
   → 그렇게 섞인 정보를 현재 토큰 안에서 비선형으로 변환한다.

dense Transformer의 FFN은 모든 토큰에 같은 큰 계산기를 적용한다.

모든 토큰 → 같은 FFN → 출력

MoE의 FFN은 여러 작은 계산기를 두고, router가 일부만 고른다.

토큰 → router → 선택된 expert 8개 + 항상 실행되는 shared expert 1개 → 가중합 → 출력

expert는 마법처럼 "코드만 아는 사람"이라고 미리 지정된 사람이 아니다. 처음에는 모두 비슷한 신경망이며, 데이터·router·학습 과정이 특정 패턴에 더 많이 반응하도록 만들 수 있다. 논문 부록의 관찰처럼 도메인별 사용 비율이 달라질 수 있지만, 사람이 읽을 수 있는 역할이 expert마다 하나씩 고정된다고 단정하면 안 된다.

점수와 실제 가중치는 다를 수 있다

router는 입력 토큰 표현 u_t와 expert별 학습 벡터 e_i의 친화도(잘 맞는 정도)를 만든다.

s(i, t) = sigmoid(u_tᵀ e_i)
  • t: 현재 토큰 위치
  • i: expert 번호
  • u_t: 현재 토큰의 숫자 벡터
  • e_i: i번 expert를 대표하는 학습 벡터
  • u_tᵀ e_i: 두 벡터가 얼마나 맞는지 나타내는 내적
  • sigmoid: 값을 0과 1 사이로 누르는 함수

큰 점수의 Top-K(상위 K개) expert만 실행하고, 선택된 expert의 출력은 gate weight(게이트 가중치)로 섞는다. DeepSeek-V3의 중요한 미세 차이는 부하 조정 bias는 누구를 고를지에만 쓰고, expert 출력의 섞는 비율은 원래 affinity(친화도)에서 계산한다는 것이다. 이 차이는 뒤의 직접 계산에서 확인한다.

KV cache와 왜 긴 답변이 비싸지는가

autoregressive generation(자기회귀 생성)은 답을 한 토큰씩 만든다. 새 토큰을 만들 때 이전 토큰의 Key와 Value를 매번 다시 계산하면 너무 느리다. 그래서 과거 Key·Value를 GPU 메모리에 저장하는 것이 KV cache다.

prompt를 읽는다: prefill(프리필)
  → 과거 모든 토큰의 K/V를 cache에 만든다.

답을 한 토큰씩 만든다: decoding(디코딩)
  → 새 토큰의 Q가 cache의 과거 K/V를 참고한다.

긴 문맥의 비용은 따라서 두 갈래다.

  1. attention 점수 계산이 문맥 길이에 따라 커진다.
  2. 각 층·각 요청의 KV cache가 길이에 비례해 커진다.

DeepSeek-V3의 MLA는 두 번째 문제, 특히 cache에 무엇을 저장할지를 바꾼다.

밑바닥 원리: MoE, MLA, MTP를 수식과 작은 예제로 연결하기

DeepSeekMoE: shared expert와 routed expert를 함께 둔다

논문 2.1.2절의 MoE 출력은 개념적으로 아래와 같다.

출력
= 입력(잔차 연결)
+ 모든 shared expert 출력의 합
+ 선택된 routed expert 출력의 가중합

수식으로 쓰면 다음이다.

h'_t = u_t
     + Σ FFN_shared_i(u_t)
     + Σ g(i, t) × FFN_routed_i(u_t)
  • u_t: FFN으로 들어오는 t번째 토큰 표현
  • h'_t: FFN을 지난 뒤의 새 표현
  • FFN_shared_i: 모든 토큰이 실행하는 공유 expert
  • FFN_routed_i: router가 고른 경우에만 실행하는 expert
  • g(i, t): 선택된 expert 출력에 곱하는 가중치

공유 expert는 모든 토큰에 공통으로 필요한 패턴을 처리하게 두고, routed expert는 더 세분화된 패턴에 특화할 여지를 준다. 이것은 역할을 보장하는 규칙이 아니라, specialization(전문화)이 학습될 수 있게 만든 구조 선택이다.

부하 균형: "인기 가게" 문제를 loss에만 맡기지 않는다

expert 256개 중 몇 개만 계속 고르면, 인기 expert가 있는 GPU가 병목이 된다. 전통적인 MoE는 auxiliary loss(보조 손실)를 추가해 expert 선택 비율이 균등해지도록 벌점을 준다.

전체 손실 = 언어 모델 손실 + α × 부하 불균형 벌점

문제는 α를 크게 하면 router가 "토큰에 잘 맞는 expert"보다 "빈 expert"를 고르도록 학습될 수 있다는 점이다. 작으면 부하가 다시 쏠린다.

DeepSeek-V3의 **auxiliary-loss-free load balancing(보조 손실 없는 부하 균형)**은 expert별 routing bias b_i를 따로 조정한다.

선택 점수 = 원래 친화도 s(i, t) + expert별 bias b_i
  • 과부하 expert: 다음 step에서 b_iγ만큼 낮춘다.
  • 저부하 expert: 다음 step에서 b_iγ만큼 높인다.
  • γ(gamma): bias update speed(편향 갱신 속도)다.

여기서 이름을 정확히 읽어야 한다. 논문은 전역 batch 단위의 주요 균형에 보조 손실을 쓰지 않는다는 뜻으로 auxiliary-loss-free라 부른다. 어떤 sequence(시퀀스, 한 입력 묶음) 안에서 너무 극단적으로 몰리는 일을 막기 위해, 아주 작은 α = 0.0001의 sequence-wise auxiliary loss(시퀀스 단위 보조 손실)는 여전히 쓴다. "보조 손실이 0개"라는 뜻이 아니다.

MLA: K와 V 전체 대신 압축 잠재 벡터를 cache한다

일반 Multi-Head Attention(MHA, 다중 헤드 어텐션)에서는 head마다 Key와 Value를 cache한다. DeepSeek-V3 MLA는 현재 토큰의 입력 h_t를 먼저 작은 latent vector(잠재 벡터) c_t^KV로 줄인다.

c_t^KV = W_D^KV × h_t
  • h_t: attention 입력 벡터
  • W_D^KV: down-projection(차원을 줄이는 행렬)
  • c_t^KV: 압축된 Key/Value 공통 잠재 벡터

이 압축 벡터에서 head별 Key·Value를 복원할 수 있다. 하지만 RoPE(Rotary Position Embedding, 회전 위치 임베딩)는 위치 정보를 Query·Key에 회전 형태로 넣으므로, 단순히 모든 것을 한 덩어리로 흡수하기 어렵다. 그래서 MLA는 RoPE가 적용된 별도의 shared key k_t^R를 함께 보관한다.

MLA가 generation 중 cache하는 것
  = compressed KV latent c_t^KV
  + position용 shared key k_t^R

이렇게 Key와 Value의 원래 head별 전체를 cache하지 않는 것이 핵심이다. 공식 구현의 MLA 클래스attn_impl == "absorb" 경로에서 kv_cachepe_cache만 저장하고, attention score를 두 항의 합으로 계산한다.

MTP: 추론 때 두 토큰을 무조건 내보내는 기능이 아니다

일반 next-token prediction(다음 토큰 예측)은 위치 i에서 t_(i+1)만 맞힌다. DeepSeek-V3는 학습 때 MTP module을 추가해 그보다 한 단계 더 먼 토큰도 맞힌다.

main model: 입력 t_i → 다음 토큰 t_(i+1) 예측
MTP depth 1: main 표현 + 정답 t_(i+1)의 embedding → t_(i+2) 예측

논문의 V3 설정에서 MTP depth D = 1이다. 즉 "추가로 한 토큰"을 예측한다. 학습 데이터의 실제 다음 토큰을 사용해 다음 단계 예측을 이어 가는 것은 teacher forcing(정답을 앞 입력으로 주는 학습 방식)이다. 미래 답을 몰래 보는 것이 아니라, 정상적인 next-token 학습을 한 단계 더 조밀하게 만든다.

MTP 손실은 각 깊이의 cross-entropy를 평균내고 가중치 λ를 곱한 추가 손실이다.

L_total = L_next_token + λ × L_MTP

논문은 MTP의 주 목적을 학습 신호를 더 촘촘하게 해 본체 모델 품질을 올리는 것으로 둔다. 표 4의 ablation(다른 조건을 고정한 비교)에서는 추론 활성 파라미터 수가 같은 작은·큰 MoE에서 MTP가 여러 평가를 개선했다고 보고한다. 일반 추론에서는 MTP module을 버려도 main model이 독립적으로 동작한다. 다만 speculative decoding(추측 디코딩)에서는 MTP가 다음 토큰 후보를 미리 제안하고 main 검증이 받아들인 부분을 한 번에 확정해 decoding을 빠르게 할 수 있다.

따라서 "MTP가 있으니 답변이 항상 2배 빠르다"는 말은 틀리다. 제안 토큰의 acceptance rate(수용률), serving engine 지원, batch, 메모리, 실제 요청 길이를 측정해야 한다. 논문 5.4.3절은 특정 평가에서 두 번째 토큰의 수용률 85~90%, speculative decoding 결합 시 1.8배 TPS(Tokens Per Second, 초당 토큰 수)를 보고하지만, 이는 그들의 구현·하드웨어 조건의 수치다.

내부 구조와 실제 실행 흐름

논문 configuration을 숫자로 읽기

논문 4.2절과 공개된 config_671B.json을 대조하면 핵심 수치는 다음과 같다.

항목의미
Transformer layer61attention + FFN/MoE block을 61번 쌓는다.
hidden dimension7,168토큰 표현 벡터 길이다.
dense layer처음 3개첫 세 FFN만 일반 dense MLP다.
MoE layer나머지 58개이후 FFN은 expert routing을 쓴다.
routed experts256각 MoE 층의 선택 후보 수다.
shared experts1모든 토큰에 항상 적용되는 expert 수다.
activated routed experts8토큰마다 Top-8 routed expert를 실행한다.
node 제한최대 4개 node토큰이 너무 많은 서버로 흩어지지 않게 한다.
attention heads128attention의 병렬 관점 수다.
MLA KV latent dimension512KV를 압축해 저장하는 차원이다.
RoPE key/query dimension64위치 정보를 따로 보존하는 차원이다.
MTP depth1다음 토큰 뒤의 한 토큰을 추가 학습한다.

한 가지 숫자 차이도 기록해 둔다. 논문은 tokenizer vocabulary를 128K라고 표현하지만, 공개 config의 vocab_size129280이다. 둘을 같은 정밀도로 단정하지 않는다. 논문은 둥근 단위로 설명하고 config는 구현의 ID 공간을 적는다. 원문이 이 차이를 명시적으로 풀이하지 않으므로, 구현을 읽을 때는 config 값, 논문 개요를 말할 때는 128K라는 범위를 각각 사용한다.

코드로 따라가는 한 토큰의 경로

공식 inference demo의 실제 흐름은 다음과 같다.

token IDs
  → ParallelEmbedding
  → Block 0 .. 60
      → RMSNorm → MLA → residual add
      → RMSNorm → dense MLP(처음 3층) 또는 MoE(나머지 층) → residual add
  → RMSNorm
  → vocabulary logits
  → sampling으로 다음 token ID 선택

공개 코드에서 이 흐름을 직접 확인했다.

  • Block은 layer ID가 3보다 작으면 dense MLP, 아니면 MoE를 고른다. model.py:715-735
  • Gate는 sigmoid score → bias 추가 → group 제한 → Top-K 선택을 하고, 선택된 원래 score를 정규화해 weight로 쓴다. model.py:535-598
  • MoE는 선택된 local expert 출력에 weight를 곱하고, shared expert 출력 z를 더한다. 다중 GPU면 expert 결과를 all_reduce한다. model.py:636-693
  • Transformer.forward는 causal mask로 미래 토큰을 가리고 61개 block을 순서대로 통과시킨 뒤 logits를 만든다. model.py:738-798

공식 코드는 모델 추론 demo다. 훈련용 HAI-LLM framework나 DualPipe 전체 구현을 공개했다는 뜻은 아니다. 코드가 보여 주는 범위와 논문이 설명하는 대규모 훈련 인프라 범위를 섞지 않았다.

데이터와 장문 문맥의 실행 경로

웹·코드·수학·다국어 원천
  → 중복 최소화·다양성 유지
  → Byte-level BPE tokenizer
  → document packing
  → 14.8T 토큰 사전학습(기본 4K)
  → YaRN으로 4K → 32K → 128K 장문 문맥 확장
  → SFT → RL/GRPO → Chat model

논문은 V2보다 수학·프로그래밍 비율과 다국어 범위를 늘렸고, FIM(Fill-in-the-Middle, 중간 채우기)을 PSM(Prefix-Suffix-Middle, 앞-뒤-중간) 형식으로 10% 적용했다고 설명한다.

<|fim_begin|> 앞부분 <|fim_hole|> 뒷부분 <|fim_end|> 정답 중간 <|eos_token|>

코드 자동완성처럼 "앞과 뒤를 보고 가운데를 채우기"에 도움이 되는 학습 형식이다. 주의할 차이도 있다. Llama 3 글에서 본 것처럼 packed document 사이 attention을 막는 모델도 있지만, DeepSeek-V3 논문은 data integrity(문서 온전성)를 위해 document packing을 하면서 cross-sample attention masking을 넣지 않았다고 쓴다. 같은 "packing"이라도 모델마다 문서 경계를 어떻게 취급하는지 다르다.

긴 문맥은 YaRN(긴 문맥용 RoPE 보정 방법)을 써서 사전학습 4K에서 32K, 다시 128K로 각각 1,000 step 확장했다. YaRN 설정은 MLA의 모든 KV가 아니라 decoupled shared key k_t^R에 적용한다. 이 사실은 MLA가 위치 정보를 별도 경로로 분리한 이유와 연결된다.

훈련 인프라: MoE는 네트워크 아키텍처이기도 하다

논문은 2,048개의 NVIDIA H800 GPU cluster에서 V3를 학습했다고 보고한다. 구성은 16-way PP(Pipeline Parallelism, 층을 stage로 나누는 병렬화), 64-way EP(Expert Parallelism, expert를 여러 GPU에 나누는 병렬화), ZeRO-1 DP(Data Parallelism, optimizer 상태를 나눠 갖는 데이터 병렬화)다.

토큰 → 현재 GPU의 router
     → 선택 expert가 있는 GPU/node로 dispatch(all-to-all)
     → expert FFN 실행
     → 결과를 원래 흐름으로 combine(all-to-all)
     → 다음 Transformer layer

이 경로는 통신이 계산만큼 오래 걸릴 수 있다. 논문은 그 비율을 약 1:1이라고 보고하고, DualPipe로 forward·backward 계산과 all-to-all·pipeline 통신을 겹친다. 핵심은 "통신이 없어졌다"가 아니라, 계산 중에 통신을 진행해 사용자가 기다리는 추가 시간을 가능한 한 숨기는 것이다. 네트워크가 느리거나 배치가 작거나 router가 쏠리면 이 겹침이 깨질 수 있다.

FP8: 숫자를 8비트로 줄여도 기준값을 버리지 않는다

FP8은 숫자 하나를 8비트로 표현하는 저정밀 부동소수점 형식이다. DeepSeek-V3는 많은 GEMM(General Matrix Multiplication, 일반 행렬 곱)을 FP8로 수행해 연산과 activation 저장 공간을 줄이지만, 전부를 8비트로 바꾸지 않는다.

구간논문의 선택이유
주요 Linear GEMM forward/backwardFP8계산량과 메모리 절감
embedding, output head, MoE gate, norm, attentionBF16 또는 FP32 유지작은 오차에도 민감하거나 고정밀 비용이 상대적으로 작음
master weight·gradient·optimizer 핵심 상태높은 정밀도 유지장기 학습 안정성
activationtoken당 1×128 tile로 scale일부 outlier가 전체 tensor scale을 망치지 않게 함
weight128×128 block으로 scale가중치 블록별 범위 차이를 반영

**quantization(양자화)**은 숫자를 적은 비트로 근사 표현하는 일이다. 값 하나를 그냥 8비트로 잘라 저장하면 큰 값 하나가 scale을 독점하거나 작은 값이 사라질 수 있다. 그래서 V3는 작은 tile/block마다 scale factor(확대·축소 기준값)를 따로 두고, FP8 행렬 곱의 중간 합은 CUDA core의 FP32 register에 주기적으로 올려 누적 정밀도를 높였다. 논문은 BF16 baseline 대비 FP8 훈련의 relative loss error가 약 0.25% 아래였다고 보고하지만, 이는 해당 실험·모델·프레임워크에서의 결과다.

직접 검증: MLA cache와 router bias를 숫자로 확인하기

검증 범위와 환경

직접 실행 확인: 2026-07-24, macOS 26.4.1, Python 3.9.6. NVIDIA GPU와 DeepSeek-V3 671B 가중치가 없으므로 실제 모델 추론·FP8 kernel·2,048 GPU 훈련을 실행하지 않았다.

대신 공개 configuration과 공식 구현으로 다음을 계산했다.

  1. 61개 층, 128 head, 128K 문맥에서 naive MHA cache와 MLA absorb cache의 이론상 크기
  2. 671B 중 37B 활성 파라미터 비율
  3. router bias가 선택만 바꾸고, 선택된 출력 weight는 원래 affinity에서 나오는지
# /tmp/verify_deepseek_v3_mechanics.py
LAYERS = 61
HEADS = 128
QK_NOPE_DIM = 128
QK_ROPE_DIM = 64
VALUE_DIM = 128
KV_LATENT_DIM = 512
TOKENS = 131_072
BYTES_PER_BF16 = 2

# 일반 MHA: 각 head의 K(nope+RoPE)와 V를 저장한다.
naive_scalars_per_token = HEADS * (QK_NOPE_DIM + QK_ROPE_DIM + VALUE_DIM)
# MLA absorb cache: 압축 KV와 공유 RoPE key만 저장한다.
mla_scalars_per_token = KV_LATENT_DIM + QK_ROPE_DIM

def cache_gib(scalars_per_token):
    return LAYERS * TOKENS * scalars_per_token * BYTES_PER_BF16 / (1024 ** 3)

print(naive_scalars_per_token, mla_scalars_per_token)
print(round(naive_scalars_per_token / mla_scalars_per_token, 2))
print(round(cache_gib(naive_scalars_per_token), 2))
print(round(cache_gib(mla_scalars_per_token), 2))
print(f"{37 / 671:.2%}")

# 논문 §2.1.2: bias는 Top-K route 선택에만 쓰고,
# 실제 expert output weight는 original affinity에서 계산한다.
affinity = [0.72, 0.64, 0.61, 0.55]
bias = [-0.12, 0.04, 0.06, 0.05]
adjusted = [score + shift for score, shift in zip(affinity, bias)]
selected = sorted(range(4), key=lambda i: adjusted[i], reverse=True)[:2]
raw = [affinity[i] for i in selected]
weights = [score / sum(raw) for score in raw]
print(selected, [round(x, 4) for x in weights])

실행 결과다.

naive scalars/token/layer: 40960
MLA scalars/token/layer: 576
compression ratio: 71.11
naive 128K cache, 61 layers: 610.0 GiB
MLA 128K cache, 61 layers: 8.58 GiB
37B / 671B: 5.51%
selected experts: [1, 2]
gate weights from original affinity: [0.512, 0.488]

해석의 경계를 분명히 한다.

  • 610.0GiB8.58GiBbatch 1, 128K, BF16/FP16 scalar 2 byte, 61개 층을 모두 합친 모델 전체 cache의 단순 산술이다. 실제 배포에서는 head와 층을 GPU에 shard(분할)하므로 GPU 한 장이 이 전부를 들고 있지 않는다.
  • 가중치, activation, runtime workspace, allocator 여유분, network buffer는 이 계산에 없다.
  • MLA의 약 71배는 이 config의 cache scalar 수 비교다. 실제 end-to-end 속도는 메모리 대역폭, prefill, all-to-all, batch, serving engine에 따라 달라진다.
  • toy router 예시는 논문의 bias 규칙을 숫자로 보인 것이지, 학습된 expert의 의미나 실제 트래픽 분포를 재현한 것이 아니다.

성능과 트레이드오프: 희소 계산은 운영 복잡도와 교환된다

Llama 3의 dense 선택과 DeepSeek-V3의 MoE 선택

질문Llama 3 Herd의 dense 경로DeepSeek-V3의 MoE 경로
토큰당 FFN 계산일반적으로 모든 dense 가중치 경로routed expert 일부 + shared expert
주된 강점구조·통신·부하 관리가 상대적으로 단순큰 총 용량을 두면서 활성 계산을 제한
주된 병목모델 전체 연산·KV cache·모델 병렬router 부하, expert all-to-all, 배포 재배치
시스템 난이도큰 모델 분산 운영큰 모델 분산 운영 + 동적 expert 부하 운영
논문의 우선순위안정성·규모·데이터 품질비용 효율·통신 겹침·정밀도·부하 균형

어느 쪽이 "더 좋다"가 아니다. 작은 팀이 RAG 서비스를 만들 때는 671B MoE architecture를 재현하는 것보다, 모델 API 또는 검증된 serving engine 뒤에 데이터 계약·검색 평가·권한·관측성을 먼저 세우는 편이 훨씬 현실적이다.

prefill과 decode를 분리하는 이유

논문은 online SLO(Service-Level Objective, 서비스 목표)와 throughput(처리량)을 함께 맞추기 위해 prefill과 decoding cluster를 분리한다.

단계주로 하는 일논문 최소 배포 단위핵심 병목
Prefill긴 prompt를 읽고 KV cache 생성4 node / 32 GPU큰 연산량, attention·MoE 통신
Decode토큰을 하나씩 생성40 node / 320 GPU작은 batch의 메모리 접근·낮은 지연 시간

decode가 더 큰 node 수를 요구하는 이유는 "모델이 더 복잡해서"만이 아니다. 논문은 decoding에서 GPU마다 expert 하나를 두고, 과부하 expert와 shared expert에는 redundant expert를 추가 배치한다. online load 통계를 보고 약 10분 간격으로 고부하 expert를 조정한다. 이는 MoE deployment가 model loading에서 끝나지 않고 실제 요청 분포를 관찰하는 운영 작업임을 보여 준다.

학습 비용 숫자를 광고 문구로 쓰지 않기

논문 표 1의 총 2.788M H800 GPU hours는 pre-training 2.664M, context extension 119K, post-training 5K의 합이다. 논문은 H800 대여를 GPU 시간당 2달러로 가정해 5.576M 달러를 제시했다.

이 숫자는 비교할 때 다음을 빼면 안 된다.

포함: 공식 V3 학습 단계의 GPU 시간
제외: 아키텍처·데이터·알고리즘을 찾기 위한 선행 연구와 ablation 비용
가정: H800 시간당 2달러

따라서 이것은 "오늘 누구나 557만 달러면 같은 모델을 만든다"는 견적이 아니다. 하드웨어, 전력, 네트워크, 인력, 데이터 권리, 실패 재시도, 연구 비용이 빠진 해당 보고의 산술이다.

실패, 한계, 장애와 운영 기준

논문이 명시한 한계

논문 결론은 다음 한계를 직접 든다.

  1. 효율적인 추론을 위한 권장 deployment unit이 커서 작은 팀에는 부담이다.
  2. V2보다 end-to-end generation speed가 2배 넘게 개선됐다고 해도 더 빠르게 만들 여지가 남아 있다.
  3. 고정 benchmark에 과도하게 최적화하면 실제 능력을 오해할 수 있으므로 더 다차원적인 평가가 필요하다.

여기에 운영 관점의 실패를 붙이면 다음과 같다.

실패 방식징후먼저 확인할 것
expert hot spot일부 GPU만 queue·latency가 급증expert별 token count, node별 dispatch bytes, redundant expert 상태
router 품질 저하특정 도메인에서 답 품질·전문성 하락route 분포와 실패 slice, 학습·운영 데이터 분포 차이
all-to-all 병목GPU 사용률은 낮은데 step/요청 시간이 김IB/NVLink 대역폭, dispatch/combine trace, micro-batch 크기
FP8 수치 불안정loss spike, NaN, 특정 layer 이상tile scale 분포, outlier, FP32 master weight/gradient 보존 여부
long-context 착시NIAH는 통과하지만 실제 문서 질의 실패문서 위치별·질문 유형별 평가, citation, RAG baseline 비교
MTP 과대평가기대한 decoding 속도가 안 나옴acceptance rate, draft/verify 비용, engine 지원, TTFT/TPOT

안전과 권한은 이 논문의 빈칸이다

DeepSeek-V3 논문은 모델 구조·효율·일반 평가에 집중한다. 내가 구축할 RAG·MCP(Model Context Protocol, 모델 문맥 프로토콜) 시스템에서는 이것만으로 충분하지 않다.

모델이 tool call을 잘 만든다
≠ 그 tool call을 실행해도 안전하다.

모델이 128K 문맥을 읽는다
≠ tenant(테넌트) 권한이 없는 문서를 넣어도 된다.

AI 백엔드에서는 모델 앞에 ACL(Access Control List, 접근 제어 목록), source provenance(원천·버전 계보), prompt-injection negative test(주입 공격 차단 시험), tool allowlist(허용 도구 목록), human approval(사람 승인) 같은 경계가 필요하다. 이는 논문의 성능을 부정하는 말이 아니라, 모델 논문이 제품 보안 설계서를 대신하지 않는다는 경계다.

대안, 비교와 선택 기준

내 상황에서 MoE를 언제 배워야 하나

상황우선 판단행동
RAG 품질이 아직 불안정MoE가 아니라 retrieval·chunk·eval 문제일 가능성이 큼BM25/dense/rerank, dev·locked test, citation부터 고정
API 모델을 사용한다내부 MoE 배포를 직접 관리하지 않음모델별 context·비용·지연 시간만 측정하고 application SLO를 설계
open-weight 대형 모델을 직접 serving한다VRAM, node 수, network, engine 지원이 핵심MLA/MTP 지원 여부, quantization, prefill/decode 분리부터 확인
expert 라우팅을 연구한다router 품질과 부하 균형을 동시에 검증해야 함작은 MoE부터 expert load·quality slice·통신 trace를 함께 실험
데이터 파이프라인 직무를 목표로 한다대형 pretraining보다 운영 가능한 데이터 증거가 더 중요manifest, backfill, DQ, index release, rollback, evaluation을 만든다

지금 당장 하지 않을 일

  • 671B MoE를 로컬에서 실행하려고 하드웨어를 무작정 사지 않는다. 공식 demo도 Linux/Python 3.10과 다중 node 실행을 전제로 설명한다.
  • 37B active라는 숫자만 보고 37B dense 모델과 같은 배포 난이도라고 가정하지 않는다.
  • FP8 변환만 하면 더 빠르고 같은 품질이라고 가정하지 않는다. kernel·GPU·scale·serving engine·정확도 회귀를 함께 본다.
  • MTP가 있다고 모델 출력 두 토큰을 검증 없이 사용하지 않는다. speculative decoding은 draft 제안과 main 검증의 계약이다.
  • MoE를 쓰면 RAG·데이터 계약·ACL·평가가 필요 없어진다고 생각하지 않는다.

흔한 오해와 최초 질문에 대한 답

오해 1: "671B인데 토큰마다 37B만 쓰니 37B 모델보다 무조건 싸다"

아니다. FFN 계산은 줄일 수 있지만 671B 가중치 저장, KV cache, attention, expert 통신, batch, GPU 대수, router 편향 비용이 남는다. 활성 파라미터는 계산 경로의 숫자이지 전체 운영비 청구서가 아니다.

오해 2: "expert는 사람이 이름 붙인 전공자다"

아니다. shared/routed라는 구조 역할은 명시하지만, routed expert 1번이 항상 Java만, 2번이 항상 수학만 맡는 식의 고정 의미는 보장하지 않는다. 도메인별 route 통계와 실제 평가로 specialization을 관찰해야 한다.

오해 3: "auxiliary-loss-free는 부하 균형 loss가 하나도 없다는 뜻이다"

아니다. 주요 batch-wise 균형은 bias 조정으로 다루지만, 논문은 시퀀스 내부 극단적 불균형을 막는 작은 sequence-wise auxiliary loss도 쓴다.

오해 4: "MLA는 attention을 근사해서 품질을 희생한 단순 압축이다"

정확한 표현이 아니다. MLA는 K/V를 shared latent로 압축하고 위치 성분을 분리해 cache 형태를 바꾸는 attention 구조다. 논문은 표준 MHA와 비슷한 성능을 유지하면서 cache를 줄이는 것을 목표로 검증했다. 다만 모든 모델·모든 구현에서 같은 품질·속도를 보장하는 일반 법칙은 아니다.

오해 5: "MTP는 ChatGPT처럼 답을 두 단어씩 보여 주는 기능이다"

아니다. V3에서 MTP는 우선 학습 목적이다. 기본 추론에서는 MTP module을 버릴 수 있고, speculative decoding을 구현할 때만 제안 토큰으로 재사용할 수 있다.

전문가에게 1분 안에 설명한다면

DeepSeek-V3는 61층 MoE Transformer로, 총 671B 파라미터 중 토큰마다 8개 routed expert와 1개 shared expert를 거쳐 약 37B만 활성화합니다. 핵심은 MoE 자체보다 세 가지입니다. 첫째, MLA가 128개 head의 K/V 전체 대신 512차원 compressed KV와 64차원 위치 key를 cache해 장문 decode 메모리를 크게 줄입니다. 둘째, expert별 bias를 router 선택에만 적용해 batch 부하를 맞추고, 실제 expert 출력 weight는 원래 affinity로 유지합니다. 셋째, FP8·DualPipe·all-to-all 통신 겹침·prefill/decode 분리·중복 expert 배치가 MoE의 계산 이득을 실제 운영 이득으로 바꿉니다. 그래서 이 논문은 671B 모델 소개라기보다, 희소 모델을 분산 시스템으로 운영하는 설계서로 읽어야 합니다.

출처

1차 자료

  1. DeepSeek-AI, DeepSeek-V3 Technical Report, arXiv:2412.19437v2, 2025-02-18. 모델 구조, data, FP8, 인프라, post-training, 평가, 한계의 주 근거다.
  2. DeepSeek-AI, DeepSeek-V3 공식 README. 공개 모델 크기·문맥 길이·가중치 형식·로컬 실행 요구 사항을 확인했다.
  3. DeepSeek-AI, 공식 inference model.py, commit 9b4e978. MLA cache, router bias/weight, MoE·shared expert, block 실행 경로를 확인했다.
  4. DeepSeek-AI, config_671B.json, commit 9b4e978weight file documentation. 61층·256 expert·Top-8·MLA rank·MTP module·FP8 weight 구조를 대조했다.

직접 실행한 검증

  • 2026-07-24, macOS 26.4.1, Python 3.9.6에서 본문의 순수 Python 계산을 실행했다.
  • 실행 범위: MLA/MHA cache scalar·메모리 산술, 활성 파라미터 비율, auxiliary-loss-free router bias의 선택·가중치 분리.
  • 미실행 범위: 671B 가중치 추론, FP8 kernel 성능, DualPipe, H800 2,048 GPU 학습, 논문 benchmark 재현. 실행한 것처럼 쓰지 않았다.

다음 글

  • 0단계 3편: DeepSeek-R1 — V3의 SFT/RL과 R1의 강화학습 기반 reasoning model을 구분하고, long CoT(긴 사고 과정)를 제품에 언제·어떻게 써야 하는지 정리한다.
대화

댓글

0
댓글을 불러오는 중입니다.