patch_mm_hc_streams.py 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. #!/usr/bin/env python3
  2. """Make the b12x runner's multimodal `inputs_embeds` buffers follow the
  3. model's native embed shape instead of a fixed 2-D [T, H].
  4. At boot the warmup probed `x` shapes of [16, 16, 4096] (hc-stream run) and
  5. [14, 4096] (plain run) from the SAME layer — the dsv4 b12x embedding emits
  6. varying rank per request. Re-fit the buffer whenever the non-token tail
  7. changes so both the mm merge and CUDA-graph capture see a stable tensor.
  8. """
  9. from pathlib import Path
  10. import vllm
  11. p = (
  12. Path(vllm.__file__).parent
  13. / "v1/worker/gpu/mm/encoder_runner.py"
  14. )
  15. text = p.read_text()
  16. old = """ x = self.model.embed_input_ids(
  17. input_ids, multimodal_embeddings=mm_embeds, is_multimodal=is_mm_embed
  18. )
  19. # Copy to the pre-allocated buffer for CUDA graphs.
  20. self.inputs_embeds[: x.shape[0]] = x
  21. return self.inputs_embeds
  22. """
  23. new = """ x = self.model.embed_input_ids(
  24. input_ids, multimodal_embeddings=mm_embeds, is_multimodal=is_mm_embed
  25. )
  26. # dsv4 b12x embeds vary in rank per request ([T, K, H] hc-stream runs,
  27. # [T, H] plain): re-fit the buffer when the non-token tail changes.
  28. tail = tuple(x.shape[1:])
  29. if (
  30. self.inputs_embeds.dim() != x.dim()
  31. or tuple(self.inputs_embeds.shape[1:]) != tail
  32. ):
  33. self.inputs_embeds = torch.zeros(
  34. self.max_num_tokens, *tail, dtype=x.dtype, device=x.device
  35. )
  36. # Copy to the pre-allocated buffer for CUDA graphs.
  37. self.inputs_embeds[: x.shape[0]] = x
  38. return self.inputs_embeds
  39. """
  40. if old not in text:
  41. raise SystemExit(f"encoder_runner patch target missing in {p}")
  42. p.write_text(text.replace(old, new, 1))
  43. print("encoder_runner mm shape-follow patch applied")
  44. # Same shape-follow for the DSpark speculator's re-embed buffer: with the
  45. # multimodal gate on, the MTP speculator re-embeds draft tokens through the
  46. # target's embed and assigns [B, T, H] rows into a [max, hidden] buffer.
  47. sp = (
  48. Path(vllm.__file__).parent
  49. / "v1/worker/gpu/spec_decode/multi_module_mtp/speculator.py"
  50. )
  51. sp_text = sp.read_text()
  52. sp_old = """ if self.inputs_embeds is not None:
  53. mm_embeds, is_mm_embed = mm_inputs or (None, None)
  54. self.inputs_embeds[:num_tokens] = self.model.embed_input_ids(
  55. self.input_buffers.input_ids[:num_tokens],
  56. multimodal_embeddings=mm_embeds,
  57. is_multimodal=is_mm_embed,
  58. )
  59. """
  60. sp_new = """ if self.inputs_embeds is not None:
  61. mm_embeds, is_mm_embed = mm_inputs or (None, None)
  62. emb = self.model.embed_input_ids(
  63. self.input_buffers.input_ids[:num_tokens],
  64. multimodal_embeddings=mm_embeds,
  65. is_multimodal=is_mm_embed,
  66. )
  67. if emb.dim() != self.inputs_embeds.dim() or tuple(
  68. emb.shape[1:]
  69. ) != tuple(self.inputs_embeds.shape[1:]):
  70. self.inputs_embeds = torch.zeros_like(
  71. emb, dtype=emb.dtype, device=emb.device
  72. )
  73. self.inputs_embeds[:num_tokens] = emb
  74. """
  75. if sp_old in sp_text:
  76. sp.write_text(sp_text.replace(sp_old, sp_new, 1))
  77. print("speculator re-embed shape-follow patch applied")
  78. else:
  79. print("speculator re-embed pattern not found — skipping (harmless)")