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

深度学习系统概览

从算法到硬件

深度学习栈框架架构GPU角色性能瓶颈

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

第1章 深度学习系统概览 - 从算法到硬件 (Deep Learning Systems Overview: From Algorithms to Hardware)

一、导读

1.1 本章学习目标

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

理解深度学习系统的完整技术栈,从高层算法到底层硬件的垂直整合关系

掌握深度学习框架的核心组件及其相互作用机制

区分训练阶段与推理阶段在系统设计上的根本差异

了解GPU、TPU等专用硬件加速器的工作原理及其适用场景

认识分布式训练的基本范式和数据并行、模型并行的核心概念

理解内存管理在深度学习系统中的关键作用及优化策略

掌握性能分析的基本方法,能够识别系统瓶颈

建立对深度学习系统全貌的系统性认知框架

1.2 为什么本章如此重要

深度学习已经从一个纯粹的学术研究领域演变为支撑现代人工智能基础设施的核心技术。然而,大多数从业者的知识往往局限于使用高级框架如PyTorch或TensorFlow编写模型代码,对于底层系统如何工作知之甚少。这种知识断层导致了诸多实际问题:模型训练效率低下、资源浪费严重、部署困难、难以调试性能问题等。

理解深度学习系统的完整架构至关重要。首先,它能够帮助开发者做出更明智的技术选型决策。当面对不同的硬件环境、数据规模和性能要求时,具备系统知识的工程师能够选择最合适的框架配置、并行策略和优化方案。其次,系统知识是解决复杂问题的基础。在实际生产环境中,模型训练往往会遇到显存溢出、通信瓶颈、数值不稳定等问题,这些问题的根源通常不在算法层面,而在于系统设计的某个环节。

更重要的是,随着大语言模型和生成式AI的兴起,深度学习系统的规模正在以前所未有的速度扩张。千卡集群训练万亿参数模型已成为常态,这对系统设计提出了全新的挑战。传统的单机单卡思维已无法应对现代深度学习工程的需求。只有深入理解从算法到硬件的完整技术栈,才能在这个快速发展的领域中保持竞争力。

本章将为读者构建一个完整的认知框架,后续章节将在此基础上深入探讨各个子系统的技术细节。

1.3 核心问题引导

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

一个典型的深度学习训练任务从用户代码到硬件执行经历了哪些转换步骤?每个步骤由哪个系统组件负责?

为什么GPU成为深度学习的主流加速硬件?它与CPU在架构设计上有哪些本质区别使其适合矩阵运算?

训练阶段和推理阶段对系统资源的需求有何不同?为什么不能简单地用同一套系统同时优化两者?

当模型规模超过单张GPU的显存容量时,有哪些技术手段可以解决这个问题?它们各自的优缺点是什么?

在多GPU分布式训练中,梯度同步是如何实现的?AllReduce操作背后的通信模式是怎样的?

深度学习框架中的计算图表示有什么优势?动态图和静态图各适用于什么场景?

内存碎片化问题是如何产生的?深度学习系统采用了哪些策略来缓解这个问题?

从软件工程的视角看,深度学习系统与传统软件系统在架构设计上有何异同?


二、核心概念详解

深度学习系统技术栈

深度学习系统是一个多层次的技术栈,每一层都建立在下一层的基础之上,同时为上一层提供抽象和服务。理解这个技术栈的结构是掌握深度学习系统工程的关键。

应用层(Application Layer)位于技术栈的最顶端,直接面向最终用户。这一层包括各种预训练模型、微调框架、模型即服务(MaaS)平台等。用户在这一层通常只需要关注业务逻辑和模型选择,无需关心底层实现细节。例如,使用Hugging Face Transformers库加载一个预训练的BERT模型进行文本分类,就属于应用层的操作。这一层的特点是高度抽象、易用性强,但灵活性相对较低。

框架层(Framework Layer)是深度学习生态中最活跃的层次,包括PyTorch、TensorFlow、JAX、MXNet等主流框架。框架层的核心职责是提供编程接口(API),让用户能够方便地定义神经网络结构、损失函数、优化器等组件,并自动处理前向传播和反向传播的计算。现代框架通常采用计算图(Computation Graph)作为内部表示,将用户的Python代码转换为可优化的中间表示。框架层还需要处理设备管理、内存分配、自动微分等系统级任务。

