[DeepSeek-V4-Flash-0731] 단일 RTX 5090 + DDR5 데스크탑 환경에서 vLLM CPU/RAM 오프로딩을 통한 1M
요약
RTX 5090과 대용량 DDR5 RAM을 활용하여 DeepSeek-V4-Flash 모델을 vLLM의 CPU/RAM 오프로딩 기술로 구동하는 방법을 다룹니다. FlashInfer 라이브러리의 CUDA 라이브러리 경로 인식 오류를 해결하기 위한 로컬 패치 방법과 최적화된 실행 환경 설정을 공유합니다.
핵심 포인트
- RTX 5090 32GB와 256GB DDR5 환경에서 대규모 MoE 모델 구동 가능
- FlashInfer의 CUDA IPC helper 라이브러리 경로 인식 오류 해결 패치 제공
- vLLM 및 lk_moe를 활용한 CPU/RAM 오프로딩 최적화 구성법
- NUMA 및 스레드 바인딩 설정을 통한 성능 최적화 가이드
우선, 이 게시물을 작성하는 데 당연히 AI의 도움을 받았으며, 제가 이 모든 것을 성취할 수 있게 해준 주제는 다음과 같습니다: https://old.reddit.com/r/LocalLLaMA/comments/1veow4b/deepseek_v4flash_284b_moe_at_33_toks_single_68/ 이 게시물은 위 링크를 기반으로 작성되었습니다.
나의 하드웨어:
RTX 5090 32GB
Ryzen 9 9950X3D
256GB DDR5-5600
Single NUMA node
Linux Mint
NVIDIA driver 595.71.05
CUDA 13.2
소프트웨어:
guqiong96/Lvllmds4-x
vLLM 2.3.9
lk_moe 2.3.2
PyTorch 2.11.0+cu130
native DeepSeek-V4-Flash-0731 safetensors checkpoint
48 safetensors shards
~155.4 GiB checkpoint size
필요했던 수정 사항:
시작 중에 FlashInfer의 CUDA IPC helper가 실제 로드된 CUDA runtime 대신 TileLang의 libcudart_stub.so를 실수로 찾을 수 있었습니다. 이는 결국 다음과 같은 오류를 유발했습니다: undefined symbol: cudaDeviceReset
문제는 FlashInfer의 find_loaded_library("libcudart")가 /proc/self/maps에 대해 부분 문자열 검색(substring search)을 수행한다는 점이었습니다. 저는 다음과 같이 flashinfer/comm/cuda_ipc.py를 패치하여 실제 파일 이름을 확인하도록 수정했습니다:
def find_loaded_library(lib_name):
with open("/proc/self/maps") as f:
for line in f:
if "/" not in line:
continue
start = line.index("/")
path = line[start:].strip()
filename = path.split("/")[-1]
if ( filename.startswith(lib_name + ".so") or filename.startswith(lib_name + "-") ):
return path
return None
그 후, FlashInfer는 TileLang 스텁 대신 실제 libcudart를 올바르게 찾아냅니다. 이것은 로컬 패치이며, 패키지가 교체될 경우 당연히 다시 적용해야 합니다.
현재 실행 구성:
제가 최종적으로 사용한 구성은 다음과 같습니다:
source ~/ds4x-venv/bin/activate
MODEL="/home/blackbeard/models/DeepSeek-V4-Flash-0731"
export CUDA_DEVICE_ORDER=PCI_BUS_ID
export CUDA_VISIBLE_DEVICES=0
export LVLLM_MOE_NUMA_ENABLED=1
export LK_THREADS=12
export OMP_NUM_THREADS=12
export LK_THREAD_BINDING=CPU_CORE
두 개의 완전한 라우팅된 MoE 레이어를 GPU에 상주하도록 유지합니다.
export LVLLM_GPU_RESIDENT_MOE_LAYERS=0,1
현재는 CPU/하이브리드 프리필(prefill) 경로를 사용합니다.
export LVLLM_GPU_PREFILL_MIN_BATCH_SIZE=0 export FLASHINFER_DISABLE_VERSION_CHECK=1 export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True vllm serve "$MODEL"
--host 0.0.0.0
--port 8070
--tensor-parallel-size 1
--max-model-len 1048576
--gpu-memory-utilization 0.92
--trust-remote-code
--served-model-name DeepSeek-V4-Flash-0731
--compilation_config.cudagraph_mode FULL_DECODE_ONLY
--enable-prefix-caching
--enable-chunked-prefill
--max-num-batched-tokens 8192
--dtype bfloat16
--max-num-seqs 2
--enable-auto-tool-choice
--tool-call-parser deepseek_v4
--kv-cache-dtype fp8_ds_mla
--tokenizer-mode deepseek_v4
--reasoning-parser deepseek_v4
--default-chat-template-kwargs '{"enable_thinking": true, "reasoning_effort": "max"}'
--speculative-config '{"method":"dspark","num_speculative_tokens":2,"draft_sample_method":"greedy"}'
--disable-custom-all-reduce
32GB GPU에 두 개의 완전한 라우팅된 MoE 레이어가 상주(resident)하더라도 전체 1M 컨텍스트가 들어맞습니다. 나머지 전문가(experts)들은 시스템 RAM에 남아 있습니다. DSpark는 추론 과정에서 매우 다르게 작동합니다. 긴 추론 구간 동안, 초안 수용률(draft acceptance)은 급격히 떨어질 수 있습니다. 저는 다음과 같은 시기들을 관찰했습니다: 초안 수용률: ~30-50% 생성 속도: ~11-13 tok/s 약 6분간의 기간이 평균적으로 다음과 같았습니다: 초안 수용률: ~40% 생성 속도: ~11.9 tok/s 이후 모델은 훨씬 더 예측 가능한 생성 단계로 전환되었고, 수치는 대략 다음과 같이 급증했습니다: 초안 수용률: ~87-88% 생성 속도: ~17.4-17.6 tok/s 관계는 매우 강력합니다: 처리량(throughput)이 기본적으로 DSpark 수용률을 따릅니다. 일부 높은 수용률 구간은 다음과 같습니다: 평균 초안 수용률: 89.8% 평균 생성 처리량: 17.9 tokens/s 반면, 낮은 수용률의 추론 구간은 다음과 같습니다: 평균 초안 수용률: 38% 평균 생성 처리량: ~12 tokens/s 이는 명확한 최적화가 필요함을 시사합니다.
동적 DSpark 깊이 (Dynamic DSpark depth): 이 워크로드의 경우, 이상적인 동작은 대략 다음과 같을 것으로 추측됩니다: 추론/사고 (reasoning/thinking): 1개의 투기적 토큰 (speculative token), 일반/최종 디코딩 (normal/final decoding): 2개의 투기적 토큰. 모델이 어려운 추론을 수행하는 동안에는 두 번째 초안 토큰을 계산하는 것이 종종 가치가 없지만, 모델이 더 예측 가능한 코드/텍스트 생성으로 전환될 때는 매우 가치 있게 변합니다. 현재 vLLM은 이를 위한 간단한 런타임 스위치를 제공하지 않으므로, 나중에 투기적 디코딩 (speculative decoding) 경로를 패치하여 모델이 현재 추론을 출력하고 있는지 아니면 최종 출력을 출력하고 있는지에 따라 초안 깊이 (draft depth)를 변경하는 실험을 해볼 수도 있습니다. 이는 남은 디코딩 최적화 중 가장 큰 과제 중 하나로 보입니다. ---비 AI 코멘트 섹션 시작--- 추론 중에 속도가 느려지는 그 멍청한 동작을 수정하고 이 스택에서 더 많은 tps를 짜내기 위해 if/else 블록을 작업 중이니 계속 지켜봐 주세요. ---비 AI 코멘트 섹션 종료--- /u/BlackBeardAI에 의해 제출됨 [link] [comments]
AI 자동 생성 콘텐츠
본 콘텐츠는 r/LocalLLaMA의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기