Ascend CANN及Pytorch使用说明(基于Atlas

2022-12-14  本文已影响0人  Mr_Michael

一、简介

1.华为昇腾AI全栈简介

2022-12-14 10-22-43 的屏幕截图.png

2.CANN简介

CANN(Compute Architecture for Neural Networks)是华为公司针对AI场景推出的异构计算架构,通过提供多层次的编程接口,支持用户快速构建基于昇腾平台的AI应用和业务。

1)CANN开发及运行环境

推理方式

2)CANN 开发辅助工具

CANN 5.0.3 开发辅助工具指南 01

3.MindSpore

MindSpore具有编程简单、端云协同、调试轻松、性能卓越、开源开放等特点,降低了AI开发门槛。

二、快速部署

快速部署(22.0.RC2版本-对应CANN 5.1.RC2 )

基于Atlas 500 Pro 智能边缘服务器(3000)的KylinV10SP1或 OpenEuler 20.03进行部署。

1.不同产品形态的部署架构

昇腾AI设备可分为EP和RC两种模式。

1)Ascend EP模式

昇腾 AI 处理器的PCIe工作在从模式,则称为EP模式。

支持EP模式的产品:

2)Ascend RC模式

昇腾 AI 处理器的PCIe工作在主模式,可以扩展外设,则称为RC模式。

支持RC模式的产品有:Atlas 200 AI加速模块、Atlas 200 DK 开发者套件。

2.安装前准备

1)CANN社区版支持的OS清单

OS清单

产品型号 支持的操作系统
A500 Pro-3000+A300I-3000 Ubuntu 18.04.1、Ubuntu 16.04.5、EulerOS 2.8、EulerOS2.9、OpenEuler 20.03、CentOS 7.6、CentOS 8.2、Linx 6.0、KylinV10SP1、UOS20 SP1

OS安装指南

2)需要准备的软件包

软件类型 软件介绍
npu-firmware 固件包含昇腾AI处理器自带的OS 、电源器件和功耗管理器件控制软件,分别用于后续加载到AI处理器的模型计算、芯片启动控制和功耗控制。
npu-driver 部署在昇腾服务器,功能类似英伟达驱动,管理查询昇腾AI处理器,同时为上层CANN软件提供芯片控制、资源分配等接口。
CANN 部署在昇腾服务器,功能类似英伟达CUDA,包含Runtime、算子库、图引擎、媒体数据处理等组件,通过AscendCL(Ascend Computing Language,昇腾计算语言)对外提供Device管理、Context管理、Stream管理、内存管理、模型加载与执行、算子加载与执行、媒体数据处理等API,帮助开发者实现在昇腾软硬件平台上开发和运行AI业务。CANN软件按照功能主要分为Toolkit(开发套件)、NNAE(深度学习引擎)、NNRT(离线推理引擎)、TFPlugin(TensorFlow框架插件)几种软件包,各软件包支持功能范围如下:Toolkit:支持训练和推理业务、模型转换、算子/应用/模型开发和编译。NNAE:支持训练和推理业务、模型转换。NNRT:仅支持推理业务。TFPlugin:用于运行训练业务时和TensorFlow框架进行对接,帮助TensorFlow框架调用底层CANN接口运行训练业务。
ToolBox ToolBox包含运维检查工具(Acsend DMI工具)和容器引擎插件(Ascend Docker),运维检查工具能够检测设备状态(如带宽、设备实时状态等);容器引擎插件本质上是基于OCI标准实现的Docker Runtime,不修改Docker引擎,对Docker以插件方式提供Ascend NPU适配功能,使用户AI作业能够以Docker容器的方式平滑运行在昇腾设备上。

3)下载软件

3.安装固件、驱动及软件包

首次安装按照“驱动 > 固件”的顺序;覆盖安装或升级按照“固件 > 驱动”顺序。

1)确认基础信息

$ tree Ascned_22.0.RC2/
.
├── Atlas300I_3000_Firmware_Driver
│   ├── A300-3000-npu-driver_5.1.rc2_linux-aarch64.run
│   └── A300-3000-npu-firmware_5.1.rc2.run
├── CANN5.1.RC2
│   ├── Ascend-cann-amct_5.1.RC2_linux-aarch64.tar.gz
│   ├── Ascend-cann-device-sdk_5.1.RC2_linux-aarch64.zip
│   ├── Ascend-cann-nnae_5.1.RC2_linux-aarch64.deb
│   ├── Ascend-cann-nnae_5.1.RC2_linux-aarch64.run
│   ├── Ascend-cann-nnrt_5.1.RC2_linux-aarch64.deb
│   ├── Ascend-cann-nnrt_5.1.RC2_linux-aarch64.run
│   ├── Ascend-cann-toolkit_5.1.RC2_linux-aarch64.deb
│   └── Ascend-cann-toolkit_5.1.RC2_linux-aarch64.run
└── ToolBox
    └── Ascend-mindx-toolbox_3.0.RC3_linux-aarch64.run

# 检测Atlas 300I 推理卡(型号:3000)是否正常在位
$ lspci | grep d100
06:00.0 Processing accelerators: Huawei Technologies Co., Ltd. Device d100 (rev 20)
07:00.0 Processing accelerators: Huawei Technologies Co., Ltd. Device d100 (rev 20)
08:00.0 Processing accelerators: Huawei Technologies Co., Ltd. Device d100 (rev 20)
09:00.0 Processing accelerators: Huawei Technologies Co., Ltd. Device d100 (rev 20)

