SophonSDK開發(fā)說(shuō)明

一、Sophon服務(wù)器及芯片簡(jiǎn)介

算能官網(wǎng)產(chǎn)品及開發(fā)資料

1.AI芯片

  • SOPHON BM1684

    • 算力:17.6 TOPS INT8鳖粟;2.2 TFLOPS FP32【不支持FP16】
    • Video Decode:32x 1080p30 (H.264/H.265)
    • Video Encode:2x 1080p30 (H.264/H.265)
    • Memory:12GB LPDDR4x
  • SOPHON BM1684X

    • CPU:8核ARM A53 2.3GHz
    • 算力:32 TOPS INT8衰猛;16 TFLOPS FP16/BF16;2 TFLOPS FP32
    • Memory:12GB LPDDR4x 128bit 68.3GB/s
    • Video Decode:32x 1080p30 (H.264/H.265)
    • Video Encode:12x 1080p30 (H.264/H.265)

2.AI服務(wù)器

  • AI微服務(wù)器SE6-192

    • 搭載國(guó)產(chǎn) TPU 芯片 BM1684无切,可選配兩塊算力板(簡(jiǎn)稱 SE6-192)或一塊算力板(簡(jiǎn)稱 SE6-96)

      • SE6-192:12張BM1684
      • SE6-96:6張BM1684
    • CPU:

      • 主控:8核ARM A53 2.3GHz
      • 算力節(jié)點(diǎn):12/6 * 8核ARM A53 2.3GHz
    • Memory:

      • 主控:12GB LPDDR4x
      • 算力節(jié)點(diǎn):12/6 *12GB LPDDR4x
        • 每個(gè)計(jì)算模組中荡短,4GB專用于TPU計(jì)算加速;4GB專用于視頻圖像編解碼加速哆键;4GB可用于系統(tǒng)內(nèi)存掘托。
    • 磁盤:

      • 主控:32GB EMMC
      • 算力節(jié)點(diǎn):12/6 * 32GB EMMC
    • 網(wǎng)絡(luò)拓?fù)?/p>

      • eth0 的 ip 為 172.16.140.200 痹束。 算 力 板 0 的 6 塊 核 心 板 ip 為 172.16.140.11 ~
        172.16.140.16。
        • ssh端口映射:10021~10026像捶,用戶名密碼均為linaro缸兔。
      • eth1 的 ip 為 172.16.150.200 卖氨。 算 力 板 1 的 6 塊 核 心 板 ip 為 172.16.150.11 ~
        172.16.150.16笑窜。
        • ssh端口映射:20021~20026尔当,用戶名密碼均為linaro配喳。

二识补、SophonSDK簡(jiǎn)介

https://github.com/sophon-ai-algo

https://github.com/sophgo【舊版】

SophonSDK 開發(fā)指南

SophonSDK是算能科技基于其自主研發(fā)的 AI 芯片所定制的深度學(xué)習(xí) SDK族淮,涵蓋了神經(jīng)網(wǎng)絡(luò)推理階段所需的模型優(yōu)化、高效運(yùn)行支持等能力凭涂,為深度學(xué)習(xí)應(yīng)用開發(fā)和部署提供易用祝辣、高效的全棧式解決方案。

SophonSDK既兼容第三代BM1684芯片切油,也支持第四代BM1684X芯片蝙斜,目前僅支持Linux版本。

1.主要功能模塊

主要模塊開發(fā)資料

  • 硬件驅(qū)動(dòng)及運(yùn)行時(shí)庫(kù) LIBSOPHON : 包含BMCV澎胡、BMRuntime孕荠、BMLib等庫(kù),用來(lái)驅(qū)動(dòng)VPP攻谁、TPU等硬件稚伍,完成圖像處理、張量運(yùn)算戚宦、模型推理等操作个曙。

  • 多媒體庫(kù) SOPHON-MW : 支持Sophon設(shè)備硬件加速的BM-OpenCV和BM-FFmpeg,支持RTSP流受楼、GB28181流的解析垦搬,視頻及圖片的編解碼。

    算法步驟 支持硬件加速 BM-OpenCV BM-FFmpeg Native接口
    視頻/圖片編解碼 支持 Y Y BMCV(圖片)/SAIL
    輸入預(yù)處理 支持 Y N BMCV/SAIL
    模型推理 支持 N N BMRuntime/SAIL
    輸出后處理 部分支持 N N BMCV
  • 模型編譯量化工具鏈 TPU-NNTC : 支持Caffe艳汽、Tensorflow猴贰、Pytorch、MXNet骚灸、 Darknet糟趾、Paddle Paddle、ONNX等框架模型的模型轉(zhuǎn)換甚牲;支持模型量化:原始模型 -> FP32 UModel -> INT8 UModel -> INT8 BModel义郑, 同時(shí)提供 auto-cali 自動(dòng)量化工具。

  • 張量運(yùn)算及圖像處理庫(kù) BMCV : 色彩空間轉(zhuǎn)換丈钙、尺度變換非驮、仿射變換、投射變換雏赦、線性變換劫笙、畫框芙扎、JPEG編碼、BASE64編碼填大、NMS戒洼、排序、特征匹配允华。

  • 設(shè)備管理 BMLib : 基礎(chǔ)接口:設(shè)備Handle的管理圈浇,內(nèi)存管理、數(shù)據(jù)搬運(yùn)靴寂、API的發(fā)送和同步磷蜀、A53使能等

  • AI加速庫(kù) SAIL : 支持Python/C++的高級(jí)接口,是對(duì)BMRuntime百炬、BMCV褐隆、BMDecoder等底層庫(kù)接口的封裝。

  • 自定義算子高級(jí)編程庫(kù) BMLang:基于C++的面向Sophon TPU的高級(jí)編程庫(kù)剖踊,與硬件信息解耦庶弃,無(wú)需了解硬件架構(gòu),使用張量數(shù)據(jù)(bmlang::Tensor)和計(jì)算操作(bmlang::Operator)編寫代碼蜜宪,最后使用bmlang::compile或bmlang::compile_with_check來(lái)生成TPU可以運(yùn)行的BModel虫埂;此外也支持使用BM168X中的arm cpu來(lái)實(shí)現(xiàn)TPU尚不支持的算子。

  • 算法并行加速編程庫(kù) TPUKernel:基于Sophon芯片底層原子操作接口的底層編程接口圃验,需要熟悉硬件架構(gòu)和指令集掉伏。

  • 模型性能和精度驗(yàn)證工具 TPUPerf : 可對(duì)模型進(jìn)行性能分析和精度驗(yàn)證。

2.sdk工程目錄說(shuō)明

sudo apt-get install p7zip
sudo apt-get install p7zip-full

$ wget https://sophon-file.sophon.cn/sophon-prod-s3/drive/23/06/15/16/Release_230501-public.zip
$ 7z x Release_230501-public.zip

