Ascend CANN及Pytorch使用說(shuō)明(基于Atlas 500 Pro)

一、簡(jiǎn)介

1.華為昇騰AI全棧簡(jiǎn)介

2022-12-14 10-22-43 的屏幕截圖.png
  • Atlas系列產(chǎn)品:提供AI訓(xùn)練辕录、推理卡及訓(xùn)練服務(wù)器.
  • CANN(異構(gòu)計(jì)算架構(gòu)):芯片算子庫(kù)和自動(dòng)化算法開(kāi)發(fā)工具肛宋。
  • ModelBox:適用于端邊云場(chǎng)景的AI推理應(yīng)用開(kāi)發(fā)框架怜校,提供標(biāo)準(zhǔn)SDK API接口。
  • MindSpore(AI框架):支持“端-邊-云”獨(dú)立和協(xié)同的統(tǒng)一訓(xùn)練和推理框架嗽交。
  • MindX SDK(昇騰SDK):行業(yè)SDK和應(yīng)用解決方案篮幢。
    • mxIndex:對(duì)于大規(guī)模特征檢索/聚類的應(yīng)用場(chǎng)景需求,基于開(kāi)源Faiss框架穷缤,提供極簡(jiǎn)易用敌蜂、高性能API。
    • mxManufacture:提供制造業(yè)視覺(jué)質(zhì)檢相關(guān)API津肛。
    • mxVision:提供智能視頻分析相關(guān)API章喉。
  • ModelArts(AI開(kāi)發(fā)平臺(tái)):華為云AI開(kāi)發(fā)平臺(tái)。
  • MindStudio(全流程開(kāi)發(fā)工具鏈):AI全流程開(kāi)發(fā)IDE身坐。

2.CANN簡(jiǎn)介

CANN(Compute Architecture for Neural Networks)是華為公司針對(duì)AI場(chǎng)景推出的異構(gòu)計(jì)算架構(gòu)秸脱,通過(guò)提供多層次的編程接口,支持用戶快速構(gòu)建基于昇騰平臺(tái)的AI應(yīng)用和業(yè)務(wù)部蛇。

  • 統(tǒng)一編程接口AscendCL適配全系列硬件摊唇。
  • 通過(guò)自動(dòng)流水、算子深度融合涯鲁、智能計(jì)算調(diào)優(yōu)巷查、自適應(yīng)梯度切分等核心技術(shù),軟硬件協(xié)同優(yōu)化撮竿,釋放硬件算力吮便。

1)CANN開(kāi)發(fā)及運(yùn)行環(huán)境

  • 開(kāi)發(fā)環(huán)境:主要用于代碼開(kāi)發(fā)笔呀、編譯幢踏、調(diào)測(cè)等開(kāi)發(fā)活動(dòng)。

    • (場(chǎng)景一)在非昇騰AI設(shè)備上安裝開(kāi)發(fā)環(huán)境许师,僅能用于代碼開(kāi)發(fā)房蝉、編譯等不依賴于昇騰設(shè)備的開(kāi)發(fā)活動(dòng)(例如ATC模型轉(zhuǎn)換、算子和推理應(yīng)用程序的純代碼開(kāi)發(fā))微渠。
    • (場(chǎng)景二)在昇騰AI設(shè)備上安裝開(kāi)發(fā)環(huán)境搭幻,支持代碼開(kāi)發(fā)和編譯,同時(shí)可以運(yùn)行應(yīng)用程序或進(jìn)行訓(xùn)練腳本的遷移逞盆、開(kāi)發(fā)&調(diào)試檀蹋。
  • 運(yùn)行環(huán)境:在昇騰AI設(shè)備上運(yùn)行用戶開(kāi)發(fā)的應(yīng)用程序或進(jìn)行訓(xùn)練腳本的遷移、開(kāi)發(fā)&調(diào)試云芦。

推理方式

  • 離線推理:是基于原有AI框架模型轉(zhuǎn)換OM模型俯逾,不依賴于AI框架執(zhí)行推理的場(chǎng)景。
  • 在線推理:是將原有AI框架做推理的應(yīng)用快速遷移至?xí)N騰AI處理器上舅逸,依賴于AI框架執(zhí)行推理的場(chǎng)景桌肴。

2)CANN 開(kāi)發(fā)輔助工具

CANN 5.0.3 開(kāi)發(fā)輔助工具指南 01

  • 精度對(duì)比工具

    • 推理場(chǎng)景中,ATC在模型轉(zhuǎn)換過(guò)程中對(duì)模型進(jìn)行了優(yōu)化琉历,包括算子消除坠七、算子融合水醋、算子拆分,可能會(huì)造成算子精度問(wèn)題彪置。
    • 訓(xùn)練場(chǎng)景中拄踪,華為支持遷移用戶原始網(wǎng)絡(luò),在昇騰910 AI處理器上訓(xùn)練拳魁,網(wǎng)絡(luò)遷移可能會(huì)造成算子精度問(wèn)題宫蛆。
  • Auto Tune調(diào)優(yōu)工具

  • 可以自動(dòng)對(duì)算子進(jìn)行性能優(yōu)化,提升算子的運(yùn)行效率的猛。

  • Profiling工具

    • 用于分析在訓(xùn)練階段或運(yùn)行在昇騰AI處理器上的APP工程各個(gè)運(yùn)行階段的關(guān)鍵性能瓶頸耀盗。
  • AI Core Error Analyzer工具

  • 可以自動(dòng)快速準(zhǔn)確地收集定位AI Core Error問(wèn)題所需的關(guān)鍵信息。

  • 腳本轉(zhuǎn)換工具

    • 可以將腳本轉(zhuǎn)換為支持在NPU上運(yùn)行的腳本卦尊,解決基于GPU的訓(xùn)練和在線推理腳本不能直接在NPU上運(yùn)行的問(wèn)題叛拷。
  • 算子及模型速查工具

    • 查詢當(dāng)前版本CANN支持的模型和算子功能
  • 推理Benchmark工具

    • 針對(duì)指定的推理模型運(yùn)行推理程序,并能夠測(cè)試推理模型的性能(包括吞吐率岂却、時(shí)延)和精度指標(biāo)忿薇。
  • 專家系統(tǒng)(MindStudio Advisor)

    • 用于聚焦模型和算子的性能調(diào)優(yōu)TOP問(wèn)題,識(shí)別性能瓶頸Pattern躏哩,重點(diǎn)構(gòu)建瓶頸分析署浩、優(yōu)化推薦模型,支撐開(kāi)發(fā)效率提升的工具扫尺。
  • 昇騰模型壓縮工具

    • 對(duì)原始網(wǎng)絡(luò)模型進(jìn)行量化(對(duì)模型的權(quán)重(weight)和數(shù)據(jù)(activation)進(jìn)行低比特處理)筋栋,節(jié)省網(wǎng)絡(luò)模型存儲(chǔ)空間、降低傳輸時(shí)延正驻、提高計(jì)算效率弊攘。
    • 無(wú)需在安裝昇騰AI處理器的服務(wù)器上運(yùn)行
      • Caffe昇騰模型壓縮工具
      • TensorFlow昇騰模型壓縮工具
      • PyTorch昇騰模型壓縮工具
      • ONNX昇騰模型壓縮工具:源模型轉(zhuǎn)量化模型
    • 須在安裝昇騰AI處理器的服務(wù)器上運(yùn)行
      • MindSpore昇騰模型壓縮工具
      • ACL昇騰模型壓縮工具:將量化模型轉(zhuǎn)換成昇騰AI處理器的離線模型。
      • TensorFlow,Ascend昇騰模型壓縮工具

    昇騰模型壓縮工具目前支持在Ubuntu 18.04.5和麒麟 V10操作系統(tǒng)安裝姑曙。

3.MindSpore

MindSpore具有編程簡(jiǎn)單襟交、端云協(xié)同、調(diào)試輕松伤靠、性能卓越捣域、開(kāi)源開(kāi)放等特點(diǎn),降低了AI開(kāi)發(fā)門檻宴合。

  • MindSpore Extend(擴(kuò)展層):MindSpore的擴(kuò)展包焕梅,社區(qū)開(kāi)發(fā)者可參與開(kāi)發(fā)。

  • MindExpression(表達(dá)層):基于Python的前端表達(dá)形纺;向用戶提供了3個(gè)不同層次的API丘侠,支撐用戶進(jìn)行網(wǎng)絡(luò)構(gòu)建、整圖執(zhí)行逐样、子圖執(zhí)行以及單算子執(zhí)行蜗字。

  • High-Level Python API:提供了訓(xùn)練推理的管理打肝、混合精度訓(xùn)練、調(diào)試調(diào)優(yōu)等高級(jí)接口挪捕。

  • Medium-Level Python API:提供網(wǎng)絡(luò)層粗梭、優(yōu)化器、損失函數(shù)等模塊级零,可靈活構(gòu)建神經(jīng)網(wǎng)絡(luò)和控制執(zhí)行流程断医,實(shí)現(xiàn)模型算法邏輯。

  • Low-Level Python API:提供張量定義奏纪、基礎(chǔ)算子鉴嗤、自動(dòng)微分等模塊,可實(shí)現(xiàn)張量定義和求導(dǎo)計(jì)算序调。

  • MindCompiler(編譯優(yōu)化層):圖層的核心編譯器醉锅,主要基于端云統(tǒng)一的MindIR實(shí)現(xiàn)三大功能:

    • 包括硬件無(wú)關(guān)的優(yōu)化(類型推導(dǎo)、自動(dòng)微分发绢、表達(dá)式化簡(jiǎn)等)
    • 硬件相關(guān)優(yōu)化(自動(dòng)并行硬耍、內(nèi)存優(yōu)化、圖算融合边酒、流水線執(zhí)行等)
    • 部署推理相關(guān)的優(yōu)化(量化经柴、剪枝等)
  • MindRT(全場(chǎng)景運(yùn)行時(shí)):含云側(cè)、端側(cè)以及更小的IoT。