# 确认操作系统和内核版本
$ uname -m && cat /etc/*release
aarch64
Kylin Linux Advanced Server release V10 (Tercel)
DISTRIB_ID=Kylin
DISTRIB_RELEASE=V10
DISTRIB_CODENAME=juniper
DISTRIB_DESCRIPTION="Kylin V10"
DISTRIB_KYLIN_RELEASE=V10
DISTRIB_VERSION_TYPE=enterprise
DISTRIB_VERSION_MODE=normal
NAME="Kylin Linux Advanced Server"
VERSION="V10 (Tercel)"
ID="kylin"
VERSION_ID="V10"
PRETTY_NAME="Kylin Linux Advanced Server V10 (Tercel)"
ANSI_COLOR="0;31"

$ uname -r
4.19.90-23.8.v2101.ky10.aarch64

2)创建运行用户HwHiAiUser

# 安装驱动前需要创建驱动运行用户(运行驱动进程的用户)
groupadd HwHiAiUser
useradd -g HwHiAiUser -d /home/HwHiAiUser -m HwHiAiUser -s /bin/bash
# 设置HwHiAiUser用户密码
passwd HwHiAiUser

3)安装驱动及固件

$ cd Atlas300I_3000_Firmware_Driver
$ chmod +x *.run

# 安装驱动
$ ./A300-3000-npu-driver_5.1.rc2_linux-aarch64.run  --full --install-for-all

# 查看驱动加载是否成功
$ npu-smi info
+------------------------------------------------------------------------------------------------+
| npu-smi 22.0.2                           Version: 22.0.2                                       |
+-----------------------+-----------------+------------------------------------------------------+
| NPU     Name          | Health          | Power(W)     Temp(C)           Hugepages-Usage(page) |
| Chip    Device        | Bus-Id          | AICore(%)    Memory-Usage(MB)                        |
+=======================+=================+======================================================+
| 2       310           | OK              | 12.8         49                0    / 970            |
| 0       0             | 0000:06:00.0    | 0            633  / 7764                             |
+-----------------------+-----------------+------------------------------------------------------+
| 2       310           | OK              | 12.8         49                0    / 970            |
| 1       1             | 0000:07:00.0    | 0            634  / 7764                             |
+-----------------------+-----------------+------------------------------------------------------+
| 2       310           | OK              | 12.8         52                0    / 970            |
| 2       2             | 0000:08:00.0    | 0            634  / 7764                             |
+-----------------------+-----------------+------------------------------------------------------+
| 2       310           | OK              | 12.8         48                0    / 970            |
| 3       3             | 0000:09:00.0    | 0            634  / 7764                             |
+=======================+=================+======================================================+

$ /usr/local/Ascend/driver/tools/upgrade-tool --device_index -1 --component -1 --version
{
Get component version(1.82.22.2.220) succeed for deviceId(0), componentType(0).
    {"device_id":0, "component":nve, "version":1.82.22.2.220}
 ...
}

$ ./A300-3000-npu-firmware_5.1.rc2.run --full

# 查看芯片信息
$ ascend-dmi -i -dt
================================Product Details===============================
ascend-dmi                               : 3.0.RC3

Card Quantity                            : 1
    Type                                 : Atlas 300I-3000
    Card Manufacturer                    : Huawei
    Card Serial Number                   : 033EFS10M8001498
... 

$ reboot

4.安装软件包

基于Kylin V10 SP1

1)物理机部署

# 1.检查root用户的umask值是否为0022
umask
    # 否则 umask 0022

# 2.安装依赖
yum install -y gcc gcc-c++ make cmake unzip zlib-devel libffi-devel openssl-devel pciutils net-tools sqlite-devel lapack-devel openblas-devel gcc-gfortran

# 检测是否已安装python 3.7.x
python3 --version
yum install -y python3-pip
pip3 install attrs cython numpy decorator sympy cffi pyyaml pathlib2 psutil protobuf scipy requests absl-py

# 安装Toolkit
cd CRNN_Package
chmod +x *.run
./Ascend-cann-toolkit_6.0.0.alpha002_linux-aarch64.run --install

# 配置环境变量
vi ~/.bashrc
    # 在文件最后一行后面添加
    source /usr/local/Ascend/ascend-toolkit/set_env.sh 
source ~/.bashrc

2)容器部署【推荐】

# 安装Docker
$ yum install docker
$ docker --version
Docker version 18.09.0, build 62eb848

# 安装toolbox
$ cd ToolBox
$ chmod +x *.run
$ ./Ascend-mindx-toolbox_3.0.RC3_linux-aarch64.run --install

# 配置环境变量
$ vi ~/.bashrc
    # 在文件最后一行后面添加
    source /usr/local/Ascend/toolbox/set_env.sh
$ source ~/.bashrc

AscendHub拉取容器镜像

docker login -u xxx -p xxx ascendhub.huawei.com

# infer-modelzoo 
docker pull ascendhub.huawei.com/public-ascendhub/infer-modelzoo:22.0.RC2

# ascend-infer
docker pull ascendhub.huawei.com/public-ascendhub/ascend-infer:22.0.RC2-centos7.6

# pytorch-modelzoo
docker pull ascendhub.huawei.com/public-ascendhub/pytorch-modelzoo:22.0.RC2     # pytorch1.5.0+ascend.post6
docker pull ascendhub.huawei.com/public-ascendhub/pytorch-modelzoo:22.0.RC2-1.8.1 # pytorch1.8.1

启动离线推理容器

#/bin/bash
export MY_CONTAINER="infer-modelzoo"
num=`sudo docker ps -a|grep -w "$MY_CONTAINER"|wc -l`
echo $num
echo $MY_CONTAINER
if [ 0 -eq $num ];then
    docker run -it -u root \
        --device=/dev/davinci0 \        # 默认挂载加速卡0到容器中
        --device=/dev/davinci_manager \
        --device=/dev/devmm_svm \
        --device=/dev/hisi_hdc \
        -itd \
        --name $MY_CONTAINER \
        -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
        -v $PWD:/home/share \
        ascendhub.huawei.com/public-ascendhub/infer-modelzoo:22.0.RC2 \
        /bin/bash
else
    #docker start $MY_CONTAINER
    docker exec -ti $MY_CONTAINER /bin/bash
fi

启动训练+在线推理容器

#/bin/bash
export MY_CONTAINER="pytorch-modelzoo"
num=`sudo docker ps -a|grep -w "$MY_CONTAINER"|wc -l`
echo $num
echo $MY_CONTAINER
if [ 0 -eq $num ];then
    docker run -it -u root \
        --device=/dev/davinci0 \        # 默认挂载加速卡0到容器中
        --device=/dev/davinci_manager \
        --device=/dev/devmm_svm \
        --device=/dev/hisi_hdc \
        -itd \
        --name $MY_CONTAINER \
        -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
        -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \
        -v /var/log/npu/conf/slog/slog.conf:/var/log/npu/conf/slog/slog.conf \
        -v /var/log/npu/slog/:/var/log/npu/slog \
        -v /var/log/npu/profiling/:/var/log/npu/profiling \
        -v /var/log/npu/dump/:/var/log/npu/dump \
        -v /var/log/npu/:/usr/slog \
        -v $PWD:/home/share \
        ascendhub.huawei.com/public-ascendhub/pytorch-modelzoo:22.0.RC2-1.8.1  \
        /bin/bash
else
    #docker start $MY_CONTAINER
    docker exec -ti $MY_CONTAINER /bin/bash
fi

注意:只能同时运行一个容器,后启动的容器无法使用设备资源。

5.模型推理测试

infer-modelzoo容器环境中测试

1)Ascend CANN Samples

CANN样例仓库以CANN AscendCL接口进行开发,制作的一系列给开发者进行参考学习的样例。

git clone https://gitee.com/ascend/samples.git

# 测试图像分类样例
cd samples/python/level2_simple_inference/1_classification/resnet50_imagenet_classification

# 准备源模型
mkdir model && cd model
wget https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/003_Atc_Models/AE/ATC%20Model/resnet50/resnet50.caffemodel
wget https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/003_Atc_Models/AE/ATC%20Model/resnet50/resnet50.prototxt

# 准备测试图片
cd ../data
wget https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/models/aclsample/dog1_1024_683.jpg
wget https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/models/aclsample/dog2_1024_683.jpg

# 源模型转om模型
cd ../
atc --model=model/resnet50.prototxt --weight=model/resnet50.caffemodel --framework=0 --output=model/resnet50 --soc_version=Ascend310 --input_format=NCHW --input_fp16_nodes=data --output_type=FP32 --out_nodes=prob:0

# 模型推理
$ python3 src/acl_net.py
Using device id:0
model path:/home/share/samples/python/level2_simple_inference/1_classification/resnet50_imagenet_classification/src/../model/resnet50.om
images path:/home/share/samples/python/level2_simple_inference/1_classification/resnet50_imagenet_classification/src/../data
init resource stage:
model_id:1
init resource success
images:/home/share/samples/python/level2_simple_inference/1_classification/resnet50_imagenet_classification/src/../data/dog2_1024_683.jpg
data interaction from host to device
data interaction from host to device success
execute stage:
execute stage success
data interaction from device to host
data interaction from device to host success
======== top5 inference results: =============
[267]: 0.935547
[266]: 0.041107
[265]: 0.018967
[219]: 0.002865
[160]: 0.000311
images:/home/share/samples/python/level2_simple_inference/1_classification/resnet50_imagenet_classification/src/../data/dog1_1024_683.jpg
data interaction from host to device
data interaction from host to device success
execute stage:
execute stage success
data interaction from device to host
data interaction from device to host success
======== top5 inference results: =============
[161]: 0.763672
[162]: 0.157593
[167]: 0.039215
[163]: 0.021835
[166]: 0.011871
*****run finish******
Releasing resources stage:
Resources released successfully.

2)MindX SDK

MindX SDK快速入门

包含如下sample:

基于 infer-modelzoo容器测试mxManufacture:

# infer-modelzoo容器中
cd /home/hwMindX/sdk_home/mxManufacture && ls
bin  config  filelist.txt  include  lib  opensource  operators  python  samples  set_env.sh  toolkit  version.info

# 使MindX SDK mxManufacture环境变量生效
bash set_env.sh

使用mxManufacture开发一个简单的图片分类的Demo

6.Ascend实用工具

1)Ascend Tools

昇腾工具仓库

2) Ascend CANN Parser

Ascend CANN Parser(简称parser)配合TF_Adapter、 ATC工具、IR构图等使用,开发者通过以上工具,借助parser能方便地将第三方框架的算法表示转换成Ascend IR。

3)Ascend ModelZoo

模型库包含pytorch与tensorflow的一系列模型及脚本。

也可以通过官网搜索模型。

三、Ascend PyTorch 在线推理

在线推理是在AI框架内执行推理的场景,相比于离线推理场景,使用在线推理可以方便将原来基于PyTorch框架做推理的应用快速迁移到昇腾AI处理器,适用于数据中心推理场景。

1.环境准备

2.运行Ascend Pytorch在线推理样例

1)环境准备

基于pytorch-modelzoo容器运行

# 初始化nnae环境变量
source /usr/local/Ascend/nnae/set_env.sh

# 可选配置
    # 指定芯片的逻辑ID
    export ASCEND_DEVICE_ID=0
    # 输出日志信息,可根据实际修改
    export ASCEND_SLOG_PRINT_TO_STDOUT=1
    # Task多线程下发
    export ASCEND_GLOBAL_LOG_LEVEL=0

2)样例准备

以ResNet50模型为例,执行在线推理样例。

四、PyTorch模型迁移与转换

1.模型迁移

1)模型算子评估

2)迁移方式

将基于PyTorch的训练脚本迁移到昇腾AI处理器上进行训练,目前有以下3种方式:

2.AMCT模型压缩【可选】

昇腾模型压缩工具(Ascend Model Compression Toolkit,简称AMCT)是通过模型压缩技术(如融合,量化,张量分解等)将模型进行压缩的工具包,压缩后模型体积变小,部署到昇腾 AI 处理器件上后可使能低比特运算,提高计算效率。

AMCT基本功能使用样例

3.导出ONNX模型

模型训练完成后,保存的.pth或.pt文件可以通过PyTorch构建模型再加载权重的方法恢复,然后导出ONNX模型。

import torch
import torch_npu
import torch.onnx
import torchvision.models as models
# 设置使用CPU导出模型
device = torch.device("cpu") 

def convert():
    # 模型定义来自于torchvision,样例生成的模型文件是基于resnet50模型
    model = models.resnet50(pretrained = False)  
    resnet50_model = torch.load('resnet50.pth', map_location='cpu')
    model.load_state_dict(resnet50_model) 

    batch_size = 1  #批处理大小
    input_shape = (3, 224, 224)   #输入数据,改成自己的输入shape

    # 模型设置为推理模式
    model.eval()

    dummy_input = torch.randn(batch_size, *input_shape) #  定义输入shape
    torch.onnx.export(model, 
                      dummy_input, 
                      "resnet50_official.onnx", 
                      input_names = ["input"],   # 构造输入名
                      output_names = ["output"],    # 构造输出名
                      opset_version=11,    # ATC工具目前支持opset_version=9,10,11,12,13
                      dynamic_axes={"input":{0:"batch_size"}, "output":{0:"batch_size"}})  #支持输出动态轴
                      ) 

if __name__ == "__main__":
    convert()

4.离线模型转换

昇腾张量编译器(Ascend Tensor Compiler,简称ATC)是异构计算架构CANN体系下的模型转换工具, 它可以将开源框架的网络模型或Ascend IR定义的单算子描述文件(json格式)转换为昇腾AI处理器支持的.om格式离线模型。

image

1)不同网络模型的转换示例

2)基础功能参数配置

3)AIPP功能配置

# 通过--insert_op_conf参数,插入aipp预处理算子
atc --model=$HOME/module/resnet50.prototxt --weight=$HOME/module/resnet50.caffemodel --framework=0 --insert_op_conf=$HOME/module/insert_op.cfg  --output=$HOME/module/out/caffe_resnet50 --soc_version=<soc_version>

insert_op.cfg:aipp配置文件使用说明

aipp_op {
       aipp_mode : static             #AIPP配置模式
       related_input_rank : 0       # 标识对第1个输入进行AIPP处理【可选】
       related_input_name : "data"  # 标识对输入名称为data的节点进行AIPP处理【可选】
       input_format : YUV420SP_U8     #输入给AIPP的原始图片格式
       src_image_size_w : 250         #输入给AIPP的原始图片宽高
       src_image_size_h : 250
       crop: true                     #抠图开关,用于改变图片尺寸
       load_start_pos_h: 0            #抠图起始位置水平、垂直方向坐标
       load_start_pos_w: 0
       csc_switch : true              #色域转换开关【可选】
       rbuv_swap_switch : false     # RGB与BGR互转
       matrix_r0c0 : 256              #matrix:色域转换系数,用户无需修改
       matrix_r0c1 : 0
       matrix_r0c2 : 359
       matrix_r1c0 : 256
       matrix_r1c1 : -88
       matrix_r1c2 : -183
       matrix_r2c0 : 256
       matrix_r2c1 : 454
       matrix_r2c2 : 0
       input_bias_0 : 0
       input_bias_1 : 128
       input_bias_2 : 128
       mean_chn_0 : 0       # 每个通道的均值【可选】
       mean_chn_1 : 0
       mean_chn_2 : 0
       var_reci_chn_0 : 0.0039216       # 每个通道方差的倒数【可选】,如:1/255
       var_reci_chn_1 : 0.0039216
       var_reci_chn_2 : 0.0039216
}
aipp_op {
    ...
}

4)ATC工具关键参数说明

ATC工具安装在Ascend-cann-toolkit安装目录/ascend-toolkit/latest/bin下。

$ atc -h
===== Basic Functionality =====
[General]       # 基础功能
  --mode              Run mode. 
            0(default): generate offline model; 
            1: convert model to JSON format;
            3: only pre-check; 
            5: convert ge dump txt file to JSON format; 
            6: display model info

[Input]
  --model            原始网络模型文件路径
  --weight           原始网络模型权重文件路径与文件名,仅当原始网络模型是Caffe时需要指定。
  --om                需要转换为json格式的离线模型或原始模型
  --framework         Framework type. 
            0:Caffe; 
            1:MindSpore; 
            3:Tensorflow; 
            5:Onnx
  --input_format      输入数据存储格式。
        当原始框架为Caffe时,支持NCHW(默认)、ND(动态维度)
        当原始框架为ONNX时,支持NCHW(默认)、NCDHW、ND
        当原始框架是TensorFlow时,支持NCHW、NHWC(默认)、ND(模型转换时根据data_format属性的算子,推导出具体的format)、NCDHW、NDHWC
  --input_shape       指定模型输入数据的shape
                      E.g.: "input_name1:n1,c1,h1,w1;input_name2:n2,c2,h2,w2"
  --input_shape_range 指定模型输入数据的shape范围,暂不支持
                      E.g.: "input_name1:[n1~n2,c1,h1,w1];input_name2:[n2,c2~c3,h2,w2]"
  --dynamic_batch_size  设置动态BatchSize参数,适用于执行推理时,每次处理图片数量不固定的场景。
                       E.g.: "1,2,4,8"
  --dynamic_image_size  设置输入图片的动态分辨率参数。适用于执行推理时,每次处理图片宽和高不固定的场景。需要与--input_shape配合使用,
                      E.g.: --input_shape="data:8,3,-1,-1;img_info:8,4,-1,-1"  --dynamic_image_size="416,416;832,832"
  --dynamic_dims      设置ND格式下动态维度的档位。适用于执行推理时,每次处理任意维度的场景。N<=4。
                      E.g.: "dims1_n1,dims1_n2;dims2_n1,dims2_n2"
  --singleop          单算子定义文件,将单个算子Json文件转换成适配昇腾AI处理器的离线模型。以便进行后续的单算子功能验证。

[Output]
  --output            Output file path
  --output_type       指定某个输出节点的输出类型,需要与--out_nodes参数配合使用。
                FP32:推荐分类网络、检测网络使用。
                UINT8:推荐图像超分辨率网络使用。
                FP16:推荐分类网络、检测网络使用。通常用于一个网络输出作为另一个网络输入场景。
                        E.g.: --output_type="conv1:0:FP16"  --out_nodes="conv1:0".
  --check_report      预检结果保存文件路径
  --json              离线模型或原始模型文件转换的json格式文件

[Target]
  --soc_version       The soc version.
          Ascend310
          Ascend910
  --virtual_type      是否支持离线模型在算力分组生成的虚拟设备上运行。
                      0 (default) : Disable virtualization; 1 : Enable virtualization.
  --core_type         设置网络模型使用的Core类型
            VectorCore: use vector core. 
            AiCore: Default 
  --aicore_num        设置模型编译时使用的aicore数量


===== Advanced Functionality =====
[Feature]       # 功能配置选项
  --out_nodes         指定某层输出节点(算子)作为网络模型的输出,如果不指定,则模型的输出默认为最后一层的算子信息。适合算子调试。
                      E.g.: "node_name1:0;node_name1:1;node_name2:0"
  --input_fp16_nodes 指定输入数据类型为FP16的输入节点名称。 配置了该参数,则不能对同一个输入节点同时使用--insert_op_conf参数。
                      E.g.: "node_name1;node_name2"
  --insert_op_conf    插入新算子的配置文件,例如aipp预处理算子。使用该参数后,则输入数据类型为UINT8。
  --op_name_map      扩展算子(非标准算子)映射配置文件

  --is_input_adjust_hw_layout    与--input_fp16_nodes配合使用。若该参数设置为true,对应--input_fp16_nodes节点的输入数据类型为float16,输入数据格式为NC1HWC0。
  --is_output_adjust_hw_layout   与--out_nodes配合使用。若该参数设置为true,对应--out_nodes中输出节点的输出数据类型为float16,数据格式为NC1HWC0。

[Model Tuning]      # 模型调优选项
  --disable_reuse_memory    内存复用开关
  --fusion_switch_file      融合规则(包括图融合和UB融合)开关配置文件
  --enable_scope_fusion_passes   指定编译时需要生效的融合规则列表
  --enable_single_stream    是否使能一个模型推理时只能使用一条Stream。 
                true: enable; 
                false(default): disable
  --enable_small_channel    是否使能small channel的优化,使能后在channel<=4的卷积层会有性能收益。建议与--insert_op_conf参数(AIPP功能)配合使用
                0(default): disable; 
                1: enable
  --enable_compress_weight  Enable compress weight. true: enable; false(default): disable
  --compress_weight_conf    压缩权重的配置文件
  --compression_optimize_conf    压缩优化功能配置文件,暂不支持。
  --sparsity                Optional; enable structured sparse. 0(default): disable; 1: enable
  --buffer_optimize        数据缓存优化开关
            "l2_optimize" (default), 
            "l1_optimize", 
            "off_optimize"
  --mdl_bank_path           加载子图调优后自定义知识库的路径
  
[Operator Tuning]       # 算子调优选项
  --op_precision_mode     设置具体某个算子的精度模式,通过 (.ini)配置文件设置。
  --precision_mode        设置网络模型的精度模式。支持如下:
            force_fp16(default), 
            force_fp32, allow_mix_precision, 
            allow_fp32_to_fp16, must_keep_origin_dtype.
  --modify_mixlist       混合精度场景下,修改算子使用混合精度名单。
  --keep_dtype            保持原始模型编译时个别算子的计算精度不变。
  --customize_dtypes      模型编译时自定义算子的计算精度。
  --auto_tune_mode        设置算子的自动调优模式。
                    E.g.: "GA,RL", support configure multiple, spit by ,
  --op_bank_path          加载Auto Tune调优后自定义知识库的路径。
  --op_select_implmode   选择算子是高精度实现还是高性能实现。支持如下: 
            high_precision, 
            high_performance,   default
            high_precision_for_all, 
            high_performance_for_all. 
  --optypelist_for_implmode    列举算子optype的列表,该列表中的算子使用--op_select_implmode参数指定的模式。                      E.g.: "node_name1,node_name2"
  --op_debug_level        TBE算子编译debug功能开关。
                          0 (default): Disable debug; 
                          1: Enable TBE pipe_all, and generate the operator CCE file and Python-CCE mapping file (.json);
                          2: Enable TBE pipe_all, generate the operator CCE file and Python-CCE mapping file (.json), and enable the CCE compiler -O0-g.
                          3: Disable debug, and keep generating kernel file (.o and .json)
                          4: Disable debug, keep generation kernel file (.o and .json) and generate the opera

五、离线推理应用开发

1.AscendCL

AscendCL(Ascend Computing Language)是一套用于在昇腾平台上开发深度神经网络推理应用的C语言API库,提供Device管理、Context管理、Stream管理、内存管理、模型加载与执行、算子加载与执行、媒体数据处理等C语言API库。

在运行应用时,AscendCL调用GE执行器提供的接口实现模型和算子的加载与执行、调用运行管理器的接口实现Device管理、Context管理、Stream管理、内存管理等。

计算资源层是昇腾AI处理器的硬件算力基础,主要完成神经网络的矩阵相关计算、完成控制算子/标量/向量等通用计算和执行控制功能、完成图像和视频数据的预处理,为深度神经网络计算提供了执行上的保障。

pyACL(Python Ascend Computing Language)就是在AscendCL的基础上使用CPython封装得到的Python API库。

1)接口调用流程

  1. AscendCL初始化。

    调用acl.init接口实现初始化pyACL。

  2. 运行管理资源申请。

    依次申请运行管理资源:Device、Context、Stream。

  3. 算子调用

    • 加载算子om文件,运行算子时使用。
    • 执行算子,输出算子的运行结果。
  4. 模型推理。

    • 模型加载
    • (可选)数据预处理:可实现JPEG图片解码、视频解码、抠图/图片缩放/格式转换、JPEG图片编码、视频编码等功能。参见AIPP与DVPP。
    • 模型推理
    • (可选)数据后处理:处理模型推理的结果。
    • 模型卸载:调用acl.mdl.unload接口卸载模型。
  5. 运行管理资源释放。

    所有数据处理都结束后,需要依次释放运行管理资源:Stream、Context、Device。

  6. pyACL去初始化。

    调用acl.finalize接口实现pyACL去初始化。

2.预处理模块AIPP与DVPP

1)AIPP

AIPP(Artificial Intelligence Pre-Processing)在AI Core上完成数据预处理,主要功能包括改变图像尺寸(Crop/Padding配置)、色域转换(转换图像格式)、归一化配置(减均值/乘系数)等。可通过ATC工具配置模型的AIPP功能。

AIPP使能模式:

AIPP支持的图像输入格式:

2)DVPP

DVPP(Digital Vision Pre-Processor)是昇腾AI处理器内置的图像处理单元,通过pyACL媒体数据处理接口提供强大的媒体处理硬加速能力,主要功能包括缩放、抠图、格式转换、图片编解码、视频编解码等。

3)AIPP与DVPP区别

3.Python推理

基于现有模型,使用pyACL提供的Python语言API库开发深度神经网络应用,用于实现目标识别、图像分类等功能。

1)推理过程

# 导入acl模块
import acl  

# 1.pyACL初始化
ret = acl.init()    

# 2.运行管理资源申请(Device、Context及Stream)
self.device_id = 0
# 指定运算的Device。
ret = acl.rt.set_device(self.device_id)
# 显式创建一个Context,用于管理Stream对象。
self.context, ret = acl.rt.create_context(self.device_id)

# 3.加载模型,并获取模型描述信息
# 初始化变量。
self.model_path = './model/resnet50.om'
# 加载离线模型文件,返回标识模型的ID。
self.model_id, ret = acl.mdl.load_from_file(self.model_path)
# 根据加载成功的模型的ID,获取该模型的描述信息。
self.model_desc = acl.mdl.create_desc()
ret = acl.mdl.get_desc(self.model_desc, self.model_id)

# 4.准备模型推理的输入、输出数据结构
# 初始化变量。
ACL_MEM_MALLOC_HUGE_FIRST = 0

# 创建aclmdlDataset类型的数据,描述模型推理的输入。
self.load_input_dataset = acl.mdl.create_dataset()
# 获取模型输入的数量。
input_size = acl.mdl.get_num_inputs(self.model_desc)
self.input_data = []
# 循环为每个输入申请内存,并将每个输入添加到aclmdlDataset类型的数据中。
for i in range(input_size):
    buffer_size = acl.mdl.get_input_size_by_index(self.model_desc, i)
    # 获取模型输入维度
    dims, ret = acl.mdl.get_input_dims(self.model_desc, i)
    # 申请输入内存。
    buffer, ret = acl.rt.malloc(buffer_size, ACL_MEM_MALLOC_HUGE_FIRST)
    data = acl.create_data_buffer(buffer, buffer_size)
    _, ret = acl.mdl.add_dataset_buffer(self.load_input_dataset, data)
    self.input_data.append({"buffer": buffer, "size": buffer_size})

# 准备模型推理的输出数据集。
# 创建aclmdlDataset类型的数据,描述模型推理的输出。
self.load_output_dataset = acl.mdl.create_dataset()
# 获取模型输出的数量。
output_size = acl.mdl.get_num_outputs(self.model_desc)
self.output_data = []
# 循环为每个输出申请内存,并将每个输出添加到aclmdlDataset类型的数据中。
for i in range(output_size):
    buffer_size = acl.mdl.get_output_size_by_index(self.model_desc, i)
    # 申请输出内存。
    buffer, ret = acl.rt.malloc(buffer_size, ACL_MEM_MALLOC_HUGE_FIRST)
    data = acl.create_data_buffer(buffer, buffer_size)
    _, ret = acl.mdl.add_dataset_buffer(self.load_output_dataset, data)
    self.output_data.append({"buffer": buffer, "size": buffer_size})
    

#  5.准备模型推理的输入数据
img = cv2,imread("test.jpg")
# img前处理
bytes_data = img.tobytes()
np_ptr = acl.util.bytes_to_ptr(bytes_data)
# 将图片数据从Host传输到Device。同步内存复制
ret = acl.rt.memcpy(self.input_data[0]["buffer"], self.input_data[0]["size"], np_ptr,
                    self.input_data[0]["size"], ACL_MEMCPY_HOST_TO_DEVICE)

# 6.执行模型推理。
# self.model_id表示模型ID,在模型加载成功后,会返回标识模型的ID。
ret = acl.mdl.execute(self.model_id, self.load_input_dataset, self.load_output_dataset)

# 7.处理模型推理的输出数据。
inference_result = []
for i, item in enumerate(self.output_data):
    buffer_host, ret = acl.rt.malloc_host(self.output_data[i]["size"])
    # 将推理输出数据从Device传输到Host。同步内存复制
    ret = acl.rt.memcpy(buffer_host, self.output_data[i]["size"], self.output_data[i]["buffer"],
                        self.output_data[i]["size"], ACL_MEMCPY_DEVICE_TO_HOST)
    # 将指针转换bytes对象
    bytes_out = acl.util.ptr_to_bytes(buffer_host, self.output_data[i]["size"])
    # bytes转numpy
    data = np.frombuffer(bytes_out, dtype=np.byte)
    inference_result.append(data)
    tuple_st = struct.unpack("1000f", bytearray(inference_result[0]))
    vals = np.array(tuple_st).flatten()
    
# 8.释放模型推理的输入、输出资源。
# 释放输入资源,包括数据结构和内存。
while self.input_data:
    item = self.input_data.pop()
    ret = acl.rt.free(item["buffer"])
input_number = acl.mdl.get_dataset_num_buffers(self.load_input_dataset)
for i in range(input_number):
    data_buf = acl.mdl.get_dataset_buffer(self.load_input_dataset, i)
    if data_buf:
        ret = acl.destroy_data_buffer(data_buf)
ret = acl.mdl.destroy_dataset(self.load_input_dataset)

# 释放输出资源,包括数据结构和内存。
while self.output_data:
    item = self.output_data.pop()
    ret = acl.rt.free(item["buffer"])
output_number = acl.mdl.get_dataset_num_buffers(self.load_output_dataset)
for i in range(output_number):
    data_buf = acl.mdl.get_dataset_buffer(self.load_output_dataset, i)
    if data_buf:
        ret = acl.destroy_data_buffer(data_buf)
ret = acl.mdl.destroy_dataset(self.load_output_dataset)


# 9.卸载模型,释放模型描述信息、管理资源和pyACL去初始化。
# 卸载模型。
ret = acl.mdl.unload(self.model_id)

# 释放模型描述信息。
if self.model_desc:
    ret = acl.mdl.destroy_desc(self.model_desc)
    self.model_desc = None
    
# 释放Context。
if self.context:
    ret = acl.rt.destroy_context(self.context)
    self.context = None

# 释放Device。
ret = acl.rt.reset_device(self.device_id)
# pyACL去初始化
ret = acl.finalize()

2)官方参考样例

4.C&C++ 推理

1)头文件和库文件说明

AscendCL头文件在“CANN软件安装后文件存储路径/include/”目录下,AscendCL库文件在“CANN软件安装后文件存储路径/lib64/”目录下。

定义接口的头文件 用途 对应的库文件
acl/acl_base.h 用于定义基本的数据类型(例如aclDataBuffer、aclTensorDesc等)及其操作接口、枚举值(例如aclFormat)、日志管理接口等。 libascendcl.so
acl/acl.h 该头文件中已包含acl/acl_mdl.h、acl/acl_rt.h、acl/acl_op.h。可以引用初始化/去初始化、Device管理、算力Group查询与设置、Context管理、Stream管理、同步等待、内存管理、模型加载与执行、算子编译(不包括aclopCompile接口)、算子加载与执行(不包括aclopCompileAndExecute接口)等接口。 libascendcl.so
acl/acl_prof.h 用于定义Profiling配置的接口。 libmsprofiler.so
acl/ops/acl_cblas.h 用于定义CBLAS接口。 libacl_cblas.so
acl/ops/acl_dvpp.h 用于定义媒体数据处理V1版本的接口。 libacl_dvpp.so
acl/ops/acl_fv.h 用于定义特征向量检索的接口。昇腾310 AI处理器,当前不支持引用该头文件中的接口。昇腾910 AI处理器,当前不支持引用该头文件中的接口。 libacl_retr.so
acl/acl_op_compiler.h 用于定义aclopCompile、aclopCompileAndExecute、aclSetCompileopt等算子在线编译相关的接口、数据类型、枚举值等。 libacl_op_compiler.so
acl/acl_tdt.h 用于定义Tensor数据传输接口。昇腾310 AI处理器,当前不支持引用该头文件中的接口。 libacl_tdt_channel.so
acl/acl_tdt_queue.h 用于定义共享队列管理、共享Buffer管理接口。预留功能,当前暂不支持引用该头文件中的接口。 libacl_tdt_queue.so
acl/dvpp/hi_dvpp.h 用于定义媒体数据处理V2版本的接口。 libacl_dvpp_mpi.so

2)推理过程

#include "acl/acl.h"
#include <iostream>
#include <fstream>
#include <cstring>
#include <map>

using namespace std;

size_t pictureDataSize = 0;
void *pictureHostData;
void *pictureDeviceData;

//申请内存,使用C/C++标准库的函数将测试图片读入内存
void ReadPictureTotHost(const char *picturePath)
{
    string fileName = picturePath;
    ifstream binFile(fileName, ifstream::binary);
    binFile.seekg(0, binFile.end);
    pictureDataSize = binFile.tellg();
    binFile.seekg(0, binFile.beg);
    aclError ret = aclrtMallocHost(&pictureHostData, pictureDataSize);
    binFile.read((char*)pictureHostData, pictureDataSize);
    binFile.close();
}

//申请Device侧的内存,再以内存复制的方式将内存中的图片数据传输到Device
void CopyDataFromHostToDevice()
{
    aclError ret = aclrtMalloc(&pictureDeviceData, pictureDataSize, ACL_MEM_MALLOC_HUGE_FIRST);
    ret = aclrtMemcpy(pictureDeviceData, pictureDataSize, pictureHostData, pictureDataSize,             ACL_MEMCPY_HOST_TO_DEVICE);
}


int main()
{   
    int32_t deviceId = 0;
    uint32_t modelId;
    aclmdlDataset *inputDataSet;
    aclDataBuffer *inputDataBuffer;
    aclmdlDataset *outputDataSet;
    aclDataBuffer *outputDataBuffer;
    aclmdlDesc *modelDesc;
    size_t outputDataSize = 0;
    void *outputDeviceData;
    void *outputHostData;
    
    // 1.AscendCL初始化、运行管理资源申请(指定计算设备)
    aclError ret;
    ret = aclInit(nullptr);
    ret = aclrtSetDevice(deviceId);
    
    // 2.加载模型
    const char *modelPath = "../model/resnet50.om";
    ret = aclmdlLoadFromFile(modelPath, &modelId);
    // 创建模型描述信息
    modelDesc =  aclmdlCreateDesc();
    ret = aclmdlGetDesc(modelDesc, modelId);
    
    // 3.将测试图片数据读入内存,并传输到Device侧,用于后续推理使用
    const char *picturePath = "../data/dog1_1024_683.bin";
    ReadPictureTotHost(picturePath);
    CopyDataFromHostToDevice();
    
    //4.准备模型推理的输入输出数据结构
    // 创建aclmdlDataset类型的数据,描述模型推理的输入
    inputDataSet = aclmdlCreateDataset();
    inputDataBuffer = aclCreateDataBuffer(pictureDeviceData, pictureDataSize);
    ret = aclmdlAddDatasetBuffer(inputDataSet, inputDataBuffer);
    
    // 创建aclmdlDataset类型的数据,描述模型推理的输出
    outputDataSet = aclmdlCreateDataset();
    // 获取模型输出数据需占用的内存大小,单位为Byte
    outputDataSize = aclmdlGetOutputSizeByIndex(modelDesc, 0);
    // 申请输出内存
    ret = aclrtMalloc(&outputDeviceData, outputDataSize, ACL_MEM_MALLOC_HUGE_FIRST);
    outputDataBuffer = aclCreateDataBuffer(outputDeviceData, outputDataSize);
    ret = aclmdlAddDatasetBuffer(outputDataSet, outputDataBuffer);
    
    // 5.执行推理
    ret = aclmdlExecute(modelId, inputDataSet, outputDataSet);
    
    // 6.获取推理结果数据
    ret = aclrtMallocHost(&outputHostData, outputDataSize);
    ret = aclrtMemcpy(outputHostData, outputDataSize, outputDeviceData, outputDataSize, ACL_MEMCPY_DEVICE_TO_HOST);
    // 将内存中的数据转换为float类型
    float* outFloatData = reinterpret_cast<float *>(outputHostData);
    
    // 7.释放模型描述信息,卸载模型
    aclmdlDestroyDesc(modelDesc);
    aclmdlUnload(modelId);
    
    // 8.释放内存、销毁推理相关的数据类型
    ret = aclrtFreeHost(pictureHostData);
    pictureHostData = nullptr;
    ret = aclrtFree(pictureDeviceData);
    pictureDeviceData = nullptr;
    aclDestroyDataBuffer(inputDataBuffer);
    inputDataBuffer = nullptr;
    aclmdlDestroyDataset(inputDataSet);
    inputDataSet = nullptr;
    
    ret = aclrtFreeHost(outputHostData);
    outputHostData = nullptr;
    ret = aclrtFree(outputDeviceData);
    outputDeviceData = nullptr;
    aclDestroyDataBuffer(outputDataBuffer);
    outputDataBuffer = nullptr;
    aclmdlDestroyDataset(outputDataSet);
    outputDataSet = nullptr;
    
    // 9.计算设备释放,AscendCL去初始化
    aclError ret = aclrtResetDevice(deviceId);
    aclFinalize();
}

参考

上一篇 下一篇

猜你喜欢

热点阅读