Skip to content

Commit 293a7a4

Browse files
mingyangHaolfr-0531
authored andcommitted
[None][fix] DSv4 fused FP8 Q-quant: q_pe must be 3D for thop.attention (NVIDIA#14433)
Signed-off-by: Mingyang Hao <mingyangh@nvidia.com> Signed-off-by: Mingyang Hao <mingyangHao@users.noreply.github.com>
1 parent 69eb559 commit 293a7a4

3 files changed

Lines changed: 42 additions & 5 deletions

File tree

tensorrt_llm/_torch/modules/attention.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,21 +1760,21 @@ def _deepseek_v4_q_b_layernorm_fused_fp8(self, q_proj: torch.Tensor):
17601760
self._quant_scale_qkv = torch.tensor([1.0],
17611761
dtype=torch.float32,
17621762
device=q_proj.device)
1763-
# Allocate the interleaved [N, H*head_dim] FP8 buffer (nope filled by
1764-
# this op, rope slot left for applyMLARopeAndAssignQKVKernelOptContext) and the bf16 rope buffer.
1763+
# q_pe is 3D so thop.attention's sparse-MLA context branch passes its
1764+
# q_pe->dim() == 3 check; the kernel op consumes the flat 2D view.
17651765
num_tokens = q_proj.shape[0]
17661766
rope_dim = self.qk_head_dim - self.kv_lora_rank
17671767
quant_q_buffer = q_proj.new_empty(
17681768
(num_tokens, self.num_heads_tp * self.qk_head_dim),
17691769
dtype=torch.float8_e4m3fn)
1770-
q_pe = q_proj.new_empty((num_tokens, self.num_heads_tp * rope_dim))
1770+
q_pe = q_proj.new_empty((num_tokens, self.num_heads_tp, rope_dim))
17711771
torch.ops.trtllm.deepseek_v4_q_norm_fused_fp8(
17721772
q_proj,
17731773
quant_q_buffer,
1774-
q_pe,
1774+
q_pe.view(num_tokens, self.num_heads_tp * rope_dim),
17751775
self.num_heads_tp,
17761776
self.qk_head_dim,
1777-
self.kv_lora_rank, # nope_dim
1777+
self.kv_lora_rank,
17781778
float(self.q_b_layernorm.variance_epsilon),
17791779
self._quant_scale_qkv,
17801780
)

tests/integration/test_lists/test-db/l0_b200_ds.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ l0_b200_ds:
2525
- unittest/_torch/attention/sparse/deepseek_v4/test_compressor_kernel.py TIMEOUT (90)
2626
- unittest/_torch/attention/sparse/deepseek_v4/test_compressor_module.py TIMEOUT (90)
2727
- unittest/_torch/attention/sparse/deepseek_v4/test_compressor_tf32.py TIMEOUT (15)
28+
- unittest/_torch/custom_ops/test_deepseek_v4_q_norm.py TIMEOUT (15)
2829
# ------------- Disaggregated transfer component tests (single GPU) ---------------
2930
- unittest/disaggregated/test_agent.py
3031
- unittest/disaggregated/test_agent_multi_backends.py

tests/unittest/_torch/custom_ops/test_deepseek_v4_q_norm.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,42 @@ def test_deepseek_v4_q_norm_fused_fp8_zero_rows():
168168
assert q_pe.shape == (0, num_heads * rope_dim)
169169

170170

171+
@pytest.mark.parametrize("num_tokens", [1, 7, 129])
172+
def test_deepseek_v4_q_b_layernorm_fused_fp8_returns_3d_q_pe(num_tokens):
173+
"""Lock down the q_pe dim==3 contract expected by thop.attention's
174+
sparse-MLA context branch (TORCH_CHECK(q_pe->dim() == 3))."""
175+
import types
176+
from types import SimpleNamespace
177+
178+
from tensorrt_llm._torch.modules.attention import MLA
179+
180+
num_heads = 16
181+
qk_head_dim = 512
182+
kv_lora_rank = 448
183+
rope_dim = qk_head_dim - kv_lora_rank
184+
stub = SimpleNamespace(
185+
num_heads_tp=num_heads,
186+
qk_head_dim=qk_head_dim,
187+
kv_lora_rank=kv_lora_rank,
188+
q_b_layernorm=SimpleNamespace(variance_epsilon=1e-6),
189+
)
190+
fused = types.MethodType(MLA._deepseek_v4_q_b_layernorm_fused_fp8, stub)
191+
q_proj = torch.randn(
192+
num_tokens, num_heads * qk_head_dim, dtype=torch.bfloat16, device="cuda"
193+
).contiguous()
194+
195+
placeholder_q, quant_q_buffer, q_pe, scale = fused(q_proj)
196+
197+
assert q_pe.shape == (num_tokens, num_heads, rope_dim)
198+
assert q_pe.stride(2) == 1
199+
assert q_pe.is_contiguous()
200+
assert quant_q_buffer.shape == (num_tokens, num_heads * qk_head_dim)
201+
assert quant_q_buffer.dtype == torch.float8_e4m3fn
202+
assert placeholder_q.data_ptr() == q_proj.data_ptr()
203+
assert scale.shape == (1,) and scale.dtype == torch.float32
204+
assert float(scale.item()) == 1.0
205+
206+
171207
@pytest.mark.parametrize("num_tokens", [1, 7, 129])
172208
@pytest.mark.parametrize("num_heads", [1, 16, 128])
173209
def test_deepseek_v4_q_norm_fused_fp8_interleaved_layout(num_tokens, num_heads):

0 commit comments

Comments
 (0)