llama.cpp 使用 GGUF 模型进行推理流程。code aspect

1. 模型加载

加载 GGUF 文件,解析权重和配置

将权重加载到内存(支持内存映射 mmap 以减少内存占用)。

初始化上下文(llama_context),包括 KV 缓存(用于加速多轮对话)和计算图。

llama.cpp 文件中:

llama_model *model = llama_model_load_from_file(model_path, params);
llama_context * lctx = llama_init_from_model(model, cparams);

2. 预处理

将输入文本(prompt)通过分词器(tokenizer)转换为 token ID 序列。分词器信息通常存储在 GGUF 文件中,llama.cpp 使用它将文本编码为输入向量。

llama.cpp 中

std::vector<llama_token> tokens = llama_tokenize(model, prompt, true);

3. 推理 pipline

llama.cpp 构建了一个推理 pipeline,基于 GGUF 文件中的配置,首先执行 Transformer 的前向传播。包括:

  1. 嵌入层:将 token ID 转换为嵌入向量。

  2. Transformer 层:循环执行多层 Transformer 模块,包括:

    • embedding ?
    • Multi-Head Attention :计算查询、键、值并应用注意力机制。
    • 层归一化(Layer Normalization):归一化中间结果。
    • 前馈网络(Feed-Forward Network):应用全连接层。
    • 残差连接(Residual Connections):确保信息流动。
  3. 输出层:将最后一层的输出转换为 logits(对下一个 token 的概率分布)。

在构建Graph时,就已经添加了 kv-cache 图节点,存储注意力机制的中间结果,加速多轮推理。

然后通过采样chain(如贪婪采样、Top-K、Top-P)从 logits 中选择下一个 token。

最后将生成的 token 序列通过分词器解码为文本

比如当我执行 llama-cli 时, 就会体现上述 pipline 。

上述推理 pipline 的组件

  • 模型加载器:解析 GGUF 文件,提取权重和配置。

  • 分词器:将输入文本转换为 token,并将输出 token 转换回文本。

  • 计算图:基于 GGML 库,构建 Transformer 的计算图(包括注意力、前馈网络等)。

  • 硬件加速模块:根据硬件(CPU、GPU、ARM)选择优化的计算内核(如 SIMD、CUDA、Metal)。

  • KV 缓存管理:存储注意力机制的键值对,加速多轮推理。

  • 采样模块:从 logits 中选择下一个 token,支持多种采样策略。

  • 工具接口:通过 llama-cli 或 llama-server 提供用户交互(命令行或 HTTP API)。

构建 pipline 过程

  • 加载配置:从 GGUF 文件读取模型参数(层数、注意力头数、隐藏维度等)。

  • 初始化计算图:根据配置,分配内存并构建 Transformer 的计算流程(通过 GGML 的操作符,如矩阵乘法、加法等)。

  • 硬件适配:根据运行时环境(CPU/GPU),选择合适的计算内核。

  • 推理循环:按 token 逐一执行前向传播、采样和输出。

Entrys

llama.cpp 项目通过其提供的各种工具( llama-clillama-serverllama-quantize 等)作为 entry point 。entry 通过调用核心的推理逻辑和相关组件来实现功能

其中最小的 entry 就是 llama-simple & llama-chat。阅读这两个应用。

KAQ:构建 Transformer 的计算图,是如何体现的

这里所谓的动态构建其实是,llama.cpp 事先在 code 中编码了常见的几乎所有开源的模型架构。详见 llama-model.cpp 文件。共有 74 个 LLMs 结构,Grok…

KAQ:实际计算中如何选择计算 kernels

KAQ:KV 缓存管理,是如何体现的

详见后续