美文网首页
Ascend CANN及Pytorch使用说明(基于Atlas

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

作者: Mr_Michael | 来源:发表于2022-12-14 10:25 被阅读0次

    一、简介

    1.华为昇腾AI全栈简介

    2022-12-14 10-22-43 的屏幕截图.png
    • Atlas系列产品:提供AI训练、推理卡及训练服务器.
    • CANN(异构计算架构):芯片算子库和自动化算法开发工具。
    • ModelBox:适用于端边云场景的AI推理应用开发框架,提供标准SDK API接口。
    • MindSpore(AI框架):支持“端-边-云”独立和协同的统一训练和推理框架。
    • MindX SDK(昇腾SDK):行业SDK和应用解决方案。
      • mxIndex:对于大规模特征检索/聚类的应用场景需求,基于开源Faiss框架,提供极简易用、高性能API。
      • mxManufacture:提供制造业视觉质检相关API。
      • mxVision:提供智能视频分析相关API。
    • ModelArts(AI开发平台):华为云AI开发平台。
    • MindStudio(全流程开发工具链):AI全流程开发IDE。

    2.CANN简介

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

    • 统一编程接口AscendCL适配全系列硬件。
    • 通过自动流水、算子深度融合、智能计算调优、自适应梯度切分等核心技术,软硬件协同优化,释放硬件算力。

    1)CANN开发及运行环境

    • 开发环境:主要用于代码开发、编译、调测等开发活动。

      • (场景一)在非昇腾AI设备上安装开发环境,仅能用于代码开发、编译等不依赖于昇腾设备的开发活动(例如ATC模型转换、算子和推理应用程序的纯代码开发)。
      • (场景二)在昇腾AI设备上安装开发环境,支持代码开发和编译,同时可以运行应用程序或进行训练脚本的迁移、开发&调试。
    • 运行环境:在昇腾AI设备上运行用户开发的应用程序或进行训练脚本的迁移、开发&调试。

    推理方式

    • 离线推理:是基于原有AI框架模型转换OM模型,不依赖于AI框架执行推理的场景。
    • 在线推理:是将原有AI框架做推理的应用快速迁移至昇腾AI处理器上,依赖于AI框架执行推理的场景。

    2)CANN 开发辅助工具

    CANN 5.0.3 开发辅助工具指南 01

    • 精度对比工具

      • 推理场景中,ATC在模型转换过程中对模型进行了优化,包括算子消除、算子融合、算子拆分,可能会造成算子精度问题。
      • 训练场景中,华为支持迁移用户原始网络,在昇腾910 AI处理器上训练,网络迁移可能会造成算子精度问题。
    • Auto Tune调优工具

    • 可以自动对算子进行性能优化,提升算子的运行效率。

    • Profiling工具

      • 用于分析在训练阶段或运行在昇腾AI处理器上的APP工程各个运行阶段的关键性能瓶颈。
    • AI Core Error Analyzer工具

    • 可以自动快速准确地收集定位AI Core Error问题所需的关键信息。

    • 脚本转换工具

      • 可以将脚本转换为支持在NPU上运行的脚本,解决基于GPU的训练和在线推理脚本不能直接在NPU上运行的问题。
    • 算子及模型速查工具

      • 查询当前版本CANN支持的模型和算子功能
    • 推理Benchmark工具

      • 针对指定的推理模型运行推理程序,并能够测试推理模型的性能(包括吞吐率、时延)和精度指标。
    • 专家系统(MindStudio Advisor)

      • 用于聚焦模型和算子的性能调优TOP问题,识别性能瓶颈Pattern,重点构建瓶颈分析、优化推荐模型,支撑开发效率提升的工具。
    • 昇腾模型压缩工具

      • 对原始网络模型进行量化(对模型的权重(weight)和数据(activation)进行低比特处理),节省网络模型存储空间、降低传输时延、提高计算效率。
      • 无需在安装昇腾AI处理器的服务器上运行
        • Caffe昇腾模型压缩工具
        • TensorFlow昇腾模型压缩工具
        • PyTorch昇腾模型压缩工具
        • ONNX昇腾模型压缩工具:源模型转量化模型
      • 须在安装昇腾AI处理器的服务器上运行
        • MindSpore昇腾模型压缩工具
        • ACL昇腾模型压缩工具:将量化模型转换成昇腾AI处理器的离线模型。
        • TensorFlow,Ascend昇腾模型压缩工具

      昇腾模型压缩工具目前支持在Ubuntu 18.04.5和麒麟 V10操作系统安装。

    3.MindSpore

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

    • MindSpore Extend(扩展层):MindSpore的扩展包,社区开发者可参与开发。

    • MindExpression(表达层):基于Python的前端表达;向用户提供了3个不同层次的API,支撑用户进行网络构建、整图执行、子图执行以及单算子执行。

    • High-Level Python API:提供了训练推理的管理、混合精度训练、调试调优等高级接口。

    • Medium-Level Python API:提供网络层、优化器、损失函数等模块,可灵活构建神经网络和控制执行流程,实现模型算法逻辑。

    • Low-Level Python API:提供张量定义、基础算子、自动微分等模块,可实现张量定义和求导计算。

    • MindCompiler(编译优化层):图层的核心编译器,主要基于端云统一的MindIR实现三大功能:

      • 包括硬件无关的优化(类型推导、自动微分、表达式化简等)
      • 硬件相关优化(自动并行、内存优化、图算融合、流水线执行等)
      • 部署推理相关的优化(量化、剪枝等)
    • MindRT(全场景运行时):含云侧、端侧以及更小的IoT。

    二、快速部署

    快速部署(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模式的产品:

    • 昇腾310 AI处理器:Atlas 200 AI加速模块、Atlas 300I 推理卡、Atlas 500 智能小站、Atlas 500 Pro 智能边缘服务器、Atlas 800 推理服务器。

    • 昇腾710 AI处理器:Atlas 300I Pro 推理卡。

    • 昇腾910 AI处理器:Atlas 800 训练服务器、Atlas 300T 训练卡。

    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
    • KylinV10SP1就是Kylin V10Tercel

    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容器的方式平滑运行在昇腾设备上。
    • npu-firmware:在运行环境中安装,依赖昇腾AI处理器。
    • npu-driver:在运行环境中安装,依赖昇腾AI处理器。
    • toolkit:在开发环境中安装,不依赖昇腾AI处理器。
    • nnrt:离线推理引擎包,用于应用程序的模型推理。仅支持离线推理,依赖昇腾AI处理器。
    • nnae:深度学习引擎,支持在线训练、在线推理、离线推理。
    • toolbox:在运行环境中安装,依赖昇腾AI处理器。

    3)下载软件

    • 主板相关固件及驱动【可选】:

      选择CANN 5.1.RC2.alpha008版本

      • KylinV10SP1 驱动包:A500-Pro-3000-iDriver_V106_KylinV10SP1.zip
      • 其他按需安装
    • AI加速卡相关固件及驱动

      选择CANN 5.1.RC2.alpha008版本

      • Atlas 300I 推理卡(型号:3000)驱动:A300-3000-npu-driver_5.1.rc2_linux-aarch64.run
      • Atlas 300I 推理卡(型号:3000)固件:A300-3000-npu-firmware_5.1.rc2.run
    • CANN 社区版软件包

      选择5.1.RC2.alpha008版本

      • Toolkit(开发套件包):Ascend-cann-toolkit_5.1.RC2_linux-aarch64.run
      • NNAE(深度学习引擎):Ascend-cann-nnae_5.1.RC2_linux-aarch64.run
      • NNRT(推理引擎):Ascend-cann-nnrt_5.1.RC2_linux-aarch64.run
      • AMCT(模型压缩工具):Ascend-cann-amct_5.1.RC2_linux-aarch64.tar.gz
      • Device-SDK(包含昇腾310/310P驱动包、acl、ctrlcpu库):Ascend-cann-device-sdk_5.1.RC2_linux-aarch64.zip
    • 实用工具包

      • Toolbox(包含容器引擎插件Ascend-docker runtime、Ascend-DMI工具等):Ascend-mindx-toolbox_3.0.RC3_linux-aarch64.run

    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拉取容器镜像

    • infer-modelzoo【推理】
      • ModelZoo 推理基础镜像,包含模型转换、模型推理功能,镜像中安装了toolkit和sdk及其依赖的软件,其中sdk默认安装的为mxmanufacture,另一个版本安装的是mxvision
    • ascend-infer【推理】
      • Ascend-infer基础镜像,基于centos7.6,ubuntu18.04制作,内部集成推理通用的第三方库(系统包、pip)和NNRT推理引擎。
    • pytorch-modelzoo【训练+推理】
      • ModelZoo PyTorch框架基础镜像,基于PyTorch 1.5.0或 1.8.1版本制作的基础镜像,镜像中安装了nnae,包含训练、转换和推理功能。
    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
    
    • 该容器还需要更新torchvision版本

      #PyTorch 1.8.1需安装0.9.1版本,PyTorch 1.11.0需安装0.12.0版本,PyTorch 1.5.0需安装0.6.0版本
      pip3 install torchvision==0.9.1   
      
    • 想要在pytorch-modelzoo容器中进行离线模型推理,还需要安装cann-toolkit。

      dpkg -i Ascend-cann-toolkit_5.1.RC2_linux-aarch64.deb
      source /usr/local/Ascend/ascend-toolkit/set_env.sh
      

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

    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:

    • mxManufacture:制造业视觉质检
    • mxVision:智能视频/图像分析,主要功能如下:
      • 快速构建推理业务:通过修改流程编排配置文件,可快速构建推理业务,通过API调用,向构建完成的推理业务发送请求,得到推理结果Json字符串或者原始数据结构。
      • 自定义功能插件:通过SDK提供的插件开发工具和业务逻辑开发基础库,用户可自行开发新插件。
    • mxIndex:特征类聚与检索

    基于 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

    昇腾工具仓库

    • msame【模型推理工具】

      输入.om模型和模型所需要的输入bin文件,输出模型的输出数据文件。

    • img2bin【bin文件生成工具】

      生成模型推理所需的输入数据,以.bin格式保存。

    • makesd【制卡工具】

      制卡工具包,提供ubuntu下制卡功能。

    • configure_usb_ethernet【USB虚拟网卡连接脚本】

      配置USB网卡对应的IP地址。

    • pt2pb【pytorch模型转tensorflow pb模型工具】

      输入pytorch权重参数模型,转为onnx,再转为pb模型

    • dnmetis【NPU推理精度和性能测试工具】

      使用Python封装ACL的C++接口,输入om模型和原始数据集图片、标签,即可执行模型推理,输出精度数据和性能数据。

    • msquickcmp【一键式全流程精度比对工具】

      该工具适用于tensorflow和onnx模型,输入原始模型和对应的离线om模型,输出精度比对结果。

    • precision_tool【精度问题分析工具】

      该工具包提供了精度比对常用的功能,当前该工具主要适配Tensorflow训练场景,同时提供Dump数据/图信息的交互式查询和操作入口。

    • cann-benchmark_infer_scripts【cann-benchmark推理软件对应的模型前后处理脚本】

      该工具包含cann-benchmark推理工具模型处理脚本, 包括:结果解析脚本和前后处理脚本等。这些脚本需根据cann-benchmark指导手册说明使用。

    • tfdbg_ascend【Tensorflow2.x dump工具】

      该工具提供CPU/GPU平台上Tensorflow2.x运行时数据Dump能力。

    • ais-bench_workload【ais-bench_workload】

      该目录包含基于Ais-Bench软件的训练和推理负载程序,用于测试验证。Ais-Bench是基于AI标准针对AI服务器进行性能测试的工具软件。

    • intelligent_edge_tools【intelligent_edge_tools】

      该目录包含智能边缘工具集。

    • auto-optimizer【auto-optimizer】

      提供基于ONNX的改图、自动优化及端到端推理流程。

    • saved_model2om【TensorFlow1.15 saved_model模型转om模型工具】

      输入TensorFlow存储的saved_model模型,转换为pb模型,再转换为om模型

    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.环境准备

    • 支持在线推理的芯片型号

      • Ascend310
      • Ascend310P*
      • Ascend910*
    • Ascend Pytorch版本对应关系

    • 安装依赖

      # CentOS
      yum install -y patch libjpeg-turbo-devel dos2unix git 
      yum install -y gcc==7.3.0 cmake==3.12.0
      
      # Ubuntu
      apt-get update
      apt-get install -y patch build-essential libbz2-dev libreadline-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev liblzma-dev m4 dos2unix git 
      apt-get install -y gcc==7.3.0 cmake==3.12.0 #3.12.0版本及以上
      
      # 安装PyTorch环境依赖
      pip3 install pyyaml
      pip3 install wheel
      
    • 安装ascend pytorch

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

    1)环境准备

    基于pytorch-modelzoo容器运行

    • 镜像:ascendhub.huawei.com/public-ascendhub/pytorch-modelzoo:22.0.RC2-1.8.1
    # 初始化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模型为例,执行在线推理样例。

    • 下载预训练模型。

      打开ModelZoo中ResNet50详情页,单击该页面的“下载模型“下载已训练好的模型文件。

    • 编辑推理脚本。

      创建“resnet50_infer_for_pytorch.py“模型脚本文件,并参考样例代码写入相关代码。

    • 执行推理

      $ tree nnae_sample/ -L 2
      nnae_sample/
      ├── data
      │   └── val
      │       ├──  val
      │         ├── dog1_1024_683.jpg
      │         ├── dog2_1024_683.jpg
      ├── ResNet50_for_Pytorch_1.4_model
      │   ├── resnet50_pytorch_1.4.om
      │   ├── resnet50_pytorch_1.4.onnx
      │   └── resnet50_pytorch_1.4.pth.tar
      └── resnet50_infer_for_pytorch.py
      
      $ python3 resnet50_infer_for_pytorch.py \
          --data ./data \
          --npu 0 \
          --epochs 90 \
          --resume ResNet50_for_Pytorch_1.4_model/resnet50_pytorch_1.4.pth.tar
          
      use  npu:0
      => creating model 'resnet50'
      Selected optimization level O2:  FP16 training with FP32 batchnorm and FP32 master weights.
      
      Defaults for this optimization level are:
      enabled                : True
      opt_level              : O2
      cast_model_type        : torch.float16
      patch_torch_functions  : False
      keep_batchnorm_fp32    : True
      master_weights         : True
      loss_scale             : dynamic
      combine_grad           : None
      combine_ddp            : None
      ddp_replica_count      : 4
      check_combined_tensors : None
      user_cast_preferred    : None
      Processing user overrides (additional kwargs that are not None)...
      After processing overrides, optimization options are:
      enabled                : True
      opt_level              : O2
      cast_model_type        : torch.float16
      patch_torch_functions  : False
      keep_batchnorm_fp32    : True
      master_weights         : True
      loss_scale             : 1024.0
      combine_grad           : None
      combine_ddp            : None
      ddp_replica_count      : 4
      check_combined_tensors : None
      user_cast_preferred    : None
      => loading checkpoint 'ResNet50_for_Pytorch_1.4_model/resnet50_pytorch_1.4.pth.tar'
      => loaded checkpoint 'ResNet50_for_Pytorch_1.4_model/resnet50_pytorch_1.4.pth.tar' (epoch 90)
      Test: [0/1]   Time  3.165 ( 0.000)    Acc@1   0.00 (  0.00)   Acc@5   0.00 (  0.00)
       * Acc@1 0.000 Acc@5 0.000
      THPModule_npu_shutdown success.
      

    四、PyTorch模型迁移与转换

    1.模型迁移

    1)模型算子评估

    • 将原始模型及训练脚本迁移到昇腾AI处理器上之前,可以将原始模型及训练脚本在CPU上进行训练,使用PyTorch profiler功能获取当前模型算子列表并在《AI框架算子支持清单》中查找该算子查看是否支持

      • 支持PyTorch1.5.0、PyTorch1.8.1、PyTorch1.11.0版本算子
    • 当有不支持算子时,可修改模型脚本用等价支持的算子替换不支持算子或者参考《自定义算子开发指南》中“算子开发过程>算子适配>适配插件开发(PyTorch框架)”进行算子适配。

    2)迁移方式

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

    • 自动迁移【推荐】:训练时,在训练脚本中导入脚本转换库,导入后执行训练。训练脚本在运行的同时,会自动将脚本中的CUDA接口替换为昇腾AI处理器支持的NPU接口。整体过程为:边训练边转换。

      • 仅PyTorch 1.8.1版本及以上使用,自动迁移方式较简单,且修改内容最少,只需在训练脚本中添加引入库代码。
      import torch
      import torch_npu
      .....
      from torch_npu.contrib import transfer_to_npu
      
    • 工具迁移:训练前,通过脚本迁移工具,自动将训练脚本中的CUDA接口替换为昇腾AI处理器支持的NPU接口,并生成迁移报告(脚本转换日志、不支持算子的列表、脚本修改记录)。训练时,运行转换后的脚本。整体过程为:先转换脚本,再进行训练。

    • 手工迁移:算法工程师通过对模型的分析、GPU与NPU代码的对比进而对训练脚本进行修改,以支持再昇腾AI处理器上执行训练。

    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
    • 开源框架网络模型经过Parser解析后,转换为中间态IR Graph(CANN模型格式)。
    • 中间态IR经过图准备,图拆分,图优化,图编译等一系列操作后,转成适配昇腾AI处理器的离线模型。
    • 转换后的离线模型上传到板端环境,通过AscendCL接口加载模型文件实现推理过程。
      • 可以将开源框架网络模型转换后的离线模型转成json文件,或者直接将开源框架网络模型通过ATC工具转成json文件,方便文件查看。

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

    • Caffe网络模型

      atc --model=$HOME/module/resnet50.prototxt --weight=$HOME/module/resnet50.caffemodel --framework=0 --output=$HOME/module/out/caffe_resnet50 --soc_version=Ascend310 
      
    • TensorFlow网络模型

      atc --model=$HOME/module/resnet50_tensorflow*.pb --framework=3 --output=$HOME/module/out/tf_resnet50 --soc_version=Ascend310 
      
    • ONNX网络模型

      atc --model=$HOME/module/resnet50.onnx --framework=5 --output=$HOME/module/out/onnx_resnet50 --soc_version=Ascend310 
      
      # yolov5 源模型转离线模型示例
      
      # yolov5 源模型 转 onnx模型
      python export.py --weights yolov5l.pt --include  onnx --imgsz 640 --batch-size 1 --opset 11 --simplify
      
      # onnx模型转om模型
      atc --model=yolov5l.onnx \
        --framework=5 \
          --output=yolov5l_b1 \
        --input_format=NCHW \
          --input_shape="images:1,3,640,640"  \ 
        --input_fp16_nodes="images" \
          --soc_version=Ascend310 \
          --output_type=FP16 \
        --log=error
      
    • MindSpore网络模型

      atc --model=$HOME/module/ResNet50.air --framework=1 --output=$HOME/module/out/ResNet50_mindspore --soc_version=Ascend310
      

    2)基础功能参数配置

    • 模型文件转json文件

      json文件可以查看基础版本号

      # 原始模型文件转json文件
      atc --mode=1 --om=$HOME/module/resnet50_tensorflow*.pb  --json=$HOME/module/out/tf_resnet50.json  --framework=3
      
      # 离线模型转json文件
      atc --mode=1 --om=$HOME/module/out/tf_resnet50.om  --json=$HOME/module/out/tf_resnet50.json
      
    • 离线模型支持动态BatchSize/动态分辨率

      # 动态BatchSize
      atc --model=$HOME/module/resnet50_tensorflow*.pb  --framework=3 --output=$HOME/module/out/tf_resnet50 --soc_version=<soc_version> --input_shape="Placeholder:-1,224,224,3"  --dynamic_batch_size="1,2,4,8"  
      
      # 动态分辨率
      atc --model=$HOME/module/resnet50_tensorflow*.pb  --framework=3 --output=$HOME/module/out/tf_resnet50 --soc_version=<soc_version>  --input_shape="Placeholder:1,-1,-1,3"  --dynamic_image_size="224,224;448,448"  
      
    • 离线模型支持动态维度

      atc --model=$HOME/module/resnet50_tensorflow*.pb --framework=3 --output=$HOME/module/out/tf_resnet50 --soc_version=<soc_version>  --input_shape="Placeholder:-1,-1,-1,3" --dynamic_dims="1,224,224;8,448,448" --input_format=ND 
      
    • 自定义离线模型的输入输出数据类型

      atc --model=$HOME/module/resnet50_tensorflow_1.7.pb  --framework=3 --output=$HOME/module/out/tf_resnet50 --soc_version=<soc_version>  --input_fp16_nodes="Placeholder" --out_nodes="fp32_vars/MaxPoolWithArgmax:0" --output_type="fp32_vars/MaxPoolWithArgmax:0:FP16"  
      

    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 {
        ...
    }
    
    • 色域转换配置表

      # YUV420SP_U8转RGB,输入数据为JPEG图像
      aipp_op {
          aipp_mode: static
          input_format : YUV420SP_U8
          csc_switch : true
          rbuv_swap_switch : false
          matrix_r0c0 : 256
          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
      }
      
      # YUV420SP_U8转BGR,输入数据为JPEG图像
      aipp_op {
          aipp_mode: static
          input_format : YUV420SP_U8
          csc_switch : true
          rbuv_swap_switch : false
          matrix_r0c0 : 256
          matrix_r0c1 : 454
          matrix_r0c2 : 0
          matrix_r1c0 : 256
          matrix_r1c1 : -88
          matrix_r1c2 : -183
          matrix_r2c0 : 256
          matrix_r2c1 : 0
          matrix_r2c2 : 359
          input_bias_0 : 0
          input_bias_1 : 128
          input_bias_2 : 128
      }
      
      # YUV420SP_U8转BGR,输入数据为JPEG图像
      aipp_op {
          aipp_mode: static
          input_format : YUV420SP_U8
          csc_switch : true
          rbuv_swap_switch : true
          matrix_r0c0 : 256
          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
      }
      
      # RGB888_U8转RGB
      aipp_op {
          aipp_mode: static
          input_format : RGB888_U8
          csc_switch : false
          rbuv_swap_switch : false
      }
      
      # RGB888_U8转BGR
      aipp_op {
          aipp_mode : static
          input_format : RGB888_U8
          csc_switch : false
          rbuv_swap_switch : true
      }
      
    • 归一化配置

      mean_chn_i    # 每个通道的均值
      min_chn_i # 每个通道的最小值
      var_reci_chn  # 每个通道方差的倒数
      
      pixel_out_chx(i)=[pixel_in_chx(i)-mean_chn_i-min_chn_i]*var_reci_chn
      
    • Crop/Padding配置

      aipp_op {
          aipp_mode: static
          input_format: YUV420SP_U8
      
          src_image_size_w: 320  
          src_image_size_h: 240
      
          crop: true
          load_start_pos_w: 10      # 左上点坐标
          load_start_pos_h: 20
          crop_size_w: 50           # 裁剪后的图像大小
          crop_size_h: 60
      
          padding: true     
          left_padding_size: 20 # 在裁剪后的图像四周padding的尺寸
          right_padding_size: 15
          top_padding_size: 20
          bottom_padding_size: 15
          padding_value: 0      # padding像素值
      
      }
      
    • 输入图像大小校验

      # YUV400_U8
      N * src_image_size_w * src_image_size_h * 1
      # YUV420SP_U8
      N * src_image_size_w * src_image_size_h * 1.5
      # XRGB8888_U8
      N * src_image_size_w * src_image_size_h * 4
      # RGB888_U8
      N * src_image_size_w * src_image_size_h * 3
      
    • AIPP输入数据格式说明

      • 数据储存格式
        • AIPP输入默认为NHWC排布,如果不是,将强制转换为NHWC。
        • 经过AIPP处理后的图片,统一采用NC1HWC0的五维数据格式进行存储。
      • 图像输入格式
        • AIPP支持的图像输入格式:YUV420SP_U8(NV12)、RGB888_U8、XRGB8888_U8、YUV400_U8。(输入数据类型为UINT8)

    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:模型生成后,AIPP参数值被保存在离线模型中,每次模型推理过程采用固定的AIPP预处理参数进行处理,而且在之后的推理过程中无法通过业务代码进行直接的修改。
    • 动态AIPP:每次模型推理前,根据需求,在执行模型前设置动态AIPP参数值,然后在模型执行时可使用不同的AIPP参数。动态AIPP参数值会根据需求在不同的业务场景下选用合适的参数(如不同摄像头采用不同的归一化参数,输入图片格式需要兼容YUV420和RGB等)。

    AIPP支持的图像输入格式:

    • YUV420SP_U8、RGB888_U8、XRGB8888_U8、YUV400_U8。

    2)DVPP

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

    • pyACL提供了基于DVPP硬件的媒体数据处理接口

      功能 说明
      VPC(Vision Preprocessing Core) 处理YUV、RGB等格式的图片,包括缩放、抠图、图像金字塔、色域转换等。
      JPEGD(JPEG Decoder) JPEG压缩格式-->YUV格式的图片解码。
      JPEGE(JPEG Encoder) YUV格式-->JPEG压缩格式的图片编码。
      VDEC(Video Decoder) H264/H265格式-->YUV/RGB格式的视频码流解码。
      VENC(Video Encoder) YUV420SP格式-->H264/H265格式的视频码流编码。
      PNGD(PNG decoder) PNG格式-->RGB格式的图片解码。
    • 昇腾AI处理器对媒体数据处理V1版本各功能的支持度

      昇腾AI处理器 VPC JPEGD JPEGE PNGD VDEC VENC
      昇腾310 AI处理器
      昇腾910 AI处理器 x
      昇腾310P AI处理器

    3)AIPP与DVPP区别

    • DVPP对输入、输出有特殊的限制(基于处理速度和处理占有量的考虑),对输出图片的宽高有对齐要求,且其输出格式通常为YUV420SP等格式。
    • AIPP能力是对DVPP能力的有效补充,AIPP主要用于在AI Core上完成数据预处理,AIPP提供色域转换功能、Crop(抠图)和Padding(补边)功能,可以输出色域转换和固定大小的图片。
    • 处理顺序:原图/视频流 -> DVPP -> AIPP -> 模型推理。

    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()
    
    • 同步内存复制

      # 1.申请内存。
      size = 1 * 1024 * 1024
      host_ptr_a, ret = acl.rt.malloc_host(size)
      dev_ptr_b, ret = acl.rt.malloc(size, ACL_MEM_MALLOC_NORMAL_ONLY)
      
      # 2.申请内存后,可向内存中读入数据,该自定义函数fead_file由用户实现。
      fead_file(fileName, host_ptr_a, size)
      
      # 3.同步内存复制。
      #host_ptr_a表示Host上源内存地址指针,dev_ptr_b表示Device上目的内存地址指针,size表示内存大小。
      # ACL_MEMCPY_HOST_TO_DEVICE = 1
      ret = acl.rt.memcpy(dev_ptr_b, size, host_ptr_a, size, ACL_MEMCPY_HOST_TO_DEVICE)
      
      # 4.使用完内存中的数据后,需及时释放资源。
      ret = acl.rt.free_host(host_ptr_a)
      ret = acl.rt.free(dev_ptr_b)
      
    • 异步内存复制

      # 1.申请内存。
      size = 1 * 1024 * 1024
      # 异步内存复制要求,内存首地址64字节对齐,使用acl.rt.malloc_host 需多申请64字节。
      host_ptr_a, ret = acl.rt.malloc_host(size + 64)
      # host申请的内存需要用户自己64对齐处理。
      host_align = host_ptr_a + 64 - host_ptr_a % 64
      # acl.rt.malloc 申请的Device 侧内存系统保证已经符合64对齐。
      dev_ptr_b, ret = acl.rt.malloc(size, ACL_MEM_MALLOC_NORMAL_ONLY)
      
      # 2.申请内存后,可向内存中读入数据,该自定义函数fead_file由用户实现。
      fead_file(fileName, host_align, size)
      
      # 3.异步内存复制。
      # host_align 表示Host上源内存地址指针,dev_ptr_b表示Device上目的内存地址指针,size表示内存大小。
      # ACL_MEMCPY_HOST_TO_DEVICE = 1。
      ret = acl.rt.memcpy_async(dev_ptr_b, size , host_align, size, ACL_MEMCPY_HOST_TO_DEVICE, stream)
      ret = acl.rt.synchronize_stream(stream)
      
      # 4.使用完内存中的数据后,需及时释放资源。
      ret = acl.rt.destroy_stream(stream)
      ret = acl.rt.free_host(host_ptr_a)
      ret = acl.rt.free(dev_ptr_b)
      
    • 多模型推理注意:一个进程内只能调用一次acl.init和acl.finalize接口。

    2)官方参考样例

    • ascendcl-samples: 以CANN AscendCL接口进行开发的样例库。

    • ModelZoo-PyTorch/ACL_Pytorch:基于昇腾芯片的推理模型参考。

      • modelzoo-GPL/ACL_Pytorch/Yolov5_for_Pytorch:对ACL_Pytorch的YoloV3/V5/V7的补充。

        • 由于slice+concat算子在Ascend AI框架下耗时比较高,所以YoloV5模型想要加速需要把slice+concat算子功能放到CPU实现。

          源模型网络:

          <img src="https://img.haomeiwen.com/i15877540/48decc4a975db971.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" style="zoom: 67%;" />

          修改后网络:

          <img src="https://img.haomeiwen.com/i15877540/dea8ed4fb091718b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" style="zoom:67%;" />

    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();
    }
    

    参考

    相关文章

      网友评论

          本文标题:Ascend CANN及Pytorch使用说明(基于Atlas

          本文链接:https://www.haomeiwen.com/subject/bhrhqdtx.html