diff --git a/05Framework/01Foundation/05MindSpore.md b/05Framework/01Foundation/05MindSpore.md new file mode 100644 index 00000000..038ac568 --- /dev/null +++ b/05Framework/01Foundation/05MindSpore.md @@ -0,0 +1,374 @@ +# 昇思 MindSore 关键特性 + +本节将会介绍华为自研AI框架昇思MindSpore,这是一个面向全场景设计的AI计算框架,旨在为AI算法研究和生产部署提供一个统一、高效、安全的平台。接下来,将详细阐述MindSpore的定位、架构、特性、以及其在端边云全场景下的应用和优势。 + +## MindSpore 基本介绍 + +### MindSpore定位 + +昇思MindSpore是面向“端-边-云”全场景设计的AI框架,旨在弥合AI算法研究与生产部署之间的鸿沟。在算法研究阶段,为开发者提供动静统一的编程体验以提升算法的开发效率;生产阶段,自动并行可以极大加快分布式训练的开发和调试效率,同时充分挖掘异构硬件的算力;在部署阶段,基于“端-边-云”统一架构,应对企业级部署和安全可信方面的挑战。开源以来,秉持全场景协同、全流程极简、全架构统一三大价值主张,致力于增强开发易用性、提升原生支持大模型和AI+科学计算的体验。” 向上使能AI模型创新,对下兼容多样性算力(NPU、GPU、CPU)。 + +![MindSporeIntroduction.png](images/01MindSpore01.png) + +### 昇思MindSpore架构 + +昇思MindSpore整体架构分为四层(如图 1所示): + +- **模型层**,为开发者提供开箱即用的功能,该层主要包含预置的模型和开发套件,以及图神经网络(GNN)、深度概率编程等热点研究领域拓展库; + +- **表达层(MindExpression)**,为开发者提供AI模型开发、训练、推理的接口,支持开发者用原生Python语法开发和调试神经网络,其特有的动静态图统一能力使开发者可以兼顾开发效率和执行性能,同时该层在生产和部署阶段提供全场景统一的C++接口; + +- **编译优化(MindCompiler)**,作为AI框架的核心,以全场景统一中间表达(MindIR)为媒介,将前端表达编译成执行效率更高的底层语言,同时进行全局性能优化,包括自动微分、代数化简等硬件无关优化,以及图算融合、算子生成等硬件相关优化; + +- **运行时**,按照上层编译优化的结果对接并调用底层硬件算子,同时通过“端 - 边 - 云”统一的运行时架构, 支持包括联邦学习在内的“端 - 边 - 云”AI 协同。 + +![MindSporeIntroduction.png](images/01MindSpore02.png) + +## 昇思MindSpore特性 + +昇思MindSpore为开发者提供Python等语言的编程范式。借助基于源码转换,开发者可以使用原生Python控制语法和其他一些高级API,如元组(Tuple)、列表(List)和Lambda表达。 + +### 前端编程 + +昇思MindSpore提供面向对象和面向函数的编程范式。开发者可以基于nn.cell类派生定义所需功能的AI网络或网络的某一层(layer),并可通过对象的嵌套调用的方式将已定义的各种layer进行组装,完成整个AI网络的定义。同时开发者也可以定义一个可被昇思MindSpore源到源编译转换的Python纯函数,通过昇思MindSpore提供的函数或装饰器,将其加速执行。 + +下面分别介绍昇思MindSpore支持的三类编程范式及其简单示例。 + +#### 面向对象编程 + +面向对象编程(Object-oriented programming,OOP),是指一种将程序分解为封装数据及相关操作的模块(类)而进行的编程方式,对象为类(class)的实例。面向对象编程将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性,对象里的程序可以访问及经常修改对象相关联的数据。 + +在一般的编程场景中,代码(code)和数据(data)是两个核心构成部分。面向对象编程是针对特定对象(Object)来设计数据结构,定义类(Class)。类通常由以下两部分构成,分别对应了code和data: + +- 方法(Methods) +- 属性(Attributes) + +对于同一个Class实例化(instantiation)后得到的不同对象而言,方法和属性相同,不同的是属性的值。不同的属性值决定了对象的内部状态,因此OOP能够很好地进行状态管理。 + +下面为Python构造简单类的示例: + +```python +class Sample: #class declaration + + def __init__(self, name): # class constructor (code) + self.name = name # attribute (data) + + def set_name(self, name): # method declaration (code) + self.name = name # method implementation (code) +``` + +对于构造神经网络来说,首要的组件就是网络层(Layer),一个神经网络层包含以下部分: + +- Tensor操作(Operation) +- 权重(Weights) + +此二者恰好与类的Methods和Attributes一一对应,同时权重本身就是神经网络层的内部状态,因此使用类来构造Layer天然符合其定义。此外,我们在编程时希望使用神经网络层进行堆叠,构造深度神经网络,使用OOP编程可以很容易地通过Layer对象组合构造新的Layer类。 + +下面为使用昇思MindSpore构造神经网络类的示例: + +```python +from mindspore import nn, Parameter +from mindspore.common.initializer import initializer + + +class Linear(nn.Cell): + + def __init__(self, in_features, out_features, + has_bias): # class constructor (code) + super().__init__() + self.weight = Parameter( + initializer('normal', [out_features, in_features], + mindspore.float32), 'weight') # layer weight (data) + self.bias = Parameter( + initializer('zeros', [out_features], mindspore.float32), + 'bias') # layer weight (data) + + def construct(self, inputs): # method declaration (code) + output = ops.matmul(inputs, self.weight.transpose( + 0, 1)) # tensor transformation (code) + output = output + self.bias # tensor transformation (code) + return output +``` + +除神经网络层的构造使用面向对象编程范式外,昇思MindSpore支持纯面向对象编程方式构造神经网络训练逻辑,此时神经网络的正向计算、反向传播、梯度优化等操作均使用类进行构造。下面是纯面向对象编程的示例: + +```python +import mindspore +import mindspore.nn as nn +from mindspore import value_and_grad + + +class TrainOneStepCell(nn.Cell): + + def __init__(self, network, optimizer): + super().__init__() + self.network = network + self.optimizer = optimizer + self.grad_fn = value_and_grad(self.network, None, + self.optimizer.parameters) + + def construct(self, *inputs): + loss, grads = self.grad_fn(*inputs) + self.optimizer(grads) + return loss + +network = nn.Dense(5, 3) +loss_fn = nn.BCEWithLogitsLoss() +network_with_loss = nn.WithLossCell(network, loss_fn) +optimizer = nn.SGD(network.trainable_params(), 0.001) +trainer = TrainOneStepCell(network_with_loss, optimizer) +``` + +此时,不论是神经网络及其训练过程均使用继承nn.Cell的类进行管理,可以方便地作为计算图进行编译加速。 + +#### 函数式编程 + +函数式编程(Functional programming)是一种将计算机运算视为函数运算,并且避免使用程序状态以及可变对象的编程范式。 + +在函数式编程中,函数被视为一等公民,这意味着它们可以绑定到名称(包括本地标识符),作为参数传递,并从其他函数返回,就像任何其他数据类型一样。这允许以声明性和可组合的风格编写程序,其中小功能以模块化方式组合。 + +函数式编程有时被视为纯函数式编程的同义词,是将所有函数视为确定性数学函数或纯函数的函数式编程的一个子集。当使用一些给定参数调用纯函数时,它将始终返回相同的结果,并且不受任何可变状态或其他副作用的影响。 + +函数式编程有两个核心特点,使其十分符合科学计算的需要: + +- 编程函数语义与数学函数语义完全对等。 +- 确定性,给定相同输入必然返回相同输出。无副作用。 + +由于确定性这一特点,通过限制副作用,程序可以有更少的错误,更容易调试和测试,更适合形式验证。下面是使用函数式编程的示例: + +```python +import mindspore.numpy as mnp +from mindspore import grad + +grad_tanh = grad(mnp.tanh) +print(grad_tanh(2.0)) +# 0.070650816 + +print(grad(grad(mnp.tanh))(2.0)) +print(grad(grad(grad(mnp.tanh)))(2.0)) +# -0.13621868 +# 0.25265405 +``` + +配合函数式编程范式的需要,昇思MindSpore提供了多种函数变换接口,涵盖包括自动微分、自动向量化、自动并行、即时编译、数据下沉等功能模块,下面简单进行介绍: + +- 自动微分:grad、value_and_grad,提供微分函数变换功能; +- 自动向量化:vamp,用于沿参数轴映射函数fn的高阶函数; +- 自动并行:shard,函数式算子切分,指定函数输入/输出Tensor的分布策略; +- 即时编译:jit,将Python函数编译为一张可调用的MindSpore图; +- 数据下沉:data_sink,对输入的函数进行变换,获得可使用数据下沉模式的函数。 + +基于上述函数变换接口,在使用函数式编程范式时可以快速高效地使用函数变换实现复杂的功能。 + +#### 融合编程 + +下面是函数式+面向对象融合编程的典型过程: + +- 用类构建神经网络; +- 实例化神经网络对象; +- 构造正向函数,连接神经网络和损失函数; +- 使用函数变换,获得梯度计算(反向传播)函数; +- 构造训练过程函数; +- 调用函数进行训练。 + +下面是函数式+面向对象融合编程的简单示例: + +```python +# Class definition +class Net(nn.Cell): + def __init__(self): + ...... + def construct(self, inputs): + ...... + +# Object instantiation +net = Net() # network +loss_fn = nn.CrossEntropyLoss() # loss function +optimizer = nn.Adam(net.trainable_params(), lr) # optimizer + +# define forward function +def forword_fn(inputs, targets): + logits = net(inputs) + loss = loss_fn(logits, targets) + return loss, logits + +# get grad function +grad_fn = value_and_grad(forward_fn, None, optim.parameters, has_aux=True) + +# define train step function +def train_step(inputs, targets): + # get values and gradients + (loss, logits), grads = grad_fn(inputs, targets) + optimizer(grads) # update gradient + return loss, logits + +for i in range(epochs): + for inputs, targets in dataset(): + loss = train_step(inputs, targets) +``` + +如上述示例,在神经网络构造时,使用面向对象编程,神经网络层的构造方式符合AI编程的习惯。在进行前向计算和反向传播时,昇思MindSpore使用函数式编程,将前向计算构造为函数,然后通过函数变换,获得grad_fn,最后通过执行grad_fn获得权重对应的梯度。 + +通过函数式+面向对象融合编程,既保证了神经网络构建的易用性,同时提高了前向计算和反向传播等训练过程的灵活性,是昇思MindSpore推荐的默认编程范式。 + +#### 函数式微分编程 + +目前主流的AI框架有三种自动微分技术: + +- 基于静态计算图的转换:在编译时将网络转换为静态数据流图,然后将链式规则转换为数据流图,实现自动微分。 + +- 基于动态计算图的转换:以算子重载的方式记录前向执行时网络的操作轨迹,然后将链式规则应用到动态生成的数据流图中,实现自动微分。 + +- 基于源码的转换:该技术是从函数式编程框架演化而来,对中间表达(程序在编译过程中的表达形式),以即时(Just-In-Time,JIT)编译的形式进行自动微分变换,支持复杂的流程控制场景、高阶函数和闭包。基于源码转化的自动微分如图所示。 + +![02AutomaticDifferentiation.png](images/01MindSpore03.png) + +昇思MindSpore开发了一种新的策略,即基于源码转换的自动微分。一方面,它支持流程控制的自动微分,因此构建像PyTorch这样的模型非常方便。另一方面,昇思MindSpore可以对神经网络进行静态编译优化,从而获得良好的性能。 + +昇思MindSpore自动微分的实现可以理解为对程序本身进行符号微分,因为MindSpore IR是函数式的中间表达,它与基本代数中的复合函数有直观的对应关系,只要已知基础函数的求导公式,就能推导出由任意基础函数组成的复合函数的求导公式。MindSpore IR中每个原语操作可以对应为基础代数中的基础函数,这些基础函数可以构建更复杂的流程控制。 + +### 动静统一 + +传统AI框架主要有2种编程执行形态,静态图模式和动态图模式。静态图模式会基于开发者调用的框架接口,在编译执行时先生成神经网络的图结构,然后再执行图中涉及的计算操作。静态图模式能有效感知神经网络各层算子间的关系情况,基于编译技术进行有效的编译优化以提升性能。 + +但传统静态图需要开发者感知构图接口,组建或调试网络比较复杂,且难于与常用Python库、自定义Python函数进行穿插使用。动态图模式,能有效解决静态图的编程较复杂问题,但由于程序按照代码的编写顺序执行,系统难于进行整图编译优化,导致相对性能优化空间较少,特别面向DSA等专有硬件的优化比较难于使能。 + +昇思MindSpore由于基于源码转换机制构建神经网络的图结构。因此相比传统的静态图模式,能有更易用的表达能力。同时也能更好的兼容动态图和静态图的编程接口,比如面向控制流,动态图可以直接基于Python的控制流关键字编程。而静态图需要基于特殊的控制流算子编程或者需要开发者编程指示控制流执行分支。这导致了动态图和静态图编程差异大。 + +而昇思MindSpore的源码转换机制,可基于Python控制流关键字,直接使能静态图模式的执行,使得动静态图的编程统一性更高。同时开发者基于昇思MindSpore的接口,可以灵活的对Python代码片段进行动静态图模式控制。即可以将程序局部函数以静态图模式执行而同时其他函数按照动态图模式执行。从而使得在与常用Python库、自定义Python函数进行穿插执行使用时,开发者可以灵活指定函数片段进行静态图优化加速,而不牺牲穿插执行的编程易用性。 + +#### 静态编译机制 + +昇思MindSpore框架在静态图模式下,先将Python代码编译成静态计算图,然后执行静态计算图。通过MindCompiler编译器将Python代码的AST表示转换成ANF范式的MindIR表示,并基于MindIR表示展开编译优化和自动微分处理。MindIR是一种基于图表示的函数式IR,从函数式编程规定来看,它跟Python语言命令式编程是有所区别的,开发者编写程序时需要遵循昇思MindSpore静态图语法支持,语法使用存在约束限制。 + +JIT Fallback是从静态图的角度出发考虑静动统一。通过JIT Fallback特性,静态图可以支持尽量多的动态图语法,使得静态图提供接近动态图的语法使用体验,从而实现动静统一。JIT Fallback特性主要作用于MindCompiler编译器,应用于图模式场景下的Python语法解析和支持,将纯底层算子执行的计算图改造成,开发者的Python代码和算子执行交替混合执行的计算图。主要过程如下: + +![ComputationalGraph](images/01MindSpore04.png) + +JIT Fallback特性主要作用于MindCompiler编译器的实现,应用于图模式场景下的Python语法解析和支持,将纯底层算子执行的计算图改造成,开发者的Python代码和算子执行交替混合执行的计算图。主要过程包括: + +1. 检测不支持语法。在图编译阶段,识别检测出图模式不支持的Python语法。 + +2. 生成解释节点。针对不支持的Python语法,将相关语句保留下来,生成解释节点,并将解释节点转换为ANF IR表示。 + +3. 推导和执行解释节点。解释节点有两种执行方式:编译时运行和运行时运行。解释节点是在编译时进行推导的,一般而言,解释节点尽量在编译时执行,另一种方式则是在运行时执行。 + +#### 动静混合编程 + +在昇思MindSpore中,称动态图模式为PyNative模式,因为代码使用Python解释器在该模式下运行。在动态图模式下,框架按照Python执行模型的所有算子,为每个算子生成计算图,并将计算图传递给后端进行前向计算。在完成前向计算的同时,根据前向算子所对应的反向传播源码,转换成单算子反向图,最终在完成整体模型的前向计算后,生成模型对应的完整反向图,并传递给后端进行执行。 + +由于编译器能获得静态图的全局信息,所以静态图在大多数情况下都表现出更好的运行性能。而动态图可以保证更好的易用性,使开发者能够更加方便地构建和修改模型。为了同时支持静态图和动态图,大多数先进的训练框架需要维护两种自动微分机制,即基于Tape的自动微分机制和基于图的自动微分机制。 + +### 端边云全场景 + +昇思MindSpore是训推一体的AI框架,同时支持训练和推理等功能。同时昇思MindSpore支持CPU、GPU、NPU等多种芯片,并且在不同芯片上提供统一的编程使用接口以及可生成在多种硬件上加载执行的离线模型。按照实际执行环境和业务需求,提供多种规格的版本形态,支持部署在云端、服务器端、手机等嵌入式设备端以及耳机等超轻量级设备端上的部署执行。 + +#### 轻量化推理 + +轻量化推理是将训练好的模型部署到运行环境中进行推理的过程,模型部署的过程中需要解决训练模型到推理模型的转换,硬件资源对模型的限制,模型推理的时延、功耗、内存占用等指标对整个系统的影响以及模型的安全等一系列的问题。 + +- 模型完成训练后,需要将模型及参数持久化成文件,不同的训练框架导出的模型文件中存储的数据结构不同,这给模型的推理系统带来了不便。推理系统为了支持不同的训练框架的模型,需要将模型文件中的数据转换成统一的数据结构。此外,在训练模型转换成推理模型的过程中,需要进行一些如算子融合、常量折叠等模型的优化以提升推理的性能。 + +- 推理模型部署到不同的场景,需要满足不同的硬件设备的限制,例如,在具有强大算力的计算中心或数据中心的服务器上可以部署大规模的模型,而在边缘侧服务器、个人电脑以及智能手机上,力和内存则相对有限,部署的模型的规模就相应地要降低。在超低功耗的微控制器上,则只能部署非常简单的机器学习模型。此外,不同硬件对于不同数据类型(如float32、float16、bfloat16、int8等)的支持程度也不相同。为了满足这些硬件的限制,在有些场景下需要对训练好的模型进行压缩,降低模型的复杂度或者数据的精度,减少模型的参数,以适应硬件的限制。 + +- 模型部署到运行环境中执行推理,推理的时延、内存占用、功耗等是影响开发者使用的关键因素,优化模型推理的方式有两种,一是设计专有的机器学习的芯片,相对于通用的计算芯片,这些专有芯片一般在能效比上具有很大的优势。二是通过软硬协同最大程度地发挥硬件的能力。对于第二种方式,以CPU为例,如何切分数据块以满足cache大小,如何对数据进行重排以便计算时可以连续访问,如何减少计算时的数据依赖以提升硬件流水线的并行,如何使用扩展指令集以提升计算性能,这些都需要针对不同的CPU架构进行设计和优化。 + +#### 联邦学习 + +随着人工智能的飞速发展,大规模和高质量的数据对模型的效果和用户的体验都变得越来越重要。与此同时,数据的利用率成为了制约了人工智能的进一步发展的瓶颈。隐私、监管和工程等问题造成了设备与设备之间的数据不能共享,进而导致了数据孤岛问题的出现。为了解决这一难题,联邦学习(Federated Learning,FL)应运而生。联邦学习的概念最早在2016年被提了出来。在满足用户隐私保护、数据安全和政府法规的要求下,联邦学习能有效地使用多方机构的数据进行机器学习建模。 + +MindSpore Federated是华为昇思MindSpore提出的一款开源联邦学习框架,支持千万级无状态终端设备商用化部署,在用户数据留存在本地的情况下,使能全场景智能应用。MindSpore Federated专注于大规模参与方的横向联邦的应用场景,使参与联邦学习的各用户在不共享本地数据的前提下共建AI模型。MindSpore Federated主要解决隐私安全、大规模联邦聚合、半监督联邦学习、通信压缩和跨平台部署等联邦学习在工业场景部署的难点。 + +### 极致性能 + +昇思MindSpore基于编译技术,提供了丰富的硬件无关优化,如IR融合、代数化简、常数折叠、公共子表达式消除等。同时昇思MindSpore针对NPU、GPU等不同硬件,也提供各种硬件优化能力,从而更好的发挥硬件的大规模计算加速能力。 + +昇思MindSpore除了提供传统AI框架常用优化,还提供了一些比较有特色的技术。 + +#### 图算融合 + +昇思MindSpore等主流AI计算框架对开发者提供的算子通常是从开发者可理解、易使用角度进行定义。每个算子承载的计算量不等,计算复杂度也各不相同。但从硬件执行角度看,这种天然的、基于开发者角度的算子计算量划分,并不高效,也无法充分发挥硬件资源计算能力。主要体现在: + +1. 计算量过大、过复杂的算子,通常很难生成切分较好的高性能算子,从而降低设备利用率; + +2. 计算量过小的算子,由于计算无法有效隐藏数据搬移开销,也可能会造成计算的空等时延,从而降低设备利用率; + +3. 硬件Device通常为多核、众核结构,当算子shape较小或其它原因引起计算并行度不够时,可能会造成部分核的空闲,从而降低设备利用率。特别是基于专用处理器架构(Domain Specific Architecture,后文简称DSA)的芯片对这些因素更为敏感。如何最大化发挥硬件算力性能的同时使算子也能具备较好的易用性,一直以来是一个很大的挑战。 + +在AI框架设计方面,目前业界主流采用图层和算子层分层的实现方法。图层负责对计算图进行融合或重组,算子层负责将融合或重组后的算子编译为高性能的可执行算子。 + +图层通常采用基于Tensor的High-Level IR的处理和优化,算子层则采用基于计算指令的Low-Level IR进行分析和优化。 这种人为分层处理显著增加了图、算两层进行协同优化的难度。昇思MindSpore在过去几年的技术实践中,采用了图算融合的技术来较好的解决了这个问题。 + +#### Ascend加速 + +昇腾芯片上集成了AICORE、AICPU和CPU。其中,AICORE负责大型Tensor Vector运算,AICPU负责标量运算,CPU负责逻辑控制和任务分发。 + +Host侧CPU负责将图或算子下发到昇腾芯片。昇腾芯片由于具备了运算、逻辑控制和任务分发的功能,所以不需要与Host侧的CPU进行频繁的交互,只需要将计算完的最终结果返回给Host侧,实现整图下沉到Device执行,避免Host-Device频繁交互,减小了开销。 + +为了充分使用昇腾芯片硬件功能,打造极致性能,昇思MindSpore提供了整图下沉功能,目的是减少Host-Device交互开销,有效的提升训练与推理的性能。 + +昇思MindSpore构建的图包含数据图和计算图,通过将数据图下沉和计算图下沉的方式,减少Host-Device交互开销。且结合循环下沉可以实现多个Step下沉,进一步减少Host和Device的交互次数。 + +#### 梯度累积 + +梯度累积是一种将训练神经网络的数据样本按Batch size拆分为几个小Batch的方式,然后按顺序进行计算。 + +神经网络模型由许多相互连接的神经网络单元所组成,在所有神经网络层中,样本数据会不断向前传播。在通过所有层后,网络模型会输出样本的预测值,通过损失函数然后计算每个样本的损失值(误差)。神经网络通过反向传播,去计算损失值相对于模型参数的梯度。最后这些梯度信息用于对网络模型中的参数进行更新。 + +梯度累积只计算神经网络模型,并不及时更新网络模型的参数,同时在计算的时候累积得到的梯度信息,最后统一使用累积的梯度来对参数进行更新。 + +$$ +\text{accumulated} = \sum_{i=0}^{N} \text{grad}_i +$$ + + +在不更新模型变量的时候,实际上是把原来的数据Batch size分成几个小的Mini-Batch,每个step中使用的样本实际上是更小的数据集。 + +在N个step内不更新变量,使所有Mini-Batch使用相同的模型变量来计算梯度,以确保计算出来得到相同的梯度和权重信息,算法上等价于使用原来没有切分的Batch size大小一样。即: + +$$ +\theta_i = \theta_{i-1} - \text{lr} \sum_{i=0}^{N} \text{grad}_i +$$ + +最终在上面步骤中累积梯度会产生与使用全局Batch size大小相同的梯度总和。 + +![01MindSporeIntroduction04](images/01MindSpore05.png) + +#### 自适应梯度求和 + +与传统的分布式训练中的梯度更新不同,自适应梯度求和考虑到梯度的方向。在网络训练初期,不同batch获得的梯度更新方向基本是平行的,但是随着训练进行,梯度更新方向趋向于正交。而且网络的不同层梯度更新的正交性差异也是比较大的。 + +![01MindSporeIntroduction05](images/01MindSpore06.png) + +以两个训练节点为例,梯度的更新原理如下: + +$$ +\begin{aligned} +w' &= w_0 - \alpha \left[ \left( 1 - \frac{(g_2^T \cdot g_1)}{2 \cdot \| g_1 \|^2} \right) g_1 + \left( 1 - \frac{(g_2^T \cdot g_1)}{2 \cdot \| g_2 \|^2} \right) g_2 \right] \\ + &= w_0 - \alpha \cdot \text{Adasum}(g_1, g_2) +\end{aligned} +$$ + +其中,g1是训练节点1的梯度,g2是训练节点2的梯度。当训练节点拓展到n(n=2x,x=1,2,3⋯)个时,采用递归的方式来对问题进行分解,递归公式如下: + +$$ +\begin{aligned} +\text{Adasum}(g_{[0,n]}) &= \text{Adasum}\left( \text{Adasum}(g_{[0,n/2]}), \text{Adasum}(g_{[n/2,n]}) \right) +\end{aligned} +$$ + +从上述公式中可见,论文中是对梯度更新,考虑到优化器(optimizer)对梯度的操作不一定满足线性转换,因此优化为对经过optimizer后的网络权重差值(delta weights)做adasum操作。 + +另外,在实际应用过程中,为了优化通信开销,通常会采取Adasum和传统Reducesum混合的执行方式,如下图所示: + +![01MindSporeIntroduction06](images/01MindSpore07.png) + +## 小结与思考 + +- 昇思MindSpore是华为推出的全场景AI计算框架,通过统一架构支持端、边、云的AI算法研究与部署,简化开发流程,并提升效率与性能。 + +- MindSpore的架构由模型层、表达层、编译优化层和运行时组成,实现了从高级API到硬件算子的全栈优化,保证了执行效率。 + +- 该框架支持面向对象和函数式编程范式,以及动静态图统一编程,提供了灵活性和易用性,同时保持高性能。 + +- MindSpore在端边云全场景下的应用包括轻量化推理、联邦学习、图算融合和Ascend加速等技术,以极致性能满足不同硬件和场景需求。 \ No newline at end of file diff --git a/05Framework/01Foundation/README.md b/05Framework/01Foundation/README.md index 6938ff28..fee9f586 100644 --- a/05Framework/01Foundation/README.md +++ b/05Framework/01Foundation/README.md @@ -16,6 +16,7 @@ AI 框架基础内容介绍,从 AI 框架基础开始去介绍为什么我们 | 02 AI 框架的作用| [文章](./02Fundamentals.md), [PPT](./02Fundamentals.pdf), [视频](https://www.bilibili.com/video/BV1fd4y1q7qk) | | 03 AI 框架之争(框架发展)| [文章](./03History.md), [PPT](./03History.pdf), [视频](https://www.bilibili.com/video/BV1C8411x7Kn) | | 04 编程范式(声明式&命令式)| [文章](./04Programing.md), [PPT](./04Programing.pdf), [视频](https://www.bilibili.com/video/BV1gR4y1o7WT) | +| 04 MindSpore 介绍 | [文章](./05MindSpore.md) | ## 备注 diff --git a/05Framework/01Foundation/images/05MindSpore01.png b/05Framework/01Foundation/images/05MindSpore01.png new file mode 100644 index 00000000..1bfb63a7 Binary files /dev/null and b/05Framework/01Foundation/images/05MindSpore01.png differ diff --git a/05Framework/01Foundation/images/05MindSpore02.png b/05Framework/01Foundation/images/05MindSpore02.png new file mode 100644 index 00000000..21e461b2 Binary files /dev/null and b/05Framework/01Foundation/images/05MindSpore02.png differ diff --git a/05Framework/01Foundation/images/05MindSpore03.png b/05Framework/01Foundation/images/05MindSpore03.png new file mode 100644 index 00000000..6db1fec3 Binary files /dev/null and b/05Framework/01Foundation/images/05MindSpore03.png differ diff --git a/05Framework/01Foundation/images/05MindSpore04.png b/05Framework/01Foundation/images/05MindSpore04.png new file mode 100644 index 00000000..b8db2714 Binary files /dev/null and b/05Framework/01Foundation/images/05MindSpore04.png differ diff --git a/05Framework/01Foundation/images/05MindSpore05.png b/05Framework/01Foundation/images/05MindSpore05.png new file mode 100644 index 00000000..78fe5b3d Binary files /dev/null and b/05Framework/01Foundation/images/05MindSpore05.png differ diff --git a/05Framework/01Foundation/images/05MindSpore06.png b/05Framework/01Foundation/images/05MindSpore06.png new file mode 100644 index 00000000..dafead0e Binary files /dev/null and b/05Framework/01Foundation/images/05MindSpore06.png differ diff --git a/05Framework/01Foundation/images/05MindSpore07.png b/05Framework/01Foundation/images/05MindSpore07.png new file mode 100644 index 00000000..b3e9898a Binary files /dev/null and b/05Framework/01Foundation/images/05MindSpore07.png differ diff --git a/05Framework/04Parallel/07MSParallel.md b/05Framework/04Parallel/07MSParallel.md new file mode 100644 index 00000000..7cf0284c --- /dev/null +++ b/05Framework/04Parallel/07MSParallel.md @@ -0,0 +1,114 @@ +# 昇思MindSpore并行 + +本节将会介绍昇思MindSpore的并行训练技术,以及如何通过张量重排布和自动微分简化并行策略搜索,实现高效大模型训练。 + +## 大模型的带来 + +随着深度学习的发展,为了实现更高的准确率和更丰富的应用场景,训练数据集和深度神经网络模型的规模日益增大。特别是自然语言处理(Natural Language Processing,NLP)领域,数据集的范围从200MB到541TB不等。模型的尺寸也从BERT的3.4亿个参数,Transformer-xl的8亿个参数,GPT-2的150亿个参数,到SwitchTransformer的万亿参数,单独存储万亿模型的参数则需要占用TB级别空间。 + +主流的用于训练的加速器(GPU、TPU和Ascend)的内存仍然只有几十GB,因此,为了能够且高效地完成大模型训练,深度学习框架需要提供丰富的并行训练的能力,支持数据并行、模型并行、混合并行、流水线并行、异构训练和专家并行等技术。 + +### AI 框架的局限性 + +当前的主流框架(如TensorFlow、Caffe和MXNet)提供了一些基本的并行技术,其中大多数框架提供了算子级别切分、流水线并行或者优化器切分的功能,支持的并行维度和功能的完整度欠佳。 + +- 第一,这些框架通过手动的切分来切分深度神经网络模型来实现模型并行,配置难度非常大,对开发者的要求非常高,需要有丰富经验的专家来操作。实现混合并行(数据并行和模型并行同时进行)又极大增加了开发的复杂度。最近的研究成果提出了简化混合并行的方法,但这些方法在几个方面都存在局限性。 + +- 第二,随着目前模型规模拓展到了万亿级别,训练卡数的规模也上升到了千级,以往的算子级别切分的并行不能满足目前大模型的需求。在大集群训练中,由于模型切分导致的通信占比在整个迭代耗时中升高,需要引入流水线并行等计算来降低通信占比,提升模型训练效率。另外,混合专家(MoE)技术能够在提升模型规模的同时,较少的提升计算量,是目前的一种主流技术。 + +### MindSpore 大模型并行 + +昇思MindSpore的目标是提供完整的大模型训练落地流程。为了解决前后设备张量排布不一致的问题,在并行化策略搜索中引入了张量重排布(Tensor Redistribution,TR),这使输出张量的设备布局在输入到后续算子之前能够被转换。 + +但是,对于复杂大型模型的搜索并行策略,在考虑张量重排布时,需要克服的挑战主要有两个。首先,既然张量重排布将通信算子(例如AllGather)引入数据流图,那么如何像普通算子一样自动地对通信算子求导呢?对于每个相应的前向算子,都需要获取反向算子,用来更新可训练参数。目前的框架需要专家在反向阶段手动添加SEND和RECV源语来传递梯度,这对模型开发者来说是一项具有挑战性的工作,尤其是在模型比较复杂的情况下。 + +其次,随着张量重排布对策略空间的极大扩展,如何为复杂的大型模型高效地找到一个好的策略?在功能和效率方面,该算法需要为具有非线性结构的大模型快速找到一种策略。在性能方面,算法返回的策略应该会缩短端到端的训练时间。需要对运行成本进行仔细建模,这一过程也增加了人工成本。最后,如何解决万亿模型训练的实际问题,最大化的利用硬件算力,同时降低训练成本? + +## MindSpore 并行策略 + +昇思MindSpore针对上述三个挑战,推出了完整的大模型训练解决方案。作为一种通用的技术方案,能够以较高效率实现万亿模型的训练。 + +第一,为了实现通信算子的自动微分,昇思MindSpore定义了通信算子的反向算子。例如,AllGather的反向算子为ReduceScatter。定义这些反向算子十分重要,因为Auto-diff过程可以一次性地区分整个前向图,而无须跳过任何算子,这也是为什么Auto-diff是Auto-parallel后面一步的原因。 + +针对第二个挑战,在同时考虑计算和通信开销的情况下,建立一个代价模型来选择一个好策略。为了快速地为复杂大图找到一个好策略,提出了几种方法:一种是支持多图操作的算法,将原始图转换成线性图;一种是策略分离机制,在保证返回解的精度的同时,有效地缩小搜索空间。例如,ResNet50在8台设备上搜索并行策略的时间在1s内,而返回的解决方案确实缩短了训练时间。例如,当模型较大(类的数量超过128K)时,返回的解决方案与原始数据并行策略相比减少了大约55%的训练时间。 + +第三,昇思MindSpore内置了多种并行技术,以易用的接口提供了混合并行、流水线并行、异构训练和优化器并行等技术,结合这些技术就可以较高的训练效率实现大模型训练。 + +```python +class Submodel(nn.Cell): + + def __init__(self, shape): + super().__init__() + self.bn = BatchNorm().shard(((4, 1), )) + self.matmul = MatMul().shard(((1, 1), (1, 4))) + self.W = Parameter(Tensor(shape), require_grad=True) + + def construct(self, X): + Y = self.bn(X) + Z = self.matmul(Y, self.W) + return Z +``` + +### 算子级别并行 + +昇思MindSpore支持开发者指定的高级策略配置,称之为半自动并行(semi-auto-parallel)。在以上代码和图示中,展示了一个从数据到模型的并行转换的例子。该子模型的结构为BatchNorm算子后跟一个MatMul算子,广泛应用于ResNet、ReID等分类任务。在BatchNorm算子中,X按行拆分为四部分,数据可以并行,效率非常高。 + +在MatMul算子中,可学习参数的权重W被分成四部分,模型可以并行,由于参数数量较多,这部分的模型并行更有效。由于BatchNorm的输出布局与MatMul的输入布局不同,所以框架插入了一个张量重排布(该例中为AllGather和ConCat),这一过程对开发者是透明的。 + +开发者也不必关注哪个设备运行了模型的哪个部分,框架会自动安排。然而,不同的模型结构在每个算子中具有不同大小的参数,如下图三种广泛使用的子结构所示,并且它们使用于不同的切分策略。在下图 三种广泛使用的子结构 (3)中,将第一算子配置为模型并行,将后续算子配置为数据并行,也需要插入张量重排布,这样可以获得更好的性能。 + +在训练新模型时,多次配置shard,耗时耗力。在这种情况下,如果配置了自动并行,则不需要调用shard方法,该算法将找到一个有效的策略。例如,当ResNet中的分类数量超过130K时,算法返回的策略导致在50ms内训练一个迭代。相比之下,原始数据并行训练一次迭代超过111ms。 + +![ParallelDistributedComputing](images/07MSParallel02.png) + +### 函数式算子切分 + +动态图支持语法更丰富,使用更为灵活,但是目前昇思MindSpore的动态图模式不支持自动并行的各种特性。借鉴Jax的pmap的设计理念,昇思MindSpore设计了函数式算子切分功能,支持在动态图模式下,指定某一部分在图模式下以算子级并行的方式执行。 + +昇思MindSpore的动态图模式下,可以通过@jit的装饰符,指定某一段以图模式编译执行,在前向执行的同时,会将执行的算子、子图记录下来,前向执行完毕后,会对得到的整图进行自动微分得到反向图,具体流程如下图所示: + +![ParallelDistributedComputing](images/07MSParallel03.png) + +函数式算子切分沿用此模式,不同的是可以指定某一段在图模式的编译执行环节进行算子级模型并行。算子级并行是通过将网络模型中每个算子涉及到的张量进行切分,降低单个设备的内存消耗。 + +### 流水线并行 + +流水线(Pipeline)并行是将神经网络中的算子切分成多个阶段(Stage),再把阶段映射到不同的设备上,使得不同设备去计算神经网络的不同部分。流水线并行适用于模型是线性的图结构。能够降低模型训练过程中的通信量,极大的提升集群的训练性能。 + +![ParallelDistributedComputing](images/07MSParallel04.png) + +如图所示,将4层MatMul的网络切分成4个阶段,分布到4台设备上。正向计算时,每台机器在算完本台机器上的MatMul之后将结果通过通信算子发送(Send)给下一台机器,同时,下一台机器通过通信算子接收(Receive)上一台机器的MatMul结果,同时开始计算本台机器上的MatMul;反向计算时,最后一台机器的梯度算完之后,将结果发送给上一台机器,同时,上一台机器接收最后一台机器的梯度结果,并开始计算本台机器的反向。 + +简单地将模型切分到多设备上并不会带来性能的提升,因为模型的线性结构到时同一时刻只有一台设备在工作,而其它设备在等待,造成了资源的浪费。为了提升效率,流水线并行进一步将小批次(mini-batch)切分成更细粒度的微批次(micro-batch),在微批次中采用流水线式的执行序,从而达到提升效率的目的,如下图所示。将小批次切分成4个微批次,4个微批次在4个组上执行形成流水线。微批次的梯度汇聚后用来更新参数,其中每台设备只存有并更新对应组的参数。其中白色序号代表微批次的索引。 + +![ParallelDistributedComputing](images/07MSParallel05.png) + +昇思MindSpore支持流水线并行,并对执行序进行了调整,来达到更优的内存管理。如下图所示,在第0 MicroBatch的正向执行完后立即执行其反向,这样做使得第0 MicroBatch的中间结果的内存得以更早地(相较于上图)释放,进而确保内存使用的峰值比上图的方式更低。 + +![ParallelDistributedComputing](images/07MSParallel06.png) + +### MoE并行 + +混合专家(MoE)能够在引入较少的计算量同时扩充模型参数量,在模型中,每一个MoE层都包含多个独立的FFN,并且包含一个路由装置用于将每个输入数据分配到FFN。传统的数据并行和模型并行在处理MoE这种结构时,其存储和通信的效率都较为低下。一种高效的实现方式是,将Gate函数的计算并行化,同时将多个FFN分配到每台设备上(通常是均匀的分配),每台设备得到一个或多个FFN。每台设备的负责的参数量有效地下降了。 + +若训练数据经过Gate计算后路由到本台设备负责的FFN,那么其直接传递给本台设备的FFN。如果路由到其他设备的FFN,那么会经过AllToAll通信,将训练数据发送到目的设备;同样地,在经过FFN计算后,数据需再次经过AllToAll通信,把相应的结果路由回原设备。下图中展示了每个设备只有一个FFN的并行执行情况。 + +当每条训练数据仅会路由到较少FFN时,这种并行方式会非常有效,因为大大降低了内存使用,同时产生的通信量是较小的。 + +![ParallelDistributedComputing](images/07MSParallel07.png) + +### 异构并行训练 + +异构并行训练方法通过将占用内存较大的参数存储于Host内存,解决单卡上无法存储完整模型的问题。通过分析图上算子内存占用和计算密集度,将内存消耗巨大或适合CPU逻辑处理的算子切分到CPU子图,将内存消耗较小计算密集型算子切分到硬件加速器子图,框架协同不同子图进行网络训练,使得处于不同硬件且无依赖关系的子图能够并行进行执行的过程。目前昇思MindSpore最多可以支持单机8卡训练和推理千亿模型,极大的降低训练卡所需的资源。 + +![ParallelDistributedComputing](images/07MSParallel08.png) + +## 小结与思考 + +- 昇思MindSpore引入张量重排布(Tensor Redistribution)技术,自动解决设备间张量布局不一致问题,简化并行策略搜索,并支持混合并行、流水线并行等高级并行技术。 + +- 该框架通过自动微分技术,定义了通信算子的反向算子,如AllGather的反向算子ReduceScatter,实现通信算子的自动微分,从而简化并行训练过程。 + +- 昇思MindSpore支持算子级别并行和半自动并行配置,允许开发者通过高级策略配置实现数据并行和模型并行,同时自动插入必要的张量重排布操作,提高并行效率。 + +- 针对大模型训练,昇思MindSpore提供了如MoE并行、异构并行训练等解决方案,优化存储和通信效率,实现单机多卡训练千亿级参数模型的能力。 diff --git a/05Framework/04Parallel/images/07MSParallel01.png b/05Framework/04Parallel/images/07MSParallel01.png new file mode 100644 index 00000000..57e13f79 Binary files /dev/null and b/05Framework/04Parallel/images/07MSParallel01.png differ diff --git a/05Framework/04Parallel/images/07MSParallel02.png b/05Framework/04Parallel/images/07MSParallel02.png new file mode 100644 index 00000000..1c5aa56f Binary files /dev/null and b/05Framework/04Parallel/images/07MSParallel02.png differ diff --git a/05Framework/04Parallel/images/07MSParallel03.png b/05Framework/04Parallel/images/07MSParallel03.png new file mode 100644 index 00000000..c6f00468 Binary files /dev/null and b/05Framework/04Parallel/images/07MSParallel03.png differ diff --git a/05Framework/04Parallel/images/07MSParallel04.png b/05Framework/04Parallel/images/07MSParallel04.png new file mode 100644 index 00000000..d2125ec4 Binary files /dev/null and b/05Framework/04Parallel/images/07MSParallel04.png differ diff --git a/05Framework/04Parallel/images/07MSParallel05.png b/05Framework/04Parallel/images/07MSParallel05.png new file mode 100644 index 00000000..918557df Binary files /dev/null and b/05Framework/04Parallel/images/07MSParallel05.png differ diff --git a/05Framework/04Parallel/images/07MSParallel06.png b/05Framework/04Parallel/images/07MSParallel06.png new file mode 100644 index 00000000..4864de77 Binary files /dev/null and b/05Framework/04Parallel/images/07MSParallel06.png differ diff --git a/05Framework/04Parallel/images/07MSParallel07.png b/05Framework/04Parallel/images/07MSParallel07.png new file mode 100644 index 00000000..52d2e4c8 Binary files /dev/null and b/05Framework/04Parallel/images/07MSParallel07.png differ diff --git a/05Framework/04Parallel/images/07MSParallel08.png b/05Framework/04Parallel/images/07MSParallel08.png new file mode 100644 index 00000000..78b0680a Binary files /dev/null and b/05Framework/04Parallel/images/07MSParallel08.png differ