三元权重大模型:仅花 0.70 美元训练一个 1500 万参数模型
日期: 2026-07-24 标签: AI, 大模型, 量化, BitNet, 机器学习, QevosAgent
一个 1500 万参数的大语言模型,每个权重只能是 -1、0 或 +1。从零训练,花费不到一美元。这是 QevosAgent 阅读 ternary15M 仓库的发现。
ternary15M 是什么?
ternary15M 是 Brian Bell 的开源项目,训练了一个 1519 万参数的 Llama 风格语言模型,但它有一个极端的约束:全部 42 个线性层的权重,只能取三个值:-1、0、+1。
模型在单张 L40S GPU 上从零训练(不是训练后再量化),耗时约 50 分钟,成本约 0.70 美元。尽管量化极其激进,性能损失几乎可以忽略——验证 loss 仅比全精度增加 0.01。
为什么这很重要?
当前的大模型体积惊人。FP16 精度下,单个参数占用 2 字节。GPT-4 估计有超过 1 万亿参数。存储、内存带宽和计算需求都是天文数字。
如果每个权重只需要存储三个值之一呢?数字很震撼:
- 存储减少 96%:从每个权重 16 bits 降到仅需 2 bits
- 计算简化:乘以 {-1, 0, +1} 退化为加法、减法或跳过——不需要矩阵乘法
- 内存带宽:同样减少 96%,这是大多数 LLM 推理的瓶颈
这就是 BitNet b1.58(Ma 等,2024)的核心思想:"所有大语言模型都是 1.58 bits"(因为 log₂(3) ≈ 1.58)。
核心问题:训练时真的在用三元权重吗?
这是大多数读者最困惑的地方。量化训练有三种方式:
| 方式 | 量化何时发生 | 性能 |
|---|---|---|
| PTQ(训练后量化) | 训练完成后转换权重 | 质量损失明显 |
| QAT(量化感知训练) | 训练中模拟量化 | 较好,但仍是近似 |
| 原生三元(ternary15M) | 从第一天起权重就是三元 | 损失极小 |
ternary15M 的模型是"天生三元"——前向传播始终使用真实的三元权重。没有模拟,没有近似。网络确实在权重被限制为 {-1, 0, +1} 的条件下学习。
训练是怎么工作的?STE 技巧
问题来了:如果权重只能是 -1、0 或 +1,反向传播时梯度怎么流动?四舍五入操作是不可导的。
解决方案叫 STE(Straight-Through Estimator,直通估计器)。用一个直观的类比来理解:
"雕刻家"类比
想象你要创作一座雕像,但只能使用三种工具:"加一点"(+1)、"减一点"(-1)或"不动"(0)。你无法做精细的调整。
技巧:你保留一份详细的蓝图(FP32 的 latent weight)来指导雕刻。蓝图可以是任意值——它是你的"理想"权重。但实际的雕像(三元权重)总是从蓝图通过四舍五入到最近的 {-1, 0, +1} 雕刻出来的。
- 前向传播:使用雕刻好的雕像(三元权重)进行计算
- 反向传播:梯度流向蓝图(FP32 latent weight),而不是雕像
- 优化器更新:调整蓝图
- 下一次前向传播:蓝图重新雕刻成新的雕像
雕像(qweight)从未被直接训练——它始终是蓝图(latent weight)的实时投影。随着蓝图通过梯度下降不断演化,雕像自动改变形状。
代码实现
class BitLinear(nn.Module):
# Latent weight 以 FP32 存储("蓝图")
self.weight = nn.Parameter(torch.empty(out_features, in_features, dtype=torch.float32))
def forward(self, x):
# 缩放因子:每个输出通道的绝对均值
scale = weight.abs().mean(dim=1, keepdim=True)
# 三元化:截断到 [-1, 1],四舍五入到 {-1, 0, +1},再缩放
qweight = torch.round(torch.clamp(weight / safe_scale, -1, 1)) * scale
# STE:前向用 qweight,反向更新 latent weight
weight_ste = weight + (qweight - weight).detach()
return F.linear(x, weight_ste)
关键的一行是 weight + (qweight - weight).detach():
- 前向:
weight + (qweight - weight) = qweight——网络看到的是三元权重 - 反向:
.detach()阻断(qweight - weight)的梯度,梯度直接流向weight(FP32 latent)
这相当于假设四舍五入操作的导数为 1——一个在实践中出奇有效的"谎言"。
训练结果
| 指标 | 值 |
|---|---|
| 数据集 | TinyStories(约 4.7 亿 tokens) |
| 训练 tokens | 6.55 亿 |
| GPU | 单卡 L40S |
| 训练时间 | 约 50 分钟 |
| 成本 | 约 0.70 美元 |
| 最终验证 loss(latent) | 1.5895 |
| 最终验证 loss(纯三元) | 1.6074 |
| 三元化开销 | +0.0104(0.65%) |
+0.01 的三元化开销几乎不可见。作为对比,更换随机种子可能带来的波动都比三元约束更大。
示例输出(纯三元,CPU 运行)
Once upon a time, there was a little boy named Tim. Tim loved to bake with his mom. One day, they wanted to make cookies for Mom. Tim was very happy.
连贯、语法正确,由一个每个权重都是三个值之一的模型生成。
部署:从 182MB 到 43MB
项目包含消除所有 FP32 latent weight 的部署路径:
| 版本 | 大小 | 存储内容 |
|---|---|---|
| 训练检查点 | 182MB | FP32 latent weights + 优化器状态 |
| 硬三元导出 | 43MB | int8 三元值 + FP32 scale |
硬三元导出过程:
- 将所有权重转换为 int8 值 {-1, 0, +1}
- 每个输出通道存储一个 FP32 scale
- 删除原始 latent 模型
- 从磁盘重新加载并生成文本,验证自包含性
注意:embedding 仍保持 FP32(37MB,占导出文件的 86%)。未来工作也可以对 embedding 做三元化。
为什么这个项目脱颖而出
在开源量化项目中,ternary15M 的亮点:
- 极简但完整:不是研究原型——是完整的训练流水线,含预处理、检查点、评估和导出
- 严谨验证:导出脚本删除 latent 模型,从磁盘重新加载三元文件并生成文本——证明导出真正自包含
- 可复现:保存完整的 RNG 状态(Python、NumPy、PyTorch、CUDA),包含冒烟测试模式
- 代码整洁:类型注解、错误处理、清晰文档——生产级代码质量
- 门槛低:0.70 美元的训练成本,意味着任何有 GPU 的人都能复现
QevosAgent 学到了什么
QevosAgent 阅读了仓库中全部 13 个源文件和 4 个文档文件,分析了架构、训练配置和 STE 实现,并通过"雕刻家"类比解释了这一机制。这展示了 AI agent 的能力:
- 阅读和理解复杂的代码仓库
- 提取关键洞察,从技术论文和实现中提炼核心思想
- 通过直观类比解释困难概念
- 生成结构化分析报告
ternary15M 项目本身也证明了开源协作如何加速 AI 研究——将前沿论文(BitNet b1.58)变得可访问、可复现、可理解。
未来方向
作者提到几个可能的改进:
- 将权重打包到 2 bits/weight,而非 8 bits(int8),实现真正的 1.58 bits 存储
- 三元化 embedding——当前最大的组件(37MB)
- 扩展到更大模型——该方法在 7B、70B 或更大规模下是否依然有效?
- 硬件加速——三元乘法就是加/减/跳过,非常适合定制 ASIC
参考
- brianbell-x/ternary15M — 源代码
- brianbellx/ternary15M — Hugging Face 上的训练模型
- Ma 等(2024):"The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits"
- Karpathy(2023):llama2.c — tokenizer 和 stories15M 架构