mlx_lm.convert 转换 HuggingFace 模型失败

在 Apple Silicon 上用 mlx_lm.convert 把 HuggingFace 模型转成 MLX 时报错:Model type not supported、GatedRepoError 401 或内存不足 OOM。修复步骤已于 2026 年 6 月核实。

在 Apple Silicon Mac 上执行 mlx_lm.convert --hf-path meta-llama/Llama-3.1-8B-Instruct --mlx-path ./mlx-llama31-8b -q,通常会以三种方式失败:报 ValueError: Model type X not supported(往往同时出现 No module named 'mlx_lm.models.X');下载时报 GatedRepoError: 401 Client Error;或者进程跑到接近结束时卡住,被 macOS 以内存不足(OOM)杀掉。

mlx-lm(Apple MLX 框架之上的大模型推理层)为每个支持的架构都内置了一个明确的 Python 类。所以一旦模型比你装的版本新、仓库是 gated 而你没登录、或者未量化权重在量化前装不进统一内存,转换就会失败。

最快修复(覆盖大多数情况):先 pip install --upgrade mlx-lm mlx 升级;gated 仓库(Llama、Gemma、部分 Mistral)用 hf auth login 登录;然后重跑。如果架构太新、PyPI 正式版仍不支持,就从 GitHub 安装 mlx-lm。如果 Mac 内存不够,干脆别本地转换,直接从 mlx-community 拉一个已转好的模型。截至 2026 年 6 月,mlx-lm 当前版本是 0.31.3(2026 年 4 月 22 日发布)。

先判断你属于哪一类

屏幕上的报错最可能的原因跳到
ValueError: Model type X not supported / No module named 'mlx_lm.models.X'你装的 mlx-lm 没有该架构Step 1
GatedRepoError401 Client ErrorYou are trying to access a gated repo未登录 / 访问权限未批准Step 2
跑到接近 100% 卡住,然后 Killed: 9 或转圈 + OOM未量化权重超出统一内存Step 3
No such file / 缺少分片 model-0000N-of-...safetensors下载中断,缓存不完整Step 4
Error while deserializing / 目录里只有 pytorch_model.bin仓库只提供 PyTorch pickle,没有 safetensorsStep 5
ImportError: cannot import name ... from 'mlx.core'mlxmlx-lm 版本不匹配Step 6

常见原因

按命中率从高到低排列。

1. mlx-lm 没有这个架构的实现类

mlx-lmmlx_lm/models/ 下为每个架构放一个模块,并按仓库 config.json 里的 model_type 字段去匹配。找不到对应模块时,加载器就报 ValueError: Model type X not supported,常常还带 No module named 'mlx_lm.models.X'。这是最常见的失败,而且总是先砸到新模型头上:2025-2026 年间,qwen3_moeminimaxgemma4_unifiedminicpmv 等架构在被支持之前都报过这个错。

怎么判断:查模型的 model_type,再和你的安装对比:

python3 -c "
import os, mlx_lm.models as m
d = os.path.dirname(m.__file__)
print(sorted(f[:-3] for f in os.listdir(d) if f.endswith('.py') and not f.startswith('_')))
"

如果 model_type 不在这个列表里,你装的 mlx-lm 就转不了它。先升级(Step 1);如果该架构只在 main 分支落地,就从 GitHub 安装。

2. gated 仓库未认证

Llama 3.x、Gemma 以及部分 Mistral 仓库是 gated 的:你必须先在模型页接受许可协议,并且处于登录状态。没有有效 token 时,mlx_lm.convert 会在下载阶段失败,报 GatedRepoError401 Client Error,或 Cannot access gated repo ... You are trying to access a gated repo. Make sure to request access

怎么判断:执行 hf auth whoami。如果输出 Not logged in,问题就在这。注意 CLI 已在 2025 年中从 huggingface-cli 改名为 hf;老的 huggingface-cli login/whoami 仍可用,但会打印一条弃用提示,引导你改用 hf auth ...

3. OOM —— 全精度权重在量化前装不下

mlx_lm.convert 会先按权重的存储精度加载(即 config.json 里的 torch_dtype,现代 Llama/Qwen/Mistral/Gemma 一般是 bfloat16),再做量化。所以峰值内存由 bf16 体积决定,而不是 fp32。粗算:bf16 体积(GB)约等于参数量(十亿)乘以 2(每个权重 2 字节)。一个 70B 模型 bf16 约 140 GB,转换时还要在此之上留余量,因此在 128 GB 的 Mac 上会 OOM,只有 192 GB 及以上的 Studio/Ultra 才装得下。macOS 会杀掉进程(Killed: 9)或卡进转圈。

