本文翻译自Compiling and Optimizing a Model with TVMC — tvm 0.9.dev0 documentation

在本节中,我们将使用TVM命令行驱动程序TVMC。TVMC是一个工具,它通过命令行接口公开TVM特性,如模型的自动调优、编译、分析和执行。

在完成这部分工作后,我们将利用TVMC完成以下工作:

  • 为TVM运行时编译一个训练好的ResNet-50 v2模型。
  • 在编译后的模型中运行一个真实的图像,并解释输出和模型性能。
  • 使用TVM在CPU上调优模型。
  • 使用TVM收集的调优数据重新编译优化模型。
  • 通过优化后的模型运行图像,并比较输出和模型性能。

本节的目标是概述TVM和TVMC的功能,并为理解TVM的工作方式奠定基础。

TVMC的使用

TVMC是一个Python应用程序,是TVM Python包的一部分。当你使用Python包安装TVM时,将会安装命令行应用程序TVMC。TVMC命令的位置取决于你的平台和安装方法。

如果你在环境变量$PYTHONPATH中添加了TVM路径,就可以通过命令python -m tvm.driver.tvmc来访问命令行提供的功能。

为简单起见,本教程将介绍TVMC命令tvmc <options>的使用,它等同于python -m tvm.driver.tvmc <options>

你可以使用以下命令查看帮助页面:

tvmc --help

tvmc执行的命令涉及的TVM特性包括编译、运行和调优等。使用tvmc <subcommand> --help可以查看子命令subcommand的参数选项。我们将在本教程中介绍这些命令,但首先我们需要为此下载一个预先训练好的模型。

获取模型

在本教程中,我们将使用ResNet-50 v2模型。ResNet-50是一个用于图像分类的,50层的卷积神经网络。我们使用的模型是已经训练好的,训练的数据集有1000种分类100多万张图像。该网络的输入图像尺寸为224x224。如果你对ResNet-50模型的结构感兴趣,我们建议下载Netron,这是一个免费的ML模型查看器。

在本教程中,我们将使用ONNX格式的模型。

get https://github.com/onnx/models/raw/main/vision/classification/resnet/model/resnet50-v2-7.onnx

TVMC支持模型有Keras, ONNX, TensorFlow, TFLite和Torch。使用--model-format选项可以查看模型格式。有关更多信息,请参阅tvmc compile --help。

TVM依赖ONNX python库。你可以使用命令pip3 install --user onnx onnxoptimizer来安装ONNX。如果你有root权限并且想全局安装ONNX,可以去掉--user选项。onnxoptimizer依赖项是可选的,仅用于onnx>=1.9版本。

ONNX模型编译为TVM运行时

下载ResNet-50模型后,我们使用tvmc编译它。模型编译得到的将是一个目标设备平台上的动态库。我们可以使用TVM运行时在目标设备上运行该模型。

# This may take several minutes depending on your machine
tvmc compile \
--target "llvm" \
--output resnet50-v2-7-tvm.tar \
resnet50-v2-7.onnx

我们来看看tvmc compile生成了哪些文件:

mkdir model
tar -xvf resnet50-v2-7-tvm.tar -C model
ls model

看到的有三个文件:

  • mod.so是一个用c++库表示的模型,可以被TVM运行时加载。
  • mod.json是TVM Relay计算图的文本表示。
  • mod.params是一个包含预训练模型参数的文件。

该模块可以由应用程序直接加载,模型可以通过TVM运行时API运行。

正确的指定目标(--target选项)可能会对编译得到的模块的性能产生巨大影响,因为它可以利用目标上可用的硬件特性。更多信息可参阅Auto-tuning a Convolutional Network for x86 CPU — tvm 0.9.dev0 documentation。我们建议你先确定使用的CPU和可选的特性,并适当地设置目标。

使用TVMC运行编译好的模型

现在我们已经将模型编译到模块中,然后就可以使用TVM运行时对其进行预测了。TVMC内置了TVM运行时,允许您运行编译后的TVM模型。为了使用TVMC运行模型并进行预测,我们需要具备两个条件:

  • 刚刚编译生成的模块
  • 对模型进行预测的有效输入

