能效优先的深度学习——精度缩放如何减少碳足迹

本文探讨了深度学习模型高能耗带来的碳足迹问题,并详细介绍了精度缩放(如FP16、INT8量化)这一核心技术如何通过减少计算量和内存占用,显著降低模型训练与推理的能源消耗,从而实现更可持续的AI发展。

引言

随着AI在各行业的应用日益广泛,部署的GPU越来越多,训练周期不断运行,服务器全天候运作。所有这些都在很大程度上推高了全球总耗电量。现代GPU的功耗已知为每块300–700瓦,当成百上千块组成集群时,总功耗会迅速攀升。此外,模型规模正从百万级参数呈指数级增长至十亿、万亿级别,而训练成本的增长速度甚至比模型规模更快。

这种指数级增长直接导致了能源使用的指数级上升。这进而增加了大规模训练、推理及整体AI部署所产生的碳足迹。

正因如此,能源效率现已成为机器学习系统的一个关键设计目标。组织不再仅仅为了准确性和速度而优化模型;他们越来越优先考虑计算效率、可持续性和运营成本降低。实现这三项目标最有效的方法之一就是精度缩放,这是一种通过减少用于表示模型权重和激活值的位数来实现的技术。

简而言之,精度缩放将模型从FP32等高精度格式,转向更紧凑的数值表示,如FP16、INT8,甚至INT4。更少的位数意味着更少的计算量、更低的内存移动量和功耗,且不会显著影响性能。这种方法正迅速成为在训练和推理阶段构建高能效深度学习系统的流行方法。

深度学习须知概念

在开始之前,这里有几个概念将帮助你理解本文,并更好地理解现代深度学习系统的工作原理。

核心计算概念

  • FLOPS:衡量处理器每秒能执行多少次数学运算的指标。FLOPS越高,计算越快。
  • 矩阵乘法:神经网络中的核心运算,消耗了大部分的训练计算。
  • 张量:深度学习模型中存储数据的多维数组。几乎所有神经网络运算都以张量作为输入和输出。
  • 比特:计算中最小的数据单位。比特数决定了数字存储的精度。更少的比特意味着更快的计算和更低的内存使用。

精度与数值概念

  • 混合精度训练:一种训练方法,模型的不同部分使用不同的数值格式。它在加速训练的同时保持准确性稳定。
  • 低精度格式:FP32、FP16/BF16、FP8/INT8/INT4。更低的精度能降低计算、内存和能源成本。
  • 量化:使用低比特数进行存储和计算的过程。通常在推理阶段用于减少内存占用并提高速度。

性能与效率概念

  • 吞吐量:系统每秒能处理的样本、令牌或请求数量。更高的吞吐量意味着更快的模型性能。
  • 延迟:单个输入获得响应所需的时间。更低的延迟意味着更快的交互。
  • GPU小时数:一种成本与效率指标,表示GPU的使用时长。
  • 内存带宽:数据在GPU内存和计算单元之间移动的速度。许多神经网络工作负载受内存限制,而非计算限制,因此内存带宽非常重要。

训练动态与模型概念

  • 激活值:前向传播过程中每层产生的中间输出。在训练期间被存储以便计算梯度。
  • 梯度:在反向传播过程中计算得出的值,指示模型如何更新其权重。
  • 优化器状态:Adam或SGD等优化器维护的额外张量,用以稳定训练。
  • 权重:模型内部可学习的值。在训练过程中更新以减少损失。
  • KV缓存:在Transformer中,推理期间用于存储过去注意力状态以加速解码的内存结构。

其他有用概念

  • 计算受限与内存受限工作负载:计算受限受限于数学运算,内存受限受限于数据移动。不同任务的瓶颈不同。
  • 轮次:完整遍历整个训练数据集一次。
  • 批次大小:单次前向/反向传播中处理的样本数量。
  • 模型大小:模型中的参数数量。更大的模型能力更强,但训练成本更高。

以下是详细的Python代码示例,用于演示这些核心概念,如FLOPS、张量、矩阵乘法、吞吐量、GPU小时数、混合精度和量化,所有内容均以可运行的实用形式呈现。

