TVM:在树莓派上部署预训练的模型

TVM:在树莓派上部署预训练的模型

之前我们已经介绍如何通过Python接口(AutoTVM)来编译和优化模型。本文将介绍如何在远程(如本例中的树莓派)上部署预训练的模型。

在设备上构建 TVM Runtime

首先我们需要再远程设备上安装 TVM。

注意:本节和下一节中的所有指令都应在目标设备上执行,例如 树莓派。 我们假设它运行着 Linux。

由于我们在本地机器上进行编译,因此远程设备仅用于运行生成的代码。 我们只需要在远程设备上构建 TVM Runtime。这里在我们安装 tvm 的文章中已经详细介绍过了,不再赘述。需要提一下的是建议在树莓派上也安装 llvm,并在安装 tvm 时指定对应的路径。

可参考:TVM:源码编译安装

git clone --recursive https://github.com/apache/tvm tvm
cd tvm
mkdir build
cp cmake/config.cmake build
cd build
cmake ..
make runtime -j4

构建成功后配置 Python 包路径:

export PYTHONPATH=$PYTHONPATH:/path/to/tvm/python

在远程设备上设置 RPC 服务器

在远程设备(如本例中的树莓派)上运行以下命令来开启 RPC 服务器:

python -m tvm.exec.rpc_server --host 0.0.0.0 --port=9090

如果看到下面这行说明远程设备上的 RPC 服务已经成功开启了:

INFO:root:RPCServer: bind to 0.0.0.0:9090

准备预训练的模型

回到我们的主机(其上应该安装了完整的 TVM),不同与之前使用onnx模型,这次我们使用mxnet的模型(起始都一样,这里只是介绍另外一种模型来源)。

不同于之前在本机上的程序,我们这里通过 MXNet 来加载模型。

加载模型、测试图像和 sysnet(用来将 ImageNet 的标签转换成类别名):

from mxnet.gluon.model_zoo.vision import get_model
from PIL import Image
import numpy as np# 一行即获取模型
block = get_model("resnet18_v1", pretrained=True)# 获取图像并做相应转换
img_url = "https://github.com/dmlc/mxnet.js/blob/main/data/cat.png?raw=true"
img_name = "cat.png"
img_path = download_testdata(img_url, img_name, module="data")
image = Image.open(img_path).resize((224, 224))def transform_image(image):image = np.array(image) - np.array([123.0, 117.0, 104.0])image /= np.array([58.395, 57.12, 57.375])image = image.transpose((2, 0, 1))image = image[np.newaxis, :]return imagex = transform_image(image)# sysnet 用来将 ImageNet 的类别标签转换为类别名称
synset_url = "".join(["https://gist.githubusercontent.com/zhreshold/","4d0b62f3d01426887599d4f7ede23ee5/raw/","596b27d23537e5a1b5751d2b0481ef172f58b539/","imagenet1000_clsid_to_human.txt",]
)
synset_name = "imagenet1000_clsid_to_human.txt"
synset_path = download_testdata(synset_url, synset_name, module="data")
with open(synset_path) as f:synset = eval(f.read())

现在我们将 Gluon 模型移植到可移植的计算图上:

# 我们在 mxnet.gluon 中支持 MXNet 静态图(符号)和 HybridBlock
shape_dict = {"data": x.shape}
mod, params = relay.frontend.from_mxnet(block, shape_dict)
# 我们要的是概率值,所以加上 softmax 算子
func = mod["main"]
func = relay.Function(func.params, relay.nn.softmax(func.body), None, func.type_params, func.attrs)

以下是一些基本的数据工作负载配置:

batch_size = 1
num_classes = 1000
image_shape = (3, 224, 224)
data_shape = (batch_size,) + image_shape

编译图

我们调用带有图配置和参数的 relay.build() 函数来编译图。 但是,我们不能在具有 ARM 指令集的设备上部署 x86 程序。 也就是说我们还需要告诉 Relay 目标设备的编译选项,除了 net 和 params 参数来指定深度学习工作负载。 选项也很重要,不同的选项会导致性能有巨大差异。

如果我们在 x86 服务器上运行示例进行演示,直接将其设置为 llvm 即可。 如果在远程设备树莓派上运行,我们需要指定它的指令集。 如果要在真实设备上运行本教程,请将 local_demo 设置为 False。

另外,要注意的是,官方给出的例程是针对树莓派3B,其指令集是ARMv7,而这里如果是树莓派4B,需要修改 target 为 aarch64。即在下面改为 target = 'llvm -mtriple=aarch64-linux-gnu'

