Repository
DeepSeek-V4-Flash-Dual-DGX-Spark-1M-Context
Deploy DeepSeek V4 Flash (MoE reasoning model) on dual DGX Spark nodes with 1M token context, InfiniBand, and FP8 KV-cache
- Component
- Requirement
- Nodes
- 2 × DGX Spark (Grace Hopper, GB10)
- Interconnect
- InfiniBand (e.g., ConnectX-7) between nodes
- Storage
- Sufficient for model weights (~400 GB with HF cache)
Specs
- ComponentRequirement
- Nodes2 × DGX Spark (Grace Hopper, GB10)
- InterconnectInfiniBand (e.g., ConnectX-7) between nodes
- StorageSufficient for model weights (~400 GB with HF cache)
- VariableDescription
- NODE_RANK0 for head (spark1), 1 for worker (spark2)
- HEADLESSSet to 1 on worker nodes
- MASTER_ADDRIP address of the head node (spark1)
- WORKER_HOSTIP address of the worker node (spark2)
- HF_CACHEPath to your HuggingFace cache
- NCCL_IB_HCAInfiniBand HCA device (run ibdev2netdev -v )
- NCCL_SOCKET_IFNAMENetwork interface for socket comms
- ParameterValue
- --tensor-parallel-size2
- --pipeline-parallel-size1
- --kv-cache-dtypefp8
- --max-model-len1000000
- --max-num-seqs6
- --block-size256
- --gpu-memory-utilization0.82
- --enable-prefix-cachingenabled
- --speculative-configMTP, 2 tokens
- --distributed-executor-backendmp
- --nnodes2
- FilePurpose
- docker-compose.ymlContainer definition with volume mounts, env vars, and entrypoint
- .env.exampleTemplate for environment configuration
- start-deepseek-v4-flash.shStart server on both nodes
- stop-deepseek-v4-flash.shStop server on both nodes
- .gitignoreFiles excluded from version control
README
DeepSeek V4 Flash – Dual DGX Spark (1M Context)
Deploy DeepSeek-V4-Flash — a Mixture-of-Experts (MoE) reasoning model — across two NVIDIA DGX Spark nodes with 1 million token context length, InfiniBand interconnect, and FP8 KV-cache.
Overview
This repository provides a ready-to-run docker-compose.yml and helper scripts that launch a vLLM inference server serving DeepSeek V4 Flash. The setup uses:
- 2 × DGX Spark nodes (spark1 = head, spark2 = worker)
- Tensor parallelism (TP) across both GPUs
- InfiniBand (NCCL over IB) for inter-node communication
- FP8 KV-cache (
--kv-cache-dtype fp8) for memory efficiency - Multi-Token Prediction (MTP) speculative decoding (2 draft tokens)
- Prefix caching and FlashInfer autotune
- Tool calling and reasoning support (DeepSeek V4 parsers)
Default generation config: The
docker-compose.ymlsets--override-generation-config '{"temperature":0.6,"top_p":0.95}'— tuned for coding tasks. Remove this line to use DeepSeek V4 Flash's default sampling parameters.
Requirements
Hardware
| Component | Requirement |
|---|---|
| Nodes | 2 × DGX Spark (Grace Hopper, GB10) |
| Interconnect | InfiniBand (e.g., ConnectX-7) between nodes |
| Storage | Sufficient for model weights (~400 GB with HF cache) |
Software
- Docker with
docker composeplugin (v2.24+) - Passwordless SSH from spark1 → spark2
- NVIDIA Container Toolkit (
nvidia-ctk) — installed by default on DGX Spark - InfiniBand drivers (
ibdev2netdev,ibstat) — installed by default - Git and curl
Quick Start
1. Clone the repo on both nodes
git clone https://github.com/MiaAI-Lab/DeepSeek-V4-Flash-Dual-DGX-Spark-1M-Context.git
cd DeepSeek-V4-Flash-Dual-DGX-Spark-1M-Context
Run this on both spark1 (head) and spark2 (worker).
2. Download model weights on both nodes
Pre-download the model weights into the HuggingFace cache so the container doesn't download them on first run:
hf download deepseek-ai/DeepSeek-V4-Flash
Run this on both spark1 (head) and spark2 (worker). This requires the huggingface_hub CLI (pip install huggingface_hub).
3. Configure environment
cp .env.example .env
Edit .env to match your cluster:
| Variable | Description | Example |
|---|---|---|
NODE_RANK |
0 for head (spark1), 1 for worker (spark2) |
0 |
HEADLESS |
Set to 1 on worker nodes |
(empty for head) |
MASTER_ADDR |
IP address of the head node (spark1) | 192.168.1.100 |
WORKER_HOST |
IP address of the worker node (spark2) | 192.168.1.101 |
HF_CACHE |
Path to your HuggingFace cache | ${HOME}/.cache/huggingface |
NCCL_IB_HCA |
InfiniBand HCA device (run ibdev2netdev -v) |
rocep1s0f1 |
NCCL_SOCKET_IFNAME |
Network interface for socket comms | enp1s0f1np1 |
Finding your InfiniBand interface:
ibdev2netdev -vPick the
rocep*device connected to your IB link.
Finding your socket interface:
ip addr show | grep 169.254Pick the interface with the link-local IP used for NCCL out-of-band communication.
4. Set NODE_RANK on each node
On spark1 (head):
NODE_RANK=0
On spark2 (worker):
NODE_RANK=1
HEADLESS=1
Update .env accordingly on each node.
5. Start the server
From spark1 only:
./start-deepseek-v4-flash.sh
This script:
- SSHs into spark2 and starts the container there
- Starts the container on spark1
- Polls
http://127.0.0.1:8000/v1/modelsuntil the API is ready (up to ~20 minutes)
6. Stop the server
From spark1 only:
./stop-deepseek-v4-flash.sh
API Usage
Once running, the OpenAI-compatible vLLM API is available on both nodes at http://localhost:8000.
Chat completion (with reasoning)
curl http://127.0.0.1:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4-flash",
"messages": [
{"role": "user", "content": "What is 47 × 89?"}
],
"temperature": 0.0
}'
Streaming
curl http://127.0.0.1:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4-flash",
"messages": [
{"role": "user", "content": "Write a haiku about distributed inference"}
],
"stream": true
}'
Tool calling
The server is configured with --tool-call-parser deepseek_v4 and --enable-auto-tool-choice for function-calling tasks.
Architecture
┌─────────────────────────┐ InfiniBand ┌─────────────────────────┐
│ spark1 (head) │◄───────────────────────►│ spark2 (worker) │
│ NODE_RANK=0 │ NCCL (IB / sockets) │ NODE_RANK=1 │
│ ┌───────────────────┐ │ │ ┌───────────────────┐ │
│ │ vLLM container │ │ │ │ vLLM container │ │
│ │ TP rank 0 (GPU 0) │ │ │ │ TP rank 1 (GPU 1) │ │
│ │ Port 8000 (API) │ │ │ │ Port 8000 (API) │ │
│ └───────────────────┘ │ │ └───────────────────┘ │
└─────────────────────────┘ └─────────────────────────┘
Key vLLM parameters
| Parameter | Value | Purpose |
|---|---|---|
--tensor-parallel-size |
2 |
Split model across 2 GPUs |
--pipeline-parallel-size |
1 |
No pipeline parallelism |
--kv-cache-dtype |
fp8 |
FP8 KV cache for memory savings |
--max-model-len |
1000000 |
1M token context |
--max-num-seqs |
6 |
Max concurrent sequences |
--block-size |
256 |
PagedAttention block size |
--gpu-memory-utilization |
0.82 |
GPU memory budget |
--enable-prefix-caching |
enabled | Reuse KV cache across requests |
--speculative-config |
MTP, 2 tokens | Multi-Token Prediction |
--distributed-executor-backend |
mp |
Multi-process backend |
--nnodes |
2 |
Two-node deployment |
Docker Images
The compose file uses aidendle94/sparkrun-vllm-ds4-gb10:production-ready — a custom vLLM build optimized for DGX Spark (GB10, CUDA arch 12.1a, FlashInfer for Hopper).
If you need to rebuild or use a different image, update the image: field in docker-compose.yml.
Files
| File | Purpose |
|---|---|
docker-compose.yml |
Container definition with volume mounts, env vars, and entrypoint |
.env.example |
Template for environment configuration |
start-deepseek-v4-flash.sh |
Start server on both nodes |
stop-deepseek-v4-flash.sh |
Stop server on both nodes |
.gitignore |
Files excluded from version control |
Troubleshooting
NCCL / InfiniBand
- Verify IB link state:
ibstat(should showLinkUp: true) - Test passwordless SSH:
ssh <WORKER_HOST> hostname - Check NCCL debug logs (set
NCCL_DEBUG=INFOin compose env)
Container fails to start
docker compose logs
CUDA out of memory
Reduce --gpu-memory-utilization (e.g., 0.75) or --max-model-len.
Timeout waiting for API
The model loads from HuggingFace on first run. Check logs:
docker logs deepseek-v4-flash-vllm-1
License
This repository's code is provided under the MIT License. The DeepSeek V4 Flash model weights are subject to DeepSeek's license.