开发者指南 / Keras 中的量化

Keras 中的量化

作者: Jyotinder Singh
创建日期 2025/10/09
最后修改日期 2025/10/09
描述: Keras 中量化的概述(int8、float8、int4、GPTQ)。

在 Colab 中查看 GitHub 源代码


简介

现代大型模型通常是内存和带宽受限的:大部分推理时间都花在了将张量在内存和计算单元之间移动上,而不是进行数学运算。量化减少了用于表示模型权重和(可选)激活值的比特数,这

  • 缩小了模型大小和 VRAM/RAM 占用空间。
  • 提高了有效内存带宽(每个值使用的字节更少)。
  • 在支持低精度内核的硬件上可以提高吞吐量,有时也能降低延迟。

Keras 提供了头等舱的训练后量化 (PTQ) 工作流程,支持预训练模型,并在模型和层级别公开统一的 API。

总的来说,Keras 支持

  • int4int8float8 中的联合权重+激活 PTQ。
  • 通过GPTQ (2/3/4/8 位) 进行仅权重 PTQ,以在最小化精度影响的情况下最大化压缩,尤其适用于大型语言模型 (LLM)。

术语

  • 比例因子/零点: 量化使用比例因子(和可选的零点)将实数值 x 映射到整数 q。对称方案仅使用比例因子。
  • 每个通道 vs 每个张量: 每个输出通道(例如,每个隐藏单元)的独立比例因子通常比整个张量的单一比例因子能更好地保留精度。
  • 校准: 对样本数据进行短暂的传递,以估算激活范围(例如,最大绝对值)。

量化模式

Keras 目前专注于以下数值格式。每种模式都可以通过相同的 API 选择性地应用于层或整个模型。

  • int8 (8 位整数)联合权重+激活 PTQ。

    • 工作原理: 值通过每个通道的比例因子线性映射到 8 位整数。使用动态量化(见下文注释)校准激活。
    • 为何使用: 对许多架构具有良好的精度;广泛的硬件支持。
    • 预期效果: 参数比 FP32 小约 4 倍(比 FP16 小约 2 倍),激活带宽更低,许多任务上的精度损失很小。吞吐量增益取决于内核可用性和内存带宽。
  • float8 (FP8: E4M3 / E5M2 变体):低精度浮点数,可用于 FP8 兼容硬件上的训练和推理。

    • 工作原理: 使用动态比例因子将值量化为 FP8。支持设备的融合 FP8 内核可带来加速。
    • 为何使用: 混合精度训练/推理,带有硬件加速,同时保留浮点语义(因为上溢/下溢特性与整数不同)。
    • 预期效果: 在有 FP8 内核可用时,性能和内存节省具有竞争力;精度因模型而异,但对大多数任务来说通常是可接受的。
  • int4:超低比特权重,用于激进压缩;激活值保持更高精度(int8)。

    • 工作原理: 每个 int8 字节打包两个有符号 4 位“半字节”。Keras 使用对称的每输出通道比例因子,在 matmul 内部高效地反量化。
    • 为何使用: 在与强大的每通道缩放结合时,为 LLM 提供显著的 VRAM/存储空间节省,同时保持可接受的精度。
    • 预期效果: 权重比 FP32 小约 8 倍(比 FP16 小约 4 倍);吞吐量增益取决于内核可用性和内存带宽。对于仅编码器架构,精度差异具有竞争力,对于仅解码器模型,可能会出现更大的回归。
  • GPTQ (仅权重 2/3/4/8 位)二阶、训练后方法,可最小化层输出误差。

    • 工作原理 (简述): 对于每个权重块(组),GPTQ 使用基于小型校准集构建的海森矩阵近似来解决局部最小二乘问题,然后量化为低比特宽度。结果是打包的权重张量加上每组参数(例如,比例因子)。
    • 为何使用: 在非常低的比特宽度下,无需重新训练即可保持强大的精度,非常适合快速 LLM 压缩。
    • 预期效果: 在许多仅解码器模型上,存储/VRAM 大幅节省,困惑度/精度差异很小,前提是使用与任务相关的样本进行校准。

