@tom_doerr: 在 16GB 内存 Mac 上运行 35B 模型 https://github.com/walter-grace/mac-code…
摘要
该工具支持通过从 SSD 流式加载模型权重,在 16GB Mac 上运行 Qwen3.5-35B 等大型语言模型,经优化配置后最高可达 30 tok/s。
查看缓存全文
缓存时间: 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
硬件投入约 2.5 万美元。告诉我你们希望我在这两台设备上部署什么模型,我会协助测试。目前我已通过 Exo 后端跑通了 DeepSeek v3.2 Q8 版本;当前每台设备均在运行 GLM 5.1 Q4(正在排查为何 Exo 无法加载 Q8 版本)。静候社区完成 Kimi 2.6 针对 MLX/mmap 的优化适配。
@remilouf: 在 @julien_c 的推文之后,我买了一台配备 128B 统一内存的 MacBook Pro,并开始将 Qwen3.6 作为我的日常驱…
作者分享了在配备 128GB 统一内存的 MacBook Pro 上运行 Qwen3.6 模型的经验,称赞了苹果硬件在本地 AI 推理方面的效率。
在配备 24GB 内存的 M4 芯片上运行本地模型
指南介绍了如何使用 LM Studio、Ollama 等工具,在拥有 24GB 内存的 M4 MacBook 上运行 Qwen 3.5-9B 等本地 AI 模型,并提供了优化性能的具体配置建议。
@tom_doerr: 在单个4GB GPU上运行70B大语言模型 https://github.com/lyogavin/airllm
AirLLM是一个开源工具,优化推理内存使用,无需量化即可在单个4GB GPU上运行70B大语言模型,并支持在8GB显存上运行405B模型。
在 8GB 显存和 32GB 内存上运行 Qwen3.6 35b a3b,~190k 上下文
作者分享了一种高性能的本地推理配置,使用支持 TurboQuant 的修改版 llama.cpp,在硬件受限(8GB 显存、32GB 内存)的情况下运行 Qwen3.6 35B A3B,实现了 ~37-51 tok/sec 的生成速度,并支持 ~190k 上下文。