$ tree -L 2 Release_230501-public
├── bmmonkey_20230605_064500
│   ├── bmmonkey.MD5
│   ├── pcie_amd
│   ├── pcie_arm
│   ├── release_version.txt
│   └── soc
├── bmpanda_20230605_065400
│   ├── amd_pcie
│   ├── arm_pcie
│   ├── arm_soc
│   ├── bm_panda_3.1.0_pcie_amd64.deb
│   ├── bm_panda_3.1.0_pcie_amd64.rpm
│   ├── bm_panda_3.1.0_pcie_arm64.deb
│   ├── bm_panda_3.1.0_soc_arm64.deb
│   ├── bmpanda.MD5
│   ├── bm_panda使用說(shuō)明.pdf
│   ├── centos
│   ├── loongarch64_pcie
│   └── release_version.txt
├── libsophon_20230605_025400
│   ├── BMCV_Technical_Reference_Manual.pdf
│   ├── BMCV開發(fā)參考手冊(cè).pdf
│   ├── BMLib_Technical_Reference_Manual.pdf
│   ├── BMLIB開發(fā)參考手冊(cè).pdf
│   ├── BMRuntime Technical Reference Manual.pdf
│   ├── BMRUNTIME開發(fā)參考手冊(cè).pdf
│   ├── centos
│   ├── libsophon_0.4.8_aarch64.tar.gz      
│   ├── libsophon_0.4.8_loongarch64.tar.gz
│   ├── libsophon_0.4.8_x86_64.tar.gz        #x86 其他LINUX系統(tǒng)對(duì)應(yīng)的libsophon安裝包
│   ├── libsophon_dockerfile
│   ├── libsophon.MD5
│   ├── LIBSOPHON_User_Guide.pdf
│   ├── LIBSOPHON使用手冊(cè).pdf
│   ├── release_version.txt
│   ├── sophon-driver_0.4.8_amd64.deb   #x86_64澳窑,Debian/Ubuntu系統(tǒng)對(duì)應(yīng)PCIe卡驅(qū)動(dòng)安裝文件
│   ├── sophon-driver_0.4.8_arm64.deb   
│   ├── sophon-libsophon_0.4.8_amd64.deb    #x86_64斧散,Debian/Ubuntu系統(tǒng)對(duì)應(yīng)libsophon運(yùn)行時(shí)環(huán)境安裝文件
│   ├── sophon-libsophon_0.4.8_arm64.deb
│   ├── sophon-libsophon-dev_0.4.8_amd64.deb    #x86_64,Debian/Ubuntu系統(tǒng)對(duì)應(yīng)libsophon開發(fā)環(huán)境安裝文件
│   └── sophon-libsophon-dev_0.4.8_arm64.deb
├── sophon-demo_20230605_085900
│   ├── release_version.txt
│   ├── sophon-demo.MD5
│   └── sophon-demo_v0.1.6_f4d1abc_20230605.tar.gz  #針對(duì)單模型或場(chǎng)景的綜合例程
├── sophon-img_20230605_054900
│   ├── bsp-debs
│   ├── bsp_update.tgz  # SoC OTA升級(jí)包【板卡升級(jí)】
│   ├── libsophon_soc_0.4.8_aarch64.tar.gz  #交叉編譯所需文件摊聋,包含aarch64 libsophon的庫(kù)和頭文件
│   ├── release_version.txt
│   ├── sdcard.tgz          #SoC SD卡刷機(jī)包
│   ├── SOPHON_BSP_Technical_Reference_Manual.pdf
│   ├── SOPHON BSP開發(fā)參考手冊(cè).pdf
│   ├── sophon-img.MD5
│   ├── system.tgz      # SoC OTA升級(jí)包【系統(tǒng)升級(jí)】
│   └── tftp.tgz
├── sophon-mw_20230605_032400
│   ├── Multimedia FAQ.pdf
│   ├── Multimedia Technical Reference Manual.pdf
│   ├── Multimedia User Guide.pdf
│   ├── MULTIMEDIA使用手冊(cè).pdf
│   ├── MULTIMEDIA常見(jiàn)問(wèn)題手冊(cè).pdf
│   ├── MULTIMEDIA開發(fā)參考手冊(cè).pdf
│   ├── release_version.txt
│   ├── sophon-mw_0.6.3_aarch64.tar.gz
│   ├── sophon-mw_0.6.3_loongarch64.tar.gz
│   ├── sophon-mw_0.6.3_x86_64.tar.gz   #x86_64鸡捐,其他LINUX系統(tǒng)對(duì)應(yīng)的sophon-mw安裝包
│   ├── sophon-mw.MD5
│   ├── sophon-mw-soc_0.6.3_aarch64.tar.gz  #交叉編譯所需文件,包含aarch64 sophon-mw的庫(kù)和頭文件
│   ├── sophon-mw-soc-sophon-ffmpeg_0.6.3_arm64.deb     #SoC平臺(tái)麻裁,ffmpeg運(yùn)行時(shí)環(huán)境安裝文件
│   ├── sophon-mw-soc-sophon-ffmpeg-dev_0.6.3_arm64.deb 
│   ├── sophon-mw-soc-sophon-opencv_0.6.3_arm64.deb     #SoC平臺(tái)箍镜,opencv運(yùn)行時(shí)環(huán)境安裝文件
│   ├── sophon-mw-soc-sophon-opencv-dev_0.6.3_arm64.deb 
│   ├── sophon-mw-soc-sophon-sample_0.6.3_arm64.deb     #SoC平臺(tái),多媒體程序示例文件
│   ├── sophon-mw-sophon-ffmpeg_0.6.3_amd64.deb
│   ├── sophon-mw-sophon-ffmpeg_0.6.3_amd64.rpm 
│   ├── sophon-mw-sophon-ffmpeg_0.6.3_arm64.deb  #arm64煎源,Debian/Ubuntu系統(tǒng)對(duì)應(yīng)的ffmpeg運(yùn)行時(shí)環(huán)境安裝文件
│   ├── sophon-mw-sophon-ffmpeg_0.6.3_arm64.rpm
│   ├── sophon-mw-sophon-ffmpeg_0.6.3_loongarch64.deb
│   ├── sophon-mw-sophon-ffmpeg-dev_0.6.3_amd64.deb 
│   ├── sophon-mw-sophon-ffmpeg-dev_0.6.3_amd64.rpm
│   ├── sophon-mw-sophon-ffmpeg-dev_0.6.3_arm64.deb 
│   ├── sophon-mw-sophon-ffmpeg-dev_0.6.3_arm64.rpm
│   ├── sophon-mw-sophon-ffmpeg-dev_0.6.3_loongarch64.deb
│   ├── sophon-mw-sophon-opencv_0.6.3_amd64.deb
│   ├── sophon-mw-sophon-opencv_0.6.3_arm64.deb  #arm64色迂,Debian/Ubuntu系統(tǒng)對(duì)應(yīng)的opencv運(yùn)行時(shí)環(huán)境安裝文件
│   ├── sophon-mw-sophon-opencv_0.6.3_loongarch64.deb
│   ├── sophon-mw-sophon-opencv-abi0_0.6.3_amd64.rpm
│   ├── sophon-mw-sophon-opencv-abi0_0.6.3_arm64.rpm
│   ├── sophon-mw-sophon-opencv-abi0-dev_0.6.3_amd64.rpm
│   ├── sophon-mw-sophon-opencv-abi0-dev_0.6.3_arm64.rpm
│   ├── sophon-mw-sophon-opencv-dev_0.6.3_amd64.deb
│   ├── sophon-mw-sophon-opencv-dev_0.6.3_arm64.deb
│   ├── sophon-mw-sophon-opencv-dev_0.6.3_loongarch64.deb
│   ├── sophon-mw-sophon-sample_0.6.3_amd64.deb
│   ├── sophon-mw-sophon-sample_0.6.3_amd64.rpm
│   ├── sophon-mw-sophon-sample_0.6.3_arm64.deb #arm64,多媒體程序示例文件
│   ├── sophon-mw-sophon-sample_0.6.3_arm64.rpm
│   └── sophon-mw-sophon-sample_0.6.3_loongarch64.deb
├── sophon-pipeline_20230605_080800
│   ├── release_version.txt
│   ├── sophon-pipeline.MD5
│   └── sophon-pipeline_v0.3.7_c9b37f7_20230605.tar.gz  #基于pipeline的高性能推理框架
├── sophon-rpc_20230608_060600
│   ├── release_version.txt
│   ├── sophon-rpc-3.0.0-1.amd64.rpm    
│   ├── sophon-rpc-3.0.0-1.arm64.rpm
│   ├── sophon-rpc_3.0.0_amd64.deb  #x86_64手销,Debian/Ubuntu系統(tǒng)對(duì)應(yīng)的sophon-rpc安裝文件
│   ├── sophon-rpc_3.0.0_arm64.deb
│   ├── sophon-rpc_3.0.0.tar.gz
│   ├── sophon-rpc.MD5
│   └── sophon-rpc使用指南.pdf
├── sophon-sail_20230605_085400
│   ├── release_version.txt
│   ├── sophon-sail_3.5.0.tar.gz     #封裝了BMLib歇僧、BMDecoder、BMCV锋拖、BMRuntime的高級(jí)接口庫(kù)
│   ├── sophon-sail_en.pdf
│   ├── sophon-sail.MD5
│   └── sophon-sail_zh.pdf
├── sophon-testhub_20221013_211859
│   ├── release_version.txt
│   ├── sophon-testhub_0.1.0.tar.gz
│   └── sophon-testhub.MD5
├── tpu-kernel_20230605_055600
│   ├── release_version.txt
│   ├── tpu-kernel-1684_v3.1.7-d286b63c-230605.tar.gz   #BM1684 自定義算子開發(fā)工具
│   ├── tpu-kernel-1684x_v3.1.7-4a3e13bf-230605.tar.gz
│   └── tpu-kernel.MD5
├── tpu-mlir_20230605_054500
│   ├── release_version.txt
│   ├── tpu-mlir.MD5
│   └── tpu-mlir_v1.1.7-g30df2e3c-20230605.tar.gz   #編譯器工具鏈
├── tpu-nntc_20230605_054100
│   ├── release_version.txt
│   ├── tpu-nntc.MD5
│   ├── tpu-nntc-test_v3.1.9-73e3f629-230605.tar.gz 
│   └── tpu-nntc_v3.1.9-73e3f629-230605.tar.gz  #模型編譯量化工具鏈
└── tpu-perf_v1.2.13
    ├── tpu_perf-1.2.13-py3-none-manylinux2014_aarch64.whl
    ├── tpu_perf-1.2.13-py3-none-manylinux2014_x86_64.whl
    └── tpu-perf-1.2.13.tar.gz      #模型的性能分析和精度驗(yàn)證工具

三诈悍、開發(fā)環(huán)境搭建

  • X86 PCIe模式:一種產(chǎn)品形態(tài)祸轮,SDK運(yùn)行于X86平臺(tái),BM1684侥钳、BM1684X存在于PCIe接口的深度學(xué)習(xí)計(jì)算加速卡上
    • 可以在x86主機(jī)上基于tpu-nntc和libsophon完成模型的編譯量化與應(yīng)用的開發(fā)部署适袜。
  • Arm PCIe模式:一種產(chǎn)品形態(tài),SDK運(yùn)行于aarch64平臺(tái)(如銀河麒麟)慕趴,BM1684痪蝇、BM1684X存在于PCIe接口的深度學(xué)習(xí)計(jì)算加速卡上鄙陡。
  • Soc模式:一種產(chǎn)品形態(tài)冕房,SDK運(yùn)行于A53 AARCH64平臺(tái),TPU作為平臺(tái)總線設(shè)備趁矾,如:SE微服務(wù)器/SM模組
    • 可以在x86主機(jī)上基于tpu-nntc和libsophon完成模型的編譯量化與程序的交叉編譯耙册,部署時(shí)將編譯好的程序拷貝至SoC平臺(tái)中執(zhí)行。

1.x86 PCIe模式

1)安裝libsophon及sophon-mw

# 安裝依賴庫(kù)
sudo apt install dkms libncurses5

# 安裝驅(qū)動(dòng)毫捣、libsophon開發(fā)包及運(yùn)行時(shí)包
cd Release_230501-public/libsophon_20230605_025400
ls *amd64.deb
    sophon-driver_0.4.8_amd64.deb  
    sophon-libsophon_0.4.8_amd64.deb  
    sophon-libsophon-dev_0.4.8_amd64.deb
cd -
sudo dpkg -i sophon-*amd64.deb
source /etc/profile

# 查看設(shè)備文件
$ ls /dev/bm*
/dev/bmdev-ctl /dev/bm-sophon0
# 查看驅(qū)動(dòng)
$ bm-smi

$ ls /sys/class/bm-sophon/bm-sophon0/device

# 安裝sophon-mw
cd Release_230501-public/sophon-mw_20230605_032400
ls *amd64.deb
    sophon-mw-sophon-ffmpeg_0.6.3_amd64.deb      
    sophon-mw-sophon-opencv_0.6.3_amd64.deb      
    sophon-mw-sophon-sample_0.6.3_amd64.deb
    sophon-mw-sophon-ffmpeg-dev_0.6.3_amd64.deb  
    sophon-mw-sophon-opencv-dev_0.6.3_amd64.deb
cd -
source /etc/profile

2.arm PCIe模式

銀河麒麟v10為例

3.SoC模式

1)x86上交叉編譯準(zhǔn)備

# 安裝交叉編譯工具鏈
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

cd Release_230501-public
mkdir -p soc-sdk

# 解壓sophon-img包详拙,拷貝已編譯的aarch64 sophon lib及include文件
cd sophon-img_20230605_054900
tar -zxvf libsophon_soc_0.4.8_aarch64.tar.gz
$ ls libsophon_soc_0.4.8_aarch64/opt/sophon/
    driver-0.4.8  libsophon-0.4.8
cp -rf  libsophon_soc_0.4.8_aarch64/opt/sophon/libsophon-0.4.8/lib/ ../soc-sdk
cp -rf  libsophon_soc_0.4.8_aarch64/opt/sophon/libsophon-0.4.8/include/ ../soc-sdk
cd -

# 解壓sophon-mw包,拷貝已編譯的aarch64 ffmpeg和opencv的lib及include文件
cd sophon-mw_20230605_032400
tar -zxvf sophon-mw-soc_0.6.3_aarch64.tar.gz
$ ls sophon-mw-soc_0.6.3_aarch64/opt/sophon/
    sophon-ffmpeg_0.6.3  sophon-opencv_0.6.3  sophon-sample_0.6.3
# 將ffmpeg和opencv的庫(kù)目錄和頭文件目錄拷貝到依賴文件根目錄下
cp -rf  sophon-mw-soc_0.6.3_aarch64/opt/sophon/sophon-ffmpeg_0.6.3/lib/ ../soc-sdk
cp -rf  sophon-mw-soc_0.6.3_aarch64/opt/sophon/sophon-ffmpeg_0.6.3/include/ ../soc-sdk
cp -rf  sophon-mw-soc_0.6.3_aarch64/opt/sophon/sophon-opencv_0.6.3/lib/ ../soc-sdk
cp -rf  sophon-mw-soc_0.6.3_aarch64/opt/sophon/sophon-opencv_0.6.3/include/ ../soc-sdk

2)SoC上運(yùn)行環(huán)境

系統(tǒng)軟件構(gòu)成

對(duì)于SoC平臺(tái)蔓同,一般內(nèi)部已經(jīng)集成了驅(qū)動(dòng)和相應(yīng)的libsophon饶辙、sophon-opencv和sophon-ffmpeg運(yùn)行庫(kù)包,位于 /opt/sophon/目錄下斑粱,如需更新弃揽,推薦直接更新固件。

# 查看設(shè)備文件
$ ls /dev/bm*
/dev/bm-tach-0  /dev/bm-tach-1  /dev/bm-top  /dev/bm-tpu0  /dev/bm-vpp  /dev/bm-wdt-0  /dev/bm_efuse  /dev/bmdev-ctl

$ ls /sys/class/bm-tpu/bm-tpu0/device