实现说明

  • 动态激活量化:在 int4int8 PTQ 路径中,激活比例因子在运行时(每个张量和每个批次)通过 AbsMax 估计器动态计算。这避免了维护来自校准传递的单独、固定的激活比例因子集,并适应变化的输入范围。
  • 4 位打包:对于 int4,Keras 打包有符号 4 位值(范围 = [-8, 7])并存储每通道比例因子,例如 kernel_scale。反量化是实时进行的,matmul 使用 8 位(解包后)内核。
  • 校准策略int4 / int8 / float8 的激活缩放默认使用AbsMax 校准(范围由观察到的最大绝对值确定)。将来的版本可能会添加替代校准方法(例如,百分位数)。
  • 对于支持的权重,每通道缩放是默认选项,因为它在可忽略的开销下显著提高了精度。

量化 Keras 模型

量化在层或模型构建后显式应用。API 的设计是可预测的:您调用 quantize,图被重写,权重被替换,然后您可以立即运行推理或保存模型。

典型工作流程

  1. 构建/加载您的 FP 模型。 如果需要,请进行训练。确保 build() 或一次前向传递已使权重具体化。
  2. (仅 GPTQ) 对于 GPTQ,Keras 会运行一个简短的校准传递来收集激活统计信息。您需要为此提供一个小型、代表性的数据集。
  3. 调用量化。 调用 model.quantize("<mode>")layer.quantize("<mode>"),模式为 "int8""int4""float8""gptq"(仅权重)。
  4. 使用或保存。 运行推理,或 model.save(...)。量化状态(打包权重、比例因子、元数据)在保存/加载时得以保留。

模型量化

import keras
import numpy as np

# Create a random number generator.
rng = np.random.default_rng()

# Sample training data.
x_train = rng.random((100, 10)).astype("float32")
y_train = rng.random((100, 1)).astype("float32")

# Build the model.
model = keras.Sequential(
    [
        keras.Input(shape=(10,)),
        keras.layers.Dense(32, activation="relu"),
        keras.layers.Dense(1),
    ]
)

# Compile and fit the model.
model.compile(optimizer="adam", loss="mean_squared_error")
model.fit(x_train, y_train, epochs=1, verbose=0)

# Quantize the model.
model.quantize("int8")

作用: 量化支持层的权重,并重新连接其前向路径以兼容量化内核和量化比例因子。

注意: 吞吐量增益取决于后端/硬件内核;在内核回退到反量化 matmul 的情况下,您仍然可以获得内存节省,但速度提升会较小。

逐层量化

Keras 量化框架允许您单独量化每个层,而无需使用相同的统一 API 来量化整个模型。

from keras import layers

input_shape = (10,)
layer = layers.Dense(32, activation="relu")
layer.build(input_shape)

layer.quantize("int4")  # Or "int8", "float8", etc.

何时使用逐层量化

  • 保留数值敏感的块(例如,小的残差路径、logits)以获得更高的精度,同时量化大型投影层。
  • 混合模式(例如,int4 的注意力投影,int8 的前馈网络)并逐步衡量权衡。
  • 在每一步之后,务必在小型评估集上进行验证;跨残差连接混合精度可能会改变分布。

层和模型覆盖范围

Keras 在其量化框架中支持以下核心层

  • Dense
  • EinsumDense
  • Embedding
  • ReversibleEmbedding (可在 KerasHub 中找到)

由上述层构建的任何复合层(例如,Transformer 中的 MultiHeadAttentionGroupQueryAttention、前馈网络块)通过构造继承了量化支持。这涵盖了大多数现代仅编码器和仅解码器的 Transformer 架构。

由于所有 KerasHub 模型都继承自 keras.Model,它们自动支持 model.quantize(...) API。实际上,这意味着您可以采用一个流行的 LLM 预设,调用一个函数来获得 int8/int4/GPTQ 量化版本,然后保存或部署它——而无需更改您的训练代码。


实践指南

  • 对于 GPTQ,请使用与您的推理域匹配的校准集(几百到几千个 token 通常足以看到强大的保留效果)。
  • 同时测量VRAM吞吐量/延迟:内存节省是即时的;速度提升取决于您设备上是否存在融合的低精度内核。