如何在KV260上快速体验Vitsi AI图像分类示例程序

本文首先将会对vitis统一软件平台和vitsi ai进行简单介绍,然后介绍如何在kv260上部署dpu镜像,最后在kv260 dpu镜像上运行vitis ai自带的图像分类示例。通过本文,你将会对vitis软件平台、vitsi ai架构有初步认识,并知道如何在kv260上快速体验vitsi ai图像分类示例程序。
01一、背景简介
开始本文的实操环节之前,这里我先介绍一些背景知识,分别是vitis统一软件平台和vitis ai。
1.1 vitis 统一软件平台简介
来自xilinx官网的简介,vitis 统一软件平台包括:
全面的内核开发套件,可无缝构建加速应用
完整的硬件加速开源库,针对 amd fpga 和 versal 自适应 soc 硬件平台进行了优化
插入特定领域的开发环境,可直接在熟悉的更高层次框架中进行开发
不断发展的硬件加速合作伙伴库和预建应用生态系统
vitis model composer 是一款基于模型的设计工具,不仅可在 mathworks matlab 和 simulink 环境中实现快速设计探索与验证 ,而且还可加速 amd 器件的生产进程。
vitis networking p4 允许创建软定义网络。vitisnetp4 数据平面构建器生成的系统可以针对从简单的数据包分类到复杂的数据包编辑的各种数据包处理功能进行编程。
来自官网的vitis统一软件平台架构图:
从官网的介绍页面我们也可以看到,vitis 统一软件平台包括如下组件:
vitis ai
vitis 视频分析sdk
vitis 库
vitis hls
vitis model composer
今天我们将会重点介绍vitis ai。
1.2 vitsi ai简介
本节内容主要参考了自官方github.io文档。
amd vitis ai 是一个集成开发环境,可用于加速 amd 平台上的 ai 推理。该工具链提供优化的ip、工具、库、模型以及资源,例如示例设计和教程,可在整个开发过程中为用户提供帮助。它在设计时充分考虑了高效率和易用性,在 amd 自适应 soc 和 alveo 数据中心加速卡上释放了 ai 加速的全部潜力。
vitis ai 解决方案由三个主要组件组成:
深度学习处理器单元 (dpu),用于优化 ml 模型推理的硬件引擎。
模型开发工具,用于为 dpu 编译和优化 ml 模型。
模型部署库和 api,用于从软件应用程序在 dpu 引擎上集成和执行 ml 模型。
vitis ai 解决方案的打包和交付方式如下:
amd 开放下载:集成 dpu 的预构建目标映像(以下简称“dpu镜像”)
vitis ai docker容器:模型开发工具
vitis ai github 存储库:模型部署库、设置脚本、示例和参考设计
02二、部署dpu镜像到kv260
2.1 下载dpu镜像
在kv260开发板上正式体验vitis ai之前,需要将上一节中提到的dpu镜像下载下来并烧录到sd上。
支持kv260的最新dpu镜像下载链接:https://china.xilinx.com/member/forms/download/design-license-xef.html?filename=xilinx-kv260-dpu-v2022.2-v3.0.0.img.gz
2.2 写入dpu镜像到sd卡
下载完成后,解压压缩包,通过rufus将解压的wic文件写入sd卡。使用rufus选择文件时,需要注意将右侧的默认文件类型修改为全部文件,否则默认不支持wic文件:
写入过程显示进度:
2.3 启动dpu镜像系统
完成dpu镜像写入sd卡后,将sd卡读卡器从pc移除后,将sd卡插入到开发板,插好串口线,打开串口终端,波特率设置为115200,就可以准备上电开机了。
启动之后会自动登录root账号(默认密码为root):
插上网线的话,启动后还可以看到输出了dashborad访问链接:
根据ifconfig查看的ip地址,浏览器访问dashboard链接,可以看到实时状态监控:
03三、运行vitsi ai图像分类示例
3.1 dpu镜像自带的一些文件介绍
dpu镜像默认带有ssh服务,并且是开机启动的,因此可以使用mobaxterm的ssh客户端通过网络登录kv260,如下图所示:
mobaxterm的ssh客户端时带有x11-forwarding功能的,支持将远程程序界面通过ssh协议显示在本地。
登录系统后,可以看到,/home/root目录下已经有了两个目录。
使用tree命令,可以看到vitis-ai目录结构:
接下来我们将会尝试运行vai_runtime下的resnet50示例程序,我们先看看这个目录下的文件结构:
里面有文件的作用分别为:
build.sh,编译脚本,里面包含编译src/main.cc的命令
resnet50,已经编译好的可执行程序,由src/main.cc编译生成
readme,说明文件
words.txt,分类标签
src/main.cc,示例程序源码
dpu镜像默认已经安装了gcc,直接运行build.sh就可以编译src/main.cc,并生成resnet50可执行文件。可以尝试将resnet50可执行文件删除掉,再运行build.sh脚本,观察是否重新生成了resnet50。
3.2 下载resnet50测试图片
通过以下命令,下载并解压resnet50测试图片:
cd ~wget https://china.xilinx.com/bin/public/opendownload?filename=vitis_ai_runtime_r3.0.0_image_video.tar.gz  -o vitis_ai_runtime_r3.0.0_image_video.tar.gzmkdir vitis_ai_runtime_r3.0.0_image_videotar -c vitis_ai_runtime_r3.0.0_image_video -xzvf vitis_ai_runtime_r3.0.0_image_video.tar.gz  
(左右移动查看全部内容)
3.3 运行resnet50示例程序
接下来,通过如下命令,运行resnet50示例程序:
cd ~/vitis-ai/examples/vai_runtime/resnet50./resnet50 /usr/share/vitis_ai_library/models/resnet50/resnet50.xmodel  
(左右移动查看全部内容)
运行结果如下:
报错说../images目录找不到。
创建../images目录,并将刚刚下载的resnet50测试图片拷贝到该目录中:
mkdir -v ../imagescp -vr ~/vitis_ai_runtime_r3.0.0_image_video/images/* ../images/  
(左右移动查看全部内容)
运行输出如下:
再次运行resnet50示例程序:
成功识别了。
命令行第二个参数 /usr/share/vitis_ai_library/models/resnet50/resnet50.xmodel 是resnet50的dpu模型文件,该文件在dpu镜像中已经有了,因此不需要手动下载。
3.4 使用金鱼图片进行测试
words.txt 文件中是resnet50识别结果的分类标签,可以看到前面几行中包含金鱼(goldfish)分类:
因此,可以找一个金鱼图片进行测试。
随便找了一张:
通过mobaxterm左侧边栏的上传功能传到开发板上:
默认上传位置为home目录(~)。
接下来,将金鱼图片拷贝到../images目录,并将原来的测试图片删除掉,重新运行resnet50示例程序,可以看到成功识别了金鱼:
04四、示例程序源码解读
接下来我们看看resnet50目录下的src/main.cc文件内容。
4.2 main函数
首先是main函数:
/** * [url=home.php?mod=space&uid=2666770]@brief[/url] entry for runing resnet50 neural network * * [url=home.php?mod=space&uid=1902110]@note[/url] runner apis prefixed with dpu are used to easily program & *       deploy resnet50 on dpu platform. * */int main(int argc, char* argv[]) {  // check args  if (argc != 2) {    cout << usage of resnet50 demo: ./resnet50 [model_file] << endl;    return -1;  }  auto graph = xir::deserialize(argv[1]);  auto subgraph = get_dpu_subgraph(graph.get());  check_eq(subgraph.size(), 1u)      << resnet50 should have one and only one dpu subgraph.;  log(info) << create running for subgraph: get_input_tensors();  auto outputtensors = runner->get_output_tensors();  /*get in/out tensor shape*/  int inputcnt = inputtensors.size();  int outputcnt = outputtensors.size();  tensorshape inshapes[inputcnt];  tensorshape outshapes[outputcnt];  shapes.intensorlist = inshapes;  shapes.outtensorlist = outshapes;  gettensorshape(runner.get(), &shapes, inputcnt, outputcnt);  /*run with batch*/  runresnet50(runner.get());  return 0;}  
(左右移动查看全部内容)
其中:
auto graph = xir::deserialize(argv[1]); 用于加载模型
auto runner = vart::create_runner(subgraph[0], run); 用于创建runner对象
auto inputtensors = runner->get_input_tensors(); 用于获取输入tensor对象
auto outputtensors = runner->get_output_tensors(); 用于获取输出tensor对象
最后的 runresnet50(runner.get()); 运行模型
4.2 runrestnet50函数
接下来我们看看runreset50函数:
/** * @brief run dpu task for resnet50 * * [url=home.php?mod=space&uid=3142012]@param[/url] taskresnet50 - pointer to resnet50 task * * [url=home.php?mod=space&uid=1141835]@return[/url] none */void runresnet50(vart::runner* runner) {  /* mean value for resnet50 specified in caffe prototxt */  vector kinds, images;  /* load all image names.*/  listimages(baseimagepath, images);  if (images.size() == 0) {    cerr << error: no images existing under << baseimagepath << endl;    return;  }  /* load all kinds words.*/  loadwords(wordspath + words.txt, kinds);  if (kinds.size() == 0) {    cerr << error: no words exist in file words.txt. get_input_tensors();  auto out_dims = outputtensors[0]->get_shape();  auto in_dims = inputtensors[0]->get_shape();  auto input_scale = get_input_scale(inputtensors[0]);  auto output_scale = get_output_scale(outputtensors[0]);  /*get shape info*/  int outsize = shapes.outtensorlist[0].size;  int insize = shapes.intensorlist[0].size;  int inheight = shapes.intensorlist[0].height;  int inwidth = shapes.intensorlist[0].width;  int batchsize = in_dims[0];  std::vector inputs, outputs;  vector imagelist;  int8_t* imageinputs = new int8_t[insize * batchsize];  float* softmax = new float[outsize];  int8_t* fcresult = new int8_t[batchsize * outsize];  std::vector inputsptr, outputsptr;  std::vector batchtensors;  /*run with batch*/  for (unsigned int n = 0; n < images.size(); n += batchsize) {    unsigned int runsize =        (images.size() < (n + batchsize)) ? (images.size() - n) : batchsize;    in_dims[0] = runsize;    out_dims[0] = batchsize;    for (unsigned int i = 0; i < runsize; i++) {      mat image = imread(baseimagepath + images[n + i]);      /*image pre-process*/      mat image2;  //= cv::mat(inheight, inwidth, cv_8sc3);      resize(image, image2, size(inheight, inwidth), 0, 0);      for (int h = 0; h < inheight; h++) {        for (int w = 0; w < inwidth; w++) {          for (int c = 0; c get_name(), in_dims,                            xir::datatype{xir::xint, 8u})));    inputs.push_back(std::make_unique(        imageinputs, batchtensors.back().get()));    batchtensors.push_back(std::shared_ptr(        xir::create(outputtensors[0]->get_name(), out_dims,                            xir::datatype{xir::xint, 8u})));    outputs.push_back(std::make_unique(        fcresult, batchtensors.back().get()));    /*tensor buffer input/output */    inputsptr.clear();    outputsptr.clear();    inputsptr.push_back(inputs[0].get());    outputsptr.push_back(outputs[0].get());    /*run*/    auto job_id = runner->execute_async(inputsptr, outputsptr);    runner->wait(job_id.first, -1);    for (unsigned int i = 0; i < runsize; i++) {      cout << image : << images[n + i] runner->wait(job_id.first, -1);  等待异步执行完成
cv::imshow(classification of resnet50, imagelist[i]); 显示图片
cv::waitkey(10000); 等待键盘按键10秒
好了本篇内容就到这里了,感谢阅读,下次再会。


Intel科普机箱积灰的解决办法
磁珠的的型号命名及选型方法
新能源汽车技术难点浅析及解决方案
常见的焊接工艺及焊接技巧
国芯思辰| 基于电力载波的大棚灌溉控制系统可用信号驱动器CN6212
如何在KV260上快速体验Vitsi AI图像分类示例程序
全球前五大PC厂商最新排名:联想第一 苹果第四
现货供应日本村田NTC贴片热敏电阻
让安全专家也头疼的7种物联网设备
魅族李楠对于苹果现在的高定价策略持的是悲观态度
英特尔推出全新产品家族 加速面向未来的解决方案
便携式atp荧光检测仪的特性及参数
AI新闻:神经形态研究社区的介绍
中国互联网时代的巨头 在汽车行业开启了新的对垒
达索系统赋能包装消费品与零售行业QMS解决方案-质量体系建设
信息分类编码系统 四大关键点进行详细介绍
紫光展锐成功进行5G新空口互操作研发测试
浅谈带宽和宽带的区别
2009台湾汽配展会/台北汽配展
火币Mena将会为中东地区的用户提供更为安全、快捷、方便的交易服务