fix(debug): move debug_dump out of h20_ops so other platforms can import it

The dump hooks live in five platform-neutral files -- `sampler.py`, `mlp.py`, `deepseek.py`,
`decoder_layer.py`, `model_runner.py` -- and all of them imported
`deepinfer.h20_ops.debug_dump`. That is wrong on every platform except SM90: `h20_ops/__init__.py`
calls `extend_import_patches(override=True, ...)` at module scope, so importing it from shared code
installs the SM90 import shims globally. On an SM100 machine that replaces
`flash_mla.decode_mla_mqa_sparse`, `flash_mla.prefill_attn_varlen_sparse` and
`deep_select.interface.topk` with the Hopper implementations, and on NPU it would do the same
before the Ascend shims get a chance to matter.

`debug_dump` itself has nothing platform-specific in it -- `os`, `pathlib`, `numpy`, `torch` --
so it moves to `deepinfer/debug_dump.py` and the five imports follow. Verified that importing it
no longer pulls `h20_ops` into `sys.modules`, and re-ran the end-to-end check on H20: same output
token for token, `[17607, 2793, 3139, 666, 6127, 666, 320, 1]`.

This bug is already in the open PR, so it needs to land before that PR is worth reviewing further.
This commit is contained in:
loopyt 2026-10-21 22:37:49 +08:00
parent 0f181be5b9
commit 74ba468e76
7 changed files with 31 additions and 8 deletions

View File

@ -366,12 +366,35 @@ prefill 选中了正确的 token,误差只把 margin 压缩了 12 倍。但端
- `scripts/h20_kv_roundtrip.py`:KV cache 闭环 round-trip(不依赖 ref)
- `scripts/h20_index_decode_check.py`:`_decode_p_sum_sm90` 的独立数值对照
## P5 logprob 异常
## P5 logprob 异常(已排查,未修,非阻塞)
当前 8 个 token 的 `token_logprobs` 全是 `0.0`(概率=1),不正常。
- [ ] P5.1 确认是采样器 bug 还是 logits 极端(打印 logits 的 max/median)
- [ ] P5.2 检查 `DEEPINFER_SAMPLER_FORCE_TOPK=4096` 与 logprob 回填的关系
### 已排除(约 20 分钟静态排查 + 单测)
| 嫌疑 | 结论 |
|---|---|
| `map_lookup` kernel | 无罪。单测 6 passed,`by_key` + float32 + `force_topk=4096` 全覆盖,与 `map_lookup_ref` 逐元素相等 |
| sampler 全部 kernel | 无罪。`sampler.py -m "not benchmark"` → **74 passed / 0 failed** |
| `SampledInfo.from_reqcnt` 的 `torch.zeros` | 死代码,全仓库无调用点;`update(is_final, candidate)` 也无调用点 |
| sampler→engine 字段传递 | 直通,`llm_engine.py:747` 原样传 `output.token_logprobs` |
**一个反向线索**:`map_lookup` 里 `out = torch.empty`,键未命中时本应写 `-inf` 而**不是 0**。
所以 0.0 更像「上层根本没把值带下来」,而不是「查表查空了」。
### 剩余候选与判定路径
- `process_sampling` 返回的 `logprobs` 本身为 0(`fused_sample` 的 logprob 输出路径;
现有单测只覆盖 kernel 本身,没有覆盖「整个 forward 的 logprob 输出」)
- `build_request_outputs` 里逐 token 对象的属性回填
判定只需跑 1 次整机(~5 min):在 sampler 里打印 `logprobs.max()` 与 `token_logprobs_cur`。
sampler 层就是 0 → 定位在 `fused_sample`;sampler 层正常 → 定位在 output 回填。
### 为什么留着不修
不影响推理正确性,只影响 logprob 字段的可用性(AIME 打分、perplexity 这类评估用途)。
预估典型 1 h、最坏 2 h(若牵涉 MTP 异步 logprob 回填),与本次 SM90 支持的目标无关。
---

View File

@ -11,8 +11,8 @@ import torch
import torch.nn as nn
from deep_select.interface import topk
from deepinfer import debug_dump as _debug_dump
from deepinfer import envs
from deepinfer.h20_ops import debug_dump as _debug_dump
from deepinfer.logger import init_logger
from deepinfer.model_executor.input_metadata import InputMetadata
from deepinfer.model_executor.layers.mtp_info_pool import MTPInfoPool

View File

@ -5,7 +5,7 @@ import torch
from torch import nn
from deepinfer import AttrDict, envs
from deepinfer.h20_ops import debug_dump as _debug_dump
from deepinfer import debug_dump as _debug_dump
from deepinfer.logger import init_logger
from deepinfer.model_executor.input_metadata import InputMetadata
from deepinfer.model_executor.input_metadata.yoco import YocoMetadataMixin

View File

@ -9,8 +9,8 @@ import torch
from torch import nn
from deepinfer import AttrDict, envs
from deepinfer import debug_dump as _debug_dump
from deepinfer.engine.engine_type import EngineType
from deepinfer.h20_ops import debug_dump as _debug_dump
from deepinfer.logger import init_logger
from deepinfer.model_executor import eplb
from deepinfer.model_executor.input_metadata import InputMetadata

View File

@ -21,8 +21,8 @@ from tile_kernels.quant import swiglu_forward_and_per_token_cast
from torch import nn
from deepinfer import PLATFORM, AttrDict, envs
from deepinfer import debug_dump as _debug_dump
from deepinfer.engine.engine_type import EngineType
from deepinfer.h20_ops import debug_dump as _debug_dump
from deepinfer.logger import init_logger
from deepinfer.model_executor import eplb
from deepinfer.model_executor.input_metadata import InputMetadata

View File

@ -11,11 +11,11 @@ import numpy as np
import torch
import torch.distributed as dist
from deepinfer import debug_dump as _debug_dump
from deepinfer import envs
from deepinfer._C.engine import prepare_sampler_inputs, update_prompt_logprobs # pyright: ignore[reportMissingModuleSource]
from deepinfer.config import CacheConfig, ModelConfig, ParallelConfig, SchedulerConfig
from deepinfer.engine.engine_type import EngineType
from deepinfer.h20_ops import debug_dump as _debug_dump
from deepinfer.logger import init_logger
from deepinfer.model_executor.input_metadata import InputMetadata
from deepinfer.model_executor.layers.mtp_info_pool import get_nextn_pad_token_ids