llama.cpp:推理原理与 C API

llama.cpp:推理原理与 C API

「本系列第 6/17 章」。上一章已经能编出 llama-cli / llama-server,并准备好一份 GGUF。本章把「输入文本变成下一段文本」收成一条 C API 心智模型:对外只认 include/llama.h,对内则是只读权重加一份不可共享的会话状态。

1. 自回归:每次只多一个 token

语言模型推理是自回归的:给定前缀,预测下一个 token,追加后再预测。用户看到的「逐字往外吐」,就是这个循环。Causal Attention 规定位置 i 只能看见 ≤ i;训练时可以对整段序列并行算 loss,推理时通常只要最后一个位置的 logits。没有 KV cache 时,每一步都要把前文重算一遍,复杂度按序列长度平方涨;有 cache 之后,decode 只算新 token 的 K/V,并读取历史。

2. Prefill 与 Decode 是同一扇门

工程上常把推理分成两段,但 llama.cpp 没有两套入口。Prompt 一次性送进模型叫 prefill:token 多、可并行、主要职责是填满 KV,通常不为中间位置采样。之后每次只送一个新 token,叫 decode:计算量小、延迟敏感,每步调用一次 llama_sampler_sample

两端都调用 llama_decode。区别只在 llama_batch 的大小,以及 logits 标志。llama_batch_allocr 默认只给最后一个 token 打开 logits。把 prefill 理解成「第一次 decode」,后面的循环就顺了。首 token 延迟主要由 prefill 决定,用户感知的吐字速度才是 decode。

3. 两个对象,两种线程语义

可以把对象关系记成:llama_model 像只读程序,llama_context 像进程,llama_batch 是本次输入包。

llama_model 装着权重、词表和架构,加载后只读,可被多个会话共享。一份 GGUF 不必为每个用户复制一遍。llama_context 装着一次推理的运行时:llama_memory_tggml_backend_sched、logits / embedding 缓冲。llama_context 不是线程安全的。多线程服务应当一线程一份 context,或在外层串行化。llama_backend_init / llama_backend_free 同样不是线程安全的,进程里只做一次。

llama_decode 的返回值要当成控制流:

返回值 含义
0 成功
1 KV 已满,当前 batch 放不进去(可 defrag 后重试)
-1 参数错误
-2 内部错误(图分配或计算失败)
2 用户 abort

返回 1 时可以清序列、缩短上下文或增大 n_ctx;返回 -2 则应停止,不要继续采样。

4. 最小 C 循环

加载仍是两阶段:gguf_init_from_file(no_alloc=true)llama_model_loaderllama_model_create。对外则收成:

1
2
3
4
5
6
7
llama_backend_init();
llama_model * model = llama_model_load_from_file(path, llama_model_default_params());
llama_context * ctx = llama_init_from_model(model, llama_context_default_params());
/* tokenize → llama_decode(prefill) → sample → llama_decode(one token) → ... */
llama_free(ctx);
llama_model_free(model);
llama_backend_free();

对照 examples/simple/simple.cppllama_model_params 里最常改的是 n_gpu_layersuse_mmapsplit_modellama_context_params 里是 n_ctxn_batchn_ubatchn_seq_maxn_threadsflash_attn_typetype_k / type_v。采样不要手写 argmax 凑合:用 llama_sampler_chain_init 串 greedy / top_k / top_p / temp / penalties / grammar。Embedding 模型把 pooling_type 设成 LLAMA_POOLING_TYPE_MEAN,再读 llama_get_embeddings_seq。LoRA 走 llama_adapter_lora_init + llama_set_adapter_lora

KV 显存可以先按 2 × n_layer × n_ctx × n_head × head_dim × sizeof(dtype) 估算。7B、4096 上下文、FP16 的 K/V 往往就要 1–2 GB,这还没算权重。--cache-type-k q8_0-fa on 是降 KV 与算子开销的第一组旋钮。

下一章《llama.cpp:Decode、KV Memory 与 Graph 复用》会打开 llama_decode 的内部:batch 如何被切开,Memory 如何按架构选型,以及为何逐步生成可以复用同一张计算图。

文章互动

阅读 --

留言

0 条留言

正在加载留言…