1.58-bit 大模型极限量化实战:从 BitNet 三值权重到单颗 CPU 跑起 100B 模型
2026 年 7 月,GitHub 热榜上出现了一个耐人寻味的信号:以往霸榜的要么是 Agent、要么是框架,而这个月冲上来的却是一个"极低位量化" Demo——把大模型压到 1-bit / 1.58-bit 还能本地跑。与此同时,国内团队把 1.58-bit 模型搬上了昇腾 NPU,1B 参数模型只需 0.2GB 内存就能在手机端丝滑推理。本文从工程视角,把"极限量化"这件事从头拆到尾:它到底是什么、为什么在 CPU 上反而更快、我们如何用几十行 PyTorch 自己实现一个 BitLinear,以及如何把它真正接进一个 Transformer、踩过哪些训练坑。
一、背景:量化是大模型落地的"最后一公里"
先算一笔账。一个 70B 的模型,如果用训练时的 FP16 精度存储权重,需要的显存是:
70B × 2 字节(FP16)= 140 GB
这还没算 KV Cache、激活值和推理时的临时缓冲。换句话说,光把权重加载进显存,你就得配 8 张 A100(每张 80GB 还装不下)。这就是为什么过去两年"大模型私有化部署"听起来很美,落地时却常被一张账单劝退。
大模型推理的成本结构,本质上是三个变量的乘积:
成本 ≈ 参数量 × 每个参数的比特数 × 数据搬运频率
- 参数量:模型能力的基本盘,不是我们能动刀的地方(至少不想动)。
- 每个参数的比特数:这就是"量化"要解决的问题。
- 数据搬运频率:每生成一个 token,权重都要从内存搬到计算单元一次。LLM 推理是典型的 memory-bound(带宽瓶颈),不是 compute-bound(算力瓶颈)——这一点是后面所有优化的总开关。
量化的演进路线非常清晰:
| 精度 | 每参数字节 | 70B 模型权重体积 | 特点 |
|---|---|---|---|
| FP16 | 2 B | 140 GB | 训练精度,精度天花板 |
| INT8 | 1 B | 70 GB | 经典推理精度,精度损失小 |
| INT4 | 0.5 B | 35 GB | 消费级显卡部署主流 |
| INT2 | 0.25 B | 17.5 GB | 开始明显掉点 |
| 1.58-bit | ~0.197 B | ~13.8 GB | 三值权重,本文主角 |
注意最后一行的数字:1.58-bit 把 70B 模型的权重压到了不到 14GB,单张 24GB 消费卡甚至一台手机的内存都能装下。而 100B 模型在 1.58-bit 下约 19.75GB——理论上单颗桌面 CPU 的内存条就够跑。
为什么这件事在 2026 年突然"能打"了?三个推力叠加:
- 框架成熟:微软的
bitnet.cpp给出了针对 ARM/x86 CPU 优化的三值矩阵乘内核,官方实测在 ARM 上提速 1.37×–5.07×,100B 模型在单 CPU 上能跑到 5–7 token/s(接近人类阅读速度)。 - 端侧/边缘需求爆发:车机、IoT、隐私敏感场景不允许把数据送云,必须把模型塞进受限硬件。
- 国产算力适配:本月国内团队把 1.58-bit 训练搬上了昇腾 NPU(BitCPM-CANN),1B 模型 0.2GB 端侧推理,标志着这条路线在自主算力上也跑通了。
一句话总结背景:算力的瓶颈不在"算得多快",而在"搬得多快",而 1-bit 量化直接把要搬的数据量砍到了原来的 1/16。
二、核心概念:到底什么是 1.58-bit
2.1 "bit" 在这里到底指什么
很多同学第一次看到 "1.58-bit" 会以为这是一种新的浮点格式。其实不是。这里的 bit 指的是每个权重能用几种取值来表示:
- FP16:每个权重是一个 16-bit 浮点数,取值空间是 2^16 = 65536 种。
- INT8:256 种。
- 1-bit(二值):只有 {-1, +1} 两种取值,所以叫 1-bit(log2(2) = 1)。
- 1.58-bit(三值):权重只有 {-1, 0, +1} 三种取值。因为 3 种取值需要 log2(3) ≈ 1.58496 bit 来编码,所以论文里把它命名为 BitNet b1.58。
这就是"1.58"的来历——它不是营销话术,就是 log2(3) 的数学结果。
2.2 三值权重为什么比二值更好
纯二值 {-1, +1} 有个致命问题:它强制每个权重都"表态",没有"我不重要"这个选项。三值引入 0 之后,带来一个关键好处——稀疏性。一部分权重被压成 0 后,对应的乘加可以直接跳过,既省算力又省带宽。论文实证也表明,b1.58 在困惑度(perplexity)上能追平同规模 FP16,而纯二值的 b1.0 会明显掉点。这也解释了为什么社区里最终胜出的是 1.58-bit 而不是 1-bit:多那 0.58 个 bit(多一个 0 值),性价比极高。
2.3 absmean 权重量化
把浮点权重变成 {-1, 0, +1},核心是一个叫 absmean 的缩放因子:
α = mean(|W|) # 所有权重绝对值的均值
Ŵ = clip(round(W / α), -1, 1) # 归一化 → 四舍五入 → 裁剪到 [-1,1]
直觉解释:α 衡量这批权重的"典型大小"。除以 α 后,大小接近 α 的权重被四舍五入成 ±1,明显小于 α 的被压成 0,明显大于 α 的(极少)被裁成 ±1。整个过程只保留一个标量 α 作为反量化系数。注意这里用的是均值(absmean)而不是最大值(absmax)——如果用最大值做缩放,个别特别大的权重会把整体尺度撑爆,导致绝大多数权重被压成 0,信息损失惨重。这是三值量化里第一个值得记住的工程细节。
2.4 absmax 激活量化(W8A8)
权重压到三值了,但输入激活(上一层输出)还是浮点,直接拿浮点和三值做乘加没意义。BitNet 的做法是把激活量化成 8-bit 整数,即 W8A8(权重 1.58-bit,激活 8-bit):
β = max(|x|) # 激活绝对值的最大值
x̃ = clip(round(127 · x / β), -127, 127)
推理时整数矩阵乘完,再用 α × β / 127 反量化回浮点尺度,加上偏置即可。
2.5 一个关键等式
把上面两条串起来看,量化后的整数运算和原始浮点运算的关系是:
x · Wᵀ ≈ (β · α / 127) · (x̃ · Ŵᵀ)
也就是说,整数矩阵乘 x̃ · Ŵᵀ 的结果,乘上一个标量 (β·α/127) 就能近似还原出浮点结果。这个标量就是反量化钥匙,推理时开销极小。
2.6 手算一个量化例子
光看公式不够直观,手算一行权重就清楚了。假设某层一个神经元的权重是:
W = [0.9, -0.3, 0.05, -1.2]
第一步算 α:α = (0.9 + 0.3 + 0.05 + 1.2) / 4 = 0.6125
第二步归一化:W / α = [1.47, -0.49, 0.082, -1.96]
第三步四舍五入再裁剪:round → [1, 0, 0, -2],clip[-1,1] → [1, 0, 0, -1]
结果 [1, 0, 0, -1] 里有两个 0,稀疏度 50%。这就是三值量化的日常:一半权重直接归零,推理时这些连接根本不参与计算。
三、架构分析:BitLinear 如何取代 nn.Linear
3.1 标准线性层
PyTorch 里我们最熟悉的 nn.Linear 做的是:
Y = X · Wᵀ + b
W 是 FP16 浮点矩阵,整个计算在浮点域完成。对 70B 模型,这个 W 有 140GB。
3.2 BitLinear:把量化塞进前向
BitLinear 在每次前向时做四件事:
- 对权重做 absmean 三值量化,得到整数
Ŵ和缩放α(权重量化只需算一次,可缓存)。 - 对输入激活做 absmax 8-bit 量化,得到
x̃和β。 - 用整数(或整数模拟)做矩阵乘
x̃ · Ŵᵀ。 - 乘以反量化系数
(β·α/127)并加偏置,得到近似的Y。
3.3 训练时怎么求导:Straight-Through Estimator
量化里的 round() 和 clip() 是不可导的——梯度在这两个操作处直接断掉,模型学不动。BitNet 用 STE(Straight-Through Estimator,直通估计器) 解决:
前向:Ŵ = clip(round(W/α), -1, 1) # 真量化
反向:∂L/∂W = ∂L/∂Ŵ # 梯度原样回传,假装量化不存在
即前向走量化路径,反向走"恒等"路径(实际还会对 clip 区间外的梯度做截断,避免更新爆炸)。这让模型在训练阶段就"习惯"三值权重,而不是训完 FP16 再硬量化。
3.4 为什么训练要从头或做量化感知
这里有个工程上很关键的点:直接拿一个 FP16 训好的大模型做 1.58-bit 后量化(PTQ),效果通常会崩。三值的信息损失太大,PTQ 补不回来。所以 1-bit 路线几乎都得走 量化感知训练(QAT)——从随机初始化就用 BitLinear 训练,或者先做几步"权重三值化 + 激活 8-bit"的微调(有点像 LoRA 式的热身)。这也是为什么社区里 1-bit 模型大多是"专门训出来的"(如 BitNet b1.58 2B/3B),而不是把 Llama 70B 直接压出来。
四、代码实战:用 PyTorch 实现 BitLinear
下面所有代码均可直接运行(需要 torch)。我们一步步来。
4.1 absmean 与 absmax 量化函数
import torch
import torch.nn.functional as F
def absmean_quantize(weight: torch.Tensor):
"""三值量化:把浮点权重压到 {-1, 0, +1}。
返回 (int8 整数权重, 缩放因子 alpha)
"""
alpha = weight.abs().mean() # absmean 缩放因子
w_quant = torch.clamp(torch.round(weight / alpha), -1, 1)
return w_quant.to(torch.int8), alpha.item()
def absmax_quantize(x: torch.Tensor):
"""激活 8-bit 量化 (W8A8)。"""
beta = x.abs().max() + 1e-8
x_quant = torch.clamp(torch.round(x * 127.0 / beta), -127, 127)
return x_quant.to(torch.int8), beta.item()
4.2 一个可运行的 BitLinear 层
class BitLinear(torch.nn.Module):
def __init__(self, in_features: int, out_features: int, bias: bool = True):
super().__init__()
# 训练时仍保存浮点权重,量化在前向里完成
self.weight = torch.nn.Parameter(torch.randn(out_features, in_features) * 0.02)
self.bias = torch.nn.Parameter(torch.zeros(out_features)) if bias else None
# 缓存量化结果(推理时权重不变,算一次即可)
self.register_buffer("w_q", torch.zeros(out_features, in_features, dtype=torch.int8))
self.register_buffer("alpha", torch.zeros(1))
def _quantize_weight(self):
w_q, alpha = absmean_quantize(self.weight.data)
self.w_q.copy_(w_q)
self.alpha.fill_(alpha)
def forward(self, x: torch.Tensor) -> torch.Tensor:
if self.training:
# 训练路径:用 STE,前向量化、反向恒等
w_q, alpha = absmean_quantize(self.weight)
x_q, beta = absmax_quantize(x)
out = F.linear(x_q.float(), w_q.float()) * (alpha * beta / 127.0)
else:
# 推理路径:权重已量化缓存,只量化激活
if self.alpha.item() == 0:
self._quantize_weight()
x_q, beta = absmax_quantize(x)
out = F.linear(x_q.float(), self.w_q.float()) * (self.alpha.item() * beta / 127.0)
return out + self.bias if self.bias is not None else out
4.3 直观对比:FP16 路径 vs 1.58-bit 路径
torch.manual_seed(0)
W = torch.randn(8, 16) * 0.5
x = torch.randn(4, 16)
# FP16(浮点)路径
y_fp = F.linear(x, W)
# 1.58-bit 路径
w_q, alpha = absmean_quantize(W)
x_q, beta = absmax_quantize(x)
y_q = F.linear(x_q.float(), w_q.float()) * (alpha * beta / 127.0)
sim = F.cosine_similarity(y_fp.flatten(), y_q.flatten(), dim=0).item()
print(f"余弦相似度: {sim:.4f}")
print(f"权重被压成 0 的比例: {((w_q == 0).float().mean()).item():.2%}")
跑一下你会看到:即使只做了一次"朴素"量化(没有训练适应),输出向量的余弦相似度通常仍在 0.9 以上,而权重里大约有 30%–50% 变成了 0(这就是白捡的稀疏性)。如果模型是从头用 BitLinear 训出来的,这个相似度会更高。
4.4 用 bitnet.cpp 跑真实模型
自己实现是为了理解原理,真要落地还是用官方优化好的内核。bitnet.cpp 的用法(与 llama.cpp 风格一致):
# 1. 拉取并编译
git clone https://github.com/microsoft/BitNet.git
cd BitNet
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
# 2. 把 HuggingFace 上的 BitNet 权重转成优化的 gguf
# (框架会自动下载并做三值 + bit-packing 转换)
python -m bitnet.ffi.convert \
--input-path microsoft/bitnet-b1.58-2B \
--output-path ./models/bitnet-2B
# 3. 在 CPU 上推理(-t 指定线程数)
./build/bin/llama-cli \
-m ./models/bitnet-2B/ggml-model-i2_s.gguf \
-p "用一句话解释什么是 1.58-bit 量化" \
-n 256 -t 8
模型文件名里的 i2_s 就是 "2-bit integer / 三值"的标记,是 bitnet.cpp 专用的存储格式(实际用 2 个物理 bit 存一个三值权重,并做 kernel 友好的打包)。
4.5 与 llama.cpp INT4 做内存对照
# INT4 版同规模模型(以 7B 为例)权重约 3.5–4 GB
# 1.58-bit 版 7B 权重约 1.4 GB,几乎腰斩再腰斩
./build/bin/llama-bench -m ./models/bitnet-2B/ggml-model-i2_s.gguf -t 8
在内存受限的设备上,这个差距往往就是"能跑"和"OOM"的分界线。
五、性能优化:为什么 1-bit 在 CPU 上反而更快
这是整篇文章最反直觉、也最值得讲清楚的一点。
5.1 LLM 推理是带宽瓶颈,不是算力瓶颈
生成每一个 token,模型都要把全部权重从内存搬到计算单元做一次矩阵乘。对 70B 模型来说,一次前向要搬 140GB(FP16)数据。现代 CPU/GPU 的算力远远用不满,瓶颈卡在内存带宽上——数据还没搬完,计算单元就闲着了。
所以,提升推理速度最粗暴有效的办法,不是让计算更快,而是让要搬的数据更少。1.58-bit 把每次要搬的数据量降到 FP16 的 1/16、INT4 的 1/4。在 CPU 这种带宽本就紧张的设备上,收益被放大得最明显。
5.2 带宽数学:单 CPU 5–7 tok/s 是怎么来的
我们可以做一个一阶估算。decode(逐 token 生成)阶段,每生成一个 token 大约要把全部权重从内存读一遍,于是:
理论 tok/s ≈ 内存带宽 / (参数量 × 每参数字节数)
代入常见硬件的内存带宽:
| 硬件 | 内存带宽 | 100B @ FP16 (200GB) | 100B @ 1.58-bit (~19.75GB) |
|---|---|---|---|
| DDR4 双通道 | ~25.6 GB/s | ~0.13 tok/s(卡死) | ~1.3 tok/s |
| DDR5 双通道 | ~38–50 GB/s | ~0.2 tok/s | ~2–2.5 tok/s |
| Apple M2 统一内存 | ~100 GB/s | ~0.5 tok/s | ~5 tok/s |
| 服务器多通道内存 | ~150–200 GB/s | ~0.75 tok/s | ~7–10 tok/s |
可以看到,在 M2 或服务器多通道内存上,1.58-bit 的 100B 模型刚好落在"阅读速度"区间(5–7 tok/s),和 bitnet.cpp 的官方实测对得上。这个估算是一阶模型——真实内核通过 bit-packing 和 LUT 进一步减少了有效内存流量、提高了缓存命中率,所以实际数字往往比裸公式更乐观。核心结论不变:FP16 的 100B 在普通内存上根本跑不动,1.58-bit 让它从"不可能"变成"能看"。
5.3 bitnet.cpp 的内核优化
bitnet.cpp 不是简单地"用整数算然后除回来",它在内核层做了两件事:
- Bit packing(位打包):三值权重只有 3 种取值,用 2 个物理 bit 就能存一个权重(00/01/10 映射 -1/0/1)。一个 128-bit 的 CPU 寄存器本来只能装 8 个 FP16 权重,现在能塞进 64 个三值权重。
- LUT 乘加(查找表):激活是 8-bit,权重是三值。三值 × 8-bit 的结果只有 3 种可能(x、-x、0),预建成查找表后,乘加退化成查表 + 累加,完全避开浮点乘法。ARM 上用 NEON、x86 上用 AVX2 把这张表铺满向量寄存器,吞吐直接拉满。
官方实测:在 Apple M 系列(ARM)上,bitnet.cpp 相对同模型的 FP16 推理提速 1.37× 到 5.07×,模型越大提速越明显(因为大模型的带宽瓶颈更突出)。
5.4 一个反直觉结论:GPU 上 1-bit 收益有限
注意,1-bit 在 GPU 上提速没那么夸张,有时甚至更慢。原因有二:
- GPU 是计算密集架构,量化带来的"少搬数据"收益被它本就宽的总线部分抵消;
- GPU 上做三值量化的"量化/反量化"开销占比变高,而它的整数矩阵乘内核又不如 CPU 上那套 LUT 方案成熟。
所以工程选型上:1-bit 是端侧、CPU、NPU/手机/IoT 的利器;云端 GPU 集群上,INT4/INT8 仍是性价比之王。
5.5 调优 checklist
- 线程数
-t:CPU 上设成物理核数,别盲目拉满(超线程对带宽瓶颈帮助有限)。 - 序列长度:prefill(处理输入)阶段是算力峰值,decode(逐 token 生成)是带宽峰值;1-bit 主要优化 decode。
- batch size = 1:单用户本地推理,batch 大了反而把带宽吃满,抵消量化收益。
- 优先选专门训出来的 1-bit 模型:别拿 FP16 模型硬压。
六、进阶:接进 Transformer 与量化感知训练的坑
理解原理和实现单层只是第一步。真要把 1-bit 用起来,还有两道坎:怎么把它塞进完整的 Transformer,以及训练时那些只有踩过才知道的坑。
6.1 把 BitLinear 接进一个 Transformer 块
一个最小的 MLP 块,把所有 nn.Linear 换成 BitLinear 即可:
class BitMLP(torch.nn.Module):
def __init__(self, d_model: int, d_ff: int):
super().__init__()
self.fc1 = BitLinear(d_model, d_ff)
self.fc2 = BitLinear(d_ff, d_model)
self.act = torch.nn.GELU()
def forward(self, x):
return self.fc2(self.act(self.fc1(x)))
在真实 Transformer(如 Llama 结构)里,要替换的是:Q/K/V 投影、输出投影、每个 MLP 的两个线性层——也就是模型里几乎所有的 nn.Linear。保持浮点不动的只有 LayerNorm/RMSNorm、RoPE 旋转位置编码,以及残差连接里的加法。一个实用的经验是:让激活在残差流里始终以 8-bit 整数流动,只有"进 BitLinear 前量化、出 BitLinear 后反量化",这样整条前向几乎不碰浮点矩阵乘。这也是 BitNet 能既省内存又省算力的关键结构选择。
6.2 坑一:激活离群值(outlier)会毁掉 absmax
这是三值量化最容易翻车的地方。Transformer 的激活里通常有极少数维度数值极大(离群值),其余维度都小得多。absmax 量化用的是 β = max(|x|),于是这一个离群值就把 β 撑得巨大,导致其他所有正常维度被 127·x/β 压成 0——整个激活几乎全废。
对策来自 QuIP、SpinQuant 一脉的旋转变换:在量化前对激活做一层随机正交矩阵(常见是 Hadamard 旋转)乘法,把离群值的能量"摊平"到所有维度上,再做 absmax 量化就均匀多了。这也是为什么成熟的三值方案几乎都先旋转、再量化。一句话:没有旋转预处理的裸 absmax,十有八九会翻车。
6.3 坑二:STE 的梯度爆炸
回想第三节的 STE:前向量化、反向恒等。但 clip 区间外的权重,反向梯度是被置 0 的(否则会一直往 ±1 外推,没意义)。于是训练初期,大部分权重要么梯度恒等、要么梯度为 0,学习率稍大就会让区间内的权重瞬间全冲到 ±1 然后卡死。实际训练里要:学习率比 FP16 训小一个数量级、warmup 拉长、并且对 clip 区间外的梯度做 soft 截断。BitNet 论文原版用的就是非常克制的优化器配置。
6.4 坑三:一定要走 QAT,别迷信 PTQ
再强调一次:把 FP16 模型直接后量化到三值,困惑度会塌方。最少也要做几百步的量化感知微调(QAT warmup)——用 BitLinear 替换后,以小学习率跑一小段数据,让权重重新适应三值约束。社区里能用的 1-bit 模型(BitNet b1.58 2B/3B、本月昇腾上的 BitCPM-CANN)无一例外都是专门训出来的。如果你手里只有 FP16 大模型又想上 1-bit,最现实的路径是:换用现成的 1-bit 基座模型做下游微调,而不是自己压。
6.5 什么时候该上 1-bit:一张决策表
| 场景 | 推荐精度 | 理由 |
|---|---|---|
| 手机/IoT/车机离线推理 | 1.58-bit | 内存装得下,CPU 能跑,隐私不出端 |
| 单机本地助手(笔记本 CPU) | 1.58-bit / INT4 | 看精度要求,低精度任务优先 1-bit |
| 云端高并发 API | INT4 / INT8 | GPU 上 1-bit 收益低,INT4 性价比最高 |
| 复杂推理 / 数学 / 代码生成 | INT8 / FP16 | 三值精度上限不够 |
| RAG/Agent 长期记忆压缩 | 1.58-bit | 背景知识模型越小越好,主推理交大模型 |
七、总结与展望
7.1 1-bit 不是银弹
把话说回来,极限量化有三道硬伤,工程上必须正视:
- 精度上限:三值只有 3 个取值,复杂推理、精确数学、长链逻辑任务上还是会掉点,别指望它替代 FP16 旗舰模型。
- 训练成本高:几乎必须从头量化感知训练,不能 PTQ 硬压,社区可用模型还少(主要集中在 2B/3B 档)。
- 工具链早期:bitnet.cpp 还在快速迭代,NPU 支持(论文里说"coming next")和国产算力适配(如本月昇腾上的 BitCPM-CANN)刚起步。但趋势已经很明确:当压缩技术成熟到这个地步,"大模型必须驻留在机房"的惯性认知,正在被一行行能在手机上跑起来的代码悄悄改写。对工程团队来说,现在就值得把 1-bit 列入端侧方案的候选清单,而不是等它"再成熟一点"才去评估。
7.2 2026 年的三个真实落地方向
- 端侧/边缘 AI:手机本地助手、车机离线语音、IoT 设备上的轻量 Agent——这些场景容不下 140GB,1.58-bit 是少有的可行解。本月趋势里的 Bonsai-demo、BitCPM-CANN 都指向这里。
- 隐私优先部署:数据不出本机(医疗、金融、政企内网),CPU 本地推理比云端 API 更符合合规。
- Agent 长期记忆压缩:Agent 要把对话历史/知识常驻内存,用 1-bit 把"背景知识模型"压到极小,主推理交给大模型,是一种很有想象力的混合架构。
7.3 工程选型一句话建议
如果你的场景是离线、隐私、低端设备、且任务不要求顶尖推理精度——上 1-bit,立刻就能跑起来;如果你要的是最高精度、复杂推理、云端高并发——老老实实用 INT4/INT8,别凑这个热闹。
最后给一句更落地的工程提醒:判断一个项目要不要上 1-bit,先问自己三个问题——设备装得下 FP16 或 INT4 吗?(装不下才轮到 1-bit 出场)任务对精度敏不敏感?(数学、长链推理这类敏感任务直接排除)数据能不能出端?(涉密、合规场景不能出端,1-bit 几乎是唯一选择)。三个问题答完,该不该上基本就清楚了,不用纠结。量化从来不是银弹,但 1.58-bit 确确实实把"在本地、在手机、在车机里跑大模型"这件事,从 PPT 上的概念变成了命令行里一行 ./llama-cli 就能起来的现实。理解了它背后的带宽逻辑,你也就理解了未来几年端侧 AI 为什么一定会越来越小、越来越快。
极限量化不会取代大模型,但它把"大模型能去的地方"从机房一路延伸到了你的口袋。2026 年,当 100B 模型开始在你笔记本的单颗 CPU 上以阅读速度吐字时,我们会更清楚地看到:AI 民主化的最后一里路,往往不是更大的模型,而是更狠的压缩。
7.4 关于 1-bit 的三个常见误区
误区一:"1-bit 就是把模型变小,精度肯定崩。" 半对半错。纯二值(1-bit)确实掉点明显,但 1.58-bit 三值配合从头量化感知训练,在同参数量下困惑度能追平 FP16 的八到九成,小模型(2B/3B)场景下体感差距很小。它真正崩的是"精确数学、长链推理"这类任务,而不是所有任务——别一棍子打死。
误区二:"有 bitnet.cpp 就能把任何大模型压成 1-bit。" 不能。bitnet.cpp 只是推理框架,它跑的是"本来就按三值训出来的模型"。你手里的 FP16 Llama 70B 直接丢进去,要么转换失败,要么精度塌方。正确姿势是用官方发布的 BitNet 1-bit 基座做下游,而不是自己压通用大模型。
误区三:"GPU 上用 1-bit 一定最快。" 恰恰相反。GPU 带宽本就宽,1-bit 省下的搬运收益被摊薄,而量化/反量化的额外开销反而拖累;GPU 上 INT4 仍是性价比之王。1-bit 的真正主场是 CPU、NPU、手机和 IoT——这些带宽紧张、又装不下大模型的场景。
参考资料与工具:microsoft/BitNet、bitnet.cpp、BitCPM-CANN(昇腾 1.58-bit)、本月 GitHub 热榜 1-bit 量化 Demo(Bonsai 等)、QuIP/SpinQuant 旋转量化。建议动手跑一遍第四节的代码,亲眼看一眼三值量化到底损失了多少、又省了多少;再照第六节把 BitLinear 塞进你自己的小 Transformer,感受带宽瓶颈消失的那一刻。