PyTorch Lightning 版本

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset
import pytorch_lightning as pl
from pytorch_lightning.callbacks import LearningRateMonitor
from pytorch_lightning.strategies import DDPStrategy
from torch.cuda.amp import GradScaler
import time

# -------------------------------------------
# 混合精度 + 基础 Lightning 模型
# -------------------------------------------

class LightningMLP(pl.LightningModule):
    def __init__(self):
        super().__init__()
        self.model = nn.Sequential(
            nn.Linear(1024, 2048),
            nn.ReLU(),
            nn.Linear(2048, 1024)
        )
        self.loss_fn = nn.MSELoss()

    def forward(self, x):
        return self.model(x)

    def training_step(self, batch, batch_idx):
        x, y = batch
        with torch.cuda.amp.autocast():     # 混合精度前向传播
            preds = self.model(x)
            loss = self.loss_fn(preds, y)
        self.log("train_loss", loss)
        return loss

    def configure_optimizers(self):
        return torch.optim.Adam(self.parameters(), lr=1e-3)

# -------------------------------------------
# 数据集
# -------------------------------------------

X = torch.randn(10_000, 1024)
Y = torch.randn(10_000, 1024)
dataset = TensorDataset(X, Y)
loader = DataLoader(dataset, batch_size=32, shuffle=True)

# -------------------------------------------
# 吞吐量测量
# -------------------------------------------

dummy_batch = next(iter(loader))[0]

start = time.time()
for _ in range(200):
    _ = dummy_batch @ dummy_batch.T
end = time.time()

throughput = (200 * dummy_batch.shape[0]) / (end - start)
print(f"矩阵乘法吞吐量: {throughput:.2f} 样本/秒")

# -------------------------------------------
# 使用混合精度的训练器
# -------------------------------------------

trainer = pl.Trainer(
    max_epochs=2,
    accelerator="gpu",
    devices=1,
    precision=16,              # 混合精度
    callbacks=[LearningRateMonitor(logging_interval="epoch")],
)

model = LightningMLP()
trainer.fit(model, loader)

# -------------------------------------------
# GPU小时数示例
# -------------------------------------------

num_gpus = 4
training_time_hours = 6

gpu_hours = num_gpus * training_time_hours
print(f"总 GPU 小时数: {gpu_hours} GPU-小时")

# -------------------------------------------
# INT8 量化(训练后)
# -------------------------------------------

model_cpu = model.to("cpu")
quantized = torch.ao.quantization.quantize_dynamic(
    model_cpu, {nn.Linear}, dtype=torch.qint8
)

test_input = torch.randn(1, 1024)
out = quantized(test_input)
print("量化输出形状:", out.shape)

# -------------------------------------------
# KV缓存示例
# -------------------------------------------

num_heads = 8
seq_len = 16
head_dim = 64

kv_cache = {
    "key": torch.randn(num_heads, seq_len, head_dim),
    "value": torch.randn(num_heads, seq_len, head_dim),
}

print("KV缓存形状:", {k: v.shape for k, v in kv_cache.items()})

这段PyTorch Lightning代码展示了如何使用混合精度训练一个小型神经网络。Lightning处理了大部分训练过程,你只需编写模型并选择精度。

此代码演示了:

  • 混合精度如何加速训练。
  • Lightning如何简化训练循环。
  • GPU如何自动使用Tensor Core进行更快的矩阵乘法运算。

TensorFlow/Keras 版本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import tensorflow as tf
from tensorflow import keras
import time

# 全局启用混合精度
mixed_precision = tf.keras.mixed_precision.set_global_policy("mixed_float16")

# ------------------------------------------------------
# 使用混合精度的简单MLP
# ------------------------------------------------------

inputs = keras.Input(shape=(1024,))
x = keras.layers.Dense(2048, activation="relu")(inputs)
outputs = keras.layers.Dense(1024)(x)

model = keras.Model(inputs, outputs)

model.compile(
    optimizer=keras.optimizers.Adam(),
    loss="mse"
)

# ------------------------------------------------------
# 数据集
# ------------------------------------------------------

X = tf.random.normal((10000, 1024))
Y = tf.random.normal((10000, 1024))

dataset = tf.data.Dataset.from_tensor_slices((X, Y)).batch(32)

# ------------------------------------------------------
# FLOPS计算示例
# ------------------------------------------------------

