|
97 | 97 | "max_model_len": 8192, |
98 | 98 | "reasoning": False, |
99 | 99 | }, |
100 | | - "llama-3.3-70b": { |
101 | | - "hf_id": "meta-llama/Llama-3.3-70B-Instruct", |
102 | | - # 70B params in bf16 = ~140 GB; doesn't fit on single H100 (80 GB). |
103 | | - # H200 has 141 GB — fits with headroom for KV cache. |
104 | | - "gpu": "H200", |
| 100 | + # DeepSeek-R1-Distill-Llama-70B — non-gated (MIT) reasoning distill; the |
| 101 | + # 70B member of the DeepSeek-R1-Distill series (base: Llama-3.3-70B). Used |
| 102 | + # in place of the gated meta-llama/Llama-3.3-70B-Instruct so no HF token is |
| 103 | + # needed. 70B bf16 checkpoint ≈ 131 GiB — a single H200 (140 GiB) loads the |
| 104 | + # weights but has no room left for the KV cache ("Available KV cache: -16 |
| 105 | + # GiB"), so shard across 2× H200 with tensor parallelism. |
| 106 | + "deepseek-r1-distill-llama-70b": { |
| 107 | + "hf_id": "deepseek-ai/DeepSeek-R1-Distill-Llama-70B", |
| 108 | + "gpu": "H200:2", |
| 109 | + "tensor_parallel_size": 2, |
105 | 110 | "max_model_len": 8192, |
106 | | - "reasoning": False, |
107 | | - "needs_hf_token": True, |
| 111 | + "reasoning": True, |
| 112 | + "reasoning_parser": "deepseek_r1", |
108 | 113 | }, |
109 | | - # Non-gated 72B-class general-purpose model. 72B in bf16 = ~144 GB; |
110 | | - # H200's 141 GB is just tight enough at gpu_memory_utilization=0.85 |
111 | | - # (~120 GB allocation, ~24 GB headroom for KV cache). |
| 114 | + # Non-gated 72B-class general-purpose model. 72B bf16 checkpoint ≈ 135 GiB — |
| 115 | + # does NOT fit one H200 (140 GiB) once memory profiling + KV cache are added |
| 116 | + # (OOMs with ~131 MiB free). Shard across 2× H200 with tensor parallelism. |
112 | 117 | "qwen2.5-72b": { |
113 | 118 | "hf_id": "Qwen/Qwen2.5-72B-Instruct", |
114 | | - "gpu": "H200", |
| 119 | + "gpu": "H200:2", |
| 120 | + "tensor_parallel_size": 2, |
115 | 121 | "max_model_len": 8192, |
116 | 122 | "reasoning": False, |
117 | 123 | }, |
118 | 124 | # Codestral may also be gated depending on HF account access policy. |
119 | 125 | # If you see "Cannot access gated repo" errors, add "needs_hf_token": True |
120 | 126 | # to its entry too. |
| 127 | + |
| 128 | + # ── Added anchors (non-gated) ───────────────────────────────────────── |
| 129 | + # Second reasoning family + newer generation, both 32B. Both emit <think>, |
| 130 | + # so the deepseek_r1 reasoning parser applies. |
| 131 | + # |
| 132 | + # These run on a SINGLE H200 (not A100-80GB) at 16384 ctx, unlike the |
| 133 | + # R1-distill-32b. A limit-4 smoke test showed QwQ on A100-80GB@8192 |
| 134 | + # exhausted its token budget (~5k tokens) mid-reasoning and never emitted |
| 135 | + # code — A100-80GB only leaves ~18.9k tokens of KV pool for a 32B model, |
| 136 | + # so it can't hold a longer context. QwQ's reasoning is far more verbose |
| 137 | + # than the R1 distills, so it needs both more tokens (16384) and the KV |
| 138 | + # headroom of an H200 (~58 GiB free after weights) to batch at that length. |
| 139 | + "qwq-32b": { |
| 140 | + # RL-trained reasoning model (NOT an R1 distill). Apache-2.0. |
| 141 | + # max_tokens 12288 (vs 4096 default): a smoke test showed QwQ's <think> |
| 142 | + # alone exceeds 4096 tokens, truncating before any code. 12288 + a |
| 143 | + # ~2-3k prompt stays within the 16384 max_model_len. |
| 144 | + "hf_id": "Qwen/QwQ-32B", |
| 145 | + "gpu": "H200", |
| 146 | + "max_model_len": 16384, |
| 147 | + "max_tokens": 12288, |
| 148 | + "reasoning": True, |
| 149 | + "reasoning_parser": "deepseek_r1", |
| 150 | + }, |
| 151 | + "qwen3-32b": { |
| 152 | + # Newer generation; thinking mode on by default. Apache-2.0. |
| 153 | + "hf_id": "Qwen/Qwen3-32B", |
| 154 | + "gpu": "H200", |
| 155 | + "max_model_len": 16384, |
| 156 | + "max_tokens": 12288, |
| 157 | + "reasoning": True, |
| 158 | + "reasoning_parser": "deepseek_r1", |
| 159 | + }, |
| 160 | + # Second coder family — tests whether the coder edge is Qwen-specific. |
| 161 | + # Non-reasoning; given comfortable GPU headroom to avoid vLLM-init OOM. |
| 162 | + "opencoder-8b": { |
| 163 | + # Open/reproducible code LLM (infly). ~7B-tier peer to coder-7b. |
| 164 | + "hf_id": "infly/OpenCoder-8B-Instruct", |
| 165 | + "gpu": "L40S", |
| 166 | + "max_model_len": 8192, |
| 167 | + "reasoning": False, |
| 168 | + }, |
| 169 | + "deepseek-coder-v2-lite": { |
| 170 | + # 16B MoE (2.4B active) code model — adds a dense-vs-MoE axis too. |
| 171 | + "hf_id": "deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct", |
| 172 | + "gpu": "A100-80GB", |
| 173 | + "max_model_len": 8192, |
| 174 | + "reasoning": False, |
| 175 | + }, |
| 176 | + "yi-coder-9b": { |
| 177 | + # 9B code model, Apache-2.0. Optional third coder family. |
| 178 | + "hf_id": "01-ai/Yi-Coder-9B-Chat", |
| 179 | + "gpu": "L40S", |
| 180 | + "max_model_len": 8192, |
| 181 | + "reasoning": False, |
| 182 | + }, |
121 | 183 | } |
122 | 184 |
|
123 | 185 | # --- Modal app + image ------------------------------------------------------ |
@@ -187,6 +249,9 @@ def load(self): |
187 | 249 | enforce_eager=True, |
188 | 250 | # Conservative GPU-mem fraction so KV cache + workspace fits. |
189 | 251 | gpu_memory_utilization=0.85, |
| 252 | + # Shard large models across multiple GPUs (1 = single-GPU default). |
| 253 | + # 70B+ bf16 weights exceed a single H200, so those cfgs set this to 2. |
| 254 | + tensor_parallel_size=cfg.get("tensor_parallel_size", 1), |
190 | 255 | ) |
191 | 256 | # Reasoning models: enable vLLM's reasoning-content parser so the |
192 | 257 | # <think> trace is exposed separately from the answer text. The |
@@ -233,8 +298,13 @@ def generate_batch(self, prompts: list[str], |
233 | 298 | not separated by vLLM (fallback for older vLLM versions). |
234 | 299 | """ |
235 | 300 | from vllm import SamplingParams |
| 301 | + # Per-model override: verbose reasoning models (QwQ, Qwen3-thinking) |
| 302 | + # need far more than the 4096 default or they exhaust the budget mid- |
| 303 | + # <think> and never emit code. Set "max_tokens" in their MODELS entry. |
| 304 | + effective_max_tokens = MODELS[self.model_key].get("max_tokens", |
| 305 | + max_tokens) |
236 | 306 | params = SamplingParams( |
237 | | - temperature=0.0, top_p=1.0, max_tokens=max_tokens, |
| 307 | + temperature=0.0, top_p=1.0, max_tokens=effective_max_tokens, |
238 | 308 | ) |
239 | 309 | # Apply each model's chat template so instruct-tuned models get |
240 | 310 | # the role/turn markers they were fine-tuned to receive. |
|
0 commit comments