在 MacBook Pro M5 Max 128GB 上,从 lordx64 的 Claude 4.7 Opus reasoning 蒸馏版出发,用 oMLX 生成 6 档(VLM × 3 + Text × 3)混合精度量化模型,并发布到 HuggingFace。
🎯 目标产物
| 产物 | 模态 | 量化级别 | 大小 | HF 链接 |
|---|---|---|---|---|
| VLM-MLX-oQ4 | 图文 | oQ4 (~4.8 bpw) | 19.6 GB | hf.co/wangkezun/…VLM-MLX-oQ4 |
| VLM-MLX-oQ6 | 图文 | oQ6 (~6.5 bpw) | 27 GB | hf.co/wangkezun/…VLM-MLX-oQ6 |
| VLM-MLX-oQ8 | 图文 | oQ8 (~8.7 bpw) | 35 GB | hf.co/wangkezun/…VLM-MLX-oQ8 |
| Text-MLX-oQ4 | 纯文本 | oQ4 | 19 GB | hf.co/wangkezun/…Text-MLX-oQ4 |
| Text-MLX-oQ6 | 纯文本 | oQ6 | 27 GB | hf.co/wangkezun/…Text-MLX-oQ6 |
| Text-MLX-oQ8 | 纯文本 | oQ8 | 34 GB | hf.co/wangkezun/…Text-MLX-oQ8 |
总数据量 162 GB(量化产物) + 102 GB(中间产物)= 264 GB
📚 关键概念
oMLX 的 oQ 量化
oMLX 是 jundot 开发的 MLX 推理服务,提供独家的 oQ 系列混合精度量化:
- oQ4 / oQ6 / oQ8:表示平均比特数(4.8 / 6.5 / 8.7 bpw),不是固定值
- 混合精度策略:根据 sensitivity model 打分,对每个权重分配不同 bit 数
- 高分权重(推理路径关键) → 保留 8bit
- 低分权重 → 激进压缩到 2-4bit
- vs mxfp8:mxfp8 是 OCP FP8 标准,固定 8bit + scale;oQ8 是平均 8.7bpw 的变长 INT 量化
Sensitivity Model 的作用
oQ 量化需要一个 sensitivity model 来指导量化策略,本质是”权重重要性参考”:
- 不用 sens → 退化为均匀量化,oQ4 等于普通 4bit AWQ
- 用 sens → 量化器知道哪些权重对推理路径重要,混合精度按重要性分配
oMLX 限制:sensitivity model 下拉只识别 MLX 量化版(不是 BF16 full-precision)。所以即使想用 BF16 模型作 sens,也必须先量化成 8bit。
VLM vs Text-Only
Qwen3.6-35B-A3B 本身是 VLM(image-text-to-text),但 oMLX 量化时可以选择 Text Only 模式:
- 关 Text Only → 保留 vision tower → VLM 量化产物
- 开 Text Only → 剥离 vision tower → 纯文本量化产物
两者文件大小差距很小(< 1 GB),因为 vision tower 参数占整个模型不到 2%。但纯文本版推理速度快约 10%(少了 vision 计算路径)。
🎯 本次量化的配置选择
选定配置
| 角色 | 选择 | 用途 |
|---|---|---|
| 源模型 | lordx64/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled | 被量化的对象(产物来自它) |
| Sensitivity | 同蒸馏版的 8bit MLX 量化 | 量化决策的权重重要性参考 |
| dtype | bfloat16 | M5 Max 在 BF16 上更稳定 |
| 量化档位 | oQ4 / oQ6 / oQ8 | 覆盖低中高 3 档 |
| 模态 | VLM + Text-Only 各做一份 | 两种使用场景 |
为什么源选蒸馏版
蒸馏版(lordx64)已经是从 Claude 4.7 Opus reasoning 数据 LoRA 微调过的模型,回答时会带 <think> 思考标签,符合 Claude Code、AstrBot 等场景的预期使用习惯。
如果想要保留 Qwen3.6 原始通用能力(比如最纯净的中文创作),可以另外做一份基于官方原版 Qwen/Qwen3.6-35B-A3B 的量化——本次没做,但流程一致,未来可以补。
为什么 sens 用同模型 8bit
oMLX 要求 sens 是 MLX 量化版,所以不能直接用 BF16 蒸馏版作 sens。把蒸馏版量化到 8bit 作 sens 有几个考虑:
- 架构 100% 对齐源模型,分布偏移最小
- 同时做 reasoning 蒸馏的偏向(高 sens 分数集中在 reasoning 路径)
- 不需要找其他兼容模型
如果未来 lordx64 出新版本但官方 Qwen3.6 不变,可以复用同样的 sens 流程。
为什么做 6 档(VLM × 3 + Text × 3)
| 用途 | 推荐版本 |
|---|---|
| Claude Code 主力 | Text-oQ4 / Text-oQ6 |
| AstrBot 后端(图文兼容) | VLM-oQ4 / VLM-oQ6 |
| 高质量参考基线 | VLM-oQ8 / Text-oQ8 |
| 内存紧张场景 | oQ4 系列 |
| 性价比首选 | oQ6 系列 |
不同场景灵活切换。每档量化只需 30 分钟,总磁盘 ~162 GB,成本可接受。
🛠️ 环境准备
工具栈
# Python 工具用 uv tool 隔离
uv tool install mlx-lm
uv tool install mlx-vlm --with torch --with torchvision
uv tool install --with hf_transfer --reinstall huggingface-hub
# oMLX 通过 Homebrew
brew tap jundot/omlx
brew install omlx关键环境变量
# HF 加速下载(国内可选)
export HF_ENDPOINT=https://hf-mirror.com
# HF 上传加速(必装,能跑到 50+ MB/s)
export HF_HUB_ENABLE_HF_TRANSFER=1📋 完整步骤
阶段 0:清理 + 工具升级
# 升级 mlx-vlm 到最新版(v0.4.4+)
uv tool upgrade mlx-vlm
# 清理之前用 mlx_lm.convert 转的产物(丢了 vision tower,无用)
rm -rf ~/.cache/huggingface/models/wangkezun/Qwen3.6-35B-A3B-Claude-4.7-Opus-Distilled-MLX-BF16
rm -rf ~/.cache/huggingface/models/wangkezun/MLX-Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-8bit阶段 1:转换源模型(BF16 VLM)
mlx_vlm.convert \
--hf-path /Users/wangkezun/.cache/huggingface/models/lordx64/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled \
--mlx-path /Users/wangkezun/.cache/huggingface/models/wangkezun/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-MLX-BF16 \
--dtype bfloat16耗时:~10 分钟 产物:~67 GB 峰值内存:~80 GB
阶段 2:转换 Sensitivity Model(8bit VLM)
mlx_vlm.convert \
--hf-path /Users/wangkezun/.cache/huggingface/models/lordx64/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled \
--mlx-path /Users/wangkezun/.cache/huggingface/models/wangkezun/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-MLX-VLM-8bit \
--quantize \
--q-bits 8 \
--dtype bfloat16耗时:~15 分钟 产物:~35 GB
阶段 3:验证转换
python3 -c "
import json
path = '/path/to/model'
with open(path + '/model.safetensors.index.json') as f:
keys = list(json.load(f)['weight_map'].keys())
vision = [k for k in keys if 'vision' in k.lower() or 'visual' in k.lower()]
print(f'Total: {len(keys)}, Vision: {len(vision)}')
"预期:Vision keys ~333(Qwen3.6 ViT 块数)
阶段 4:oMLX 量化(6 次)
打开 oMLX → 模型管理器 → 重新加载(确保识别新转的两个模型)。
进 oQ 量化页面,6 次任务的通用配置:
| 项 | 值 |
|---|---|
| 源模型 | Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-MLX-BF16 |
| Sensitivity | Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-MLX-VLM-8bit |
| Non-quant dtype | bfloat16 |
每次只改两个开关:
| # | oQ 级别 | Text Only | 单次耗时 | 产物大小 |
|---|---|---|---|---|
| 1 | oQ4 | 关 | ~30 min | 19.6 GB |
| 2 | oQ6 | 关 | ~30 min | 27 GB |
| 3 | oQ8 | 关 | ~30 min | 35 GB |
| 4 | oQ4 | 开 | ~30 min | 19 GB |
| 5 | oQ6 | 开 | ~30 min | 27 GB |
| 6 | oQ8 | 开 | ~30 min | 34 GB |
每次产物名相同(...-MLX-oQ4/oQ6/oQ8),跑完立刻改名加 -VLM- 或 -Text- 区分:
# VLM 版改名
mv ~/.omlx/models/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-MLX-oQ4 \
~/.omlx/models/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-VLM-MLX-oQ4
# Text 版改名
mv ~/.omlx/models/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-MLX-oQ4 \
~/.omlx/models/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-Text-MLX-oQ4阶段 5:补全 VLM processor 配置
每次量化后必须补 VLM processor 文件(参见 坑 3:lordx64 蒸馏版本身缺 VLM processor 配置):
SRC=~/.cache/huggingface/models/wangkezun/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-MLX-BF16
DST=~/.omlx/models/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-VLM-MLX-oQ4
cp -Lvn $SRC/processor_config.json $DST/
cp -Lvn $SRC/video_preprocessor_config.json $DST/阶段 6:上传到 HuggingFace
# 登录(一次性)
hf auth login
# 加速
export HF_HUB_ENABLE_HF_TRANSFER=1
# 单个上传
hf upload \
wangkezun/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-VLM-MLX-oQ4 \
~/.omlx/models/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-VLM-MLX-oQ4 \
--commit-message "Initial upload: VLM oQ4 quantization"阶段 7:备份到 NAS
NAS_ROOT=/Volumes/nas/omlx-models
mkdir -p $NAS_ROOT/{quants,intermediate}
# 备份 6 个量化产物
rsync -avh --progress --size-only \
~/.omlx/models/ \
$NAS_ROOT/quants/
# 备份 BF16 源 + 8bit sens
rsync -avh --progress --size-only \
~/.cache/huggingface/models/wangkezun/ \
$NAS_ROOT/intermediate/阶段 8:清理本地中间产物
rm -rf ~/.cache/huggingface/models/wangkezun/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-MLX-BF16
rm -rf ~/.cache/huggingface/models/wangkezun/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-MLX-VLM-8bit释放约 102 GB。
🐛 踩过的坑
坑 1:mlx_lm.convert 不能转 VLM
最初尝试用 mlx_lm.convert 转 lordx64 蒸馏版,转换”成功”但视觉塔丢失:
Total: 733, Vision: 0 ❌
原因:mlx-lm 是纯 LM 工具,看到 vision tower 直接丢弃。
解决:必须用 mlx-vlm 包,它专门处理 VLM 架构。mlx_vlm.convert 转完后 Vision: 333 ✅
坑 2:mlx-vlm 缺 torch/torchvision 依赖
第一次跑 mlx_vlm.convert 报错:
ImportError: Qwen3VLVideoProcessor requires the Torchvision library
原因:Qwen3.6 的 processor 需要 torchvision 处理视频帧。mlx-vlm 包默认没声明这个依赖。
解决:
uv tool install --with torch --with torchvision --reinstall mlx-vlm坑 3:lordx64 蒸馏版本身缺 VLM processor 配置
oMLX 量化产物运行 mlx_vlm.generate 时报错:
OSError: Can't load image processor ... preprocessor_config.json
根本原因链:
lordx64上传蒸馏版时漏了preprocessor_config.json(可能是 unsloth 训练后保存疏漏)mlx_vlm.convert不会主动从基座补这个文件oMLX量化产物只复制 BF16 源里有的文件- → 一路传染,量化产物缺关键 VLM 配置
解决:从官方 Qwen/Qwen3.6-35B-A3B 借这几个文件,并先补到 BF16 源里(让后续量化能继承):
OFFICIAL=~/.cache/huggingface/models/Qwen/Qwen3.6-35B-A3B
DST=~/.cache/huggingface/models/wangkezun/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-MLX-BF16
# 注意 -L 跟随软链接,否则 hfd 下载是 symlink
cp -Lv $OFFICIAL/preprocessor_config.json $DST/
cp -Lv $OFFICIAL/video_preprocessor_config.json $DST/
cp -Lv $OFFICIAL/generation_config.json $DST/但 oMLX 仍只会自动复制部分文件(白名单机制)。具体行为:
| 文件 | oMLX 自动复制? |
|---|---|
chat_template.jinja | ✅ |
tokenizer.json / tokenizer_config.json | ✅ |
config.json | ✅ |
preprocessor_config.json | ✅(如果源里有) |
generation_config.json | ✅ |
processor_config.json | ❌ |
video_preprocessor_config.json | ❌ |
每次量化后都要手动补这两个文件:
cp -Lvn $SRC/processor_config.json $DST/
cp -Lvn $SRC/video_preprocessor_config.json $DST/坑 4:oMLX 命名冲突
oMLX 量化产物默认命名 {源名}-oQ4,VLM 和 Text Only 两次量化会输出同名,第二次会覆盖第一次。
解决:每次量化跑完立刻 mv 改名加 -VLM- 或 -Text- 标识,避免下次量化覆盖。
坑 5:sens model 必须是 MLX 量化版
oMLX 的 sensitivity model 下拉只识别已量化的 MLX 格式,BF16 full-precision 模型选不上。
解决:必须先做一份 8bit 量化版作 sens(阶段 2),不能直接用 BF16 源。
坑 6:fp16 vs bf16 选择
oMLX 提供两个选项:
- float16:M1/M2 prefill 快 ~20%(原生 FP16 加速)
- bfloat16:M3+ 更稳定,数值动态范围大
M5 Max 选 bfloat16 是对的(M3+ 的 fp16 红利消失,bf16 在量化场景更安全)。
坑 7:HF cache 软链接陷阱
hfd 和 hf download --local-dir 默认下载是软链接到 ~/.cache/huggingface/hub/... 的实际文件。直接 cp 会复制软链接本身,必须用 cp -L 才能复制实际内容。
# 错误:复制了软链接(目标移动后会失效)
cp $OFFICIAL/preprocessor_config.json $DST/
# 正确:跟随软链接复制实际文件
cp -L $OFFICIAL/preprocessor_config.json $DST/📊 实测性能对比
测试硬件:MacBook Pro M5 Max 128GB 测试图片:网络梗图(“核善的笑容”,Antony Starr 演 Homelander)
VLM 系列
| 档位 | 大小 | 内存 | Prompt t/s | Gen t/s | 知识识别 |
|---|---|---|---|---|---|
| oQ4 | 19.6 GB | 22 GB | 157 | 117 | ”金发男子”(泛泛) |
| oQ6 | 27 GB | 30 GB | 617 | 103 | 认出演员+剧+角色 |
| oQ8 | 35 GB | 39 GB | 637 | 96 | 同 oQ6(边际收益小) |
关键发现:oQ4 → oQ6 是质的飞跃(世界知识保留),oQ6 → oQ8 是量变。oQ6 是性价比最高档位。
Text 系列
| 档位 | 大小 | 内存 | Gen t/s |
|---|---|---|---|
| oQ4 | 19 GB | 20 GB | 127 |
| oQ6 | 27 GB | 28 GB | 112 |
| oQ8 | 34 GB | 37 GB | 103 |
Text 比 VLM 快 ~10%(少了 vision 计算路径)。
Vision keys 验证
VLM 系列:Total 2010, Vision 333
Text 系列:Total 1677, Vision 0 ✅ 视觉塔成功剥离
333 个 vision keys 是 Qwen3.6 ViT 的标准结构。
🗂️ 最终目录结构
本地:
~/.cache/huggingface/models/
├── Qwen/
│ └── Qwen3.6-35B-A3B/ # 官方原版(保留,可作未来量化源)
└── lordx64/
└── Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled/ # 蒸馏源(保留)
~/.omlx/models/
├── Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-VLM-MLX-oQ4
├── Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-VLM-MLX-oQ6
├── Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-VLM-MLX-oQ8
├── Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-Text-MLX-oQ4
├── Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-Text-MLX-oQ6
└── Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-Text-MLX-oQ8
NAS:
/Volumes/nas/
├── hf-models/ # hfd 管理的 HF 原版下载
└── omlx-models/ # 自转 + 量化产物
├── quants/ # 6 个最终量化产物(162 GB)
└── intermediate/ # BF16 源 + 8bit sens(102 GB)
HuggingFace:
huggingface.co/wangkezun/
├── Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled-VLM-MLX-oQ4
├── ...VLM-MLX-oQ6
├── ...VLM-MLX-oQ8
├── ...Text-MLX-oQ4
├── ...Text-MLX-oQ6
└── ...Text-MLX-oQ8
🔄 后续工作流(重做量化时)
如果将来 lordx64 出新版本(比如 v2 或 4.8 蒸馏),重做量化只需:
# 1. 更新蒸馏源
hf download lordx64/Qwen3.6-35B-A3B-Claude-X.X-Opus-Reasoning-Distilled \
--local-dir ~/.cache/huggingface/models/lordx64/...
# 2. 从 NAS 恢复 BF16 + 8bit sens(如果之前同源没变)
rsync -avh --progress /Volumes/nas/omlx-models/intermediate/ \
~/.cache/huggingface/models/wangkezun/
# 否则重新运行阶段 1 + 2 重新转换
# 3. 直接进 oMLX 跑量化(阶段 4)
# 4. 修复 processor 配置(阶段 5)
# 5. 上传 HF(阶段 6)💡 经验总结
- VLM 量化必须用 mlx-vlm,不要用 mlx-lm
- uv tool install 时记得
--with torch --with torchvision - 量化产物总要手动补
processor_config.json+video_preprocessor_config.json - oMLX 命名会撞,量化跑完立刻 mv 加标识
cp -L才能复制软链接的实际内容- dry-run rsync 是好习惯(
-n标志) - HF 上传必装
hf_transfer,速度提升 3-5 倍 - oQ6 是性价比拐点,质量逼近 oQ8,体积小 8GB
📎 相关链接
- 基座: Qwen/Qwen3.6-35B-A3B
- 蒸馏源: lordx64/Qwen3.6-35B-A3B-Claude-4.7-Opus-Reasoning-Distilled
- oMLX: https://omlx.ai
- mlx-vlm: https://github.com/Blaizzy/mlx-vlm
- mlx-lm: https://github.com/ml-explore/mlx-lm
- HF Hub: wangkezun’s profile
🏷️ 标签
mlx apple-silicon quantization omlx vlm qwen claude-distilled workflow completed