def compute_flops(M, N, K):
    return 2 * M * N * K

flops = compute_flops(2048, 2048, 2048)
print(f"矩阵乘法的FLOPS: {flops/1e9:.2f} GFLOPs")

# ------------------------------------------------------
# 测量吞吐量
# ------------------------------------------------------

batch = next(iter(dataset))

start = time.time()
for _ in range(200):
    _ = tf.matmul(batch[0], batch[0], transpose_b=True)
end = time.time()

throughput = (200 * batch[0].shape[0]) / (end - start)
print(f"TensorFlow 吞吐量: {throughput:.2f} 样本/秒")

# ------------------------------------------------------
# 训练
# ------------------------------------------------------

model.fit(dataset, epochs=2)

# ------------------------------------------------------
# GPU小时数示例
# ------------------------------------------------------

num_gpus = len(tf.config.list_physical_devices("GPU"))
training_time_hours = 4
gpu_hours = num_gpus * training_time_hours

print("GPU 小时数:", gpu_hours)

# ------------------------------------------------------
# 训练后量化 (INT8)
# ------------------------------------------------------

converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]  # 启用 INT8
tflite_model = converter.convert()

print("TFLite INT8 模型大小:", len(tflite_model) / 1024, "KB")

# ------------------------------------------------------
# KV缓存示例
# ------------------------------------------------------

num_heads = 8
seq_len = 16
head_dim = 64

kv_cache = {
    "k": tf.random.normal((num_heads, seq_len, head_dim)),
    "v": tf.random.normal((num_heads, seq_len, head_dim)),
}

print("KV缓存形状:", {k: v.shape for k, v in kv_cache.items()})

这段TensorFlow/Keras代码演示了相同的概念,使用混合精度训练模型以加速并提高训练效率。TensorFlow在全局层面启用混合精度,并自动在安全的地方使用FP16。

此代码演示了:

  • 如何在TensorFlow中使用混合精度。
  • 模型如何以更少的GPU内存更快地训练。
  • TensorFlow如何自动处理损失缩放和FP32稳定性。

理解深度学习的碳足迹

深度学习模型功能强大,但也消耗大量能源。这种能源使用是其碳足迹上升的主要原因。由于全球很大一部分电力仍然来自化石燃料,GPU消耗的每一瓦额外电力最终都会在世界某个地方转化为更多的二氧化碳排放。

训练大型模型是这种能源消耗的最大贡献者之一。像Transformers和Vision Transformers这样的模型对每个令牌或图像块执行大量的矩阵乘法运算。它们还会多次处理整个数据集,通常使用许多GPU并行运行数天甚至数周。所有这些GPU持续运行消耗大量电力。

几个技术因素使得深度学习更加耗能。模型规模是一个主要因素:更大的模型需要更多的计算。序列长度,尤其是在Transformers中,会导致计算量呈二次方增长;序列长度翻倍可能需要四倍的计算量。批次大小也会影响功耗;更大的批次可以加速训练,但每一步需要更多的电力。除此之外,硬件效率低下,如使用旧GPU、散热不良或内存访问速度慢,会进一步增加能源消耗。

所有这些功耗直接转化为二氧化碳排放。由于世界大部分地区仍然依赖煤炭、天然气和其他化石燃料发电,高GPU消耗意味着需要燃烧更多的化石燃料来满足需求。

链条很简单:

[高计算需求 → 更多GPU时间 → 更高功耗 → 更多化石燃料燃烧 → 更多碳排放]

这就是为什么提高深度学习能源效率正成为公司和研究人员优先考虑的事项。

降低这种碳影响最有效的方法之一是精度缩放。精度指的是在计算过程中用于表示数字的比特数。例如,FP32使用32位,而FP16使用16位,大小减半。FP32需要更多的内存带宽和更重的计算,从而导致更多的能源使用。另一方面,FP16更轻量,允许GPU更快、更高效地处理数据。

你可以把它想象成举重:FP32就像举起一个10公斤的哑铃,而FP16就像举起一个5公斤的哑铃。

动作是一样的,但FP16每次需要的力气更小。经过数百万或数十亿次操作,这可以显著降低功耗。

