指南)
ik_llama.cpp 中 Kimi-K2 轉換腳本與聊天模板的完整實戰(zhàn)指南【免費下載鏈接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance項目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cppKimi-K2-Instruct 是一個規(guī)模約 671B 的 MoE 模型總參數(shù)量超過 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的全流程讀完后你可以獨立復現(xiàn)這條鏈路。1. 背景為什么 Kimi-K2 需要專屬轉換支持Kimi-K2-Instruct 由 Moonshot AI 發(fā)布在 ik_llama.cpp 社區(qū)中迅速成為「硬核玩家」的壓測對象——它是 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的特殊分支實現(xiàn)——這也說明了 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。這意味著轉換環(huán)境需要安裝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由于模型體積巨大單次轉換耗時以小時計社區(qū)成員實測約 17 小時、2.05T 數(shù)據(jù)、33.6 Mbyte/s 寫入速度。PR #617「Fixup kimi-k2 convert indentation」專門修復了轉換腳本中的一個 Python 縮進復制粘貼錯誤修復后輸出 GGUF 中確認存在attn_kv_b。如果你在轉換后檢查不到該張量可優(yōu)先排查腳本版本是否包含此修復。3. 為什么attn_kv_b如此重要MLA 與-mla 3ik_llama.cpp 支持通過-mla參數(shù)選擇 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 系統(tǒng)對張量在內存中的存儲方式非常敏感這可能帶來性能影響但還沒有人深入研究過這個效應的細節(jié)。也就是說即使沒有attn_kv_b也能生成可用的量化模型但保留它可以讓張量存儲更連續(xù)在大內存 NUMA 機器上可能更有利。作者后續(xù)在雙路 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使用內置實現(xiàn)。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|引導生成對多模態(tài) contentimage/image_url渲染|media_start|image|media_content||media_pad||media_end|占位。PR 討論中記錄了一個真實問題模型有時會返回空響應且服務器日志出現(xiàn)異常高的 TG 速度45454.55 tokens per second這種明顯異常的數(shù)值。作者排查后確認是模板中缺少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格式含函數(shù)名與遞增計數(shù)器。這保證了在llama-server的 OpenAI 兼容接口下Kimi-K2 的思維鏈與工具調用都能被正確解析為結構化輸出而不是原始文本。5. 量化實戰(zhàn)從 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 解讀正則規(guī)則按張量名匹配--custom-q接受blk\..*\.attn_kv_b\.weightq8_0形式的正則→量化類型映射該特性在 ik_llama.cpp 中由 PR #244「Custom quantization rules with regular expressions」引入grep -v ^#去掉注釋后由sed拼成逗號分隔的規(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 個路由專家 1 個共享專家路由專家作為內存大頭單層三個專家張量各約 10.5 GiB見轉換日志給到最低的 iq2_kl / iq3_ks--imatrix輸入量化前先用 Q8_0 版本跑 imatrix 得到激活重要性數(shù)據(jù)此處文件為imatrix-Kimi-K2-Instruct-Q8_0.datik_llama.cpp 的 imatrix 支持 MLA 模型對應 PR #411 的修復numactl -N 1 -m 1綁定 NUMA 節(jié)點因為 345GiB 的 IQ2_KL 恰好能放進單 socket 的 ~768GB 內存末尾的192量化線程數(shù)匹配 192 核機器。5.3 張量規(guī)模參考PR 中貼出的 Q8_0 轉換日志可作為量化前的規(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每層三個各超 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關鍵參數(shù)說明-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作者實測的關鍵發(fā)現(xiàn)數(shù)據(jù)來自 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 相關選項并非必需省略反而更優(yōu)。這些結論提醒讀者大 MoE 模型的性能高度依賴硬件拓撲NUMA、batch 大小與內核版本同一命令在別的機器上需要重新標定。7. 配套進展與延伸PR #612 只是 Kimi-K2 支持鏈路的一環(huán)相關配套工作包括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而明顯優(yōu)于IQ1_M且 CUDA 端性能良好PR #628為 Kimi-K2 增加 function calling 支持草稿。此外社區(qū)在 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驗證與調優(yōu)。每一步都對應倉庫中的實際源碼或模板文件轉換邏輯convert_hf_to_gguf.py聊天模板models/templates/Kimi-K2-Instruct.jinja、models/templates/Kimi-K2-Thinking.jinja內置模板注冊src/llama.cppThinking 專用解析common/chat.cpp對于想要復現(xiàn)的讀者建議按順序先確認轉換腳本包含kv_b_proj拆分與 163840 vocab 分支再檢查生成的 GGUF 是否含attn_kv_b隨后用官方模板驗證 chat endpoint 輸出非空最后再投入數(shù)小時的量化與驗證。畢竟駕馭 1TB 級模型就像作者所說的——driving a barge開一艘駁船每一步都要穩(wěn)?!久赓M下載鏈接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance項目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp創(chuàng)作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考