@tom_doerr: 在 16GB 内存 Mac 上运行 35B 模型 https://github.com/walter-grace/mac-code…

X AI KOLs Timeline 工具

摘要

该工具支持通过从 SSD 流式加载模型权重,在 16GB Mac 上运行 Qwen3.5-35B 等大型语言模型,经优化配置后最高可达 30 tok/s。

在 16GB 内存 Mac 上运行 35B 模型 https://t.co/LXrWOHZthu https://t.co/OXxdMFStfo
查看原文
查看缓存全文

缓存时间: 2026/05/11 18:52

可在 16GB 内存的 Mac 上运行 35B 参数模型 https://t.co/LXrWOHZthu https://t.co/OXxdMFStfo — # walter-grace/mac-code 来源:https://github.com/walter-grace/mac-code # mac code **在 Mac 上运行无法装入内存的模型。每月 0。** ## 我可以在我的 Mac 上运行吗? | 您的 Mac | 内存 | 可运行的内容 | 速度 | |----------|-----|-----------------|-------| | 任意 Mac | 8 GB | Qwen3.5-9B (Q4_K_M, 5.3 GB),4K 上下文 | 16-20 词/秒 | | 任意 Mac | 16 GB | Qwen3.5-9B (Q4_K_M, 5.3 GB),64K 上下文 | 16-20 词/秒 | | **Mac mini M4** | **16 GB** | **Qwen3.5-35B-A3B (IQ2_M, 10.6 GB)** | **30 词/秒** | | **Mac mini M4** | **16 GB** | **Qwen3-30B-A3B Q4 (17.2 GB) via Expert Sniper** | **4.3 词/秒** | | **Mac mini M4** | **16 GB** | **Qwen3.5-35B-A3B Q4 (19.5 GB) via Expert Sniper** | **5.4 词/秒** | | Mac mini M4 | 16 GB | Qwen3.5-35B-A3B Q4_K_M (22 GB) via Flash Streaming | 1.54 词/秒 | | Mac mini M4 | 16 GB | Qwen3.5-27B (16.1 GB) via Flash Streaming | 0.18 词/秒 | | Mac mini M4 Pro | 48 GB | 35B at full Q4 in RAM | 30+ 词/秒 | > **“我想在我的 16GB M2 上运行 Qwen 27B 但失败了。这不可能吧?”** > > 这是可能的。我们从 SSD 流式传输 FFN 权重——仅有 5.5 GB 驻留在内存中。输出连贯,全 4-bit 质量。虽然速度慢(Mac mini M4 上为 0.18 词/秒),但该方法适用于任何 16 GB Apple Silicon Mac。无需 2-bit 压缩,无 mmap 抖动,无交换空间耗尽崩溃。[查看工作原理](#how-flash-streaming-works) --- ## 快速开始 ### 35B 代理(推荐 —— 16 GB 下 30 词/秒)最快的选项。使用 llama.cpp 配合完全装入内存的 2-bit 量化 (IQ2_M)。 ``bash brew install llama.cpp pip3 install rich ddgs --break-system-packages # 下载模型 (10.6 GB) python3 -c " from huggingface_hub import hf_hub_download hf_hub_download('unsloth/Qwen3.5-35B-A3B-GGUF', 'Qwen3.5-35B-A3B-UD-IQ2_M.gguf', local_dir='HOME/models/’) “ # 启动服务器 + 代理 llama-server \ –model ~/models/Qwen3.5-35B-A3B-UD-IQ2_M.gguf \ –port 8000 –host 127.0.0.1 \ –flash-attn on –ctx-size 12288 \ –cache-type-k q4_0 –cache-type-v q4_0 \ –n-gpu-layers 99 –reasoning off -np 1 -t 4 python3 agent.py ### 9B 支持 64K 上下文bash python3 -c “ from huggingface_hub import hf_hub_download hf_hub_download(‘unsloth/Qwen3.5-9B-GGUF’, ‘Qwen3.5-9B-Q4_K_M.gguf’, local_dir=‘HOME/models/') " llama-server \ --model ~/models/Qwen3.5-9B-Q4_K_M.gguf \ --port 8000 --host 127.0.0.1 \ --flash-attn on --ctx-size 65536 \ --cache-type-k q4_0 --cache-type-v q4_0 \ --n-gpu-layers 99 --reasoning off -t 4 python3 agent.py `` --- ## Flash 流式传输 以完整质量运行**确实无法装入内存**的模型。无需 2-bit 压缩。无 mmap 抖动。 ### 实测结果 下方的所有数字均在 16 GB Mac mini M4 上测量。非估算值。 | 模型 | 总大小 | 内存占用 | 速度 | 质量 | |-------|-----------|---------|-------|---------| | Qwen3-32B (dense) | 18.4 GB | 4.5 GB | 0.15 词/秒 | 全 4-bit | | **Qwen3.5-27B (dense hybrid)** | **16.1 GB** | **5.5 GB** | **0.18 词/秒** | **全 4-bit** | | Qwen3-30B-A3B (MoE) | 17.2 GB | 8.7 GB | 4.3 词/秒 | 全 4-bit | | Qwen3.5-35B-A3B (MoE) | 19.5 GB | 8.7 GB | 5.4 词/秒 | 全 4-bit | 所有数字均在 16 GB M4 Mac Mini 上针对冷启动下的 5 个不同提示词测量。质量已验证(Canberra 数据集,8.3066 分,正确的 Python 代码等)。两款模型均使用:感知缓存的路由偏置 (1.0) + 共激活预取 + 合适大小的 LRU 缓存。bias=1.0 是通用的安全最大值——两款模型在 1.5 时质量都会下降。 ### 磁盘需求 | 模型 | 处理后大小 | 所需可用磁盘空间 | |-------|---------------|-----------------| | 30B / Coder-30B | 17 GB | ~20 GB | | 35B | 19 GB | ~25 GB | | 80B | 43 GB | ~50 GB | | 122B | ~65 GB | ~70 GB | | 235B | ~130 GB | ~140 GB | 对于更大的模型,请使用外部 NVMe 驱动器: ``bash mlx-sniper download qwen3-next-80b -o /Volumes/MySSD/qwen3-next-80b mlx-sniper run /Volumes/MySSD/qwen3-next-80b -p "hello" -v `` ### Flash 流式传输的工作原理 按访问模式拆分模型: **固定在内存中(4-6 GB):** 注意力权重、嵌入、归一化层、KV 缓存。加载一次,永久驻留。 **每 token 从 SSD 流式传输:** FFN 权重(模型的主体)。逐层加载,用于一次矩阵乘法,随即丢弃。内存永不增长。 `` 对于每个 token: 对于每一层: 1. 运行注意力计算(来自内存 —— 瞬间完成) 2. 从 SSD 加载 FFN 权重 (~165-221 MB) 3. 在 GPU 上运行 FFN 矩阵乘法 4. 丢弃 FFN 权重 —— 内存保持平稳 `` 对于 MoE 模型,第 2 步仅加载 8 个活跃专家 (~14 MB),而非全部 256 个。这就是为什么 MoE 快 10 倍的原因。 ### 运行 35B MoE 代理(1.54 词/秒,1.42 GB 内存) 交互式代理,支持网络搜索、Shell 命令和思维链。16 GB Mac 上的 22 GB 模型。 **需要预构建的流式文件** —— 参见 [`research/flash-streaming/`](research/flash-streaming/) 获取拆分/重建工具。 ``bash cd research/flash-streaming python3 moe_agent.py `` ### 在 16 GB 上运行 27B Dense(0.18 词/秒,5.5 GB 内存) ``bash cd research/flash-streaming pip3 install mlx-lm transformers --break-system-packages # 一次性操作:下载模型 (~16 GB) 并拆分以便流式传输 python3 -c " from huggingface_hub import snapshot_download snapshot_download('mlx-community/Qwen3.5-27B-4bit', local_dir='HOME/models/qwen35-27b-mlx-4bit’) “ python3 split_dense_27b.py # 运行 python3 flash_stream_27b.py ### 批处理联合专家 (Batched Union-of-Experts)(5.1 词/秒) 一个研究原型,在一次前向传播中验证 8 个 token。而不是为每个 token 单独加载专家,它计算所有 8 个 token 的活跃专家的集合并(每层约 27 个独特专家,而不是 64 个),并加载一次。bash cd research/flash-streaming python3 batched_moe.py 这是验证速度(检查草稿 token),而非生成速度。适用于推测解码。 --- ## 代理命令 | 命令 | 操作 | |---------|--------| | `/agent` | 代理模式(默认)—— 搜索、shell、聊天 | | `/raw` | 直接流式传输,无工具 | | `/search ` | 快速网络搜索 | | `/stats` | 会话统计信息 | | `/clear` | 重置对话 | | `/quit` | 退出 | --- ## 文件 ### 顶层(日常使用) | 文件 | 功能 | |------|-------------| | `agent.py` | 生产级代理 —— 通过 llama.cpp 路由到搜索/shell/chat | | `chat.py` | 带有 llama.cpp 的简单流式聊天 | | `dashboard.py` | llama.cpp 的实时监控仪表板 | | `setup.sh` | 一键安装(llama.cpp + 模型下载 + 配置) | | `config.example.json` | 示例配置 | | `web/` | Web UI (server.py + index.html) | ### MLX 后端 (`mlx/`) | 文件 | 功能 | |------|-------------| | `mlx_engine.py` | MLX 推理服务器,支持 64K 上下文和 KV 缓存持久化 | | `kv_cache.py` | KV 缓存保存/加载以实现会话持久化 | | `paged_inference.py` | 分页注意力实验 | | `turboquant.py` | TurboQuant 量化实验 | | `benchmark.py` | 基准测试工具 | ### Flash 流式传输研究 (`research/flash-streaming/`) 研究历程:我们构建、测量并迭代。每个文件代表一个步骤。 | 文件 | 功能 | 关键发现 | |------|-------------|---------------| | `flash_stream.py` | v1: 基于 mmap 的流式传输 (0.12 词/秒) | 拆分模型架构可行 | | `flash_stream_v2.py` | v2: F_NOCACHE 直接 I/O (0.15 词/秒) | 比 mmap 快 27% | | `flash_stream_27b.py` | 27B dense 流式传输 (0.18 词/秒) | 方法适用于 dense + 混合 SSM 模型 | | `flash_moe.py` | MoE 专家级流式传输引擎 | 仅从 SSD 加载活跃专家 | | `moe_agent.py` | **可用的 35B 代理** (1.54 词/秒,1.42 GB) | 16 GB Mac 上连贯的 22 GB 模型 | | `batched_moe.py` | 批处理联合专家 (5.1 词/秒) | 每层约 27 个独特专家,而非 64 个 | | `expert_io.py` | F_NOCACHE + pread 专家读取器 (8 线程) | 填满 NVMe 队列深度 | | `direct_io.py` | F_NOCACHE + pread 用于 dense FFN 层 | 绕过 macOS 统一缓冲缓存 | | `split_mlx_model.py` | 将 35B MoE 拆分为固定部分 + 每层专家 | 16KB 对齐以适配 DART IOMMU | | `split_dense_27b.py` | 将 27B dense 拆分为固定部分 + 每层 FFN | 相同技术,不同架构 | | `convert_split.py` | GGUF → 拆分 safetensors 转换 | GGUF 是列主序 | | `convert_aligned.py` | Safetensors → 16KB 对齐的二进制 | F_NOCACHE 直接 I/O 必需 | | `dequant_gguf.py` | 自定义 Q4_K/Q6_K 反量化 (numpy) | MLX 无法读取 GGUF Q4_K 块 | | `rebuild_pinned.py` | 从 MLX 黄金模型重建固定权重 | 修复 SSM 权重的 dtype 问题 | | `flash_agent.py` | 32B dense 流式传输代理(早期版本) | 概念验证 | | `flash_stream_batched.py` | 批处理评估实验 | 证明 eval 同步不是瓶颈 | | `README.md` | 详细的研究报告及所有测量数据 | 完整方法论和结果 | --- ## 关键发现 这些都是我们要付出艰辛代价才学到的东西。每项链接至发现/修复该问题的文件。 1. **GGUF 是列主序** — `flat.reshape(ne[1], ne[0])`,而非 `.reshape(ne[0], ne[1]).T`。错误的 reshape 会产生正确的形状但输出垃圾数据。(`dequant_gguf.py`, `convert_split.py`) 2. **MLX 4-bit 比预期大 15%** — group_size=64 时的 scales + biases 增加了 0.031 bytes/param。32B 模型是 18.4 GB,而非 16 GB。这就是为什么即使在 4-bit 下模型也无法装入 16 GB 内存的原因。(`research/flash-streaming/README.md`) 3. **`nn.quantize()` 静默跳过 MoE 专家** — `SwitchLinear` 不是 `nn.Linear` 的子类。您必须传递一个明确包含它的 `class_predicate`。否则,专家将以 float16 运行并产生垃圾输出。(`moe_agent.py`) 4. **`gather_qmm` 消除了累加器发散** — 8 次单独的 `quantized_matmul` 调用会在 40 层上累积舍入误差。单次批处理的 `gather_qmm` 调用与参考模型完全匹配。(`batched_moe.py`, `flash_moe.py`) 5. **F_NOCACHE 比 mmap 快 27%** — macOS 统一缓冲缓存为顺序流式工作负载添加了开销。`fcntl(F_NOCACHE)` + 具有 16KB 对齐的 `os.pread()` 可以完全绕过它。(`direct_io.py`, `expert_io.py`) 6. **在 `nn.Module` 上使用 `setattr` 会导致内存泄漏** — 通过 `setattr` 将 FFN 权重注入模型树会阻止垃圾回收。内存每 16 层增长 3.6 GB。修复:直接在加载的数组上使用 `mx.quantized_matmul`,切勿触碰模型树。(`flash_stream.py`) 7. **批处理层没有帮助** — 我们测试了 8 层批次(16 次 eval 对 128 次)。零速度提升。瓶颈是 SSD I/O,而非 GPU 同步开销。(`flash_stream_batched.py`) --- ## 架构 ┌──────────────────────────────────────────────┐ │ agent.py — 作为路由器的 LLM │ │ 搜索 / shell / chat │ ├──────────┬───────────────────────────────────┤ │ llama.cpp│ MLX 后端 │ │ (快) │ + KV 缓存保存/加载 │ │ │ + Flash 流式传输(外存计算) │ │ │ + MoE Expert Sniper (SSD) │ ├──────────┴───────────────────────────────────┤ │ Apple Silicon — 统一内存 + NVMe SSD │ └──────────────────────────────────────────────┘ `` — ## 致谢 - Qwen3.5 (https://huggingface.co/Qwen) — 模型 - llama.cpp (https://github.com/ggerganov/llama.cpp) — 推理引擎 - MLX (https://github.com/ml-explore/mlx) — Apple 的 ML 框架 - Unsloth (https://huggingface.co/unsloth) — GGUF 量化 - mlx-community (https://huggingface.co/mlx-community) — 预先转换的 MLX 模型 ## 许可证 MIT

相似文章

2台配备 512GB 内存的 M3 Ultra Mac Studio

Reddit r/LocalLLaMA

硬件投入约 2.5 万美元。告诉我你们希望我在这两台设备上部署什么模型,我会协助测试。目前我已通过 Exo 后端跑通了 DeepSeek v3.2 Q8 版本;当前每台设备均在运行 GLM 5.1 Q4(正在排查为何 Exo 无法加载 Q8 版本)。静候社区完成 Kimi 2.6 针对 MLX/mmap 的优化适配。