WWDC Quick Look 💓 By SwiftGGTeam
Explore large language models on Apple silicon with MLX

Explore large language models on Apple silicon with MLX

观看原视频

Highlight

在 M3 Ultra 512GB 统一内存上,MLX LM 一行命令就能跑起 4.5-bit 量化、权重约 380GB 的 DeepSeek 670B 模型。

核心内容

要在本地跑大模型,过去通常意味着一台带独立显卡的 PC、CUDA 工具链、HuggingFace 转换脚本、量化插件,外加显存不够时的各种 offload 折腾。Mac 用户长期被排除在外,因为没有 NVIDIA 卡,也没有几十 GB 显存可用。

Apple 在 WWDC 2025 推出 MLX LM,把这条链路压成两步:pip install mlx-lm,然后一条命令。MLX 是基于 Metal 加速、利用统一内存的开源机器学习库,CPU 和 GPU 共享同一份数据,不需要在显存与内存之间反复拷贝。MLX LM 在它之上封装出一套 CLI 工具和 Python API,覆盖文本生成、模型量化、LoRA 微调、adapter 融合的全流程,并直接对接 Hugging Face。Angelos 在演示里用 M3 Ultra 跑通了 670B 参数、4.5-bit 量化的 DeepSeek V3,权重约 380GB,生成速度超过阅读速度——这是消费级硬件第一次能本地交互这种规模的模型。

详细内容

最简文本生成(03:51)。 CLI 一条命令解决下载、加载、推理:

mlx_lm.generate --model "mlx-community/Mistral-7B-Instruct-v0.3-4bit" \
                --prompt "Write a quick sort in Swift"

关键点:

  • --model 接受 Hugging Face 仓库 ID 或本地路径,模型不在本地时自动下载。
  • --prompt 为输入文本,工具内部会套上 chat template。
  • 还可加 --top-p--temp--max-tokens 调节采样行为,与主流推理工具的参数一致。

Python API 拿到完整模型对象(05:26)。 load 返回的是真正的 MLX 神经网络,可以打印结构、读取参数:

from mlx_lm import load, generate

model, tokenizer = load("mlx-community/Mistral-7B-Instruct-v0.3-4bit")

prompt = "Write a quick sort in Swift"
messages = [{"role": "user", "content": prompt}]
prompt = tokenizer.apply_chat_template(
    messages, add_generation_prompt=True
)

text = generate(model, tokenizer, prompt=prompt, verbose=True)

关键点:

  • load 同时返回模型与 tokenizer,自动从 HF 拉取并缓存。
  • apply_chat_template 把 messages 渲染成模型期望的 prompt 字符串。
  • generate 是阻塞调用,verbose=True 会边生成边打印 token 与吞吐速度。
  • 拿到的 model 可直接 print(model.layers[0].self_attn) 检查结构,方便做 layer swap 或低层手术。

KV Cache 维持多轮对话(08:01)。 长 prompt 和多轮场景下,attention 重算成本极高:

from mlx_lm import load, generate
from mlx_lm.models.cache import make_prompt_cache

model, tokenizer = load("mlx-community/Mistral-7B-Instruct-v0.3-4bit")

prompt = "Write a quick sort in Swift"
messages = [{"role": "user", "content": prompt}]
prompt = tokenizer.apply_chat_template(
    messages, add_generation_prompt=True
)

cache = make_prompt_cache(model)

text = generate(model, tokenizer, prompt=prompt, prompt_cache=cache, verbose=True)

关键点:

  • make_prompt_cache(model) 创建可复用的 KV cache 对象。
  • 把 cache 通过 prompt_cache= 传入 generate,每次调用从上次 token 位置继续。
  • cache 可被原地编辑、保存、在多个会话之间切换,适合聊天机器人或 agent 场景。

按层混合精度量化(10:33)。 Embedding 层和 lm_head 对量化更敏感,可单独保留更高精度:

from mlx_lm.convert import convert

def mixed_quantization(layer_path, layer, model_config):
    if "lm_head" in layer_path or "embed_tokens" in layer_path:
        return {"bits": 6, "group_size": 64}
    elif hasattr(layer, "to_quantized"):
        return {"bits": 4, "group_size": 64}
    else:
        return False

convert(
    hf_path="mistralai/Mistral-7B-Instruct-v0.3",
    mlx_path="./mistral-7b-v0.3-mixed-4-6-bit",
    quantize=True,
    quant_predicate=mixed_quantization
)