每个模型都有特定的张量形状、格式和数据类型。所以大多数模型需要一些预处理和后处理,以确保输入正确,并解释输出。TVMC的输入和输出数据都采用了NumPy的.npz格式。这是一种支持良好的NumPy格式,可以将多个数组序列化存入到一个文件中。

作为本教程的输入,我们将使用一只猫的图像,您也可以替换为其他任何图像。

输入预处理

我们使用的ResNet-50 v2模型预期输入为ImageNet格式。下面是一个对ResNet-50 v2输入图像做预处理的脚本示例。

这个脚本要求环境支持Python Image库。您可以使用pip3 install --user pillow安装Image

#!python ./preprocess.py
from tvm.contrib.download import download_testdata
from PIL import Image
import numpy as npimg_url = "https://s3.amazonaws.com/model-server/inputs/kitten.jpg"
img_path = download_testdata(img_url, "imagenet_cat.png", module="data")# Resize it to 224x224
resized_image = Image.open(img_path).resize((224, 224))
img_data = np.asarray(resized_image).astype("float32")# ONNX expects NCHW input, so convert the array
img_data = np.transpose(img_data, (2, 0, 1))# Normalize according to ImageNet
imagenet_mean = np.array([0.485, 0.456, 0.406])
imagenet_stddev = np.array([0.229, 0.224, 0.225])
norm_img_data = np.zeros(img_data.shape).astype("float32")
for i in range(img_data.shape[0]):norm_img_data[i, :, :] = (img_data[i, :, :] / 255 - imagenet_mean[i]) / imagenet_stddev[i]# Add batch dimension
img_data = np.expand_dims(norm_img_data, axis=0)# Save to .npz (outputs imagenet_cat.npz)
np.savez("imagenet_cat", data=img_data)

运行编译后的模型

有了模型和输入数据,我们现在可以运行TVMC进行预测:

tvmc run \
--inputs imagenet_cat.npz \
--output predictions.npz \
resnet50-v2-7-tvm.tar

回想一下,.tar模型文件包括一个C++库、一个Relay模型的描述,以及模型的参数。TVMC包括TVM运行时,运行时可以加载模型并根据输入进行预测。当运行上面的命令时,TVMC生成文件predictions. npz,它包含NumPy格式的模型输出张量。

在本例中模型编译和运行在同一台机器上。在某些情况下,我们可能希望通过RPC Tracker远程运行模型。要了解更多相关选项,请查看tvmc run --help。

输出后处理

正如前面提到的,每个模型都有自己特定的输出张量。

在我们的示例中,我们需要对输出做一些后处理,同时提供一个查找表,将ResNet-50 v2的输出翻译为便于人类阅读的形式。

下面的脚本是从输出中提取标签的后处理示例。

#!python ./postprocess.py
import os.path
import numpy as npfrom scipy.special import softmaxfrom tvm.contrib.download import download_testdata# Download a list of labels
labels_url = "https://s3.amazonaws.com/onnx-model-zoo/synset.txt"
labels_path = download_testdata(labels_url, "synset.txt", module="data")with open(labels_path, "r") as f:labels = [l.rstrip() for l in f]output_file = "predictions.npz"# Open the output and read the output tensor
if os.path.exists(output_file):with np.load(output_file) as data:scores = softmax(data["output_0"])scores = np.squeeze(scores)ranks = np.argsort(scores)[::-1]for rank in ranks[0:5]:print("class='%s' with probability=%f" % (labels[rank], scores[rank]))

运行脚本将产生下面的输出:

python postprocess.py
# class='n02123045 tabby, tabby cat' with probability=0.610553
# class='n02123159 tiger cat' with probability=0.367179
# class='n02124075 Egyptian cat' with probability=0.019365
# class='n02129604 tiger, Panthera tigris' with probability=0.001273
# class='n04040759 radiator' with probability=0.000261

试着用其他图片替换猫的图像,看看ResNet模型会做出什么样的预测。

ResNet模型自动调优

前面我们将模型编译为TVM运行时,不包括任何针对特定平台的优化。在本节中,我们将向您展示如何使用TVMC构建一个针对您的工作平台的优化模型。

