
ik_llama.cpp 中 Kimi-K2 转换脚本与聊天模板的完整实战指南【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cppKimi-K2-Instruct 是一个规模约 671B 的 MoE 模型总参数量超过 1T其权重文件在 BF16 下接近 2TB且采用了与 DeepSeek 同源的 MLAMulti-head Latent Attention注意力架构。要在 ik_llama.cpp 中把它跑起来需要解决两个问题一是通过convert_hf_to_gguf.py把 HuggingFace safetensors 正确转换为带完整 MLA 张量的 GGUF二是提供匹配 Moonshot 官方 tokenizer 的聊天模板让llama-server的 chat endpoint 能正确格式化对话。本文以 ik_llama.cpp 仓库中 PR #612「kimi-k2 convert script and chat template」为主线结合仓库内实际源码与模板文件完整讲解从原始权重转换、聊天模板落地到量化Q8_0 → IQ2_KL、验证perplexity / sweep-bench的全流程读完后你可以独立复现这条链路。1. 背景为什么 Kimi-K2 需要专属转换支持Kimi-K2-Instruct 由 Moonshot AI 发布在 ik_llama.cpp 社区中迅速成为「硬核玩家」的压测对象——它是 1TB 级别的模型对内存带宽、量化策略和 MLA 支持都提出了极高要求。PR #612 由ubergarm提交包含两个核心改动移植 mainline llama.cpp PR #14654gabriellarson的转换脚本改动添加 kimi-k2 聊天模板使llama-server的 chat endpoint 能正确工作。在此之前PR #609 已经完成了 C 侧的模型加载支持从 llama.cpp 移植 kimi-k2 架构支持但转换脚本和聊天模板尚未跟上。PR #612 正是补上了这两块拼图。在仓库当前的 convert_hf_to_gguf.py 中Kimi-K2 的识别与处理逻辑依然保留并作为DeepseekV2ModelModel.register(DeepseekV2ForCausalLM)、Model.register(DeepseekV3ForCausalLM)见 convert_hf_to_gguf.py的特殊分支实现——这也说明了 Kimi-K2 与 DeepSeek 系列在架构上同源可以直接复用 DEEPSEEK2 架构映射。2. 转换脚本从 safetensors 到 GGUF2.1 词表vocab构建163840 的特殊分支Kimi-K2 的词表大小为 163840这在当前仓库的转换脚本中是一个关键分水岭。在 set_vocab 中if self.hparams[vocab_size] 163840: # Kimi-K2 model from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained( self.dir_model, trust_remote_codeTrue ) tokpre self.get_vocab_base_pre(tokenizer) # Build merges list using the approach similar to HunYuanMoE merges [] vocab {} mergeable_ranks tokenizer.model._mergeable_ranks for token, rank in mergeable_ranks.items(): vocab[QwenModel.token_bytes_to_string(token)] rank ...Kimi-K2 使用 GPT-2 风格的 BPE 分词器add_tokenizer_model(gpt2)转换时从AutoTokenizer中恢复mergeable_ranks并逐一重建tokens、toktypes与merges。未覆盖的 token 位用[PAD{i}]填充并标记为UNUSED特殊 token 标记为CONTROL。这意味着转换环境需要安装transformers并能正常加载该模型的 tokenizertrust_remote_codeTrue。2.2 专家张量合并384 个路由专家Kimi-K2 每层有 384 个路由专家外加共享专家转换脚本在modify_tensors中将这些分散的专家权重合并为单一三维张量if name.find(mlp.experts) ! -1: n_experts self.hparams[n_routed_experts] ... # merge the experts into a single 3d tensor for w_name in [down_proj, gate_proj, up_proj]: datas: list[Tensor] [] for xid in range(n_experts): ... data_torch torch.stack(datas, dim0)最终生成的张量形如blk.9.ffn_down_exps.weight - [2048, 7168, 384, 1]见下文 PR 实测日志这正是 ik_llama.cpp 的 MoE 内核所期望的布局。2.3 MLA 关键kv_b_proj的拆分PR #612 中最有价值的改动之一是确保转换产物保留attn_kv_b张量。在 modify_tensors 中kv_b_proj.weight会被拆分if name.endswith(kv_b_proj.weight): name_kb name.replace(kv_b_proj, k_b_proj) name_vb name.replace(kv_b_proj, v_b_proj) ... kv_b data_torch.view(n_head_kv, v_head_dim qk_nope_head_dim, data_torch.shape[-1]) k_b, v_b torch.split(kv_b, [qk_nope_head_dim, v_head_dim], dim1) ... return [ (self.map_tensor_name(name), data_torch), (self.map_tensor_name(name_kb), k_b), (self.map_tensor_name(name_vb), v_b) ]即一个kv_b_proj被展开为三个 GGUF 张量attn_kv_b.weight、attn_k_b.weight、attn_v_b.weight。PR 作者在转换日志中验证了输出blk.0.attn_kv_b.weight - [ 512, 16384, 1, 1], type bf16, converting to q8_0 .. size 16.00 MiB - 8.50 MiB同时转换脚本还会跳过超出num_hidden_layers的 MTPMulti-Token Prediction层避免把预测头误当成主模型层写入。2.4 一个值得注意的坑转换脚本缩进 bug由于模型体积巨大单次转换耗时以小时计社区成员实测约 17 小时、2.05T 数据、33.6 Mbyte/s 写入速度。PR #617「Fixup kimi-k2 convert indentation」专门修复了转换脚本中的一个 Python 缩进复制粘贴错误修复后输出 GGUF 中确认存在attn_kv_b。如果你在转换后检查不到该张量可优先排查脚本版本是否包含此修复。3. 为什么attn_kv_b如此重要MLA 与-mla 3ik_llama.cpp 支持通过-mla参数选择 MLA 计算路径-mla 3使用带attn_kv_b的快速路径。在 PR #612 中作者明确说明只有 ik 的 fork 会用到attn_kv_b将其保持为 q8_0因为它只用于 PPprompt processing阶段的-mla 3。而attn_k_b/attn_v_b则用于 TGtoken generation阶段。项目维护者 ikawrakow 在 PR #617 的讨论中进一步解释了attn_kv_b是否存在于 GGUF 中的差异如果 GGUF 中没有attn_kv_b内存会为它单独分配但仍与对应的attn_k、attn_v在同一设备上。考虑到大型 NUMA 系统对张量在内存中的存储方式非常敏感这可能带来性能影响但还没有人深入研究过这个效应的细节。也就是说即使没有attn_kv_b也能生成可用的量化模型但保留它可以让张量存储更连续在大内存 NUMA 机器上可能更有利。作者后续在双路 AMD EPYC 9965192 核、每 socket 约 768GB RAM、实测约 256GiB/s 内存带宽上验证了这套模型可以单 socket 运行小量化版本。4. 聊天模板让 chat endpoint 正确工作4.1 模板检测与内置支持PR #612 在模型加载日志中确认聊天模板被正确识别INFO [ main] chat template | ... chat_example|im_system|system|im_middle|You are a helpful assistant|im_end||im_assistant|assistant|im_middle|Hello|im_end||im_user|user|im_middle|Hi there|im_end||im_assistant|assistant|im_middle|How are you?|im_end| built_intruebuilt_intrue说明模板来自 GGUF 内置的 jinja 模板Moonshot 官方tokenizer_config.json中的模板被写入 GGUF而非外部指定。当前仓库中模板也作为独立文件保留在 models/templates/Kimi-K2-Instruct.jinja 和 models/templates/Kimi-K2-Thinking.jinja。同时C 侧在 src/llama.cpp 中注册了LLM_CHAT_TEMPLATE_KIMI_K2字符串名kimi-k2使得模板缺失或需要强制指定时可通过--chat-template kimi-k2使用内置实现。4.2 模板结构|im_*|标记与add_assKimi-K2 的模板围绕|im_system|、|im_user|、|im_assistant|、|im_middle|、|im_end|这组特殊 token 构建。以 Kimi-K2-Instruct.jinja 为例其关键行为包括若第一条消息不是 system自动插入|im_system|system|im_middle|You are Kimi, an AI assistant created by Moonshot AI.|im_end|支持name字段覆盖角色名message.get(name) or message[role]支持 tool callsassistant 消息中的tool_calls被渲染为|tool_calls_section_begin|...|tool_call_begin|functions.name:index|tool_call_argument_begin|...|tool_call_end|结构tool 响应则渲染为## Return of functions.name:index结尾若add_generation_prompt为真追加|im_assistant|assistant|im_middle|引导生成对多模态 contentimage/image_url渲染|media_start|image|media_content||media_pad||media_end|占位。PR 讨论中记录了一个真实问题模型有时会返回空响应且服务器日志出现异常高的 TG 速度45454.55 tokens per second这种明显异常的数值。作者排查后确认是模板中缺少assistant角色的add_generation_prompt处理导致的更新模板后问题解决the updated chat templateadd_assfixed the generation issue。这提醒我们对于这类自研模板模型模板结尾的 generation prompt 是否正确直接影响生成是否为空。4.3 Thinking 模板与 PEG 解析器仓库还提供 Kimi-K2-Thinking.jinja对应带思考过程的版本。在 common/chat.cpp 中当模板包含|tool_calls_section_begin|与|tool_call_begin|标记时会自动切换到专门的 Kimi K2 Thinking 处理路径common_chat_params_init_kimi_k2推理内容包裹在think.../think中工具调用 ID 采用functions.name:index格式含函数名与递增计数器。这保证了在llama-server的 OpenAI 兼容接口下Kimi-K2 的思维链与工具调用都能被正确解析为结构化输出而不是原始文本。5. 量化实战从 Q8_0 到 IQ2_KL 的 recipe5.1 混合量化策略模型体量决定了必须做混合量化。PR #612 给出了一个完整、可复制的llama-quantize --custom-qrecipe作者实测用于生成Kimi-K2-Instruct-IQ2_KL.gguf模型元信息显示model params 1.027 T、model size 345.687 GiB (2.892 BPW)custom ## Attention [0-60] (GPU) # 只有 ik 的 fork 会用到 attn_kv_b保持 q8_0仅用于 PP 阶段的 -mla 3 blk\..*\.attn_kv_b\.weightq8_0 # k_b / v_b 用于 TG 阶段的 -mla 3ik 的 imatrix 也支持它们 # 注意 attn_k_b.weight 维度不可被 256 整除因此只支持 qN_0 或 iq4_nl blk\..*\.attn_k_b\.weightq5_0 # 其余注意力张量取平衡点 blk\..*\.attn_.*iq5_ks ## 第 0 层唯一一个稠密 FFN 层(GPU) blk\..*\.ffn_down\.weightiq5_ks blk\..*\.ffn_(gate|up)\.weightiq4_ks ## 共享专家 (1-60) (GPU) blk\..*\.ffn_down_shexp\.weightiq5_ks blk\..*\.ffn_(gate|up)_shexp\.weightiq4_ks ## 路由专家 (1-60) (CPU) blk\..*\.ffn_down_exps\.weightiq3_ks blk\..*\.ffn_(gate|up)_exps\.weightiq2_kl ## 词嵌入与输出张量 (GPU) token_embd\.weightiq4_k output\.weightiq6_k custom$( echo $custom | grep -v ^# | \ sed -Ez s:\n:,:g;s:,$::;s:^,:: ) numactl -N 1 -m 1 \ ./build/bin/llama-quantize \ --custom-q $custom \ --imatrix /mnt/raid/models/ubergarm/Kimi-K2-Instruct-GGUF/imatrix-Kimi-K2-Instruct-Q8_0.dat \ /mnt/raid/models/ubergarm/Kimi-K2-Instruct-GGUF/Kimi-K2-384x15B-Instruct-safetensors-BF16-00001-of-00045.gguf \ /mnt/raid/models/ubergarm/Kimi-K2-Instruct-GGUF/Kimi-K2-Instruct-IQ2_KL.gguf \ IQ2_KL \ 1925.2 Recipe 解读正则规则按张量名匹配--custom-q接受blk\..*\.attn_kv_b\.weightq8_0形式的正则→量化类型映射该特性在 ik_llama.cpp 中由 PR #244「Custom quantization rules with regular expressions」引入grep -v ^#去掉注释后由sed拼成逗号分隔的规则串MLA 张量的差异化处理attn_kv_b保持 q8_0PP 用attn_k_b因维度128×32768不可被 256 整除只能选择 qN_0 或 iq4_nl 类量化作者选用 q5_0其余注意力张量用 iq5_ks 平衡稀疏 vs 稠密分离第 0 层是唯一带稠密 FFN 的层ffn_down/gate/up其余层是 384 个路由专家 1 个共享专家路由专家作为内存大头单层三个专家张量各约 10.5 GiB见转换日志给到最低的 iq2_kl / iq3_ks--imatrix输入量化前先用 Q8_0 版本跑 imatrix 得到激活重要性数据此处文件为imatrix-Kimi-K2-Instruct-Q8_0.datik_llama.cpp 的 imatrix 支持 MLA 模型对应 PR #411 的修复numactl -N 1 -m 1绑定 NUMA 节点因为 345GiB 的 IQ2_KL 恰好能放进单 socket 的 ~768GB 内存末尾的192量化线程数匹配 192 核机器。5.3 张量规模参考PR 中贴出的 Q8_0 转换日志可作为量化前的规模参照均以 bf16 → q8_0张量形状原始 → Q8_0 大小token_embd.weight / output.weight[7168, 163840]2240 MiB → 1190 MiBblk.0.ffn_{down,gate,up}.weight[18432, 7168] 等252 MiB → 133.88 MiBblk.0.attn_q_a.weight[7168, 1536]21 MiB → 11.16 MiBblk.0.attn_kv_a_mqa.weight[7168, 576]7.88 MiB → 4.18 MiBblk.0.attn_kv_b.weight[512, 16384]16 MiB → 8.50 MiBblk.9.ffn_{down,gate,up}_exps.weight[2048/7168, 7168/2048, 384]10752 MiB → 5712 MiB路由专家张量ffn_*_exps每层三个各超 10 GiB是全模型占比最大的部分这也是 recipe 给它们分配最低位宽的原因。6. 验证perplexity 与性能基准6.1 困惑度验证CPU 全量作者在双路 EPYC 9965 上对 IQ2_KL 做了 CPU-only 的 perplexity 验证model/mnt/raid/hf/Kimi-K2-Instruct-GGUF/IQ2_KL/Kimi-K2-Instruct-IQ2_KL-00001-of-00008.gguf numactl -N 1 -m 1 \ ./build/bin/llama-perplexity \ -m $model \ -f wiki.test.raw \ --seed 1337 \ -fa -fmoe \ -mla 3 \ --ctx-size 512 \ --numa numactl \ --threads 192 Final estimate: PPL 3.2741 /- 0.01689关键参数说明-fa启用 Flash Attention-fmoe启用 MoE 专用内核路径-mla 3使用含attn_kv_b的 MLA 快速路径需要转换脚本保留该张量这正是 PR 的核心目的之一--numa numactl配合numactl的 NUMA 感知调度。6.2 性能基准sweep-bench同一台机器上使用llama-sweep-bench做了多组对照IQ2_KL12288 ctx-ctk q8_0numactl -N 0 -m 0 \ ./build/bin/llama-sweep-bench \ --model $model \ --ctx-size 12288 \ -ctk q8_0 \ -fa -fmoe \ -mla 3 \ --threads 128 \ --threads-batch 192 \ -ub 4096 -b 4096 \ --no-mmap \ --numa numactl \ --warmup-batch作者实测的关键发现数据来自 PR 讨论仅代表该特定硬件与量化组合默认配置-ub 512 -b 2048下 PP 约 107~174 t/s、TG 约 12~13.6 t/s加大 batch-ub 4096 -b 4096后 PP 提升到 237.58 t/s空 KV 时TG 基本不变配合 PR #610 的 AVX512 内核ik/q8_k_r8_avx512后 PP 进一步提升到约 258.53 t/s约 8% 提升作者推测与 Zen5 平台相关该 MoE 模型上-rtrrepetition token removal 相关选项并非必需省略反而更优。这些结论提醒读者大 MoE 模型的性能高度依赖硬件拓扑NUMA、batch 大小与内核版本同一命令在别的机器上需要重新标定。7. 配套进展与延伸PR #612 只是 Kimi-K2 支持链路的一环相关配套工作包括PR #609从 llama.cpp 移植 kimi-k2 架构支持C 侧是 PR #612 的前置PR #617修复转换脚本缩进 bug确保attn_kv_b正确输出PR #616新增 sub-2 bpw 量化类型IQ1_KT1.75 bpwTrellis 结构。维护者 ikawrakow 在 PR #612 讨论中透露其初衷正是服务于这类 1TB 级模型——在 Kimi-2 时代会有更多人追求最低 bpw 的模型该量化实测接近IQ2_XXS2.0625 bpw而明显优于IQ1_M且 CUDA 端性能良好PR #628为 Kimi-K2 增加 function calling 支持草稿。此外社区在 PR 讨论中还验证了从 unsloth 的 BF16 safetensors 转换的可行性与局限BF16 版本可能已移除attn_kv_b若需保留该张量应从原始 FP8 safetensors 走fp8_cast_bf16.py中间步骤。8. 总结在 ik_llama.cpp 中落地 Kimi-K2 的完整链路可以概括为转换脚本保张量attn_kv_b/attn_k_b/attn_v_b与 384 专家合并→ 模板让 chat endpoint 可用|im_*|结构 add_generation_prompt Thinking/PEG 支持→ 混合量化压缩体量--custom-q正则 recipe --imatrix→-mla 3 -fa -fmoe验证与调优。每一步都对应仓库中的实际源码或模板文件转换逻辑convert_hf_to_gguf.py聊天模板models/templates/Kimi-K2-Instruct.jinja、models/templates/Kimi-K2-Thinking.jinja内置模板注册src/llama.cppThinking 专用解析common/chat.cpp对于想要复现的读者建议按顺序先确认转换脚本包含kv_b_proj拆分与 163840 vocab 分支再检查生成的 GGUF 是否含attn_kv_b随后用官方模板验证 chat endpoint 输出非空最后再投入数小时的量化与验证。毕竟驾驭 1TB 级模型就像作者所说的——driving a barge开一艘驳船每一步都要稳。【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考