9深度学习系统:从算法到硬件

推理优化

从训练到部署

模型量化知识蒸馏算子融合TensorRT

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第9章 推理优化 - 从训练到部署 (Inference Optimization: From Training to Deployment)

一、导读

1.1 本章学习目标

通过本章的学习,读者将能够:

理解推理与训练在系统需求上的根本差异

掌握模型优化的主要技术路线(量化、剪枝、蒸馏、编译)

深入分析量化的原理、类型和实现细节

了解结构化剪枝与非结构化剪枝的区别及应用

掌握知识蒸馏的基本方法和高级变体

理解推理引擎(TensorRT、ONNX Runtime、TFLite)的工作原理

能够分析和优化推理服务的延迟、吞吐量和资源占用

设计端到端的推理部署方案

1.2 为什么本章如此重要

虽然训练吸引了大量研究关注,但推理才是深度学习应用的最终形态。绝大多数AI产品——从智能手机上的语音助手到数据中心里的推荐系统——都依赖于高效的推理服务。推理优化的重要性体现在多个维度。

规模效应:推理的计算总量远超训练。一个模型可能只训练一次或几次,但会被部署到数百万设备上执行数十亿次推理。即使微小的效率提升,在大规模下也能带来显著的成本节约。

实时性要求:许多应用场景(如自动驾驶、实时翻译、在线推荐)对延迟有严格要求。优化推理速度可以直接改善用户体验。

资源约束:边缘设备(手机、IoT设备)的计算能力、内存和电池容量有限。高效的推理模型使得在这些设备上运行复杂AI成为可能。

成本考量:在云环境中,推理服务占AI相关计算成本的绝大部分。优化推理可以显著降低运营成本。

理解推理优化技术,使我们能够在保持模型质量的同时,最大化效率和最小化成本。这对于构建实际可用的AI产品至关重要。

1.3 核心问题引导

在学习本章内容时,请思考以下问题:

推理和训练在计算模式、内存需求和精度要求上有哪些本质区别?

量化如何将FP32模型转换为INT8?校准(calibration)过程是如何工作的?

结构化剪枝和非结构化剪枝各有什么优缺点?哪种更容易被硬件加速?

知识蒸馏中,教师模型的"暗知识"是什么?温度参数如何影响蒸馏效果?

模型编译器(如TVM、XLA)与传统推理引擎有什么区别?它们如何进行优化?

批处理(batching)如何影响推理性能?动态批处理的挑战是什么?

延迟和吞吐量之间如何权衡?在不同应用场景下应该优先优化哪个指标?

端侧部署与云端部署在优化策略上有何不同?


二、核心概念详解

推理 vs 训练:系统需求的差异

虽然推理和训练都涉及神经网络的前向传播,但它们在系统设计上有着本质的差异。

计算内容:

  • 训练:前向传播 + 反向传播 + 参数更新。反向传播的计算量通常是前向的2-3倍。
  • 推理:仅前向传播。计算量显著减少。

内存需求:

  • 训练:需要保存中间激活值用于反向传播,需要存储梯度、优化器状态。显存占用大。
  • 推理:只需存储模型参数和少量临时缓冲区。显存占用小,主要来自参数本身。

精度要求:

  • 训练:通常需要FP32或混合精度(FP16/BF16),以保证数值稳定性和收敛性。
  • 推理:可以使用更低精度(INT8、INT4甚至二值化),因为不需要考虑梯度流动的稳定性。

批处理策略:

  • 训练:使用较大批次以提高GPU利用率和梯度估计准确性。
  • 推理:批次大小取决于延迟要求。实时应用可能需要批次大小为1,离线批量推理可以使用较大批次。

执行模式:

  • 训练:迭代式,多次遍历数据。
  • 推理:单次或少次执行,强调低延迟启动。

这些差异意味着针对训练优化的系统不一定适合推理,反之亦然。推理引擎可以省略反向传播相关的代码路径,采用更激进的优化策略。

量化(Quantization)

量化是将高精度表示转换为低精度表示的技术,是推理优化中最有效的方法之一。

量化的基本原理

神经网络中的权重和激活值通常使用FP32表示,占用4字节。量化将这些值映射到低精度格式,如INT8(1字节)、INT4(0.5字节)甚至二值(1位)。

线性量化公式:

