乐趣区

关于python:技术解读倚天-ECS-实例-Arm-芯片的-PythonAI-算力优化

深度学习技术在图像识别、搜寻举荐等畛域失去了广泛应用。近年来各大 CPU 厂商也逐步把 AI 算力纳入了重点倒退方向,通过《Arm 芯片 Python-AI 算力优化》咱们将看到龙蜥社区 Arm 架构 SIG(Special Interest Group)利用最新的 Arm 指令集优化 Python-AI 推理 workload 的性能。

倚天 ECS 实例的 AI 推理软件优化

阿里云推出的倚天 Arm ECS 实例,领有针对 AI 场景的推理减速能力,咱们将理解减速的原理以及以及相干的软件生态适配。

卷积神经网络 (CNN) 在图像和语音畛域应用宽泛,神经网络算法相比传统的算法耗费了更多算力。为了摸索对计算的优化,咱们进一步看到 AlexNet 模型 (一种 CNN) 的推理过程的各个层的计算资源耗费占比。

能够看到名为 conv[1-5]的 5 个卷积层耗费了 90% 的计算资源,因而优化 CNN 推理的要害就是优化卷积层的计算。

咱们进一步来看如何对图像利用卷积核:

1. 应用 im2col 依据卷积核尺寸,将图像转化为若干块(patch)
2. 将多个卷积核开展成若干向量
3. 对由图像块组成的矩阵和由多个卷积核开展组成的矩阵利用矩阵乘法

下面一页的计算利用了矩阵乘法操作,为什么咱们不采纳更加间接的迭代计算形式,而是采纳须要额定内存的矩阵乘法呢?这里有两个关键因素:

  • 深度学习的卷积计算量很大,典型计算须要波及 5000 万次乘法和加法操作,因而对计算的优化非常重要
  • 计算机科学家们曾经深刻摸索了矩阵乘法操作,矩阵乘法操作能够被优化得十分快。

在 fortran 世界中,GEMM(general matrix multiplication)曾经成为一个通用操作: 该操作通过对数据重新排列,精心设计计算过程,利用多线程和向量指令,能够比本人实现的奢侈版本快十倍以上。因而应用矩阵运算带来的收益相比额定的开销是值得的。

因为 AI 推理大量应用了矩阵乘法,现在也有许多硬件对矩阵运算进行了减速:

  • NVIDIA Volta 架构引入了 tensor core,能够高效地以混合精度解决矩阵乘
  • Intel AMX(Advanced Matrix Extensions) 通过脉动阵列在硬件层面反对矩阵乘
  • ARM SME(Scalable Matrix Extension) 反对向量外积运算,减速矩阵乘

尽管在 AI 算力上 GPU 要远高于 CPU,然而 CPU 因为其部署不便,且无需在主机 - 设施间拷贝内存,在 AI 推理场景占有一席之地。目前市面上尚没有能够大规模应用的反对 AMX 或者 SME 的硬件,在这个阶段咱们应该如何优化 CPU 上的 AI 推理算力呢?咱们首先要理解 BF16 数据类型。

BF16(Brain Float 16)是由 Google Brain 开发设计的 16 位浮点数格局。相比传统的 IEEE16 位浮点数,BF16 领有和 IEEE 单精度浮点数 (FP32) 一样的取值范畴,然而精度较差。钻研人员发现,在 AI 训练和推理中,应用 BF16 能够节约一半的内存,取得和单精度浮点数靠近的准确率。

依据右图,BF16 指数的位数和 FP32 是统一的,因而 BF16 和 FP32 的互相转换只有截断尾数即可,左下角图上便是 tensorflow 源码中的转换实现。

引入 BF16 的一大价值是现在的很多硬件计算的瓶颈在寄存器宽度或者拜访内存的速度上,更紧凑的内存示意往往能够取得更高的计算吞吐,在现实状况下,BF16 相比 FP32 能够进步一倍的吞吐(FLOPS)。

现在咱们尽管无奈大规模应用到反对 AMX/SME 的硬件,然而 Armv8.6- A 提供了 bf16 扩大,该扩大利用了无限的 128bit 向量寄存器,通过 BFMMLA 指令执行矩阵乘法运算:

  • 输出 A: 大小为 2 * 4 的 BF16 矩阵,按行存储
  • 输出 B: 大小为 4 * 2 的 BF16 矩阵,按列存储
  • 输入 C: 大小为 2 * 2 的 FP32 矩阵该指令

单次执行进行了 16 次浮点数乘法和 16 次浮点数加法运算,计算吞吐十分高。

阿里巴巴向 OpenBLAS 我的项目奉献了 sbgemm(s 示意返回单精度,b 示意输出 bf16)的硬件加速实现,从 GEMM 吞吐上看,BF16 相比 FP32 GEMM 吞吐晋升超过 100%。