# 查看驅(qū)動(dòng)
$ bm-smi
+--------------------------------------------------------------------------------------------------+                                                     
| SDK Version:    0.4.8             Driver Version:  0.4.8                                         |                                        
+---------------------------------------+----------------------------------------------------------+                                                     
......
$ bm_version 
sophon-soc-libsophon : 0.4.8
sophon-soc-libsophon-dev : 0.4.8
sophon-mw-soc-sophon-ffmpeg : 0.6.3
sophon-mw-soc-sophon-opencv : 0.6.3
BL2 v2.7(release):3612e34 Built : 05:50:40, Jun  5 2023
BL31 v2.7(release):3612e34 Built : 05:50:40, Jun  5 2023
U-Boot 2022.10 3612e34 (Jun 05 2023 - 05:50:17 +0800) Sophon BM1684
KernelVersion : Linux bm1684 5.4.217-bm1684-g5223559170c0 #1 SMP Mon Jun 5 05:51:01 CST 2023 aarch64 aarch64 aarch64 GNU/Linux
HWVersion: 0x11
MCUVersion: 0x35

# 查看sophon庫(kù)文件
$ $ tree /opt/sophon/ -L 2
/opt/sophon/
├── libsophon-0.4.8
│   ├── bin
│   │   ├── bm-smi
│   │   ├── bm1684x
│   │   ├── bm_firmware_update
│   │   ├── bm_test
│   │   ├── bmjpegdec
│   │   ├── bmjpegenc
│   │   ├── bmjpegmulti
│   │   ├── bmrt_test
│   │   ├── bmvpuenc
│   │   ├── fbcmulti
│   │   ├── i420tonv12
│   │   ├── ...
│   ├── data
│   ├── include
│   └── lib
├── libsophon-current -> /opt/sophon/libsophon-0.4.8
├── sophon-ffmpeg-latest -> /opt/sophon/sophon-ffmpeg_0.6.3
├── sophon-ffmpeg_0.6.3
│   ├── bin
│   ├── data
│   └── lib
├── sophon-opencv-latest -> /opt/sophon/sophon-opencv_0.6.3
└── sophon-opencv_0.6.3
    ├── bin
    ├── data
    ├── lib
    ├── opencv-python
    └── test

四则北、模型轉(zhuǎn)移及量化

有兩種方式支持用戶構(gòu)建自己的深度學(xué)習(xí)Graph模型矿微,并離線編譯成bmodel,部署在Sophon TPU中尚揣。

兩種方式為:

  1. 通過(guò)BMCompiler的算子IR(中間表示)接口來(lái)構(gòu)建涌矢。
  2. 通過(guò)BMLang來(lái)構(gòu)建。

1.TPU-NNTC簡(jiǎn)介

TPU-NNTC開發(fā)參考手冊(cè)

NNToolchain是算能基于其自主研發(fā)的AI芯片快骗,所定制的深度學(xué)習(xí)工具鏈娜庇,涵蓋了神經(jīng)網(wǎng)絡(luò)推理階段所需的模型優(yōu)化、高效運(yùn)行時(shí)支持等能力方篮,為深度學(xué)習(xí)應(yīng)用開發(fā)和部署提供易用名秀、高效的全棧式解決方案。

NNToolchain整體架構(gòu)如下圖所示恭取,由Compiler和Runtime(圖中左右)兩部分組成泰偿。

  • Compiler負(fù)責(zé)對(duì)各種主流深度神經(jīng)網(wǎng)絡(luò)模型(如Caffe model、Tensorflow model等)進(jìn)行編譯和優(yōu)化蜈垮。
    • 離線運(yùn)行在X86平臺(tái)耗跛,該平臺(tái)不用包含BM168x產(chǎn)品裕照。
  • Runtime向下屏蔽底層硬件實(shí)現(xiàn)細(xì)節(jié),驅(qū)動(dòng)TPU芯片调塌,向上為應(yīng)用程序提供統(tǒng)一的可編程接口晋南,既提供神經(jīng)網(wǎng)絡(luò)推理功能,又提供對(duì)DNN和CV算法的加速羔砾。
    • PCIE模式:SDK運(yùn)行于X86平臺(tái)负间,BM168x作為PCIE接口的深度學(xué)習(xí)計(jì)算加速卡存在;
    • SOC模式:SDK獨(dú)立運(yùn)行于BM168x平臺(tái)姜凄,支持通過(guò)千兆以太網(wǎng)與其他設(shè)備連接;
    • CMODEL模式:SDK運(yùn)行在X86平臺(tái)政溃,并脫離BM168x運(yùn)行,用于在沒(méi)有芯片的模式下進(jìn)行軟件仿真态秧。

1)框架支持及轉(zhuǎn)換過(guò)程

算子支持情況

深度學(xué)習(xí)框架 版本要求 使用的bmnetx模型編譯器
Caffe 官方版本 bmnetc
Darknet 官方版本 bmnetd
MXNet mxnet >= 1.3.0 bmnetm
ONNX onnx == 1.7.0 (Opset version == 12)
onnxruntime == 1.3.0
protobuf >= 3.8.0
bmneto
PyTorch pytorch >= 1.3.0, 建議1.8.0 bmnetp
TensorFlow tensorflow >= 1.10.0 bmnett
PaddlePaddle paddlepaddle >= 2.1.1 bmpaddle

轉(zhuǎn)換過(guò)程

  • TPU-NNTC工具鏈提供了bmnetc董虱、bmnetd、bmnetm申鱼、bmneto愤诱、bmnetp、bmnett捐友、bmnetu等工具淫半,分別用來(lái)轉(zhuǎn)換Caffe、Darknet匣砖、MXNet科吭、ONNX、Pytorch脆粥、Tensorflow砌溺、UFramework(算能科技自定義的模型中間格式框架)等框架下的模型。
  • 經(jīng)前端工具解析后变隔,模型編譯器BMNet Compiler會(huì)對(duì)各種框架的模型進(jìn)行離線轉(zhuǎn)換规伐,生成 TPU 能夠執(zhí)行的指令流并序列化保存為BModel文件;
  • 當(dāng)執(zhí)行在線推理時(shí)匣缘, 由BMRuntime負(fù)責(zé)BModel模型的讀取猖闪、數(shù)據(jù)的拷貝傳輸、TPU推理的執(zhí)行以及計(jì)算結(jié)果的讀取等肌厨。

2)BModel簡(jiǎn)介

bmodel是面向算能TPU處理器的深度神經(jīng)網(wǎng)絡(luò)模型文件格式培慌,基于BMLang編程語(yǔ)言的編譯所得,包含一個(gè)至多個(gè)目標(biāo)網(wǎng)絡(luò)的權(quán)重(weight)柑爸、TPU指令流等吵护,在runtime階段作為模型文件被加載和使用。

  • 靜態(tài)bmodel

    保存TPU可直接使用的固定參數(shù)原子操作指令,模型輸入大小固定馅而。

    • 由于靜態(tài)接口簡(jiǎn)單穩(wěn)定祥诽,在新的sdk下編譯出來(lái)的模型通常能在舊機(jī)器上運(yùn)行,不用更新firmware刷機(jī)瓮恭。
    • 有些模型雖然指定的是靜態(tài)編譯雄坪,但有些算子必需有TPU內(nèi)部mcu參與或host cpu參與,如排序屯蹦、nms维哈、where、detect_out這類邏輯運(yùn)算比較多的算子登澜,該部分會(huì)被切分成子網(wǎng)阔挠,用動(dòng)態(tài)方式實(shí)現(xiàn)。
  • 多stage bmodel(適用于輸入的shape只有固定離散的幾種情況)

    使用tpu_model將同一個(gè)網(wǎng)絡(luò)的不同batch size的模型combine為一個(gè)BModel帖渠;同一個(gè)網(wǎng)絡(luò)的不同batch size的輸入對(duì)應(yīng)著不同的stage谒亦,推理時(shí)BMRuntime會(huì)根據(jù)輸入shape的大小自動(dòng)選擇相應(yīng)stage的模型。

  • 動(dòng)態(tài)bmodel(適用于可變shape過(guò)多的情況)

    保存每個(gè)算子的參數(shù)信息空郊,并不能直接在TPU上運(yùn)行。需要TPU內(nèi)部的mcu逐層解析參數(shù)切揭,進(jìn)行shape及dtype推理狞甚,調(diào)用原子操作來(lái)實(shí)現(xiàn)具體的功能,故運(yùn)行效率比靜態(tài)bmodel稍差廓旬。

    • 動(dòng)態(tài)bmodel為了保證參數(shù)可擴(kuò)展以及兼容哼审,會(huì)保證新sdk的runtime能運(yùn)行舊版本sdk編譯出的動(dòng)態(tài)bmodel。通常建議換新sdk后刷機(jī)孕豹,保證兩者版本一致涩盾。

2.容器部署tpu-nntc量化環(huán)境【X86平臺(tái)】

https://hub.docker.com/r/sophgo/tpuc_dev

或者官網(wǎng)下載nntc鏡像

# pull docker image
sudo docker pull sophgo/tpuc_dev:latest
# 或者官網(wǎng)下載鏡像解壓
7z x sophgo-tpuc_dev-v2.1-82d75f5c633d.tar.zip
bunzip2 sophgo-tpuc_dev-v2.1-82d75f5c633d.tar.bz2
sudo docker load -i sophgo-tpuc_dev-v2.1-82d75f5c633d.tar

# 解壓tpu-nntc
cd Release_230501-public/tpu-nntc_20230605_054100
mkdir tpu-nntc
tar zxvf tpu-nntc_v3.1.9-73e3f629-230605.tar.gz --strip-components=1 -C tpu-nntc

# 創(chuàng)建docker容器并進(jìn)入Docker
sudo docker run -v $PWD:/workspace -p 8001:8001 -it sophgo/tpuc_dev:v2.1

# 初始化軟件環(huán)境【容器中】
cd /workspace/tpu-nntc
source scripts/envsetup.sh

$ python --version
Python 3.7.5
$ pip list
bmlang                        3.1.9
bmnetc                        3.1.9
bmnetd                        3.1.9
bmnetm                        3.1.9
bmneto                        3.1.9
bmnetp                        3.1.9
bmnett                        3.1.9
bmnetu                        3.1.9
bmpaddle                      3.1.9
bmprofile                     3.1.9
bmtflite                      3.1.9
...
onnx                          1.12.0
onnxruntime                   1.12.0
onnxsim                       0.4.17
opencv-contrib-python         4.7.0.68
opencv-python                 4.7.0.68
opencv-python-headless        4.7.0.68
...
numpy                         1.21.6
protobuf                      3.19.6
...
paddle-bfloat                 0.1.7
paddle2onnx                   1.0.5
paddlepaddle                  2.4.2
...
torch                         1.13.0+cpu
torchaudio                    0.13.0
torchvision                   0.14.0+cpu
...

3.PyTorch模型轉(zhuǎn)bmodel

BMNETP是針對(duì)pytorch的模型編譯器,可以把pytorch的model直接編譯成BMRuntime所需的執(zhí)行指令励背。pytorch的模型在編譯前要經(jīng)過(guò)torch.jit.trace春霍,trace后的模型才能用于編譯。在編譯模型的同時(shí)叶眉,可選擇將每一個(gè)操作的NPU模型計(jì)算結(jié)果和CPU的計(jì)算結(jié)果進(jìn)行對(duì)比址儒,保證正確性。

