RuntimeError: Triton Error [CUDA]: an illegal memory access was encountered`. Because of async error reporting, it surfaces in a later, unrelated kernel. In our case it was usually the first pre

当使用 --kv-cache-dtype int4_per_token_head 时,如果 reshape_and_cache_int4 送入 single_rht 的行数( num_tokens * num_kv_heads_per_rank )为奇数且达到约 1025 以上,Hadamard 变

快速结论:当使用 --kv-cache-dtype int4_per_token_head 时,如果 reshape_and_cache_int4 送入 single_rht 的行数(num_tokens * num_kv_heads_per_rank)为奇数且达到约 1025 以上,Hadamard 变换核会产生错误的 K/V 结果;如果越界读取命中未映射内存,就表现为 Triton 报错 CUDA illegal memory access。优先排查 KV cache 量化路径和奇数行数的 prefill 步。

适用环境:vLLM 0.30.0(pip wheel)、torch 2.13.0、triton 3.7.1;4x NVIDIA L4(sm_89),驱动 580.178.04,CUDA 13.0;--kv-cache-dtype int4_per_token_head,head_dim 256,每 TP rank 1 个 KV head(TP=2,DP=2)。另有用户在 RTX 4090(sm_89,驱动 580.95.05,CUDA 13.0,torch 2.14.1+cu132)复现到同类问题。

最快修复方案:暂无确认的一步修复方案。#63614 尚未合并;在修复落地前,可优先尝试避免产生奇数行数的 KV 缓存写入(例如调整 chunked prefill 使 num_tokens * num_kv_heads_per_rank 为偶数),或在无法规避时暂时不使用 int4_per_token_head。这些措施属于规避手段,不是根因修复。

注意事项:该错误是静默数据损坏,并非每次都会崩溃;是否崩溃取决于越界读取是否落在已映射内存上,冷启动崩溃概率随环境不同可从 0% 变到 85%。仅仅“能跑通”不能证明问题不存在,需要用数值比对验证。不要用 tests/kernels/quantization/test_hadacore.py 的既有参数判断正常,因为该测试只覆盖偶数 batch_size,无法命中此问题。

问题场景

用户在 vLLM 中启用了 INT4 per-token-head KV cache 量化(--kv-cache-dtype int4_per_token_head,head_dim 256)。写入 KV 缓存时,reshape_and_cache_int4 会先对 key/value 做随机 Hadamard 变换(single_rht → fast_hadamard_transform → ops.hadacore_transform)再量化。传入张量形状为 [num_tokens, num_kv_heads_per_rank, 256],因此 Hadamard 核实际看到 num_tokens * num_kv_heads_per_rank 行。

当这个行数为奇数时,变换结果有时完全错误:整个 batch 的变换值出现巨大数值(相对误差可达 ~1e36),而不是正确的 Hadamard 变换结果。当核读完输入之后继续读取的内存处于未映射状态时,引擎直接因非法内存访问退出。触发场景包括奇数长度的 prompt prefill、chunked-prefill 步骤叠加奇数个 decode 行,以及抢占后的重新计算。

报错原文

RuntimeError: Triton Error [CUDA]: an illegal memory access was encountered

由于 CUDA 错误异步上报,该报错常常出现在之后一个不相关的 kernel 中;在排查时表现为首次 prefill 阶段偶发崩溃。若在每个 module 之后加 torch.cuda.synchronize(),首个错误会定位到第一个 INT4-KV attention 层的 reshape_and_cache_int4 之后。

原因分析

最可能的原因在 Hadamard 变换核的 masked 路径。对 head_dim 256,run_fht(csrc/libtorch_stable/quantization/hadamard/hadacore/hadamard_transform_cuda.cu)在 numel > 256 时使用 chunks_per_warp_large = 2;当 num_chunks % (chunks_per_warp * warps_per_block) != 0 时,run_kernel 会启动 enable_mask = true 的变体,而这正好对应奇数行数的情形。目前尚未定位到 masked 路径内具体的出错读取指令。

实测证据支持“越界读取输入末尾”的判断,而不是确定性的算术错误:

  • 在 L4 上对 N=1 到 4352 的 [N, 1, 256] fp32 张量逐一与 float64 参考 (x * signs) @ H_256 比对,4335 个行数中有 1101 个错误,全部为奇数,偶数 N 全部正确。
  • 在 RTX 4090、master 0e5b2ba118 上独立复现,4352 个行数中 1352 个错误,同样全部为奇数;N=1025、1041、1537、2049、3001、4351 等出现 inf/nan/1e30+ 量级垃圾值,而约 771 以下的奇数行数正常。
  • 用 canary 填充输入周边内存后 canary 未被改写,说明核是在“读”越界而非“写”越界;失败的具体 N 集合会随张量后相邻内存内容变化。

CI 未发现该问题的原因:现有测试用偶数 batch_size([1, 32])和幂次 hidden_dim,根本无法产生奇数行数,更别说 ≥1025 的行数。

环境排查

  • 确认是否启用了 --kv-cache-dtype int4_per_token_head,以及 head_dim 是否为 256。
  • 确认 vLLM 版本(报告为 0.30.0)、torch(2.13.0)和 triton(3.7.1)版本;独立复现使用 torch 2.14.1+cu132,说明该问题不局限于单一 torch 版本。
  • 确认显卡架构是否为 sm_89(L4、RTX 4090 均可复现),以及驱动与 CUDA 版本(580.x / CUDA 13.0)。
  • 确认并行配置:TP、DP 大小,以及每个 TP rank 的 KV head 数;每 rank 1 个 KV head 时,行数就等于 token 数。
  • 检查 prefill 是否会出现奇数 token 数,或 chunked-prefill 加 decode 行后合计为奇数;确认 CUDA graph 的捕获尺寸是否为偶数(偶数的 decode 不受影响)。
  • 确认所测 vLLM 是否包含 #63614 的修复;该 PR 在报告关闭时仍处于未合并状态。

解决步骤

  1. 先用数值比对确认问题存在:按 Issue 给出的方法,对 N=1 起逐一构造 [N, 1, 256] fp32 张量调用 single_rht,与 float64 参考 (x * signs) @ H 比较相对误差;重点测试 N=1025、1041、1537、2049 这些已知失败点,并包含奇数 N。
  2. 若确认存在错误输出或偶发 illegal memory access,检查运行中是否出现奇数行数的 reshape_and_cache_int4 调用,尤其是 1025 以上的奇数行。
  3. 在缓解层面,可优先尝试让每次写入的行数保持偶数(调整 chunked prefill 的 chunk 大小或批组合方式),或在不影响业务的前提下暂时关闭 int4_per_token_head KV 量化。
  4. 跟踪 [PR #63614](https://github.com/vllm-project/vllm/pull/63614) 的合并状态;按维护者说明,该 PR 已覆盖 N ≥ 1025 的奇数行测试,并计划补充 1041、1537、2049 这几个边界尺寸。
  5. 修复合并后升级到包含修复的 vLLM 构建,不要仅凭“不再崩溃”判断已修复,需重复第 1 步的数值比对。

验证方法

对 1 到 4352 的所有 N(至少包含全部奇数 N 及 1025/1041/1537/2049 边界)运行 single_rht 与 float64 参考的比较,所有行数的相对误差都应落在正常数值精度范围内(不应出现 inf、nan 或 1e30 量级结果)。同时在真实推理中启用 int4_per_token_head,跑奇数长度 prompt prefill 与 chunked prefill 混合负载,并在 reshape_and_cache_int4 后加 torch.cuda.synchronize() 做严格检查,确认不再出现 illegal memory access,且输出与未量化参考模型一致。

参考来源

vllm-project/vllm #63514

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 32234

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注