编译器层(Compiler Layer)近年来受到越来越多的关注,代表项目包括TVM、XLA、Triton等。编译器的作用是将框架生成的计算图进一步优化,生成针对特定硬件的高效代码。这一层的优化包括算子融合(Operator Fusion)、常量折叠(Constant Folding)、内存复用(Memory Reuse)等。随着硬件多样性的增加,编译器层的重要性日益凸显,它使得上层框架能够透明地利用不同硬件的加速能力。

运行时层(Runtime Layer)负责实际的执行调度,包括任务队列管理、线程池调度、异步执行等。这一层需要与操作系统内核交互,管理CPU和GPU之间的数据传输,处理并发和同步问题。CUDA Runtime、cuDNN库等都属于这一层的组成部分。运行时的效率直接影响整体性能,特别是在多GPU和多节点场景下,通信调度和负载均衡成为关键挑战。

硬件抽象层(Hardware Abstraction Layer)提供统一的硬件访问接口,屏蔽不同硬件平台的差异。CUDA是NVIDIA GPU的事实标准抽象层,而ROCm是AMD的对应方案。这一层暴露了硬件的底层能力,如共享内存、原子操作、 warp级别原语等,供上层系统使用。

硬件层(Hardware Layer)是技术栈的物理基础,包括GPU、TPU、FPGA、ASIC等各种计算加速器。现代AI芯片通常包含大量的并行计算单元、高带宽内存(HBM)、专用矩阵乘法单元(如Tensor Core)等组件。硬件的设计决策直接影响上层系统的性能和功能边界。

计算图表示

计算图(Computation Graph)是深度学习框架的核心数据结构,它将神经网络的计算过程表示为一个有向图,其中节点代表操作(Operation),边代表数据流(Tensor)。

计算图的引入解决了几个关键问题。首先,它使得框架能够在执行前对整个计算过程进行分析,从而进行全局优化。例如,框架可以识别出可以合并的操作序列,减少内核启动开销;可以分析数据的生命周期,优化内存分配策略;可以检测出未使用的分支,避免无效计算。

其次,计算图为自动微分提供了基础。反向传播算法本质上是在计算图的反向边上进行梯度传递。框架通过记录前向传播时构建的计算图,能够自动生成对应的反向传播代码,无需用户手动推导梯度公式。这是现代深度学习框架相比早期工具(如Theano之前的手工实现)的巨大进步。

计算图有两种主要形式:静态图(Static Graph)和动态图(Dynamic Graph)。静态图在执行前需要先定义完整的图结构,然后一次性编译和执行。TensorFlow 1.x是静态图的代表,它的优点是便于优化和部署,但缺点是调试困难、灵活性差。动态图则在执行过程中逐步构建,每次前向传播都可以有不同的图结构。PyTorch采用动态图(也称为Define-by-Run),它的优点是灵活、易于调试,与原生Python代码无缝集成,但优化空间相对有限。

现代框架正在趋向于融合两种范式的优点。PyTorch 2.0引入了Torch Compile功能,可以将动态图转换为静态图进行优化;TensorFlow 2.0则默认启用Eager Execution(动态执行),同时保留Graph Mode用于高性能场景。JAX采用函数式编程范式,通过即时编译(JIT)在保持灵活性的同时获得静态图的优化优势。

自动微分机制

自动微分(Automatic Differentiation, AD)是深度学习框架的核心引擎,它能够自动计算任意复杂函数的梯度。理解自动微分的工作原理对于正确使用框架和调试数值问题至关重要。

自动微分不同于符号微分和数值微分。符号微分通过解析表达式推导闭式解,适用于简单函数但无法处理控制流;数值微分通过有限差分近似梯度,存在精度问题和计算开销大的缺点。自动微分则通过将复杂函数分解为基本操作的组合,利用链式法则逐层计算梯度,既保持了精确性又具有通用性。