1)注意事項(xiàng)

  • 什么是JIT(torch.jit)

  • JIT(Just-In-Time)是一組編譯工具衅疙,用于彌合PyTorch研究與生產(chǎn)之間的差距莲趣。它允許創(chuàng)建可以在不依賴Python解釋器的情況下運(yùn)行的模型,并且可以更積極地進(jìn)行優(yōu)化饱溢。

  • JIT與BMNETP的關(guān)系

  • BMNETP只接受PyTorch的JIT模型喧伞,且須為CPU模型。

  • 如何得到JIT模型

    • 通過(guò)torch.jit.trace將PyTorch的Python模型(基類為torch.nn.Module)轉(zhuǎn)換得到JIT模型。

      torch.jit.trace(python_model, torch.rand(input_shape)).save('jit_model')
      
    • 為什么不能使用torch.jit.script得到JIT模型

      • BMNETP暫時(shí)不支持帶有控制流操作(如if語(yǔ)句或循環(huán))潘鲫、inplace的操作(如copy_函數(shù)等)的JIT模型绿聘,但torch.jit.script可以產(chǎn)生這類模型,而torch.jit.trace卻不可以次舌,僅跟蹤和記錄張量上的操作熄攘,不會(huì)記錄任何控制流操作。
  • pytorch模型需包含權(quán)重信息和完整網(wǎng)絡(luò)信息彼念,可以通過(guò)torch.jit.load(pt_file_path, map_location="cpu")是否報(bào)錯(cuò)來(lái)測(cè)試挪圾。

2)模型轉(zhuǎn)換

方法1:命令行方式

python -m bmnetp [-h] 
                        [--mode {compile,GenUmodel,dump,check,verify}]
                        [--model MODEL]     # Necessary. Traced PyTorch model (.pt) path
                        [--shapes SHAPES]   # Necessary. Shapes of all inputs, format [x,x,x,x],[x,x]…
                        [--net_name NET_NAME] # Optional. Name of the network, default “network”
                        [--outdir OUTDIR]   # Optional. Output directory, default “compilation”
                        [--target {BM1684,BM1684X,BM1686}] 
                        [--opt {1,2}]   # Optional. Optimization level. Option: 0, 1, 2, default 1.
                        [--cmp {True,False}] # Optional. Check result during compilation. Default: True
                        [--dyn {True,False}] # Optional. Use dynamic compilation, default False.
                        [--seed SEED] 
                        [--descs DESCS] 
                        [--desc DESC]
                        [--enable_profile {True,False}] # Optional. Enable profile log. Default: False
                        [--log_dir LOG_DIR]
                        [--v V] 
                        [--no_log_prefix] 
                        [--list_ops]    # Optional. List supported ops.
                        [--input_structure INPUT_STRUCTURE]
                        [--output_names OUTPUT_NAMES]

## List all supported ops
python -m bmnetp --list_ops
  • cmp=True模式,會(huì)在指定的文件夾中生成一個(gè)input_ref_data.dat和一個(gè)output_ref_data.dat逐沙, 分別是Pytorch產(chǎn)生的網(wǎng)絡(luò)輸入?yún)⒖紨?shù)據(jù)和網(wǎng)絡(luò)輸出參考數(shù)據(jù)哲思,可用于bmrt_test驗(yàn)證生成的bmodel在芯片運(yùn)行時(shí)結(jié)果是否正確。

方法2:python接口

import bmnetp

## compile fp32 model
bmnetp.compile(
  model = "/path/to/.pth",        ## Necessary
  outdir = "xxx",                 ## Necessary
  target = "BM1684",              ## Necessary
  shapes = [[x,x,x,x], [x,x,x]],  ## Necessary
  net_name = "name",              ## Necessary
  opt = 2,                        ## optional, if not set, default equal to 1
  dyn = False,                    ## optional, if not set, default equal to False
  cmp = True,                     ## optional, if not set, default equal to True
  enable_profile = True           ## optional, if not set, default equal to False
)

4.ONNX模型轉(zhuǎn)bmodel

https://github.com/sophon-ai-algo/examples/tree/3.0.0/nntc/bmneto

BMNETO是針對(duì)ONNX的模型編譯器吩案,可以把ONNX格式的model經(jīng)過(guò)圖編譯優(yōu)化后棚赔,轉(zhuǎn)換成BMRuntime所需的文件。在編譯模型的同時(shí)徘郭,可選擇將每一個(gè)操作的NPU模型計(jì)算結(jié)果和CPU的計(jì)算結(jié)果進(jìn)行對(duì)比靠益,保證正確性。

環(huán)境要求

  • python 3.x
  • onnx == 1.7.0 (Opset version == 12)
  • onnxruntime == 1.3.0
  • protobuf >= 3.8.0

1)方法1:命令行轉(zhuǎn)換

python3 -m bmneto [-h] 
                   [--mode {compile,GenUmodel,check}] 
                   [--model MODEL]  # Necessary. ONNX model (.onnx) path
                   [--input_names INPUT_NAMES] 
                   [--output_names OUTPUT_NAMES]
                   [--shapes SHAPES]    # Necessary. Shapes of all inputs, format [x,x,x,x],[x,x]…
                   [--net_name NET_NAME] #  Optional. Name of the network, default “network”
                   [--dyn {True,False}]  # Optional. Use dynamic compilation, default False.
                   [--opt OPT] # Optional. Optimization level. Option: 0, 1, 2, default 1.
                   [--outdir OUTDIR] # Optional. Output directory, default "compilation"
                   [--input_data INPUT_DATA] 
                   [--target {BM1684,BM1684X}]
                   [--cmp [CMP]]  # Compare compile results with reference DL software tool. (default: None)
                   [--debug DEBUG]
                   [--enable_profile {True,False}]  # Optional. Enable profile log. Default: False
                   [--log_dir LOG_DIR]
                   [--v {0,1,2,3,4}] 
                   [--list_ops] 
                   [--log_prefix]
                   [--seed SEED]    # Random seed (default: 42)
                   [--descs DESCS]
                   
python3 -m bmneto \
    --mode compile \
    --model mobilenetv2.onnx \
    --outdir compilation \
    --target BM1684 \
    --shapes [1,3,224,224] \
    --net_name mobilenetv2 \
    --opt 2 \
    --dyn False \
    --cmp True \
    --enable_profile True 

2)方法2:python轉(zhuǎn)換

import bmneto

## compile fp32 model
bmneto.compile(
  model = "xxx.onnx",        ## Necessary
  outdir = "compilation",                 ## Necessary
  target = "BM1684",              ## Necessary
  shapes = [[1,3,224,224]],  ## Necessary
  net_name = "mobilenetv2",              ## optional
  opt = 2,                        ## optional, if not set, default equal to 1
  dyn = False,                    ## optional, if not set, default equal to False
  cmp = True,                     ## optional, if not set, default equal to True
  enable_profile = True           ## optional, if not set, default equal to False
)

輸出內(nèi)容

$ ls compilation/
compilation.bmodel  compiler_profile_0.dat  input_ref_data.dat  io_info.dat  net_0.profile  output_ref_data.dat

5.bmodel驗(yàn)證

1)bmrt_test

基于bmruntime接口實(shí)現(xiàn)的對(duì)bmodel的正確性和實(shí)際運(yùn)行性能的測(cè)試工具残揉。包含以下功能:

  1. 直接用隨機(jī)數(shù)據(jù)bmodel進(jìn)行推理胧后,驗(yàn)證bmodel的完整性及可運(yùn)行性
  2. 通過(guò)固定輸入數(shù)據(jù)直接用bmodel進(jìn)行推理,會(huì)對(duì)輸出與參考數(shù)據(jù)進(jìn)行比對(duì)抱环,驗(yàn)證證數(shù)據(jù)正確性
  3. 測(cè)試bmodel的實(shí)際運(yùn)行時(shí)間
  4. 通過(guò)bmprofile機(jī)制進(jìn)行bmodel的profile
$ bmrt_test -h
Usage:
  --context_dir      : 模型編譯出的結(jié)果文件夾壳快,比對(duì)數(shù)據(jù)也是編譯時(shí)生成的, 默認(rèn)開啟比對(duì).
  --append_dir       : The dir of another context after compiltaion.
  --bmodel           : 與context_dir二選一, 直接指定.bmodel文件,默認(rèn)不開啟比對(duì)
  --bmodel_list      : File that include one or more context dirs.
  --devid            : The number of device.
  --compare          : 可選, 0表示不開比對(duì), 1表示開啟比對(duì)
  --accuracy_f       : 可選, 指定浮點(diǎn)數(shù)據(jù)比對(duì)誤差門限镇草,默認(rèn)是0.01
  --accuracy_i       : 可選, 指定整數(shù)數(shù)據(jù)比對(duì)誤差門限眶痰,默認(rèn)是0
  --loopnum          : 可選, 指定連續(xù)運(yùn)行次數(shù),默認(rèn)是1
  --thread_num       : 可選, 指定運(yùn)行線程數(shù)目梯啤,默認(rèn)是1竖伯,測(cè)試多線程正確性
  --prealloc         : Set alloc ion size (hex format) before load bmodel.
  --export_neuron    : Export neuron mem to file.
  --export_output    : Export output data to file.
  --profile          : Open profile function.
  --subnet_time      : 可選, 是否顯示bmodel的subnet時(shí)間
  --net_idx          : 可選, 在包含多個(gè)網(wǎng)絡(luò)的bmodel通過(guò)序號(hào)選擇運(yùn)行用的net
  --stage_idx        : 可選, 在包含多個(gè)stage的bmodel通過(guò)序號(hào)選擇運(yùn)行用的stage
  --debug_output     : Dump output data and reference data for debug.
  --shapes           : Set shapes of the input shapes
  
$ bmrt_test  --context_dir compilation --compare 1 --loopnum 1
[BMRT][deal_with_options:1412] INFO:Loop num: 1
bmcpu init: skip cpu_user_defined
open usercpu.so, init user_cpu_init 
[BMRT][load_bmodel:1018] INFO:Loading bmodel from [compilation/compilation.bmodel]. Thanks for your patience...
[BMRT][load_bmodel:982] INFO:pre net num: 0, load net num: 1
[BMRT][show_net_info:1336] INFO: ########################
[BMRT][show_net_info:1337] INFO: NetName: mobilenetv2, Index=0
[BMRT][show_net_info:1339] INFO: ---- stage 0 ----
[BMRT][show_net_info:1347] INFO:   Input 0) 'input' shape=[ 1 3 224 224 ] dtype=FLOAT32 scale=1
[BMRT][show_net_info:1356] INFO:   Output 0) 'output' shape=[ 1 4 ] dtype=FLOAT32 scale=1
[BMRT][show_net_info:1359] INFO: ########################
[BMRT][bmrt_test:770] INFO:==> running network #0, name: mobilenetv2, loop: 0
[BMRT][bmrt_test:834] INFO:reading input #0, bytesize=602112
[BMRT][print_array:702] INFO:  --> input_data: < 0.37454 0.950714 0.731994 0.598659 0.156019 0.155995 0.0580836 0.866176 0.601115 0.708073 0.0205845 0.96991 0.832443 0.212339 0.181825 0.183405 ... > len=150528
[BMRT][bmrt_test:987] INFO:reading output #0, bytesize=16
[BMRT][print_array:702] INFO:  --> output ref_data: < -2.20592 1.20597 -12.6197 -10.1316 >
[BMRT][bmrt_test:1019] INFO:net[mobilenetv2] stage[0], launch total time is 1033 us (npu 942 us, cpu 91 us)
[BMRT][bmrt_test:1022] INFO:+++ The network[mobilenetv2] stage[0] output_data +++
[BMRT][print_array:702] INFO:output data #0 shape: [1 4 ] < -2.20592 1.20597 -12.6197 -10.1316 >
[BMRT][bmrt_test:1038] INFO:==>comparing #0 output ... 
[BMRT][bmrt_test:1043] INFO:+++ The network[mobilenetv2] stage[0] cmp success +++
[BMRT][bmrt_test:1063] INFO:load input time(s): 0.001336
[BMRT][bmrt_test:1064] INFO:calculate  time(s): 0.001036
[BMRT][bmrt_test:1065] INFO:get output time(s): 0.000046
[BMRT][bmrt_test:1066] INFO:compare    time(s): 0.000113