二、快速部署

快速部署(22.0.RC2版本-對(duì)應(yīng)CANN 5.1.RC2 )

  • 根據(jù)官方提供容器鏡像的最高版本來(lái)選擇盾似。

基于Atlas 500 Pro 智能邊緣服務(wù)器(3000)的KylinV10SP1或 OpenEuler 20.03進(jìn)行部署。

1.不同產(chǎn)品形態(tài)的部署架構(gòu)

昇騰AI設(shè)備可分為EP和RC兩種模式鹃操。

1)Ascend EP模式

昇騰 AI 處理器的PCIe工作在從模式,則稱為EP模式春哨。

支持EP模式的產(chǎn)品:

  • 昇騰310 AI處理器:Atlas 200 AI加速模塊、Atlas 300I 推理卡恩伺、Atlas 500 智能小站赴背、Atlas 500 Pro 智能邊緣服務(wù)器、Atlas 800 推理服務(wù)器晶渠。

  • 昇騰710 AI處理器:Atlas 300I Pro 推理卡凰荚。

  • 昇騰910 AI處理器:Atlas 800 訓(xùn)練服務(wù)器、Atlas 300T 訓(xùn)練卡褒脯。

2)Ascend RC模式

昇騰 AI 處理器的PCIe工作在主模式便瑟,可以擴(kuò)展外設(shè),則稱為RC模式番川。

支持RC模式的產(chǎn)品有:Atlas 200 AI加速模塊到涂、Atlas 200 DK 開(kāi)發(fā)者套件脊框。

2.安裝前準(zhǔn)備

1)CANN社區(qū)版支持的OS清單

OS清單

產(chǎn)品型號(hào) 支持的操作系統(tǒng)
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)需要準(zhǔn)備的軟件包

軟件類型 軟件介紹
npu-firmware 固件包含昇騰AI處理器自帶的OS 、電源器件和功耗管理器件控制軟件诵棵,分別用于后續(xù)加載到AI處理器的模型計(jì)算窜护、芯片啟動(dòng)控制和功耗控制。
npu-driver 部署在昇騰服務(wù)器非春,功能類似英偉達(dá)驅(qū)動(dòng)柱徙,管理查詢昇騰AI處理器,同時(shí)為上層CANN軟件提供芯片控制奇昙、資源分配等接口护侮。
CANN 部署在昇騰服務(wù)器,功能類似英偉達(dá)CUDA储耐,包含Runtime羊初、算子庫(kù)、圖引擎什湘、媒體數(shù)據(jù)處理等組件长赞,通過(guò)AscendCL(Ascend Computing Language,昇騰計(jì)算語(yǔ)言)對(duì)外提供Device管理闽撤、Context管理得哆、Stream管理、內(nèi)存管理哟旗、模型加載與執(zhí)行贩据、算子加載與執(zhí)行、媒體數(shù)據(jù)處理等API闸餐,幫助開(kāi)發(fā)者實(shí)現(xiàn)在昇騰軟硬件平臺(tái)上開(kāi)發(fā)和運(yùn)行AI業(yè)務(wù)饱亮。CANN軟件按照功能主要分為Toolkit(開(kāi)發(fā)套件)、NNAE(深度學(xué)習(xí)引擎)舍沙、NNRT(離線推理引擎)近上、TFPlugin(TensorFlow框架插件)幾種軟件包,各軟件包支持功能范圍如下:Toolkit:支持訓(xùn)練和推理業(yè)務(wù)拂铡、模型轉(zhuǎn)換壹无、算子/應(yīng)用/模型開(kāi)發(fā)和編譯葱绒。NNAE:支持訓(xùn)練和推理業(yè)務(wù)、模型轉(zhuǎn)換格遭。NNRT:僅支持推理業(yè)務(wù)哈街。TFPlugin:用于運(yùn)行訓(xùn)練業(yè)務(wù)時(shí)和TensorFlow框架進(jìn)行對(duì)接,幫助TensorFlow框架調(diào)用底層CANN接口運(yùn)行訓(xùn)練業(yè)務(wù)拒迅。
ToolBox ToolBox包含運(yùn)維檢查工具(Acsend DMI工具)和容器引擎插件(Ascend Docker)骚秦,運(yùn)維檢查工具能夠檢測(cè)設(shè)備狀態(tài)(如帶寬、設(shè)備實(shí)時(shí)狀態(tài)等)璧微;容器引擎插件本質(zhì)上是基于OCI標(biāo)準(zhǔn)實(shí)現(xiàn)的Docker Runtime作箍,不修改Docker引擎,對(duì)Docker以插件方式提供Ascend NPU適配功能前硫,使用戶AI作業(yè)能夠以Docker容器的方式平滑運(yùn)行在昇騰設(shè)備上胞得。
  • npu-firmware:在運(yùn)行環(huán)境中安裝,依賴昇騰AI處理器屹电。
  • npu-driver:在運(yùn)行環(huán)境中安裝阶剑,依賴昇騰AI處理器。
  • toolkit:在開(kāi)發(fā)環(huán)境中安裝危号,不依賴昇騰AI處理器牧愁。
  • nnrt:離線推理引擎包,用于應(yīng)用程序的模型推理外莲。僅支持離線推理猪半,依賴昇騰AI處理器。
  • nnae:深度學(xué)習(xí)引擎偷线,支持在線訓(xùn)練磨确、在線推理、離線推理声邦。
  • toolbox:在運(yùn)行環(huán)境中安裝乏奥,依賴昇騰AI處理器。

3)下載軟件

  • 主板相關(guān)固件及驅(qū)動(dòng)【可選】:

    選擇CANN 5.1.RC2.alpha008版本

    • KylinV10SP1 驅(qū)動(dòng)包:A500-Pro-3000-iDriver_V106_KylinV10SP1.zip
    • 其他按需安裝
  • AI加速卡相關(guān)固件及驅(qū)動(dòng)

    選擇CANN 5.1.RC2.alpha008版本

    • Atlas 300I 推理卡(型號(hào):3000)驅(qū)動(dòng):A300-3000-npu-driver_5.1.rc2_linux-aarch64.run
    • Atlas 300I 推理卡(型號(hào):3000)固件:A300-3000-npu-firmware_5.1.rc2.run
  • CANN 社區(qū)版軟件包

    選擇5.1.RC2.alpha008版本

    • Toolkit(開(kāi)發(fā)套件包):Ascend-cann-toolkit_5.1.RC2_linux-aarch64.run
    • NNAE(深度學(xué)習(xí)引擎):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驅(qū)動(dòng)包翔忽、acl英融、ctrlcpu庫(kù)):Ascend-cann-device-sdk_5.1.RC2_linux-aarch64.zip
  • 實(shí)用工具包

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

3.安裝固件歇式、驅(qū)動(dòng)及軟件包

首次安裝按照“驅(qū)動(dòng) > 固件”的順序;覆蓋安裝或升級(jí)按照“固件 > 驅(qū)動(dòng)”順序胡野。

1)確認(rèn)基礎(chǔ)信息

$ 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

# 檢測(cè)Atlas 300I 推理卡(型號(hào):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)

# 確認(rèn)操作系統(tǒng)和內(nèi)核版本
$ 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)創(chuàng)建運(yùn)行用戶HwHiAiUser

# 安裝驅(qū)動(dòng)前需要?jiǎng)?chuàng)建驅(qū)動(dòng)運(yùn)行用戶(運(yùn)行驅(qū)動(dòng)進(jìn)程的用戶)
groupadd HwHiAiUser
useradd -g HwHiAiUser -d /home/HwHiAiUser -m HwHiAiUser -s /bin/bash
# 設(shè)置HwHiAiUser用戶密碼
passwd HwHiAiUser

3)安裝驅(qū)動(dòng)及固件

$ cd Atlas300I_3000_Firmware_Driver
$ chmod +x *.run

