Eval bug: std::out_of_range in load_tensors when a device reports 0 free bytes (NaN tensor split)

这个报错通常发生在 llama.cpp 加载模型(尤其是加载目标模型后再加载投机解码 draft 模型)时,某块 CUDA 设备通过 cudaMemGetInfo 报告 free == 0 ,导致 tensor split 归一化时出现除零、产生 NaN,最终把层分配到不存在的设备索引上。优先排查显

快速结论:这个报错通常发生在 llama.cpp 加载模型(尤其是加载目标模型后再加载投机解码 draft 模型)时,某块 CUDA 设备通过 cudaMemGetInfo 报告 free == 0,导致 tensor split 归一化时出现除零、产生 NaN,最终把层分配到不存在的设备索引上。优先排查显存占用与 tensor split 计算逻辑。

适用环境:llama.cpp(llama-server,version 0.1.2-dev,build 1,commit 9d77fa1,GNU 15.2.0);Linux x86_64(WSL2,Ubuntu on Windows);GGML backend 为 CUDA;硬件为 NVIDIA GeForce RTX 4070 SUPER(12 GB),驱动 596.49,CUDA 13.3。

最快修复方案:Issue 讨论中已验证的修复是在 src/llama-model.cpp 的 load_tensors 中给归一化加零保护并回退到均分,对应提交 f6342de:

-        splits[i] /= split_sum;
+        splits[i] = split_sum != 0.0f ? splits[i] / split_sum : float(i + 1) / n_devices();

注意事项:该修复解决的是除零导致的 NaN 和越界崩溃,并不解决“显存实际不足”本身;即使按均分正常分配,显存不足时仍可能返回内存分配错误。此外作者观察到 nvidia-smi 报告约 1.6 GiB 空闲,而进程内 cudaMemGetInfo 返回 0,这部分怀疑是 WSL2 的怪癖,未在 Issue 中确认。

问题场景

用户在 llama.cpp 中先用 -ngl 99 加载一个接近占满 12 GB 显存的目标模型(例如 Qwen3.8-27B UD-Q2_K_XL,约 9.8 GB),然后在同一进程里继续加载投机解码 draft 模型(-md <draft.gguf> --spec-type <draft-type> -ngld 99)。draft 模型加载阶段没有返回常规的显存分配失败,而是抛出 vector::_M_range_check 并中止。

报错原文

llama_model_load: error loading model: vector::_M_range_check: __n (which is 1) >= this->size() (which is 1)

PROBE mem: dev[0]=CUDA0 free=0 MiB total=12281 MiB
PROBE split: il=0 i_gpu_start=0 act_gpu_layers=6 n_gpu_layers=99 n_layer_all=5 n_devices=1 layer_gpu=1 val=0.000000 splits[0]=-nan

_ZSt24__throw_out_of_range_fmtPKcz
libllama.so.0(+0xc413d)  -> llama_model_base::load_tensors(llama_model_loader&) [clone .cold]
libllama.so.0(+0xd7ae5)  -> llama_model_load(...)
libllama.so.0(+0xd8c12)  -> llama_model_load_from_file_impl(...)
libllama.so.0(llama_model_load_from_file+0xc8)
libllama-common.so.0(common_speculative_init_result::common_speculative_init_result(...))
libllama-server-impl.so(server_context_impl::load_model(common_params&))

原因分析

根因在 llama_model_base::load_tensors(src/llama-model.cpp)。当用户未设置 tensor_split 时,splits[i] 保存的是每块设备的空闲显存。归一化时先累加得到 split_sum,再执行 splits[i] /= split_sum;如果每块设备都报告 0 空闲字节,split_sum 为 0,就变成 0.0f / 0.0f,所有 split 点变成 NaN。

随后 std::upper_bound 在 NaN 序列上返回 end(),使 layer_gpu 等于 n_devices(),接着 devices.at(layer_gpu) 抛出 std::out_of_range,被包装成用户看到的 vector::_M_range_check 消息,容易误判为 GGUF 损坏。

代码中已有的回退分支只覆盖 free == 0 且 total == 0 的设备:

if (free == 0 && total == 0) {
    ggml_backend_dev_memory(cpu_dev, &free, &total);
}

本案例中 total 为 12281 MiB、仅 free 为 0,因此不会触发回退。作者指出同一路径在任何“设备报告 0 空闲字节”的后端上都可能复现;“cudaMemGetInfo 返回 0 而 nvidia-smi 显示约 1.6 GiB 空闲”可能归因于 WSL2,但崩溃本身来自未加保护的除法。

环境排查

  • 确认 llama.cpp 版本与 commit:llama-server --version,本 Issue 为 version 0.1.2-dev,build 1,commit 9d77fa1。
  • 确认是否使用 CUDA backend,以及编译所用工具链(本 Issue 为 GNU 15.2.0 for Linux x86_64)。
  • 确认 GPU 型号、驱动与 CUDA 版本:RTX 4070 SUPER(12 GB)、驱动 596.49、CUDA 13.3。
  • 确认运行环境是否 WSL2(Ubuntu on Windows),WSL2 下 cudaMemGetInfo 的可用显存报告可能与 nvidia-smi 不一致。
  • 确认是否显式设置了 tensor_split;未设置时该路径才会用设备空闲显存作为 split 依据。
  • 确认是否在加载目标模型后于同进程加载 draft 模型(-md / --spec-type / -ngld)。
  • 确认出现 free=0 MiB 的设备及其 total 是否非 0(可用 Issue 中的 PROBE 输出方式观察)。

解决步骤

  1. 先确认崩溃点信息:看到 vector::_M_range_check 时不要直接判定 GGUF 损坏,检查是否有设备 free=0 MiB 且 total 非 0。
  2. 可优先尝试 Issue 中验证的补丁:在 src/llama-model.cpp 的 load_tensors 中,将 splits[i] /= split_sum; 替换为带零保护的均分逻辑,或直接应用提交 f6342de。
  3. 重新编译 llama.cpp 后再复现同样的加载流程,观察是否不再出现 NaN split 与越界异常。
  4. 如果补丁后行为变为正常的内存分配失败提示,说明除零问题已解决,需要按显存不足的方向处理(例如减少 -ngl / -ngld、先卸载或减少目标模型占用、改用更小的量化)。
  5. 若仍怀疑 WSL2 下显存报告异常,可在 WSL2 环境对比 nvidia-smi 与进程内 cudaMemGetInfo 的空闲值,判断是否需要调整运行环境;该点 Issue 中未给出确定结论。

验证方法

用与复现相同的参数再次加载目标模型与 draft 模型。若不再抛出 vector::_M_range_check / std::out_of_range,且 split 点不再为 NaN(例如 PROBE 输出中 splits[0] 不再是 -nan),则除零引发的越界崩溃已修复。此时如果显存确实不足,应看到明确的内存分配失败信息,而非 out_of_range 异常。

参考来源

ggml-org/llama.cpp #27440

fix commit f6342de11036b9e8f27b9f42c4e96d7331926f75

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 29122

发表回复

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