6.FP32 BModel精度對(duì)齊

https://github.com/sophgo/sophon-demo/blob/release/docs/FP32BModel_Precise_Alignment.md

  • 原始模型轉(zhuǎn)FP32 BModel存在一定的精度誤差,如果開啟精度對(duì)比(cmp=True)条辟,且精度對(duì)比通過(guò)黔夭,在前后處理與原算法對(duì)齊的前提下,F(xiàn)P32 BModel的最大誤差通常在0.001以下羽嫡,不會(huì)對(duì)最終的預(yù)測(cè)結(jié)果造成影響本姥。
  • Sophon OpenCV使用芯片中的硬件加速單元進(jìn)行解碼,相比原生OpenCV采用了不同的upsample算法杭棵。解碼和前后處理的方式與原生的OpenCV存在一定差異婚惫,可能影響最終的預(yù)測(cè)結(jié)果氛赐,但通常不會(huì)對(duì)魯棒性好的模型造成明顯影響。
  • 多輸出模型的輸出是以字典形式保存的先舷,如果將輸出字典values轉(zhuǎn)list艰管,可能出現(xiàn)輸出順序錯(cuò)誤的問(wèn)題,建議使用輸出名稱獲取對(duì)應(yīng)的輸出數(shù)據(jù)蒋川。

五牲芋、離線模型推理

分析任務(wù)與接口庫(kù)

任務(wù)流程 是否支持硬件加速 SAIL高級(jí)接口庫(kù) OPENCV接口庫(kù) FFMPEG接口庫(kù) Native接口庫(kù)
視頻/圖片解碼 支持 sail::Decoder Y Y BMCV(圖片)
輸入預(yù)處理 支持 sail::Bmcv Y N BMCV
模型推理 支持 sail::Engine N N BMruntime
輸出后處理 部分支持 sail::Bmcv N N BMCV
視頻/圖片編碼 支持 sail::Bmcv Y Y BMCV(圖片)
  • BMRuntime模塊支持C/C++接口編程,用于讀取BMCompiler的編譯輸出(.bmodel)捺球,驅(qū)動(dòng)其在Sophon TPU芯片中執(zhí)行缸浦。
  • BMCV、BMLib支持C接口編程
  • SAIL庫(kù)(Sophon Artificial Intelligent Library)

1.BMRuntime及BMLib庫(kù)使用

軟件架構(gòu)

1)BMLib

BMLib開發(fā)參考手冊(cè)

實(shí)現(xiàn)C語(yǔ)言接口氮兵,負(fù)責(zé)設(shè)備Handle的管理裂逐、內(nèi)存管理、數(shù)據(jù)搬運(yùn)泣栈、API的發(fā)送和同步卜高、A53使能、設(shè)置TPU工作頻率等南片。

  • 頭文件bmlib_runtime.h掺涛,lib庫(kù)為libbmlib.so。
/*******************handle releated functions *********************************/
// 用于請(qǐng)求一個(gè)設(shè)備铃绒,得到設(shè)備句柄handle鸽照。
bm_status_t bm_dev_request(bm_handle_t *handle, int devid);
// get device index for the given handle
int bm_get_devid(bm_handle_t handle);
// 用于釋放一個(gè)設(shè)備。
void bm_dev_free(bm_handle_t handle);


/*******************memory help functions ************************************/
// 申請(qǐng)指定大小的device mem颠悬,size為device mem的字節(jié)大小。
bm_status_t bm_malloc_device_byte(bm_handle_t handle, bm_device_mem_t *pmem,
                                  unsigned int size);
// 釋放device mem
void bm_free_device(bm_handle_t handle, bm_device_mem_t mem);

// 將在系統(tǒng)內(nèi)存上的數(shù)據(jù)拷貝到device mem定血。
// 拷貝的大小是device mem的大小赔癌,從src開始拷貝
bm_status_t bm_memcpy_s2d(bm_handle_t handle, bm_device_mem_t dst, void *src);
// size指定拷貝的字節(jié)大小,從src的offset偏移開始拷貝
bm_status_t bm_memcpy_s2d_partial_offset(bm_handle_t handle, bm_device_mem_t dst,
                                         void *src, unsigned int size,
                                         unsigned int offset);
// size指定拷貝的字節(jié)大小澜沟,從src開始拷貝
bm_status_t bm_memcpy_s2d_partial(bm_handle_t handle, bm_device_mem_t dst,
                                  void *src, unsigned int size);

// 將device mem中的數(shù)據(jù)拷貝到系統(tǒng)內(nèi)存
bm_status_t bm_memcpy_d2s(bm_handle_t handle, void *dst, bm_device_mem_t src);
bm_status_t bm_memcpy_d2s_partial_offset(bm_handle_t handle, void *dst,
                                         bm_device_mem_t src, unsigned int size,
                                         unsigned int offset);
bm_status_t bm_memcpy_d2s_partial(bm_handle_t handle, void *dst,
                                  bm_device_mem_t src, unsigned int size);

// 將數(shù)據(jù)從一個(gè)device mem拷貝到另一個(gè)device mem灾票。len是以dword為單位(4bytes)
bm_status_t bm_memcpy_d2d(bm_handle_t handle, bm_device_mem_t dst, int dst_offset,
                          bm_device_mem_t src, int src_offset, int len);


/*******************memory map functions *************************************/
// 在SoC上,系統(tǒng)內(nèi)存和Device Memory雖然是隔開的茫虽,但其實(shí)都是DDR上的內(nèi)存刊苍。
// 通過(guò)mmap,得到Device Memory的虛擬地址濒析,從而可以被應(yīng)用程序直接訪問(wèn)正什。
// 1.將device mem映射出來(lái),得到虛擬地址号杏。
bm_status_t bm_mem_mmap_device_mem(bm_handle_t handle,
                                   bm_device_mem_t *dmem,
                                   unsigned long long *vmem);
bm_status_t bm_mem_unmap_device_mem(bm_handle_t handle,
                                    void* vmem, int size);
// 2.使cache失效婴氮,確保DDR數(shù)據(jù)同步到了cache【應(yīng)用程序獲取數(shù)據(jù)前需操作】
bm_status_t bm_mem_invalidate_device_mem(bm_handle_t handle, bm_device_mem_t *dmem);
bm_status_t bm_mem_invalidate_partial_device_mem(bm_handle_t handle, bm_device_mem_t *dmem,
                                                 unsigned int offset, unsigned int len);
// 3.刷新cache數(shù)據(jù),確保cache數(shù)據(jù)同步到了DDR【應(yīng)用程序修改數(shù)據(jù)后需操作】
bm_status_t bm_mem_flush_device_mem(bm_handle_t handle, bm_device_mem_t *dmem);
bm_status_t bm_mem_flush_partial_device_mem(bm_handle_t handle, bm_device_mem_t *dmem,
                                            unsigned int offset, unsigned int len);


/*******************api(kernel) functions *************************************/
// To synchronize APIs of the current thread.
void bm_flush(bm_handle_t handle);
// To synchronize APIs of the device.
bm_status_t bm_device_sync(bm_handle_t handle);
// To synchronize APIs of the handle.
bm_status_t bm_handle_sync(bm_handle_t handle);
// To synchronize APIs of the current thread.
bm_status_t bm_thread_sync(bm_handle_t handle);

2)BMRuntime

BMRUNTIME開發(fā)參考手冊(cè)

實(shí)現(xiàn)了C/C++接口,用于讀取BMCompiler的編譯輸出(.bmodel)主经,驅(qū)動(dòng)其在Sophon TPU芯片中執(zhí)行荣暮。

C Interface
  • 頭文件為bmruntime_interface.h,lib庫(kù)為libbmrt.so罩驻。
  • 線程安全
// 通過(guò)bm_handle創(chuàng)建bmruntime穗酥,返回runtime指針。
void* bmrt_create(bm_handle_t bm_handle);
// 銷毀bmruntime惠遏,釋放資源砾跃。
void bmrt_destroy(void* p_bmrt);

// 從runtime指針中得到設(shè)備句柄bm_handle
void * bmrt_get_bm_handle(void* p_bmrt);

// To load the bmodel which is created by BM compiler
bool bmrt_load_bmodel(void* p_bmrt, const char *bmodel_path);
// 加載bmodel,不同于bmrt_load_bmodel爽哎,它的bmodel數(shù)據(jù)存在內(nèi)存中
bool bmrt_load_bmodel_data(void* p_bmrt, const void * bmodel_data, size_t size);

// 打印bmruntime中存在的網(wǎng)絡(luò)的名稱
void bmrt_show_neuron_network(void* p_bmrt);
// 獲得bmruntime中存在的網(wǎng)絡(luò)的數(shù)量
int bmrt_get_network_number(void* p_bmrt);
// 得到runtime中存在的所有網(wǎng)絡(luò)的名稱
void bmrt_get_network_names(void* p_bmrt, const char*** network_names);
// To get network info by net name
typedef struct {
    bm_shape_t* input_shapes;   /* input_shapes[0] / [1] / ... / [input_num-1] */
    bm_shape_t* output_shapes;  /* output_shapes[0] / [1] / ... / [output_num-1] */
} bm_stage_info_t;
typedef struct {
    const char* name;              /* net name */
    bool is_dynamic;               /* dynamic or static */
    int input_num;                 /* number of inputs */
    char const** input_names;      /* input_names[0] / [1] / .../ [input_num-1] */
    bm_data_type_t* input_dtypes;  /* input_dtypes[0] / [1] / .../ [input_num-1] */
    float* input_scales;           /* input_scales[0] / [1] / .../ [input_num-1] */
    int output_num;                /* number of outputs */
    char const** output_names;     /* output_names[0] / [1] / .../ [output_num-1] */
    bm_data_type_t* output_dtypes; /* output_dtypes[0] / [1] / .../ [output_num-1] */
    float* output_scales;          /* output_scales[0] / [1] / .../ [output_num-1] */
    int stage_num;                 // 網(wǎng)絡(luò)支持的stages數(shù)量
    bm_stage_info_t* stages;     // 表示該網(wǎng)絡(luò)支持的不同的shape情況
} bm_net_info_t;    // 表示一個(gè)網(wǎng)絡(luò)的全部信息
const bm_net_info_t* bmrt_get_network_info(void* p_bmrt, const char* net_name);
// 打印網(wǎng)絡(luò)的信息
void bmrt_print_network_info(const bm_net_info_t* net_info);

// 對(duì)指定的網(wǎng)絡(luò)蜓席,進(jìn)行npu推理
bool bmrt_launch_tensor(void* p_bmrt, const char * net_name,
                        const bm_tensor_t input_tensors[], int input_num,
                        bm_tensor_t output_tensors[], int output_num);
    // 會(huì)為output_tensors申請(qǐng)device mem,用于存儲(chǔ)結(jié)果數(shù)據(jù)课锌。
    // 輸出數(shù)據(jù)是以BM_STROE_1N存儲(chǔ)厨内;
    // 為異步接口,需要調(diào)用bm_thread_sync確保推理完成渺贤。