现代GPU拥有专门的硬件——张量核心,旨在以极高的效率运行FP16甚至更低的精度(如INT8和INT4)。通过在可能的地方切换到较低的精度格式,我们可以大大减少训练和推理所需的能量,从而在不牺牲模型性能的情况下帮助减少碳排放。

什么是精度缩放?

精度缩放是一种在深度学习模型的训练、推理或两者中改变用于表示数字的数值精度(比特数)的技术。

在深度学习中,每个权重、激活值、梯度以及其他任何值都以某种数值表示形式存储。这些数字可以用不同的精度表示,例如:

  • FP32 (32位浮点数)
  • FP16 / BF16 (16位浮点数)
  • FP8 (8位浮点数)
  • INT8 (8位整数)
  • INT4 (4位整数)
  • …一直到二进制(1位)。

精度缩放简单来说就是在可能的地方使用更少的比特。

精度缩放旨在降低计算成本,因为更少的比特意味着更小的数字,从而带来更快的矩阵乘法运算。 精度缩放还能减少内存使用,因为更低的精度导致张量更小,从而减少GPU内存占用和内存带宽需求。

深度学习如何使用数值格式

神经网络包含:

  • 权重
  • 激活值
  • 梯度
  • 优化器状态
  • KV缓存(针对Transformers)

这些都以浮点数或整数形式存在。传统上使用FP32,但现在的趋势是:

  • 训练 → BF16 / FP16 / FP8
  • 推理 → INT8 / INT4 / 甚至 INT3

模型的不同部分可以根据以下因素使用不同的精度:

  • 稳定性
  • 硬件支持
  • 瓶颈(计算 vs 内存)

精度缩放如何提高能源效率

如前所述,精度缩放是在训练或推理期间减少数值位宽的实践,直接提高现代深度学习工作负载的计算效率并降低能耗。随着大型模型规模的持续增长,降低精度已成为减少碳足迹和运营成本最具影响力的策略之一。

降低计算负载

低精度格式(如FP16、BF16、FP8或INT8)每次乘积累加运算使用更少的比特,这显著减少了GPU计算单元所需完成的工作量。

  • 更少的比特 → 每次操作所需的FLOPS更少
  • 矩阵乘法执行更快,缩短训练周期。
  • 降低的计算复杂性也提高了GPU占用率。

因此,使用FP8或BF16执行的训练步骤通常比FP32完成得快得多,从而提高了整体训练吞吐量。

降低内存带宽需求

内存访问是现代加速器功耗的最大贡献者之一。使用低精度张量减少了必须在GPU内存和计算核心之间移动的字节数。 例如:

  • INT8张量比FP32少用4倍内存
  • 更低的精度导致更少的内存事务和更低的延迟
  • 提高了带宽受限工作负载(如推理和长序列解码)的效率

这种数据移动的减少直接降低了能耗,尤其是在大规模场景下。

更高的吞吐量

现代加速器(如NVIDIA H100和NVIDIA A100)在以低精度执行计算时提供远高于FP32的峰值性能。

  • 张量核心在FP16/FP8/INT8下提供的TFLOPs远高于FP32
  • 更高的吞吐量意味着每个训练步骤或推理运行使用更少的挂钟时间和总能量完成

在推理工作负载中,这转化为:

  • 更快的响应
  • 每个请求消耗的能量更低
  • 每瓦特处理更多的查询

碳排放的实际减少

由于计算时间与功耗直接相关,降低精度对环境产生有意义的积极影响。

  • 更短的训练时间 = 更少的GPU小时数 = 更低的总能耗
  • 主要的AI实验室已经采用混合精度或低精度训练来降低运营成本和碳排放。Meta、Google和OpenAI等公司在其生产流程中广泛使用低精度格式(BF16、FP8、INT8),并且新硬件正在加速推动向更低比特宽度的转变。

混合精度训练

混合精度训练的引入是为了在不牺牲准确性的前提下使深度学习更快、更高效。随着模型和数据集变得越来越大,使用全FP32训练变得缓慢且占用大量内存。混合精度通过为大多数操作(如FP16)使用低精度格式来解决这个问题,这减少了内存使用并提高了数学运算吞吐量,同时仍将权重和累加等关键值保持在FP32中以保持数值稳定性。

