ik_llama.cpp 中 Gemma3(纯文本)推理支持:图构建实现与注意力机制深度解析 📅 发布时间:2026/9/19 3:49:02 👁 浏览次数: ik_llama.cpp 中 Gemma3纯文本推理支持图构建实现与注意力机制深度解析【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp导读本文基于 ik_llama.cpp 仓库中Add Gemma3 support (text only)PR #276这一合并记录深入解析 Gemma3 纯文本推理在图构建层面的完整实现。文章以 PR 描述 为核心骨架结合仓库源码build_gemma3.cpp、llama-arch.cpp、llama-hparams.cpp 等展开重点讲解 Gemma3 架构特有的5-to-1 交错注意力Sliding Window Attention 与全局注意力交替、滑动窗口层的独立 RoPE 频率基准、以及注意力缩放系数差异等关键实现。读者读完可掌握 Gemma3 文本模型在 ik_llama.cpp 中从 GGUF 加载、超参解析到计算图构建的完整链路理解其与 Gemma2 的核心差异。一、PR 背景与工作范围1.1 PR 基本信息项目内容PR 编号#276作者ikawrakow项目维护者状态❌ Closed已关闭创建时间2025-03-21更新时间2025-03-22PR 描述极其精简Basically just the graph building. Conversion from safetensors needs to be done with upstream.基本只是图构建部分。从 safetensors 的转换需要借助上游完成。这句话界定了本次工作的明确边界本仓库负责的部分Gemma3 架构在 llama.cpp 推理侧的计算图graph构建即把 Gemma3 的权重张量组织成可执行的推理流程不负责的部分safetensors → GGUF 的模型转换脚本。转换需要借助上游 llama.cpp 的convert_hf_to_gguf.py完成该脚本在本仓库根目录下同样存在convert_hf_to_gguf.py但 Gemma3 的转换支持以上游版本为准。也就是说这是一次推理侧先行的架构适配先在本地图构建层吃下 Gemma3 权重转换管线随后补齐。1.2 从源码结构确认的 Gemma3 支持全貌虽然 PR 描述简短但当前仓库源码已经完整保留了 Gemma3 支持的全部痕迹可以从以下维度确认实现事实维度源码位置内容架构注册src/llama-arch.cpp{ LLM_ARCH_GEMMA3, gemma3 }将gemma3字符串映射到架构枚举架构枚举src/llama-arch.hLLM_ARCH_GEMMA3紧随LLM_ARCH_GEMMA、LLM_ARCH_GEMMA2之后超参解析src/llama-hparams.cppcase LLM_ARCH_GEMMA3:分支读取滑动窗口、RMS eps并设置注意力缩放张量加载src/llama-load-tensors.cppcase LLM_ARCH_GEMMA3: use_mmap_buffer create_gemma_tensors(tn, 3);复用 Gemma 系列张量创建逻辑图构建src/graphs/build_gemma3.cppllm_build_context::build_gemma3()完整的前向计算图图调度src/llama-build-context.cppcase LLM_ARCH_GEMMA3: result llm.build_gemma3();可以推断本 PR 的核心改动即build_gemma3()图构建函数而架构注册、超参解析等配套代码在后续迭代中持续完善当前仓库的 Gemma3 分支比 PR 提交时更完整例如n_swa_pattern的硬编码已抽象为超参。二、Gemma3 架构要点5-to-1 交错注意力2.1 与 Gemma2 的对比Gemma2 使用统一滑动窗口hparams.n_swa 4096为默认值见 llama-hparams.cpp所有层都受滑动窗口约束且采用 logit soft-capping。Gemma3 则引入了**5-to-1 interleaved attention5:1 交错注意力模式**每 5 层局部注意力sliding window attention, SWA后跟 1 层全局注意力。这在 build_gemma3.cpp 中有直接注释与实现// 5-to-1 interleaved attention // 5 layers of local attention followed by 1 layer of global attention static const int sliding_window_pattern 6;判定逻辑为for (int il 0; il n_layer; il) { const bool is_sliding (il 1) % sliding_window_pattern; ... }即第il层从 0 计数当(il 1) % 6 ! 0时是滑动窗口层(il 1) % 6 0时是全局层。注意在 llama-hparams.cpp 中hparams.n_swa_pattern 6被写入超参后续架构可通过 GGUF 元数据覆盖该模式。2.2 滑动窗口层的独立 RoPE 配置这是 Gemma3 实现的另一关键点。滑动窗口层与全局层在位置编码上使用不同的 RoPE 频率基准const float freq_base_l is_sliding ? 10000.0f : freq_base; const float freq_scale_l is_sliding ? 1.0f : freq_scale;对应 llama-hparams.cpp 中hparams.rope_freq_base_train_swa 10000.0f; hparams.rope_freq_scale_train_swa 1.0f;含义滑动窗口层在训练时使用freq_base 10000的 RoPE 配置而全局层沿用模型整体通常更长上下文优化的freq_base。这样局部层不需要为长上下文外推而修改频率——因为它本来只看窗口内的有限 token。同时build_gemma3()利用了本仓库的 RoPE 缓存机制cparams.rope_cache对滑动层与全局层分别构建缓存if (cparams.rope_cache (rope_type LLAMA_ROPE_TYPE_NEOX || rope_type LLAMA_ROPE_TYPE_NORM)) { rope_cache ggml_rope_cache(ctx0, inp_pos, nullptr, n_rot, n_rot, rope_type, n_ctx_orig, freq_base, freq_scale, ...); rope_cache_l ggml_rope_cache(ctx0, inp_pos, nullptr, n_rot, n_rot, rope_type, n_ctx_orig, 10000.0f, 1.0f, ...); }推理时按层选用auto rcache is_sliding ? rope_cache_l : rope_cache; Qcur ggml_rope_fast(ctx0, Qcur, rcache); Kcur ggml_rope_fast(ctx0, Kcur, rcache);非缓存路径则用ggml_rope_ext并传入freq_base_l / freq_scale_l。两种路径殊途同归。2.3 双 KQ Mask全局与滑动窗口由于存在两种注意力层计算图需要两个不同的 attention maskstruct ggml_tensor * KQ_mask build_inp_KQ_mask(true); struct ggml_tensor * KQ_mask_swa build_inp_KQ_mask_swa(true);每层根据is_sliding选用对应 maskbuild_gemma3.cppstruct ggml_tensor * KQ_mask_l is_sliding ? KQ_mask_swa : KQ_mask;并在 KV 注意力计算中传入滑动窗口大小cur llm_build_kv(ctx0, lctx, kv_self, gf, model.layers[il].wo, NULL, Kcur, Vcur, Qcur, KQ_mask_l, n_tokens, kv_head, n_kv, hparams.f_attention_scale, cb, il, nullptr, KQ_mask_l KQ_mask_swa ? hparams.n_swa : 0);build_inp_KQ_mask_swa的声明位于 src/llama-build-context.h它构造只允许当前 token 回溯n_swa个位置的因果 mask。三、build_gemma3() 计算图逐步拆解下面按 build_gemma3.cpp 的实际代码顺序逐段拆解图构建逻辑。3.1 输入嵌入与缩放inpL llm_build_inp_embd(ctx0, lctx, hparams, batch, model.tok_embd, cb); // important: do not normalize weights for raw embeddings input (i.e. encoded image embeddings) if (batch.token) { inpL ggml_scale(ctx0, inpL, sqrtf(n_embd)); cb(inpL, inp_scaled, -1); }关键注释点明了 Gemma 系列的设计词嵌入需要乘以sqrt(n_embd)缩放但若输入来自编码器如图像嵌入则不能缩放。本 PR 是text only纯文本支持batch.token路径即文本输入因此会执行缩放。这一行为与 src/graphs/build_gemma.cpp 中 Gemma/Gemma2 的处理一致——Gemma3 图构建直接复用了家族惯例。3.2 单层 Transformer 结构对每一层il计算图依次完成RMS 归一化 QKV 投影cur llm_build_norm(ctx0, inpL, hparams, model.layers[il].attn_norm, NULL, LLM_NORM_RMS, cb, il); auto [Qcur, Kcur, Vcur] llm_build_mul_mat_qkv(gf, cur, model.layers[il].wqkv, nullptr, model.layers[il].wqk, nullptr, model.layers[il].wq, nullptr, model.layers[il].wk, nullptr, model.layers[il].wv, nullptr, model.layers[il].attn_q_norm, model.layers[il].attn_k_norm, 0, il);llm_build_mul_mat_qkv是一个通用辅助函数会根据模型实际存在的权重融合的wqkv或分离的wq/wk/wv自动选择投影方式并处理 Q/K 的 RMS 归一化attn_q_norm、attn_k_normGemma 系列在注意力前对 Q、K 做 RMS norm这是其区别于 LLaMA 的显著特征之一。RoPE 位置编码按层选择 RoPE 缓存/频率见 2.2 节。KV 注意力选用全局或滑动窗口 mask 进入llm_build_kv。注意力后归一化 残差cur llm_build_norm(ctx0, cur, hparams, model.layers[il].attn_post_norm, NULL, LLM_NORM_RMS, cb, il); struct ggml_tensor * sa_out ggml_add(ctx0, cur, inpL);Gemma3 在注意力输出之后还有一个attn_post_norm这与 Gemma2 类似pre-norm 与 post-norm 双重归一化的sandwich结构。FFN含 post-normcur llm_build_ffn(ctx0, lctx, model.layers[il].ffn_norm, sa_out, model.layers[il].ffn_up, NULL, NULL, model.layers[il].ffn_gate, NULL, NULL, model.layers[il].ffn_down, NULL, NULL, NULL, LLM_FFN_GELU, LLM_FFN_PAR, cb, il); cur llm_build_norm(ctx0, cur, hparams, model.layers[il].ffn_post_norm, NULL, LLM_NORM_RMS, cb, -1); cur ggml_add(ctx0, cur, sa_out);激活函数为LLM_FFN_GELU并使用LLM_FFN_PARparallelFFN 与注意力并行共享输入布局同样带ffn_post_norm。随后lctx.cvec.apply_to应用上下文向量contrastive 控制向量。末层优化在最后一层il n_layer - 1用inp_out_ids提前裁剪掉未使用 token 的输出减少后续计算量build_gemma3.cpp。3.3 输出头cur llm_build_norm(ctx0, cur, hparams, model.output_norm, NULL, LLM_NORM_RMS, cb, -1); cur llm_build_lora_mm(lctx, ctx0, model.output, cur); ggml_build_forward_expand(gf, cur);最终经output_normRMS norm后用llm_build_lora_mm做 lm_head 投影该辅助函数支持 LoRA 适配器无 LoRA 时即普通矩阵乘最后ggml_build_forward_expand展开为完整前向图返回。3.4 图构建的注册入口在 src/llama-build-context.cppcase LLM_ARCH_GEMMA3: result llm.build_gemma3(); break;而 src/llama-build-context.h 声明了ggml_cgraph * build_gemma3();。整条链路架构枚举 → 图分发 → 图实现闭合。四、超参解析llama-hparams.cpp 中的 Gemma3 分支在 src/llama-hparams.cppLLM_ARCH_GEMMA3分支完成了以下工作case LLM_ARCH_GEMMA3: { hparams.n_swa_pattern 6; hparams.rope_freq_base_train_swa 10000.0f; hparams.rope_freq_scale_train_swa 1.0f; ml.get_key(LLM_KV_ATTENTION_SLIDING_WINDOW, hparams.n_swa); ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps); switch (hparams.n_layer) { case 26: model.type e_model::MODEL_2B; break; case 34: model.type e_model::MODEL_4B; break; case 48: model.type e_model::MODEL_12B; break; case 62: model.type e_model::MODEL_27B; break; default: model.type e_model::MODEL_UNKNOWN; } hparams.f_attention_scale model.type e_model::MODEL_27B ? 1.0f / std::sqrt(float(hparams.n_embd / hparams.n_head(0))) : 1.0f / std::sqrt(float(hparams.n_embd_head_k_full)); } break;各要点说明配置项说明n_swa_pattern 6交错注意力周期5 层局部 1 层全局rope_freq_base_train_swa 10000.0f滑动层训练期 RoPE 基准频率rope_freq_scale_train_swa 1.0f滑动层训练期频率缩放LLM_KV_ATTENTION_SLIDING_WINDOW从 GGUF 读取滑动窗口大小如 1024LLM_KV_ATTENTION_LAYERNORM_RMS_EPS读取 RMS 归一化 epsilon模型规格识别26 层 → 2B、34 层 → 4B、48 层 → 12B、62 层 → 27Bf_attention_scale注意力缩放系数27B 与其他尺寸不同4.1 注意力缩放系数的尺寸差异值得单独强调Gemma3 的注意力缩放系数不是统一公式27B 模型1 / sqrt(n_embd / n_head(0))即按每个头的维度n_embd / n_head缩放经典1/sqrt(d_k)风格其余尺寸2B/4B/12B1 / sqrt(n_embd_head_k_full)按完整 K 头维度缩放。这直接影响了llm_build_kv中hparams.f_attention_scale的取值是从 llama-hparams.cpp 源码可确认的实现事实。4.2 张量加载复用 create_gemma_tensors在 src/llama-load-tensors.cppcase LLM_ARCH_GEMMA3: use_mmap_buffer create_gemma_tensors(tn, 3); break;create_gemma_tensors(tn, 3)复用了 Gemma 系列的张量创建函数第三参数为版本号 3。Gemma2create_gemma_tensors(tn, 2)与 Gemmacreate_gemma_tensors(tn, 1)同样走此路径。这印证了 PR 描述中Basically just the graph building的边界张量加载层几乎零改动差异集中在图构建。五、从 PR 到当前仓库的演进附实践指引5.1 可以观察到的演进痕迹对比 PR 提交2025-03-21/22与当前仓库代码可以推断以下演进滑动窗口模式超参化sliding_window_pattern从图构建函数的局部静态常量static const int sliding_window_pattern 6;演进为hparams.n_swa_pattern使模式可通过超参读取RoPE 缓存路径cparams.rope_cache分支ggml_rope_cacheggml_rope_fast是仓库为提升长上下文性能引入的机制Gemma3 图构建同步适配多模态支持当前仓库 examples/mtmd多模态与 gguf-py/gguf/constants.py 中均出现 gemma3 相关条目说明纯文本支持之后视觉模态也已跟进本 PR 仅覆盖文本。5.2 如何使用 Gemma3 文本模型结合仓库结构与文档运行 Gemma3 文本模型的标准路径为获取 GGUF使用上游 llama.cpp 的convert_hf_to_gguf.py将 Hugging Face 上的 Gemma3 safetensors 权重转换为 GGUF本仓库也提供 convert_hf_to_gguf.py但 PR 明确说明转换需以上游为准构建按 docs/install.md 配置并编译如cmake -B build cmake --build build --config Release -j运行使用 examples/main/main.cpp 或 examples/server 加载 GGUF 推理./build/bin/llama-cli -m path/to/gemma3-4b-it.gguf -p Hello, Gemma3! -n 256验证启动时日志会输出架构名gemma3如需对比量化效果可参考仓库讨论 334 -iq4_ksperforms great on gemma-3-27b-it-qat-q4_0-unquantized 中的社区实践注意该讨论为社区观测非官方承诺。5.3 关键源码速查表关注点文件Gemma3 图构建实现src/graphs/build_gemma3.cpp图构建分发入口src/llama-build-context.cpp图构建类声明src/llama-build-context.h架构字符串注册src/llama-arch.cpp超参解析SWA/RoPE/缩放src/llama-hparams.cpp张量加载复用 Gemma 家族src/llama-load-tensors.cpp六、总结PR #276 以极简的改动面Basically just the graph building为 Gemma3 纯文本推理铺平了道路。当前仓库的 build_gemma3.cpp 完整呈现了这一实现其技术要点可归纳为5-to-1 交错注意力5 层滑动窗口注意力 1 层全局注意力循环窗口层与全局层使用不同 KQ mask 和不同的 RoPE 频率基准滑动层固定freq_base10000全局层沿用长上下文配置双重 post-norm注意力与 FFN 输出后均附加 RMS post-norm延续 Gemma2 的prepost归一化风格家族复用张量加载复用create_gemma_tensors(tn, 3)超参解析与图构建为 Gemma3 单独分支尺寸差异化缩放27B 模型与其他尺寸采用不同的注意力缩放系数公式由超参解析阶段按层数判定。对希望移植或对比 Gemma 系列架构的开发者而言build_gemma3.cpp 与 llama-hparams.cpp 是理解交错注意力如何在 C 推理引擎中落地的最佳范本。【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考