首页
/ llama.cpp 部署 MiniCPM-o 2.6 多模态模型:从 PyTorch 转换到 llama-mtmd-cli 图文推理全流程

llama.cpp 部署 MiniCPM-o 2.6 多模态模型:从 PyTorch 转换到 llama-mtmd-cli 图文推理全流程

2026-09-04 10:44:21作者:咎竹峻Karen

本文基于 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 中的推理链路可以分为四步:

  1. 准备 PyTorch 模型:从 Hugging Face 下载 openbmb/MiniCPM-o-2_6 的 PyTorch 权重,放入 MiniCPM-o-2_6 目录;
  2. 构建 llama.cpp:使用 CMake 编译出 llama-mtmd-cli(多模态命令行工具)与 llama-quantize 等二进制;
  3. 转换为 GGUF:对 PyTorch 模型做“手术”(剥离视觉塔与 Resampler 权重)、将图像编码器转换为 mmproj-*.gguf,再将 LLM 部分转换为 ggml-model-*.gguf,最后量化出 Q4_K_M 版本;
  4. 推理:通过 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_sizevision_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_embedresampler.proj 张量在转换时会被重写/扩展为 pos_embed_k,并通过 2D sin-cos 位置编码(70×70 网格)生成对应数据,同时 attn.in_proj_* 被拆分为独立的 q/k/v 投影权重——这些重命名规则与推理端 clip-impl.h 中定义的张量名(TN_MINICPMV_POS_EMBD_KTN_MINICPMV_QUERYTN_MINICPMV_KV_PROJTN_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.cppis_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 严格对应:

  1. ViT 编码build_vit() 对 patch 化后的图像做标准 ViT 前向(带学习位置嵌入 ggml_get_rows 选择);
  2. 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 行的实现,位置频率 omegapos_h/pos_w 作为图输入在运行时按实际 patch 网格填充);
  3. 输出投影:注意力输出经 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.projscale_emb 补偿由 surgery 脚本自动完成,手工搬运权重时必须保留该缩放,否则投影层数值会系统性偏大;
  • 上下文预算:图像固定映射为 64 个 token(version 4),加上提示文本一起计入 -c 指定长度;
  • 构建时效:原 README 标注的文档修改时间为 20250206,若与当前仓库实际行为有出入,以仓库内 docs/multimodal/minicpmo2.6.mdtools/mtmd 源码为准。

至此,MiniCPM-o 2.6 在 llama.cpp 中的完整落地路径已经打通:手术式拆分 PyTorch 权重、SigLIP 视觉塔加 Resampler 的 mmproj 转换、LLM 的 GGUF 化与 Q4_K_M 量化,最后由 llama-mtmd-cli 完成单轮与多轮图文推理。后续若全模态支持补齐,本文的转换框架同样可以在此基础上扩展音频链路。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
980
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384