用一杯咖啡的时间,把 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 个疑问
-
Q: Windows 能跑吗?
A: 用 WSL2 + Ubuntu 子系统即可,步骤同上。 -
Q: 为什么编译时报
pcre.h not found
?
A: 漏装libpcre3-dev
,重新执行 2.1 节。 -
Q: 推理时内存占用多少?
A: int8 1B 模型常驻内存 ≈ 1.3 GB;3B 模型 ≈ 3.9 GB。 -
Q: 能否用 AMD CPU?
A: 可以,只要支持 SSE4.2。-march=native
会自动选指令集。 -
Q: 能跑更大的 8B 模型吗?
A: 理论上能,但内存需 8 GB+,速度会掉到 2–3 tok/s。 -
Q: 能不能用 GPU?
A: 本仓库只提供 CPU 实现,想 GPU 推理请移步 llama.cpp。 -
Q: 如何保存对话历史?
A: 目前代码未实现,需要你自己把stdout
重定向到文件。 -
Q: 中文效果怎么样?
A: Llama 3.2 1B 的中文能力一般,适合做技术演示;3B 稍好。 -
Q: 如何微调?
A: README 明确说“不支持训练”,需你自己改代码。 -
Q: 与 llama.cpp 区别?
A: llama.cpp 功能全、社区大;本项目极简教学向,单文件易读。 -
Q: 输出乱码?
A: 确认终端编码 UTF-8,或尝试export PYTHONIOENCODING=utf-8
。 -
Q: 如何退出 chat 模式?
A: 键盘输入exit
回车即可。
8. 性能调优速查表
优化手段 | 编译命令 | 速度提升 | 备注 |
---|---|---|---|
默认 O3 | make run |
1× | 最稳 |
Ofast | gcc -Ofast ... |
1.2× | 可能破坏 IEEE 合规 |
原生指令 | -march=native |
1.3× | 老 CPU 可能不支持 |
OpenMP | make runomp |
2–3× | 需多核 CPU |
int8 量化 | runq |
3× | 质量轻微下降 |
组合 | 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
,开始属于你的文本冒险。