bool bmrt_launch_tensor_ex(void* p_bmrt, const char * net_name,
                           const bm_tensor_t input_tensors[], int input_num,
                           bm_tensor_t output_tensors[], int output_num,
                           bool user_mem, bool user_stmode);
    // 可以在output_tensors中指定輸出的device mem雏胃,以及輸出的store mode。
    // 為異步接口志鞍,需要調(diào)用bm_thread_sync確保推理完成瞭亮。
bool bmrt_launch_data(void* p_bmrt, const char* net_name, void* const input_datas[],
                      const bm_shape_t input_shapes[], int input_num, void * output_datas[],
                      bm_shape_t output_shapes[], int output_num, bool user_mem);
    // 輸入和輸出都存儲(chǔ)在系統(tǒng)內(nèi)存
    // 為同步接口,接口返回的時(shí)候推理已經(jīng)完成固棚。

// 校驗(yàn)runtime的數(shù)據(jù)统翩,打印runtime的一些信息,方便調(diào)試此洲。
void bmrt_trace(void* p_bmrt);
C++ Interface
  • 頭文件為bmruntime_cpp.h厂汗,lib庫(kù)為libbmrt.so
  • 線程安全
namespace bmruntime {
    class Context;  // 用于網(wǎng)絡(luò)管理,比如加載模型呜师,可以加載1個(gè)到多個(gè)模型娶桦;獲取網(wǎng)絡(luò)信息,可以得到已經(jīng)加載了的所有網(wǎng)絡(luò)的名稱汁汗,以及通過(guò)網(wǎng)絡(luò)名獲得某個(gè)具體網(wǎng)絡(luò)的信息衷畦。
    class Network; // 用于對(duì)某個(gè)具體網(wǎng)絡(luò)進(jìn)行推理,會(huì)自動(dòng)為該網(wǎng)絡(luò)申請(qǐng)輸入輸出的device memory知牌。
    class Tensor; // 用于對(duì)網(wǎng)絡(luò)的input tensors和output tensors進(jìn)行管理祈争。
    ......
};

explicit Context(int devid = 0);
explicit Context(bm_handle_t bm_handle);
Context ctx;
delete ctx;
    // 加載模型
    bm_status_t load_bmodel(const void *bmodel_data, size_t size);
    bm_status_t load_bmodel(const char *bmodel_file);

    // 獲得已加載的網(wǎng)絡(luò)的數(shù)量。
    int get_network_number() const;
    // 獲得已加載的網(wǎng)絡(luò)的名稱送爸,保存到names中铛嘱。
    void get_network_names(std::vector<const char *> *names) const;
    // 通過(guò)網(wǎng)絡(luò)名暖释,獲得某個(gè)具體網(wǎng)絡(luò)的信息。
    const bm_net_info_t *get_network_info(const char *net_name) const;

    // 得到context的設(shè)備句柄
    bm_handle_t handle() const;


Network(const Context &ctx, const char *net_name, int stage_id = -1);
    // 得到所有input tensors
    const std::vector<Tensor *> &Inputs();
    // 通過(guò)input name得到input tensor
    Tensor *Input(const char *tensor_name);

    // 網(wǎng)絡(luò)推理
    bm_status_t Forward(bool sync = true) const;
        // sync為false時(shí)墨吓,需要調(diào)用bm_thread_sync接口確保它推理結(jié)束球匕。

    // 得到output tensors
    const std::vector<Tensor *> &Outputs();
    // 通過(guò)output name得到output tensor
    Tensor *Output(const char *tensor_name);

    // 得到該網(wǎng)絡(luò)的信息
    const bm_net_info_t *info() const;


// 用戶不能自己創(chuàng)建Tensor,Tensor在Network類生成時(shí)自動(dòng)創(chuàng)建
    // 將tensor的device mem上的數(shù)據(jù)拷貝到系統(tǒng)內(nèi)存帖烘。
    bm_status_t CopyTo(void *data) const;
    bm_status_t CopyTo(void *data, size_t size, uint64_t offset = 0) const;

    // 將系統(tǒng)內(nèi)存的數(shù)據(jù)拷貝到tensor中的device mem亮曹。
    bm_status_t CopyFrom(const void *data);
    bm_status_t CopyFrom(const void *data, size_t size, uint64_t offset = 0);

    // 設(shè)置tensor的shape。
    bm_status_t Reshape(const bm_shape_t &shape);

    // 獲得tensor的數(shù)據(jù)的大小秘症,以字節(jié)為單位照卦。
    size_t ByteSize() const;
    // 獲得tensor的元素?cái)?shù)量。
    uint64_t num_elements() const;
    // 獲得tensor的bm_tensor_t結(jié)構(gòu)
    const bm_tensor_t *tensor() const;
    // 設(shè)置tensor的store mode乡摹。
    void set_store_mode(bm_store_mode_t mode) const;
    // 設(shè)置tensor的device mem役耕。
    bm_status_t set_device_mem(const bm_device_mem_t &device_mem);

3)bm_wrapper.hpp

需要在include/bmruntime/bm_wrapper.hpp頭文件中開啟宏定義USE_OPENCV和USE_FFMPEG

// Convert opencv Mat object to BMCV bm_image object
static inline bool bm_image_from_mat (cv::Mat &in, bm_image &out);
static inline bool bm_image_from_mat (std::vector<cv::Mat> &in, std::vector<bm_image> &out);

// Convert ffmpeg a avframe object to a BMCV bm_image object
static inline bool bm_image_from_frame (bm_handle_t &bm_handle,
                                      AVFrame           &in,
                                      bm_image          &out);
static inline bool bm_image_from_frame (bm_handle_t &bm_handle,
                                      std::vector<AVFrame> &in,
                                      std::vector<bm_image> &out);

// Copy a malloc() buffer to BMCV bm_image object
bm_status_t bm_image_copy_buffer (void *in, int size, bm_image &out)
bm_status_t bm_image_copy_buffer (const std::vector<void *> &in,
                                      const std::vector<int>    &size,
                                      std::vector<bm_image>     &out);

// create bm images with continuous device memory
bm_status_t bm_image_create_batch (bm_handle_t handle,
                                                 int img_h,
                                                 int img_w,
                                                 bm_image_format_ext img_format,
                                                 bm_image_data_format_ext data_type,
                                                 bm_image *image,
                                                 int batch_num,
                                                 int *stride = NULL,
                                                 int heap_mask = -1);
bm_status_t bm_image_destroy_batch (bm_image *image, int batch_num);

// Convert BMCV bm_image memory to bin
bm_status_t bm_image_dumpdata (bm_image &in, const char *output_name);

    
// 需要在include/bmruntime/bm_wrapper.hpp頭文件中開啟宏定義USE_OPENCV
// TPU推理模型(CPU程序會(huì)被阻塞)
static inline bool bm_inference (void *p_bmrt,
                                bm_image *input,
                                void *output,
                                bm_shape_t input_shape,
                                const char *net_name);
// * This API support single input && multi output, and multi thread safety
static inline bool bm_inference (void                       *p_bmrt,
                                bm_image                    *input,
                                std::vector<void*>         outputs,
                                bm_shape_t             input_shape,
                                const char               *net_name);
// * This API support multiple inputs && multiple outputs, and multi thread safety
static inline bool bm_inference (void                           *p_bmrt,
                                std::vector<bm_image*>          inputs,
                                std::vector<void*>             outputs,
                                std::vector<bm_shape_t>   input_shapes,
                                const char                   *net_name);

2.BMCV庫(kù)使用

BMCV開發(fā)參考手冊(cè)

BMCV 提供了一套基于 Sophon AI 芯片優(yōu)化的機(jī)器視覺(jué)庫(kù),通過(guò)利用芯片的 TPU 和 VPP 模塊聪廉,可以完成色彩空間轉(zhuǎn)換瞬痘、尺度變換、仿射變換、透射變換、線性變換瓣铣、畫框、JPEG編解碼津辩、BASE64編解碼、NMS容劳、排序喘沿、特征匹配等操作。

  • 頭文件為bmcv_api.h和bmcv_api_etx.h竭贩,lib庫(kù)為libbmcv.so
// ====== bmcv_api.h ======
typedef struct bm_image_t{
    bmcv_color_space color_space;
    bmcv_data_format data_format;
    bm_image_format image_format;
    int              image_width;
    int              image_height;
    bm_device_mem_t  data[MAX_bm_image_CHANNEL];
    int              stride[MAX_bm_image_CHANNEL];
}bmcv_image;

bm_status_t bm_img_yuv2bgr(bm_handle_t handle, bmcv_image input, bmcv_image output);
bm_status_t bmcv_img_crop(bm_handle_t handle, bmcv_image input,
                          int channels,
                          int top,
                          int left,
                          bmcv_image output);
bm_status_t  bmcv_img_bgrsplit(bm_handle_t handle, bmcv_image input, bmcv_image output);
bm_status_t  bmcv_img_transpose(bm_handle_t handle, bmcv_image input, bmcv_image output);

bm_status_t bmcv_img_scale(bm_handle_t handle, bmcv_image  input,
                           int n,
                           int do_crop, int top, int left, int height, int width,
                           unsigned char stretch, unsigned char padding_b, unsigned char padding_g, unsigned char padding_r,
                           int pixel_weight_bias,
                           float weight_b, float bias_b,
                           float weight_g, float bias_g,
                           float weight_r, float bias_r,
                           bmcv_image  output);
bm_status_t bmcv_gemm(bm_handle_t handle,
                      bool is_A_trans, bool is_B_trans,
                      int M, int N, int K,
                      float alpha,
                      bm_device_mem_t A, int lda,
                      bm_device_mem_t B, int ldb,
                      float beta,
                      bm_device_mem_t C, int ldc);

bm_status_t bm_image_to_bmcv_image(bm_image *src, bmcv_image *dst);



// ====== bmcv_api_etx.h ======
struct bm_image {
    int                      width;
    int                      height;
    bm_image_format_ext      image_format;
    bm_image_data_format_ext data_type;
    bm_image_private *       image_private = NULL;
};

// Create and fill bm_image structure
bm_status_t bm_image_create(bm_handle_t handle,
                            int img_h, int img_w,
                            bm_image_format_ext image_format,
                            bm_image_data_format_ext data_type,
                            bm_image * image,
                            int * stride = NULL);
bm_status_t bm_image_destroy(bm_image image);

bm_status_t bm_image_copy_host_to_device(bm_image image, void *   buffers[]);
bm_status_t bm_image_copy_device_to_host(bm_image image, void *   buffers[]);

bm_status_t bm_image_alloc_contiguous_mem(int image_num, bm_image *images, int heap_id = BMCV_HEAP_ANY);
bm_status_t bm_image_free_contiguous_mem(int image_num, bm_image *images);

bm_status_t bmcv_image_copy_to(bm_handle_t handle,
                               bmcv_copy_to_atrr_t copy_to_attr,
                               bm_image input,
                               bm_image output);
bm_status_t bmcv_image_crop(bm_handle_t handle,
                            int crop_num,
                            bmcv_rect_t * rects,
                            bm_image input,
                            bm_image * output);
bm_status_t bmcv_image_split(bm_handle_t handle,
                             bm_image input,
                             bm_image * output);

bm_status_t bmcv_image_jpeg_enc(bm_handle_t handle, int image_num, bm_image *  src,
        void ** p_jpeg_data,
        size_t * out_size,
        int quality_factor = 85);
