@@ -99,11 +99,53 @@ If you omit `MODEL_PATH`, the entrypoint defaults to pulling
9999` r0b0tlab/Ornith-1.5-35B-A3B-NVFP4-W4A16 ` from Hugging Face at boot
100100(` HF_HOME ` is a named volume, so the download persists across restarts).
101101
102- The image bakes the ** pre-warmed FlashInfer JIT caches** (CUTLASS FP4 GEMM
102+ The GB10 image bakes the ** pre-warmed FlashInfer JIT caches** (CUTLASS FP4 GEMM
103103sm121 modules + autotune tables + Triton cache) from the validated runs —
104104first boot does zero JIT compilation. On a cold system, first-use JIT with
105105the model resident can OOM (see [ Known runtime notes] ( #known-runtime-notes ) ).
106106
107+ ### RTX 5090 profile (Blackwell SM 12.0, 32 GB, x86-64)
108+
109+ A second, x86 image and tuned profile target a single RTX 5090:
110+
111+ ``` bash
112+ hf download r0b0tlab/Ornith-1.5-35B-A3B-NVFP4-W4A16 \
113+ --local-dir ./models/ornith-15-35b-a3b-nvfp4-w4a16-B
114+
115+ docker compose -f docker-compose.rtx5090.yml up -d
116+ # or bare:
117+ docker run --rm --gpus all --ipc host -p 8000:8000 \
118+ -v $PWD /models/ornith-15-35b-a3b-nvfp4-w4a16-B:/models/ckpt:ro \
119+ -e MODEL_PATH=/models/ckpt \
120+ ghcr.io/r0b0tlab/ornith-15-35b-nvfp4-w4a16-sm121-sglang:rtx5090
121+ ```
122+
123+ Differences vs the GB10 profile ([ ` serve-profiles/rtx5090/serve.sh ` ] ( serve-profiles/rtx5090/serve.sh ) ):
124+
125+ | Knob | GB10 (121 GB unified) | RTX 5090 (32 GB) | Why |
126+ | ---| ---| ---| ---|
127+ | ` --mem-fraction-static ` | 0.80 | ** 0.92** | dedicated 32 GB part; OS doesn't share VRAM |
128+ | ` --max-running-requests ` | default (48/105) | ** 4** | mamba state cache is the binding constraint at 32 GB |
129+ | ` --max-mamba-cache-size ` | default (528) | ** 24** | ~ 1.4 GB state cache → 4 × 32K contexts fit |
130+ | context / KV | 32768 × 105 reqs | 32768 × 4 reqs | ~ 2.5 GB FP8 KV at this occupancy |
131+ | MTP (EAGLE K=1) | on | on; ` MTP=0 ` env to disable | draft costs ~ 3.6 GB; disabling reclaims it for KV |
132+
133+ Memory budget ≈ 21.1 GB weights + 3.6 GB draft + 1.1 GB graphs + 1.4 GB
134+ mamba + 2.5 GB KV ≈ 29.7 GB. First boot on a cold cache JIT-compiles the
135+ sm_120 CUTLASS FP4 kernels (~ 10–20 min; runs in host RAM on a discrete-GPU
136+ box — safe, unlike unified-memory parts). ` docker-compose.rtx5090.yml `
137+ mounts a persistent volume for the caches so subsequent boots are warm.
138+ If capture OOMs, lower ` MAX_RUNNING_REQUESTS ` /` CONTEXT_LENGTH ` first.
139+
140+ The ` rtx5090 ` tag is built by CI ([ workflow] ( .github/workflows/build-rtx5090-image.yml ) )
141+ from [ container/Dockerfile.rtx5090] ( container/Dockerfile.rtx5090 ) , which
142+ pip-installs the same pinned stack (sglang ` 5a7b26c63 ` , torch 2.13.0+cu130,
143+ triton 3.7.1, flashinfer-python 0.6.17 + cubins) on x86 Ubuntu 24.04.
144+ ** Note:** validated end-to-end on GB10/SM121; the 5090 profile is sized from
145+ the measured memory ledger and the vendor's SM 12.0 support envelope, but was
146+ not run on physical 5090 hardware before publication — report issues if
147+ first-boot JIT behaves differently on sm_120 discrete parts.
148+
107149### Serving without the container
108150
109151SGLang ` 0.5.6.post3.dev9218+g5a7b26c63 ` , FlashInfer 0.6.17,
@@ -203,22 +245,26 @@ It scored GSM8K 70.00% vs this recipe's 76.25% and decoded at 38.6 tok/s vs
203245
204246```
205247├── README.md
206- ├── docker-compose.yml # one-command launch
207- ├── container/ # Dockerfile, serve.sh entrypoint, build script
248+ ├── docker-compose.yml # GB10/SM121 one-command launch
249+ ├── docker-compose.rtx5090.yml # RTX 5090 (SM 12.0, 32 GB) launch
250+ ├── container/ # GB10 Dockerfile + serve.sh + build script
251+ │ └── Dockerfile.rtx5090 # x86 CI-built image (same pinned stack)
252+ ├── serve-profiles/
253+ │ └── rtx5090/serve.sh # tuned launcher for a single 32 GB card
208254├── eval/
209- │ ├── run_quality_set.py # run the 200-question suite (resumable)
210- │ ├── rescore.py # fixed-scorer summaries from raw rows
211- │ ├── answer_extract.py # GSM8K answer extraction (the fixed scorer)
212- │ └── data/ # quality-200.jsonl + raw rows for 4 runs
255+ │ ├── run_quality_set.py # run the 200-question suite (resumable)
256+ │ ├── rescore.py # fixed-scorer summaries from raw rows
257+ │ ├── answer_extract.py # GSM8K answer extraction (the fixed scorer)
258+ │ └── data/ # quality-200.jsonl + raw rows for 4 runs
213259├── quantization/
214- │ ├── w4a16-nvfp4-std.yaml # the shipped recipe (candidate B)
215- │ ├── w4a16-expert-4o6.yaml # experts-only 4/6 alternative (candidate A)
216- │ ├── quant-cand-custom.py # CPU-first quantize driver
217- │ └── reattach-mtp.py # BF16 MTP re-attachment
260+ │ ├── w4a16-nvfp4-std.yaml # the shipped recipe (candidate B)
261+ │ ├── w4a16-expert-4o6.yaml # experts-only 4/6 alternative (candidate A)
262+ │ ├── quant-cand-custom.py # CPU-first quantize driver
263+ │ └── reattach-mtp.py # BF16 MTP re-attachment
218264└── audits/
219- ├── audit_checkpoint.py # scale pairing / MTP hashes / key closure
220- ├── cosine_probe.py # NVFP4 dequant cosine vs BF16 source
221- └── results/ # audit JSON outputs
265+ ├── audit_checkpoint.py # scale pairing / MTP hashes / key closure
266+ ├── cosine_probe.py # NVFP4 dequant cosine vs BF16 source
267+ └── results/ # audit JSON outputs
222268```
223269
224270## Credits and attribution
0 commit comments