# 安裝驅(qū)動(dòng)
$ ./A300-3000-npu-driver_5.1.rc2_linux-aarch64.run  --full --install-for-all

# 查看驅(qū)動(dòng)加載是否成功
$ 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)物理機(jī)部署

# 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

# 檢測(cè)是否已安裝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

# 配置環(huán)境變量
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

# 配置環(huán)境變量
$ vi ~/.bashrc
    # 在文件最后一行后面添加
    source /usr/local/Ascend/toolbox/set_env.sh
$ source ~/.bashrc

AscendHub拉取容器鏡像

  • infer-modelzoo【推理】
    • ModelZoo 推理基礎(chǔ)鏡像材失,包含模型轉(zhuǎn)換、模型推理功能硫豆,鏡像中安裝了toolkit和sdk及其依賴的軟件龙巨,其中sdk默認(rèn)安裝的為mxmanufacture笼呆,另一個(gè)版本安裝的是mxvision
  • ascend-infer【推理】
    • Ascend-infer基礎(chǔ)鏡像旨别,基于centos7.6诗赌,ubuntu18.04制作,內(nèi)部集成推理通用的第三方庫(kù)(系統(tǒng)包秸弛、pip)和NNRT推理引擎铭若。
  • pytorch-modelzoo【訓(xùn)練+推理】
    • ModelZoo PyTorch框架基礎(chǔ)鏡像,基于PyTorch 1.5.0或 1.8.1版本制作的基礎(chǔ)鏡像递览,鏡像中安裝了nnae叼屠,包含訓(xùn)練、轉(zhuǎn)換和推理功能绞铃。
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

啟動(dòng)離線推理容器

#/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 \        # 默認(rèn)掛載加速卡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

啟動(dòng)訓(xùn)練+在線推理容器

#/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 \        # 默認(rèn)掛載加速卡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容器中進(jìn)行離線模型推理儿捧,還需要安裝cann-toolkit荚坞。

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

注意:只能同時(shí)運(yùn)行一個(gè)容器,后啟動(dòng)的容器無(wú)法使用設(shè)備資源菲盾。

5.模型推理測(cè)試

infer-modelzoo容器環(huán)境中測(cè)試

1)Ascend CANN Samples

CANN樣例倉(cāng)庫(kù)以CANN AscendCL接口進(jìn)行開(kāi)發(fā)颓影,制作的一系列給開(kāi)發(fā)者進(jìn)行參考學(xué)習(xí)的樣例。

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

# 測(cè)試圖像分類樣例
cd samples/python/level2_simple_inference/1_classification/resnet50_imagenet_classification

# 準(zhǔn)備源模型
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

# 準(zhǔn)備測(cè)試圖片
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

# 源模型轉(zhuǎn)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:制造業(yè)視覺(jué)質(zhì)檢
  • mxVision:智能視頻/圖像分析亿汞,主要功能如下:
    • 快速構(gòu)建推理業(yè)務(wù):通過(guò)修改流程編排配置文件瞭空,可快速構(gòu)建推理業(yè)務(wù),通過(guò)API調(diào)用疗我,向構(gòu)建完成的推理業(yè)務(wù)發(fā)送請(qǐng)求咆畏,得到推理結(jié)果Json字符串或者原始數(shù)據(jù)結(jié)構(gòu)。
    • 自定義功能插件:通過(guò)SDK提供的插件開(kāi)發(fā)工具和業(yè)務(wù)邏輯開(kāi)發(fā)基礎(chǔ)庫(kù)吴裤,用戶可自行開(kāi)發(fā)新插件旧找。
  • mxIndex:特征類聚與檢索

基于 infer-modelzoo容器測(cè)試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環(huán)境變量生效
bash set_env.sh

使用mxManufacture開(kāi)發(fā)一個(gè)簡(jiǎn)單的圖片分類的Demo

  • 參考快速入門

6.Ascend實(shí)用工具

1)Ascend Tools

昇騰工具倉(cāng)庫(kù)

  • msame【模型推理工具】

    輸入.om模型和模型所需要的輸入bin文件,輸出模型的輸出數(shù)據(jù)文件麦牺。

  • img2bin【bin文件生成工具】

    生成模型推理所需的輸入數(shù)據(jù)钮蛛,以.bin格式保存。

  • makesd【制卡工具】

    制卡工具包剖膳,提供ubuntu下制卡功能魏颓。

  • configure_usb_ethernet【USB虛擬網(wǎng)卡連接腳本】

    配置USB網(wǎng)卡對(duì)應(yīng)的IP地址。

  • pt2pb【pytorch模型轉(zhuǎn)tensorflow pb模型工具】

    輸入pytorch權(quán)重參數(shù)模型吱晒,轉(zhuǎn)為onnx甸饱,再轉(zhuǎn)為pb模型

  • dnmetis【NPU推理精度和性能測(cè)試工具】

    使用Python封裝ACL的C++接口,輸入om模型和原始數(shù)據(jù)集圖片、標(biāo)簽叹话,即可執(zhí)行模型推理偷遗,輸出精度數(shù)據(jù)和性能數(shù)據(jù)。

  • msquickcmp【一鍵式全流程精度比對(duì)工具】

    該工具適用于tensorflow和onnx模型驼壶,輸入原始模型和對(duì)應(yīng)的離線om模型氏豌,輸出精度比對(duì)結(jié)果。

  • precision_tool【精度問(wèn)題分析工具】

    該工具包提供了精度比對(duì)常用的功能热凹,當(dāng)前該工具主要適配Tensorflow訓(xùn)練場(chǎng)景泵喘,同時(shí)提供Dump數(shù)據(jù)/圖信息的交互式查詢和操作入口。

  • cann-benchmark_infer_scripts【cann-benchmark推理軟件對(duì)應(yīng)的模型前后處理腳本】

    該工具包含cann-benchmark推理工具模型處理腳本, 包括:結(jié)果解析腳本和前后處理腳本等碌嘀。這些腳本需根據(jù)cann-benchmark指導(dǎo)手冊(cè)說(shuō)明使用涣旨。

  • tfdbg_ascend【Tensorflow2.x dump工具】

    該工具提供CPU/GPU平臺(tái)上Tensorflow2.x運(yùn)行時(shí)數(shù)據(jù)Dump能力。

  • ais-bench_workload【ais-bench_workload】

    該目錄包含基于Ais-Bench軟件的訓(xùn)練和推理負(fù)載程序股冗,用于測(cè)試驗(yàn)證霹陡。Ais-Bench是基于AI標(biāo)準(zhǔn)針對(duì)AI服務(wù)器進(jìn)行性能測(cè)試的工具軟件。

  • intelligent_edge_tools【intelligent_edge_tools】

    該目錄包含智能邊緣工具集止状。

  • auto-optimizer【auto-optimizer】

    提供基于ONNX的改圖烹棉、自動(dòng)優(yōu)化及端到端推理流程。

  • saved_model2om【TensorFlow1.15 saved_model模型轉(zhuǎn)om模型工具】

    輸入TensorFlow存儲(chǔ)的saved_model模型怯疤,轉(zhuǎn)換為pb模型浆洗,再轉(zhuǎn)換為om模型

2) Ascend CANN Parser

Ascend CANN Parser(簡(jiǎn)稱parser)配合TF_Adapter、 ATC工具集峦、IR構(gòu)圖等使用伏社,開(kāi)發(fā)者通過(guò)以上工具,借助parser能方便地將第三方框架的算法表示轉(zhuǎn)換成Ascend IR塔淤。

3)Ascend ModelZoo

模型庫(kù)包含pytorch與tensorflow的一系列模型及腳本摘昌。

也可以通過(guò)官網(wǎng)搜索模型。

三高蜂、Ascend PyTorch 在線推理

在線推理是在AI框架內(nèi)執(zhí)行推理的場(chǎng)景聪黎,相比于離線推理場(chǎng)景,使用在線推理可以方便將原來(lái)基于PyTorch框架做推理的應(yīng)用快速遷移到昇騰AI處理器备恤,適用于數(shù)據(jù)中心推理場(chǎng)景稿饰。

1.環(huán)境準(zhǔn)備

  • 支持在線推理的芯片型號(hào)

    • Ascend310
    • Ascend310P*
    • Ascend910*
  • Ascend Pytorch版本對(duì)應(yīng)關(guān)系

  • 安裝依賴

    # 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環(huán)境依賴
    pip3 install pyyaml
    pip3 install wheel
    
  • 安裝ascend pytorch

2.運(yùn)行Ascend Pytorch在線推理樣例

1)環(huán)境準(zhǔn)備

基于pytorch-modelzoo容器運(yùn)行

  • 鏡像:ascendhub.huawei.com/public-ascendhub/pytorch-modelzoo:22.0.RC2-1.8.1
# 初始化nnae環(huán)境變量
source /usr/local/Ascend/nnae/set_env.sh

