华为Ascend芯片显卡docker环境搭建并完成YOLO8推理

目前随着AI应用的爆发式增长,支持AI模型训练的显卡硬件也变得炙手可热。目前,由于xx颁布了芯片销售禁令,随着而来的是,在国内高端的英伟达显卡买不到了,中低端的显卡价格也水涨船高。在此环境下,华为技术有限公司自研的达芬奇架构的Ascend芯片映入了AI开发者的视野,据说Ascend910高端型号的芯片的算力已经跟NVIDIA A100旗鼓相当,但是前者价格是后者的十分之一!!! 目前国内生成式AI巨头,比如阿里的通义千问,智谱AI的ChatGLM都对华为Ascend芯片做了适配,可见未来Ascend芯片无论是市场前景还是行业应用,都将越来越普遍,或许在不久,显卡不再是英伟达一家独大。

想了解更多有关Ascend芯片的架构及特点,可以查看官方写的论文,地址:

Ascend: a Scalable and Unified Architecture for Ubiquitous Deep Neural Network Computing : Industry Track Paper | IEEE Conference Publication | IEEE Xplore

本文记录如何在拥有Ascend310芯片的Ubuntu服务器上搭建docker推理环境并完成YOLO8推理。

一、驱动下载安装

直接到Ascend官网,根据自己的芯片型号下载对应的驱动

固件与驱动-昇腾社区

我们安装上面页面给出的下载链接,下载driver和固件

驱动的安装也较为简单,首先增加对软件包的可执行权限

chmod +x A300-3010-npu-driver_23.0.0_linux-x86_64.run
chmod +x A300-3010-npu-firmware_7.1.0.3.220.run

然后执行下面的命令安装:

./A300-3010-npu-driver_23.0.0_linux-x86_64.run --full --install-for-all

关机重启,驱动安装成功

关于驱动安装,官方也给出了具体的详细教程:

昇腾社区-官网丨昇腾万里 让智能无所不及

二、Docker环境搭建

Ascend芯片推理环境我们选择在docker容器内搭建,AscendHub上有各种各样已经搭建好相关环境的Docker镜像,只需要宿主机有ascend芯片和驱动即可,免去了我们手动下载配置CANN、mxvision等软件。因此,这种环境配置方式首先需要在服务器上安装好docker,docker的安装较为简单,如果没有安装,apt源设置正确且可用,直接按照下面的步骤即可安装docker。

安装好docker以后就可以下载ascendhub的官方镜像,下面给出AscendHub地址:

AscendHub

我们直接注册账号然后按照上面给出的步骤把docker images下载到服务器即可。值得注意的是宿主机需要满足下面的调条件:

  • 物理机上有Ascend芯片
  • 物理机已安装对应CANN版本的驱动和固件(注意跟你要下载的镜像支持的驱动对应,比如在ascendhub下载的镜像往往是最新版本的cann、mxvision,此时宿主机的驱动版本注意对应,如果驱动太老的话是不行的,需要升级或者重装。版本对应关系可以从下面给出的昇腾官网查询到)
  • 物理机已安装Docker,且Docker网络可用

我这里以安装 infer-modelzoo 镜像(mxvision版本)为例,该镜像包含模型转换、模型推理等功能。

将镜像下载到本地以后,docker启动命令示例如下

docker run -it \
--device=/dev/davinci0 \
--device=/dev/davinci_manager \
--device=/dev/devmm_svm \
--device=/dev/hisi_hdc \
-v /usr/local/dcmi:/usr/local/dcmi \
-v /var/log/npu:/var/log/npu \
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
-v /usr/slog:/usr/slog \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
-v /usr/local/Ascend/driver/tools/:/usr/local/Ascend/driver/tools/ \
-v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \
-v /data:/data \
ascendhub.huawei.com/public-ascendhub/infer-modelzoo:{tag} \
/bin/bash
  • tag为镜像版本号,如21.0.3。
  • -u 以指定用户进入容器,如不指定用户,默认为HwHiAiUser。
  • /usr/local/Ascend/driver为物理机上安装的NPU驱动目录,根据实际安装的驱动目录进行挂载。
  • /data为模型转换和推理要用的代码目录,根据实际代码目录进行挂载。
  • 命令中默认挂载0卡到容器中,可根据实际需要挂载device。

下面是我自己的docker容器启动命令:

docker run -itd --name ascend-infer --network=host --device=/dev/davinci0 --device=/dev/davinci_manager --device=/
dev/devmm_svm --device=/dev/hisi_hdc -v /usr/local/dcmi:/usr/local/dcmi -v /var/log/npu:/var/log/npu -v /usr/local/Ascend/driver:/usr/local/Ascend/driver -v
 /usr/slog:/usr/slog -v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi -v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ -v /usr/local/Ascen