在某些情况下,编译后的模型在推理时并没有获得预期的性能。此时我们可以使用自动调优器,为我们的模型找到更好的配置,从而提高性能。TVM中的调优是对模型进行优化,使其在给定目标上运行得更快。这与模型的训练或参数微调不同,因为调优不会影响模型的准确性,而只会影响运行性能。作为调优过程的一部分,TVM将尝试运行许多不同的算子实现变体,看哪一种性能最好。这些运行结果存储在调优记录文件中,该文件最终作为调优子命令的输出。

以最简单的形式来说,调优需要提供以下三件事:

  • 运行模型的设备规格
  • 存储调优记录输出文件的路径,
  • 要调优的模型的路径。

下面的例子演示了它是如何实际工作的:

# The default search algorithm requires xgboost, see below for further
# details on tuning search algorithms
pip install xgboosttvmc tune \
--target "llvm" \
--output resnet50-v2-7-autotuner_records.json \
resnet50-v2-7.onnx

在这个例子中,如果为--target选项指定一个更具体的目标,您将看到更好的结果。例如,在Intel i7处理器上,你可以使用--target llvm -mcpu=skylake。在这个调优示例中,我们使用LLVM作为指定架构的编译器在CPU上进行本地调优。

TVMC将对模型的参数空间进行搜索,尝试不同的算子配置,并选择在您的平台上运行最快的配置。虽然这是一个基于CPU和模型运算的引导搜索,但仍然需要几个小时才能完成搜索。此搜索的输出将保存到resnet50-v2-7-autotuner_records.json文件中,稍后将用于编译一个优化的模型。

默认情况下,使用XGBoost Grid算法引导搜索。根据模型的复杂性和可用时间,您可能想要选择不同的算法。可以通过tvmc tune --help获得完整的列表。

消费级Skylake CPU的输出如下所示:

tvmc tune \
--target "llvm -mcpu=broadwell" \
--output resnet50-v2-7-autotuner_records.json \
resnet50-v2-7.onnx
# [Task  1/24]  Current/Best:    9.65/  23.16 GFLOPS | Progress: (60/1000) | 130.74 s Done.
# [Task  1/24]  Current/Best:    3.56/  23.16 GFLOPS | Progress: (192/1000) | 381.32 s Done.
# [Task  2/24]  Current/Best:   13.13/  58.61 GFLOPS | Progress: (960/1000) | 1190.59 s Done.
# [Task  3/24]  Current/Best:   31.93/  59.52 GFLOPS | Progress: (800/1000) | 727.85 s Done.
# [Task  4/24]  Current/Best:   16.42/  57.80 GFLOPS | Progress: (960/1000) | 559.74 s Done.
# [Task  5/24]  Current/Best:   12.42/  57.92 GFLOPS | Progress: (800/1000) | 766.63 s Done.
# [Task  6/24]  Current/Best:   20.66/  59.25 GFLOPS | Progress: (1000/1000) | 673.61 s Done.
# [Task  7/24]  Current/Best:   15.48/  59.60 GFLOPS | Progress: (1000/1000) | 953.04 s Done.
# [Task  8/24]  Current/Best:   31.97/  59.33 GFLOPS | Progress: (972/1000) | 559.57 s Done.
# [Task  9/24]  Current/Best:   34.14/  60.09 GFLOPS | Progress: (1000/1000) | 479.32 s Done.
# [Task 10/24]  Current/Best:   12.53/  58.97 GFLOPS | Progress: (972/1000) | 642.34 s Done.
# [Task 11/24]  Current/Best:   30.94/  58.47 GFLOPS | Progress: (1000/1000) | 648.26 s Done.
# [Task 12/24]  Current/Best:   23.66/  58.63 GFLOPS | Progress: (1000/1000) | 851.59 s Done.
# [Task 13/24]  Current/Best:   25.44/  59.76 GFLOPS | Progress: (1000/1000) | 534.58 s Done.
# [Task 14/24]  Current/Best:   26.83/  58.51 GFLOPS | Progress: (1000/1000) | 491.67 s Done.
# [Task 15/24]  Current/Best:   33.64/  58.55 GFLOPS | Progress: (1000/1000) | 529.85 s Done.
# [Task 16/24]  Current/Best:   14.93/  57.94 GFLOPS | Progress: (1000/1000) | 645.55 s Done.
# [Task 17/24]  Current/Best:   28.70/  58.19 GFLOPS | Progress: (1000/1000) | 756.88 s Done.
# [Task 18/24]  Current/Best:   19.01/  60.43 GFLOPS | Progress: (980/1000) | 514.69 s Done.
# [Task 19/24]  Current/Best:   14.61/  57.30 GFLOPS | Progress: (1000/1000) | 614.44 s Done.
# [Task 20/24]  Current/Best:   10.47/  57.68 GFLOPS | Progress: (980/1000) | 479.80 s Done.
# [Task 21/24]  Current/Best:   34.37/  58.28 GFLOPS | Progress: (308/1000) | 225.37 s Done.
# [Task 22/24]  Current/Best:   15.75/  57.71 GFLOPS | Progress: (1000/1000) | 1024.05 s Done.
# [Task 23/24]  Current/Best:   23.23/  58.92 GFLOPS | Progress: (1000/1000) | 999.34 s Done.
# [Task 24/24]  Current/Best:   17.27/  55.25 GFLOPS | Progress: (1000/1000) | 1428.74 s Done.