# 可選配置
    # 指定芯片的邏輯ID
    export ASCEND_DEVICE_ID=0
    # 輸出日志信息,可根據(jù)實(shí)際修改
    export ASCEND_SLOG_PRINT_TO_STDOUT=1
    # Task多線程下發(fā)
    export ASCEND_GLOBAL_LOG_LEVEL=0

2)樣例準(zhǔn)備

以ResNet50模型為例露泊,執(zhí)行在線推理樣例喉镰。

  • 下載預(yù)訓(xùn)練模型。

    打開(kāi)ModelZoo中ResNet50詳情頁(yè)惭笑,單擊該頁(yè)面的“下載模型“下載已訓(xùn)練好的模型文件梧喷。

  • 編輯推理腳本。

    創(chuàng)建“resnet50_infer_for_pytorch.py“模型腳本文件脖咐,并參考樣例代碼寫入相關(guān)代碼铺敌。

  • 執(zhí)行推理

    $ 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模型遷移與轉(zhuǎn)換

1.模型遷移

1)模型算子評(píng)估

  • 將原始模型及訓(xùn)練腳本遷移到昇騰AI處理器上之前屁擅,可以將原始模型及訓(xùn)練腳本在CPU上進(jìn)行訓(xùn)練偿凭,使用PyTorch profiler功能獲取當(dāng)前模型算子列表并在《AI框架算子支持清單》中查找該算子查看是否支持

    • 支持PyTorch1.5.0、PyTorch1.8.1派歌、PyTorch1.11.0版本算子
  • 當(dāng)有不支持算子時(shí)弯囊,可修改模型腳本用等價(jià)支持的算子替換不支持算子或者參考《自定義算子開(kāi)發(fā)指南》中“算子開(kāi)發(fā)過(guò)程>算子適配>適配插件開(kāi)發(fā)(PyTorch框架)”進(jìn)行算子適配。

2)遷移方式

將基于PyTorch的訓(xùn)練腳本遷移到昇騰AI處理器上進(jìn)行訓(xùn)練胶果,目前有以下3種方式:

  • 自動(dòng)遷移【推薦】:訓(xùn)練時(shí)匾嘱,在訓(xùn)練腳本中導(dǎo)入腳本轉(zhuǎn)換庫(kù),導(dǎo)入后執(zhí)行訓(xùn)練早抠。訓(xùn)練腳本在運(yùn)行的同時(shí)霎烙,會(huì)自動(dòng)將腳本中的CUDA接口替換為昇騰AI處理器支持的NPU接口。整體過(guò)程為:邊訓(xùn)練邊轉(zhuǎn)換蕊连。

    • 僅PyTorch 1.8.1版本及以上使用悬垃,自動(dòng)遷移方式較簡(jiǎn)單,且修改內(nèi)容最少甘苍,只需在訓(xùn)練腳本中添加引入庫(kù)代碼尝蠕。
    import torch
    import torch_npu
    .....
    from torch_npu.contrib import transfer_to_npu
    
  • 工具遷移:訓(xùn)練前,通過(guò)腳本遷移工具载庭,自動(dòng)將訓(xùn)練腳本中的CUDA接口替換為昇騰AI處理器支持的NPU接口看彼,并生成遷移報(bào)告(腳本轉(zhuǎn)換日志、不支持算子的列表囚聚、腳本修改記錄)靖榕。訓(xùn)練時(shí),運(yùn)行轉(zhuǎn)換后的腳本靡挥。整體過(guò)程為:先轉(zhuǎn)換腳本序矩,再進(jìn)行訓(xùn)練。

  • 手工遷移:算法工程師通過(guò)對(duì)模型的分析跋破、GPU與NPU代碼的對(duì)比進(jìn)而對(duì)訓(xùn)練腳本進(jìn)行修改簸淀,以支持再昇騰AI處理器上執(zhí)行訓(xùn)練。

2.AMCT模型壓縮【可選】

昇騰模型壓縮工具(Ascend Model Compression Toolkit毒返,簡(jiǎn)稱AMCT)是通過(guò)模型壓縮技術(shù)(如融合租幕,量化,張量分解等)將模型進(jìn)行壓縮的工具包拧簸,壓縮后模型體積變小劲绪,部署到昇騰 AI 處理器件上后可使能低比特運(yùn)算,提高計(jì)算效率。

AMCT基本功能使用樣例

3.導(dǎo)出ONNX模型

模型訓(xùn)練完成后贾富,保存的.pth或.pt文件可以通過(guò)PyTorch構(gòu)建模型再加載權(quán)重的方法恢復(fù)歉眷,然后導(dǎo)出ONNX模型。

import torch
import torch_npu
import torch.onnx
import torchvision.models as models
# 設(shè)置使用CPU導(dǎo)出模型
device = torch.device("cpu") 

def convert():
    # 模型定義來(lái)自于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)   #輸入數(shù)據(jù),改成自己的輸入shape

    # 模型設(shè)置為推理模式
    model.eval()

    dummy_input = torch.randn(batch_size, *input_shape) #  定義輸入shape
    torch.onnx.export(model, 
                      dummy_input, 
                      "resnet50_official.onnx", 
                      input_names = ["input"],   # 構(gòu)造輸入名
                      output_names = ["output"],    # 構(gòu)造輸出名
                      opset_version=11汗捡,    # ATC工具目前支持opset_version=9,10畏纲,11扇住,12,13
                      dynamic_axes={"input":{0:"batch_size"}, "output":{0:"batch_size"}})  #支持輸出動(dòng)態(tài)軸
                      ) 

if __name__ == "__main__":
    convert()

4.離線模型轉(zhuǎn)換

昇騰張量編譯器(Ascend Tensor Compiler盗胀,簡(jiǎn)稱ATC)是異構(gòu)計(jì)算架構(gòu)CANN體系下的模型轉(zhuǎn)換工具艘蹋, 它可以將開(kāi)源框架的網(wǎng)絡(luò)模型或Ascend IR定義的單算子描述文件(json格式)轉(zhuǎn)換為昇騰AI處理器支持的.om格式離線模型。

image
  • 開(kāi)源框架網(wǎng)絡(luò)模型經(jīng)過(guò)Parser解析后票灰,轉(zhuǎn)換為中間態(tài)IR Graph(CANN模型格式)女阀。
  • 中間態(tài)IR經(jīng)過(guò)圖準(zhǔn)備,圖拆分米间,圖優(yōu)化强品,圖編譯等一系列操作后,轉(zhuǎn)成適配昇騰AI處理器的離線模型屈糊。
  • 轉(zhuǎn)換后的離線模型上傳到板端環(huán)境的榛,通過(guò)AscendCL接口加載模型文件實(shí)現(xiàn)推理過(guò)程。
    • 可以將開(kāi)源框架網(wǎng)絡(luò)模型轉(zhuǎn)換后的離線模型轉(zhuǎn)成json文件逻锐,或者直接將開(kāi)源框架網(wǎng)絡(luò)模型通過(guò)ATC工具轉(zhuǎn)成json文件夫晌,方便文件查看。

1)不同網(wǎng)絡(luò)模型的轉(zhuǎn)換示例

  • Caffe網(wǎng)絡(luò)模型

    atc --model=$HOME/module/resnet50.prototxt --weight=$HOME/module/resnet50.caffemodel --framework=0 --output=$HOME/module/out/caffe_resnet50 --soc_version=Ascend310 
    
  • TensorFlow網(wǎng)絡(luò)模型

    atc --model=$HOME/module/resnet50_tensorflow*.pb --framework=3 --output=$HOME/module/out/tf_resnet50 --soc_version=Ascend310 
    
  • ONNX網(wǎng)絡(luò)模型

    atc --model=$HOME/module/resnet50.onnx --framework=5 --output=$HOME/module/out/onnx_resnet50 --soc_version=Ascend310 
    
    # yolov5 源模型轉(zhuǎn)離線模型示例
    
    # yolov5 源模型 轉(zhuǎn) onnx模型
    python export.py --weights yolov5l.pt --include  onnx --imgsz 640 --batch-size 1 --opset 11 --simplify
    
    # onnx模型轉(zhuǎn)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網(wǎng)絡(luò)模型

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

2)基礎(chǔ)功能參數(shù)配置

  • 模型文件轉(zhuǎn)json文件

    json文件可以查看基礎(chǔ)版本號(hào)

    # 原始模型文件轉(zhuǎn)json文件
    atc --mode=1 --om=$HOME/module/resnet50_tensorflow*.pb  --json=$HOME/module/out/tf_resnet50.json  --framework=3
    
    # 離線模型轉(zhuǎn)json文件
    atc --mode=1 --om=$HOME/module/out/tf_resnet50.om  --json=$HOME/module/out/tf_resnet50.json
    
  • 離線模型支持動(dòng)態(tài)BatchSize/動(dòng)態(tài)分辨率

    # 動(dòng)態(tài)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"  
    
    # 動(dòng)態(tài)分辨率
    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"  
    
  • 離線模型支持動(dòng)態(tài)維度

    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 
    
  • 自定義離線模型的輸入輸出數(shù)據(jù)類型

    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功能配置