bm_status_t bmcv_image_jpeg_dec(bm_handle_t handle, void ** p_jpeg_data, size_t * in_size,
        int image_num,
        bm_image *  dst);
......

3.sophon-mw使用

多媒體開發(fā)參考手冊(cè)

4.SAIL庫(kù)使用

sophon-sail使用手冊(cè)

SophonSDK通過(guò)SAIL庫(kù)(Sophon Artificial Intelligent Library)向用戶提供Python編程接口摹恨。其支持Python/C++編程接口編程。對(duì)BMRuntime娶视、 BMCV、 BMLib睁宰、BMDecoder庫(kù)的高級(jí)封裝肪获,將 SophonSDK中原有的“加載 BModel 并驅(qū)動(dòng) TPU 推理”、“驅(qū)動(dòng) TPU+VPP 做圖像處理”柒傻、“驅(qū)動(dòng) VPU 做圖像和視頻解碼”等功能抽象成更為簡(jiǎn)單的 C++ 接口對(duì)外提供孝赫;并且使用 pybind11 再次封裝,提供了簡(jiǎn)潔易用的 Python 接口红符。

SAIL 模塊中所有的類青柄、枚舉伐债、函數(shù)都在“sail”命名空間下,核心的類包括:

  • Handle:SDK中BMLib的bm_handle_t的包裝類致开,設(shè)備句柄峰锁,上下文信息,用來(lái)和內(nèi)核驅(qū)動(dòng)交互信息双戳。
  • Tensor:SDK中BMLib的包裝類虹蒋,封裝了對(duì)device memory的管理以及與system memory的同步。
  • Engine:SDK中BMRuntime的包裝類飒货,可以加載bmodel并驅(qū)動(dòng)TPU進(jìn)行推理魄衅。一個(gè)Engine實(shí)例可以加載一個(gè)任意的bmodel,自動(dòng)地管理輸入張量與輸出張量對(duì)應(yīng)的內(nèi)存塘辅。
  • Decoder:使用VPU解碼視頻晃虫,JPU解碼圖像,均為硬件解碼扣墩。
  • Bmcv:SDK中BMCV的包裝類哲银,封裝了一系列的圖像處理函數(shù),可以驅(qū)動(dòng) TPU 進(jìn)行圖像處理沮榜。

1)SAIL的編譯及安裝

cd sophon-sail_20230605_085400
tar -zxvf sophon-sail_3.5.0.tar.gz
cd sophon-sail

$ tree -L 2
├── 3rdparty
│   ├── catch.hpp
│   ├── inireader.hpp
│   ├── json
│   ├── jsoncpp.cpp
│   ├── prebuild
│   ├── pybind11
│   ├── spdlog
│   └── tabulate.hpp
├── build_unix.cmake
├── cmake
│   ├── BM168x_ARM_PCIE
│   ├── BM168x_LoongArch64
│   ├── BM168x_SOC
│   └── SAILConfig.cmake.in
├── CMakeLists.txt
├── docs
├── git_version
├── include
│   ├── algokit.h
│   ├── base64.h
│   ├── cvwrapper.h
│   ├── decoder_multi.h
│   ├── encoder.h
│   ├── engine.h
│   ├── engine_multi.h
│   ├── graph.h
│   ├── message_queue.hpp
│   ├── tensor.h
│   ├── tools.h
│   └── tpu_kernel_api.h
├── python
│   ├── arm_pcie
│   ├── pcie
│   └── soc
├── python_wheels
│   ├── arm_pcie
│   └── soc
├── README.md
├── sample
│   ├── cpp
│   └── python
└── src
    ├── algokit.cpp
    ├── base64.cpp
    ├── bind.cpp
    ├── CMakeLists.txt
    ├── cvwrapper.cpp
    ├── decoder_multi.cpp
    ├── encoder.cpp
    ├── engine.cpp
    ├── engine_multi.cpp
    ├── graph.cpp
    ├── internal.h
    ├── sail.pyi
    ├── tensor.cpp
    ├── tools.cpp
    └── tpu_kernel_api.cpp
  • 編譯可被C++接口調(diào)用的動(dòng)態(tài)庫(kù)及頭文件

    mkdir build && cd build
    
    # PCIE MODE 需預(yù)先安裝libsophon,sophon-ffmpeg,sophon-opencv
    cmake -DBUILD_PYSAIL=OFF ..
    
    # SOC MODE 需要指定依賴庫(kù)
    cmake -DBUILD_TYPE=soc -DBUILD_PYSAIL=OFF \
        -DCMAKE_TOOLCHAIN_FILE=../cmake/BM168x_SOC/ToolChain_aarch64_linux.cmake \
        -DLIBSOPHON_BASIC_PATH=../../../soc-sdk \
        -DFFMPEG_BASIC_PATH=../../../soc-sdk \
        -DOPENCV_BASIC_PATH=../../../soc-sdk  ..
    
    # ARM PCIE MODE 需要指定依賴庫(kù)
    cmake -DBUILD_TYPE=arm_pcie -DBUILD_PYSAIL=OFF \
        -DCMAKE_TOOLCHAIN_FILE=../cmake/BM168x_ARM_PCIE/ToolChain_aarch64_linux.cmake \
        -DLIBSOPHON_BASIC_PATH=../../../soc-sdk \
        -DFFMPEG_BASIC_PATH=../../../soc-sdk \
        -DOPENCV_BASIC_PATH=../../../soc-sdk  ..
    
    make sail
    sudo make install
      # 默認(rèn)安裝到/opt/sophon
    
  • 編譯可被Python3接口調(diào)用的Wheel文件

    mkdir build && cd build
    
    # PCIE MODE 需預(yù)先安裝libsophon,sophon-ffmpeg,sophon-opencv
    cmake  ..
    make pysail
    # 打包生成python wheel
    cd ../python/pcie
    chmod +x sophon_pcie_whl.sh
    ./sophon_pcie_whl.sh
      #  .whl文件輸出到dist路徑
      
    
    # SOC MODE 需要指定依賴庫(kù)
    cmake -DBUILD_TYPE=soc \
        -DCMAKE_TOOLCHAIN_FILE=../cmake/BM168x_SOC/ToolChain_aarch64_linux.cmake \
        -DPYTHON_EXECUTABLE=python_3.8.2/bin/python3 \    # 可以指定運(yùn)行環(huán)境的python版本
        -DCUSTOM_PY_LIBDIR=python_3.8.2/lib \
        -DLIBSOPHON_BASIC_PATH=../../../soc-sdk \
        -DFFMPEG_BASIC_PATH=../../../soc-sdk \
        -DOPENCV_BASIC_PATH=../../../soc-sdk  ..
    make pysail
    # 打包生成python wheel
    cd ../python/soc
    chmod +x sophon_soc_whl.sh
    ./sophon_soc_whl.sh
      #  .whl文件輸出到dist路徑
    
    
    # ARM PCIE MODE 需要指定依賴庫(kù)
    cmake -DBUILD_TYPE=arm_pcie -DBUILD_PYSAIL=OFF \
        -DCMAKE_TOOLCHAIN_FILE=../cmake/BM168x_ARM_PCIE/ToolChain_aarch64_linux.cmake \
        -DPYTHON_EXECUTABLE=python_3.8.2/bin/python3 \    # 可以指定運(yùn)行環(huán)境的python版本
        -DCUSTOM_PY_LIBDIR=python_3.8.2/lib \
        -DLIBSOPHON_BASIC_PATH=../../../soc-sdk \
        -DFFMPEG_BASIC_PATH=../../../soc-sdk \
        -DOPENCV_BASIC_PATH=../../../soc-sdk  ..
    make pysail
    # 打包生成python wheel
    cd ../python/arm_pcie
    chmod +x sophon_arm_pcie_whl.sh
    ./sophon_arm_pcie_whl.sh
      #  .whl文件輸出到dist路徑
    

2)使用SAIL的Python接口

示例

#define USE_FFMPEG  1
#define USE_OPENCV  1
#define USE_BMCV    1

#include <stdio.h>
#include <sail/cvwrapper.h>
#include <iostream>
#include <string>

using namespace std;

int main()
{
    int device_id = 0;
    std::string video_path = "test.avi";
    sail::Decoder decoder(video_path,true,device_id);
    if(!decoder.is_opened()){
        printf("Video[%s] read failed!\n",video_path.c_str());
        exit(1) ;
    }

    sail::Handle handle(device_id);
    sail::Bmcv bmcv(handle);

    while(true){
        sail::BMImage ost_image = decoder.read(handle);
        bmcv.imwrite("test.jpg", ost_image);
        break;
    }

    return 0;
}

3)使用SAIL的C++接口

5.sophon-demo

https://github.com/sophgo/sophon-demo

cd sophon-demo_20230605_085900
tar -zxvf sophon-demo_v0.1.6_f4d1abc_20230605.tar.gz
tree sophon-demo_v0.1.6_f4d1abc_20230605
├── cmake
│   └── common.cmake
├── CONTRIBUTING_CN.md
├── CONTRIBUTING_EN.md
├── docs
│   ├── Calibration_Guide_EN.md
│   ├── Calibration_Guide.md
│   ├── Environment_Install_Guide_EN.md
│   ├── Environment_Install_Guide.md
│   ├── FAQ_EN.md
│   ├── FAQ.md
│   ├── FP32BModel_Precise_Alignment_EN.md
│   ├── FP32BModel_Precise_Alignment.md
│   ├── torch.jit.trace_Guide_EN.md
│   └── torch.jit.trace_Guide.md
├── git_version
├── include
│   ├── bmnn_utils.h
│   ├── bm_wrapper.hpp
│   ├── ff_decode.hpp
│   ├── json.hpp
│   └── utils.hpp
├── LICENSE
├── README_EN.md
├── README.md
├── sample
│   ├── ByteTrack
│   ├── C3D
│   ├── CenterNet
│   ├── DeepSORT
│   ├── LPRNet
│   ├── OpenPose
│   ├── PP-OCR
│   ├── ResNet
│   ├── RetinaFace
│   ├── SSD
│   ├── WeNet
│   ├── yolact
│   ├── YOLOv34
│   ├── YOLOv5
│   ├── YOLOv5_opt
│   ├── YOLOv8
│   └── YOLOX
├── scripts
│   ├── auto_test_regression.sh
│   └── release.sh
└── src
    └── ff_decode.cpp

1)YOLOv8模型推理

https://github.com/sophgo/sophon-demo/tree/release/sample/YOLOv8

交叉編譯sample

# 安裝交叉編譯工具鏈
sudo apt-get install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

cd sophon-demo_20230605_085900/sophon-demo_v0.1.6_f4d1abc_20230605/sample/YOLOv8/cpp/yolov8_bmcv

mkdir build && cd build

#請(qǐng)根據(jù)實(shí)際情況修改-DSDK的路徑盘榨,需使用絕對(duì)路徑。
cmake -DTARGET_ARCH=soc -DSDK=/home/share/thirdparty/sophon/Release_230501-public/soc-sdk/ ..  
make -j12; cd -

$ file yolov8_bmcv.soc
yolov8_bmcv.soc: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=c27677bdeec30625bc78ecb20e742881b3693705, not stripped

模型推理

# 將yolov8_bmcv.soc和soc-sdk拷貝到BM1684設(shè)備上蟆融。

library="soc-sdk"
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${library}/lib/

./yolov8_bmcv.soc --input=datasets/test --bmodel=models/BM1684X/yolov8s_fp32_1b.bmodel --dev_id=0 --conf_thresh=0.5 --nms_thresh=0.7 --classnames=datasets/coco.names 

