用一杯咖啡的时间,把 Llama 3.2 跑在纯 C 里:一份面向毕业生的极简推理实战笔记

“我能不能只用一台普通笔记本,就跑得动一个 10 亿参数的大模型?”
“当然可以,而且只要 700 行 C 代码就够了。”

本文会把官方仓库 llama3.2.c 的 README 拆成一步步可操作的实验手册。你不需要任何分布式框架,也不需要 GPU,只要装好 gcc、PCRE,就能在 30 分钟内看到终端里一行一行蹦出的中文或英文续写。


1. 先弄清三个核心问题

问题 一句话答案
Llama 3.2 是什么? Meta 最新开源的 1B/3B 小尺寸大语言模型,参数少但能力不弱。
为什么用 C? 避免 Python 运行时开销,文件体积 < 1 MB,嵌入式或老机器也能跑。
700 行代码够干什么? 只做推理,不训练;支持 fp32、int8 两种精度,带 chat 模式。

2. 五分钟完成环境准备

以下步骤在 Ubuntu 22.04 测试通过,macOS 用 brew 同理。

2.1 系统依赖

sudo apt update
sudo apt install gcc make libpcre3 libpcre3-dev

如果你用 clang,后面把 gcc 换成 clang 即可。

2.2 克隆仓库

git clone https://github.com/Dylan-Harden3/llama3.2.c.git
cd llama3.2.c        # 注意这里是 llama2.c,作者沿用了旧目录名

3. 拿到模型:从 Hugging Face 导出 .bin

先确认你已在 HuggingFace 申请并通过 Llama 3.2 权限,然后用 CLI 登录:

pip install huggingface_hub
huggingface-cli login

3.1 导出 float32 版(体积 4.7 GB)

python3 export.py Llama-3.2-1B.bin --hf meta-llama/Llama-3.2-1B

3.2 导出 int8 量化版(体积 1.3 GB)

python3 export.py Llama-3.2-1B-q8_0.bin --version 2 --hf meta-llama/Llama-3.2-1B
精度 文件大小 推理速度* 质量损失
fp32 4.7 GB 9 tok/s
int8 1.3 GB 26 tok/s 轻微,日常文本几乎感知不到

*测试机:6 核 i7-8750H,16 GB RAM,无 GPU。


4. 编译与第一次推理

4.1 最简编译

make run

命令等价于:

gcc -O3 -o run run.c -lm -lpcre

4.2 跑起来

./run Llama-3.2-1B.bin

默认随机采样 256 步,你会看到类似:

<|begin_of_text|>One day, Lily met a Shoggoth...

4.3 带提示词

./run Llama-3.2-1B.bin -t 0.8 -n 256 -i "为什么天空是蓝色的?"

5. 打开 Chat 模式

5.1 导出 Instruct 版

python3 export.py Llama-3.2-1B-Instruct.bin --hf meta-llama/Llama-3.2-1B-Instruct

5.2 启动对话

./run Llama-3.2-1B-Instruct.bin -m chat

终端会变成交互式,输入 exit 可退出。


6. 把速度再翻三倍:int8 量化 + OpenMP

6.1 安装 OpenMP

sudo apt install clang libomp-dev

6.2 编译带 OpenMP 的 int8 版本

make runomp

等价于:

clang -Ofast -fopenmp -march=native run.c -lm -lpcre -o run

6.3 运行并指定线程数

OMP_NUM_THREADS=6 ./runq Llama-3.2-1B-q8_0.bin -n 256

经验法则:

CPU 物理核心 推荐线程
4 4
6 6
12(含超线程) 6–8

线程数并非越多越好,超过物理核心后反而因缓存颠簸而变慢。


7. FAQ:你可能遇到的 12 个疑问

  1. Q: Windows 能跑吗?
    A: 用 WSL2 + Ubuntu 子系统即可,步骤同上。

  2. Q: 为什么编译时报 pcre.h not found
    A: 漏装 libpcre3-dev,重新执行 2.1 节。

  3. Q: 推理时内存占用多少?
    A: int8 1B 模型常驻内存 ≈ 1.3 GB;3B 模型 ≈ 3.9 GB。

  4. Q: 能否用 AMD CPU?
    A: 可以,只要支持 SSE4.2。-march=native 会自动选指令集。

  5. Q: 能跑更大的 8B 模型吗?
    A: 理论上能,但内存需 8 GB+,速度会掉到 2–3 tok/s。

  6. Q: 能不能用 GPU?
    A: 本仓库只提供 CPU 实现,想 GPU 推理请移步 llama.cpp。

  7. Q: 如何保存对话历史?
    A: 目前代码未实现,需要你自己把 stdout 重定向到文件。

  8. Q: 中文效果怎么样?
    A: Llama 3.2 1B 的中文能力一般,适合做技术演示;3B 稍好。

  9. Q: 如何微调?
    A: README 明确说“不支持训练”,需你自己改代码。

  10. Q: 与 llama.cpp 区别?
    A: llama.cpp 功能全、社区大;本项目极简教学向,单文件易读。

  11. Q: 输出乱码?
    A: 确认终端编码 UTF-8,或尝试 export PYTHONIOENCODING=utf-8

  12. Q: 如何退出 chat 模式?
    A: 键盘输入 exit 回车即可。


8. 性能调优速查表

优化手段 编译命令 速度提升 备注
默认 O3 make run 最稳
Ofast gcc -Ofast ... 1.2× 可能破坏 IEEE 合规
原生指令 -march=native 1.3× 老 CPU 可能不支持
OpenMP make runomp 2–3× 需多核 CPU
int8 量化 runq 质量轻微下降
组合 Ofast + OpenMP + int8 6–8× 终极方案

9. 代码结构 1 分钟速览

  • run.c
    700 行纯 C,包含:

    • tokenizer(基于 PCRE 正则切词)
    • transformer 前向:rmsnorm、matmul、rope、softmax、kv-cache
    • 采样策略:temperature、top-p
    • 主函数:解析命令行、加载 .bin、循环生成 token
  • runq.c
    run.c 几乎相同,只是 matmul 前后多了 quantize / dequantize

  • export.py
    Python 脚本,把 HuggingFace 的 PyTorch 权重转成本地 .bin


10. 动手实验:用 3B 模型写一段科幻故事

10.1 启动

./run Llama-3.2-3B.bin -t 1.0 -p 0.9 -n 512 \
  -i "在火星的地下城市,警探林澜发现了一具"

10.2 结果片段(示例)

在火星的地下城市,警探林澜发现了一具漂浮在真空管中的尸体。
尸体没有外伤,但视网膜里嵌着一串加密坐标……

不同随机种子会有不同走向,可多次尝试。


11. 扩展阅读与引用

  • 原始仓库:karpathy/llama2.c – 第一个把 7B 模型塞进 500 行 C 的人
  • TinyStories 论文 – 证明 10M 参数模型也能讲完整故事
  • HuggingFace Llama-3.2-1B – 官方模型卡,含数据、许可证、限制说明

12. 结语:小而美的力量

Llama 3.2 的 1B/3B 模型告诉我们:
参数规模不再是门槛,算法、数据与场景同样重要。
700 行 C 代码像一把瑞士军刀,让你随时随地把大模型塞进树莓派、老旧笔记本,甚至路由器。

现在,轮到你动手了。把终端打开,输入第一行 ./run,开始属于你的文本冒险。