# 通過(guò)--insert_op_conf參數(shù)昧诱,插入aipp預(yù)處理算子
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配置文件使用說(shuō)明

aipp_op {
       aipp_mode : static             #AIPP配置模式
       related_input_rank : 0       # 標(biāo)識(shí)對(duì)第1個(gè)輸入進(jìn)行AIPP處理【可選】
       related_input_name : "data"  # 標(biāo)識(shí)對(duì)輸入名稱為data的節(jié)點(diǎn)進(jìn)行AIPP處理【可選】
       input_format : YUV420SP_U8     #輸入給AIPP的原始圖片格式
       src_image_size_w : 250         #輸入給AIPP的原始圖片寬高
       src_image_size_h : 250
       crop: true                     #摳圖開(kāi)關(guān)晓淀,用于改變圖片尺寸
       load_start_pos_h: 0            #摳圖起始位置水平、垂直方向坐標(biāo)
       load_start_pos_w: 0
       csc_switch : true              #色域轉(zhuǎn)換開(kāi)關(guān)【可選】
       rbuv_swap_switch : false     # RGB與BGR互轉(zhuǎn)
       matrix_r0c0 : 256              #matrix:色域轉(zhuǎn)換系數(shù)盏档,用戶無(wú)需修改
       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       # 每個(gè)通道的均值【可選】
       mean_chn_1 : 0
       mean_chn_2 : 0
       var_reci_chn_0 : 0.0039216       # 每個(gè)通道方差的倒數(shù)【可選】凶掰,如:1/255
       var_reci_chn_1 : 0.0039216
       var_reci_chn_2 : 0.0039216
}
aipp_op {
    ...
}
  • 色域轉(zhuǎn)換配置表

    # YUV420SP_U8轉(zhuǎn)RGB,輸入數(shù)據(jù)為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轉(zhuǎn)BGR蜈亩,輸入數(shù)據(jù)為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轉(zhuǎn)BGR懦窘,輸入數(shù)據(jù)為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轉(zhuǎn)RGB
    aipp_op {
        aipp_mode: static
        input_format : RGB888_U8
        csc_switch : false
        rbuv_swap_switch : false
    }
    
    # RGB888_U8轉(zhuǎn)BGR
    aipp_op {
        aipp_mode : static
        input_format : RGB888_U8
        csc_switch : false
        rbuv_swap_switch : true
    }
    
  • 歸一化配置

    mean_chn_i    # 每個(gè)通道的均值
    min_chn_i # 每個(gè)通道的最小值
    var_reci_chn  # 每個(gè)通道方差的倒數(shù)
    
    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      # 左上點(diǎn)坐標(biāo)
        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像素值
    
    }
    
  • 輸入圖像大小校驗(yàn)

    # 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輸入數(shù)據(jù)格式說(shuō)明

    • 數(shù)據(jù)儲(chǔ)存格式
      • AIPP輸入默認(rèn)為NHWC排布,如果不是稚配,將強(qiáng)制轉(zhuǎn)換為NHWC畅涂。
      • 經(jīng)過(guò)AIPP處理后的圖片,統(tǒng)一采用NC1HWC0的五維數(shù)據(jù)格式進(jìn)行存儲(chǔ)道川。
    • 圖像輸入格式
      • AIPP支持的圖像輸入格式:YUV420SP_U8(NV12)午衰、RGB888_U8立宜、XRGB8888_U8、YUV400_U8臊岸。(輸入數(shù)據(jù)類型為UINT8)

4)ATC工具關(guān)鍵參數(shù)說(shuō)明

ATC工具安裝在Ascend-cann-toolkit安裝目錄/ascend-toolkit/latest/bin下橙数。

$ atc -h
===== Basic Functionality =====
[General]       # 基礎(chǔ)功能
  --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            原始網(wǎng)絡(luò)模型文件路徑
  --weight           原始網(wǎng)絡(luò)模型權(quán)重文件路徑與文件名,僅當(dāng)原始網(wǎng)絡(luò)模型是Caffe時(shí)需要指定扇单。
  --om                需要轉(zhuǎn)換為json格式的離線模型或原始模型
  --framework         Framework type. 
            0:Caffe; 
            1:MindSpore; 
            3:Tensorflow; 
            5:Onnx
  --input_format      輸入數(shù)據(jù)存儲(chǔ)格式商模。
        當(dāng)原始框架為Caffe時(shí),支持NCHW(默認(rèn))蜘澜、ND(動(dòng)態(tài)維度)
        當(dāng)原始框架為ONNX時(shí),支持NCHW(默認(rèn))响疚、NCDHW鄙信、ND
        當(dāng)原始框架是TensorFlow時(shí),支持NCHW忿晕、NHWC(默認(rèn))装诡、ND(模型轉(zhuǎn)換時(shí)根據(jù)data_format屬性的算子,推導(dǎo)出具體的format)践盼、NCDHW鸦采、NDHWC
  --input_shape       指定模型輸入數(shù)據(jù)的shape
                      E.g.: "input_name1:n1,c1,h1,w1;input_name2:n2,c2,h2,w2"
  --input_shape_range 指定模型輸入數(shù)據(jù)的shape范圍,暫不支持
                      E.g.: "input_name1:[n1~n2,c1,h1,w1];input_name2:[n2,c2~c3,h2,w2]"
  --dynamic_batch_size  設(shè)置動(dòng)態(tài)BatchSize參數(shù)咕幻,適用于執(zhí)行推理時(shí)渔伯,每次處理圖片數(shù)量不固定的場(chǎng)景。
                       E.g.: "1,2,4,8"
  --dynamic_image_size  設(shè)置輸入圖片的動(dòng)態(tài)分辨率參數(shù)肄程。適用于執(zhí)行推理時(shí)锣吼,每次處理圖片寬和高不固定的場(chǎng)景。需要與--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      設(shè)置ND格式下動(dòng)態(tài)維度的檔位玄叠。適用于執(zhí)行推理時(shí),每次處理任意維度的場(chǎng)景拓提。N<=4读恃。
                      E.g.: "dims1_n1,dims1_n2;dims2_n1,dims2_n2"
  --singleop          單算子定義文件,將單個(gè)算子Json文件轉(zhuǎn)換成適配昇騰AI處理器的離線模型代态。以便進(jìn)行后續(xù)的單算子功能驗(yàn)證寺惫。

[Output]
  --output            Output file path
  --output_type       指定某個(gè)輸出節(jié)點(diǎn)的輸出類型,需要與--out_nodes參數(shù)配合使用胆数。
                FP32:推薦分類網(wǎng)絡(luò)柑贞、檢測(cè)網(wǎng)絡(luò)使用蕉堰。
                UINT8:推薦圖像超分辨率網(wǎng)絡(luò)使用。
                FP16:推薦分類網(wǎng)絡(luò)、檢測(cè)網(wǎng)絡(luò)使用。通常用于一個(gè)網(wǎng)絡(luò)輸出作為另一個(gè)網(wǎng)絡(luò)輸入場(chǎng)景所灸。
                        E.g.: --output_type="conv1:0:FP16"  --out_nodes="conv1:0".
  --check_report      預(yù)檢結(jié)果保存文件路徑
  --json              離線模型或原始模型文件轉(zhuǎn)換的json格式文件

[Target]
  --soc_version       The soc version.
          Ascend310
          Ascend910
  --virtual_type      是否支持離線模型在算力分組生成的虛擬設(shè)備上運(yùn)行。
                      0 (default) : Disable virtualization; 1 : Enable virtualization.
  --core_type         設(shè)置網(wǎng)絡(luò)模型使用的Core類型
            VectorCore: use vector core. 
            AiCore: Default 
  --aicore_num        設(shè)置模型編譯時(shí)使用的aicore數(shù)量


===== Advanced Functionality =====
[Feature]       # 功能配置選項(xiàng)
  --out_nodes         指定某層輸出節(jié)點(diǎn)(算子)作為網(wǎng)絡(luò)模型的輸出,如果不指定育谬,則模型的輸出默認(rèn)為最后一層的算子信息。適合算子調(diào)試帮哈。
                      E.g.: "node_name1:0;node_name1:1;node_name2:0"
  --input_fp16_nodes 指定輸入數(shù)據(jù)類型為FP16的輸入節(jié)點(diǎn)名稱膛檀。 配置了該參數(shù),則不能對(duì)同一個(gè)輸入節(jié)點(diǎn)同時(shí)使用--insert_op_conf參數(shù)娘侍。
                      E.g.: "node_name1;node_name2"
  --insert_op_conf    插入新算子的配置文件咖刃,例如aipp預(yù)處理算子。使用該參數(shù)后憾筏,則輸入數(shù)據(jù)類型為UINT8嚎杨。
  --op_name_map      擴(kuò)展算子(非標(biāo)準(zhǔn)算子)映射配置文件

  --is_input_adjust_hw_layout    與--input_fp16_nodes配合使用。若該參數(shù)設(shè)置為true氧腰,對(duì)應(yīng)--input_fp16_nodes節(jié)點(diǎn)的輸入數(shù)據(jù)類型為float16枫浙,輸入數(shù)據(jù)格式為NC1HWC0。
  --is_output_adjust_hw_layout   與--out_nodes配合使用古拴。若該參數(shù)設(shè)置為true箩帚,對(duì)應(yīng)--out_nodes中輸出節(jié)點(diǎn)的輸出數(shù)據(jù)類型為float16,數(shù)據(jù)格式為NC1HWC0黄痪。

