首页
/ llama.cpp 中运行 LLaVA 多模态模型:llama-mtmd-cli 使用与 1.5/1.6 模型转换实战指南

llama.cpp 中运行 LLaVA 多模态模型:llama-mtmd-cli 使用与 1.5/1.6 模型转换实战指南

2026-09-04 16:12:31作者:秋泉律Samson

本文围绕 llama.cpp 官方的 LLaVA 支持文档(docs/multimodal/llava.md),讲解如何在 llama.cpp 中运行 LLaVA v1.5 与 v1.6 视觉语言模型:包括 llama-mtmd-cli 的构建与运行、从 PyTorch 权重到 GGUF 的完整拆分与转换流程(llava_surgery.py / llava_surgery_v2.py / convert_image_encoder_to_gguf.py)、vicuna 聊天模板的使用,并结合 tools/mtmd 源码剖析 CLIP 视觉编码器与 LLaVA 投影器(projector)在 GGML 计算图中的实现。读完本文,你可以独立完成 LLaVA 1.5/1.6 模型的本地推理部署与权重转换。

支持范围与模型来源

llama.cpp 当前实现支持 LLaVA v1.5 系列模型(如 llava-v1.5-7b/13b),以及 LLaVA v1.6 系列(涵盖 7B 到 34B 的多种规格)。官方文档同时提供了两类模型的预转换 GGUF 版本(7b、13b 及 llava-1.6 的 7b-34b 系列),可直接下载使用,无需自行转换。

需要注意 llama.cpp 的多模态支持是一个处于快速迭代中的子项目,tools/mtmd/README.md 中明确提示“very heavy development,breaking changes are expected”。LLaVA 是最早引入的多模态模型,其 llava.cpp/clip.cpp 架构后来被扩展为统一的多模态库 libmtmd,并整合进单一命令行工具 llama-mtmd-cli

运行 LLaVA:llama-mtmd-cli

构建与启动

首先构建 llama-mtmd-cli 二进制文件(它是 tools/mtmd 下的统一多模态 CLI,取代了早期的 llava-cli)。构建完成后,直接运行 ./llama-mtmd-cli 即可查看用法。

文档给出的典型运行命令:

./llama-mtmd-cli -m ../llava-v1.5-7b/ggml-model-f16.gguf \
    --mmproj ../llava-v1.5-7b/mmproj-model-f16.gguf \
    --chat-template vicuna

关键要点:

  • 两个 GGUF 文件缺一不可-m 指定语言模型 GGUF,--mmproj 指定多模态投影器(multimodal projector)文件。这与 tools/mtmd/README.md 的说明一致——运行多模态模型通常需要两个 GGUF:标准语言模型文件和对应的 mmproj 文件,后者负责图像编码与投影。
  • 建议低温度采样:文档明确建议 --temp 0.1 左右的低温度以获得更好的回答质量。
  • GPU 卸载:使用常规的 -ngl 参数将层卸载到 GPU,与纯文本推理一致。
  • LLaVA 1.6 需要更大上下文:llava-1.6 比 1.5 需要更多上下文,至少 3000,文档建议直接 -c 4096 运行。
  • 批处理提示词:llava-1.6 从批量提示处理(batched prompt processing)中获益明显,使用默认设置即可。

聊天模板:vicuna

对 llava-1.5 和 llava-1.6,都需要使用 vicuna 聊天模板,即添加 --chat-template vicuna。在源码中可以看到对应的处理逻辑:tools/mtmd/mtmd-cli.cpp 在加载旧 LLaVA 模型时会提示 For old llava models, you may need to use '--chat-template vicuna',并在 params.chat_template == "vicuna" 时启用相应模板。

区分当前运行的是 1.5 还是 1.6

运行时,提示词处理前会打印一条视觉编码信息,可以据此判断模式:

  • LLaVA 1.5encode_image_with_clip: image embedding created: 576 tokens
  • LLaVA 1.6(大于 576)encode_image_with_clip: image embedding created: 2880 tokens

也可以直接观察 prompt 实际消耗的 token 数,llava-1.6 会显示 1000+ 个 token。

这个差异源于两个版本图像分辨率策略不同:1.5 使用 CLIP 固定分辨率输出 24×24=576 个 patch token(源码注释中可见 shape [1, 576, 1024],见 tools/mtmd/models/llava.cpp),而 1.6 采用多分辨率切片,token 数相应成倍增加。因此 1.6 才会出现“至少 3000 上下文”的要求。

LLaVA 1.5 模型转换流程

完整流程是把一个 LLaVA 模型拆成 LLaMA 语言部分和 CLIP 视觉编码 + 投影器部分,再分别转换为 GGUF。

第 1 步:克隆 LLaVA 模型和 CLIP 模型(可用 HuggingFace 仓库):

git clone <llava-v1.5-7b 仓库地址>

git clone <clip-vit-large-patch14-336 仓库地址>

第 2 步:安装所需 Python 依赖:

pip install -r tools/mtmd/requirements.txt

该依赖文件(tools/mtmd/requirements.txt)包含 pillow、torch、torchvision 以及 legacy 转换脚本所需的依赖。

第 3 步:用 llava_surgery.py 将 LLaVA 模型拆分为 LLaMA 和 multimodal projector 两部分:

python ./tools/mtmd/llava_surgery.py -m ../llava-v1.5-7b

脚本位于 tools/mtmd/legacy-models/llava_surgery.py-m 参数指向 LLaVA v1.5 模型目录。

第 4 步:用 convert_image_encoder_to_gguf.py 把视觉编码器(CLIP ViT + LLaVA projector)转换为 GGUF:

python ./tools/mtmd/convert_image_encoder_to_gguf.py -m ../clip-vit-large-patch14-336 \
    --llava-projector ../llava-v1.5-7b/llava.projector --output-dir ../llava-v1.5-7b

第 5 步:用 examples/convert_legacy_llama.py 把 LLaVA 中的 LLaMA 部分转换为 GGUF:

python ./examples/convert_legacy_llama.py ../llava-v1.5-7b --skip-unknown

完成后,llava-v1.5-7b 目录中同时包含语言模型 GGUF(ggml-model-f16.gguf)和视觉编码 GGUF(mmproj-model-f16.gguf),即可按上文方式运行。

LLaVA 1.6 GGUF 转换流程

llava-1.6 的模型结构是 HuggingFace transformers 的 ImageTextToText 格式(视觉塔内嵌在模型中),因此流程略有不同,使用 llava_surgery_v2.py

1) 克隆 LLaVA 1.6 模型,例如:

git clone <llava-v1.6-vicuna-7b 仓库地址>

2) 安装 Python 依赖(同上):

pip install -r tools/mtmd/requirements.txt

3) 运行 llava_surgery_v2.py 拆分模型。该脚本(tools/mtmd/legacy-models/llava_surgery_v2.py)同时支持 llava-1.5 的 pytorch 与 safetensors 格式模型:

python tools/mtmd/llava_surgery_v2.py -C -m ../llava-v1.6-vicuna-7b/

其中 -C--clean-vision-tower)表示从模型文件中移除视觉塔。运行后,模型目录中会生成 llava.projectorllava.clip 两个文件。

4) 组装一个独立的 ViT 目录:把 llava.clip 复制为 vit/pytorch_model.bin,把 llava.projector 复制进 vit/,并放入匹配的 ViT 配置文件(文档以 cmp-nct 的 llava-1.6-gguf 仓库中提供的 config_vit.json 为例):

mkdir vit
cp ../llava-v1.6-vicuna-7b/llava.clip vit/pytorch_model.bin
cp ../llava-v1.6-vicuna-7b/llava.projector vit/
# 将对应的 ViT 配置文件下载/复制为 vit/config.json

5) 生成视觉 GGUF 模型。与 1.5 相比,差别在于需要额外加 --clip-model-is-vision 参数,告诉编码器现在处理的是纯视觉模型部分:

python ./tools/mtmd/convert_image_encoder_to_gguf.py -m vit \
    --llava-projector vit/llava.projector --output-dir vit --clip-model-is-vision

6) 转换语言模型部分

python ./examples/convert_legacy_llama.py ../llava-v1.6-vicuna-7b/ --skip-unknown

7) 运行 CLI

./llama-mtmd-cli -m ../llava-v1.6-vicuna-7b/ggml-model-f16.gguf \
    --mmproj vit/mmproj-model-f16.gguf

记得按需加 -c 4096(1.6 需要至少约 3000 上下文)以及 -ngl 做 GPU 卸载。

语言模型不兼容 legacy 转换脚本时:文档给出了备用方案——如果第 6 步中语言模型与 legacy 转换脚本不兼容,最简便的做法是用 transformers 加载模型并仅导出其中的 LLM 部分:

import transformers

model_path = ...
llm_export_path = ...

tokenizer = transformers.AutoTokenizer.from_pretrained(model_path)
model = transformers.AutoModelForImageTextToText.from_pretrained(model_path)

tokenizer.save_pretrained(llm_export_path)
model.language_model.save_pretrained(llm_export_path)

然后用覆盖面更广的 convert_hf_to_gguf.py 转换导出的 LLM。

源码级剖析:CLIP 编码与 LLaVA 投影器如何实现

从源码结构看,LLaVA 的视觉编码核心位于 tools/mtmd/models/llava.cppclip_graph_llava::build() 中(注释标明该图被 llava、granite 和 glm 共用)。其执行链路为:

  1. 输入准备:仅支持方形 patch 网格(GGML_ASSERT(n_patches_x == n_patches_y))。若有 class embedding,将其与 patch embedding 沿第 1 维拼接,再加上按 position 索引取出的位置编码。
  2. Transformer 层循环:逐层执行 pre-LayerNorm → 多头自注意力(Q/K/V 投影 + reshape 到 [d_head, n_head, n_pos])→ 残差 → LayerNorm2 → FFN(支持 gate 分支)→ 残差。
  3. 取特征层:默认取倒数第二层(hparams.n_layer - 1)作为投影器输入,这与 LLaVA 原设计一致;部分变体(如 granite)可显式指定多个 feature layer 并堆叠。
  4. LLaVA 投影器:当 hparams.has_llava_projector 时,先按 patch 索引取回 576 个视觉 token(注释中标明 shape [1, 576, 1024]),再按投影器类型执行:
    • PROJECTOR_TYPE_MLP:标准 LLaVA 两线形层 + GELU(mm_0_w → GELU → 可选 mm_2_w),对应 llava.projector 中的权重;
    • PROJECTOR_TYPE_MLP_NORM:带 LayerNorm 的四线形层版本;
    • 其余类型(如 MobileVLM 的 LDP/LDPV2、GLM-Edge 卷积投影器)也复用同一张图,但 LLaVA 本身只用 MLP 类型。

投影后的视觉 embedding 随后进语言模型,替换 prompt 中的图像占位符——这也解释了为什么 1.5 会打印 576 个 image token。

llava_surgery.py / llava_surgery_v2.py 脚本(位于 tools/mtmd/legacy-models/)的作用正是在 Python 侧把上述“CLIP 视觉塔权重”“projector 权重”“LLM 权重”分离到不同文件中,再由 convert_image_encoder_to_gguf.pyconvert_legacy_llama.py 分别打包成 mmproj-*.ggufggml-model-*.gguf,与 C++ 侧加载的张量命名一一对应。

实用检查清单

  • 运行前确认两份文件:LLM 的 ggml-model-f16.gguf + 视觉的 mmproj-model-f16.gguf
  • --chat-template vicuna(1.5 与 1.6 通用);
  • 建议 --temp 0.1;GPU 上用 -ngl 卸载;
  • llava-1.6 加 -c 4096,并留意 prompt 中 1000+ 的图像 token 占用;
  • 通过 image embedding created: N tokens 日志确认模式:576 为 1.5,2880 及以上为 1.6;
  • 语言模型若无法用 legacy 脚本转换,改用 transformers 导出 LLM 后用 convert_hf_to_gguf.py

相关文档与代码入口

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

项目优选

收起
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