倚天 ECS 实例是市面上多数能够反对 bf16 指令扩大的 ARM 服务器。目前曾经反对了 Tensorflow 和 Pytorch 两种框架的 AI 推理

  • Tensorflow 下能够通过 OneDNN + ACL(Arm Compute Library)来应用 BFMMLA 加
  • Pytorch 曾经反对了 OneDNN + ACL,然而目前还在试验状态,无奈很好地施展性能。然而 Pytorch 同时反对 OpenBLAS 作为其计算后端,因而能够通过 OpenBLAS 来享受 ARM bf16 扩大带来的性能收益

能够看到相比默认的 eigen 实现,开启 OneDNN + ACL 后,perf 取得的计算热点曾经从 fmla(向量乘加)转换到了 bfmmla,算力显著晋升。

从 workload 角度评测,上图比照了两种机型:

  • g7:Intel IceLake 实例
  • g8m:倚天 ARM 服务器

右边柱状图中蓝色柱子示意算力比照,橙色柱子示意思考性价比后应用倚天处理器取得的收益。能够看到在 Resnet50 和 BERT-Large 模型的推理场景下,软件优化后的倚天处理器皆可取得一倍左右的性价比收益。

在上文中,咱们看到应用倚天处理器若想取得较高收益,软件版本的抉择非常重要。随便抉择 tensorflow 或者 pytorch 包可能遭逢:

  • 未适配 arm 架构,装置失败
  • 软件未适配 bf16 扩大或者环境参数有误,无奈施展硬件的全副算力,性能打折
  • 须要精心抉择计算后端,例如目前 pytorch 下 OpenBLAS 较快

因而咱们提供了 Docker 镜像,帮忙云上的用户充沛应用倚天 ECS 实例的 AI 推理性能:

  • accc-registry.cn-hangzhou.cr.aliyuncs.com/tensorflow/tensorflow
  • accc-registry.cn-hangzhou.cr.aliyuncs.com/pytorch/pytorch

通过 Serverless 能力充沛开释

算力除了使能更多的硬件指令,另一种充沛开释硬件算力的形式就是通过 Serverless 架构进步 CPU 利用率。Python 作为动静语言,其模块是动静导入的,因而启动速度不是 Python 的强项,这也制约了 Python workload 在 Serverless 场景的遍及。

Python 利用启动的次要耗时在模块导入,Python 模块导入步骤为:

  1. 寻找到模块所在的文件
  2. 取得代码对象 code_object
  3. 执行代码对象

其中的第二步在首次加载模块时,要对.py 文件进行编译,取得 code_object, 为了升高未来加载的开销,Python 解释器会序列化并缓存 code_object 到.pyc 文件。

即使模块导入过程曾经通过缓存机制优化过了,然而读取.pyc 文件并反序列化仍旧比拟耗时。

在这里咱们借助了 OpenJDK 的 AppCDS 的思路:将 heap 上的 code_object 复制到内存映射文件中(mmap)。在下次加载模块时,间接应用 mmap 中的 code_object。

这种框架下有两个难点:

  • Python 的 code_object 是散落在 heap 的各处且不间断的,因而 mmap 复制整个 heap 是行不通的。咱们采纳的形式是以 code_object 为根,遍历对象图,对感兴趣的内容复制并紧凑排布
  • Python 的 code_object 会援用.data 段的变量,在 Linux 的随机地址平安机制下,.data 段的数据的地址在每次运行时都会随机变动,这样 mmap 中的指针就生效了。咱们的解决形式是遍历所有对象,针对.data 段的指针进行偏移量修复

因为该我的项目共享了 python 的 code_object,因而名字是 code-data-share-for-python,简称 pycds。

咱们测试了 bota3、numpy、flask 等罕用的 python 苦,均匀能够节俭 20% 的模块导入耗时。

对于现有的 python 利用能够轻易地应用 pycds,且无需批改任何代码:

# 装置 pycds
pip install code-data-share # 装置 pycds
 # 生成模块列表
PYCDSMODE=TRACE PYCDSLIST=mod.lst python -c 'import numpy’# 生成 archive
python -c 'import cds.dump; cds.dump.run_dump("mod.lst","mod.img")’# 应用 archive
time PYCDSMODE=SHARE PYCDSARCHIVE=mod.img python -c 'import numpy'
real 0m0.090s
user 0m0.180s
sys 0m0.339s
# 比照基线
time python -c 'import numpy'
real 0m0.105s
user 0m0.216s
sys 0m0.476s

咱们仅仅通过装置 PyPI,批改环境变量运行和应用 cdsAPI 做 dump 即可对现有的利用启动进行减速了。

code-data-share-for-python 是一个新我的项目,须要大家的参加和反馈,欢送通过以下链接理解和应用:

  • https://github.com/alibaba/code-data-share-for-python
  • https://pypi.org/project/code-data-share-for-python

ARM 架构 SIG 链接地址:https://openanolis.cn/sig/ARM_ARCH_SIG

原文链接

本文为阿里云原创内容,未经容许不得转载。

退出移动版