[Model Tuning]      # 模型調(diào)優(yōu)選項(xiàng)
  --disable_reuse_memory    內(nèi)存復(fù)用開(kāi)關(guān)
  --fusion_switch_file      融合規(guī)則(包括圖融合和UB融合)開(kāi)關(guān)配置文件
  --enable_scope_fusion_passes   指定編譯時(shí)需要生效的融合規(guī)則列表
  --enable_single_stream    是否使能一個(gè)模型推理時(shí)只能使用一條Stream紧帕。 
                true: enable; 
                false(default): disable
  --enable_small_channel    是否使能small channel的優(yōu)化,使能后在channel<=4的卷積層會(huì)有性能收益满力。建議與--insert_op_conf參數(shù)(AIPP功能)配合使用
                0(default): disable; 
                1: enable
  --enable_compress_weight  Enable compress weight. true: enable; false(default): disable
  --compress_weight_conf    壓縮權(quán)重的配置文件
  --compression_optimize_conf    壓縮優(yōu)化功能配置文件焕参,暫不支持。
  --sparsity                Optional; enable structured sparse. 0(default): disable; 1: enable
  --buffer_optimize        數(shù)據(jù)緩存優(yōu)化開(kāi)關(guān)
            "l2_optimize" (default), 
            "l1_optimize", 
            "off_optimize"
  --mdl_bank_path           加載子圖調(diào)優(yōu)后自定義知識(shí)庫(kù)的路徑
  
[Operator Tuning]       # 算子調(diào)優(yōu)選項(xiàng)
  --op_precision_mode     設(shè)置具體某個(gè)算子的精度模式油额,通過(guò) (.ini)配置文件設(shè)置叠纷。
  --precision_mode        設(shè)置網(wǎng)絡(luò)模型的精度模式。支持如下:
            force_fp16(default), 
            force_fp32, allow_mix_precision, 
            allow_fp32_to_fp16, must_keep_origin_dtype.
  --modify_mixlist       混合精度場(chǎng)景下潦嘶,修改算子使用混合精度名單涩嚣。
  --keep_dtype            保持原始模型編譯時(shí)個(gè)別算子的計(jì)算精度不變。
  --customize_dtypes      模型編譯時(shí)自定義算子的計(jì)算精度掂僵。
  --auto_tune_mode        設(shè)置算子的自動(dòng)調(diào)優(yōu)模式航厚。
                    E.g.: "GA,RL", support configure multiple, spit by ,
  --op_bank_path          加載Auto Tune調(diào)優(yōu)后自定義知識(shí)庫(kù)的路徑。
  --op_select_implmode   選擇算子是高精度實(shí)現(xiàn)還是高性能實(shí)現(xiàn)锰蓬。支持如下: 
            high_precision, 
            high_performance,   default
            high_precision_for_all, 
            high_performance_for_all. 
  --optypelist_for_implmode    列舉算子optype的列表幔睬,該列表中的算子使用--op_select_implmode參數(shù)指定的模式。                      E.g.: "node_name1,node_name2"
  --op_debug_level        TBE算子編譯debug功能開(kāi)關(guān)芹扭。
                          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

五麻顶、離線推理應(yīng)用開(kāi)發(fā)

1.AscendCL

AscendCL(Ascend Computing Language)是一套用于在昇騰平臺(tái)上開(kāi)發(fā)深度神經(jīng)網(wǎng)絡(luò)推理應(yīng)用的C語(yǔ)言API庫(kù)赦抖,提供Device管理、Context管理辅肾、Stream管理队萤、內(nèi)存管理、模型加載與執(zhí)行矫钓、算子加載與執(zhí)行要尔、媒體數(shù)據(jù)處理等C語(yǔ)言API庫(kù)。

在運(yùn)行應(yīng)用時(shí)新娜,AscendCL調(diào)用GE執(zhí)行器提供的接口實(shí)現(xiàn)模型和算子的加載與執(zhí)行赵辕、調(diào)用運(yùn)行管理器的接口實(shí)現(xiàn)Device管理、Context管理杯活、Stream管理匆帚、內(nèi)存管理等。

計(jì)算資源層是昇騰AI處理器的硬件算力基礎(chǔ)旁钧,主要完成神經(jīng)網(wǎng)絡(luò)的矩陣相關(guān)計(jì)算、完成控制算子/標(biāo)量/向量等通用計(jì)算和執(zhí)行控制功能互拾、完成圖像和視頻數(shù)據(jù)的預(yù)處理歪今,為深度神經(jīng)網(wǎng)絡(luò)計(jì)算提供了執(zhí)行上的保障。

pyACL(Python Ascend Computing Language)就是在AscendCL的基礎(chǔ)上使用CPython封裝得到的Python API庫(kù)颜矿。

  • 邏輯架構(gòu)圖:

1)接口調(diào)用流程

  1. AscendCL初始化寄猩。

    調(diào)用acl.init接口實(shí)現(xiàn)初始化pyACL。

  2. 運(yùn)行管理資源申請(qǐng)骑疆。

    依次申請(qǐng)運(yùn)行管理資源:Device田篇、Context、Stream箍铭。

  3. 算子調(diào)用

    • 加載算子om文件泊柬,運(yùn)行算子時(shí)使用。
    • 執(zhí)行算子诈火,輸出算子的運(yùn)行結(jié)果兽赁。
  4. 模型推理。

    • 模型加載
    • (可選)數(shù)據(jù)預(yù)處理:可實(shí)現(xiàn)JPEG圖片解碼冷守、視頻解碼刀崖、摳圖/圖片縮放/格式轉(zhuǎn)換、JPEG圖片編碼拍摇、視頻編碼等功能亮钦。參見(jiàn)AIPP與DVPP。
    • 模型推理
    • (可選)數(shù)據(jù)后處理:處理模型推理的結(jié)果充活。
    • 模型卸載:調(diào)用acl.mdl.unload接口卸載模型蜂莉。
  5. 運(yùn)行管理資源釋放蜡娶。

    所有數(shù)據(jù)處理都結(jié)束后,需要依次釋放運(yùn)行管理資源:Stream巡语、Context翎蹈、Device。

  6. pyACL去初始化男公。

    調(diào)用acl.finalize接口實(shí)現(xiàn)pyACL去初始化荤堪。

2.預(yù)處理模塊AIPP與DVPP

1)AIPP

AIPP(Artificial Intelligence Pre-Processing)在AI Core上完成數(shù)據(jù)預(yù)處理,主要功能包括改變圖像尺寸(Crop/Padding配置)枢赔、色域轉(zhuǎn)換(轉(zhuǎn)換圖像格式)澄阳、歸一化配置(減均值/乘系數(shù))等√ぐ荩可通過(guò)ATC工具配置模型的AIPP功能碎赢。

AIPP使能模式:

  • 靜態(tài)AIPP:模型生成后,AIPP參數(shù)值被保存在離線模型中速梗,每次模型推理過(guò)程采用固定的AIPP預(yù)處理參數(shù)進(jìn)行處理肮塞,而且在之后的推理過(guò)程中無(wú)法通過(guò)業(yè)務(wù)代碼進(jìn)行直接的修改。
  • 動(dòng)態(tài)AIPP:每次模型推理前姻锁,根據(jù)需求枕赵,在執(zhí)行模型前設(shè)置動(dòng)態(tài)AIPP參數(shù)值,然后在模型執(zhí)行時(shí)可使用不同的AIPP參數(shù)位隶。動(dòng)態(tài)AIPP參數(shù)值會(huì)根據(jù)需求在不同的業(yè)務(wù)場(chǎng)景下選用合適的參數(shù)(如不同攝像頭采用不同的歸一化參數(shù)拷窜,輸入圖片格式需要兼容YUV420和RGB等)。

AIPP支持的圖像輸入格式:

  • YUV420SP_U8涧黄、RGB888_U8篮昧、XRGB8888_U8、YUV400_U8笋妥。

2)DVPP

