換腳本與聊天模板的完整實(shí)戰(zhàn)指南)
ik_llama.cpp 中 Kimi-K2 轉(zhuǎn)換腳本與聊天模板的完整實(shí)戰(zhàn)指南【免費(fèi)下載鏈接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance項(xiàng)目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cppKimi-K2-Instruct 是一個(gè)規(guī)模約 671B 的 MoE 模型總參數(shù)量超過(guò) 1T其權(quán)重文件在 BF16 下接近 2TB且采用了與 DeepSeek 同源的 MLAMulti-head Latent Attention注意力架構(gòu)。要在 ik_llama.cpp 中把它跑起來(lái)需要解決兩個(gè)問(wèn)題一是通過(guò)convert_hf_to_gguf.py把 HuggingFace safetensors 正確轉(zhuǎn)換為帶完整 MLA 張量的 GGUF二是提供匹配 Moonshot 官方 tokenizer 的聊天模板讓llama-server的 chat endpoint 能正確格式化對(duì)話。本文以 ik_llama.cpp 倉(cāng)庫(kù)中 PR #612「kimi-k2 convert script and chat template」為主線結(jié)合倉(cāng)庫(kù)內(nèi)實(shí)際源碼與模板文件完整講解從原始權(quán)重轉(zhuǎn)換、聊天模板落地到量化Q8_0 → IQ2_KL、驗(yàn)證perplexity / sweep-bench的全流程讀完后你可以獨(dú)立復(fù)現(xiàn)這條鏈路。1. 背景為什么 Kimi-K2 需要專屬轉(zhuǎn)換支持Kimi-K2-Instruct 由 Moonshot AI 發(fā)布在 ik_llama.cpp 社區(qū)中迅速成為「硬核玩家」的壓測(cè)對(duì)象——它是 1TB 級(jí)別的模型對(duì)內(nèi)存帶寬、量化策略和 MLA 支持都提出了極高要求。PR #612 由ubergarm提交包含兩個(gè)核心改動(dòng)移植 mainline llama.cpp PR #14654gabriellarson的轉(zhuǎn)換腳本改動(dòng)添加 kimi-k2 聊天模板使llama-server的 chat endpoint 能正確工作。在此之前PR #609 已經(jīng)完成了 C 側(cè)的模型加載支持從 llama.cpp 移植 kimi-k2 架構(gòu)支持但轉(zhuǎn)換腳本和聊天模板尚未跟上。PR #612 正是補(bǔ)上了這兩塊拼圖。在倉(cāng)庫(kù)當(dāng)前的 convert_hf_to_gguf.py 中Kimi-K2 的識(shí)別與處理邏輯依然保留并作為DeepseekV2ModelModel.register(DeepseekV2ForCausalLM)、Model.register(DeepseekV3ForCausalLM)見(jiàn) convert_hf_to_gguf.py的特殊分支實(shí)現(xiàn)——這也說(shuō)明了 Kimi-K2 與 DeepSeek 系列在架構(gòu)上同源可以直接復(fù)用 DEEPSEEK2 架構(gòu)映射。2. 轉(zhuǎn)換腳本從 safetensors 到 GGUF2.1 詞表vocab構(gòu)建163840 的特殊分支Kimi-K2 的詞表大小為 163840這在當(dāng)前倉(cāng)庫(kù)的轉(zhuǎn)換腳本中是一個(gè)關(guān)鍵分水嶺。在 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 風(fēng)格的 BPE 分詞器add_tokenizer_model(gpt2)轉(zhuǎn)換時(shí)從AutoTokenizer中恢復(fù)mergeable_ranks并逐一重建tokens、toktypes與merges。未覆蓋的 token 位用[PAD{i}]填充并標(biāo)記為UNUSED特殊 token 標(biāo)記為CONTROL。這意味著轉(zhuǎn)換環(huán)境需要安裝transformers并能正常加載該模型的 tokenizertrust_remote_codeTrue。2.2 專家張量合并384 個(gè)路由專家Kimi-K2 每層有 384 個(gè)路由專家外加共享專家轉(zhuǎn)換腳本在modify_tensors中將這些分散的專家權(quán)重合并為單一三維張量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]見(jiàn)下文 PR 實(shí)測(cè)日志這正是 ik_llama.cpp 的 MoE 內(nèi)核所期望的布局。2.3 MLA 關(guān)鍵kv_b_proj的拆分PR #612 中最有價(jià)值的改動(dòng)之一是確保轉(zhuǎn)換產(chǎn)物保留attn_kv_b張量。在 modify_tensors 中kv_b_proj.weight會(huì)被拆分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) ]即一個(gè)kv_b_proj被展開(kāi)為三個(gè) GGUF 張量attn_kv_b.weight、attn_k_b.weight、attn_v_b.weight。PR 作者在轉(zhuǎn)換日志中驗(yàn)證了輸出blk.0.attn_kv_b.weight - [ 512, 16384, 1, 1], type bf16, converting to q8_0 .. size 16.00 MiB - 8.50 MiB同時(shí)轉(zhuǎn)換腳本還會(huì)跳過(guò)超出num_hidden_layers的 MTPMulti-Token Prediction層避免把預(yù)測(cè)頭誤當(dāng)成主模型層寫(xiě)入。2.4 一個(gè)值得注意的坑轉(zhuǎn)換腳本縮進(jìn) bug由于模型體積巨大單次轉(zhuǎn)換耗時(shí)以小時(shí)計(jì)社區(qū)成員實(shí)測(cè)約 17 小時(shí)、2.05T 數(shù)據(jù)、33.6 Mbyte/s 寫(xiě)入速度。PR #617「Fixup kimi-k2 convert indentation」專門(mén)修復(fù)了轉(zhuǎn)換腳本中的一個(gè) Python 縮進(jìn)復(fù)制粘貼錯(cuò)誤修復(fù)后輸出 GGUF 中確認(rèn)存在attn_kv_b。如果你在轉(zhuǎn)換后檢查不到該張量可優(yōu)先排查腳本版本是否包含此修復(fù)。3. 為什么attn_kv_b如此重要MLA 與-mla 3ik_llama.cpp 支持通過(guò)-mla參數(shù)選擇 MLA 計(jì)算路徑-mla 3使用帶attn_kv_b的快速路徑。在 PR #612 中作者明確說(shuō)明只有 ik 的 fork 會(huì)用到attn_kv_b將其保持為 q8_0因?yàn)樗挥糜?PPprompt processing階段的-mla 3。而attn_k_b/attn_v_b則用于 TGtoken generation階段。項(xiàng)目維護(hù)者 ikawrakow 在 PR #617 的討論中進(jìn)一步解釋了attn_kv_b是否存在于 GGUF 中的差異如果 GGUF 中沒(méi)有attn_kv_b內(nèi)存會(huì)為它單獨(dú)分配但仍與對(duì)應(yīng)的attn_k、attn_v在同一設(shè)備上??紤]到大型 NUMA 系統(tǒng)對(duì)張量在內(nèi)存中的存儲(chǔ)方式非常敏感這可能帶來(lái)性能影響但還沒(méi)有人深入研究過(guò)這個(gè)效應(yīng)的細(xì)節(jié)。也就是說(shuō)即使沒(méi)有attn_kv_b也能生成可用的量化模型但保留它可以讓張量存儲(chǔ)更連續(xù)在大內(nèi)存 NUMA 機(jī)器上可能更有利。作者后續(xù)在雙路 AMD EPYC 9965192 核、每 socket 約 768GB RAM、實(shí)測(cè)約 256GiB/s 內(nèi)存帶寬上驗(yàn)證了這套模型可以單 socket 運(yùn)行小量化版本。4. 聊天模板讓 chat endpoint 正確工作4.1 模板檢測(cè)與內(nèi)置支持PR #612 在模型加載日志中確認(rèn)聊天模板被正確識(shí)別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說(shuō)明模板來(lái)自 GGUF 內(nèi)置的 jinja 模板Moonshot 官方tokenizer_config.json中的模板被寫(xiě)入 GGUF而非外部指定。當(dāng)前倉(cāng)庫(kù)中模板也作為獨(dú)立文件保留在 models/templates/Kimi-K2-Instruct.jinja 和 models/templates/Kimi-K2-Thinking.jinja。同時(shí)C 側(cè)在 src/llama.cpp 中注冊(cè)了LLM_CHAT_TEMPLATE_KIMI_K2字符串名kimi-k2使得模板缺失或需要強(qiáng)制指定時(shí)可通過(guò)--chat-template kimi-k2使用內(nèi)置實(shí)現(xiàn)。4.2 模板結(jié)構(gòu)|im_*|標(biāo)記與add_assKimi-K2 的模板圍繞|im_system|、|im_user|、|im_assistant|、|im_middle|、|im_end|這組特殊 token 構(gòu)建。以 Kimi-K2-Instruct.jinja 為例其關(guān)鍵行為包括若第一條消息不是 system自動(dòng)插入|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|結(jié)構(gòu)tool 響應(yīng)則渲染為## Return of functions.name:index結(jié)尾若add_generation_prompt為真追加|im_assistant|assistant|im_middle|引導(dǎo)生成對(duì)多模態(tài) contentimage/image_url渲染|media_start|image|media_content||media_pad||media_end|占位。PR 討論中記錄了一個(gè)真實(shí)問(wèn)題模型有時(shí)會(huì)返回空響應(yīng)且服務(wù)器日志出現(xiàn)異常高的 TG 速度45454.55 tokens per second這種明顯異常的數(shù)值。作者排查后確認(rèn)是模板中缺少assistant角色的add_generation_prompt處理導(dǎo)致的更新模板后問(wèn)題解決the updated chat templateadd_assfixed the generation issue。這提醒我們對(duì)于這類自研模板模型模板結(jié)尾的 generation prompt 是否正確直接影響生成是否為空。4.3 Thinking 模板與 PEG 解析器倉(cāng)庫(kù)還提供 Kimi-K2-Thinking.jinja對(duì)應(yīng)帶思考過(guò)程的版本。在 common/chat.cpp 中當(dāng)模板包含|tool_calls_section_begin|與|tool_call_begin|標(biāo)記時(shí)會(huì)自動(dòng)切換到專門(mén)的 Kimi K2 Thinking 處理路徑common_chat_params_init_kimi_k2推理內(nèi)容包裹在think.../think中工具調(diào)用 ID 采用functions.name:index格式含函數(shù)名與遞增計(jì)數(shù)器。這保證了在llama-server的 OpenAI 兼容接口下Kimi-K2 的思維鏈與工具調(diào)用都能被正確解析為結(jié)構(gòu)化輸出而不是原始文本。5. 量化實(shí)戰(zhàn)從 Q8_0 到 IQ2_KL 的 recipe5.1 混合量化策略模型體量決定了必須做混合量化。PR #612 給出了一個(gè)完整、可復(fù)制的llama-quantize --custom-qrecipe作者實(shí)測(cè)用于生成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 會(huì)用到 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 # 其余注意力張量取平衡點(diǎn) blk\..*\.attn_.*iq5_ks ## 第 0 層唯一一個(gè)稠密 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 解讀正則規(guī)則按張量名匹配--custom-q接受blk\..*\.attn_kv_b\.weightq8_0形式的正則→量化類型映射該特性在 ik_llama.cpp 中由 PR #244「Custom quantization rules with regular expressions」引入grep -v ^#去掉注釋后由sed拼成逗號(hào)分隔的規(guī)則串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 個(gè)路由專家 1 個(gè)共享專家路由專家作為內(nèi)存大頭單層三個(gè)專家張量各約 10.5 GiB見(jiàn)轉(zhuǎn)換日志給到最低的 iq2_kl / iq3_ks--imatrix輸入量化前先用 Q8_0 版本跑 imatrix 得到激活重要性數(shù)據(jù)此處文件為imatrix-Kimi-K2-Instruct-Q8_0.datik_llama.cpp 的 imatrix 支持 MLA 模型對(duì)應(yīng) PR #411 的修復(fù)numactl -N 1 -m 1綁定 NUMA 節(jié)點(diǎn)因?yàn)?345GiB 的 IQ2_KL 恰好能放進(jìn)單 socket 的 ~768GB 內(nèi)存末尾的192量化線程數(shù)匹配 192 核機(jī)器。5.3 張量規(guī)模參考PR 中貼出的 Q8_0 轉(zhuǎn)換日志可作為量化前的規(guī)模參照均以 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每層三個(gè)各超 10 GiB是全模型占比最大的部分這也是 recipe 給它們分配最低位寬的原因。6. 驗(yàn)證perplexity 與性能基準(zhǔn)6.1 困惑度驗(yàn)證CPU 全量作者在雙路 EPYC 9965 上對(duì) IQ2_KL 做了 CPU-only 的 perplexity 驗(yàn)證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關(guān)鍵參數(shù)說(shuō)明-fa啟用 Flash Attention-fmoe啟用 MoE 專用內(nèi)核路徑-mla 3使用含attn_kv_b的 MLA 快速路徑需要轉(zhuǎn)換腳本保留該張量這正是 PR 的核心目的之一--numa numactl配合numactl的 NUMA 感知調(diào)度。6.2 性能基準(zhǔn)sweep-bench同一臺(tái)機(jī)器上使用llama-sweep-bench做了多組對(duì)照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作者實(shí)測(cè)的關(guān)鍵發(fā)現(xiàn)數(shù)據(jù)來(lái)自 PR 討論僅代表該特定硬件與量化組合默認(rèn)配置-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 時(shí)TG 基本不變配合 PR #610 的 AVX512 內(nèi)核ik/q8_k_r8_avx512后 PP 進(jìn)一步提升到約 258.53 t/s約 8% 提升作者推測(cè)與 Zen5 平臺(tái)相關(guān)該 MoE 模型上-rtrrepetition token removal 相關(guān)選項(xiàng)并非必需省略反而更優(yōu)。這些結(jié)論提醒讀者大 MoE 模型的性能高度依賴硬件拓?fù)銷UMA、batch 大小與內(nèi)核版本同一命令在別的機(jī)器上需要重新標(biāo)定。7. 配套進(jìn)展與延伸PR #612 只是 Kimi-K2 支持鏈路的一環(huán)相關(guān)配套工作包括PR #609從 llama.cpp 移植 kimi-k2 架構(gòu)支持C 側(cè)是 PR #612 的前置PR #617修復(fù)轉(zhuǎn)換腳本縮進(jìn) bug確保attn_kv_b正確輸出PR #616新增 sub-2 bpw 量化類型IQ1_KT1.75 bpwTrellis 結(jié)構(gòu)。維護(hù)者 ikawrakow 在 PR #612 討論中透露其初衷正是服務(wù)于這類 1TB 級(jí)模型——在 Kimi-2 時(shí)代會(huì)有更多人追求最低 bpw 的模型該量化實(shí)測(cè)接近IQ2_XXS2.0625 bpw而明顯優(yōu)于IQ1_M且 CUDA 端性能良好PR #628為 Kimi-K2 增加 function calling 支持草稿。此外社區(qū)在 PR 討論中還驗(yàn)證了從 unsloth 的 BF16 safetensors 轉(zhuǎn)換的可行性與局限BF16 版本可能已移除attn_kv_b若需保留該張量應(yīng)從原始 FP8 safetensors 走fp8_cast_bf16.py中間步驟。8. 總結(jié)在 ik_llama.cpp 中落地 Kimi-K2 的完整鏈路可以概括為轉(zhuǎn)換腳本保張量attn_kv_b/attn_k_b/attn_v_b與 384 專家合并→ 模板讓 chat endpoint 可用|im_*|結(jié)構(gòu) add_generation_prompt Thinking/PEG 支持→ 混合量化壓縮體量--custom-q正則 recipe --imatrix→-mla 3 -fa -fmoe驗(yàn)證與調(diào)優(yōu)。每一步都對(duì)應(yīng)倉(cāng)庫(kù)中的實(shí)際源碼或模板文件轉(zhuǎn)換邏輯convert_hf_to_gguf.py聊天模板models/templates/Kimi-K2-Instruct.jinja、models/templates/Kimi-K2-Thinking.jinja內(nèi)置模板注冊(cè)src/llama.cppThinking 專用解析common/chat.cpp對(duì)于想要復(fù)現(xiàn)的讀者建議按順序先確認(rèn)轉(zhuǎn)換腳本包含kv_b_proj拆分與 163840 vocab 分支再檢查生成的 GGUF 是否含attn_kv_b隨后用官方模板驗(yàn)證 chat endpoint 輸出非空最后再投入數(shù)小時(shí)的量化與驗(yàn)證。畢竟駕馭 1TB 級(jí)模型就像作者所說(shuō)的——driving a barge開(kāi)一艘駁船每一步都要穩(wěn)。【免費(fèi)下載鏈接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance項(xiàng)目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考