d/driver/tools/:/usr/local/Ascend/driver/tools/ -v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ -v /work:/work ascendhub.huawei.com/public-ascendhub/infer-modelzoo:23.0.RC2-mxvision /bin/bash

上图可以看到,我们成功启动了容器并进入到了容器中。

三、模型转化

接下来我们在本地电脑将yolov8s.pt转onnx(我这里直接用的是yolo export命令)

特别需要注意,pt模型转onnx模型的过程中,onnx算子版本必须保持为11,否则后onnx转om会失败!!!

将转化好的ONNX模型上传到服务器的work目录下(由于容器启动的时候/work挂载/work,因此将本地的onnx模型上传到根目录下的/work目录下,在容器内就可以使用该onnx文件)

下面在容器内对onnx模型进行转化,将其转化为适用于Ascend显卡平台的om模型 。这里我们要使用到ATC转化工具(上面运行的容器内有安装好),下面首先简单了解一下ATC命令:

atc --model=./yolov8s.onnx --framework=5 --output=./yolov8s --input_format=NCHW --input_shape="images:1,3,640,640" --soc_version=Ascend310

--model:待转换的ONNX模型。(必须)

--framework:5代表ONNX模型。(必须)

--output:输出的om模型。(必须)

--input_format:输入数据的格式。Caffe、ONNX默认为NCHW;TensorFlow默认为NHWC。

--input_shape:输入数据的shape

--soc_version: 模型转换时指定芯片版本(必须)

上面的转换指令几乎是最简的,更多atc转化参数请参考官方文档,链接如下:

昇腾社区-官网丨昇腾万里 让智能无所不及

我这里以HwHiAiUser用户登录进docker容器内执行 上述atc模型转换命令出现报错,有大量的Permission Error。(因为我是以root登录进服务器并且以root身份将onnx文件上传到服务器,因此onnx文件所属组和拥有组都是root)

大概是 HwHiAiUser用户无相关权限,退出容器以root身份进入docker内,重新执行上述atc模型转化命令,成功。

此时,在容器内的/work目录下可以看到成功转化的yolov8s.om模型。

接下来修改yolov8s.om所属组和拥有者,使其所属用户和用户组为HwHiAiUser

chown HwHiAiUser:HwHiAiUser yolov8s.om
chown HwHiAiUser:HwHiAiUser fusion_result.json

可以直接将yolo8s.om所在的上级目录(work目录)更改为所属用户和用户组为HwHiAiUser

chown -R HwHiAiUser:HwHiAiUser /work

四、使用mxvision sdk进行推理

接下来我们mxvision使用yolov8s.om模型进行加速推理 。官方也有详细的教程:

开发流程-使用API接口方式开发(Python)-mxVision 用户指南-智能视频分析-MindX SDK5.0.1开发文档-昇腾社区 (hiascend.com)

mxvision sdk一般有两种推理方式。一种是pipeline,需要我们写pipeline文件,不得不说ascend自带的视频图片编解码能力(DVPP、AIPP)真的很强大,不仅自持硬件加速功能,而且模块都封装好了,只需要我们调用相关接口即可,比如图片直接输入、视频流直接输入rtsp流地址即可,无需我们自己写编解码程序、写前处理程序、写后处理程序,直接将模型预测结果返回!!! 改变了我们过去需要用opencv numpy等去做相关的工作。第二种是使用api的方式,这种方式不常用,官方给出的案例都是pipeline推理方式,几乎没有一个完整的api推理的案例,唯一可借鉴的是ascend论坛给出的:

https://www.hiascend.com/forum/thread-0281145770724671193-1-1.html

我们这里使用api推理方式,因为这种方式最符合我们过去使用pytorch、paddlepaddle、tensorflow等原生框架推理、ONNX中间态推理的风格习惯,而使用pipeline推理虽然代码量很少很少,但是得要我们比较深入地了解pipeline的流程及芯片内置的模块、接口等。有的项目为了适配不同的平台,可能分为Tensorrt推理版本的代码、onnx推理版本的代码、opencv dnn推理版本的代码 、openvion推理版本.....而使用api推理只需要我们修改之前写过的很少的代码,就拿onnx推理版本来说,基本上修改几行代码即可将onnx推理版本的代码修改为华为Ascend推理版本的代码。

import cv2
import numpy as np
import time
from mindx.sdk import Tensor  # mxVision 中的 Tensor 数据结构
from mindx.sdk import base

