DeepInfer 내부: DeepSeek의 V4.1-Flash 아키텍처
DeepInfer는 DeepSeek의 V4.1-Flash 추론 아키텍처입니다. 가장 흥미로운 코드는 특정 커널 하나가 아니라, 거대한 GPU 클러스터가 자기 자신을 기다리지 않게 만드는 스케줄링과 메모리 결정들의 집합입니다. 프로덕션 관련 유의점과 함께 살펴봅니다.
DeepInfer는 V4.1-Flash를 위한 DeepSeek의 오픈소스 추론 아키텍처입니다. 제대로 읽으려면 모델, 엔진, 서비스라는 세 층을 분리해야 합니다. 모델은 V4.1-Flash입니다. 이 페이지가 다루는 것은 엔진입니다. 서비스는 DeepSeek가 남겨 둔 부분입니다.
추론 엔진이 실제로 하는 일
학습된 모델은 가중치 덩어리입니다. 그것을 서빙한다는 것은 요청에 응답하는 일입니다. 프롬프트를 읽고, 모델을 실행하고, 토큰을 생성해 돌려주는 일을, 비싼 하드웨어를 낭비하지 않으면서 여러 사용자에게 동시에 해내는 것입니다.
비용을 좌우하는 두 단계가 있습니다.
- 프리필은 프롬프트를 읽고 KV cache를 만듭니다. 연산량이 많고, 프롬프트 토큰 여러 개를 병렬로 처리할 수 있습니다.
- 디코드는 한 번에 토큰 하나를 생성합니다. 스텝마다 KV cache와 모델의 일부를 읽어야 하므로 메모리 대역폭을 많이 쓰고, 스텝당 지연 시간에 민감합니다.
대부분의 서빙 최적화는 이 두 단계 중 하나를 더 싸게 만들거나, 다른 작업과 겹쳐 실행하려는 시도입니다. DeepInfer의 기능들도 이 구분에 깔끔하게 대응합니다.
배포 형태: EPD, Wide-EP, 그리고 많은 GPU
DeepSeek의 Q&A는 프로덕션 V4.1 시스템을 비전 인코더 / 프리필 / 디코드(E/P/D) 배포 형태로 설명합니다.
이 분리는 프리필과 디코드가 원하는 하드웨어 형태가 다르기 때문에 존재합니다. 프리필은 연산 바운드이고 디코드는 메모리 바운드입니다. 둘을 같은 풀에 두면 타협이 강제됩니다. 분리하면 각 단계를 독립적으로 확장할 수 있지만, 그 대가로 풀 사이에서 KV cache를 옮기고 서로 다른 두 워크로드의 균형을 맞춰야 합니다.
DeepSeek의 프로덕션 수치는 다음과 같습니다.
| 단계 | 병렬 배치 | 이유 |
|---|---|---|
| 프리필 | EP2–8 / DP2–8 | HBM에 들어가는 가장 작은 EP/DP를 사용합니다. 프리필은 연산 바운드입니다. |
| 디코드 | EP64–128 / DP64–128 (Wide-EP) | 가능한 가장 큰 EP/DP를 사용합니다. 디코드는 메모리 트래픽 바운드입니다. |
| 비전 인코더 | 인스턴스당 GPU 1개 | 작은 모델이므로 빠른 카드를 낭비하지 않습니다. |
| TP / CP | 프로덕션에서는 사용하지 않음 | 오픈소스 엔진은 예제에서 여전히 CP를 노출하지만, 프로덕션 설명에는 TP/CP가 등장하지 않습니다. |
DeepSeek는 프리필 64개 GPU에 디코드 64개 GPU를 더한 구성을 가장 작은 효율적 단위라고 부릅니다. 1P + 1D 구성도 배포는 가능하지만 권장 디코드 배치는 EP64 이상이므로, 작은 클러스터에서는 같은 효율을 얻기 어렵습니다.
전문가 로드 밸런싱: 중복 복사본과 주기적 재배치
MoE 라우팅은 고르지 않습니다. 어떤 전문가는 붐비고 어떤 전문가는 놀고 있습니다. 정적 배치는 GPU를 낭비합니다. DeepSeek의 EPLB(전문가 병렬 로드 밸런싱)는 붐비는 전문가의 복제본인 중복 전문가를 추가하고, 최근 부하를 기준으로 전문가를 GPU에 주기적으로 재배치합니다.
Q&A에 설명된 동작 방식은 다음과 같습니다.
- 각 GPU는 기본 전문가에 더해 몇 개의 중복 전문가를 보유합니다.
- 시스템은 최근 N개 스텝 동안의 전문가별 부하를 기록합니다.
- M개 스텝마다 전문가를 GPU에 재배치하고, 대칭 메모리를 사용해 NVLink 도메인 안에서 가중치를 옮깁니다.
| 단계 | 중복 전문가 | 통계 구간 | 재배치 | 측정된 moe_lb |
|---|---|---|---|---|
| 프리필 | GPU당 4개(시작값) | 100 스텝 | 1,000 스텝마다 | ≈1.03–1.07 |
| 디코드 | GPU당 1개(시작값) | 1,000 스텝 | 10,000 스텝마다 | 1.090 |
moe_lb는 가장 느린 랭크를 평균으로 나눈 값입니다. 1.09라면 가장 느린 GPU가 평균보다 약 9% 더 많은 일을 한다는 뜻입니다. 디코드 규모에서는 상당히 타이트한 수치이며, 동시에 가장 빠른 GPU도 배리어에서 기다린다는 의미입니다.
moe_lb를 1.074 / 1.045로, 중국어 Zhihu 글은 1.0320 / 1.0618로 제시합니다. 디코드 값(1.090)은 양쪽이 일치합니다. 그래서 프리필은 범위로, 디코드는 안정적으로 일치하는 값을 사용합니다.DSpark: 효과가 있는 곳에만 검증 연산을 쓰기
추측 디코딩은 드래프트 모델로 토큰 여러 개를 제안한 뒤 한 번의 패스로 검증합니다. 드래프트가 맞으면 검증 한 번의 비용으로 토큰 여러 개를 얻습니다. 틀리면 되돌아갑니다.
단순한 방식은 정해진 개수의 드래프트를 검증합니다. DSpark의 차별점은 가변 길이 검증입니다. 신뢰도 헤드가 드래프트 토큰마다 수용 확률을 예측하고, 스케줄러가 유효 처리량을 최대화하는 프리픽스 부분집합을 고릅니다.
DeepSeek는 추측 디코딩용 드래프트 모델을 학습하고 평가하는 MIT 라이선스 코드베이스 DeepSpec도 공개했습니다. DSpark, DFlash, Eagle3를 다루며, DeepInfer 엔진과는 별개입니다.
DeepSeek의 프로덕션 측정값은 다음과 같습니다.
| 지표 | 고정 5 | 동적 길이 |
|---|---|---|
| 스텝당 검증한 드래프트 토큰 | 5.00 | 3.2–4.4 |
| 평균 수용 길이 | 3.29 | 3.20 |
| 프로덕션 지점 처리량(랭크당 약 60 시퀀스) | — | +4–7% |
| 랭크당 96 시퀀스에서의 처리량 | — | +11% |
해석이 중요합니다. 검증 작업량은 약 30% 줄지만 수용 길이는 거의 변하지 않습니다. 동시성이 높을 때 순이득이 플러스가 됩니다. 랭크당 16 시퀀스에서는 표에 작은 손실(−1.5%)이 나옵니다. 공짜 점심이 아니라 부하에 따라 달라지는 최적화입니다.
릴리스의 기본 최대 드래프트 길이는 5입니다. 반면 공개된 디코드 차트는 nextn=3 fixed와 토큰당 수용률 75% 가정을 사용합니다. 이는 측정 구성이지 기본 배포 구성이 아닙니다.
SWA 바운디드 리플레이: 미스 비용을 낮추고, 캐시 저장을 포기하기
슬라이딩 윈도 어텐션(SWA)은 전체 어텐션에서 가장 최근 토큰만 유지합니다. V4.1은 128토큰 윈도를 사용합니다. SWA KV cache가 없으면 정확한 복구 비용이 큽니다. 각 디코더 레이어의 윈도가 아래 레이어에 의존하므로, 20개 디코더 레이어에 걸쳐 상태를 다시 만들려면 약 2,560회의 토큰-레이어 리플레이(20 × 128)가 필요합니다.
SWA 바운디드 리플레이는 의도적으로 근사적인 방식을 택합니다.
- 마지막 128개 토큰만 재생합니다.
- 재생 시작 지점에서 어텐션 윈도를 자릅니다. 위치 i는
[max(s, i−127), i]에만 어텐션합니다. - 근사적인 SWA KV cache를 받아들이고, 재계산 비용을 일정한 상한 안에 둡니다.
릴리스의 V4.1 기본 설정은 140토큰 서픽스를 유지합니다(DEEPINFER_YOCO_PREFILL_KEEP_TOKENS=140). 남는 여유분은 윈도와 추측 디코딩의 백트래킹을 함께 감당하기 위한 것입니다.
연산을 아끼는 것보다 중요한 이유가 있습니다. 이 방식은 SWA KV를 저장하지 않는 선택을 합리적으로 만듭니다. 그래서 V4.1의 영구 KV cache는 SWA KV가 아니라 글로벌 KV를 저장하고, 크기는 V4의 약 8분의 1로 줄어듭니다. 글로벌 KV 자체도 토큰당 약 890바이트로 압축되어 V4-Flash의 약 4분의 1 수준입니다.
바운디드 리플레이는 비트 단위로 정확하지 않습니다. DeepSeek는 품질 손실이 미미하다고 말합니다. vLLM은 자체 구현에서 같은 아이디어를 GSM8K와 GPQA로 독립 테스트했고, 격차가 약 1.5 표준오차 이내라고 보고했습니다. 이는 접근 방식이 타당하다는 증거이지, DeepInfer의 특정 코드를 검증한 것은 아닙니다.
비동기 스케줄링: GPU가 CPU를 기다리지 않게
디코드 스텝은 이렇게 흘러갑니다.
schedule(N) → forward(N) → sample(N) → post-process(N)
schedule과 post-process는 CPU 작업입니다. post-process(N) 전에 CPU는 GPU에서 sample(N) 결과를 받아야 합니다. 이 동기화 때문에 CPU가 결과를 처리하고 다음 배치를 스케줄하는 동안 GPU는 놀게 됩니다.
DeepInfer는 둘을 겹쳐 실행합니다.
GPU: forward(N) → sample(N)
CPU: schedule(N+1) → launch_forward(N+1) → post-process(N−1) → launch_sample(N+1)
아이디어 자체는 새롭지 않습니다. DeepSeek는 SGLang과 NanoFlow를 인용합니다. 하지만 구현이 릴리스에 포함되어 있고 기본으로 켜져 있습니다. 벤치마크용 커널과 서빙 엔진을 가르는 작업이 어떤 것인지 보여 주는 좋은 예입니다.
배치 불변 추론과 결정론적 샘플링
동적 배칭은 부동소수점 연산 순서를 바꿉니다. 같은 프롬프트라도 어떤 요청이 함께 배치에 들어왔는지에 따라 로짓이 조금씩 달라질 수 있습니다. 채팅에서는 대개 눈에 띄지 않습니다. 벤치마크, 감사, 에이전트 실행 재현에서는 문제가 됩니다.
DeepInfer는 두 가지 수준의 제어를 제공합니다.
- 배치 불변 추론(
DEEPINFER_BATCH_INVARIANT=1): 배치 구성이 달라도 결과가 일관됩니다. - 결정론적 샘플링: 입력 토큰과 샘플링 파라미터가 같으면 출력도 같습니다. 배치 불변 모드, MTP 가변 길이 디코딩 비활성화(
DEEPINFER_ENABLE_MTP_VARLEN=0), 고정된seq_seed가 필요합니다.
둘 다 이번 릴리스에서는 NVIDIA 전용입니다. 대표 기능은 아니지만, 진지한 평가 팀이라면 눈여겨볼 만한 항목입니다.
구조화된 출력: 프롬프트가 아니라 문법을 제약하기
구조화된 출력은 생성을 정규식, JSON Schema, EBNF 문법으로 제약합니다. DeepSeek의 프로덕션 설계는 제약을 별도 머신에서 문법 오토마타로 컴파일한 뒤, 디코드 스텝마다 토큰 마스크를 적용합니다. 컴파일과 추론이 분리되어 있어, 요청은 엔진에 들어가기 전에 컴파일된 문법을 받아 올 수 있습니다.
릴리스에서 API는 SamplingParams(so_args={"schema_type": ..., "schema": ...})입니다. 오프라인 예제는 --check_structured_output으로 정규식, JSON, EBNF 검사를 실행하고 정상적인 EOS 종료까지 확인할 수 있습니다.
DeepInfer만의 기능은 아닙니다. 제약 디코딩은 널리 알려진 기법입니다. 다만 서빙 엔진 안에 들어 있다는 점이 에이전트와 추출 워크로드에는 편리합니다.
DeepSeek Recipe: “API 호환”의 나머지 절반
추론 엔진은 토큰을 계산합니다. API 서비스는 그 외에도 다음을 해야 합니다.
- Chat Completions, Responses, Messages 요청을 받아들이고,
- 사고 모드, 도구, 이미지를 포함한 모델의 프롬프트 형식을 렌더링하고,
- 사용자 텍스트가 특수 토큰을 주입하지 못하게 하면서 텍스트를 토큰 ID로 인코딩하고,
- 청크 경계를 넘나드는 스트리밍 출력을 파싱하고,
- 추론 내용, 도구 호출, 정지 시퀀스를 다시 프로토콜 응답으로 변환합니다.
deepseek-recipe가 그 일을 합니다. 별도의 MIT 라이선스 저장소로, Python 바인딩을 제공하는 Rust 라이브러리와 예제 서버로 구성됩니다. DeepSeek는 처리 로직이 공식 API와 정렬되어 있어 서드파티 배포도 공식 서비스처럼 동작할 수 있다고 말합니다.
눈여겨볼 만한 두 가지 세부 사항이 있습니다.
- 특수 토큰 주입 방어. 사용자가
<|User|>나<|image|>를 입력하면 Recipe는 이를 제어 토큰이 아니라 일반 텍스트로 인코딩합니다. 사용자 콘텐츠를 역할 경계로 착각하게 만들 수 없습니다. - 분할 병렬 토큰화. 프롬프트를 만들 때 특수 토큰과 그 위치를 이미 알고 있으므로, 그 사이의 일반 텍스트 구간을 독립적으로 인코딩한 뒤 이어 붙일 수 있습니다. 긴 컨텍스트에서 토큰화 지연이 줄어듭니다.
DeepInfer를 서빙 스택으로 평가하고 있다면 Recipe도 엔진만큼 주의 깊게 볼 가치가 있습니다. 엔진이 비싼 부분이라면, API가 제대로 느껴지게 만드는 것은 Recipe입니다.
새로운 아이디어인가, 오래된 아이디어인가?
| 개념 | 상태 | DeepSeek가 더한 것 |
|---|---|---|
| 추측 디코딩 | 확립된 기법 | DSpark의 신뢰도 기반 가변 길이 검증 스케줄링 |
| 슬라이딩 윈도 어텐션 | 확립된 기법 | 바운디드 리플레이 + SWA KV 비영구화 |
| 전문가 병렬화 | 확립된 기법 | 64–128 GPU 규모의 Wide-EP와 프로덕션 EPLB 튜닝 |
| 연속 배칭 / 비동기 스케줄링 | 확립된 기법 | 완성도 있는 기본 활성 구현 |
| 구조화된 출력 | 확립된 기법 | 엔진에 통합, 문법 컴파일 분리 |
| 배치 불변 / 결정론적 추론 | 덜 흔함 | 조건이 문서화된 명시적 지원(NVIDIA 전용) |
| 전용 3FS 클러스터의 KV cache | DeepSeek 고유 | 100 PiB, 3/7일 TTL, 머신 간 프리픽스 적중 |
| CED + SWA 리플레이 공동 설계 | DeepSeek 고유 | 모델 아키텍처와 엔진을 함께 튜닝 |
솔직하게 말하면, DeepSeek가 이 기본 요소 대부분을 발명한 것은 아닙니다. 기여는 통합이며, 프로덕션 튜닝을 공개하려는 의지입니다.
프로덕션 설계 ≠ 오픈소스 코드
EPD, EPLB, KV cache, 로드 밸런싱 절에서 다룬 내용은 모두 DeepSeek의 Q&A에 문서화된 프로덕션 시스템을 설명한 것입니다. 릴리스에는 KV cache 시스템, VE/프리필/디코드 분리, 데이터 병렬 로드 밸런싱이 포함되지 않았습니다. 프로덕션 설계를 읽는 것은 엔진을 이해하는 데는 유용하지만, 저장소의 기능 목록은 아닙니다.
Q&A가 주는 것은 코드 뒤의 결정들을 담은 드문 지도입니다. 왜 Wide-EP인지, 왜 64+64인지, 왜 3FS인지, 왜 3/7일 TTL인지, 왜 바운디드 리플레이인지, 왜 가변 검증인지. 다른 연구소의 엔지니어에게 이 지도는 릴리스에서 가장 값진 부분입니다. 코드가 엔진 경계에서 멈추더라도 마찬가지입니다.
다음: 두 차트를 읽는 법, 빠진 구성요소가 배포에 무엇을 뜻하는지, 또는 서빙 비교: vLLM, SGLang, TensorRT-LLM.