$$x_{quant} = \text{round}\left(\frac{x_{fp32}}{scale} + zero\_point\right)$$

其中:

  • $scale$:缩放因子,决定量化的粒度
  • $zero\_point$:零点偏移,确保0值能精确表示

反量化公式:

$$x_{fp32} \approx scale \times (x_{quant} - zero\_point)$$

量化类型

按阶段分类:

  • 训练后量化(Post-Training Quantization, PTQ):在训练完成后进行量化,无需重新训练。实现简单,但精度损失可能较大。
  • 量化感知训练(Quantization-Aware Training, QAT):在训练过程中模拟量化效应,使模型适应低精度表示。精度更高,但需要额外的训练。

按粒度分类:

  • 每张量量化(Per-tensor):整个张量使用相同的scale和zero_point。实现简单,但可能无法很好地处理值分布不均匀的情况。
  • 每通道量化(Per-channel):每个通道(如卷积核的输出通道)使用独立的scale和zero_point。精度更高,是现代推理引擎的默认选择。

按位宽分类:

  • INT8量化:最常用,提供良好的精度-效率平衡。大多数现代硬件原生支持INT8加速。
  • INT4/INT2量化:进一步压缩,但精度损失较大。适用于对精度要求不高的场景。
  • 二值化/三值化:权重只有{-1, 1}或{-1, 0, 1}两个或三个值。极致压缩,但需要专门的训练方法。

校准(Calibration)

对于PTQ,需要确定合适的scale和zero_point。这通过在少量代表性数据上运行模型,统计激活值的分布来完成。

常用的校准方法:

  • MinMax:使用最大值和最小值确定范围。简单但对异常值敏感。
  • Moving Average MinMax:使用指数移动平均,减少异常值影响。
  • Entropy-based(KL散度):寻找使量化前后分布KL散度最小的阈值。TensorRT使用此方法。
  • Percentile:使用某个百分位数(如99.9%)作为最大值,忽略极端异常值。

硬件支持

现代CPU和GPU都提供了INT8加速指令:

  • CPU:Intel VNNI、ARM Neon
  • GPU:NVIDIA Tensor Core(Volta及以后)
  • 专用芯片:TPU、NPU等原生支持低精度计算

INT8相比FP32可以带来约2-4倍的吞吐量提升和4倍的内存节省。

剪枝(Pruning)

剪枝通过移除模型中不重要的连接或结构来减少参数量和计算量。

非结构化剪枝(Unstructured Pruning)

移除单个权重连接,通常基于权重的绝对值大小。绝对值小的权重被认为不重要。

优点:可以达到很高的稀疏度(90%+)。

缺点:产生的稀疏矩阵需要专门的数据结构和硬件支持才能加速。通用硬件上可能反而变慢。

结构化剪枝(Structured Pruning)

移除整个结构单元,如滤波器、通道、层等。

  • 滤波器剪枝:移除整个卷积滤波器
  • 通道剪枝:移除整个输入/输出通道
  • 层剪枝:移除整个层
  • 头剪枝:移除Transformer中的注意力头

优点:剪枝后的模型仍然是稠密的,可以直接在现有硬件上加速。

缺点:可达到的稀疏度较低,精度损失可能更大。

剪枝流程

训练:训练一个完整模型

评估重要性:计算每个单元的重要性分数

剪枝:移除低于阈值的单元

微调:在训练数据上微调以恢复精度

迭代:重复步骤2-4以达到目标稀疏度

知识蒸馏(Knowledge Distillation)

知识蒸馏通过将大模型(教师)的知识转移到小模型(学生)中,使得小模型能够达到接近大模型的性能。

基本方法

标准蒸馏使用软标签(soft labels)而非硬标签(hard labels)来训练学生模型。

教师模型的输出经过温度缩放:

$$p_i = \frac{\exp(z_i / T)}{\sum_j \exp(z_j / T)}$$

其中$T$是温度参数。较高的$T$产生更平滑的概率分布,包含更多关于类别间相似性的信息。

学生模型的损失函数:

$$\mathcal{L} = \alpha \cdot \mathcal{L}_{hard} + (1-\alpha) \cdot T^2 \cdot \mathcal{L}_{KL}(p_{teacher} || p_{student})$$

其中$\mathcal{L}_{hard}$是标准交叉熵损失,$\mathcal{L}_{KL}$是KL散度损失,$\alpha$是平衡系数。