自动微分有两种模式:前向模式(Forward Mode)和反向模式(Reverse Mode)。前向模式从输入变量开始,沿着计算图正向传播,同时计算函数值和梯度;反向模式先从输入计算输出,然后从输出反向传播梯度到输入。对于深度学习中的典型场景——输入维度高(百万级参数)、输出维度低(单个损失值)——反向模式的效率远高于前向模式,因为反向模式只需一次遍历即可计算所有输入的梯度,而前向模式需要对每个输入变量单独遍历。因此,深度学习框架普遍采用反向模式自动微分,这也解释了为什么反向传播成为深度学习的标准算法。

在实现层面,框架通过记录前向传播时的操作序列(称为tape或gradient tape),构建一个反向计算图。当调用backward()时,框架从损失值开始,按照拓扑排序的逆序依次调用每个操作的梯度函数,将上游梯度乘以局部梯度,得到下游梯度。这个过程涉及大量的张量操作和内存管理,是框架性能的关键瓶颈之一。

训练与推理的差异

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

计算内容:训练阶段需要执行前向传播和反向传播两个阶段,反向传播涉及梯度计算和优化器更新,计算量通常是前向传播的2-3倍。推理阶段只执行前向传播,计算量显著减少。

内存需求:训练时需要保存前向传播的中间激活值,以便在反向传播时使用,这导致显存占用大幅增加。对于大型模型,激活值可能占据大部分显存。推理时不需要保存中间结果,显存需求主要来自模型参数和少量临时缓冲区。

精度要求:训练通常使用FP32或混合精度(FP16/BF16),以保证数值稳定性和收敛性。推理可以使用更低精度的INT8甚至二值化表示,以换取更高的吞吐量和更低的延迟。

批处理策略:训练时通常使用较大的批次大小以充分利用硬件并行性和提高梯度估计的准确性。推理时批次大小取决于延迟要求,实时应用场景可能需要批次大小为1,而离线批量推理可以使用较大批次以提高吞吐量。

状态管理:某些层(如Batch Normalization、Dropout)在训练和推理时有不同的行为。BatchNorm在训练时统计批次均值和方差,在推理时使用运行平均值;Dropout在训练时随机丢弃神经元,在推理时保持完整网络。框架需要正确管理这些状态切换。

理解这些差异有助于针对性地优化系统。例如,推理引擎可以省略反向传播相关的代码路径,采用更激进的内存优化策略,使用专门的量化感知编译流程等。

GPU加速原理

图形处理单元(GPU)之所以成为深度学习的主流加速硬件,源于其架构设计与神经网络计算特性的高度契合。

GPU的核心优势在于大规模并行处理能力。与CPU通常拥有少数几个高性能核心不同,现代GPU包含数千个相对简单的计算核心。例如,NVIDIA A100 GPU拥有6912个CUDA核心。这种众核架构特别适合处理深度学习中大量独立的矩阵乘法和卷积运算,这些运算可以被分解为成千上万个并行执行的线程。

GPU的内存层次结构也经过专门优化。高带宽内存(HBM)提供超过1TB/s的内存带宽,远超CPU系统的DDR内存。片上共享内存(Shared Memory)和寄存器文件为频繁访问的数据提供低延迟存储。L1/L2缓存层级进一步减少全局内存访问的开销。

Tensor Core是NVIDIA Volta架构引入的专用矩阵乘法单元,能够在一个时钟周期内完成4x4矩阵的乘加运算。使用Tensor Core可以将矩阵乘法性能提升数倍,但要求数据布局符合特定格式(如半精度浮点、特定的维度对齐)。

GPU执行模型基于SIMT(Single Instruction Multiple Threads)范式。一组线程(称为warp,通常包含32个线程)同时执行相同的指令,但各自操作不同的数据。这种执行模式非常适合神经网络的批量计算,但也带来了分支发散(Branch Divergence)的问题:当warp内的线程执行不同的控制流路径时,性能会显著下降。

CUDA编程模型将GPU视为一个可以执行内核函数(Kernel Function)的设备。内核函数由大量线程并行执行,线程被组织成线程块(Thread Block)和网格(Grid)两级层次。程序员需要合理设计线程划分和数据布局,以最大化并行效率和内存访问效率。

分布式训练范式