local_demo = Trueif local_demo:target = tvm.target.Target("llvm")
else:target = tvm.target.arm_cpu("rasp3b")# 上面这行是下面这行的简单形式# target = tvm.target.Target('llvm -device=arm_cpu -model=bcm2837 -mtriple=armv7l-linux-gnueabihf -mattr=+neon')with tvm.transform.PassContext(opt_level=3):lib = relay.build(func, target, params=params)# 在 `relay.build` 之后, 我们将得到三个返回值:图(graph),库(library)和新的参数(new parameter), 因为我们需要做一些优化,这可能会改变某些参数但是保证模型的输出结果不变# 将库(library)保存为本地临时目录
tmp = utils.tempdir()
lib_fname = tmp.relpath("net.tar")
lib.export_library(lib_fname)

此处输出:

/workspace/python/tvm/relay/build_module.py:333: DeprecationWarning: Please use input parameter mod (tvm.IRModule) instead of deprecated parameter mod (tvm.relay.function.Function)DeprecationWarning,

通过 RPC 将模型进行远程部署

通过 RPC,我们可以将模型从本机远程部署到树莓派上。

# 与远程设备建立 RPC会话
if local_demo:remote = rpc.LocalSession()
else:# 这里是笔者ip,要改成你自己的host = "10.206.205.11"port = 9090remote = rpc.connect(host, port)# 将库(library)上传到远程设备并加载它
remote.upload(lib_fname)
rlib = remote.load_module("net.tar")# 建立远程 runtime模块
dev = remote.cpu(0)
module = runtime.GraphModule(rlib["default"](dev))
# 设置输入数据
module.set_input("data", tvm.nd.array(x.astype("float32")))
# 运行
module.run()
# 得到输出
out = module.get_output(0)
# 得到 top1 分类结果
top1 = np.argmax(out.numpy())
print("TVM prediction top-1: {}".format(synset[top1]))

此处输出:

TVM prediction top-1: tiger cat

Ref:

https://tvm.apache.org/docs/how_to/deploy_models/deploy_model_on_rasp.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/532678.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2.2线性表的顺序表

2.2.1线性表的顺序表示和实现------顺序映像 【顺序存储】在【查找时】的时间复杂度为【O(1)】,因为它的地址是连续的,只要知道首元素的地址,根据下标可以很快找到指定位置的元素 【插入和删除】操作由于可能要在插入前或删除后对元素进行移…

TVM:交叉编译和RPC

TVM:交叉编译和RPC 之前我们介绍了 TVM 的安装、本机demo和树莓派远程demo。本文将介绍了在 TVM 中使用 RPC 进行交叉编译和远程设备执行。 通过交叉编译和 RPC,我们可以在本地机器上编译程序,然后在远程设备上运行它。 当远程设备资源有限…

2.3单链表的基本使用及其cpp示例