借助损失缩放等技术,混合精度提供了与FP32训练相同的准确性,但速度显著提高,资源需求更低,使其成为现代大规模AI工作负载的理想选择。

混合精度训练是一种深度学习模型结合使用FP16(半精度)和FP32(单精度)的技术,旨在使训练更快、内存效率更高,同时仍保持模型的数值稳定性。大部分繁重的计算,如前向和反向传播,在FP16中运行,这要快得多且使用更少内存。但重要的值,如主权重和累加值,则保持在FP32中,以避免精度损失并确保训练保持准确。这种平衡使你获得了FP16的速度优势,同时不损害模型质量。

现代框架使这变得简单:PyTorch AMP和TensorFlow混合精度API都提供了内置支持,自动选择哪些操作在FP16中运行,哪些保持在FP32中,因此你几乎不需要额外努力就能获得更快的训练。

混合精度训练中的损失缩放是什么?

损失缩放是混合精度训练中使用的一种技术,用于防止梯度变得太小而无法在FP16中表示。由于FP16的动态范围有限,许多梯度值,尤其是非常小的负值,会被舍入为零,这会损害学习过程。为了解决这个问题,我们在反向传播之前将损失乘以一个常数因子进行放大。由于反向传播遵循链式法则,所有梯度都会按相同比例放大。这将小梯度推入FP16可表示的范围内,使其不会消失。在反向传播之后,我们在更新FP32主权重之前将梯度缩小,确保更新大小保持正确。

简而言之:

  • 放大损失 → 梯度变大 → FP16可以表示它们
  • 缩小梯度 → 正确的更新大小 → 稳定的训练

缩放因子的选择可以是手动的或自动的。如果因子太大,梯度会溢出为NaN/Inf,因此框架会检测到这一点并跳过该迭代的更新。但如果正确执行,损失缩放可以防止微小梯度消失,并允许FP16训练达到与FP32相当的准确性。

量化

量化是一种模型压缩技术,可减少用于存储神经网络中权重和激活值的数字精度。模型不再使用32位浮点数,而是使用低比特整数格式,如INT8或INT4,其中每个数字需要的比特数少得多。

其思路很简单: 神经网络不需要完整的32位精度即可做出准确的预测。因此,我们通过将数字映射到较小的整数范围和一个缩放因子来“压缩”这些数字。这极大地减少了模型大小、内存消耗和计算成本,而不会严重影响准确性。

量化现已成为在服务器、边缘设备和GPU上高效部署大型模型的标准技术。

训练后量化

训练后量化是最简单的方法,其中完全训练好的模型被转换为低精度而无需重新训练。PTQ快速且易于应用,仅需一个小型校准数据集来估计激活值范围。虽然PTQ可能导致准确性略有下降,但它极大地减少了内存占用并加速了推理,使其成为部署的流行默认选择。

量化感知训练

量化感知训练更进一步,通过在训练期间模拟量化效果。模型“学习”在低精度约束下操作,调整权重以补偿舍入误差。由于模型在训练期间适应INT8或INT4算术,QAT通常比PTQ获得更好的准确性,特别是对于目标检测或生成建模等敏感任务。QAT前期计算量更大,但它能生成高度优化的量化模型。

量化优势

量化的最大优势之一是能够大幅减少能源使用。整数运算所需的晶体管、内存访问和功耗远低于浮点运算。因此,量化模型可以运行得快得多,并且能耗显著降低——这对于移动、物联网和大规模推理工作负载至关重要。

现代工具使量化变得更加容易。Hugging Face Optimum库为Transformers提供了优化的INT8和INT4流水线,支持通过ONNX Runtime或Intel Neural Compressor后端快速转换。同时,Quanto作为一个轻量级的PyTorch量化后端,支持原生PyTorch兼容的快速量化工作流,并提供动态、静态和纯整数量化模式。这些工具共同简化了部署更小、更环保、更快的AI模型的过程。

要了解更多关于量化技术的信息,我们在资源部分链接了详细的博客文章。

不同精度下的节能效果对比

精度 相对计算成本 内存使用 节能效果
FP32 基线
FP16/BF16 ~2倍更快 内存减少50% 减少约30–50%的能源
FP8 ~4倍更快 内存减少75% 最多减少60%的能源
INT8 ~4–6倍更快 内存减少75% 最多减少70%的能源
INT4 ~8倍更快 内存减少87% 最多减少80%的能源