当模型规模或数据量超出单机能力时,分布式训练成为必要手段。分布式训练主要有两种范式:数据并行(Data Parallelism)和模型并行(Model Parallelism)。

数据并行是最常用的分布式策略。在这种模式下,模型副本分布在多个设备上,每个设备处理不同的数据子集。前向传播在各设备上独立执行,反向传播计算出本地梯度后,需要通过AllReduce操作在所有设备间同步梯度。数据并行的实现相对简单,通信开销与模型大小成正比,与批次大小无关。当批次大小足够大时,通信开销可以被计算开销掩盖,从而实现良好的扩展效率。

模型并行将模型的不同部分分布在不同设备上。这又分为两种方式:流水线并行(Pipeline Parallelism)和张量并行(Tensor Parallelism)。流水线并行将模型的层分组分配到不同设备,数据像流水线一样依次通过各组;张量并行将单个层的权重矩阵分割到多个设备上,每个设备计算矩阵的一部分。模型并行适用于模型太大无法放入单张GPU显存的场景,但实现复杂度高,通信开销大,且可能引入流水线气泡(Pipeline Bubble)降低效率。

混合并行策略结合多种并行方式,是现代大模型训练的标配。例如,GPT-3的训练使用了数据并行、流水线并行和张量并行的组合,在数千张GPU上扩展。


三、程序员的视角

3.1 在实际项目中的应用

理解深度学习系统架构在实际开发中有广泛的应用价值。

性能调优:当模型训练速度慢于预期时,系统知识帮助开发者定位瓶颈。是使用nvprof或Nsight Profiler分析GPU利用率?检查数据加载是否成为瓶颈?评估是否需要启用混合精度训练?还是考虑增加批次大小以提高GPU利用率?具备系统知识的开发者能够系统性地进行性能分析,而不是盲目尝试。

资源规划:在项目初期,需要根据模型规模和数据量估算所需的硬件资源。这需要理解模型参数量、激活值大小、梯度存储需求与显存占用的关系,以及不同并行策略下的通信开销。准确的资源规划可以避免后期因资源不足导致的返工。

框架选型:不同的框架在性能、易用性、生态系统方面各有优劣。PyTorch在研究和原型开发中占主导地位,因其动态图特性和丰富的社区资源;TensorFlow在生产部署方面有更成熟的工具链;JAX在科学计算和高性能研究场景中表现出色。理解各框架的系统特性有助于做出合适的选择。

部署优化:模型从训练环境迁移到生产环境时,需要进行一系列优化:转换为ONNX或TensorRT格式、应用量化、剪枝、蒸馏等技术。这些优化措施的效果依赖于对推理系统工作原理的理解。

3.2 常见陷阱与误区

显存泄漏:在PyTorch中,如果在前向传播中保存了带有梯度的张量引用(如将其添加到列表中),这些张量及其计算图将无法被垃圾回收,导致显存持续增长。解决方法是使用.detach()分离张量或禁用梯度计算。

小批次效率低下:当批次大小过小时,GPU的并行能力无法充分利用,内核启动开销占比过高。应尽量增大批次大小,或使用梯度累积模拟大批次效果。

数据加载瓶颈:如果数据预处理在CPU上进行且速度较慢,GPU将经常处于空闲等待状态。应使用多进程数据加载(PyTorch的DataLoader设置num_workers>0)、预取和缓存策略来缓解这一问题。

不必要的同步:在分布式训练中,频繁的同步操作会引入显著的通信开销。应尽量减少同步频率,使用异步更新或局部更新策略。

数值精度问题:混合精度训练可以显著提升性能,但不当使用可能导致数值溢出或下溢。需要使用损失缩放(Loss Scaling)和适当的精度转换策略。

3.3 与其他层级的联系

深度学习系统不是孤立存在的,它与整个软件基础设施紧密集成。

与操作系统的交互:GPU驱动程序作为内核模块运行,CUDA Runtime通过系统调用与驱动通信。内存分配涉及操作系统级别的虚拟内存管理。理解这些交互有助于诊断底层问题。

与网络栈的集成:分布式训练依赖高速网络进行通信。InfiniBand和RoCE提供低延迟、高带宽的网络连接,NCCL库针对这些网络进行了优化。网络拓扑感知调度可以进一步减少通信延迟。

