开源llama.cpp Releases·原文 2026年10月5日

llama.cpp b11412修复k-pool模型解码时图重分配问题

该版本针对qwen4exp与glm5-next两个k-pool模型,在llama_memory_seq_cp共享单元格等场景下会触发解码期重新预留、进而在GGML_SCHED_DEBUG_REALLOC=1 时中止的问题,改为始终对池化键执行scatter+gather,并仅用上下文常量决定gather形状。

AI解读:修复由PR #29958 提出。两个k-pool模型会构建依赖预留阶段无法获知的状态的图结构:qwen4exp依赖inp->cache_safe(当llama_memory_seq_cp共享单元格时变为false,例如batched-bench -pps),QSA层从scatter+gather换成fill+concat并丢掉new_pool_rep叶节点,解码图比预留图少 12 个节点;glm5-next依赖gather = n_tokens n_sel,TG解码构建 7564 节点的gather形状,而最后一次预留(PP)是 7762 节点的密集形状。

两种不匹配都会迫使解码期重新预留,丢弃最坏情况尺寸并固化当前状态,下一次状态增长(n_pool、n_kv、n_new)在图层大小不变时需要更多空间,从而在GGML_SCHED_DEBUG_REALLOC=1 下中止。

修复方式:始终对池化键执行scatter+gather,并仅从上下文常量选取gather形状(n_ubatch约束每个ubatch,top_k + kpool - 1约束n_sel)。这样同一上下文的每个图共享同一形状,预留即可覆盖;作者称在 2.5k和 16k上下文下密集路径比gather路径更快。

该PR同时移除了未使用的k-pool cache_safe图API:图不再依赖cache_safe分支,get_kpool_cache_safe() 与条件new_pool_rep无读取方,set_input_kpool现在要求scatter目标。布局与状态标志保留,仍决定共享单元格的布局须重新池化哪些池。

新增共享序列图预留回归测试:将提示解码到seq 0,通过llama_memory_seq_cp与seq 1共享单元格,再继续解码两个序列。在 2220411ec1之前的两个k-pool模型上,该测试会中止;kimi-linear与minimax-01被跳过,因其以n_seqs=1 预留最终pp图。

另修复CUDA侧ggml_cuda_match_moe_weighted_reduction拒绝零行张量的问题:无输出的ubatch会使最后一层行数变为零,graph_optimize丢掉其alloc依赖,调度器图比预留图少一个节点,随后在GGML_SCHED_DEBUG_REALLOC=1 下中止。

llama.cpp发布b11412版本,修复k-pool模型在解码时发生非预期图重分配的问题(PR #29958)。

qwen4exp与glm5-next为何会在解码时重新预留

提交信息称,两个k-pool模型构建的图形状依赖全上下文预留阶段无法知道的状态。qwen4exp分支依赖inp->cache_safe,一旦llama_memory_seq_cp共享单元格(例如batched-bench -pps)就变为false:QSA层把scatter+gather换成fill+concat,并丢掉new_pool_rep叶节点,使解码图比预留图少 12 个节点。

glm5-next分支依赖gather = n_tokens n_sel,TG解码构建gather形状(7564 个节点),而最后一次预留即PP预留是密集形状(7762 个节点)。提交说明写道,任一不匹配都会迫使解码期重新预留,丢弃最坏情况尺寸并固化当前状态,下一次状态增长(n_pool、n_kv、n_new)在图层大小不变时需要更多空间,从而在GGML_SCHED_DEBUG_REALLOC=1 下中止。

  • 复现命令:GGML_SCHED_DEBUG_REALLOC=1 ./bin/llama-batched-bench -hf ggml-org/GLM-5.3-Flash-GGUF:Q2_K -npp 2500 -ntg 32 -npl 1,2 -c 32768 -pps -kvu
  • qwen4exp解码图比预留图少 12 个节点
  • glm5-next的TG解码为 7564 节点gather形状,PP预留为 7762 节点密集形状

修复方式与作者给出的性能观察

修复改为始终对池化键执行scatter+gather,并仅从上下文常量选取gather:n_ubatch约束每个ubatch,top_k + kpool - 1约束n_sel。提交信息称,同一上下文的每个图由此共享同一形状,预留即可覆盖。

作者在提交信息中表示,在 2.5k和 16k上下文下,密集路径测得比gather路径更快。

  • 始终scatter+gather池化键
  • gather由n_ubatch与top_k + kpool - 1等上下文常量决定
  • 作者称 2.5k和 16k上下文下密集路径更快

被移除的API与新增回归测试

该PR还移除了未使用的k-pool cache_safe图API:图不再依赖cache_safe分支,get_kpool_cache_safe() 与条件new_pool_rep已无读取方,两个模型始终传入scatter目标,set_input_kpool现在要求该目标而非仅优先使用。kpool_build_sizes() 中的cache_safe副本也被删除;布局与状态标志自身保留,仍决定带共享单元格的布局必须重新池化哪些池。

新增的共享序列图预留回归测试将提示解码到seq 0,通过llama_memory_seq_cp与seq 1共享单元格(即llama-batched-bench对 -pps所做的操作),然后继续解码两个序列。提交信息称,该测试在 2220411ec1之前的两个k-pool模型上都会中止;kimi-linear与minimax-01被跳过,因为它们以n_seqs = 1 预留最终pp图,多序列图各自布局不同并按设计重新预留。

  • 移除get_kpool_cache_safe() 与条件new_pool_rep
  • set_input_kpool现在要求scatter目标
  • 回归测试在 2220411ec1之前的两个k-pool模型上中止
  • kimi-linear与minimax-01因以n_seqs = 1 预留最终pp图而被跳过

CUDA零行张量与测试链接的附带修复

CUDA侧,ggml_cuda_match_moe_weighted_reduction此前拒绝零行张量。没有输出的ubatch会通过inp_out_ids把最后一层缩小到零行,graph_optimize因此丢掉其alloc依赖,调度器图比预留图少一个节点;调度器随后按该ubatch的尺寸重新预留,下一个节点数相同但张量更大的ubatch在GGML_SCHED_DEBUG_REALLOC=1 下中止。提交信息称计算循环在尝试任何融合前已跳过空节点,因此该守卫只让alloc依赖取决于行数。

测试构建方面,共享序列用例调用llm_arch_from_string,而libllama未通过LLAMA_API导出该符号,导致Windows共享库下test-recurrent-state-rollback链接失败;其构建现位于NOT WIN32 OR NOT BUILD_SHARED_LIBS块中。共享序列预留测试对kimi-linear与minimax-01的跳过也改成了直接比较general.architecture字符串,使该测试在所有平台可构建。

  • 零行张量因inp_out_ids使调度器图少一个节点
  • 共享序列测试改用general.architecture字符串比较,恢复跨平台构建
  • test-recurrent-state-rollback移至NOT WIN32 OR NOT BUILD_SHARED_LIBS块

信息来源

llama.cpp Releases原始来源