c++ yolov8_bmcv 關(guān)鍵代碼

#include <iostream>
#include <vector>
#include "opencv2/opencv.hpp"
#include "bmnn_utils.h"
#include "utils.hpp"
#include "bm_wrapper.hpp"
// Define USE_OPENCV for enabling OPENCV related funtions in bm_wrapper.hpp
#define USE_OPENCV 1
#define DEBUG 0


YoloV8::YoloV8(std::shared_ptr<BMNNContext> context) : m_bmContext(context) {
    std::cout << "YoloV8 ctor .." << std::endl;
}

int YoloV8::Init(float confThresh, float nmsThresh, const std::string& coco_names_file) {
    m_confThreshold = confThresh;
    m_nmsThreshold = nmsThresh;

    std::ifstream ifs(coco_names_file);
    if (ifs.is_open()) {
        std::string line;
        while (std::getline(ifs, line)) {
            line = line.substr(0, line.length() - 1);
            m_class_names.push_back(line);  // vector <string>
        }
    }

    // 1. get network
    m_bmNetwork = m_bmContext->network(0);

    // 2. get input
    max_batch = m_bmNetwork->maxBatch();
    auto tensor = m_bmNetwork->inputTensor(0);
    m_net_h = tensor->get_shape()->dims[2];
    m_net_w = tensor->get_shape()->dims[3];

    // 3. get output
    output_num = m_bmNetwork->outputTensorNum();
    assert(output_num > 0);
    min_dim = m_bmNetwork->outputTensor(0)->get_shape()->num_dims;

    // 4. initialize bmimages
    m_resized_imgs.resize(max_batch);
    m_converto_imgs.resize(max_batch);

    // some API only accept bm_image whose stride is aligned to 64
    int aligned_net_w = FFALIGN(m_net_w, 64);
    int strides[3] = {aligned_net_w, aligned_net_w, aligned_net_w};
    for (int i = 0; i < max_batch; i++) {
        auto ret = bm_image_create(m_bmContext->handle(), m_net_h, m_net_w, FORMAT_RGB_PLANAR, DATA_TYPE_EXT_1N_BYTE,
                                   &m_resized_imgs[i], strides);
        assert(BM_SUCCESS == ret);
    }
    bm_image_alloc_contiguous_mem(max_batch, m_resized_imgs.data());
    bm_image_data_format_ext img_dtype = DATA_TYPE_EXT_FLOAT32;
    if (tensor->get_dtype() == BM_INT8) {
        img_dtype = DATA_TYPE_EXT_1N_BYTE_SIGNED;
    }
    auto ret = bm_image_create_batch(m_bmContext->handle(), m_net_h, m_net_w, FORMAT_RGB_PLANAR, img_dtype,
                                     m_converto_imgs.data(), max_batch);
    assert(BM_SUCCESS == ret);

    // 5.converto
    float input_scale = tensor->get_scale();
    input_scale = input_scale * 1.0 / 255.f;
    converto_attr.alpha_0 = input_scale;
    converto_attr.beta_0 = 0;
    converto_attr.alpha_1 = input_scale;
    converto_attr.beta_1 = 0;
    converto_attr.alpha_2 = input_scale;
    converto_attr.beta_2 = 0;

    return 0;
}

int YoloV8::pre_process(const std::vector<bm_image>& images) {
    std::shared_ptr<BMNNTensor> input_tensor = m_bmNetwork->inputTensor(0);
    int image_n = images.size();

    // 1. resize image letterbox
    int ret = 0;
    for (int i = 0; i < image_n; ++i) {
        bm_image image1 = images[i];
        bm_image image_aligned;
        bool need_copy = image1.width & (64 - 1);
        if (need_copy) {
            int stride1[3], stride2[3];
            bm_image_get_stride(image1, stride1);
            stride2[0] = FFALIGN(stride1[0], 64);
            stride2[1] = FFALIGN(stride1[1], 64);
            stride2[2] = FFALIGN(stride1[2], 64);
            bm_image_create(m_bmContext->handle(), image1.height, image1.width, image1.image_format, image1.data_type,
                            &image_aligned, stride2);

            bm_image_alloc_dev_mem(image_aligned, BMCV_IMAGE_FOR_IN);
            bmcv_copy_to_atrr_t copyToAttr;
            memset(&copyToAttr, 0, sizeof(copyToAttr));
            copyToAttr.start_x = 0;
            copyToAttr.start_y = 0;
            copyToAttr.if_padding = 1;
            bmcv_image_copy_to(m_bmContext->handle(), copyToAttr, image1, image_aligned);
        } else {
            image_aligned = image1;
        }
#if USE_ASPECT_RATIO
        bool isAlignWidth = false;
        float ratio = get_aspect_scaled_ratio(images[i].width, images[i].height, m_net_w, m_net_h, &isAlignWidth);
        bmcv_padding_atrr_t padding_attr;
        memset(&padding_attr, 0, sizeof(padding_attr));
        padding_attr.dst_crop_sty = 0;
        padding_attr.dst_crop_stx = 0;
        padding_attr.padding_b = 114;
        padding_attr.padding_g = 114;
        padding_attr.padding_r = 114;
        padding_attr.if_memset = 1;
        if (isAlignWidth) {
            padding_attr.dst_crop_h = images[i].height * ratio;
            padding_attr.dst_crop_w = m_net_w;

            int ty1 = (int)((m_net_h - padding_attr.dst_crop_h) / 2);  // padding 大小
            padding_attr.dst_crop_sty = ty1;
            padding_attr.dst_crop_stx = 0;
        } else {
            padding_attr.dst_crop_h = m_net_h;
            padding_attr.dst_crop_w = images[i].width * ratio;

            int tx1 = (int)((m_net_w - padding_attr.dst_crop_w) / 2);
            padding_attr.dst_crop_sty = 0;
            padding_attr.dst_crop_stx = tx1;
        }

        bmcv_rect_t crop_rect{0, 0, image1.width, image1.height};
        auto ret = bmcv_image_vpp_convert_padding(m_bmContext->handle(), 1, image_aligned, &m_resized_imgs[i],
                                                  &padding_attr, &crop_rect);
#else
        auto ret = bmcv_image_vpp_convert(m_bmContext->handle(), 1, images[i], &m_resized_imgs[i]);
#endif
        assert(BM_SUCCESS == ret);
        if (need_copy)
            bm_image_destroy(image_aligned);
    }

    // 2. converto img /= 255
    ret = bmcv_image_convert_to(m_bmContext->handle(), image_n, converto_attr, m_resized_imgs.data(),
                                m_converto_imgs.data());
    CV_Assert(ret == 0);

    // 3. attach to tensor
    if (image_n != max_batch)
        image_n = m_bmNetwork->get_nearest_batch(image_n);
    bm_device_mem_t input_dev_mem;
    bm_image_get_contiguous_device_mem(image_n, m_converto_imgs.data(), &input_dev_mem);
    input_tensor->set_device_mem(&input_dev_mem);
    input_tensor->set_shape_by_dim(0, image_n);  // set real batch number

    return 0;
}

float YoloV8::get_aspect_scaled_ratio(int src_w, int src_h, int dst_w, int dst_h, bool* pIsAligWidth) {
    float ratio;
    float r_w = (float)dst_w / src_w;
    float r_h = (float)dst_h / src_h;
    if (r_h > r_w) {
        *pIsAligWidth = true;
        ratio = r_w;
    } else {
        *pIsAligWidth = false;
        ratio = r_h;
    }
    return ratio;
}

int YoloV8::post_process(const std::vector<bm_image>& images, std::vector<YoloV8BoxVec>& detected_boxes) {
    YoloV8BoxVec yolobox_vec;
    std::vector<cv::Rect> bbox_vec;
    std::vector<std::shared_ptr<BMNNTensor>> outputTensors(output_num);

    for (int i = 0; i < output_num; i++) {
        outputTensors[i] = m_bmNetwork->outputTensor(i);
    }

    for (int batch_idx = 0; batch_idx < images.size(); ++batch_idx) {
        yolobox_vec.clear();
        auto& frame = images[batch_idx];
        int frame_width = frame.width;
        int frame_height = frame.height;

        int min_idx = 0;
        int box_num = 0;

        // Single output
        auto out_tensor = outputTensors[min_idx];
        m_class_num = out_tensor->get_shape()->dims[1] - mask_num - 4;
        int feat_num = out_tensor->get_shape()->dims[2];
        int nout = m_class_num + mask_num + 4;
        float* output_data = nullptr;
        std::vector<float> decoded_data;

        LOG_TS(m_ts, "post 1: get output");
        assert(box_num == 0 || box_num == out_tensor->get_shape()->dims[1]);
        box_num = out_tensor->get_shape()->dims[1];
        output_data = (float*)out_tensor->get_cpu_data() + batch_idx * feat_num * (m_class_num + mask_num + 4);
        LOG_TS(m_ts, "post 1: get output");
    }

    return 0;
}

int YoloV8::Detect(const std::vector<bm_image>& input_images, std::vector<YoloV8BoxVec>& boxes) {
    int ret = 0;
    // 3. preprocess
    ret = pre_process(input_images);

    // 4. forward
    LOG_TS(m_ts, "yolov8 inference");
    ret = m_bmNetwork->forward();
  
    // 5. post process
    ret = post_process(input_images, boxes);
    return ret;
}

int main(int argc, char *argv[]) {
    // creat handle
    BMNNHandlePtr handle = make_shared<BMNNHandle>(dev_id);
    cout << "set device id: "  << dev_id << endl;
    bm_handle_t h = handle->handle();

    // load bmodel
    shared_ptr<BMNNContext> bm_ctx = make_shared<BMNNContext>(handle, bmodel_file.c_str());

    // initialize net
    YoloV8 yolov8(bm_ctx);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末草巡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子型酥,更是在濱河造成了極大的恐慌山憨,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弥喉,死亡現(xiàn)場(chǎng)離奇詭異郁竟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)由境,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門棚亩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人虏杰,你說(shuō)我怎么就攤上這事讥蟆。” “怎么了纺阔?”我有些...
    開封第一講書人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵瘸彤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我笛钝,道長(zhǎng)质况,這世上最難降的妖魔是什么愕宋? 我笑而不...
    開封第一講書人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮结榄,結(jié)果婚禮上中贝,老公的妹妹穿的比我還像新娘。我一直安慰自己潭陪,他們只是感情好雄妥,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著依溯,像睡著了一般老厌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上黎炉,一...
    開封第一講書人閱讀 52,158評(píng)論 1 308
  • 那天枝秤,我揣著相機(jī)與錄音,去河邊找鬼慷嗜。 笑死淀弹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的庆械。 我是一名探鬼主播薇溃,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼缭乘!你這毒婦竟也來(lái)了沐序?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤堕绩,失蹤者是張志新(化名)和其女友劉穎策幼,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體奴紧,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡特姐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了黍氮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唐含。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖沫浆,靈堂內(nèi)的尸體忽然破棺而出觉壶,到底是詐尸還是另有隱情,我是刑警寧澤件缸,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站叔遂,受9級(jí)特大地震影響他炊,放射性物質(zhì)發(fā)生泄漏争剿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一痊末、第九天 我趴在偏房一處隱蔽的房頂上張望蚕苇。 院中可真熱鬧,春花似錦凿叠、人聲如沸涩笤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蹬碧。三九已至,卻和暖如春炒刁,著一層夾襖步出監(jiān)牢的瞬間恩沽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工翔始, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罗心,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓城瞎,卻偏偏與公主長(zhǎng)得像渤闷,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子脖镀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

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