与存储系统的关系:大规模训练需要从存储系统读取海量数据。并行文件系统(如Lustre、GPFS)和对象存储(如S3)提供高吞吐的数据访问。数据格式(如TFRecord、WebDataset)的选择影响I/O效率。


四、代码实战

示例1:分析PyTorch计算图

python
import torch
import torch.nn as nn

class SimpleNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 50)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(50, 1)
    
    def forward(self, x):
        x = self.fc1(x)
        x = self.relu(x)
        x = self.fc2(x)
        return x

# 创建模型和输入
model = SimpleNet()
x = torch.randn(5, 10, requires_grad=True)

# 前向传播
output = model(x)
loss = output.sum()

# 查看计算图信息
print(f"输出张量的梯度函数: {output.grad_fn}")
print(f"损失的梯度函数: {loss.grad_fn}")

# 反向传播
loss.backward()

# 查看梯度
print(f"输入梯度形状: {x.grad.shape}")
print(f"fc1权重梯度形状: {model.fc1.weight.grad.shape}")

示例2:GPU内存使用监控

python
import torch
import gc

def print_gpu_memory():
    """打印当前GPU内存使用情况"""
    if torch.cuda.is_available():
        allocated = torch.cuda.memory_allocated() / 1024**2
        reserved = torch.cuda.memory_reserved() / 1024**2
        print(f"已分配: {allocated:.2f} MB")
        print(f"已预留: {reserved:.2f} MB")
        print(f"空闲: {reserved - allocated:.2f} MB")
    else:
        print("CUDA不可用")

# 测试内存分配
print("初始状态:")
print_gpu_memory()

# 分配大张量
x = torch.randn(1000, 1000, device='cuda')
print("\n分配1000x1000张量后:")
print_gpu_memory()

# 释放张量
del x
gc.collect()
torch.cuda.empty_cache()
print("\n释放后:")
print_gpu_memory()

示例3:简单的数据并行训练

python
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

# 检查多GPU可用性
if torch.cuda.device_count() < 2:
    print("需要至少2个GPU来演示数据并行")
else:
    # 创建模型
    model = nn.Sequential(
        nn.Linear(100, 256),
        nn.ReLU(),
        nn.Linear(256, 10)
    )
    
    # 包装为DataParallel
    model = nn.DataParallel(model)
    model = model.cuda()
    
    # 创建假数据
    X = torch.randn(1000, 100)
    y = torch.randint(0, 10, (1000,))
    dataset = TensorDataset(X, y)
    dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
    
    # 训练循环
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    
    for epoch in range(3):
        total_loss = 0
        for batch_X, batch_y in dataloader:
            batch_X, batch_y = batch_X.cuda(), batch_y.cuda()
            
            optimizer.zero_grad()
            output = model(batch_X)
            loss = criterion(output, batch_y)
            loss.backward()
            optimizer.step()
            
            total_loss += loss.item()
        
        print(f"Epoch {epoch+1}, Loss: {total_loss/len(dataloader):.4f}")

五、深入思考

5.1 历史背景

深度学习系统的发展经历了多个阶段。早期的神经网络研究受限于计算资源,主要在CPU上运行小规模模型。2006年,Hinton等人提出深度信念网络,重新点燃了深度学习的研究热情。2012年,AlexNet在ImageNet竞赛中的突破性表现证明了GPU加速的深度卷积网络的强大能力,标志着深度学习进入主流视野。

随后的几年中,深度学习框架迅速演进。Caffe提供了高效的卷积实现但缺乏灵活性;Theano首次引入了自动微分和符号计算的概念;Torch(Lua版本)在研究社区广泛使用。2015-2016年,TensorFlow和PyTorch相继发布,确立了现代深度学习框架的基本形态。

近年来,随着Transformer架构和大语言模型的兴起,深度学习系统的规模呈指数级增长。从单机单卡到千卡集群,从GB级到TB级模型,系统设计的挑战不断升级。专用的AI芯片(如TPU、Graphcore IPU、Cerebras Wafer-Scale Engine)也在探索新的硬件架构可能性。

5.2 前沿方向