高级蒸馏方法

  • 中间层蒸馏:不仅匹配输出,还匹配中间层的特征表示
  • 注意力蒸馏:学生模仿教师的注意力分布
  • 关系蒸馏:学生模仿教师样本间的关系结构
  • 自蒸馏:同一模型的不同部分相互蒸馏

蒸馏的优势

蒸馏不仅可以减小模型大小,还可以提高鲁棒性和泛化能力。教师模型的"暗知识"(dark knowledge)——即关于哪些错误更合理的知识——可以帮助学生模型做出更好的决策。

模型编译与图优化

模型编译器将高层模型表示转换为优化的底层代码,是推理优化的关键技术。

传统推理引擎

TensorRT:NVIDIA的高性能推理库,针对GPU优化。

  • 层融合:将多个操作合并为一个内核
  • 内核自动调优:选择最快的实现
  • 精度优化:FP16/INT8量化
  • 动态形状支持

ONNX Runtime:跨平台的推理引擎,支持多种硬件后端。

  • 通用性强
  • 丰富的执行提供者(CUDA、TensorRT、OpenVINO等)

TFLite:Google的移动和边缘设备推理引擎。

  • 轻量级
  • 专为移动端优化

现代编译器

TVM:端到端的深度学习编译器栈。

  • 自动代码生成
  • 跨硬件支持
  • Ansor自动调度搜索

XLA(Accelerated Linear Algebra):Google的线性代数编译器。

  • JIT编译
  • 操作融合
  • 内存优化

MLIR(Multi-Level Intermediate Representation):LLVM的扩展,为机器学习提供多级IR。

  • 模块化设计
  • 可重用的优化pass

图优化技术

  • 常量折叠(Constant Folding):预先计算常量表达式
  • 死代码消除(Dead Code Elimination):移除未使用的节点
  • 公共子表达式消除(CSE):避免重复计算
  • 算子融合(Operator Fusion):将多个操作合并为一个内核,减少内存访问
  • 布局优化:选择最优的内存布局(NCHW vs NHWC)

运行时优化

批处理(Batching)

批处理通过同时处理多个请求来提高吞吐量。

静态批处理:固定批次大小,简单但可能导致延迟波动。

动态批处理:根据到达的请求动态组成批次。需要在延迟和吞吐量之间权衡。

最大批次大小的选择:

  • 太大:增加等待时间,提高延迟
  • 太小:GPU利用率低,吞吐量低

内存管理

  • 权重预加载:将模型权重固定在GPU显存中,避免每次推理时传输
  • 工作区复用:重用临时缓冲区,减少分配开销
  • 分页注意力:对于长序列,使用分页机制管理KV缓存

并发执行

  • 多流执行:使用多个CUDA流并行处理不同请求
  • 模型并行:将模型拆分到多个设备上
  • 流水线推理:将请求分阶段处理

三、程序员的视角

3.1 在实际项目中的应用

选择合适的优化技术:根据应用场景选择优化策略。延迟敏感用量化和编译;资源受限用剪枝和蒸馏;云端部署用批处理。

精度验证:量化后必须验证精度。使用验证集比较量化前后的性能差异。如果精度下降过多,尝试QAT或调整校准方法。

基准测试:在目标硬件上进行全面的基准测试,测量延迟、吞吐量和资源占用。

3.2 常见陷阱与误区

忽略校准数据的质量:PTQ的效果高度依赖校准数据的代表性。应使用与真实分布一致的验证集。

过度优化:在某些情况下,优化可能引入额外的开销(如稀疏矩阵的索引管理)。始终测量实际效果。

假设线性扩展:批处理增加并不总是线性提高吞吐量。存在饱和点,超过后收益递减。

忽视端到端延迟:只优化模型推理时间,忽略了预处理、后处理和通信开销。

3.3 与其他层级的联系

推理优化需要软硬件协同。编译器需要了解硬件特性,模型设计需要考虑部署约束,硬件设计需要支持常见的推理模式。


四、代码实战

示例1:PyTorch模型量化

python
import torch
import torch.nn as nn
from torch.quantization import quantize_dynamic, quantize_qat