实践指南:实施精度缩放

训练简明清单

  • 启用AMP,以获得即时的速度和内存收益。
  • 在支持的平台上使用框架级混合精度。
  • 当可用时,尝试FP8或相关库以获得额外节省。
  • 在降低精度时,验证模型稳定性。

PyTorch — 启用AMP

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# PyTorch: 使用AMP的简单混合精度训练循环
import torch
from torch import nn, optim
from torch.cuda.amp import autocast, GradScaler

model = nn.Sequential(nn.Linear(1024, 2048), nn.ReLU(), nn.Linear(2048, 1024)).cuda()
opt = optim.Adam(model.parameters(), lr=1e-3)
scaler = GradScaler()  # 用于稳定的FP16训练

for epoch in range(num_epochs):
    for x, y in dataloader:
        x, y = x.cuda(), y.cuda()
        opt.zero_grad()
        with autocast():              # 混合精度前向传播
            pred = model(x)
            loss = ((pred - y) ** 2).mean()
        scaler.scale(loss).backward() # 缩放梯度
        scaler.step(opt)
        scaler.update()

说明:

  • 使用autocast()进行FP16训练;在支持BF16的平台上,相应设置dtype。
  • 对于非常大的模型,使用梯度累积和谨慎的损失缩放。

PyTorch — FP8 / 低精度入门

FP8依赖于硬件(例如H100/Hopper)。当可用时,使用供应商库。 典型步骤:安装供应商SDK → 使用供应商FP8加速算子替换核心算子 → 运行完整性检查。 示例:

1
2
3
4
# 伪代码
from transformer_engine import fp8_layer, cast_to_fp8
x_fp8 = cast_to_fp8(x)
out = fp8_layer(x_fp8, weight_fp8)

TensorFlow / Keras — 混合精度

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import tensorflow as tf
from tensorflow import keras

# 全局启用策略(在支持的TPU/GPU上自动选择BF16)
tf.keras.mixed_precision.set_global_policy('mixed_float16')

model = keras.Sequential([
    keras.layers.Dense(2048, activation='relu', input_shape=(1024,)),
    keras.layers.Dense(1024)
])
model.compile(optimizer='adam', loss='mse')
model.fit(dataset, epochs=2)

说明:

  • Keras为mixed_float16自动处理损失缩放。
  • 对于云TPU或支持的GPU上的BF16,mixed_bfloat16是一个选项。

推理简明清单

  • 首先尝试训练后量化——这是实现内存节省的最快途径。
  • 如果PTQ损害了准确性,则使用量化感知训练来调整权重。
  • 导出到ONNX,然后使用TensorRT或ONNX Runtime进行优化以获得最大吞吐量。
  • 在广泛部署之前,测量准确性、能源和延迟之间的权衡。

PyTorch → ONNX → TensorRT(导出)

1
2
3
4
5
6
7
8
import torch

# 假设 `model` 在CPU上 / 评估模式
model.eval()
dummy = torch.randn(1, 1024)
torch.onnx.export(model.cpu(), dummy, "model.onnx",
                  input_names=["input"], output_names=["output"],
                  opset_version=17, do_constant_folding=True)

ONNX Runtime — 量化ONNX模型(动态/静态)

1
2
3
from onnxruntime.quantization import quantize_dynamic, QuantType

quantize_dynamic("model.onnx", "model_int8.onnx", weight_type=QuantType.QInt8)

加载并运行:

1
2
3
import onnxruntime as ort
sess = ort.InferenceSession("model_int8.onnx", providers=['CUDAExecutionProvider'])
out = sess.run(None, {'input': dummy_np})

TensorFlow Lite(移动/边缘INT8)

1
2
3
4
5
6
import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
# (可选,为full-int8提供代表性数据集)
tflite_model = converter.convert()
open("model.tflite","wb").write(tflite_model)