2.3线性表的链式表现与实现 2.3.1.1单链表 【特点: *用一组任意的存储单元存储线性表的数据元素 *利用指针实现用不同相邻的存储单元存放逻辑上相邻的元素 *每个元素ai,除存储本身信息外,还存储其直接后继的元素(后一个元素的地址…

TVM:简介

TVM:简介概述 Apache TVM 是一个用于 CPU、GPU 和机器学习加速器的开源机器学习编译器框架。它旨在使机器学习工程师能够在任何硬件后端上高效地优化和运行计算。本教程的目的是通过定义和演示关键概念,引导您了解 TVM 的所有主要功能。新用户应该能够从…

2.3.3单链表的双向链表

2.3.3双向链表 插入、删除 指在前驱和后驱方向都能游历(遍历)的线性链表 双向链表的每个结点有两个指针域 【结构】:prior data next 双链表通常采用带头结点的循环链表形式 可理解为首位相接的数据“圈”,每个结点都可以向前…

nvidia-smi 命令详解

nvidia-smi 命令详解 简介 nvidia-smi - NVIDIA System Management Interface program nvidia smi(也称为NVSMI)为来自 Fermi 和更高体系结构系列的 nvidia Tesla、Quadro、GRID 和 GeForce 设备提供监控和管理功能。GeForce Titan系列设备支持大多数…

2.4一元多项式的表示及相加,含cpp算法

2.4一元多项式的表示及相加 n阶多项式的表示: n阶多项式有n1项 指数按升幂排序 【 优点: 多项式的项数可以动态增长,不存在存储溢出的问题插入,删除方便,不移动元素 【表示: 有两个数据域,一…

TVM:使用Tensor Expression (TE)来处理算子

TVM:使用Tensor Expression (TE)来处理算子 在本教程中,我们将聚焦于在 TVM 中使用张量表达式(TE)来定义张量计算和实现循环优化。TE用纯函数语言描述张量计算(即每个表达式都没有副作用)。当在 TVM 的整体…

4-数据结构-串的学习

4.1串类型的定义 1.串:(或字符串) 串是由多个字符组成的有限序列,记作:S‘c1c2c3…cn’ (n>0) 其中S是串的名字,‘c1c2c3…cn’ 是串值 ci是串中字符 n是串的长度,表示字符的数目 空串&a…

Linux下rm误删恢复 extundelete

Linux下rm误删恢复 extundelete 误删之后要第一时间卸载(umount)该分区,或者以只读的方式来挂载(mount)该分区,否则覆写了谁也没办法恢复。如果误删除的是根分区,最好直接断电,进入…

5-数据结构-数组的学习

5.1数组的定义 定义: 由一组类型相同的数据元素构成的有序集合,每个数据元素称为一个数据元素(简称元素),每个元素受n(n>1)个线性关系的约束,每个元素在n个线性关系中的序号i1、…

timm 视觉库中的 create_model 函数详解

timm 视觉库中的 create_model 函数详解 最近一年 Vision Transformer 及其相关改进的工作层出不穷,在他们开源的代码中,大部分都用到了这样一个库:timm。各位炼丹师应该已经想必已经对其无比熟悉了,本文将介绍其中最关键的函数之…

C--数据结构--树的学习

6.2.1二叉树的性质 1.二叉树 性质: 1.若二叉树的层次从1开始,则在二叉树的第i层最多有2^(i-1)个结点 2.深度为k的二叉树最多有2^k -1个结点 (k>1) 3.对任何一颗二叉树,如果其叶结点个数为n0,度为2的非叶结点个数…

TVM:使用 Schedule 模板和 AutoTVM 来优化算子

TVM:使用 Schedule 模板和 AutoTVM 来优化算子 在本文中,我们将介绍如何使用 TVM 张量表达式(Tensor Expression,TE)语言编写 Schedule 模板,AutoTVM 可以搜索通过这些模板找到最佳 Schedule。这个过程称为…

TVM:使用 Auto-scheduling 来优化算子

TVM:使用 Auto-scheduling 来优化算子 在本教程中,我们将展示 TVM 的 Auto-scheduling 功能如何在无需编写自定义模板的情况下找到最佳 schedule。 与基于模板的 AutoTVM 依赖手动模板定义搜索空间不同,auto-scheduler 不需要任何模板。 用…

C语言—sort函数比较大小的快捷使用--algorithm头文件下

sort函数 一般情况下要将一组数从的大到小排序或从小到大排序&#xff0c;要定义一个新的函数排序。 而我们也可以直接使用在函数下的sort函数&#xff0c;只需加上头文件&#xff1a; #include<algorithm> using namespace std;sort格式&#xff1a;sort(首元素地址&…

散列的使用

散列 散列简单来说&#xff1a;给N个正整数和M个负整数&#xff0c;问这M个数中的每个数是否在N中出现过。 比如&#xff1a;N&#xff1a;{1,2,3,4}&#xff0c;M{2,5,7}&#xff0c;其中M的2在N中出现过 对这个问题最直观的思路是&#xff1a;对M中每个欲查的值x&#xff0…

关于C++中的unordered_map和unordered_set不能直接以pair作为键名的问题

关于C中的unordered_map和unordered_set不能直接以pair作为键名的问题 在 C STL 中&#xff0c;不同于有序的 std::map 和 std::set 是基于红黑树实现的&#xff0c;std::unordered_map 和 std::unordered_set 是基于哈希实现的&#xff0c;在不要求容器内的键有序&#xff0c…

AI编译器与传统编译器的联系与区别

AI编译器与传统编译器的区别与联系 总结整理自知乎问题 针对神经网络的编译器和传统编译器的区别和联系是什么&#xff1f;。 文中提到的答主的知乎主页&#xff1a;金雪锋、杨军、蓝色、SunnyCase、贝壳与知了、工藤福尔摩 笔者本人理解 为了不用直接手写机器码&#xff0…

python学习1:注释\变量类型\转换函数\转义字符\运算符

python基础学习 与大多数语言不同&#xff0c;python最具特色的就是使用缩进来表示代码块&#xff0c;不需要使用大括号 {} 。缩进的空格数是可变的&#xff0c;但是同一个代码块的语句必须包含相同的缩进空格数。 &#xff08;一个tab4个空格&#xff09; Python语言中常见的…