CLASSES={0: 'person', 1: 'bicycle', 2: 'car', 3: 'motorcycle', 4: 'airplane', 5: 'bus', 
 6: 'train', 7: 'truck', 8: 'boat', 9: 'traffic light', 10: 'fire hydrant', 
 11: 'stop sign', 12: 'parking meter', 13: 'bench', 14: 'bird', 15: 'cat', 
 16: 'dog', 17: 'horse', 18: 'sheep', 19: 'cow', 20: 'elephant', 21: 'bear', 
 22: 'zebra', 23: 'giraffe', 24: 'backpack', 25: 'umbrella', 26: 'handbag', 
 27: 'tie', 28: 'suitcase', 29: 'frisbee', 30: 'skis', 31: 'snowboard',
 32: 'sports ball', 33: 'kite', 34: 'baseball bat', 35: 'baseball glove',
 36: 'skateboard', 37: 'surfboard', 38: 'tennis racket', 39: 'bottle', 
 40: 'wine glass', 41: 'cup', 42: 'fork', 43: 'knife', 44: 'spoon', 45: 'bowl', 
 46: 'banana', 47: 'apple', 48: 'sandwich', 49: 'orange', 50: 'broccoli', 
 51: 'carrot', 52: 'hot dog', 53: 'pizza', 54: 'donut', 55: 'cake', 56: 'chair', 
 57: 'couch', 58: 'potted plant', 59: 'bed', 60: 'dining table', 61: 'toilet', 
 62: 'tv', 63: 'laptop', 64: 'mouse', 65: 'remote', 66: 'keyboard', 67: 'cell phone',
 68: 'microwave', 69: 'oven', 70: 'toaster', 71: 'sink', 72: 'refrigerator', 
 73: 'book', 74: 'clock', 75: 'vase', 76: 'scissors', 77: 'teddy bear', 
 78: 'hair drier', 79: 'toothbrush'}

class YOLO8:
    def __init__(self,model_path,conf_thres=0.25, iou_thres=0.45):
        self.conf_threshold = conf_thres
        self.iou_threshold = iou_thres
        self.input_height=640
        self.input_width=640
        self.class_names=CLASSES
        reverse_class_names = {v : k for k, v in self.class_names.items()}
        self.reverse_class_names=reverse_class_names
        #模型初始化
        base.mx_init()
        self.model = base.model(modelPath='yolov8s.om', deviceId=0) 
        
    #前处理模块
    def pre_process(self,img, new_shape):
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img, _, _ = self.letterbox(img, new_shape)
        img = img.astype('float32')
        img /= 255.0
        img = np.transpose(img, [2, 0, 1])
        img = np.expand_dims(img, axis=0)
        img = np.ascontiguousarray(img)
        return img
    #推理模块
    def inference(self,img):
        # print(img)
        img_tensor = Tensor(img)
        img_tensor.to_device(0)
        start = time.perf_counter()
        outputs = self.model.infer([img_tensor])
        print(f"Inference time: {(time.perf_counter() - start) * 1000:.2f} ms")
        nps = [] # 原始numpy结果数组
        for i in range(len(outputs)):
            outputs[i].to_host()
            n = np.array(outputs[i])
            nps.append(n) # 使用自定义后处理时直接用此numpy数组即可!!!
        #这里的nps 数组维度就是[1,84,8400].后续就可以后处理了
        return nps
    .......
    letterbox nms 后处理等模块与原来保持一致,此处省略

然后执行我们写好的yolo8_om_det.py ,我这里推理了yolo官方给出的bus.jpg(下图),推理尺寸640*640

可以看到程序执行成功,整个推理过程为14ms左右,我这里的服务器是租用的,应该是租用服务器Ascend310算力做了切分之类的,反正这个推理速度不是正常的,不过这个主要以演示为主,正常的应该是3ms以内推理一张图片,下面是图片推理结果

相关推荐
pk_xz12345626 分钟前
Shell 脚本中变量和字符串的入门介绍
linux·运维·服务器
小珑也要变强29 分钟前
Linux之sed命令详解
linux·运维·服务器
Lary_Rock3 小时前
RK3576 LINUX RKNN SDK 测试
linux·运维·服务器
昌sit!5 小时前
K8S node节点没有相应的pod镜像运行故障处理办法
云原生·容器·kubernetes
追风林6 小时前
mac 本地docker-mysql主从复制部署
mysql·macos·docker
一坨阿亮6 小时前
Linux 使用中的问题
linux·运维
A ?Charis8 小时前
Gitlab-runner running on Kubernetes - hostAliases
容器·kubernetes·gitlab
城南vision8 小时前
Docker学习—Docker核心概念总结
java·学习·docker
wclass-zhengge8 小时前
Docker篇(Docker Compose)
运维·docker·容器
李启柱8 小时前
项目开发流程规范文档
运维·软件构建·个人开发·设计规范