DVPP(Digital Vision Pre-Processor)是昇騰AI處理器內(nèi)置的圖像處理單元懊昨,通過(guò)pyACL媒體數(shù)據(jù)處理接口提供強(qiáng)大的媒體處理硬加速能力,主要功能包括縮放挽鞠、摳圖疚颊、格式轉(zhuǎn)換、圖片編解碼信认、視頻編解碼等材义。

  • pyACL提供了基于DVPP硬件的媒體數(shù)據(jù)處理接口

    功能 說(shuō)明
    VPC(Vision Preprocessing Core) 處理YUV、RGB等格式的圖片嫁赏,包括縮放其掂、摳圖、圖像金字塔潦蝇、色域轉(zhuǎn)換等款熬。
    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處理器對(duì)媒體數(shù)據(jù)處理V1版本各功能的支持度

    昇騰AI處理器 VPC JPEGD JPEGE PNGD VDEC VENC
    昇騰310 AI處理器
    昇騰910 AI處理器 x
    昇騰310P AI處理器

3)AIPP與DVPP區(qū)別

  • DVPP對(duì)輸入殉簸、輸出有特殊的限制(基于處理速度和處理占有量的考慮)闰集,對(duì)輸出圖片的寬高有對(duì)齊要求,且其輸出格式通常為YUV420SP等格式般卑。
  • AIPP能力是對(duì)DVPP能力的有效補(bǔ)充武鲁,AIPP主要用于在AI Core上完成數(shù)據(jù)預(yù)處理,AIPP提供色域轉(zhuǎn)換功能蝠检、Crop(摳圖)和Padding(補(bǔ)邊)功能沐鼠,可以輸出色域轉(zhuǎn)換和固定大小的圖片。
  • 處理順序:原圖/視頻流 -> DVPP -> AIPP -> 模型推理叹谁。

3.Python推理

基于現(xiàn)有模型饲梭,使用pyACL提供的Python語(yǔ)言API庫(kù)開(kāi)發(fā)深度神經(jīng)網(wǎng)絡(luò)應(yīng)用,用于實(shí)現(xiàn)目標(biāo)識(shí)別焰檩、圖像分類等功能排拷。

1)推理過(guò)程

# 導(dǎo)入acl模塊
import acl  

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

# 2.運(yùn)行管理資源申請(qǐng)(Device、Context及Stream)
self.device_id = 0
# 指定運(yùn)算的Device锅尘。
ret = acl.rt.set_device(self.device_id)
# 顯式創(chuàng)建一個(gè)Context,用于管理Stream對(duì)象布蔗。
self.context, ret = acl.rt.create_context(self.device_id)

# 3.加載模型藤违,并獲取模型描述信息
# 初始化變量。
self.model_path = './model/resnet50.om'
# 加載離線模型文件纵揍,返回標(biāo)識(shí)模型的ID顿乒。
self.model_id, ret = acl.mdl.load_from_file(self.model_path)
# 根據(jù)加載成功的模型的ID,獲取該模型的描述信息泽谨。
self.model_desc = acl.mdl.create_desc()
ret = acl.mdl.get_desc(self.model_desc, self.model_id)

# 4.準(zhǔn)備模型推理的輸入璧榄、輸出數(shù)據(jù)結(jié)構(gòu)
# 初始化變量。
ACL_MEM_MALLOC_HUGE_FIRST = 0

# 創(chuàng)建aclmdlDataset類型的數(shù)據(jù)吧雹,描述模型推理的輸入骨杂。
self.load_input_dataset = acl.mdl.create_dataset()
# 獲取模型輸入的數(shù)量。
input_size = acl.mdl.get_num_inputs(self.model_desc)
self.input_data = []
# 循環(huán)為每個(gè)輸入申請(qǐng)內(nèi)存雄卷,并將每個(gè)輸入添加到aclmdlDataset類型的數(shù)據(jù)中搓蚪。
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)
    # 申請(qǐng)輸入內(nè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})

# 準(zhǔn)備模型推理的輸出數(shù)據(jù)集丁鹉。
# 創(chuàng)建aclmdlDataset類型的數(shù)據(jù)妒潭,描述模型推理的輸出悴能。
self.load_output_dataset = acl.mdl.create_dataset()
# 獲取模型輸出的數(shù)量。
output_size = acl.mdl.get_num_outputs(self.model_desc)
self.output_data = []
# 循環(huán)為每個(gè)輸出申請(qǐng)內(nèi)存雳灾,并將每個(gè)輸出添加到aclmdlDataset類型的數(shù)據(jù)中漠酿。
for i in range(output_size):
    buffer_size = acl.mdl.get_output_size_by_index(self.model_desc, i)
    # 申請(qǐng)輸出內(nè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.準(zhǔn)備模型推理的輸入數(shù)據(jù)
img = cv2,imread("test.jpg")
# img前處理
bytes_data = img.tobytes()
np_ptr = acl.util.bytes_to_ptr(bytes_data)
# 將圖片數(shù)據(jù)從Host傳輸?shù)紻evice谎亩。同步內(nèi)存復(fù)制
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.執(zhí)行模型推理炒嘲。
# self.model_id表示模型ID,在模型加載成功后团驱,會(huì)返回標(biāo)識(shí)模型的ID摸吠。
ret = acl.mdl.execute(self.model_id, self.load_input_dataset, self.load_output_dataset)

# 7.處理模型推理的輸出數(shù)據(jù)。
inference_result = []
for i, item in enumerate(self.output_data):
    buffer_host, ret = acl.rt.malloc_host(self.output_data[i]["size"])
    # 將推理輸出數(shù)據(jù)從Device傳輸?shù)紿ost嚎花。同步內(nèi)存復(fù)制
    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)
    # 將指針轉(zhuǎn)換bytes對(duì)象
    bytes_out = acl.util.ptr_to_bytes(buffer_host, self.output_data[i]["size"])
    # bytes轉(zhuǎn)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.釋放模型推理的輸入寸痢、輸出資源。
# 釋放輸入資源紊选,包括數(shù)據(jù)結(jié)構(gòu)和內(nèi)存啼止。
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)

# 釋放輸出資源,包括數(shù)據(jù)結(jié)構(gòu)和內(nèi)存兵罢。
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()
  • 同步內(nèi)存復(fù)制

    # 1.申請(qǐng)內(nèi)存。
    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.申請(qǐng)內(nèi)存后裆赵,可向內(nèi)存中讀入數(shù)據(jù)东囚,該自定義函數(shù)fead_file由用戶實(shí)現(xiàn)。
    fead_file(fileName, host_ptr_a, size)
    
    # 3.同步內(nèi)存復(fù)制战授。
    #host_ptr_a表示Host上源內(nèi)存地址指針页藻,dev_ptr_b表示Device上目的內(nèi)存地址指針,size表示內(nèi)存大小植兰。
    # ACL_MEMCPY_HOST_TO_DEVICE = 1
    ret = acl.rt.memcpy(dev_ptr_b, size, host_ptr_a, size, ACL_MEMCPY_HOST_TO_DEVICE)
    
    # 4.使用完內(nèi)存中的數(shù)據(jù)后份帐,需及時(shí)釋放資源。
    ret = acl.rt.free_host(host_ptr_a)
    ret = acl.rt.free(dev_ptr_b)
    
  • 異步內(nèi)存復(fù)制

    # 1.申請(qǐng)內(nèi)存钉跷。
    size = 1 * 1024 * 1024
    # 異步內(nèi)存復(fù)制要求弥鹦,內(nèi)存首地址64字節(jié)對(duì)齊,使用acl.rt.malloc_host 需多申請(qǐng)64字節(jié)。
    host_ptr_a, ret = acl.rt.malloc_host(size + 64)
    # host申請(qǐng)的內(nèi)存需要用戶自己64對(duì)齊處理彬坏。
    host_align = host_ptr_a + 64 - host_ptr_a % 64
    # acl.rt.malloc 申請(qǐng)的Device 側(cè)內(nèi)存系統(tǒng)保證已經(jīng)符合64對(duì)齊朦促。
    dev_ptr_b, ret = acl.rt.malloc(size, ACL_MEM_MALLOC_NORMAL_ONLY)
    
    # 2.申請(qǐng)內(nèi)存后,可向內(nèi)存中讀入數(shù)據(jù)栓始,該自定義函數(shù)fead_file由用戶實(shí)現(xiàn)务冕。
    fead_file(fileName, host_align, size)
    
    # 3.異步內(nèi)存復(fù)制。
    # host_align 表示Host上源內(nèi)存地址指針幻赚,dev_ptr_b表示Device上目的內(nèi)存地址指針禀忆,size表示內(nèi)存大小。
    # 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.使用完內(nèi)存中的數(shù)據(jù)后箩退,需及時(shí)釋放資源。
    ret = acl.rt.destroy_stream(stream)
    ret = acl.rt.free_host(host_ptr_a)
    ret = acl.rt.free(dev_ptr_b)
    
  • 多模型推理注意:一個(gè)進(jìn)程內(nèi)只能調(diào)用一次acl.init和acl.finalize接口佳谦。