关键点:

  • quant_predicate 是一个针对每层调用的函数,返回该层的量化参数或 False(跳过)。
  • lm_headembed_tokens 用 6-bit、group_size 64,其余层走 4-bit。
  • convert 一步完成下载、转换、保存,可加 upload_repo 推回 Hugging Face。

LoRA 微调(13:37)。 直接在 4-bit 量化模型上训练 adapter:

mlx_lm.lora --model "mlx-community/Mistral-7B-Instruct-v0.3-4bit" \
            --train \
            --data /path/to/our/data/folder \
            --iters 300 \
            --batch-size 16

关键点:

  • 在量化模型上训练 adapter,内存占用比训练全精度模型显著降低。
  • --data 指向本地数据目录,使用 Hugging Face 标准数据集格式。
  • 训练结束后 adapter 文件单独保存,推理时通过 --adapter 加载。
  • 之后用 mlx_lm.fuse16:29)把 adapter 合回基座,部署时只剩一个量化好的模型文件。

Swift 端集成(17:14)。 把 LLM 推理放进 Mac/iOS 应用:

import Foundation
import MLX
import MLXLMCommon
import MLXLLM

@main
struct LLM {
    static func main() async throws {
        let modelId = "mlx-community/Mistral-7B-Instruct-v0.3-4bit"
        let modelFactory = LLMModelFactory.shared
        let configuration = ModelConfiguration(id: modelId)
        let model = try await modelFactory.loadContainer(configuration: configuration)

        try await model.perform({context in
            let prompt = "Write a quicksort in Swift"
            let input = try await context.processor.prepare(input: UserInput(prompt: prompt))

            let params = GenerateParameters(temperature: 0.0)
            let tokenStream = try generate(input: input, parameters: params, context: context)
            for await part in tokenStream {
                print(part.chunk ?? "", terminator: "")
            }
        })
    }
}

关键点:

  • LLMModelFactory.shared.loadContainer(configuration:) 返回 ModelContainer,是 Swift 6 的 actor,天然处理并发安全。
  • context.processor.prepare(input:) 完成 tokenize 与 chat template 套用。
  • generate(...) 返回 AsyncSequence,可用 for await 流式消费 token。
  • 多轮对话只需在 generate 之前调用 context.model.newCache(parameters:) 创建 KV cache 并传入 TokenIterator18:00)。

核心启发

  • 做什么:在 Mac 上自建本地推理服务,替代云 API 处理隐私敏感数据

    • 为什么值得做:M-series Mac 的统一内存让 70B 4-bit 模型在 64–128GB 设备上可跑,敏感数据无需出本机;推理成本归零。
    • 怎么开始:pip install mlx-lm,先用 mlx_lm.generate --model "mlx-community/Mistral-7B-Instruct-v0.3-4bit" 跑通,再用 Python API 包装成 HTTP 接口。
  • 做什么:用 LoRA 微调把私域知识注入到一个量化基座模型

    • 为什么值得做:4-bit 模型上训练 adapter,内存占用低,能在 32GB Mac 上完成;adapter 体积只有几十 MB,便于按客户/场景分发。
    • 怎么开始:把数据整理成 Hugging Face 标准 jsonl,跑 mlx_lm.lora --train --data ./data --iters 300,再用 mlx_lm.fuse 合并部署。
  • 做什么:把 MLX Swift 直接嵌入 Mac/iOS 应用,做端侧 chat 或代码补全

    • 为什么值得做:Foundation Models 框架的内置模型受规模限制,自带 MLX 可挑选 7B–70B 任意模型,质量上限更高。
    • 怎么开始:在 Xcode 工程加 MLXLLM 依赖,参照 17:14 的 28 行示例搭起 ModelContainer,再加 KV cache 支持多轮对话。
  • 做什么:按层混合精度量化,给质量敏感场景一个折中方案

    • 为什么值得做:纯 4-bit 偶尔会显著掉分,特别是数学和代码任务;embedding/lm_head 提到 6-bit 通常能挽回大部分损失,体积只增加几个百分点。
    • 怎么开始:套用文中 mixed_quantization 函数,调 convert(quant_predicate=...),对比量化前后在自家评测集上的得分。

关联 Session

评论

GitHub Issues · utterances