【AI系统】计算图原理

简介: 本文介绍了AI框架中使用计算图来抽象神经网络计算的必要性和优势,探讨了计算图的基本构成,包括标量、向量、矩阵、张量等数据结构及其操作,并详细解释了计算图如何帮助解决AI工程化中的挑战。此外,文章还通过PyTorch实例展示了动态计算图的特点和实现方法,包括节点(张量或函数)和边(依赖关系)的定义,以及如何通过自定义Function实现正向和反向传播逻辑。

在前面的文章曾经提到过,目前主流的 AI 框架都选择使用计算图来抽象神经网络计算表达,通过通用的数据结构(张量)来理解、表达和执行神经网络模型,通过计算图可以把 AI 系统化的问题形象地表示出来。

本文将会以 AI 概念落地的时候,遇到的一些问题与挑战,因此引出了计算图的概念来对神经网络模型进行统一抽象。接着展开什么是计算,计算图的基本构成来深入了解诶计算图。最后简单地学习 PyTorch 如何表达计算图。

AI 系统化问题

遇到的挑战

在真正的 AI 工程化过程中,我们会遇到诸多问题。而为了高效地训练一个复杂神经网络,AI 框架需要解决许多问题,例如:

  • 如何对复杂的神经网络模型实现自动微分?

  • 如何利用编译期的分析 Pass 对神经网络的具体执行计算进行化简、合并、变换?

  • 如何规划基本计算 Kernel 在计算加速硬件 GPU/TPU/NPU 上高效执行?

  • 如何将基本处理单元派发(Dispatch)到特定的高效后端实现?

  • 如何对通过神经网络的自动微分(反向传播实现)衍生的大量中间变量,进行内存预分配和管理?

为了使用用统一的方式,解决上述提到的挑战,驱使着 AI 框架的开发者和架构师思考如何为各类神经网络模型的计算提供统一的描述,从而使得在运行神经网络计算之前,能够对整个计算过程尽可能进行推断,在编译期间自动为深度学习的应用程序补全反向计算、规划执行、降低运行时开销、复用和节省内存。能够更好地对特定领域语言(DSL),这里特指深度学习和神经网络进行表示,并对使用 Python 编写的神经网络模型进行优化与执行。

因此派生出了目前主流的 AI 框架都选择使用计算图来抽象神经网络计算。

image

计算图的定义

我们会经常遇到有些 AI 框架把统一的图描述称为数据流图,有些称为计算图,这里可以统称为计算图。下面简单介绍为什么可以都统称为计算图的原因。

  • 数据流图(Data Flow Diagram,DFD):从数据传递和加工角度,以图形方式来表达系统的逻辑功能、数据在系统内部的逻辑流向和逻辑变换过程,是结构化系统分析方法的主要表达工具及用于表示软件模型的一种图示方法。在 AI 框架中数据流图表示对数据进行处理的单元,接收一定的数据输入,然后对其进行处理,再进行系统输出。

  • 计算图(Computation Graph):被定义为有向图,其中节点对应于数学运算,计算图是表达和评估数学表达式的一种方式。而在 AI 框架中,计算图就是一个表示运算的有向无环图(Directed Acyclic Graph,DAG)。

其两者都把神经网络模型统一表示为图的形式,而图则是由节点和边组成。其都是在描述数据在图中的节点传播的路径,是由固定的计算节点组合而成,数据在图中的传播过程,就是对数据进行加工计算的过程。下面以公式为例:

$$ f(x_{1},x_{2})=ln(x_{1})+x_{1}*x_{2}−sin(x_{2})\\ $$

对上述公式转换为对应的计算图。

image

计算图的基本构成

数据表达方式

  • 标量 Scalar

标量(scalar),亦称“无向量”。有些物理量,只具有数值大小,而没有方向,部分有正负之分,物理学上指有大小而没有方向的量(跟「矢量」相区别)。物理学中,标量(或作纯量)指在坐标变换下保持不变的物理量。用通俗的说法,标量是只有大小,没有方向的量,如功、体积、温度等。

