开源llama.cpp Releases·原文 2026年9月28日

llama.cpp b11224修复Vulkan后端读取KV缓存切片时算错结果的问题

在mul_mat等算子原地读取带步长的KV缓存视图时,Vulkan后端此前把ne00*ne01当作批次步长,导致第一个head之后的注意力读出错误行;b11224改为从nb[2] 取步长,并修正了A/B绑定的内存范围。

llama.cpp发布构建b11224,修复Vulkan后端在mul_mat读取较大缓存切片时返回错误结果的问题(PR #28956)。

问题根源是批次步长的计算:一个dim01连续张量仍可能是视图,其各批次之间的实际间隔大于ne[1] 行,KV缓存的前几行就是这种情况。mat-vec和matrix两条路径都原地读取这类张量,却把ne00*ne01当作批次步长,导致第一个head之后的每个head都读到错误的行;src1存在同样问题。

步长改从nb[2] 读取

修复后,只要张量是原地使用,批次步长就来自nb[2];对连续张量而言该值不变。提交说明提到,原地张量的批次步长按nb[2] / type_size * block_size计算,这在nb[2] 带填充且不是nb[1] 整数倍时同样成立。

test-backend-ops的test_mul_mat新增m_v参数,表示a在内存中的行数,并加入两个按解码器自注意力缓存形状构造的用例;另有一个带填充批次步长的test_mul_mat用例覆盖上述计算。mul_mat_id的原地src0和src1也改用与mul_mat相同的辅助函数读取批次步长,test_mul_mat_id增加了m_v参数和一个专家视图跨步行数多于其使用行数的用例。

  • mul_mat_vec_id的单token路径此前把ne00*ne01当作A的批次步长,跨步的专家视图会读错行;现在与其余三条路径一样从ggml_vk_batch_stride取步长,src1遵循同一规则。
  • test_mul_mat_id增加了一个在跨步视图上跑单token的用例。

A/B内存绑定范围两次调整

第一次提交中,matrix路径用“元素数乘类型大小”把src0和src1绑定给着色器,这个范围在跨步视图的批次之前就结束了;启用了边界访问的管线越界后会读到零,于是同一种mat-vec路径已能处理的视图,在Intel以及不带coopmat2的NVIDIA上得到错误结果。改为原地读取时从ggml_nbytes取范围。

根据jeffbolznv的评审意见,matrix路径的原地A和B改用ggml_vk_subbuffer绑定,覆盖到缓冲区末尾,这样跨步视图无需计算范围就落在边界内。但随后发现mul_mm的量化A加载没有行边界,依赖描述符范围在部分tile的最后一行之后读零;把A和B绑到缓冲区末尾会让这些tile读到上一个节点的残留数据,并在不带coopmat2的NVIDIA上挂起NVFP4的mul_mm。现在范围取原地读取张量的跨步范围,否则取暂存大小。

信息来源

llama.cpp Releases原始来源