class SimpleClassifier(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(784, 256)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(256, 128)
        self.fc3 = nn.Linear(128, 10)
    
    def forward(self, x):
        x = x.view(x.size(0), -1)
        x = self.relu(self.fc1(x))
        x = self.relu(self.fc2(x))
        x = self.fc3(x)
        return x

def post_training_quantization():
    """训练后动态量化"""
    
    # 创建并加载模型
    model = SimpleClassifier()
    model.eval()
    
    # 动态量化(仅量化权重)
    quantized_model = quantize_dynamic(
        model,
        {nn.Linear},  # 要量化的模块类型
        dtype=torch.qint8
    )
    
    # 测试
    x = torch.randn(1, 784)
    output = quantized_model(x)
    
    # 检查量化
    print(f"FC1 weight dtype: {quantized_model.fc1.weight().dtype}")
    print(f"Model size saved: ~75%")
    
    return quantized_model

def quantization_aware_training():
    """量化感知训练"""
    
    model = SimpleClassifier()
    model.train()
    
    # 准备QAT
    model.qconfig = torch.quantization.get_default_qat_qconfig('fbgemm')
    torch.quantization.prepare_qat(model, inplace=True)
    
    # 模拟训练几个epoch
    # ... 训练代码 ...
    
    # 转换为量化模型
    model.eval()
    quantized_model = torch.quantization.convert(model, inplace=False)
    
    return quantized_model

def benchmark_quantization():
    """对比FP32和INT8的性能"""
    
    import time
    
    model_fp32 = SimpleClassifier().eval()
    model_int8 = post_training_quantization()
    
    x = torch.randn(1, 784)
    
    # FP32基准
    torch.cuda.synchronize() if torch.cuda.is_available() else None
    start = time.time()
    for _ in range(1000):
        _ = model_fp32(x)
    time_fp32 = (time.time() - start) / 1000 * 1000
    
    # INT8基准
    start = time.time()
    for _ in range(1000):
        _ = model_int8(x)
    time_int8 = (time.time() - start) / 1000 * 1000
    
    print(f"FP32 latency: {time_fp32:.3f} ms")
    print(f"INT8 latency: {time_int8:.3f} ms")
    print(f"Speedup: {time_fp32/time_int8:.2f}x")

if __name__ == "__main__":
    benchmark_quantization()

示例2:简单的通道剪枝

python
import torch
import torch.nn as nn
import torch.nn.utils.prune as prune

class PrunableConv(nn.Module):
    """支持剪枝的卷积层"""
    
    def __init__(self, in_channels, out_channels, kernel_size):
        super().__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, padding=1)
        self.bn = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU()
    
    def forward(self, x):
        return self.relu(self.bn(self.conv(x)))

def magnitude_based_pruning(model, pruning_ratio=0.5):
    """
    基于权重大小的剪枝
    
    Args:
        model: 要剪枝的模型
        pruning_ratio: 剪枝比例
    """
    
    for name, module in model.named_modules():
        if isinstance(module, nn.Conv2d):
            # L1范数剪枝
            prune.l1_unstructured(
                module,
                name='weight',
                amount=pruning_ratio
            )
            # 移除掩码,使剪枝永久化
            prune.remove(module, 'weight')

def structured_channel_pruning(model, pruning_ratio=0.3):
    """
    结构化通道剪枝
    
    基于BN层的gamma值判断通道重要性
    """
    
    for name, module in model.named_modules():
        if isinstance(module, nn.BatchNorm2d):
            # 计算gamma的L1范数
            gamma = module.weight.data.abs()
            
            # 确定剪枝阈值
            k = int(len(gamma) * pruning_ratio)
            threshold = gamma.sort()[0][k]
            
            # 创建掩码
            mask = (gamma >= threshold).float()
            
            # 应用掩码到BN和对应的卷积
            module.weight.data *= mask
            
            # 找到对应的卷积层并剪枝
            # 这里简化处理,实际需要更复杂的逻辑

def evaluate_sparsity(model):
    """评估模型的稀疏度"""
    
    total_params = 0
    zero_params = 0
    
    for param in model.parameters():
        total_params += param.numel()
        zero_params += (param == 0).sum().item()
    
    sparsity = zero_params / total_params * 100
    print(f"Sparsity: {sparsity:.1f}%")
    print(f"Total params: {total_params}")
    print(f"Zero params: {zero_params}")