在 AI 框架或者计算机中,标量是一个独立存在的数,比如线性代数中的一个实数 488 就可以被看作一个标量,所以标量的运算相对简单,与平常做的算数运算类似。代码 x 则作为一个标量被赋值。

x = 488
  • 向量 Vector

向量(vector),物理、工程等也称作矢量、欧几里得向量(Euclidean vector),是数学、物理学和工程科学等多个自然科學中的基本概念。指一个同时具有大小和方向,且满足平行四边形法则的几何對象。理论数学中向量的定义为任何在稱為向量空间的代數結構中的元素。

在 AI 框架或者计算机中,向量指一列顺序排列的元素,通常习惯用括号将这些元素扩起来,其中每个元素都又一个索引值来唯一的确定其中在向量中的位置。其有大小也有方向,以公式为例,其代码 x_vec 则被作为一个向量被赋值。

$$ x_{vec} = \begin{bmatrix} 1.1 \\ 2.2 \\ 3.3 \end{bmatrix} \\$$

x_vec = [1.1, 2.2, 3.3]
  • 矩阵 Matrix

矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,最早来自于方程组的系数及常数所构成的方阵。这一概念由 19 世纪英国数学家凯利首先提出。矩阵是高等代数学中的常见工具,也常见于统计分析等应用数学学科中。

在机器学习领域经常被使用,比如有 N 个用户,每个用户有 M 个特征,那这个数据集就可以用一个 NxM 的矩阵表示,在卷积神经网络中输入模型的最初的数据是一个图片,读取图片上的像素点(Pixel)作为输入,一张尺寸大小为 256x256 的图片,实质上就可以用 256*256 的矩阵进行表示。

以公式为例,其代码 x_mat 则被表示为一个矩阵被赋值。

$$ x_{mat} = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{bmatrix}\\ $$

x_mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

图中对标量、向量、矩阵进行形象化表示:

image

  • 张量

张量(tensor)理论是数学的一个分支学科,在力学中有重要应用。张量这一术语起源于力学,它最初是用来表示弹性介质中各点应力状态的,后来张量理论发展成为力学和物理学的一个有力的数学工具。张量之所以重要,在于它可以满足一切物理定律必须与坐标系的选择无关的特性。张量概念是矢量概念的推广,矢量是一阶张量。

在几何代数中,张量是基于向量和矩阵的推广,通俗一点理解的话,可以将标量是为零阶张量,向量视为一阶张量,矩阵视为二阶张量。在 AI 框架中,所有数据将会使用张量进行表示,例如,图像任务通常将一副图片根据组织成一个 3 维张量,张量的三个维度分别对应着图像的长、宽和通道数,一张长和宽分别为 H, W 的彩色的图片可以表示为一个三维张量,形状为 (C, H, W)。自然语言处理任务中,一个句子被组织成一个 2 维张量,张量的两个维度分别对应着词向量和句子的长度。

一组图像或者多个句子只需要为张量再增加一个批量(batch)维度,N 张彩色图片组成的一批数据可以表示为一个四维张量,形状为 (N, C, H, W)。

张量和张量操作

在执行计算任务中,数据常常被组织成一个高维数组,整个计算任务的绝大部分时间都消耗在高维数组上的数值计算操作上。高维数组和高维数组之上的数值计算是神经网络的核心,构成了计算图中最重要的一类基本算子。在 AI 框架的数据中主要有稠密张量和稀疏张量,这里先考虑最为常用的稠密张量。

张量作为高维数组,是对标量,向量,矩阵的推广。AI 框架对张量的表示主要有以下几个重要因素:

  1. 元素数据类型:在一个张量中,所有元素具有相同的数据类型,如整型,浮点型,布尔型,字符型等数据类型格式;
  2. 形状:张量每个维度具有固定的大小,其形状是一个整型数的元组,描述了一个张量的维度以及每个维度的长度;
  3. 设备:决定了张量的存储设备,如在通用处理器 CPU 中的 DDR 上还是 GPU/NPU 的 HBM 上等。

下面是针对形状为 (3, 2, 5) 的三维张量进行表示。

image