调优命令运行时间可能很长,所以tvmc调优提供了许多选项来定制调优过程,包括重复次数(例如--repeat和--number)、使用的调优算法等等。查看tvmc tune --help以获得更多信息。

使用调优数据编译优化模型

resnet50-v2-7-autotuner_records.json中存储了作为上面调优过程的输出的调优记录。这个文件有两种用法:

  • 作为进一步调优的输入(通过tvmc tune --tuning-records)
  • 作为编译器的输入

编译器将使用调优结果为您指定的目标上的模型生成高性能代码。编译命令为tvmc compile --tuning-records。可以查看tvmc compile --help以获得更多信息。

现在已经收集了模型的调优数据,我们可以使用优化后的算子重新编译模型,以加快计算速度。

tvmc compile \
--target "llvm" \
--tuning-records resnet50-v2-7-autotuner_records.json  \
--output resnet50-v2-7-tvm_autotuned.tar \
resnet50-v2-7.onnx

运行优化后的模型,并产生和优化前相同的输出:

tvmc run \
--inputs imagenet_cat.npz \
--output predictions.npz \
resnet50-v2-7-tvm_autotuned.tarpython postprocess.py

可以看到模型预测的结果一致:

# class='n02123045 tabby, tabby cat' with probability=0.610550
# class='n02123159 tiger cat' with probability=0.367181
# class='n02124075 Egyptian cat' with probability=0.019365
# class='n02129604 tiger, Panthera tigris' with probability=0.001273
# class='n04040759 radiator' with probability=0.000261

比较调优和未调优模型

TVMC为您提供了在模型之间进行基本性能基准测试的工具。您可以指定重复次数,并在模型运行时(独立于运行时启动)报告给TVMC。我们可以大致了解调优在多大程度上提高了模型性能。例如,在测试Intel i7系统中,我们发现调优后的模型比未调优的模型运行速度快47%:

tvmc run \
--inputs imagenet_cat.npz \
--output predictions.npz  \
--print-time \
--repeat 100 \
resnet50-v2-7-tvm_autotuned.tar# Execution time summary:
# mean (ms)   max (ms)    min (ms)    std (ms)
#     92.19     115.73       89.85        3.15tvmc run \
--inputs imagenet_cat.npz \
--output predictions.npz  \
--print-time \
--repeat 100 \
resnet50-v2-7-tvm.tar# Execution time summary:
# mean (ms)   max (ms)    min (ms)    std (ms)
#    193.32     219.97      185.04        7.11

小结

在本教程中,我们介绍了TVM的命令行驱动程序TVMC。我们演示了如何编译、运行和调优模型。我们还讨论了对输入和输出进行预处理和后处理的必要性。在调优过程之后,我们演示了如何比较未优化模型和优化模型的性能。

这里我们给出了一个在本地运行ResNet-50 v2的简单示例。但是,TVMC支持更多的特性,包括交叉编译、远程执行和分析/基准测试。

要了解其他可用选项,请查看tvmc --help。

