讳疾忌医丶头像
关注

硬核 C++:拆解 ggml_tensor,看 llama.cpp 如何用两个数组做尽零拷贝算子

几年前带一个刚转来做推理的新人上手 llama.cpp,他做的第一件事是给一个几百兆的权重矩阵做转置,然后打印耗时。他盯着屏幕愣了半天,跑过来问我:转置这么大一个矩阵,耗时那栏怎么快得像什么都没发生,难道是我把计时代码写岔了?

我让他先按住计时器。我说你再写一段 kernel,把转置后的矩阵按行读出来求个和,看看结果对不对。他跑完回来,脸更绿了:和是错的,而且错得毫无规律——每一行读出来的数字,像是从矩阵里随机捞的。

这两件事其实是同一件事。转置之所以快得像什么都没做,是因为 ggml 根本就不搬数据;而 kernel 读出来是乱的,是因为它按“数据是连续排布的”这个假设去算地址,可转置之后这个假设已经不成立了。这两句话背后,藏着 ggml——也就是 llama.cpp 的底层张量库——整个 Tensor 抽象的核心:一个张量,是一块内存,加一张描述怎么读这块内存的说明书。转置改的只是说明书。

这篇文章就顺着这张说明书往下拆。我们会从 ggml/include/ggml.h 里那个巴掌大的 struct ggml_tensor 结构体开始,看清 ne[]nb[] 这两个数组怎么用一次乘法把逻辑坐标变成字节地址;再看行主序和“连续”到底指什么,为什么转置、permute、view 能凭空造出一个不连续的张量;最后拆开 ggml_view_* 这一族零拷贝切片,看清它省下的拷贝,是用什么代价换来的。读完你应该能自己判断任意一个 tensor 连不连续,能看懂 ggml 里那些满是 nb0nb1 的 kerne

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/weixin_45715405/article/details/164375610

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--