如果你听说一个大模型的全部权重只能用 -1、0、1 三个数来表示,同时它的任务效果还能对齐全精度的 LLaMA 基线,你大概率会先怀疑:这是标题党,还是压缩算法的魔法?
这不是魔法。2024 年 10 月微软研究院公开的 BitNet b1.58 论文,标题就叫《The Era of 1-bit LLMs: All Large Language Models are in 1.58 Bits》。它把 Transformer 里所有线性层的权重矩阵全部量化到三值空间,也就是每个权重只取 {-1, 0, +1} 三种状态,信息论意义上的位宽只有 log2(3) ≈ 1.58 位。
我的判断是:1.58 位并不是把量化精度又往下“削了一刀”,而是把神经网络里最核心的矩阵乘法,从“乘加运算”变成了“加减和跳过”。从 AI Infra 的视角看,这是计算范式层面的变化,不只是内存变小的附带好处。
这篇文章会把下面几个问题讲透:
- 1.58 位、三值权重这些概念到底是什么意思;
- BitNet b1.58 的量化算法是怎么设计的,为什么模型没有崩;
- 省下的账到底算在内存、带宽还是算力上;
- 给你一份能跑的最小 PyTorch 实现,以及训练和部署时必须避开的坑。
如果你正在做大模型推理优化、量化部署、AI 芯片或 AI Infra 相关工作,这篇值得收藏后读完。
1. 这篇文章真正要解决的问题
先回到一个非常现实的问题:大模型推理为什么贵?
当你部署一个 70B 模型时,显存里装的主要是权重。FP16 权重每个占 2 字节,70B 权重就是 140GB,单卡 A100 的 80GB 显存根本装不下。就算装下了,每次推理都要把权重从 HBM 搬到计算单元,内存带宽决定吞吐上限。很多场景里,模型不是“算不动”,而是“搬不动”。
于是量化成了必选项。INT8、FP8、INT4 都是把权重位宽往下压,但压到一定程度,精度损失就开始放大。各家推理框架都在 4-bit 附近打转,很少继续往下走,因为大家都默认位宽越低、模型越笨。
BitNet b1.58 打破了这条默认路径。它不是说“我再把 4-bit 压到 2-bit”,而是直接用三值权重训练模型,让模型从第一天起就适应“权重只能是 -1、0、1”这个约束。结果是在 3B 规模下,它的困惑度和下游任务表现对齐了 FP16 的 LLaMA 对照模型,同时吞吐提升 2.71 倍,显存占用降为原来的约 1/3.55。
所以这篇文章真正要解决的问题是:为什么三个数字就能撑起一个大模型?以及这种模型在工程上到底怎么落地、适合什么场景、不适合什么场景。
读完你应该能形成三个清晰的判断:
- 1.58 位的核心收益不在“省显存”本身,而在矩阵乘法从乘加变成加减运算,这改变了硬件设计的成本模型;
- 它不能通过后量化把现成的 FP16 模型转成三值权重,必须从零开始做量化感知训练;
- 在没有定制 kernel 的通用 GPU 上,你不一定能拿到论文里的提升,落地前必须做实测。
2. 基础概念:1.58 位、三值权重与常见量化对比
2.1 什么是量化
量化就是把连续取值映射到有限离散值的过程。模型的权重和激活原本是 FP16 或 BF16 的高精度数值,量化后变成 INT8、INT4 这种更窄的表示,目的是减少存储和计算开销。
传统量化关心的是“如何逼近原始数值”,误差越小越好。比如 INT8 有 256 个取值等级,INT4 有 16 个等级。量化后一般还需要做反量化,把结果缩放回原始范围,精度损失主要发生在这一步。
2.2 三值权重:{-1, 0, +1}
BitNet b1.58 的权重不是 256 个等级,也不是 16 个等级,而是只有三个:
-1, 0, +1每个权重要么是正方向上的激活,要么是负方向上的抑制,要么是零。零这个状态非常关键,它让模型可以“关掉”一部分连接,这相当于在三值空间里内嵌了一定程度的稀疏性。传统二值量化只有 {-1, +1},没有“无所谓”这个选项,表达能力弱得多。
2.3 为什么叫 1.58 位
三个取值的信息量就是 log2(3) ≈ 1.58496 位,约等于 1.58 位。这是信息论的下限,不是说有 1.58 个比特的物理存储。
实际落地时,为了寻址方便,主流做法是用 2 个比特表示一个三值权重(00、01、10),一个字节能放 4 个权重。更紧凑的打包可以做到 5 个权重塞进一个字节,因为 3 的 5 次方等于 243,刚好小于 256,代价是解包时要做查表或位运算。
2.4 量化和位宽方案对比
| 方案 | 权重取值范围 | 理论位宽 | 特点 |
|---|---|---|---|
| FP16 | 浮点数 | 16 bit | 精度高,存储和带宽开销大 |
| INT8 | -128 ~ 127 | 8 bit | 当前主流后量化方案,生态成熟 |
| FP8 | 有限浮点 | 8 bit | 新一代 GPU 支持,混合精度训练常用 |
| INT4 | -8 ~ 7 | 4 bit | 部署常见,精度损失需校准 |
| 1-bit 二值 | {-1, +1} | 1 bit | 无零状态,表达能力受限 |
| 1.58-bit 三值 | {-1, 0, +1} | log2(3) ≈ 1.58 bit | 有零状态,乘法变加减 |
2.5 从 BitNet 到 BitNet b1.58
微软最早提出的 BitNet 是 1-bit 模型,权重只取 {-1, +1}。b1.58 是在这个基础上的扩展,增加了零值,同时把激活量化成 8 位整数。零值让模型不是简单的“正反二值”,而是可以表达“这条连接不重要”,这对维持模型表达能力非常关键。
一个辅助理解的角度:三值权重不是“压缩后的 FP16”,而是一种从头训练出来的、和约束共存的参数表示。它更像“原生低比特模型”,而不是“事后瘦身”。
3. 核心原理:BitNet b1.58 的量化方案拆解
3.1 权重三值化:absmean 量化
BitNet b1.58 的权重量化分为三步。
第一步,计算权重矩阵的平均绝对值 gamma:
gamma = mean(|W|)第二步,把每个权重除以 gamma,做归一化:
W_norm = W / gamma第三步,用阈值 0.5 做四舍五入并截断到 [-1, 1]:
W_q = clamp(round(W_norm), -1, 1)用阈值 0.5 的含义是:归一化后绝对值小于 0.5 的权重被清零,大于 0.5 的保留正负号。这个过程看起来很粗暴,但 gamma 是动态计算的,每个权重矩阵会自适应地落到 {-1, 0, +1} 这个集合里。
用一个具体例子说明。假设一行权重是:
W = [0.20, -0.90, 1.30, -0.60, 0.05]平均绝对值是 0.61,归一化后变成:
W_norm = [0.33, -1.48, 2.13, -0.98, 0.08]按 0.5 阈值做三值化:
W_q = [0, -1, 1, -1, 0]原先是正的小权重 0.2 变成了零,负的大权重 -0.9 变成了 -1,正的大权重 1.3 变成了 1。信息确实有损失,但 gamma 缩放会在后续矩阵乘里补偿数值范围。
3.2 激活量化:per-token 的 8 位量化
权重可以三值化,激活不能用三值化。激活的取值随输入变化,动态范围大,如果也压成三个值,信息会严重丢失。
BitNet b1.58 的做法是对激活做 8 位整数量化,而且按 per-token 方式计算缩放因子。每个 token 对应的那一整行激活,用各自的最大绝对值做缩放:
scale = max(|x|) # 按 token 维度计算 x_q = clamp(round(x / scale * 127), -127, 127)为什么按 token 而不是按整个矩阵?因为不同位置的 token 激活分布差异可能很大,全局一个缩放因子会放大量化误差,per-token 可以保证每个 token 行都能充分利用 8 位的动态范围。
在通用 GPU 上,量化后的 INT8 激活通常会再转回 BF16 做矩阵乘,因为现有矩阵乘单元不一定支持直接拿 INT8 激活和低比特权重做运算。在专用硬件上,这一步可以全程保留整数计算。
3.3 非线性部分保持高精度
不是所有的东西都是 1.58 位。LayerNorm、Softmax、GELU 这些非线性算子,以及注意力得分计算,仍然保留在 BF16 或 FP32。原因很直接:这些算子的输入输出分布极不稳定,强行低比特化会造成数值崩溃,收益也不大。
矩阵乘的累加器通常用 FP32 或 INT32 来减少累加误差。这是量化模型里非常容易被忽略的部分,累加精度不够,低位宽权重的误差会被放大。
3.4 这里真正容易踩坑的地方
最容易踩的坑是:把 BitNet b1.58 当成一个“压缩工具”,以为可以直接加载一个 FP16 模型,然后用三值量化做推理。这个思路对 INT8、INT4 可能有效,对三值权重几乎必崩。
原因在于,三值化是一个极端非线性的映射,FP16 模型学到的权重分布完全不是围绕 -1、0、1 分布的,硬切过去等于把大部分权重信息直接丢弃,而且无法靠一个缩放因子找回。
BitNet b1.58 的做法是量化感知训练:模型从随机初始化开始,训练时就使用三值权重参与前向传播,让整个网络在“权重只能是三个值”的约束下调整参数和激活分布。这个区别是整篇文章最值得记住的一点。
4. 从 AI Infra 角度看收益:内存、能耗、吞吐
4.1 内存和带宽账怎么算
以 70B 参数模型为例:
- FP16 权重:70B × 2 字节 = 140GB;
- 三值权重按 2 比特存储:70B × 0.25 字节 = 17.5GB;
- 如果做 5 权重 1 字节的紧凑打包,约 14GB。
从 140GB 到 17.5GB,权重占用的显存缩小到原来的八分之一。对推理服务来说,这直接决定了能不能单卡部署,也决定了权重复用时的带宽压力。
但这里要泼一盆冷水:模型权重只是显存的一部分。推理时的激活、KV Cache、临时中间结果仍然占用大量显存。三值化解决的是“权重读带宽”这半边问题,KV Cache 和激活的优化是另外半边,需要通过 8 位 KV Cache 等方案继续处理。
4.2 计算模型的变化:乘法变加减
这是 1.58 位最核心的硬件价值。
一个常规线性层的输出是:
y_i = sum_j (w_ij * x_j)当权重只有 -1、0、1 时,乘法变为:
w = +1 时,累加 x_j w = -1 时,累减 x_j w = 0 时,跳过也就是说,矩阵乘的乘加单元(MAC,multiply-accumulate)可以直接替换为加减单元。微电子领域里,加法器在面积、功耗、延迟上比乘法器低一个量级,这是三值模型对芯片设计最具有吸引力的地方。
对于现有 GPU,情况略微复杂。你依然可以用 INT8 或 BF16 的矩阵乘去模拟三值权重,但这样做拿不到“乘法消失”的红利,主要收益来自权重体积变小带来的带宽下降。要拿到论文里的 2.71 倍吞吐提升,必须依赖为三值权重定制实现的算子或专用硬件。
4.3 论文报告的收益数据
论文里最关键的一组数据是 3B 规模下的对比:
- 效果上,BitNet b1.58 3B 在困惑度和下游任务上和 FP16 的 LLaMA 对照基本持平;
- 吞吐上,三值版本比 FP16 版本快约 2.71 倍;
- 显存上,三值版本占用约为 FP16 版本的 1/3.55。
论文还强调,三值模型同样遵循参数规模缩放规律,70B 级别的三值模型可以在有限 GPU 资源下高效运行,显存成本相比 FP16 大幅下降。也就是说,位宽虽低,但不是只能在小模型上玩的花活。
4.4 对部署形态的影响
三值模型最大的意义可能不在数据中心,而在端侧和边缘设备。权重小、带宽需求低、加减运算的门槛低,这让 CPU 推理、FPGA 实现和专用 NPU 都有了新的设计空间。微软后续也开源了面向三值模型的 CPU 推理方向的工作,这条链路正在从论文走向工程。
5. 最小代码实现:三值量化线性层
下面用 PyTorch 写一个可运行的最小实现。它不是论文的完整复现,但完整覆盖了权重三值化、激活 8 位量化和直通估计器(STE)这几个关键机制。
5.1 环境准备
- Python 3.10 及以上;
- PyTorch 2.x;
- 不需要额外依赖,CPU 上即可验证。
如果你要在 GPU 上训练,建议使用 BF16 混合精度,但代码本身不依赖 GPU。
5.2 量化函数实现
先写两个量化函数,一个是权重三值化,一个是激活 8 位量化。
import torch import torch.nn as nn import torch.nn.functional as F def ternary_weight_quantize(W: torch.Tensor): """ 权重三值化:将权重映射到 {-1, 0, +1}。 使用 absmean 量化: 1. 计算权重平均绝对值 gamma; 2. 权重除以 gamma 归一化; 3. 用 0.5 阈值四舍五入并截断。 """ gamma = W.abs().mean().clamp(min=1e-6) W_norm = W / gamma W_ternary = torch.clamp(torch.round(W_norm), -1, 1) return W_ternary, gamma def activation_quantize_int8(x: torch.Tensor): """ 激活 8 位量化:per-token 方式。 每个 token 对应的一行,用该行的最大绝对值作为缩放因子。 量化到 [-127, 127] 后,再反量化回原始数值范围。 """ scale = x.abs().amax(dim=-1, keepdim=True).clamp(min=1e-6) x_q = torch.clamp(torch.round(x / scale * 127), -127, 127) x_deq = x_q / 127.0 * scale return x_deq, scale可以先拿一个小矩阵验证:
W = torch.tensor([[0.20, -0.90, 1.30, -0.60, 0.05]]) W_q, gamma = ternary_weight_quantize(W) print(W_q) # 预期输出类似 [0, -1, 1, -1, 0] assert set(W_q.unique().tolist()).issubset({-1.0, 0.0, 1.0})5.3 BitLinear 层与直通估计器
直接使用三值权重做前向会带来一个问题:round和clamp不可导,训练时梯度会全部消失。解决方法是直通估计器(Straight-Through Estimator),前向使用量化后的权重,反向把量化函数近似为恒等映射。
class BitLinear(nn.Module): """ 三值权重线性层。 前向过程: 1. 权重三值化; 2. 激活 8 位量化; 3. 用三值权重做矩阵乘; 4. 乘回缩放因子 gamma。 训练时通过 STE 让梯度穿过量化函数。 """ def __init__(self, in_features: int, out_features: int): super().__init__() self.weight = nn.Parameter(torch.randn(out_features, in_features) * 0.02) def forward(self, x: torch.Tensor) -> torch.Tensor: W_ternary, gamma = ternary_weight_quantize(self.weight) # STE 技巧:前向使用 W_ternary,反向梯度等价于恒等映射 W_effective = W_ternary + self.weight - self.weight.detach() x_q, _ = activation_quantize_int8(x) out = F.linear(x_q, W_effective) return out * gamma解释一下关键行:
W_effective = W_ternary + self.weight - self.weight.detach()前向传播时,self.weight - self.weight.detach()等于 0,所以实际参与计算的是W_ternary。反向传播时,W_ternary对self.weight的导数是 0,但self.weight - self.weight.detach()对self.weight的导数是 1,合成之后梯度可以直接回传到原始权重上。这是 QAT 里最常见的 STE 写法。
5.4 替换注意力投影
把标准多头自注意力里的 QKV 和输出投影替换成 BitLinear 即可,其他结构不变。
class TinyBitAttention(nn.Module): def __init__(self, d_model: int, n_heads: int): super().__init__() self.n_heads = n_heads self.d_head = d_model // n_heads self.q_proj = BitLinear(d_model, d_model) self.k_proj = BitLinear(d_model, d_model) self.v_proj = BitLinear(d_model, d_model) self.o_proj = BitLinear(d_model, d_model) def forward(self, x: torch.Tensor) -> torch.Tensor: b, t, c = x.shape q = self.q_proj(x).view(b, t, self.n_heads, self.d_head).transpose(1, 2) k = self.k_proj(x).view(b, t, self.n_heads, self.d_head).transpose(1, 2) v = self.v_proj(x).view(b, t, self.n_heads, self.d_head).transpose(1, 2) attn = F.softmax(q @ k.transpose(-1, -2) / (self.d_head ** 0.5), dim=-1) out = (attn @ v).transpose(1, 2).reshape(b, t, c) return self.o_proj(out)需要注意:上面代码省略了因果掩码、LayerNorm 以及位置编码,只用于演示投影层替换方式。实际训练时,每个 Block 入口应该先做 LayerNorm,再做投影,这一点对应论文中对输入分布稳定性的设计。
5.5 训练配置示例
下面是一份训练配置示例,可以根据自己项目调整:
model: name: bitnet_tiny hidden_size: 256 num_layers: 4 num_heads: 4 vocab_size: 10000 max_seq_len: 128 quantization: weight: ternary # 权重只用 {-1, 0, +1} weight_storage_bit: 2 # 物理存储按 2 位 activation: int8 # 激活 8 位 per-token 量化 nonlinear_part: bf16 # LayerNorm / GELU / Softmax 保持高精度 training: lr: 2.0e-4 warmup_steps: 2000 total_steps: 100000 batch_size: 64 grad_clip: 1.0训练循环核心部分:
optimizer = torch.optim.AdamW(model.parameters(), lr=2e-4, weight_decay=0.1) for step in range(10000): x_batch, y_batch = next_batch() # 自行准备数据 logits = model(x_batch) loss = F.cross_entropy(logits.view(-1, logits.size(-1)), y_batch.view(-1)) loss.backward() torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) optimizer.step() optimizer.zero_grad()5.6 如何运行和验证结果
用一个几千万参数的玩具模型,在小型语料上跑通整个训练流程后,可以这样验证:
- 检查权重确实三值化:训练结束后打印
model.q_proj.weight,应该观察到大量 0 和正负 1 附近的分布,说明量化约束生效; - 对比同一规模的 FP16 Transformer,观察困惑度是否接近;
- 推理时把
BitLinear.forward里的 STE 分支去掉,或者直接用torch.no_grad()之后的三值权重参与计算,确认输出稳定。
如果训练 loss 在初期就不降,优先检查:
- 是否用了 STE,梯度是否为零;
- 学习率是否过大;
- 是否在 LayerNorm 之后再做量化。
6. 训练与推理的工程要点
6.1 从零训练是唯一的可靠路径
必须再次强调:BitNet b1.58 的性能来自量化感知训练,不是后量化。你没办法加载一个 LLaMA 的 FP16 权重,然后直接转成三值权重用来部署,精度会崩得很彻底。
如果确实要在一个已有模型上做低比特化,可以尝试长时间 QAT 恢复训练,也就是用原有权重做初始化,但强制前向使用三值权重继续训练几十万步。这个方案成本不低,效果也未必能对齐从零训练,实践中要提前做好评估。
6.2 训练稳定性控制
三值化引入了强非线性,训练时数值稳定性需要重点管理:
- 使用 AdamW 时,学习率不要太大,2e-4 到 5e-4 是现金流范围;
- 打开梯度裁剪,范围 0.5 到 1.0 比较安全;
- 监控 gamma 的数值,gamma 是权重平均绝对值,如果持续变大或突变,说明权重分布出了问题;
- 监控激活量化后的位分布,如果大量集中在 ±127,说明 per-token 缩放不稳定。
6.3 推理 kernel 与内存布局
论文的吞吐收益依赖专门的推理算子。在通用框架里,直接把三值权重存成 INT8 走通用 GEMM,虽然能跑,但无法发挥“乘法变加减”的优势。
实用的内存布局有两种:
- 2 位存储:一个字节存 4 个三值权重,解包简单,适合带宽敏感但计算单元通用的场景;
- 5 权重打包:5 个权重用 3^5=243 种状态编码进 1 个字节,接近 1.58 位的理论下限,但解包需要查表或位运算,要评估解包开销换来带宽收益是否划算。
6.4 KV Cache 和通信不能忽视
三值化把权重内存降了很多,但大模型推理的显存大头不只有权重。长上下文场景下,KV Cache 会和序列长度线性增长,甚至成为主要瓶颈。论文里的激活量化是 8 位,KV Cache 也有继续量化的空间,二者是独立优化维度,可以叠加使用。
在多卡推理时,权重变小也意味着通信量变小,这对张量并行是利好,但通信的固定开销不会因为权重三值化消失。
7. 常见问题与误区排查
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 训练 loss 不降或急剧升高 | 梯度被量化函数截断;学习率过大;没有使用 STE | 检查权重梯度范数;对比是否禁用 QAT | 引入 STE;调低学习率;先在小模型上复现 |
| 直接加载 FP16 模型三值化后效果崩坏 | 使用了后量化路线 | 查看单 layer 输出差异 | 改为从零训练或长周期 QAT 恢复 |
| 激活量化后训练不稳定 | per-token 缩放异常;出现 NaN | 打印激活 scale 统计 | 检查归一化前置层;加 epsilon;必要时降激活量化位宽 |
| 推理速度没有提升 | 没有定制 kernel | 用 profiler 查看算子和内存耗时 | 更换专用三值 kernel;或改用更紧凑的权重打包 |
| 显存降了但延迟没降 | 模型变成带宽不敏感,算子成了瓶颈 | 分别测计算量和带宽占比 | 优化算子展开;考虑批量推理提升带宽利用率 |
7.1 常见的三个概念误区
误区一:1.58 位就是 2 位量化。2 位量化有 4 个状态,三值权重只有 3 个状态。1.58 是信息论位宽,物理上更常用 2 位容器,但语义和表达力完全不同。
误区二:三值模型一定比 INT8 快。在没有定制算子的通用 GPU 上,三值权重通常还是要走模拟计算,提升主要来自带宽下降。要拿到质的提升,必须用支持三值累加的精简内核或专用硬件。
误区三:这个技术已经能直接替换现有部署。现阶段 BitNet 类模型需要从零训练,这意味着模型权重、训练流程、推理栈全部要配套支持。对于已经投入成本训练好的 FP16 模型,转成三值的迁移成本远高于 INT8 或 INT4 方案。
8. 最佳实践与工程建议
8.1 什么场景适合引入 1.58 位
适合:
- 显存和带宽是主要约束的端侧推理场景;
- 高通量、长上下文的批量推理服务,权重搬移占比高;
- 自研 FPGA、ASIC 或 NPU,希望在硬件层去掉乘法器;
- 从零训练新模型并且评估质量容错度。
不适合:
- 已经有稳定 FP16 或 INT8 模型,且没有重新训练预算;
- 团队没有底层算子开发能力,只靠通用框架搬运;
- 任务对极小精度损失极其敏感,且无法通过校准兜底。
8.2 落地时的操作清单
推荐按下面的顺序推进:
- 先用 100M 到 1B 的模型做 QAT 训练实验,验证质量对比;
- 完成权重三值化验证,确认训练完成后权重分布符合预期;
- 用 profiling 工具对比三值实现与 INT8/FP16 基线在目标硬件上的差异;
- 评估打包方案,优先选 2 位存储,再做 5 权重打包的收益测试;
- 部署阶段把 KV Cache 量化、连续批处理、投机采样等优化叠加进来,看整体吞吐是否还有增量。
8.3 质量验证不能只看 loss
训练 loss 下降不代表下游任务没问题。建议准备一个固定的评测集,对比三值模型和 FP16 基线在不同任务上的差距。特别要关注长文本、代码生成、多轮对话这类对细节敏感的指标,因为这些任务最容易暴露量化误差积累。
8.4 关注开源生态与工具链
三值大模型正在从论文走向开源实现。微软官方开源了面向 BitNet 类模型的推理工具链,社区里也出现了大量基于 PyTorch 的三值量化训练复现。建议在做技术选型前,先跑通一个公开的模型权重和推理 demo,再评估是否要把自己的训练链路改造成 QAT 模式。
工具链成熟度是当前最大的风险点。你别只盯着理论位宽,要确认推理框架、算子库、模型转换工具、微调流程是否都支持三值权重,这一条链路缺一环,项目推进都会很吃力。
9. 总结与后续学习方向
这篇文章真正讲清楚了几件事。
第一,1.58 位不是简单的“更激进的量化”,而是把模型权重放进三值空间,核心价值在于矩阵乘法从乘加运算变成加减运算,这改变了 LLM 推理的成本结构。
第二,BitNet b1.58 的核心机制是 absmean 权重量化加 per-token 8 位激活量化,非线性部分保留高精度,模型必须从零训练,通过 STE 让梯度穿过不可导的量化函数。
第三,工程落地的收益需要分清楚:内存和带宽的收益是确定的,计算加速则依赖专用 kernel 或硬件。论文里快速、省显存的数据是定制实现下的结果,通用 GPU 上需要重新实测。
如果你想继续深入,建议按这个顺序往下学:
- KV Cache 量化,解决长上下文场景的显存瓶颈;
- 激活值的进一步低比特化,判断 8 位激活是不是下一块硬骨头;
- 三值模型与 MoE、稀疏化的结合,看看能不能把稀疏性和低比特叠加;
- CPU 和 FPGA 上的三值矩阵乘算子实现,理解带宽受限场景下真正有效的循环展开和打包方式。
动手时有一条实用的建议:先用一个亿级以内的小模型把 QAT 全流程跑通,不要直接冲向 70B。验证完质量、稳定性和性能三项指标后,再决定是否把三值化引入你真正负责的业务项目。技术选型的判断,永远要建立在你能复现的数据上。