DeepSeek-V4.1-Flash(Q3_K_M 347 GB)를 VRAM 72 GB·RAM 251 GB 기계에서 돌리는 evergreen 기록이다. 첫 실행 전에 쓴 산술은 측정으로 교정했고, 틀린 투영은 지우지 않고 남긴다.
아홉 샤드 텐서 헤더에서 읽었다. 1046개 텐서, 역할별 합산:
| 역할 | 텐서 | 크기 |
|---|---|---|
| routed expert | 120 | 258.8 GB |
| engram 테이블 | 8 | 84.6 GB |
| attention + hyper-connection | 623 | 2.2 GB |
| 임베딩·norm·출력 | 175 | 1.1 GB |
| shared expert | 120 | 0.7 GB |
| 합계 | 1046 | 347.4 GB |
두 줄이 전부다. dense 부분은 4.0 GB — 파일의 1% 남짓이라 VRAM은 사실상 routed expert 차지다. routed expert는 파일의 75%인데 희소하게 읽힌다. 레이어당 384개 중 6개가 도니 토큰당 expert 가중치는 258.8 GB × 6/384 = 4.04 GB다. 그 바이트가 어디 사는지지가 성능 이야기의 전부다. 나머지 critical path는 토큰당 3 GB 미만이고 GPU에 있다.
engram 테이블은 마흔 층 중 두 층만 지고 있다. 두 텐서(blk.1·blk.14.engram_embd, 각 [256, 384006168] Q3_K)로 하나가 42,240,678,480 바이트 — 가중치당 3.44비트다. 둘을 합치면 196.6 B 파라미터, 모델의 약 40%다. 저장된 행 수 384,006,168은 24개 해시 버킷의 합과 정확히 일치한다.
읽기는 토큰당 48행이고 페이로드는 5.2 KiB에 불과하다. 문제는 그 48행이 흩어져 있다는 것이라, 4 KiB 페이지로 끊으면 최악 192 KiB를 건드린다. 대역폭이 아니라 I/O 횟수 문제이고, NVMe가 이야기에 들어오는 이유다.
로드가 이것을 확인해 준다. 상주량이 파일 크기보다 84.5 GB 적게 잡히면 테이블은 드라이브에 있는 것이다.
첫 실행 전에는 상수가 없었다. 이전 모델(V4-Flash 24.6 tok/s, 토큰당 RAM에서 expert 2.63 GB)에서 64.8 GB/s를 빌려 V4.1에 투영하면 16–18 tok/s였다.
첫 실행이 갈아엎었다. GPU에 expert 6층, engram 행은 페이지 캐시에 있는 상태 — DDR4 경로 그 자체:
49.65 ms/token, GPU 작업 6.6 ms 제외 = DDR4에서 43.1 ms
3.44 GB/token ÷ 43.1 ms = 79.8 GB/s
이 상자의 RAM은 한 NUMA 노드에 다 있다(node 0 size: 257559 MB). 같은 메모리의 순차읽기 115.8 GB/s(TSTREAM식 측정, README 기계표) against **69%**다. 200 GB mmap expert 가중치 gather가 순차읽기의 69%에 닿는다. 빌린 상수는 5분의 1 비관적이었다. 남은 31%가 여기서 가장 큰 미설명량이고, -thp가 물을 자리다.
Steady state 실측:
| 구성 | steady | 비고 |
|---|---|---|
| expert 6층(4+2), engram 캐시 | 20.14 tok/s | DDR4 상한, 실부하 아님 |
| expert 8층(6+2), 프롬프트 4종 | ~20.1 tok/s | 수렴 |
| expert 8층, 로드 직후 첫 실행 | 9.28 tok/s | GPU0 46.2/49.1 GB |
투영 17.4, 기계는 20을 돌려준다. 제대로 재는 데 수정이 두 번 들었다. 마음대로 멈춘 19토큰 샘플(캐시 워밍이 전부 지배)과, temperature 0 동일 프롬프트 반복(같은 토큰·같은 engram 행, 두 번째는 전부 페이지 캐시 — major fault 0에 20.14 tok/s, 한 적 없는 일의 숫자). 둘 다 configs/bench-serve.sh에 주석으로 있다. 정직한 프로토콜은 실행마다 다른 프롬프트고, 거기서 나온 것이 engram 지역성이다. 서로 무관한 영어 텍스트 네 개에 major fault가 토큰당 38.6→9.4개로 떨어진다. 흔한 n-gram이 겹쳐 3.84억 행 테이블의 hot 행이 캐시에 모여 산다. working set은 테이블보다 훨씬 작다.
위의 토큰당 예산은 패스 하나를 가정한다. 투기 디코딩의 검증 패스는 토큰 k개를 한 번에 보므로 예산이 어떻게 자라는지가 따로 있고, 그게 이 기계에서 측정됐다(WKS-36 기록).
ms/패스(k) = 10.32 + 50.21 + 17.28·k (잔차 ±0.36 ms, 세 점·두 파라미터)
드래프트 첫 위치 위치 하나 더
dense 7.658 GB는 k에 상관없이 한 번 읽히고, 라우팅 expert 4.044 GB는 토큰마다 다시 읽힌다. 기울기 17.28 ms가 패스 50.21 ms의 34.43%이고 라우팅 몫이 34.56%다 — 0.13%p.
이유는 라우팅이 토큰별이라는 것뿐이다. 층마다 384개 중 6개를 뽑으니 두 토큰이 같은 expert에 닿을 기대값이 0.09개고, 합집합이 선형으로 자란다. 한 문장 안의 인접 토큰에서도 그렇다는 것이 이 측정의 내용이다.
실무 규칙 셋:
- 검증 패스를 "공짜"로 두고 투영하지 않는다. MoE에서 그 항의 바닥은 0이 아니라 라우팅 바이트 몫이다. 이 파일의 이전 투영 중 그 가정을 쓴 것이 있으면 이 절이 정본이다.
- 깊이를 늘리는 것은 레버가 아니다. 드래프트 토큰의 실효 단가가
n_max1·2·3에서 39.5 → 40.3 → 44.0 ms로 오른다. 수락률이 떨어지는 속도가 더 빠르다. - 드래프트 자체 비용은 k에 평평하다(10.32 ms). DSpark가 블록 전체를 한 패스에 내기 때문이고, EAGLE 계열을 쓴다면 이 항이 k에 비례한다.
DDR4에서 토큰당 바이트가 예산의 8할이라, tok/s는 거의 선형으로 따라간다(잰 79.8 GB/s 기준이 아니라 빌린 64.8 기준 산술이라, 아래 투영은 하한으로 읽는다 — 베이스행 투영 17.4에 실측 20.1).
| 변경 | 엔진 | 파일 크기 | RAM에서 GB/토큰 | 투영 |
|---|---|---|---|---|
| 베이스 Q3_K_M, 384 중 6층 | mainline | 347.4 GB | 3.08 | 17.4 → 20.1 실측 |
-ser 5 expert |
ik 전용 | 347.4 GB | 2.56 | 20.2 |
-ser 4 expert |
ik 전용 | 347.4 GB | 2.05 | 24.0 |
-ser 3 expert |
ik 전용 | 347.4 GB | 1.54 | 29.6 |
| REAP 256E(공개 변형) | 무관 | 172.5 GB | 2.59 | 20.0 |
| expert ~3.0 bpw | ik 퀀트 | 203.8 GB | 2.22 | 22.6 |
| expert ~2.4 bpw | ik 퀀트 | 163.0 GB | 1.58 | 29.1 |
오늘 도는 것은 첫 행뿐이다. 큰 숫자는 전부 ik 아키텍처 이식 뒤에 있다. 그래서 이식이 최적화가 아니라 critical path다.
-ser가 가장 싸다. expert 개수를 바꾸는 ik 플래그, 새 파일 없이. 품질 트레이드이고 그 크기는 여기서 안 쟀다. 오후 한 번에 sweep 가능한 유일한 레버라 첫 실험은 이것이다.- expert 가지치기(REAP)는 토큰당 바이트를 안 줄인다. 384→256개를 잘라도 도는 6개는 같으니 active 바이트가 동일하다. 사는 것은 저장소 3분의 1이 사라져 VRAM에 드는 분율이 느는 것(9.6층→14.4층). 간접적이고 실재한다.
- 저비트 expert가 가장 크고 가장 안 열려 있다. expert 평균 3.81 bpw를 IQ2/IQ3으로 2.4–3.0에 넣으면 토큰당 읽기 축소와 VRAM 적재 증가가 곱해진다. ik가 이 아키텍처를 지원해야 하고(아직), fp8 원본 510 GB를 양자화해야 한다.
읽는 것은 안 바꾸고 도착 속도만 바꾼다. 이 워크로드에 정량화된 것은 하나도 없다.
- THP(
-thp, ik 전용). 4 KB 페이지에 200 GB expert면 페이지테이블 5천만 항목, 토큰마다 전역 랜덤 gather라 매번 TLB 미스 유력. 2 MB 페이지는 512분의 1이다. 이 기계 THP는madvise라 묻는 프로세스에만 나가서, 플래그는 시스템 설정과 중복이 아니라 발동 조건이다. 사라진 31%의 일부 설명 후보 중 가장 흥미로운 미측정 항목. 플래그 하나로 잰다. -rtr은 이 모델과 충돌한다. CPU 커널 선호 배치로 다시 깔아준다는데, mmap을 끈다. mmap 없이 engram을 드라이브에 둘 수 없고, engram 84.6 GB + expert ~197 GB = 282 GB 대 RAM 251 GB다.-rtr과 NVMe 상주 engram은 양립 불가. 어느 쪽이 이득인지는 질문이지 결론이 아니다.- NUMA는 제외. 싱글소켓(노드 1개)이라 묶을 것이 없다. 다음 사람이 저녁을 버리지 말라고 적는다.
- 선읽기 증폭은 해결됨. 110바이트 engram 행마다 64 KB 선읽기를 우려했는데, v41 브랜치가 lazy 범위에
POSIX_MADV_RANDOM을 박는다. 고칠 것 하나 감소.
초기 실행 프리필 39–46 tok/s는 프리필 숫자가 아니다. 벤치 프롬프트 24토큰은 배치 처리량이 의미를 갖기 한참 밑이고, MoE에서는 더하다. 24토큰 배치는 레이어마다 최대 144개 expert를 건드려 단일 토큰의 6개와 비교가 안 된다. 24로 나누면 고정 오버헤드의 숫자만 나온다.
제대로 재면 프롬프트 길이를 따라 올라가 수렴한다. 18토큰 30.2 → 133토큰 46.6 → 535토큰 117.5 → 2135토큰 150.0 → 4281토큰 160.6 tok/s. 그래도 낮았고, 두 설정이 눌렀다. -np 4가 프리필을 깎는다. 컨텍스트를 4슬롯으로 쪼개 통합 KV 캐시를 끄니, 빼자 4288토큰이 160→214 tok/s. -ub 512가 훨씬 크다. 프롬프트 처리는 compute-bound 배치라 마이크로배치가 expert 텐서 읽기를 토큰들에 분할한다.
| 구성 | 4288토큰 프리필 | 디코드 |
|---|---|---|
expert 8층(6+2), -ub 512 |
214.0 tok/s | 16.35 tok/s |
expert 6층(4+2), -ub 2048 |
344.2 tok/s | 16.47 tok/s |
expert 4층(CUDA0만), -ub 3072 |
245.2 tok/s | 15.75 tok/s |
expert 4층(CUDA0만), -ub 4096 |
282.8 tok/s | 14.98 tok/s |
디코드 무손실 프리필 +61%. 위 레버표 무엇보다 크고, 새 엔진·파일·플래그 없이 됐다.
상한은 작은 카드가 정한다. 프리필 연산 버퍼가 마이크로배치에 비례해 24 GB 카드(CUDA1)에 앉으니, 마이크로배치와 expert 층이 같은 메모리를 다툰다. GPU1을 통째로 비워 -ub 4096을 넣으면 오히려 나빠진다(282.8). 작은 카드에 expert 2층 + 마이크로배치 2048이 이 쌍의 균형점이다.
컨텍스트 길이도 같은 트레이드의 반대면이다. -c 32768 -ub 1024 디코드 19.89·프리필 187.8 대 -c 16384 -ub 2048 디코드 19.97·프리필 343.4. 컨텍스트 2배가 프리필 45%를 깎고 디코드는 그대로다. KV 양자화로 안 돌아온다. 안 맞는 것은 캐시가 아니라 연산 버퍼라서다. 서빙은 16k, 32k 세션은 프롬프트 처리량 절반을 내기로 한 선택이다.
추측. 레이어 expert 읽기는 1토큰이나 2토큰이나 거의 같으니 draft 토큰 검증이 메모리 쪽에서 거의 공짜다. 2026-09-19 선 그음 — 위 「k토큰 패스의 규칙」이 정본이다. 그 전제는 틀렸다: 레이어 expert 읽기는 토큰마다 다시 난다(토큰이 각자 자기 expert를 고른다). 1토큰이나 2토큰이나 같은 것은 **dense 몫 65.44%**뿐이고, 라우팅 34.56%는 그대로 두 번 읽힌다. 이 문단의 관찰은 그대로 맞다 — V4 실행이 draft depth 2에서 24.6→29.1 tok/s를 얻고 depth 3에서 acceptance 하락으로 잃었다. WKS-36이 같은 모양을 V4.1에서 재확인했다(수락률 0.702→0.570→0.478, 드래프트 토큰 단가 39.5→40.3→44.0 ms). 틀린 것은 관찰이 아니라 그것에 붙인 메커니즘이다. 같은 1.18×를 걸면 20.5 tok/s 근처라는 투영은 우연히 맞는 자리에 서 있을 뿐이다. V4.1은 DSpark draft 미공개다. MTP 모듈(mtp.0.*, 완전한 MoE 레이어 하나)은 safetensors 원본에 있는데 GGUF 변환에서 떨어졌다. 복원은 변환 변경이다.
동시성. 같은 V4 실행이 4동시에서 합계 47 tok/s(단일 29)를 냈다. 서빙 엔드포인트가 목표면 이 페이지 가장 큰 숫자고, 바꿀 것 없이 된다.
자주 라우팅되는 expert를 GPU에 올리는 세밀 배치는 안 된다. 한 레이어 384개 expert가 텐서 하나라(blk.0.ffn_*_exps.weight [*, *, 384]), -ot 이름 매칭 최소 단위가 "그 레이어 전부 아니면 전무"다. 라우팅은 치우쳐 있고 VRAM은 저장소의 24%만 드니, 빈도순 배치는 24%를 훨씬 넘는 라우트를 VRAM에서 맞출 수 있다. 엔진 변경 사항이지 플래그가 아니다.
expert 197 GB와 engram 84.6 GB가 둘 다 mmap이라 합 282 GB 대 RAM 251 GB다. engram이 드라이브에 남는 전제인데 커널은 모른다. engram 페이지가 캐시에 들어와 expert 페이지를 쫓아내면 47 ms 토큰이 깨진다. --lazy-mode 표시로 막히는지, 사용 후 MADV_DONTNEED가 필요한지는 미확인이다. 로드 시 상주집합 크기와 함께 처음 볼 것이다.
돌린다.끝. mainline steady 20.1 tok/s, 잰 79.8 GB/s가 빌린 64.8을 대체.전제를 확인한다.끝. 상주집합 215 GB 대 파일 347 GB. engram은 드라이브에 있고 토큰당 3.3 ms(예산의 6.3%) — hot 행 캐시 덕에 예상보다 싸다.끝. 32k 컨텍스트에 8층이 들고 9층은 안 든다. 실측 기울기 층당 +0.27 tok/s(예측 +0.5의 절반)라 남은 headroom은 찾아도 1 tok/s 미만이다.-ot분할을 민다.- KV 캐시가 쥔 VRAM을 회수한다.
-ctk q8_0 -ctv q8_0아니면 작은-c가 mainline에서 expert를 더 올리는 유일한 길이다. 기울기상 +0.5 tok/s어치. 정직하고 재미없다. - 동시성. 여기서 미측정. 엔진 안 바꾸고 쓸 수 있는 가장 큰 숫자다.
- ik 아키텍처 이식.
-ser·-thp·-rtr·저비트 퀀트를 한 번에 연다. 20 tok/s 위 투영은 전부 뒤에 있다. - 그 다음 MTP 변환과 재양자화.
4·5는 오늘 mainline으로 돈다. 그 뒤는 전부 이식 뒤다. 기울기가 이식을 최적화에서 유일한 큰 레버로 바꿨다.
가중치 Q3_K_M 347 GB 대 VRAM 72 GB. 가중치가 VRAM에 든다고 가정하는 엔진(vLLM·SGLang·EXL3 — 공개 EXL3 변환이 저장소 제목에 목표 카드 RTX PRO 6000 2장을 박았다)은 후보가 아니다.
남는 것은 모델 대부분이 호스트 RAM에 있고 토큰당 몇 %만 도는 경우를 전제로 지은 엔진이다. ik_llama.cpp·mainline llama.cpp·KTransformers. ik의 구조적 논거: 토큰당 384 중 6 expert라 일은 시스템 RAM에서 양자화 가중치를 읽는 것이고, 그 경로에 이 포크의 인생이 있다. 당시 V4-Flash를 그 구성으로 27.7 tok/s 서빙 중이었다. mainline이 --override-tensor·--n-cpu-moe·ik에 없는 --lazy-mode로 격차를 좁힌 것이 반대 논거다. 다투지 않고 잰다. V4.1 참조 런타임이 mainline 파생이라 첫 실행이 mainline 숫자를 내고, 뒤의 이식이 포크 숫자를 낸다. 같은 기계·파일·프롬프트.
Rust 엔진을 갈아탈 것 없다는 질문도 답했다. 경계가 언어가 아니다. 일은 손으로 쓴 AVX-512·CUDA 커널이고, 이 포크가 빠른 이유는 튜닝된 CPU matmul 파일 하나다. 다른 호스트 언어도 같은 코드를 부른다. 메모리 안전은 mmap 파일 몇 스레드가 읽는 프로그램의 binding 조건이 아니다. 둘째는 쌓인 포맷·아키텍처 표면 — 퀀트 타입마다 참조 구현이 여기 있고, 아키텍처마다 그래프를 누군가 썼다. V4.1은 참조 948줄, 코드베이스를 아는 사람이 쓰고도 이틀 뒤에 디버깅 중이었다. 그 비용은 모델마다 매번 들고, 내는 사람이 많은 쪽이 llama.cpp다. 토크나이저·서빙 앞단은 Rust가 이겼고 표준이다. 경계는 깨끗하다. 오케스트레이션·툴 위, 커널·포맷 아래다.
이 기계에 지을 값어치 있는 것은 셋이고, 전부 엔진 밖에 있다. 자식 프로세스로 엔진을 몰고, 커널을 안 만지니 틀린 숫자를 낼 수 없다. 최악은 나쁜 배치라 느린 실행이나 로드 거부로 드러난다.
- 배치 플래너. 텐서 목록·형상·타입은 GGUF에, VRAM·RAM·드라이브 수치는 측정됐다. 어느 텐서를 어디에 올릴지는 계산 가능한 문제인데 지금 손으로 — 나쁘게 — 한다. 첫 런치 스크립트 초안이 48 GB 카드에 expert 20층(130 GB 가중치)을 올렸다. 파일에서 읽지 않고 머리에서 들고 와서다. mainline
--fit과 포크-ot가 재료고, 없는 것은 파일과 기계를 읽고 배치를 뱉는 것이다. - expert 선읽기. 더 투기적이고 더 흥미롭다. 레이어당 384 중 6개가 돌고, 라우터 출력이 필요 직전에 이름을 부른다. 한 층 lookahead는 짧은 창이지만
드라이브 순차 6.0 GB/s다(2026-09-23 정정: 드라이브 읽기는 잰 적이 없다 — 쓰기만 5.74–5.85 GB/s, 한 줄기 populate는 1.33 GB/s였다, 09-23#v41-oracle-dump). 되면 현재안에서 RAM에 있어야 하는 205 GB가 줄고, 445 GB Q4_K_M이 사정권에 든다. 하드웨어를 정확히 아는 것이 처리량으로 바뀌는 자리다. - VRAM 중재. 이미 필요하고 가장 재미없다. 서비스 하나가 두 카드를 쥐니 나머지는 중단부터 시작한다. 소유하는 슈퍼바이저면 하루 작업에 매일 쓴다.
순서는 플래너 먼저다. 비교 대상 배치가 좋은지 모르면 선읽기가 돕는다는 것을 보일 수 없다.
2026-09-13, 5975WX 32코어. -ngl 0, 직렬, -r 3. ik 7b79b229 대 mainline 5210c7c. 한 문장씩:
- Qwen2.5-7B dense: t=32 tg128 ik/mainline 1.05–1.08. 1.0 근처.
- DeepSeek-V2-Lite MoE: t=32 tg128 1.11. 1.0 근처.
- pp512는 ik가 2.1–2.2배 빠르다(dense 217 대 104, MoE 447 대 201). tg가 아니라 pp의 이야기다.
그래서 V4.1의 20% 디코드 격차는 CPU 커널이 아니었다. -fmoe on/off ±2.5%, -rtr ±2% — 찾는 크기의 설명이 아니다. 스레드 sweep은 32가 정점(64는 떨어진다).
오염 기록도 여기 둔다. 게이트가 1분 loadavg < 4를 봤는데, 200 GB 모델 로드는 I/O-bound라 loadavg가 늦게 올라 문이 열린 채 벤치 5건이 오염됐다. "조용함"의 판정은 loadavg가 아니다. 단일 임대 파일 + /proc/pressure/io + 살아 있는 측정 프로세스 목록이고, 측정 행마다 시작·종료 시점 값을 증인으로 기록한다. 방법은 조용한 기계. ik 프롬프트 경로가 경쟁 부하에서 45% 꺼지는 부차 측정도 있다(진단 아님).