常见问题解答

  1. 什么是FP32,为什么在深度学习中使用它? FP32是大多数深度学习模型使用的标准数值格式。其高数值稳定性使其成为训练复杂网络(如Transformers和CNN)的理想选择。由于FP32能捕捉非常小的十进制变化,它支持稳定的梯度更新并防止训练发散。然而,其高内存占用和计算成本使其耗能严重,这就是为什么低精度格式变得越来越流行。

  2. 在AI工作负载的背景下,“碳足迹"意味着什么? 碳足迹指的是训练和运行机器学习模型所用电力的总温室气体排放。大型模型,尤其是在GPU上使用高精度数学进行长时间训练周期时,会消耗大量能源。这些能源通常来自不可再生能源,加剧了全球排放。降低精度、优化计算和使用更高效的硬件可以显著降低AI系统的碳足迹。

  3. 什么是混合精度训练? 混合精度训练结合了两种数值格式,通常是FP16和FP32,以实现速度和稳定性。FP16用于大多数操作以加速计算并减少内存使用,而FP32则保留用于损失缩放和梯度累积等敏感计算。PyTorch AMP和TensorFlow的混合精度API等框架自动化了这一过程,确保准确性得以保持。混合精度现已成为在不牺牲模型性能的情况下提高效率的最广泛采用的方法之一。

  4. 有哪些不同类型的精度缩放技术? 精度缩放涉及调整数值格式以提高计算效率。最常见的形式包括:用于训练加速的混合精度,用于部署效率的降低精度推理,以及通过降低权重和激活精度来压缩模型的量化。每种技术都在速度、准确性和能耗之间提供其自身的权衡。它们共同构成了高能效深度学习的核心工具包。

  5. 降低精度如何降低能耗? 低精度格式需要更少的比特来存储数字,这减少了计算期间传输的内存量,而这是能源使用的主要来源。INT8或INT4等整数运算也比浮点数学消耗的功率少得多,因为它们使用更简单的电路和更少的计算步骤。这导致推理速度更快、模型更小,并显著降低了硬件能耗。在大规模应用时,精度降低可以显著降低AI工作负载对环境的影响。

  6. 什么是量化,它与混合精度有何不同? 量化将模型权重和激活值从浮点值转换为低精度整数值,如INT8或INT4。与仍使用浮点数学的混合精度不同,量化用整数替换了许多运算,提供了更高的效率。它可以在训练后应用,也可以在训练期间应用以保持准确性。量化模型使用的内存和功率少得多,使量化成为边缘设备、大规模推理或注重碳足迹的部署的理想选择。

  7. 精度缩放会影响模型准确性吗? 精度缩放可能引入舍入误差并降低表示粒度,这可能会略微影响准确性——特别是对于小型模型或敏感任务。然而,现代技术如损失缩放、量化感知训练和FP8训练极大地缓解了这些问题。在许多情况下,模型在保持几乎相同准确性的同时,仅使用一小部分计算量。微小的准确性权衡通常值得换来速度、成本节省和环境影响方面的大幅收益。

  8. 精度缩放可以应用于任何模型架构吗? 大多数现代架构,包括Transformers、CNN、RNN和扩散模型,都支持混合精度和量化。框架和硬件加速器现在提供内置支持,使采用变得简单直接。但是,某些较旧的架构或自定义操作可能需要调整以避免数值不稳定性。借助适当的工具,几乎所有广泛使用的深度学习模型都可以受益于精度缩放以提高效率。

结论

精度缩放正迅速成为降低深度学习任务模型复杂性和能源需求的有效方法之一。通过从全FP32转向更轻量级的格式,如FP16、FP8、INT8或INT4,我们可以在缩小现代AI系统碳足迹的同时,削减训练和推理成本。这是一个简单但影响巨大的想法:更快的模型、更低的账单,以及更具可持续性的AI扩展路径。

当然,它并非完美无缺。极低的精度可能会损害准确性,框架支持可能不一致,并且一些硬件在处理高级量化方面仍有困难。某些领域,如科学计算,也需要更高精度的稳定性。但尽管存在这些挑战,精度缩放仍然是构建高效、负责任且面向未来的AI的强大策略。

参考文献

  • Building Intelligence: Neural Network Basics
  • Understanding Model Quantization in Large Language Models
  • Optimizing AI Models with Quanto
  • MIXED PRECISION TRAINING
  • Scaling Laws for Precision
  • Optimizing deep learning pipelines for maximum efficiency
  • FlashAttention-2
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计