编译器驱动的优化:TVM、XLA、MLIR等项目正在推动深度学习编译器的发展,目标是实现跨硬件的高性能代码生成。

稀疏计算:利用模型中的稀疏性(激活稀疏、权重稀疏)来加速计算,需要硬件和算法的协同设计。

存算一体:新型存储器(如ReRAM、PCM)支持在存储单元内直接进行计算,有望突破冯·诺依曼瓶颈。

量子机器学习:虽然仍处于早期阶段,但量子计算可能在未来为特定类型的机器学习任务提供指数级加速。

5.3 延伸阅读

  • "Deep Learning" by Ian Goodfellow, Yoshua Bengio, and Aaron Courville - 深度学习理论基础
  • "Programming Massively Parallel Processors" by David Kirk and Wen-mei Hwu - CUDA编程权威指南
  • PyTorch官方文档中的"Internals"部分 - 框架内部实现细节
  • NVIDIA Developer Blog - GPU技术和最佳实践
  • MLSys Conference Proceedings - 机器学习系统领域的最新研究成果

六、实验笔记

实验1:比较CPU和GPU训练性能

目标:量化GPU加速带来的性能提升

步骤:

创建一个中等规模的卷积神经网络(如ResNet-18)

分别在CPU和GPU上训练该网络,使用相同的数据集(如CIFAR-10)

记录每轮训练的时间和总训练时间

使用nsight-compute或torch.profiler分析GPU利用率

预期结果:GPU训练速度应该是CPU的10-50倍,具体取决于模型和硬件配置

分析要点:

  • GPU利用率是否接近100%?如果不是,瓶颈在哪里?
  • 数据传输(CPU到GPU)占总时间的比例是多少?
  • 不同批次大小对性能的影响如何?

实验2:分析不同并行策略的扩展效率

目标:理解数据并行和模型并行的性能特征

步骤:

准备一个可以在多GPU上运行的模型

分别使用DataParallel和DistributedDataParallel进行训练

测量使用1、2、4、8张GPU时的训练吞吐量

计算线性扩展效率(实际加速比/理想加速比)

预期结果:DistributedDataParallel应该比DataParallel有更好的扩展效率,尤其是在多节点场景下

分析要点:

  • 通信开销随GPU数量增加的变化趋势
  • 批次大小对扩展效率的影响
  • 网络带宽是否是瓶颈?

七、本章小结

本章介绍了深度学习系统的完整技术栈,从应用层到硬件层的各个组成部分及其相互关系。我们讨论了计算图表示、自动微分、训练与推理差异、GPU加速原理和分布式训练范式等核心概念。通过程序员的视角,我们了解了系统知识在实际开发中的应用价值和常见陷阱。最后,通过代码示例和实验任务,我们将理论知识与实践相结合。

深度学习系统是一个快速发展的领域,新技术和新架构不断涌现。但无论技术如何演变,理解系统的基本原理和设计原则都是掌握这一领域的关键。后续章节将深入探讨各个子系统的具体实现和技术细节,帮助读者建立更深入的专业知识。


八、习题

解释静态计算图和动态计算图的区别,并说明各自的优势和适用场景。

为什么反向模式自动微分比前向模式更适合深度学习中的梯度计算?请从计算复杂度角度进行分析。

描述GPU的内存层次结构,并解释每种内存类型的特点和使用场景。

在数据并行训练中,梯度同步的通信开销与哪些因素相关?如何估算AllReduce操作的时间?

假设你有一个包含1亿参数的模型,使用FP32精度训练。估算仅存储参数和梯度所需的显存量。如果启用Adam优化器,额外需要多少显存?

解释Tensor Core的工作原理,以及使用Tensor Core需要满足哪些条件。

在PyTorch中,.detach()和with torch.no_grad()有什么区别?分别在什么场景下使用?

设计一个实验来诊断模型训练中的数据加载瓶颈。列出你需要测量的指标和分析方法。

比较流水线并行和张量并行的优缺点。在什么情况下应该选择其中一种而非另一种?

阅读一篇最近的MLSys会议论文,总结其提出的系统优化技术,并讨论其在实际场景中的潜在应用价值。

1/12深度学习
0%