怎么判断:转换前在 Activity Monitor(内存标签页,看 Memory Pressure/内存压力)或 vm_stat 查看可用内存;运行卡住时,vm_stat 1 显示 Pageouts 大量且持续增长,就说明内存耗尽了。

4. 分片模型没下完整

大仓库会把权重拆成 model-00001-of-0000N.safetensors 多个分片。下载中断会导致部分分片缺失;转换器加载完前几个分片后,会在缺失文件上失败。

怎么判断:把磁盘上的分片和清单对比。仓库的 model.safetensors.index.json 列出了所有应有的分片:

ls ~/.cache/huggingface/hub/models--*/snapshots/*/model-*.safetensors | wc -l

如果这个数小于 index.json 里引用的分片数,就重新下载(Step 4)。

5. 仓库只有 PyTorch pickle,没有 safetensors

一些较老或自定义的仓库只含 pytorch_model.bin(Python pickle),没有 model.safetensorsmlx_lm.convert 期望的是 safetensors;只有 .bin 时可能加载失败,或在意外的权重键名上失败。(注意:mlx_lm.convert 完全不接受 GGUF 作为输入,详见 FAQ。)

怎么判断ls ~/.cache/huggingface/hub/models--*/snapshots/*/ —— 如果看到 pytorch_model*.bin 而没有 *.safetensors,先把权重转成 safetensors(Step 5)。

6. mlx 与 mlx-lm 版本不匹配

mlx-lm 会锁定一个兼容的核心 mlx 版本范围。只升级其中一个,可能导致导入失败或结果错误。

怎么判断ImportError: cannot import name 'X' from 'mlx.core' 就是信号。执行 pip show mlx mlx-lm,并把两者一起升级(Step 1)。

最短修复路径

Step 1:把 mlx-lm 和 mlx 一起升级

# 两个一起升,保持版本兼容
pip install --upgrade mlx-lm mlx

# 确认安装版本(截至 2026 年 6 月为 0.31.3)
python3 -c "import mlx_lm; print(mlx_lm.__version__)"

# 确认你的架构现在有对应模块
python3 -c "
import os, mlx_lm.models as m
d = os.path.dirname(m.__file__)
print(sorted(f[:-3] for f in os.listdir(d) if f.endswith('.py') and not f.startswith('_')))
"

如果该架构只在 main 分支落地、PyPI 正式版还没收录,就装开发版:

pip install --upgrade "mlx-lm @ git+https://github.com/ml-explore/mlx-lm.git"

Step 2:为 gated 仓库做 HuggingFace 认证

# 新版 CLI(huggingface-cli 仍可用但已弃用)
hf auth login
# 粘贴 https://huggingface.co/settings/tokens 上的 token(read 权限即可)

# 验证已登录
hf auth whoami

# gated 模型还必须在模型页接受许可,例如
# https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct  -> 点 "Agree and access"

如果 hf auth whoami 成功但仍报 401,说明这个具体仓库的访问申请尚未批准 —— 审批可能要几分钟到几天。确认模型页上出现绿色的 “You have been granted access” 横幅。

Step 3:带量化转换,并选一个能装下的 dtype

-q(即 --quantize)默认产出 4-bit 模型(group size 64,affine 量化),这是内存占用最小的输出。但转换仍会先加载源权重,所以 bf16 体积是你的下限。

# 8B 模型:一步转换并量化到 4-bit
mlx_lm.convert \
  --hf-path meta-llama/Llama-3.1-8B-Instruct \
  --mlx-path ./mlx-llama31-8b-4bit \
  -q --q-bits 4 --q-group-size 64

# 如果要不量化的输出,但用更小的 dtype 省空间:
mlx_lm.convert \
  --hf-path meta-llama/Llama-3.1-8B-Instruct \
  --mlx-path ./mlx-llama31-8b-bf16 \
  --dtype bfloat16

如果某模型 bf16 能转、但一加 -q 就失败,说明问题在量化步骤而非架构支持 —— 试试 --q-group-size 32,或者干脆不量化、跑 bf16。

如果 bf16 权重根本装不进你的统一内存,就别在本地转了。从 mlx-community 下载已转好的 MLX 模型(Step 6),或者换台内存更大的机器做量化。

Step 4:转换前先下完所有分片

# 提前把每个分片都拉下来,这样即便中断也不会留下半截缓存
python3 << 'EOF'
from huggingface_hub import snapshot_download
snapshot_download(
    "meta-llama/Llama-3.1-8B-Instruct",
    local_dir="./llama31-8b-hf",
    ignore_patterns=["*.msgpack", "*.h5", "*.bin"],  # 只要 safetensors
)
print("Download complete")
EOF

# 然后从本地目录转换
mlx_lm.convert \
  --hf-path ./llama31-8b-hf \
  --mlx-path ./mlx-llama31-8b-4bit \
  -q --q-bits 4

Step 5:先把 PyTorch .bin 权重转成 safetensors

pip install safetensors torch

python3 << 'EOF'
from safetensors.torch import save_file
import torch, os

model_path = "./model-path"
for f in os.listdir(model_path):
    if f.endswith(".bin"):
        sd = torch.load(f"{model_path}/{f}", map_location="cpu")
        out = f.replace(".bin", ".safetensors")
        save_file(sd, f"{model_path}/{out}")
        print(f"Converted {f} -> {out}")
EOF

转好后,把 --hf-path 指向包含新 .safetensors 文件的本地目录。

Step 6:跳过转换 —— 直接拉已转好的 MLX 模型

如果转换一直跟你较劲(架构不支持、OOM、gated 访问),HuggingFace 上的 mlx-community 组织已经发布了数千个预转换的 MLX 模型。mlx_lm.generatemlx_lm.load 会在首次使用时自动下载:

# 4-bit(占用最小)
mlx_lm.generate \
  --model mlx-community/Llama-3.1-8B-Instruct-4bit \
  --prompt "你好" --max-tokens 200

# 8-bit(质量更高,体积更大)
mlx_lm.generate \
  --model mlx-community/Llama-3.1-8B-Instruct-8bit \
  --prompt "你好" --max-tokens 200

如何确认已修复

对转换后的目录跑一次快速生成,再检查权重是否真的被量化了:

# 1. 应当产出连贯文本,而非乱码或报错
mlx_lm.generate --model ./mlx-llama31-8b-4bit --prompt "说出三种原色。" --max-tokens 30

# 2. 确认量化确实生效(4-bit 模型会带 quantization 配置)
python3 -c "
import json, glob
cfg = json.load(open(glob.glob('./mlx-llama31-8b-4bit/config.json')[0]))
print('quantization:', cfg.get('quantization'))
"

如果 quantizationNone,说明 -q 没生效、模型是全尺寸的 —— 带 -q 重跑 Step 3。

预防建议

  • requirements.txt 里把 mlx-lmmlx 一起固定,并同时升级;单独升 mlxImportError 的常见来源。
  • 转换全新模型前,先在 mlx-lm 的 GitHub issues 里搜它的 model_type —— 不支持的架构通常都有 issue 跟踪,并注明在哪个版本加入支持。
  • 长时间转换前先跑一遍 hf auth whoami,免得 token 过期、白下载半小时。
  • 提前估算内存:bf16 体积(GB)约等于参数量(十亿)乘以 2。若超过你的空闲统一内存,就别本地转,直接从 mlx-community 拉预转换模型。
  • snapshot_download 在转换前下完所有分片,避免中断留下半截缓存。
  • 转换后先跑一次短生成测试,并确认 config.json 里量化字段符合预期,再删除 HuggingFace 源权重。

常见问答 (FAQ)

Q: 能用 mlx_lm.convert 把 GGUF 转成 MLX 吗? A: 不能 —— 它只接受 HuggingFace safetensors(或 PyTorch .bin)作为输入,不接受 GGUF。你得先用 llama.cpp 的转换脚本把 GGUF 还原成 HuggingFace 仓库,再跑 mlx_lm.convert,这意味着二次量化和质量损失。几乎总是更划算的做法是:下载原始 safetensors 仓库,或者直接从 mlx-community 拉预转换模型。

Q: 升级后仍报 ValueError: Model type X not supported,怎么办? A: PyPI 正式版可能落后 main 好几周。用 pip install --upgrade "mlx-lm @ git+https://github.com/ml-explore/mlx-lm.git" 装开发版。如果 main 也不支持,说明该架构还没被移植 —— 去 GitHub issues 看进度,期间先用 llama.cpp/Ollama 跑 GGUF 版本。

Q: 在 Apple Silicon 上,MLX 4-bit 比 bf16 慢多少? A: 4-bit 模型每 token 的吞吐通常低于 bf16,因为有反量化开销;但 4-bit 往往是唯一装得下的选项。一个 13B 模型 bf16 约 26 GB、4-bit 约 7-8 GB,所以在 16 GB 的 Mac 上只有 4-bit 能加载。

Q: 转换后的模型能跑但很慢,为什么? A: 先确认它真的被量化了。按「如何确认已修复」里的 config.json 检查跑一遍。如果 quantizationNone,说明漏了 -q、你在跑全精度权重;带 -q --q-bits 4 重转。也要确认没有其他 App 把你顶进内存压力、强制换页。

Q: 是不是每个模型都得登录? A: 不用。hf auth login 只需存一次 token。只有 gated 仓库(Llama、Gemma、部分 Mistral)才需要逐个申请访问。像大多数 mlx-communityQwen 这类开放仓库完全不用登录。

相关阅读

标签: #local-llm #mlx #排查