Perplexity 开源 Mac 本地推理引擎 Lily

Perplexity 为其 Mac 端 Hybrid Compute 构建并开源了一个本地推理引擎:Lily https://t.co/7fJnDpCdpP Lily 用 Rust 运行时 + 自定...

精选理由

Perplexity 为 Mac 开发了专用推理引擎 Lily,比 MLX-LM 快 23%-35%,专为 Qwen3.6-35B-A3B 和 Apple Silicon 优化。

AI 摘要

Perplexity 为 Mac 端 Hybrid Compute 开发了本地推理引擎 Lily,使用 Rust 运行时和自定义 Metal 内核,专为 Qwen3.6-35B-A3B 模型和 Apple Silicon 硬件深度定制。在 M5 Max 上,Lily 的 prefill 吞吐为 MLX-LM 的 1.23 倍,decode 为 1.35 倍。Lily 通过 GPU 路径匹配推理阶段、最小化数据搬运和动态选择内核等策略实现性能优化。

原文 · shao__meng

Perplexity 为其 Mac 端 Hybrid Compute 构建并开源了一个本地推理引擎:Lily https://t.co/7fJnDpCdpP Lily 用 Rust 运行时 + 自定...

Perplexity 为其 Mac 端 Hybrid Compute 构建并开源了一个本地推理引擎:Lily perplexity.ai/hub/blog/optim… Lily 用 Rust 运行时 + 自定义 Metal 内核,只为一个模型(Qwen3.6-35B-A3B)和一种硬件(Apple Silicon)做深度定制,不依赖 PyTorch 或 MLX。在 M5 Max,prefill 吞吐平均为 MLX-LM 的 1.23 倍,decode 为 1.35 倍。 # Perplexity 为什么要做专用引擎? 背景动机:Hybrid Compute 中云端负责研究与推理,本地模型处理私密文件和应用。若本地推理跟不上节奏,整个任务体验就会割裂,因此需要快速处理提示词(prefill)并维持高生成速率(decode)。 通用 vs. 专用: · MLX + MLX-LM 是 Mac 上的主流方案,通用、开箱即用,但其可复用算子必须兼容大量模型架构。 · Lily 放弃通用性,把模型结构、分阶段执行计划、内核选择都收进一个围绕 Qwen 和 Apple Silicon 的 Rust 运行时中,单进程完成加载、会话管理、OpenAI 兼容 API 和 Metal 内核执行。 # 优化的前提:模型与硬件各有三种"形状" Qwen3.6-35B-A3B 的三种计算模式 · 不均匀的专家分组:350 亿参数,每 token 只激活约 30 亿;路由器从 256 个专家中选 8 个,再加一个共享专家。各专家收到的 token 数量差异很大。 · 随上下文增长的注意力缓存:10 层全注意力,使用 GQA(16 个查询头共享 2 个 KV 头),KV cache 随生成变长,每步 decode 读取更多数据。 · 固定大小的递归状态:30 层 Gated DeltaNet,将历史压缩进固定尺寸状态。prefill 阶段既可逐 token 顺序扫描,也可分块并行,哪种更快取决于维度、负载和硬件。 Apple Silicon 的差异化路径 · 统一内存:CPU/GPU 共享一个物理内存池,模型无需 GPU 副本,但读写仍消耗带宽,寄存器和片上存储快但小。 · 两种计算单元:prefill 是 GEMM(矩阵×矩阵),权重可在成百上千行间复用,适合走 M5 每个 GPU 核心内的 Neural Accelerator(通过 Metal 4 tensor 操作);batch-1 decode 是 GEMV(矩阵×向量),几乎无权重复用,受内存带宽限制,更适合 GPU 的 向量 ALU。 团队明确指出:这些路径 MLX 同样具备(专家分组、融合递归内核、GQA 感知注意力),是双方共同的起点。Lily 的优势来自围绕固定结构做协调,而非独占某种硬件能力。 # 优化策略三原则 1. GPU 路径匹配推理阶段:prefill 走矩阵路径,decode 走向量路径。 2. 把模型结构映射到 GPU 上并最小化数据搬运:权重用前才解压、专家路由不回 CPU、递归状态留在片上、复用 GQA 共享的 KV 数据。 3. 按实测负载形状选内核:根据行数、专家分布、算子维度、上下文长度动态选择 tile 大小、执行布局和注意力路径。 # Prefill 优化:复用权重,路由留在 GPU GEMM 内联反量化:4-bit 权重(每 64 个共享一个 bf16 scale/bias,模型从约 70GB 压到 19.4GB)逐小块在片上解压、立即参与乘法,从不在统一内存中生成完整 bf16 数组;效果:512 token prompt 下 prefill +77.4% 路由全程在 GPU:直方图→前缀和→scatter→block map 全部放进一个 command buffer,不让 CPU 中途检查中间结果;效果:+89%;说明"内核数量"不是好指标——更快的路径内核更多但零 CPU 等待 Tile 大小匹配专家负载:32 行 tile + 4 个 simdgroup,替代固定 16 行;效果:2K prompt 下 +13.2% 递归状态寄存器常驻:每个 simdgroup 负责状态矩阵一列,加载一次后在寄存器里完成整个扫描,用 simdgroup 操作交换数据而非 threadgroup 内存;状态和门用 fp32 以防误差累积;效果:+5.6%(专家 GEMM 占 prefill 约 90%,递归扫描本身占比小) 分块 prefill:长 prompt 切成有界块,只保留当前块的临时激活,权重、递归状态、KV cache 跨块延续;效果:“限制峰值内存,不改变输出;注意力部分仍随 prompt 长度呈二次增长 # Decode 优化:最小化每 token 搬运的字节 行并行 GEMV:单行激活专用内核,一个 simdgroup 协作读权重的不同部分:效果:基础能力,对齐 MLX 已有做法 Token 交接留在 GPU:双 command buffer + 双 GPU 常驻 token 槽,GPU 选出 token 后直接写入下一步的输入槽,消除每 token 一次的 CPU 同步 并发调度独立内核:一步 decode 启动 795 个内核,依赖关系只有 555 个串行阶段;改用记录真实数据依赖的并发 Metal pass,仅在必要处插 barrier 四条链融合:专家输入投影+门控激活、专家输出投影+路由分数+共享专家、Q/K 准备、递归更新+归一化;中间值留在寄存器,同时消除相应 barrier KV cache 读取合并:相邻线程请求相邻字节;效果:key 带宽 33.8→47.9 GB/s,value 42.0→61.8 GB/s,3,840 上下文下 decode +2.1% GQA 打包:4 个查询头放进一个 threadgroup,每行 KV 只加载一次复用 4 次;8 次独立请求变 2 次共享加载,输出字节完全一致;效果:32K 上下文下 decode +23.8% 长上下文切换注意力布局:≥32K 切到固定块布局,把 KV cache 分成等份并行处理;效果:32K +7.7%,64K +27.4%,128K +40.2% # 优化的边界:哪些没用,以及为什么 投机解码反而慢 18%:验证阶段一次处理 2–5 行,对这种硬件是低效形状;且多行常选中不同专家,反而增加了专家权重读取。缩小草稿模型词表提升了草稿速度 4.7–5.1%,但整体循环仍不划算。作者强调这是负载相关的结论——其 Blackwell 上的批量部署仍使用投机解码。 其他无效尝试:减少 GPU 启动次数、整阶段重叠、更大 prefill tile、更广泛融合、加速路由器、输出投影与 token 选择合并,均未改善端到端。 已接近硬件极限:MoE GEMM 和 GEMV 分别达到其访问模式下最快持续权重读取速率的 97.9% 和 90.3%;从稀疏 GEMV 中移除算术运算只改变 0.2% 吞吐,证实瓶颈是权重读取而非计算;prefill 矩阵乘法孤立测试达理论上限 93%,模型内 80–86%。 Perplexity @perplexity_ai Today we’re open-sourcing Lily, the local inference engine we built for hybrid compute in Perplexity Computer. Lily is specialized for Qwen3.6-35B-A3B on Apple silicon, built so on-device compute doesn’t bottleneck Computer tasks. Read more: perplexity.ai/hub/blog/optim… 🔗 View Quoted Tweet 💬 0 🔄 0 ❤️ 1 👀 92 ⚡