Vitis-AI量化编译YOLOv5(Pytorch框架)并部署ZCU104(一)(代码已开源)

白敬亭分亭 2024-06-18 12:31:01 阅读 57


文章目录

前言

 一、Vitis-AI Pytorch框架量化(vai_q_pytorch)

 二、编写量化脚本并进行量化

 三、模型编译

总结


前言

Github仓库上传量化全部源码,需要自取(顺手点一个star)

Vitis-AI量化

--------------------------------------------

        虽然Xilinx提供了Vitis-AI用户手册Vitis-AI 2.5用户手册,但是其中对于一些安装和使用介绍极为简略,在安装和使用过程中碰到了一系列问题,所以在这里记录一下使用Vitis-AI过程中遇到的各种坑。

一、Vitis-AI Pytorch框架量化(vai_q_pytorch)

     我们使用的是pytorch框架的yolo模型,在使用vitis-ai量化前根据指导手册,要安装vai_q_pytorch,但是需要注意,我们在安装过程中一直在报错,如下图。

453e94221fc244178c0acb2d6e006b27.png

      上图中几个package一直无法下载,一开始根据下方报错,以为是代理问题,我们尝试寻找代理服务器去下载,发现还是这几个包无法正常下载。

      仔细观察了无法下载的几个package,发现有一个共同特点,就是版本号均为2.5.0,这就很奇怪了,为什么全都是2.5.0版本的package无法下载,于是去看xilinx提供的下载脚本,突然发现这么一行,该行命令是提供下载地址的,如下图:

508c3d06190c41249e3f2ce2a8b3fc2e.png

      此时恍然大悟啊!官方提供的最新脚本中版本号是2.0.0,而执行安装命令时默认安装版本号是2.5.0,所以下载好的package里没有所需要的版本号,自然无法安装对应package。知道问题后,接下来就是寻找2.5.0版本的下载包地址(个人觉得Xilinx很狗,这么大的企业,对这些软件的维护,修改信息全都放在GitHub上)。在GitHub Xilinx账号下找到了其更新后的下载脚本,接下来就很简单了,将更新后的脚本copy到conda环境中,重新运行命令即可正常安装。可以看到下图中版本号为正确的2.5.0。

c154b9641d2549d2b55f07601fbc899e.png

(Ps:正确脚本地址:val_q_pytorch2.5.0脚本)

 二、编写量化脚本并进行量化

      Xilinx用户手册提供的语言可以看一下:

503cadaeb0284f7e9c0a2b78d627bb78.png

      

      ???一脸问号,这只提供了API接口,里面对于模型的处理,数据的导入完全没有介绍,那就只能自己来写,可以参考官方量化脚本。pytorch模型量化代码(minst数据集手写体识别)

icon-default.png?t=N7T8

https://github.com/Xilinx/Vitis-AI-Tutorials/blob/1.4/Design_Tutorials/09-mnist_pyt/files/quantize.py

      可以发现主要包括几部分:读取模型、调用数据集、常规预测函数(包括Detect、前向传播等等)、量化校准、Xmodel生成。

      首先我们来看一下模型的读取。

model = model.to(device)model_name = "yolov5" file_path = os.path.join(args.model_dir, model_name + '.pt')

      根据自己选择使用GPU还是CPU。

if (torch.cuda.device_count() > 0): print('You have',torch.cuda.device_count(),'CUDA devices available') for i in range(torch.cuda.device_count()): print(' Device',str(i),': ',torch.cuda.get_device_name(i)) print('Selecting device 0..') device = torch.device('cuda:0') else: print('No CUDA devices available..selecting CPU') device = torch.device('cpu')

      加载数据集,因为我使用的是Coco数据集,所以Class数为80(具体数字根据自己数据集和所训练的模型决定)。

parser.add_argument('--data_dir',default="datasets/val", help='Data set directory, when quant_mode=calib, it is for calibration, while quant_mode=test it is for evaluation')dataloader = create_dataloader(args.data_dir, imgsz=imgsz, batch_size=batch_size, pad=0.5,stride=32, workers=workers, prefix=colorstr(f'quant: '))[0]model.eval() nc =80 # number of classes

      在脚本中加入Detect时需要注意,在用户手册中有这么一段话,如下图。