def demo_pruning():
    """演示剪枝流程"""
    
    # 创建模型
    model = nn.Sequential(
        PrunableConv(3, 64, 3),
        PrunableConv(64, 128, 3),
        nn.AdaptiveAvgPool2d(1),
        nn.Flatten(),
        nn.Linear(128, 10)
    )
    
    print("Before pruning:")
    evaluate_sparsity(model)
    
    # 剪枝
    magnitude_based_pruning(model, pruning_ratio=0.5)
    
    print("\nAfter pruning:")
    evaluate_sparsity(model)
    
    # 微调以恢复精度
    # ... 训练代码 ...

demo_pruning()

示例3:知识蒸馏实现

python
import torch
import torch.nn as nn
import torch.nn.functional as F

class TeacherModel(nn.Module):
    """大型教师模型"""
    
    def __init__(self):
        super().__init__()
        self.network = nn.Sequential(
            nn.Linear(784, 512),
            nn.ReLU(),
            nn.Linear(512, 256),
            nn.ReLU(),
            nn.Linear(256, 128),
            nn.ReLU(),
            nn.Linear(128, 10)
        )
    
    def forward(self, x):
        x = x.view(x.size(0), -1)
        return self.network(x)

class StudentModel(nn.Module):
    """小型学生模型"""
    
    def __init__(self):
        super().__init__()
        self.network = nn.Sequential(
            nn.Linear(784, 128),
            nn.ReLU(),
            nn.Linear(128, 10)
        )
    
    def forward(self, x):
        x = x.view(x.size(0), -1)
        return self.network(x)

class KnowledgeDistillationLoss(nn.Module):
    """
    知识蒸馏损失
    
    结合硬标签损失和软标签蒸馏损失
    """
    
    def __init__(self, temperature=5.0, alpha=0.3):
        super().__init__()
        self.temperature = temperature
        self.alpha = alpha
        self.ce_loss = nn.CrossEntropyLoss()
        self.kl_loss = nn.KLDivLoss()
    
    def forward(self, student_logits, teacher_logits, targets):
        # 硬标签损失
        hard_loss = self.ce_loss(student_logits, targets)
        
        # 软标签蒸馏损失
        soft_targets = F.softmax(teacher_logits / self.temperature, dim=1)
        student_probs = F.log_softmax(student_logits / self.temperature, dim=1)
        
        distillation_loss = self.kl_loss(
            student_probs, 
            soft_targets
        ) * (self.temperature ** 2)
        
        # 组合损失
        total_loss = self.alpha * hard_loss + (1 - self.alpha) * distillation_loss
        
        return total_loss

def train_with_distillation(teacher, student, dataloader, num_epochs=10):
    """
    使用知识蒸馏训练学生模型
    """
    
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    teacher = teacher.to(device).eval()
    student = student.to(device).train()
    
    optimizer = torch.optim.Adam(student.parameters(), lr=0.001)
    criterion = KnowledgeDistillationLoss(temperature=5.0, alpha=0.3)
    
    for epoch in range(num_epochs):
        total_loss = 0
        
        for data, targets in dataloader:
            data, targets = data.to(device), targets.to(device)
            
            # 教师模型推理(无梯度)
            with torch.no_grad():
                teacher_logits = teacher(data)
            
            # 学生模型推理
            student_logits = student(data)
            
            # 计算损失
            loss = criterion(student_logits, teacher_logits, targets)
            
            # 反向传播
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
            
            total_loss += loss.item()
        
        avg_loss = total_loss / len(dataloader)
        print(f"Epoch {epoch+1}/{num_epochs}, Loss: {avg_loss:.4f}")

def compare_models(teacher, student, test_loader):
    """比较教师和学生模型的精度"""
    
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    
    def evaluate(model):
        model.eval()
        correct = 0
        total = 0
        
        with torch.no_grad():
            for data, targets in test_loader:
                data, targets = data.to(device), targets.to(device)
                outputs = model(data)
                predictions = outputs.argmax(dim=1)
                
                correct += (predictions == targets).sum().item()
                total += targets.size(0)
        
        return correct / total * 100
    
    teacher_acc = evaluate(teacher)
    student_acc = evaluate(student)
    
    print(f"\nTeacher accuracy: {teacher_acc:.2f}%")
    print(f"Student accuracy: {student_acc:.2f}%")
    print(f"Size ratio: {get_model_size(student) / get_model_size(teacher) * 100:.1f}%")

def get_model_size(model):
    """获取模型参数量"""
    return sum(p.numel() for p in model.parameters())