虽然张量通常用索引来指代轴,但是始终要记住每个轴的含义。轴一般按照从全局到局部的顺序进行排序:首先是批次轴,随后是空间维度,最后是每个位置的特征。这样,在内存中,特征向量就会位于连续的区域。例如针对形状为 (3, 2, 4, 5) 的四维张量进行表示,其内存表示如图中右侧所示。

image

高维数组为开发者提供了一种逻辑上易于理解的方式来组织有着规则形状的同质数据,极大地提高了编程的可理解性。另一方面,使用高维数据组织数据,易于让后端自动推断并完成元素逻辑存储空间向物理存储空间的映射。更重要的是:张量操作将同构的基本运算类型作为一个整体进行批量操作,通常都隐含着很高的数据并行性,因此非常适合在单指令多数据(SIMD)并行后端上进行加速。

计算图表示 AI 框架

计算图是用来描述运算的有向无环图,有两个主要元素:节点 (Node) 和边 (Edge)。节点表示数据,如向量、矩阵、张量;边表示具体执行的运算,如加、减、乘、除和卷积等。

下面以简单的数学公式 $z = x + y$ 为例,可以绘制上述方程的计算图如下:

image

上面的计算图具有一个三个节点,分别代表张量数据中的两个输入变量 x 和 y 以及一个输出 z。两条边带有具体的 “+” 符号表示加法。

在 AI 框架中会稍微有点不同,其计算图的基本组成有两个主要的元素:1)基本数据结构张量和 2)基本计算单元算子。节点代表 Operator 具体的计算操作(即算子),边代表 Tensor 张量。整个计算图能够有效地表达神经网络模型的计算逻辑和状态。

  • 基本数据结构张量:张量通过 shape 来表示张量的具体形状,决定在内存中的元素大小和元素组成的具体形状;其元素类型决定了内存中每个元素所占用的字节数和实际的内存空间大小

  • 基本运算单元算子:具体在加速器 GPU/NPU 中执行运算的是由最基本的代数算子组成,另外还会根据深度学习结构组成复杂算子。每个算子接受的输入输出不同,如 Conv 算子接受 3 个输入 Tensor,1 个输出 Tensor

下面以简单的一个卷积、一个激活的神经网络模型的正向和反向为例,其前向的计算公式为:

$$ f(x) = ReLU(Conv(w, x, b))\\ $$

反向计算微分的时候,需要加上损失函数:

$$ Loss(x, x') = f(x) - x' \\$$

根据正向的神经网络模型定义,AI 框架中的计算图如下:

image

上面 (a) 中计算图具有两个节点,分别代表卷积 Conv 计算和激活 ReLU 计算,Conv 计算接受三个输入变量 x 和权重 w 以及一个偏置 b,激活接受 Conv 卷积的输出并输出一个变量。(b)为对应(a)的反向计算图,在神经网络模型训练的过程当中,自动微分功能会为开发者自动构建反向图,然后输入输出完整一个完整 step 计算。

总而言之,AI 框架的设计很自然地沿用了张量和张量操作,将其作为构造复杂神经网络的基本描述单元,开发者可以在不感知复杂的框架后端实现细节的情况下,在 Python 脚本语言中复用由后端优化过的张量操作。而计算 Kernel 的开发者,能够隔离神经网络算法的细节,将张量计算作为一个独立的性能域,使用底层的编程模型和编程语言应用硬件相关优化。

在这里的计算图其实忽略了 2 个细节,特殊的操作:如:程序代码中的 For/While 等构建控制流;和特殊的边:如:控制边表示节点间依赖。

PyTorch 计算图

动态计算图

在 Pytorch 的计算图中,同样由节点和边组成,节点表示张量或者函数,边表示张量和函数之间的依赖关系。其中 Pytorch 中的计算图是动态图。这里的动态主要有两重含义。

  • 第一层含义是:计算图的正向传播是立即执行的。无需等待完整的计算图创建完毕,每条语句都会在计算图中动态添加节点和边,并立即执行正向传播得到计算结果。
import torch

w = torch.tensor([[3.0,1.0]],requires_grad=True)
b = torch.tensor([[3.0]],requires_grad=True)
X = torch.randn(10,2)
Y = torch.randn(10,1)

# Y_hat 定义后其正向传播被立即执行,与其后面的 loss 创建语句无关
Y_hat = X@w.t() + b
print(Y_hat.data)

loss = torch.mean(torch.pow(Y_hat-Y,2))
print(loss.data)
  • 第二层含义是:计算图在反向传播后立即销毁。下次调用需要重新构建计算图。如果在程序中使用了 backward 方法执行了反向传播,或者利用 torch.autograd.grad 方法计算了梯度,那么创建的计算图会被立即销毁,释放存储空间,下次调用需要重新创建。
# 如果再次执行反向传播将报错
loss.backward()  

# 计算图在反向传播后立即销毁,如果需要保留计算图, 需要设置 retain_graph = True
loss.backward(retain_graph = True)

计算图中 Function

计算图中的另外一种节点是 Function, 实际上为对张量操作的函数,其特点为同时包括正向计算逻辑和反向传播的逻辑。通过继承 torch.autograd.Function 来创建。

以创建一个 ReLU 函数为例:

class MyReLU(torch.autograd.Function):

    # 正向传播逻辑,可以用 ctx 存输入张量,供反向传播使用
    @staticmethod
    def forward(ctx, input):
        ctx.save_for_backward(input)
        return input.clamp(min=0)

    #反向传播逻辑
    @staticmethod
    def backward(ctx, grad_output):
        input, = ctx.saved_tensors
        grad_input = grad_output.clone()
        grad_input[input < 0] = 0
        return grad_input

接着在构建动态计算图的时候,加入刚创建的 Function 节点。

# relu 现在也可以具有正向传播和反向传播功能
relu = MyReLU.apply
Y_hat = relu(X@w.t() + b)

loss = torch.mean(torch.pow(Y_hat-Y,2))
loss.backward()

print(w.grad)
print(b.grad)
print(Y_hat.grad_fn)
tensor([[4.5000, 4.5000]])
tensor([[4.5000]])
<torch.autograd.function.MyReLUBackward object at 0x1205a46c8>

如果您想了解更多AI知识,与AI专业人士交流,请立即访问昇腾社区官方网站https://www.hiascend.com/或者深入研读《AI系统:原理与架构》一书,这里汇聚了海量的AI学习资源和实践课程,为您的AI技术成长提供强劲动力。不仅如此,您还有机会投身于全国昇腾AI创新大赛和昇腾AI开发者创享日等盛事,发现AI世界的无限奥秘~

目录
相关文章
|
3天前
|
存储 人工智能 算法
【AI系统】计算图的优化策略
本文深入探讨了计算图的优化策略,包括算子替换、数据类型转换、存储优化等,旨在提升模型性能和资源利用效率。特别介绍了Flash Attention算法,通过分块计算和重算策略优化Transformer模型的注意力机制,显著减少了内存访问次数,提升了计算效率。此外,文章还讨论了内存优化技术,如Inplace operation和Memory sharing,进一步减少内存消耗,提高计算性能。
53 34
【AI系统】计算图的优化策略
|
2天前
|
机器学习/深度学习 人工智能 PyTorch
【AI系统】计算图基本介绍
近年来,AI框架如TensorFlow和PyTorch通过计算图描述神经网络,推动了AI技术的发展。计算图不仅抽象了神经网络的计算表达,还支持了模型算子的高效执行、梯度计算及参数训练。随着模型复杂度增加,如MOE、GAN、Attention Transformer等,AI框架需具备快速分析模型结构的能力,以优化训练效率。计算图与自动微分紧密结合,实现了从前向计算到反向传播的全流程自动化。
21 4
【AI系统】计算图基本介绍
|
2天前
|
机器学习/深度学习 人工智能 算法
【AI系统】计算图挑战与未来
当前主流AI框架采用计算图抽象神经网络计算,以张量和算子为核心元素,有效表达模型计算逻辑。计算图不仅简化数据流动,支持内存优化和算子调度,还促进了自动微分功能的实现,区分静态图和动态图两种形式。未来,计算图将在图神经网络、大数据融合、推理部署及科学计算等领域持续演进,适应更复杂的计算需求。
29 5
【AI系统】计算图挑战与未来
|
2天前
|
机器学习/深度学习 人工智能 前端开发
【AI系统】计算图的控制流实现
计算图作为有向无环图(DAG),能够抽象神经网络模型,但在编程中遇到控制流语句(如if、else、while、for)时,如何表示成为难题。引入控制流后,开发者可构建更复杂的模型结构,但部署含控制流的模型至不支持Python的设备上较为困难。目前,PyTorch仅支持Python控制流,而TensorFlow通过引入控制流原语来解决此问题。计算图的动态与静态实现各有优劣,动态图易于调试,静态图利于优化。
20 5
【AI系统】计算图的控制流实现
|
2天前
|
机器学习/深度学习 存储 人工智能
【AI系统】计算图与自动微分
自动求导利用链式法则计算雅可比矩阵,从结果节点逆向追溯计算路径,适用于神经网络训练中损失值对网络参数的梯度计算。AI框架中,自动微分与反向传播紧密相连,通过构建计算图实现高效梯度计算,支持动态和静态计算图两种模式。动态图如PyTorch,适合灵活调试;静态图如TensorFlow,利于性能优化。
23 6
【AI系统】计算图与自动微分
|
2天前
|
人工智能 调度 算法框架/工具
【AI系统】计算图的调度与执行
深度学习训练过程涉及前向计算、计算损失及更新权重参数。AI框架通过计算图统一表示训练过程,算子作为计算图的节点,由后端硬件高效执行。计算图调度包括算子间的调度、并发调度和异构调度,确保计算资源的有效利用。图执行模式分为单算子执行、整图下沉执行和图切分多设备执行,适应不同场景需求。以PyTorch为例,其算子执行通过两次调度选择合适的Kernel进行张量操作,并支持自动求导。
22 5
|
2天前
|
机器学习/深度学习 人工智能 编译器
【AI系统】微分实现方式
本文详细介绍了自动微分的三种实现方法:基本表达式、操作符重载和源代码转换。每种方法都有其特点和适用场景,包括它们的实现原理、优缺点。自动微分是机器学习和深度学习中的关键技术,理解这些实现方式有助于更好地掌握其背后的数学原理和工程实践。文中还提到了具体的应用案例和工具,如PyTorch和MindSpore,展示了这些方法在实际项目中的应用。
15 3
|
7天前
|
存储 人工智能 缓存
【AI系统】布局转换原理与算法
数据布局转换技术通过优化内存中数据的排布,提升程序执行效率,特别是对于缓存性能的影响显著。本文介绍了数据在内存中的排布方式,包括内存对齐、大小端存储等概念,并详细探讨了张量数据在内存中的排布,如行优先与列优先排布,以及在深度学习中常见的NCHW与NHWC两种数据布局方式。这些布局方式的选择直接影响到程序的性能,尤其是在GPU和CPU上的表现。此外,还讨论了连续与非连续张量的概念及其对性能的影响。
27 3
|
5月前
|
机器学习/深度学习 人工智能 Shell
人工智能平台PAI操作报错合集之在分布式训练过程中遇到报错,是什么原因
阿里云人工智能平台PAI是一个功能强大、易于使用的AI开发平台,旨在降低AI开发门槛,加速创新,助力企业和开发者高效构建、部署和管理人工智能应用。其中包含了一系列相互协同的产品与服务,共同构成一个完整的人工智能开发与应用生态系统。以下是对PAI产品使用合集的概述,涵盖数据处理、模型开发、训练加速、模型部署及管理等多个环节。
|
14天前
|
存储 人工智能 缓存
【AI系统】核心计算之矩阵乘
本文探讨了AI模型中矩阵乘运算的优化实现及其在AI芯片设计中的重要性。文章首先介绍了卷积操作如何转化为矩阵乘,接着阐述了矩阵乘的分块(Tiling)技术以适应芯片内存限制,最后总结了几种常见的矩阵乘优化方法,包括循环优化、分块矩阵乘法、SIMD指令优化等,旨在提高计算效率和性能。
38 0