vllm.models.deepseek_v41.amd.ops.fused_markov
¶
DSpark's sequential Markov sampling with one launch a draft step.
vLLM's DSparkSpeculator._sample_sequential runs about 9 kernels for each
of the 5 draft steps: the Markov embedding of the previous token, the bias
GEMV over the whole vocabulary (66 MB of markov_w2 at 129280 x 256 bf16),
the add to the base logits, the Gumbel sample (its kernel, the argmax over
its blocks and a gather) and the copy into draft_tokens. On MI325X at TP 4
that is about 220 us a decode step.
Here each step is one launch over the vocabulary in blocks of BLOCK tokens.
For each row, a program computes its block's bias from markov_w2, adds the
base logits, stores the step's logits into the draft logits cache and takes
the Gumbel-max of its block with vLLM's own gumbel_noised_argmax. The
next step's programs first take the argmax over the previous step's block
maxima themselves, which gives the previous token, and the last step's
tokens get one small launch. The noise depends only on the request's seed,
the draft step, the position and the token id, and both paths keep the first
of equal maxima, so the sampled token does not depend on the block size.
The bias is an fp32 sum of 256 products rounded to bf16, as vLLM's GEMV output. The products are added in another order than in vLLM's GEMV, so a bias value can differ in its last bf16 bit. That changes only which tokens the draft proposes, not the target's output, because the rejection sampler verifies every draft token against the target's own distribution.
It runs on gfx942 with --monokernel (ops.enabled()). The speculator asks
the draft model's sample_sequential (dspark.py) before its loop, and that
calls sample_sequential here.
tests/kernels/models/amd/test_dsv41_gfx942_fused_markov.py compares it with vLLM's loop.
Functions:
-
sample_sequential–DSparkSpeculator._sample_sequential with the fused launches. Returns
_loop_rest(spec, num_reqs, base_logits, sample_hidden)
¶
VLLM's loop from its base logits on, for a step whose base logits the fused launch does not take. It is the loop of _sample_sequential after compute_draft_logits, so the step computes them only once.
Source code in vllm/models/deepseek_v41/amd/ops/fused_markov.py
_scratch(device, vocab, use_fp64)
¶
Two sets of block maxima and their token ids, one written by the current step and one read from the previous step. They are allocated once, so a CUDA graph keeps their addresses.
Source code in vllm/models/deepseek_v41/amd/ops/fused_markov.py
_why_not(spec, num_reqs)
¶
Why this speculator's step takes vLLM's loop, or None when the fused launches compute the same sampling.
Source code in vllm/models/deepseek_v41/amd/ops/fused_markov.py
sample_sequential(spec, num_reqs, head_hidden)
¶
DSparkSpeculator._sample_sequential with the fused launches. Returns False, having done nothing, when this step takes vLLM's loop.
Source code in vllm/models/deepseek_v41/amd/ops/fused_markov.py
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | |