跳到正文

目录

MLX-VLM:在 Apple Silicon 上运行与微调视觉语言模型

MLX-VLM:在 Apple Silicon 上运行与微调视觉语言模型

想要在 Mac 上本地跑视觉语言模型(VLM),最顺手的入口是 MLX-VLM。它把推理和微调都封装好了:读图、听音频、看视频、开一个 OpenAI 兼容的接口,或者用 LoRA 调一个自己的模型,都可以在这一个包里完成。它的价值来自底层 MLX 与 Apple Silicon 统一内存的配合——模型权重直接放在 GPU 可访问的内存里,省掉了 CPU 与 GPU 之间的搬运,让消费级 Mac 也能跑多模态模型。

下面按“是什么 → 架构 → 能跑哪些模型 → 怎么用 → 进阶调优 → 部署”展开。

学习目标

读完本文后,你应该能够:

  • 说清 MLX-VLM 在 Apple Silicon 上的推理原理和优势
  • 安装 MLX-VLM,并会用命令行和 Python API 做图像、音频、视频理解
  • 根据内存选择模型,并理解视觉特征缓存与 KV Cache 量化的取舍
  • 用 LoRA/QLoRA 微调自己的模型
  • 启动 FastAPI 服务器并调用 OpenAI 兼容接口

目录


1. MLX-VLM 是什么

1.1 定位

MLX-VLM 是一个 Python 包,由 Blaizzy Prince Canuma 维护,专注做两件事:在 Apple Silicon Mac 上推理微调两类模型:

  • 视觉语言模型(VLM):看图说话、视觉问答、图文对照
  • 全能模型(Omni Model):VLM 的扩展,额外支持音频、视频输入

模型权重通常来自 Hugging Face 上的 mlx-community 组织,那里提供了大量预量化权重,首次使用自动下载,无需手动转换格式。

1.2 关键信息

项目说明
开发者Blaizzy Prince Canuma
许可证MIT
支持模型50+ 种架构
微调方式LoRA、QLoRA
服务器FastAPI,兼容 OpenAI Chat Completions / Responses API
安装pip install -U mlx-vlm

本地推理意味着数据不离开设备。图片、音频、提示词都只在你的 Mac 上处理,涉及隐私或合规的场景这一点很关键;代价是算力和内存都花在本地。

1.3 技术标签

mlx · vision-language-model · apple-silicon · omni-model · local-ai

1.4 主要特点

  • Apple Silicon 优先:基于 MLX,利用统一内存与 Metal GPU 加速
  • 多模态输入:图像、视频、音频,取决于所加载的模型架构
  • 量化友好:直接加载 mlx-community 的 4-bit 等量化权重
  • 本地可微调:LoRA/QLoRA,用小批量数据在本地训出垂直模型
  • 服务化:FastAPI 服务器,OpenAI 兼容,便于接进现有应用

2. 技术架构

2.1 MLX 框架为什么适合做这件事

MLX 是 Apple 的开源机器学习框架,几个特性直接决定 VLM 能在 Mac 上跑起来:

  • 统一内存:CPU 与 GPU 共享同一块物理内存,模型权重省去在两者之间搬移。VRAM 受限的显卡生态里,超大模型的显存放不下,而 Mac 可以整块模型驻留在统一内存里。
  • Metal GPU 加速:张量计算走 Apple GPU 的并行内核。
  • Python 优先:API 风格接近 NumPy,写起来直接。

2.2 MLX-VLM 的分层结构

MLX-VLM 提供三层入口,上层是 CLI 和服务器,中层是各种模型实现,底层是 MLX 的算子:

用户接口层   CLI(mlx_vlm.generate / chat / chat_ui)
             Python API(load / generate / stream_generate / apply_chat_template)
             服务器(FastAPI,/v1/chat/completions、/responses、/health)
───────────────────────────────────────────────
模型层       Vision Encoder · LLM Backbone · Audio Encoder(按模型架构组合)
───────────────────────────────────────────────
MLX 核心层   mlx.core · mlx.nn · mlx.optim
───────────────────────────────────────────────
硬件层       Apple GPU(统一内存架构,Metal)

注意一点:并非所有模型都同时带这三块。只有 Omni 架构(如 Gemma-3n、Qwen3-Omni、MiniCPM-o、Phi-4 Multimodal)才有音频编码器。

2.3 核心模块

  • mlx_vlm.load:加载模型与处理器(processor),支持 Hugging Face 仓库 ID 或本地路径。
  • mlx_vlm.generate:一次性生成。
  • mlx_vlm.stream_generate:逐 token 流式返回,适合交互式界面。
  • mlx_vlm.prompt_utils.apply_chat_template:把提示词、图片占位符、对话历史格式化成模型预期的输入。

加载和生成的例子:

from mlx_vlm import load, generate

model, processor = load("mlx-community/Qwen2-VL-2B-Instruct-4bit")
output = generate(
    model, processor, "描述这张图片", image=["image.jpg"]
)
print(output)

3. 支持模型

按用途分组,列一部分常用架构。标注“多图/视频/音频”的,指的是该架构在 MLX-VLM 中支持对应输入。

3.1 图像理解

架构代表示例备注
Qwen2-VL / Qwen2.5-VLmlx-community/Qwen2-VL-2B-Instruct-4bit支持多图与视频
Qwen3-VL / Qwen3-VL-MoE同上系列新一代视觉模型
Qwen3.5 / Qwen3.5-MoE同系列支持思考预算
LLaVA 系列llava多图
Gemma-4google/gemma-4-26b-a4b-it26B MoE,约 4B 激活
PixtralpixtralMistral 的多模态模型
Molmo / MolmoPointmolmomolmo_pointPoint 支持像素级指认
Moondream3moondream39.27B MoE,约 2B 激活,轻量
SmolVLMsmolvlm小型,适合内存紧张
Llama-3.2-Visionmllama单图
InternVL / Kimi-VLinternvl_chatkimi_vl国内模型
Florence-2 / ARIAflorence2提示词驱动的视觉任务

3.2 OCR 专用模型

处理文档、表格、公式、版面:

架构用途
DeepSeek-OCR / OCR-2通用文档识别
DOTS-OCR / DOTS-MOCR版面 JSON、表格、公式提取
GLM-OCRGLM 系 OCR
PaddleOCR-VLPaddleOCR 视觉语言版

3.3 音频理解(全能模型)

架构能力
Gemma-3n图像 + 音频
Qwen3-Omni图像 + 音频
MiniCPM-o图像 + 音频
Phi-4 Multimodal图像 + 音频 + 文本

3.4 视频理解

Qwen2-VLQwen2.5-VLIdefics3LLaVA 支持视频输入,可做字幕生成、片段摘要。


4. 基本用法

4.1 命令行

图像理解:

python -m mlx_vlm.generate \
  --model mlx-community/Qwen2-VL-2B-Instruct-4bit \
  --prompt "描述这张图片" \
  --image path/to/image.jpg

音频理解(加载 Omni 模型):

python -m mlx_vlm.generate \
  --model mlx-community/gemma-3n-E2B-it-4bit \
  --prompt "描述你听到的声音" \
  --audio path/to/audio.wav

4.2 Python API:图像理解

from mlx_vlm import load, generate

model, processor = load("mlx-community/Qwen2-VL-2B-Instruct-4bit")
output = generate(model, processor, "描述这张图片", image=["image.jpg"])
print(output)

4.3 多图像

多图模型需要按图片数量格式化提示词:

from mlx_vlm import load, generate
from mlx_vlm.prompt_utils import apply_chat_template

model, processor = load("mlx-community/Qwen2-VL-2B-Instruct-4bit")
images = ["path/to/image1.jpg", "path/to/image2.jpg"]

prompt = apply_chat_template(
    processor, model.config,
    "比较这两张图片的异同",
    num_images=len(images),
)
output = generate(model, processor, prompt, images)
print(output)

4.4 音频理解

from mlx_vlm import load, generate
from mlx_vlm.prompt_utils import apply_chat_template

model, processor = load("mlx-community/gemma-3n-E2B-it-4bit")
audio = ["/path/to/audio1.wav"]

prompt = apply_chat_template(
    processor, model.config,
    "描述你听到的内容",
    num_audios=len(audio),
)
output = generate(model, processor, prompt, audio=audio)
print(output)

5. 视觉特征缓存

5.1 解决什么问题

多轮对话里,同一张图如果每轮都重新过一遍视觉编码器,前面的对话越多,浪费越大。比如先问“图里有什么”,再问“穿什么颜色”,图片本身没变,却没完没了地重复编码。

5.2 怎么做

视觉特征缓存按输入图像的特征做缓存:命中就直接复用已编码的特征,跳过编码这一步。它在服务器(FastAPI)里默认启用,容量用 --vision-cache-size 控制,默认 20 条。多图聊天里复用同一批图效果最明显。

官方介绍称多轮场景能带来数量级的提速;具体数字依赖模型、图片尺寸和 Mac 型号,建议在自己的机器上跑两轮对比实测。

5.3 用法

启动服务器时指定缓存容量即可:

python -m mlx_vlm.server \
  --model mlx-community/Qwen2-VL-2B-Instruct-4bit \
  --vision-cache-size 20

本质是拿内存换时间:缓存占一点统一内存,换来多轮对话少做视觉编码。上到长视频、大图这类本身就重的输入,收益会更明显。


6. KV Cache 量化:Uniform 与 TurboQuant

6.1 为什么需要

长上下文推理的显存大头往往不是权重,而是 KV Cache——注意力层要记住前面每个 token 的 key 和 value。上下文到几十万 token 时这块内存非常可观。把它量化,是压低长上下文内存占用最直接的手段。

6.2 两种方案

MLX-VLM 服务器在连续批处理(Continuous Batching)下支持两种 KV Cache 量化:

选项位宽机制
Uniform通常 8-bit均匀量化,速度影响小
TurboQuant3.5-bit3-bit keys + 4-bit values,压缩更狠

对应参数:

  • --kv-bits:位宽,Uniform 写 8,TurboQuant 写 3.5
  • --kv-quant-scheme:后端,uniformturboquant
  • --kv-group-size:均匀量化的组大小,默认 64

6.3 机理

量化不是无脑做。实测说明里提到几点取舍:

  • 全注意力层使用量化的批缓存;滑动窗口层保留固定大小的旋转缓存。
  • 最后一个全注意力层默认保持不量化——深度靠后的层对数值更敏感。

6.4 官方实测数据

官方在 gemma-4-26b-a4b-it、20K 上下文上测过(来源:仓库 PR #1030):

配置生成速度KV Cache 占用压缩倍数
不量化50.3 tok/s0.624 GB1x
Uniform 8-bit52.6 tok/s0.469 GB1.33x
TurboQuant 3.5-bit25.6 tok/s0.365 GB1.71x

值得注意:这篇实测是 MoE 模型,滑动窗口多,压缩倍数不算高。纯全注意力模型(Qwen、LLaMA 这类)压缩空间大得多,官方说明称 8-bit 可达约 3.6x、4-bit 可达约 6.4x。同时 TurboQuant 明显降速(25.6 vs 50.3),换来的内存上限要按场景权衡。

README 对长上下文场景给出的总体结论是约 76% 的内存削减。这些数字来自仓库维护者,不同模型和上下文长度会变化,应以实测为准。

6.5 用法

python -m mlx_vlm.server \
  --model google/gemma-4-26b-a4b-it \
  --kv-bits 3.5 \
  --kv-quant-scheme turboquant

选量化前先问自己缺的是内存还是速度:内存紧张、要超长上下文,TurboQuant;要吞吐,Uniform 或干脆不量化,配大内存。


7. LoRA / QLoRA 微调

7.1 为什么用 LoRA

VLM 权重动辄几十亿参数,全量微调在本地不现实。LoRA 只给权重加少量低秩适配器,可训练参数占比小,配合量化(即 QLoRA)能进一步压低内存,是本地微调的主要路径。

7.2 数据格式

用 Hugging Face 的 datasets,每行包含两个关键字段:

  • 图像/音频列:放媒体路径或 URL
  • messages 列:对话格式,含 role 与 content

需要多轮、带媒体的样本时,把角色和媒体按模型模板组织好。

7.3 训练

仓库提供一个 lora.py 脚本(或 mlx_vlm.train 模块)。典型调用:

python -m mlx_vlm.train \
  --model mlx-community/Qwen3-VL-2B-Instruct-bf16 \
  --dataset your-custom-dataset \
  --batch-size 2 \
  --epochs 2 \
  --learning-rate 2e-5 \
  --lora-rank 8 \
  --output-path ./my-lora-adapter.safetensors

要动视觉塔,加 --train-vision;要省显存,可配合梯度检查点。数据集规模和批次按内存调整。

7.4 使用微调后的适配器

推理时把适配器传进 load:

from mlx_vlm import load, generate

model, processor = load(
    "mlx-community/Qwen3-VL-2B-Instruct-bf16",
    adapter_path="./my-lora-adapter.safetensors",
)
output = generate(model, processor, "描述这张图片", image=["image.jpg"])
print(output)

8. 服务器部署

8.1 启动

python -m mlx_vlm.server \
  --model mlx-community/Qwen2-VL-2B-Instruct-4bit \
  --port 8080

不给 --model 也行,在第一个请求到达时再加载。

8.2 接口

服务器提供 /v1/chat/completions/responses(兼容 OpenAI),另有 /health 做健康检查。特性包括:

  • 连续批处理(Continuous Batching):并发请求共享批
  • 自动前缀缓存(APC):复用相同提示词前缀
  • KV Cache 量化(见第 6 节)
  • 视觉特征缓存(见第 5 节)
  • logprob 输出:/chat/completions 支持 logprobs 参数

8.3 调用示例

curl http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "mlx-community/Qwen2-VL-2B-Instruct-4bit",
    "messages": [
      {"role": "user", "content": "描述这张图片"}
    ]
  }'

Python 侧直接接 OpenAI SDK 即可,把 base_url 指到本地。


9. 安装与配置

9.1 系统要求

  • Apple Silicon 芯片(M1 及以上)
  • macOS 13 或更新版本
  • Python 3.9 或更新版本
  • 统一内存足够容纳所选模型与上下文

9.2 安装

pip install -U mlx-vlm

或从源码安装最新功能:

git clone https://github.com/Blaizzy/mlx-vlm.git
cd mlx-vlm
pip install -e .

9.3 验证

python -m mlx_vlm.generate --help

能打印出参数说明即安装成功。跑通一次图像理解,再确认网络能访问 Hugging Face(首次会下载权重)。


10. 实践建议

10.1 选模型:按内存

  • 16 GB 起步Qwen2-VL-2B-Instruct-4bit、Moondream、SmolVLM 这类 4-bit 小模型
  • 24 GB 以上Qwen2.5-VL-7B-Instruct-4bit、Pixtral-12B
  • 64 GB 以上:能跑更大的 Qwen、Gemma-4 或 MoE 模型,配合量化

具体上限要看量化位宽和上下文长度,落地前在自己机器上实测一次内存峰值。

10.2 内存紧张时

  • 优先用 mlx-community 的量化权重
  • 长上下文用 KV Cache 量化(第 6 节)
  • 多轮多图开视觉特征缓存(第 5 节)

10.3 吞吐优先时

  • 服务器接 OpenAI SDK,启用连续批处理和前缀缓存
  • 上下文不大就少用 TurboQuant,它省内存但降速

11. 常见问题与排查

模型加载失败

多半是网络或模型 ID 问题。检查能否访问 Hugging Face;把模型显式下到本地,再从本地路径加载;核对 ID 写在 mlx-community/ 下。

内存不足(OOM)

先用更小的量化模型,缩短上下文,再考虑 KV Cache 量化;多轮会话清理未用的视觉缓存。

多轮对话很慢

确认走了视觉特征缓存,并复用了同一批图像。图片尺寸越大,复用的收益越大。

生成速度慢

检查是否启用了量化、是否有其他进程占用 GPU;长上下文下 TurboQuant 也会明显降速。


12. 总结

MLX-VLM 把 Apple Silicon 上跑 VLM 和 Omni 模型这件事做成了“装上就能用”:50+ 架构、预量化权重、LoRA/QLoRA 微调、OpenAI 兼容服务器。三个调优点对应三种瓶颈:视觉特征缓存治多轮重复编码,KV Cache 量化治长上下文内存,量化权重治模型过大。它们的取舍都指向同一件事——你的统一内存和期望的响应速度落在哪里。

相关资源:

  • 仓库:https://github.com/Blaizzy/mlx-vlm
  • 预量化权重:https://huggingface.co/mlx-community
  • 问题反馈:https://github.com/Blaizzy/mlx-vlm/issues

自测题

回答下面 5 个问题,检验你的理解:

  1. MLX 的“统一内存”为什么能降低运行 VLM 的门槛?它在 CPU/GPU 分工上解决的是什么问题?
  2. 视觉特征缓存解决哪种场景的浪费?它用 --vision-cache-size 控制什么?
  3. Uniform 与 TurboQuant 的 KV Cache 量化各有什么取舍?TurboQuant 的位宽构成是什么?
  4. 一台 16 GB 内存的 Mac,你倾向先试哪个模型?为什么?
  5. MLX-VLM 的服务器提供哪些 OpenAI 兼容端点?continuous batching 和自动前缀缓存各自有什么用?
参考答案

题 1:统一内存让 CPU 和 GPU 共享同一块物理内存,模型权重不必在两者之间搬运。这样显卡显存堆不下的多模态模型,可以整块驻留在 Mac 的统一内存里运行,也省去了跨 PCIe 传输的时间。

题 2:它针对“同一批图像在多轮或多图对话里被重复做视觉编码”的浪费。命中缓存的图像直接复用已编码特征,跳过视觉塔。--vision-cache-size 控制缓存条数,默认 20。

题 3:Uniform(通常 8-bit)量化均匀,速度影响小;TurboQuant(3.5-bit,3-bit keys + 4-bit values)压缩更狠、省更多内存,但会明显降速(官方实测 20K 上下文中约匀速的一半)。内存紧张选 TurboQuant,吞吐优先选 Uniform。

题 4:先试小规模 4-bit 模型,如 Qwen2-VL-2B-Instruct-4bit。权重小、容易跑通,可作为后续选型的基线。

题 5/v1/chat/completions/responses/health。continuous batching 让并发请求共享一个批,提高吞吐;自动前缀缓存(APC)复用相同提示词前缀的计算,减少重复处理。


练习

  1. 环境搭建:按第 9 节完成安装,跑通一次 generate --help 和一次图像理解。
  2. 多模态对比:用同样的图片分别测 Qwen2-VL-2B 和 Moondream 的生成质量与速度。
  3. 多轮对话:不带和带视觉特征缓存各跑两轮,对比第二轮耗时。
  4. KV Cache 量化:在 gemma-4-26b-a4b-it 上分别用不量化、Uniform 8-bit、TurboQuant 3.5-bit 跑长上下文,对比内存峰值与 tok/s。
  5. 部署:启动服务器,用 Python 的 requests 或 OpenAI SDK 调用一次 /v1/chat/completions

进阶路径

阶段 1:跑通基础(1-2 天)

  • 安装并跑通图像、音频示例
  • 记录自己的 Mac 内存峰值,建立选型基线

阶段 2:调优(3-5 天)

  • 给多轮对话加视觉特征缓存,量化验证加速
  • 对比 KV Cache 三种配置在长上下文下的显存与速度
  • mlx_vlm/ 源码,理解 load 与 generate 的加载流程

阶段 3:部署与微调(1-2 周)

  • 服务器 + OpenAI SDK 接入现有应用
  • 用 LoRA 调一个自己的垂直模型,并用 adapter_path 加载

阶段 4:深入原理(2-4 周)

  • 对照 mlx 源码理解 KV Cache 量化与 Metal 内核实现
  • 读 MLX 的算子与内存管理,理解统一内存的边界
  • 尝试给仓库提 PR 或补新模型适配

参与讨论

使用 GitHub 登录。欢迎补充事实、异议与实践。