080bd311a2004f8d9f76fe386062ac1e.png

       可以看到,脚本中只能包含前传函数,所以需要将特征提取中多余的部分注释掉,仅保留下面代码即可。

z = [] for i in range(nl): bs, _, ny, nx, _no= x[i].shape # x[i] = x[i].view(bs, na, no, ny, nx).permute(0, 1, 3, 4, 2).contiguous() if grid[i].shape[2:4] != x[i].shape[2:4]: grid[i], anchor_grid[i] = _make_grid(anchors,stride,nx, ny, i)

    之后是模型推理部分(部分代码)。

x=model(im) # ckpt = torch.load(file_path, map_location=device) # paras=ckpt['model'].yaml nc = 10 # number of classfication no = nc+5 #each anchor's output,include nc(class)+conf(1)+xywh(4),故nc+5 anchors = [[1.25, 1.625, 2, 3.75, 4.125, 2.875], [1.875, 3.8125, 3.875, 2.8125, 3.6875, 7.4375], [3.625, 2.8125, 4.875, 6.1875, 11.65625, 10.1875]] nl = 3 # number of detection layers na = 3 # number of anchors grid = [torch.zeros(1)] * nl # init grid anchors = torch.tensor(anchors).float().view(nl, -1, 2) # register_buffer('anchors', a) anchor_grid=[torch.zeros(1)] * nl stride = [8, 16, 32]

        脚本写好之后便可以开始模型的量化,分为两步,第一步是量化校准,使用如下命令。可以看到校准过程。

python quantize.py --quant_mode calib --subset_len 1

625a176f2ce940fda8b86ed6888f0eb7.png

         第二部便是生成.Xmodel文件,使用如下命令,可以看到生成过程。

934760cee0fb4c14b07082dd1c7f73b2.png

        查看量化后F1参数,精度并没有过多损失。

fb6e9ea49631472eb32b324acac67e58.png

 三模型编译

       这一步才是最容易踩坑的地方!!可以看到上一步量化后精度还是很不错的!此时大部分工作已经完成,编译时候仅需要一行命令就可以解决,选择相对应FPGA开发板DPU的型号:

vai_c_xir -x ./quantize_result/DetectMultiBackend_int.xmodel -a /opt/vitis_ai/compiler/arch/DPUCZDX8G/ZCU104/arch.json -o ./ -n model

       很简单对吧!但是编译结束后,我们发现有多个DPU子图的模型(下图红框位置),说明此时模型并没有被完整的量化编译过来。

8180f340217d4cbda9de3f35ab140149.png

​      

       红框位置正确编译后应该只会生成一个子图,也就是DPU subgraph number为1,那么问题出在哪里呢?

       首先需要检查量化脚本中是否按照手册要求仅保留前传函数,其余函数均移除,经过检查是没有问题的。

       那么问题只能是模型中存在了DPU不能够识别的算子,才会导致生成多个子图,我们打开DPUCZDX8G产品指南,可以清楚看到该型号下DPU所支持的算子,如下图。

722662c0430f4184a551474a90c1a9a0.png

       相信大家看到后肯定明白问题出在哪里了!那就是激活函数的问题,我们本次yolo模型选用的是yolov5 6.0及以上版本,这些版本中一个显著的变化就是激活函数已经更改为SiLu,我们可以看到SiLu并不在该型号DPU支持算子目录下,为了验证猜想,我们将生成的.Xmodel用Netron工具打开,我们可以看到量化模型结构(其中一小部分)如下图: 

41f63afeca3c4634afa975e4f10e5c77.png

       可以看到红框部分就是我们所用模型的激活函数,果然!激活函数是silu,不是DPU所支持的算子类型,我们将其改为ReLu,之后重新编译,得到下图:

77a43a45603e4615b6621c5d1561a1c8.png

       可以看到,DPU subgraph number为1!编译成功!! 


   

总结

       以上就是今天要讲的我在使用Vitis-AI过程中才的一些坑,本文仅仅简单介绍了Vitis-AI量化编译的过程,后续在ZCU104开发板的部署将持续更新。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。