【TVM帮助文档学习】使用TVMC编译和优化模型相关推荐

  1. 【TVM帮助文档学习】使用张量表达式处理算子

    本文翻译自Working with Operators Using Tensor Expression - tvm 0.9.dev0 documentation 在本教程中,我们将把注意力转向TVM如 ...

  2. Spring文档学习

    Spring文档学习 参考Spring Framework Documentation学习 1. IoC 容器 1.1 容器实例化 <beans><import resource=& ...

  3. EasyUI文档学习心得

    概述 jQuery EasyUI 是一组基于jQuery 的UI 插件集合,它可以让开发者在几乎完全不需要CSS以及复杂的JS代码情况下完成美观且功能强大的Web界面. 本文主要说明一些如何利用Eas ...

  4. UHS-II文档学习

    #UHS-II文档学习 UHS-II 引脚分配 SD4.0与SD3.0相比多了底下一排引脚[10-17],UHS-II Mode使用的是三组差分信号分别为:D0.D1和RCLK差分信号.RCLK差分信 ...

  5. python文档学习

    文章目录 python文档学习 python解释器 传入参数 交互模式的提示符 帮助信息 基础知识 python保留字 注释 多行语句 缩进 python数据类型与运算符 变量与基本类型 数字类型 集 ...

  6. Django 4.0文档学习(一)

    本系列文章基于Django4.0版本官方网站文档学习 使用开发工具为pycharm > python -m django --version 4.0 文章目录 编写你的第一个 Django 应用 ...

  7. Spring Framework 5.3文档学习(一)

    Spring Framework 5.3文档学习(一) Overview 1.What We Mean by "Spring" 2. History of Spring and t ...

  8. TVM:通过Python接口(AutoTVM)来编译和优化模型

    TVM:通过Python接口(AutoTVM)来编译和优化模型 上次我们已经介绍了如何从源码编译安装 tvm,本文我们将介绍在本机中使用 tvm Python 接口来编译优化模型的一个demo. TV ...

  9. BERT-QE:用于文档Rerank的上下文化查询扩展模型

    BERT-QE 论文名称:EMNLP2020 | BERT-QE: Contextualized Query Expansion for Document Re-ranking arxiv地址:htt ...

最新文章

  1. PostgreSQL 电商业务(任意维度商品圈选应用) - json包range数组的命中优化 - 展开+索引优化...
  2. 【白话机器学习】算法理论+实战之K-Means聚类算法
  3. php七牛云储存图片,wordpress使用七牛云存储图片 | 厘米天空
  4. 【十二省联考】春节十二响【贪心】【堆】【启发式合并】
  5. c++清空输入缓冲区_干货 | C++的输入输出方法
  6. 双11奇迹背后的大数据平台,不喧哗,自有声!
  7. Flutter ScrollController not attached to any scroll views 异常
  8. 数据科学 IPython 笔记本 7.10 组合数据集:合并和连接
  9. 使用Tensorflow Lite创建一个Android AI应用
  10. 2016二级c语言成绩查询,2016年12月计算机二级C语言测试及答案
  11. 学习笔记:聚类算法Kmeans/K-均值算法
  12. 基于基本面因子的量化交易模型解析
  13. 微信小程序wxParse富文本解析
  14. Elasticsearch添加拼音搜索支持
  15. 计算机地图制图符号制作的心得,计算机地图制图.docx
  16. Python 在线电子零售公司销售数据(Online Retail | Kaggle)关联规则分析(Apriori算法)
  17. android数据球图,Android OpenGL球体贴图
  18. 数论讨伐!欧拉函数!
  19. 这几点技巧可提高 Kindle 使用体验
  20. 根据日期计算星期几 -- 基姆拉尔森计算公式

热门文章

  1. json数据和对象的区别
  2. 批改网的英语作文老师设置不允许被粘贴的话,可以使用下面的办法使用复制粘贴功能,快速提交作文
  3. (3.1)【多媒体中的数据隐藏】数字音频中的数据隐藏、原理、音频隐写工具 S-TOOLS、提取工具MP3Stego
  4. 中国焦炭行业发展现状及趋势分析,提高市场集中度「图」
  5. 浪漫是浪漫,不浪漫也是浪漫
  6. 【蓝桥杯真题】2021年蓝桥杯省赛A组题目解析+代码(python组)
  7. 四、NPP/VIIRS夜间灯光数据校正之连续性校正
  8. Android小游戏开发:简单的合金弹头游戏(一)游戏框架
  9. 给赞!移动端网页调试利器-uc开发者工具
  10. python编程从入门到实践 配套资源下载地址 免费!