一、参考资料
比PyTorch、TensorFlow更快,MindSpore开源一周年升级巨量新特性 (baidu.com)
深度学习之MindSpore | Blog (youcongtech.com)
二、相关介绍
2.1 导包技巧
import mindspore.dataset as ds
import mindspore.dataset.transforms.c_transforms as C
import mindspore.dataset.vision.c_transforms as vision
import mindspore.dataset.vision.py_transforms as pvision
2.2 动态图与静态图
2.2.1 动态图
AI框架的动态图基本上是指类似PyTorch的实现(非torchscript),原理上比较简单,使用Python的c extension机制注册算子(算子一般性能比较高,采用native的语言开发),正向利用Python进行解释执行,同时通过Tape机制(自动微分)生成反向图,然后基于反向图进行梯度更新,反向执行其实也是图的一种模式,不过不会做图的编译优化。
2.2.2 静态图
与动态图相比,静态图在执行前有一个 构图和编译优化 的过程,即执行前先生成正反向图并完成编译优化,然后再执行。那如何从Python的神经网络表达翻译到图呢?目前主要有两种方式:
- Tracing模式:框架把Python代码假执行一遍,记住算子执行序列(Tensor相关操作),作为正向图,并以此进行自动微分生成反向图,并进行正反向图的编译优化,最后以图模式进行执行
- AST转换:框架获取Python代码的AST,然后通过编译的技术转换成正向图(这里面有Parser、Resolver、Specialize、Optimize等),并基于此生成反向图,同时再进行编译优化,最后以图模式进行执行。
tracing based
和 ast based
两种静态图模式在表达上/编译优化上也有少许差异,比如 tracing based
的方法,可以充分利用Python的执行完成推导功能(实现比较完整的Python复杂的数据结构和动态类型到Tensor的映射),问题是很难处理控制流并丢失了scope的信息;ast based
的方法原理上功能可以做的比较强大,但是在python语法的翻译需要比较全量的翻译,工程量比较大/方案比较复杂。
tracing based的静态图
这种方式拿到的图实际上是平铺的一个执行流,所以很难处理控制流的情况,比如循环,对于tracing来说就是展开,但是有些情况下循环无法展开,如循环条件根据训练的收敛情况/算子的执行结果等。
ast based的静态图
这种方式拿到的图是从python的ast转换而来,好处是控制流和scope信息都可以保留,但是挑战是那么多python的语法和数据结构都要转换到静态图的表达,更难的是python是动态类型的,所以这个ast到静态图的转换中需要一个复杂的类型/值推导过程。
2.2.3 动静态图优缺点
动态图:灵活易用,基本上Python的语法都支持,对于动态模型,比如动态shape、有复杂控制流等,尤其有利;当然它的缺点也比较明显,就是性能和部署,动态图的执行性能基本上取决于单算子的性能,缺乏算子间的融合优化,无法充分发挥AI芯片的算力(这个对性能快速提升的AI芯片来说不是个好事情),同时AI在部署的时候,为了性能和功耗(比如端侧部署),一般要需要生成一个部署模型,部署模型本质是静态图的表达,所以这里就存在一个动静态转换的问题,太灵活的动态图训练完后,想转换变成一个部署模型(静态图)同样存在很大的挑战。
静态图:优缺点和动态图刚好相反,表达上有许多限制,不灵活;但是性能好(适合面向芯片的编译优化、适合分布式并行优化),部署能力强。
2.2.4 动静图的发展阶段
动静图的发展分为三个阶段:动静态图分离——>动静图结合——>动静图统一。
2.3 配置环境变量
如果昇腾AI处理器配套软件包没有安装在默认路径,安装好MindSpore之后,需要导出Runtime相关环境变量,下述命令中LOCAL_ASCEND=/usr/local/Ascend
的/usr/local/Ascend
表示配套软件包的安装路径,需注意将其改为配套软件包的实际安装路径。
# control log level. 0-DEBUG, 1-INFO, 2-WARNING, 3-ERROR, 4-CRITICAL, default level is WARNING.
export GLOG_v=2
# Conda environmental options
LOCAL_ASCEND=/usr/local/Ascend # the root directory of run package
# lib libraries that the run package depends on
export LD_LIBRARY_PATH=${LOCAL_ASCEND}/ascend-toolkit/latest/fwkacllib/lib64:${LOCAL_ASCEND}/driver/lib64:${LOCAL_ASCEND}/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe/op_tiling:${LD_LIBRARY_PATH}
# Environment variables that must be configured
## TBE operator implementation tool path
export TBE_IMPL_PATH=${LOCAL_ASCEND}/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe
## OPP path
export ASCEND_OPP_PATH=${LOCAL_ASCEND}/ascend-toolkit/latest/opp
## AICPU path
export ASCEND_AICPU_PATH=${ASCEND_OPP_PATH}/..
## TBE operator compilation tool path
export PATH=${LOCAL_ASCEND}/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin/:${PATH}
## Python library that TBE implementation depends on
export PYTHONPATH=${TBE_IMPL_PATH}:${PYTHONPATH}
2.4 数据下沉
昇腾芯片上集成了AICORE、AICPU和CPU。其中,AICORE负责大型Tensor Vector运算,AICPU负责标量运算,CPU负责逻辑控制和任务分发。
Host侧CPU负责将图或算子下发到昇腾芯片。昇腾芯片由于具备了运算、逻辑控制和任务分发的功能,所以不需要与Host侧的CPU进行频繁的交互,只需要将计算完的最终结果返回给Host侧,实现 整图下沉到Device执行,避免Host-Device频繁交互,减小了开销。
Model
的train
接口参数dataset_sink_mode
可以控制数据是否下沉。dataset_sink_mode
为True表示数据下沉,否则为非下沉。所谓下沉即数据通过通道直接传送到Device上。当dataset_sink_mode
设置为False,Host侧和Device侧之间每个step
交互一次,所以会每个step
返回一个结果。当dataset_sink_mode
为True,因为数据在Device上通过通道传输, Host侧和Device侧之间每个epoch
进行一次数据交互,所以每个epoch
只返回一次结果。
三、分布式训练
3.1 问题引入
在深度学习中,当数据集和参数量的规模越来越大,训练所需的时间和硬件资源会随之增加,最后会变成制约训练的瓶颈。分布式并行训练,可以降低对内存、计算性能等硬件的需求,是进行训练的重要优化手段。MindSpore动态图模式支持数据并行,通过对数据按batch维度进行切分,将数据分配到各个计算单元中进行模型训练,从而缩短训练时间。
如何在大集群下高效训练千亿至万亿参数模型?当前主要面临两个挑战:
- 切分难:用户需要综合考虑参数量、计算量、计算类型、集群带宽拓扑和样本数量等,才能设计出性能较优的并行切分策略;
- 编码难:模型编码除了要考虑算法以外,还需要编写大量并行切分和通信代码。
3.2 业界主流的并行类型
根据并行的原理及模式不同,业界主流的并行类型有以下几种:
- 数据并行(Data Parallel):对数据进行切分的并行模式,一般按照batch维度切分,将数据分配到各个计算单元(worker)中,进行模型计算。
- 模型并行(Model Parallel):对模型进行切分的并行模式。MindSpore中支持层内模型并行模式,即对参数切分后分配到各个计算单元中进行训练。
- 混合并行(Hybrid Parallel):指涵盖数据并行和模型并行的并行模式。
3.3 MindSpore分布式并行训练模式
在MindSpore中,支持四种分布式并行训练模式,即自动并行模式(Auto Parallel)、数据并行模式(Data Parallel)、半自动并行模式(Semi Auto Parallel)、手动混合并行模式(Hybrid Parallel)。
- 自动并行模式(Auto Parallel):自动并行模式,融合了数据并行、模型并行及混合并行的1种分布式并行模式,可以自动建立代价模型,找到训练时间较短的并行策略,为用户选择1种并行模式。MindSpore提供了如下的两种不同的策略搜索算法:
- dynamic_programming :动态规划策略搜索算法。能够搜索出代价模型刻画的最优策略,但在搜索巨大网络模型的并行策略时耗时较长。其代价模型是围绕Ascend 910芯片基于内存的计算开销和通信开销对训练时间建模。
- recursive_programming :双递归策略搜索算法。对于巨大网络以及大规模多卡切分能够保证瞬间生成最优策略。其基于符号运算的代价模型可以自由适配不同的加速器集群。
- 数据并行模式(Data Parallel):对数据进行切分的并行模式,一般按照batch维度切分,将数据分配到各个计算单元(worker)中,进行模型计算。
- 半自动并行模式(Semi Auto Parallel):半自动并行模式,相较于自动并行,该模式需要用户对算子手动配置切分策略实现并行。
- 手动混合并行模式(Hybrid Parallel):在MindSpore中特指用户通过手动切分模型实现混合并行的场景。
3.4 MindSpore多维度自动并行
前提条件
多卡环境,即 device_num > 1
。
MindSpore采用 多维度自动并行,通过 数据并行、模型并行、Pipeline并行、异构并行、重复计算、高效内存复用及拓扑感知调度,降低通信开销,实现整体迭代时间最小(计算时间+通信时间)。
3.5 MindSpore/PyTorch/TensorFlow对比
基于ResNet50 v1.5+ImageNet数据集测试,在昇腾计算硬件平台,MindSpore动态图模式分布式的表现,可以达到PyTorch典型分布式场景的1.6倍, 静态图模式分布式的表现也可以达到TensorFlow典型分布式场景的2倍。
四、MindSpore for IoT
4.1 问题引入
相较于移动终端设备,IoT设备上系统资源有限,对ROM空间占用、运行时内存和功耗要求较高,为了使得IoT设备上也能方便快速的部署AI应用,MindSpore Lite开源了 代码自动生成工具Codegen,旨在将模型编译为极简的代码,用于推理。
4.2 代码自动生成工具Codegen
Codegen可对接MindSpore Lite的NNACL算子库和ARM的CMSIS算子库,支持生成可在X86/ARM64/ARM32A/ARM32M平台部署的推理代码。
易上手:用户输入ms模型文件,并指定推理执行硬件平台,即可生成与该模型执行相关的代码、编译构建脚本。
极致优化:无图引擎,模型即代码,极小ROM占用完成推理。算子数据重排、内存分配移至离线完成,节省了初始化时间;同时引入Conv & BN & Pooling融合,Conv分块计算等技术,达到极致性能。华为内部应用有广泛应用,比如在Huawei Watch GT系列的智慧抬腕亮屏算法中,推理内存占用仅1KB,时延低至5ms。
五、MindInsight
MindSpore在MindInsight部件中集成了的可解释AI能力:显著图可视化、反事实解释和可解释AI评估体系(度量体系),旨在帮忙开发者更好进行模型调优。
5.1 显著图可视化和反事实解释
能够为图片分类模型的推理结果,标识影响分类结果的关键特征,方便理解分类依据,帮助分析定位分类错误原因,加速模型调优。
如上图所示,有个错误预测标签“person”,根据显著图可视化结果,高亮区域在摩托车的前部,便于针对性的分析误判的可能原因。
如上图所示,图片被错分为“cat”,使用基于层级遮掩的反事实解释,发现对这个分类结果影响最可能的区域是右边遮掩后留下的区域,便于用户发现判断错误的缘由,从而帮助调优。
5.2 评估体系
面向各种解释方法,给出在具体场景下,选中解释方法在不同度量方法下的解释效果得分,助力用户选择最优的解释方法,从而更好的帮助模型调优。
六、MindConverter
mindspore(二)-yolov5的训练、改进及MindConverter的使用
七、MindSpore算子
深度学习算法由一个个计算单元组成,我们称这些计算单元为算子(Operator,简称Op)。Operator算子,操作运算,比如AI的ReLU、Conv、Pooling、Scale、Softmax等。
7.1 查询算子
7.2 算子分类
MindSpore算子主要分为Primitivie算子和nn算子。思维导图,请参考:MindSpore算子分类.xmind
简单理解
- Primitive算子可以认为是一些基础调料,你可以根据自己的口味按需组合出让自己满意的味道。
- nn算子则是满足大众口味调好的蘸料,你自己不用费脑筋调味,直接用就完了。
即nn算子是由Primitive组成的,提供特定功能的api,但如果你觉得这个api不能满足你的要求,你可以自己用Primitive算子来组合实现,例如:你吃火锅非得用芥辣+花椒做蘸料才爽快,估计你是找不到有这种成品蘸料了,就需要你自己来配置这种蘸料。所以选择哪种API,还是要从你的需求出发。
Primitive算子(低阶算子)
Primitive算子是 低阶算子,是开放给用户的最低阶算子接口,一个Primitive算子对应一个原语,它封装了底层的Ascend、GPU、AICPU、CPU等多种算子的具体实现,为用户提供基础算子能力。
Primitive算子接口是构建高阶接口、自动微分、网络模型等能力的基础。
Primitive算子可以分为计算算子和框架算子。计算算子主要负责具体的计算,而框架算子主要用于构图,自动微分等功能。
nn算子(高阶算子)
nn算子是 高阶算子,是对低阶API的封装,主要包括卷积层算子、池化层算子、损失函数、优化器等。还提供了部分与Primitive算子同名的接口,主要作用是对Primitive算子进行进一步封装,为用户提供更友好的API。当nn算子功能满足用户的要求时可以直接使用nn算子,而当nn算子功能无法满足用户特定要求时可以使用低阶的Primitive算子实现特定的功能。
7.3 自定义算子
问题引入
在模型转换过程中出现算子不支持的情况,例如昇腾AI软件栈不支持模型中的算子、开发者想修改现有算子中的计算逻辑、或者开发者想自己开发算子来提高计算性能,这时就需要进行自定义算子的开发。
DSL与TIK开发
TBE支持两种算子开发方式:特定域语言开发(DSL开发)和TVM原语开发(TIK开发)。DSL开发相对简单,适用于入门级的开发者。TBE工具提供自动优化机制,给出较优的调度流程,开发者仅需要了解神经网络和TBE DSL相关知识,便可指定目标生成代码,进一步被编译成专用内核。TIK开发难度较高,适用于对于TVM编程及达芬奇结构都非常了解的开发者使用。这种方式的接口偏底层,需开发者自己控制数据流及算子的硬件调度。
八、常用API
mindspore.nn.Cell
mindspore.nn.Cell
与 PyTorch的 torch.nn.Module
是一样的,用来定义神经网络的API。一个神经网络,由一个或者多个Cell组成,用户自定义的网络需要继承Cell类。
简单理解,MindSpore想象成一个3D打印机,Cell就是模型设计软件,通过在Cell中完成模型设计,MindSpore就可以根据设计生产出需要的模型。
mindspore.ops.functional
functional算子是经过初始化后的Primitive,可以直接作为函数使用。functional接口是为简化不带属性的Primitive算子调用流程而提供的,functional接口、composite接口和Primitive算子都可以从mindspore.ops中导入。
例如用户想使用pow功能,若使用Primitive算子,用户需要先实例化Pow算子,此时用户可以直接使用functional接口的tensor_pow来简化流程,代码示例如下:
import numpy as np
import mindspore
from mindspore import Tensor
import mindspore.ops as ops
input_x = mindspore.Tensor(np.array([1.0, 2.0, 4.0]), mindspore.float32)
input_y = 3.0
# 使用Primitive算子需先实例化
pow = ops.Pow()
output = pow(input_x, input_y)
# 直接使用functional接口
output = ops.tensor_pow(input_x, input_y)
print(output)
# 输出
[ 1. 8. 64.]