llama.cpp 部署 MiniCPM-o 2.6 多模态模型:从 PyTorch 转换到 llama-mtmd-cli 图文推理全流程
本文基于 llama.cpp 仓库官方文档 MiniCPM-o 2.6 整理,介绍如何在 llama.cpp 中加载 openbmb 的 MiniCPM-o 2.6 多模态模型并完成图文推理。读完本文,你将掌握完整的模型准备、GGUF 转换(含图像编码器 mmproj 文件生成)、量化与推理命令,并理解 MiniCPM-V 系列“视觉编码器 + Resampler 投影器”在 llama.cpp 中的实际图构建实现。
需要提前说明的是:当前版本 llama.cpp 对 MiniCPM-o 2.6 仅支持其图像(vision)能力,音频/语音等全模态(omni)能力尚未接入,官方文档明确表示全模态支持会尽快更新。也就是说,MiniCPM-o 2.6 在本流程中等价于一个强大的视觉-语言模型(VLM)来使用。
一、整体流程概览
MiniCPM-o 2.6 在 llama.cpp 中的推理链路可以分为四步:
- 准备 PyTorch 模型:从 Hugging Face 下载 openbmb/MiniCPM-o-2_6 的 PyTorch 权重,放入
MiniCPM-o-2_6目录; - 构建 llama.cpp:使用 CMake 编译出
llama-mtmd-cli(多模态命令行工具)与llama-quantize等二进制; - 转换为 GGUF:对 PyTorch 模型做“手术”(剥离视觉塔与 Resampler 权重)、将图像编码器转换为
mmproj-*.gguf,再将 LLM 部分转换为ggml-model-*.gguf,最后量化出 Q4_K_M 版本; - 推理:通过
llama-mtmd-cli以单轮问答或交互会话两种方式喂入图片和提示词。
与纯文本模型不同,多模态模型需要加载两个 GGUF 文件:LLM 主干(-m 指定)和图像编码器投影器(--mmproj 指定)。
二、准备模型与构建 llama.cpp
2.1 下载 PyTorch 模型
将 openbmb 发布的 MiniCPM-o-2_6 PyTorch 模型下载至本地 MiniCPM-o-2_6 文件夹(模型来自 Hugging Face 的 openbmb/MiniCPM-o-2_6)。下载完成后该目录应包含 config.json、词表文件以及含 vpm.*(视觉塔)与 resampler.*(Resampler 投影器)张量的检查点文件。
2.2 构建 llama.cpp
克隆仓库并使用 CMake 构建(若构建方式有差异,以官方构建文档为准):
git clone https://gitcode.com/GitHub_Trending/ll/llama.cpp
cd llama.cpp
cmake -B build
cmake --build build --config Release
构建产物位于 build/bin/ 下,本文后续用到的可执行文件包括:
llama-mtmd-cli:多模态命令行推理工具(源码 tools/mtmd/mtmd-cli.cpp);llama-quantize:GGUF 量化工具。
多模态能力的总览见 tools/mtmd/README.md,其中列出的支持模型清单就包含 MiniCPM-o 2.6 的独立文档入口;集成测试脚本 tools/mtmd/tests.sh 中也有一条针对 openbmb/MiniCPM-o-2_6-gguf:Q4_0 的视觉推理测试用例,说明该模型处于 mtmd 工具的常规回归测试范围内。
三、PyTorch 模型转 GGUF:四步转换与量化
如果你不想本地转换,也可以直接下载社区已转换好的 GGUF 文件(openbmb 在 Hugging Face 上提供了 MiniCPM-o-2_6-gguf)。下面是从 PyTorch 权重自行转换的完整命令:
# 第 1 步:剥离视觉权重,准备标准 LLM 目录
python ./tools/mtmd/legacy-models/minicpmv-surgery.py -m ../MiniCPM-o-2_6
# 第 2 步:生成图像编码器 + Resampler 投影器的 mmproj GGUF
python ./tools/mtmd/legacy-models/minicpmv-convert-image-encoder-to-gguf.py -m ../MiniCPM-o-2_6 \
--minicpmv-projector ../MiniCPM-o-2_6/minicpmv.projector \
--output-dir ../MiniCPM-o-2_6/ \
--minicpmv_version 4
# 第 3 步:将 LLM 部分转换为 f16 GGUF
python ./convert_hf_to_gguf.py ../MiniCPM-o-2_6/model
# 第 4 步:量化出 Q4_K_M 版本
./build/bin/llama-quantize ../MiniCPM-o-2_6/model/ggml-model-f16.gguf \
../MiniCPM-o-2_6/model/ggml-model-Q4_K_M.gguf Q4_K_M
下面逐条解释每一步在做什么、以及为什么必须这样做。
3.1 minicpmv-surgery.py:把“多模态大杂烩”拆成 LLM / 视觉塔 / 投影器三部分
MiniCPM-o 的 PyTorch 检查点把语言模型、视觉塔(vpm.*)和 Resampler 投影器(resampler.*)混在同一个 state_dict 里,而 llama.cpp 的通用转换器 convert_hf_to_gguf.py 只认标准 LLM 目录。minicpmv-surgery.py 就是完成这次“外科手术”的脚本,其行为如下:
- 抽出 Resampler(
resampler.*)张量:存为minicpmv.projector文件。源码中有一个关键的数值修正——如果 LLM 配置带有scale_emb,则对resampler.proj权重做除以scale_emb的缩放(因为加载标准 MiniCPM LLM 时嵌入层会被放大该系数,投影层必须做等价补偿); - 抽出视觉塔(
vpm.*)张量:去掉vpm.前缀后存为minicpmv.clip文件,供第 2 步加载; - 清空
added_tokens.json:写为{}。注释说明这是为了移除多模态专用 token,让model/子目录能按标准 LLM 格式转换; - 改写
auto_map配置并另存 LLM:将配置映射回标准 MiniCPM 类(MiniCPMConfig/MiniCPMModel/MiniCPMForCausalLM等),把 LLM 权重和 tokenizer 保存到{模型目录}/model子目录——这正是第 3 步convert_hf_to_gguf.py的输入。
脚本结束时会打印提示:此时你可以把 model/ 当普通 LLM GGUF 转换,并用 minicpmv.projector 生成 mmproj 文件。
3.2 minicpmv-convert-image-encoder-to-gguf.py:生成 mmproj-model-f16.gguf
该脚本 负责把视觉编码器与 Resampler 合并写成一个 mmproj GGUF。对 MiniCPM-o 2.6 最关键的参数是 --minicpmv_version 4,其取值含义在脚本的参数帮助中写得很明确:
MiniCPM-V-2 use 1; MiniCPM-V-2.5 use 2; MiniCPM-V-2.6 use 3; MiniCPM-o-2.6 use 4; MiniCPM-V 4.0 use 5; MiniCPM-o-4.0 use 6; MiniCPM-o-4.5 use 100045
(见 minicpmv-convert-image-encoder-to-gguf.py#L504)
指定 version 4 时,脚本会走 SigLIP 视觉编码器分支:用 SiglipVisionConfig + SiglipVisionTransformer 实例化视觉塔(version 2/2.6 则默认使用 Idefics2 风格 ViT),从 config.json 读取 hidden_size、vision_config 等实际配置(而非硬编码),并把权重按 clip.* 命名规范写入 GGUF。
写入的元数据中还有几个与 MiniCPM-V 直接相关的字段(源码中可见):
clip.projector_type = "resampler"、clip.minicpmv_version = 4:标记投影器类型与版本;clip.minicpmv_query_num:来自配置的query_num(Resampler 可学习 query 的数量),推理端据此决定投影后送入 LLM 的 token 数;clip.vision.image_size / patch_size等视觉超参与图像归一化均值/方差(clip.vision.image_mean/image_std)。
输出文件名由脚本按 mmproj- + model- + f16 拼接而成,即文档推理命令中使用的 mmproj-model-f16.gguf。另外,如果 --minicpmv-projector 未显式指定但默认路径 {模型目录}/minicpmv.projector 存在,脚本会自动采用该文件。
一个值得注意的实现细节:resampler.pos_embed 与 resampler.proj 张量在转换时会被重写/扩展为 pos_embed_k,并通过 2D sin-cos 位置编码(70×70 网格)生成对应数据,同时 attn.in_proj_* 被拆分为独立的 q/k/v 投影权重——这些重命名规则与推理端 clip-impl.h 中定义的张量名(TN_MINICPMV_POS_EMBD_K、TN_MINICPMV_QUERY、TN_MINICPMV_KV_PROJ、TN_MINICPMV_ATTN 等)一一对应。
3.3 convert_hf_to_gguf.py 与量化
第 3 步把 model/ 子目录转换为 ggml-model-f16.gguf;第 4 步用 llama-quantize 产出 ggml-model-Q4_K_M.gguf,供显存/内存紧张的场景使用。mmproj 文件保持 f16 不参与量化。
四、llama-mtmd-cli 推理:单轮问答与交互会话
4.1 单轮模式
./build/bin/llama-mtmd-cli -m ../MiniCPM-o-2_6/model/ggml-model-f16.gguf \
--mmproj ../MiniCPM-o-2_6/mmproj-model-f16.gguf \
-c 4096 --temp 0.7 --top-p 0.8 --top-k 100 --repeat-penalty 1.05 \
--image xx.jpg -p "What is in the image?"
参数含义:
| 参数 | 说明 |
|---|---|
-m |
LLM 主干 GGUF(f16 或量化版均可) |
--mmproj |
图像编码器投影器 GGUF,必填 |
-c 4096 |
上下文长度 |
--temp 0.7 / --top-p 0.8 / --top-k 100 |
采样参数 |
--repeat-penalty 1.05 |
重复惩罚,抑制复读 |
--image xx.jpg |
输入图片路径 |
-p |
提示词 |
从源码可以印证单轮模式的判定逻辑:mtmd-cli.cpp 中 is_single_turn = !params.prompt.empty() && !params.image.empty(),即同时提供 -p 与 --image 时走一次性问答流程;若只加载图片、不提供 prompt,则同样进入单轮模式(图片标记插入提示前)。
4.2 交互会话模式
./build/bin/llama-mtmd-cli -m ../MiniCPM-o-2_6/model/ggml-model-Q4_K_M.gguf \
--mmproj ../MiniCPM-o-2_6/mmproj-model-f16.gguf
不传 --image 和 -p 时,CLI 进入聊天模式。进入会话后可以随时用内置命令加载媒体文件(源码 mtmd-cli.cpp#L483 打印的帮助中可见):
/image <path> load an image
加载后继续输入文本即可围绕已加载图片连续提问,支持多张图片依次加载(params.image 是列表,媒体标记会按顺序逐张插入)。会话中同样支持 /audio、/video 命令,但如前所述,MiniCPM-o 2.6 在当前 llama.cpp 中仅保证图像能力可用。
五、源码透视:MiniCPM-V 投影器图是如何构建的
以上述 mmproj GGUF 加载时,mtmd 会根据 clip.projector_type = "resampler" 选择 MiniCPM-V 分支。真正的计算图由 tools/mtmd/models/minicpmv.cpp 中的 clip_graph_minicpmv::build() 完成,其结构与 OpenBMB 官方 resampler.py 严格对应:
- ViT 编码:
build_vit()对 patch 化后的图像做标准 ViT 前向(带学习位置嵌入ggml_get_rows选择); - Resampler 即一个小型 Transformer:可学习的
query(数量由minicpmv_query_num决定,version 4 在 GGUF 元数据缺失时回退为 64)先经 LayerNorm,与 ViT 输出投影出的 KV 一起做注意力——其中 K = KV 投影结果 加 2D sin-cos 正弦位置嵌入(源码注释直接引用了 MiniCPM-o-2_6 官方resampler.py第 70 行的实现,位置频率omega与pos_h/pos_w作为图输入在运行时按实际 patch 网格填充); - 输出投影:注意力输出经 post-LayerNorm 与最终线性投影(即 surgery 阶段做过
scale_emb补偿的resampler.proj.weight),得到n_embd_proj维、长度等于 query 数的特征序列,作为图像 token 插入 LLM 的提示位置。
版本分派逻辑集中在 tools/mtmd/clip.cpp:加载元数据时读取 clip.minicpmv_version(#L1310 附近,version 4 的 query_num 回退值为 64);选择图像预处理与 patch 数时(#L4080 附近),MiniCPM-V 系列使用 llava-uhd 风格的默认预处理参数,version 4 的投影 token 数固定为 64。也就是说,一张图经过 mmproj 后最终占用 64 个上下文位置——在规划 -c 上下文长度时需要考虑这部分开销。
六、注意事项与适用边界
- 能力边界:当前文档仅覆盖图像能力;MiniCPM-o 2.6 的语音输入/输出等 omni 能力在 llama.cpp 中尚未支持,请勿按完整 Omni 模型预期使用;
- 版本参数的对应关系务必记牢:转换 mmproj 时
--minicpmv_version必须传4,传错版本会导致视觉塔类型(Idefics2 风格 ViT 与 SigLIP)或 query 数量不匹配; resampler.proj的scale_emb补偿由 surgery 脚本自动完成,手工搬运权重时必须保留该缩放,否则投影层数值会系统性偏大;- 上下文预算:图像固定映射为 64 个 token(version 4),加上提示文本一起计入
-c指定长度; - 构建时效:原 README 标注的文档修改时间为 20250206,若与当前仓库实际行为有出入,以仓库内 docs/multimodal/minicpmo2.6.md 及 tools/mtmd 源码为准。
至此,MiniCPM-o 2.6 在 llama.cpp 中的完整落地路径已经打通:手术式拆分 PyTorch 权重、SigLIP 视觉塔加 Resampler 的 mmproj 转换、LLM 的 GGUF 化与 Q4_K_M 量化,最后由 llama-mtmd-cli 完成单轮与多轮图文推理。后续若全模态支持补齐,本文的转换框架同样可以在此基础上扩展音频链路。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00