2)官方參考樣例

  • ascendcl-samples: 以CANN AscendCL接口進(jìn)行開(kāi)發(fā)的樣例庫(kù)戴涝。

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

    • modelzoo-GPL/ACL_Pytorch/Yolov5_for_Pytorch:對(duì)ACL_Pytorch的YoloV3/V5/V7的補(bǔ)充钻蔑。

      • 由于slice+concat算子在Ascend AI框架下耗時(shí)比較高啥刻,所以YoloV5模型想要加速需要把slice+concat算子功能放到CPU實(shí)現(xiàn)。

        源模型網(wǎng)絡(luò):

        <img src="https://upload-images.jianshu.io/upload_images/15877540-48decc4a975db971.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" style="zoom: 67%;" />

        修改后網(wǎng)絡(luò):

        <img src="https://upload-images.jianshu.io/upload_images/15877540-dea8ed4fb091718b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" style="zoom:67%;" />

4.C&C++ 推理

1)頭文件和庫(kù)文件說(shuō)明

AscendCL頭文件在“CANN軟件安裝后文件存儲(chǔ)路徑/include/”目錄下咪笑,AscendCL庫(kù)文件在“CANN軟件安裝后文件存儲(chǔ)路徑/lib64/”目錄下可帽。

定義接口的頭文件 用途 對(duì)應(yīng)的庫(kù)文件
acl/acl_base.h 用于定義基本的數(shù)據(jù)類型(例如aclDataBuffer、aclTensorDesc等)及其操作接口窗怒、枚舉值(例如aclFormat)映跟、日志管理接口等。 libascendcl.so
acl/acl.h 該頭文件中已包含acl/acl_mdl.h扬虚、acl/acl_rt.h申窘、acl/acl_op.h】字幔可以引用初始化/去初始化、Device管理碎捺、算力Group查詢與設(shè)置路鹰、Context管理、Stream管理收厨、同步等待晋柱、內(nèi)存管理、模型加載與執(zhí)行诵叁、算子編譯(不包括aclopCompile接口)雁竞、算子加載與執(zhí)行(不包括aclopCompileAndExecute接口)等接口。 libascendcl.so
acl/acl_prof.h 用于定義Profiling配置的接口。 libmsprofiler.so
acl/ops/acl_cblas.h 用于定義CBLAS接口碑诉。 libacl_cblas.so
acl/ops/acl_dvpp.h 用于定義媒體數(shù)據(jù)處理V1版本的接口彪腔。 libacl_dvpp.so
acl/ops/acl_fv.h 用于定義特征向量檢索的接口。昇騰310 AI處理器进栽,當(dāng)前不支持引用該頭文件中的接口德挣。昇騰910 AI處理器,當(dāng)前不支持引用該頭文件中的接口快毛。 libacl_retr.so
acl/acl_op_compiler.h 用于定義aclopCompile格嗅、aclopCompileAndExecute、aclSetCompileopt等算子在線編譯相關(guān)的接口唠帝、數(shù)據(jù)類型屯掖、枚舉值等。 libacl_op_compiler.so
acl/acl_tdt.h 用于定義Tensor數(shù)據(jù)傳輸接口襟衰。昇騰310 AI處理器贴铜,當(dāng)前不支持引用該頭文件中的接口。 libacl_tdt_channel.so
acl/acl_tdt_queue.h 用于定義共享隊(duì)列管理右蒲、共享Buffer管理接口阀湿。預(yù)留功能,當(dāng)前暫不支持引用該頭文件中的接口瑰妄。 libacl_tdt_queue.so
acl/dvpp/hi_dvpp.h 用于定義媒體數(shù)據(jù)處理V2版本的接口陷嘴。 libacl_dvpp_mpi.so

2)推理過(guò)程

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

using namespace std;

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

//申請(qǐng)內(nèi)存,使用C/C++標(biāo)準(zhǔn)庫(kù)的函數(shù)將測(cè)試圖片讀入內(nèi)存
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();
}

//申請(qǐng)Device側(cè)的內(nèi)存间坐,再以內(nèi)存復(fù)制的方式將內(nèi)存中的圖片數(shù)據(jù)傳輸?shù)紻evice
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初始化灾挨、運(yùn)行管理資源申請(qǐng)(指定計(jì)算設(shè)備)
    aclError ret;
    ret = aclInit(nullptr);
    ret = aclrtSetDevice(deviceId);
    
    // 2.加載模型
    const char *modelPath = "../model/resnet50.om";
    ret = aclmdlLoadFromFile(modelPath, &modelId);
    // 創(chuàng)建模型描述信息
    modelDesc =  aclmdlCreateDesc();
    ret = aclmdlGetDesc(modelDesc, modelId);
    
    // 3.將測(cè)試圖片數(shù)據(jù)讀入內(nèi)存,并傳輸?shù)紻evice側(cè)竹宋,用于后續(xù)推理使用
    const char *picturePath = "../data/dog1_1024_683.bin";
    ReadPictureTotHost(picturePath);
    CopyDataFromHostToDevice();
    
    //4.準(zhǔn)備模型推理的輸入輸出數(shù)據(jù)結(jié)構(gòu)
    // 創(chuàng)建aclmdlDataset類型的數(shù)據(jù)劳澄,描述模型推理的輸入
    inputDataSet = aclmdlCreateDataset();
    inputDataBuffer = aclCreateDataBuffer(pictureDeviceData, pictureDataSize);
    ret = aclmdlAddDatasetBuffer(inputDataSet, inputDataBuffer);
    
    // 創(chuàng)建aclmdlDataset類型的數(shù)據(jù),描述模型推理的輸出
    outputDataSet = aclmdlCreateDataset();
    // 獲取模型輸出數(shù)據(jù)需占用的內(nèi)存大小蜈七,單位為Byte
    outputDataSize = aclmdlGetOutputSizeByIndex(modelDesc, 0);
    // 申請(qǐng)輸出內(nèi)存
    ret = aclrtMalloc(&outputDeviceData, outputDataSize, ACL_MEM_MALLOC_HUGE_FIRST);
    outputDataBuffer = aclCreateDataBuffer(outputDeviceData, outputDataSize);
    ret = aclmdlAddDatasetBuffer(outputDataSet, outputDataBuffer);
    
    // 5.執(zhí)行推理
    ret = aclmdlExecute(modelId, inputDataSet, outputDataSet);
    
    // 6.獲取推理結(jié)果數(shù)據(jù)
    ret = aclrtMallocHost(&outputHostData, outputDataSize);
    ret = aclrtMemcpy(outputHostData, outputDataSize, outputDeviceData, outputDataSize, ACL_MEMCPY_DEVICE_TO_HOST);
    // 將內(nèi)存中的數(shù)據(jù)轉(zhuǎn)換為float類型
    float* outFloatData = reinterpret_cast<float *>(outputHostData);
    
    // 7.釋放模型描述信息秒拔,卸載模型
    aclmdlDestroyDesc(modelDesc);
    aclmdlUnload(modelId);
    
    // 8.釋放內(nèi)存、銷毀推理相關(guān)的數(shù)據(jù)類型
    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.計(jì)算設(shè)備釋放飒硅,AscendCL去初始化
    aclError ret = aclrtResetDevice(deviceId);
    aclFinalize();
}

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末砂缩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子三娩,更是在濱河造成了極大的恐慌庵芭,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雀监,死亡現(xiàn)場(chǎng)離奇詭異双吆,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門好乐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)匾竿,“玉大人,你說(shuō)我怎么就攤上這事曹宴÷С龋” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵笛坦,是天一觀的道長(zhǎng)区转。 經(jīng)常有香客問(wèn)我,道長(zhǎng)版扩,這世上最難降的妖魔是什么废离? 我笑而不...
    開(kāi)封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮礁芦,結(jié)果婚禮上蜻韭,老公的妹妹穿的比我還像新娘。我一直安慰自己柿扣,他們只是感情好肖方,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著未状,像睡著了一般俯画。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上司草,一...
    開(kāi)封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天艰垂,我揣著相機(jī)與錄音,去河邊找鬼埋虹。 笑死猜憎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的搔课。 我是一名探鬼主播胰柑,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼爬泥!你這毒婦竟也來(lái)了旦事?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤急灭,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后谷遂,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體葬馋,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了畴嘶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛋逾。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖窗悯,靈堂內(nèi)的尸體忽然破棺而出区匣,到底是詐尸還是另有隱情,我是刑警寧澤蒋院,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布亏钩,位于F島的核電站,受9級(jí)特大地震影響欺旧,放射性物質(zhì)發(fā)生泄漏姑丑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一辞友、第九天 我趴在偏房一處隱蔽的房頂上張望栅哀。 院中可真熱鬧,春花似錦称龙、人聲如沸留拾。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)痴柔。三九已至,卻和暖如春马昨,著一層夾襖步出監(jiān)牢的瞬間竞帽,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工鸿捧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屹篓,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓匙奴,卻偏偏與公主長(zhǎng)得像堆巧,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子泼菌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容