def demo_distillation():
    """演示知识蒸馏"""
    
    # 创建模型
    teacher = TeacherModel()
    student = StudentModel()
    
    print(f"Teacher params: {get_model_size(teacher)}")
    print(f"Student params: {get_model_size(student)}")
    
    # 假设已经训练好教师模型
    # train_teacher(teacher, ...)
    
    # 蒸馏训练
    # train_with_distillation(teacher, student, dataloader)
    
    # 比较
    # compare_models(teacher, student, test_loader)

demo_distillation()

五、深入思考

5.1 历史背景

推理优化的研究与深度学习的发展同步。早期的工作主要集中在模型压缩,如LeCun在1990年提出的最优脑损伤(OBD)剪枝方法。

2015年后,随着深度学习的复兴,推理优化再次受到关注。Han等人的Deep Compression工作展示了大幅压缩的可能性。Distilling the Knowledge in a Neural Network(Hinton et al., 2015)开创了知识蒸馏领域。

近年来,随着边缘AI和大模型部署的需求增长,推理优化成为工业界和学术界的共同焦点。

5.2 前沿方向

神经架构搜索(NAS)for Efficiency:自动搜索既准确又高效的模型架构。

稀疏训练:从头训练稀疏模型,而非先训练稠密再剪枝。

自适应推理:根据输入难度动态调整计算量。

联合优化:同时优化模型、编译器和硬件,实现全局最优。

大模型推理:针对LLM的专门优化,如KV缓存、投机解码等。

5.3 延伸阅读

  • "Deep Compression: Compressing Deep Neural Networks with Pruning, Trained Quantization and Huffman Coding" - Han et al.
  • "Distilling the Knowledge in a Neural Network" - Hinton et al.
  • TensorRT官方文档
  • TVM论文和教程
  • "EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks"

六、实验笔记

实验1:量化精度分析

目标:评估不同量化方法对模型精度的影响

步骤:

训练一个标准CNN模型

分别应用PTQ和QAT

在测试集上比较精度

分析各层的量化敏感度

预期结果:QAT精度高于PTQ,某些层对量化更敏感

分析要点:

  • 哪些层最容易受量化影响?
  • 校准数据量的影响如何?
  • INT8与FP16的精度差距有多大?

实验2:剪枝与微调的迭代效果

目标:观察迭代剪枝-微调过程的精度恢复

步骤:

训练基线模型

逐步增加剪枝比例(10%, 30%, 50%, 70%, 90%)

每次剪枝后微调

记录精度和稀疏度的关系

预期结果:适度剪枝(50%以下)可以通过微调完全恢复精度

分析要点:

  • 精度下降的拐点在哪里?
  • 微调需要多少epoch?
  • 结构化vs非结构化剪枝的差异?

七、本章小结

本章深入探讨了推理优化的各种技术,从量化、剪枝、蒸馏到编译优化。我们分析了推理与训练的系统差异,掌握了主要的模型压缩方法,并通过代码实战将理论转化为实践。

推理优化是AI产品化的关键环节。高效的推理不仅可以降低成本,还能改善用户体验,使得AI技术在更多场景中变得可行。随着硬件和算法的不断进步,推理优化的空间仍在扩大。


八、习题

比较推理和训练在内存需求上的差异。对于一个Transformer模型,估算推理时的显存占用主要由哪些部分组成?

解释量化中的scale和zero_point的作用。如果一个张量的值范围是[-3.5, 7.2],如何计算INT8量化的scale和zero_point?

结构化剪枝和非结构化剪枝各有什么优缺点?为什么非结构化剪枝在通用硬件上难以加速?

知识蒸馏中,温度参数T的作用是什么?T过大或过小分别有什么问题?

模型编译器中的算子融合为什么能提高性能?列举三个可以融合的操作组合。

动态批处理如何在延迟和吞吐量之间权衡?设计一个自适应批处理策略。

阅读TensorRT文档,解释其优化流程。它进行了哪些类型的优化?

对于一个BERT模型,设计一个完整的推理优化方案,包括量化、编译和运行时优化。

分析量化感知训练为何比训练后量化效果更好。QAT在训练中模拟了什么?

调研新兴的推理优化技术(如 speculative decoding for LLMs),解释其工作原理和适用场景。

9/12推理优化
0%