**内容一览:**本节讲解运用 TVMC 编译和优化模型。TVMC 是 TVM 的指令驱动程序,经过指令行履行 TVM 功用。本节是了解 TVM 作业原理的根底。
**关键词:**TVMC TVM 机器学习
本节将介绍 TVMC(TVM 的指令行驱动程序)。TVMC 经过指令行界面履行 TVM 功用 (包括对模型的主动调优、编译、分析和履行)。
学完本节后,可用 TVMC 完结下面的使命:
-
为 TVM runtime 编译预练习的 ResNet-50 v2 模型。
-
用编译好的模型猜测真实图画,并解说输出和模型功用。
-
运用 TVM 在 CPU上调优模型。
-
用 TVM 搜集的调优数据,重新编译优化过的模型。
-
经过优化的模型猜测图画,并比较输出和模型功用。
本节对 TVM 及 TVMC 的功用进行了概述,并为了解 TVM 的作业原理奠定根底。
运用 TVMC
TVMC 是 Python 应用程序,也是 TVM Python 软件包的一部分。 用 Python 包装置 TVM 时,会得到一个叫 tvmc 的指令行应用程序。渠道和装置办法不同,此指令的方位也会发生变化。
另外,假如 $PYTHONPATH 上有 TVM 这个 Python 模块,则可经过可履行 Python 模块(用 python -m tvm.driver.tvmc 指令)来拜访指令行驱动功用。
本教程用 tvmc 或 python -m tvm.driver.tvmc 来翻开 TVMC 指令行。
运用如下指令检查协助页:
tvmc --help
tvmc 可用的 TVM 的主要功用来自子指令 compile 、run 和 tune 。运用 tvmc–help 检查给定子指令的特定选项。
本教程将介绍这些指令,开端前请先下载一个预练习的模型。
获取模型
在本教程中,咱们将运用 ResNet-50 v2。ResNet-50 是一个用来对图画进行分类的 50 层深的卷积神经网络。 接下来要用的模型,已经在超过100万张具有1000种不同分类的图画上,进行了预练习。该网络的输入图画的巨细为224×224。
引荐下载 Netron(免费的 ML 模型检查器)来更深入地探究 ResNet-50 模型的组织结构。
下载 Netron:netron.app/
本教程运用 ONNX 格局的模型:
wget https://github.com/onnx/models/raw/b9a54e89508f101a1611cd64f4ef56b9cb62c7cf/vision/classification/resnet/model/resnet50-v2-7.onnx
Tips 1 支撑的模型格局:
TVMC 支撑用 Keras、ONNX、TensorFlow、TFLite 和 Torch 创立的模型。可用 –model-format 选项指明正在运用的模型格局。履行 tvmc compile –help 来获取更多信息。
Tips 2 向 TVM 添加对 ONNX 的支撑:
TVM 依靠系统中可用的 ONNX Python 库。用指令 pip3 install –user onnx onnxoptimizer 来装置 ONNX。假如具有 root 拜访权限并且希望大局装置 ONNX,则能够删除 –user 选项。onnxoptimizer 依靠是可选的,仅用于 onnx>=1.9 。
将 ONNX 模型编译到 TVM Runtime
下载 ResNet-50 模型后,用 tvmc compile 对其进行编译。编译的输出成果是模型(被编译为方针渠道的动态库)的 TAR 包。用 TVM runtime 可在方针设备上运转该模型:
# 大概需求几分钟,取决于设备tvmc compile \--target "llvm" \--input-shapes "data:[1,3,224,224]" \--output resnet50-v2-7-tvm.tar \resnet50-v2-7.onnx
检查 tvmc compile 在模块中创立的文件:
mkdir modeltar -xvf resnet50-v2-7-tvm.tar -C modells model
解压后有三个文件:
* mod.so 是可被 TVM runtime 加载的模型,表示为 C++ 库。
* mod.json 是 TVM Relay 核算图的文本表示。
* mod.params 是包括预练习模型参数的文件。
模块可由应用程序直接加载,而模型可经过 TVM runtime API 运转。
Tips 3 定义正确的 TARGET:
指定正确的 target(选项 **–target** )可大大提升编译模块的功用,由于可利用 target 上可用的硬件功用。参看 针对 x86 CPU 主动调优卷积网络 获取更多信息。主张确定好运用的 CPU 类型以及可选功用,然后适当地设置 target。
运用 TVMC 运转来自编译模块的模型
将模型编译到模块后,可用 TVM runtime 对其进行猜测。 TVMC 具有内置的 TVM runtime,答应运转已编译的 TVM 模型。
要用 TVMC 运转模型并猜测,需求:
-
刚生成的编译模块。
-
用来猜测的模型的有用输入。
模型的张量 shape、格局和数据类型各不相同。 因而,大多数模型都需求预处理和后处理,确保输入有用,并能够解说输出。TVMC 采用了 NumPy 的 .npz 格局的输入和输出,可很好地支撑将多个数组序列化到一个文件中。
本教程中的图画输入运用的是一张猫的图画,你也能够依据喜好挑选其他图画。
输入预处理
ResNet-50 v2 模型的输入应该是 ImageNet 格局。下面是 ResNet-50 v2 预处理图画的脚本示例。
首先用 pip3 install –user pillow 下载 Python 图画库,以满意脚本运转对图画库的依靠。
#!python ./preprocess.pyfrom tvm.contrib.download import download_testdatafrom PIL import Imageimport numpy as npimg_url = "https://s3.amazonaws.com/model-server/inputs/kitten.jpg"img_path = download_testdata(img_url, "imagenet_cat.png", module="data")# 重设巨细为 224x224resized_image = Image.open(img_path).resize((224, 224))img_data = np.asarray(resized_image).astype("float32")# ONNX 需求 NCHW 输入, 因而对数组进行转化img_data = np.transpose(img_data, (2, 0, 1))# 依据 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]# 添加 batch 维度img_data = np.expand_dims(norm_img_data, axis=0)# 保存为 .npz(输出 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 runtime(可加载模型,并对输入进行猜测)。运转以上指令,TVMC 会输出一个新文件 predictions.npz, 其中包括 NumPy 格局的模型输出张量。
在此示例中,用于编译模型的和运转模型的是同一台机器。某些情况下,或许会用 RPC Tracker 来长途运转它。检查 tvmc run –help 来了解有关这些选项的更多信息。
输出后处理
如前所述,每个模型供给输出张量的方式都不一样。
本示例中,咱们需求用专为该模型供给的查找表,运转一些后处理(post-processing),然后使得 ResNet-50 v2 的输出方式更具有可读性。
下面的脚本是一个后处理示例,它从编译模块的输出中提取标签:
#!python ./postprocess.pyimport os.pathimport numpy as npfrom scipy.special import softmaxfrom tvm.contrib.download import download_testdata# 下载标签列表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"# 翻开并读入输出张量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 runtime 上运转,因而不包括特定于渠道的优化。本节将介绍怎么用 TVMC,针对作业渠道构建优化模型。
用编译的模块推理,有时或许无法取得预期的功用。在这种情况下,可用主动调优器更好地装备模型,然后进步功用。 TVM 中的调优是指,在给定 target 上优化模型,使其运转得更快。与练习或微调不同,它不会影响模型的准确性,而只会影响 runtime 功用。
作为调优进程的一部分,TVM 完结并运转许多不同算子的变体,以检查哪个功用最佳。 这些运转的成果存储在调优记载文件(tune 指令的终究输出)中。
调优最少要包括:
-
运转此模型的方针设备的渠道要求
-
存储调优记载的输出文件的途径
-
要调优的模型的途径。
下面的示例演示了其作业流程:
# 默认查找算法需求 xgboost,有关调优查找算法的详细信息,拜见下文pip install xgboosttvmc tune \--target "llvm" \--output resnet50-v2-7-autotuner_records.json \resnet50-v2-7.onnx
此例中,为 –target 标志指定更详细的 target 时,会得到更好的成果。例如,在 Intel i7 处理器上,可用 –target llvm -mcpu=skylake 。 这个调优示例把 LLVM 作为指定架构的编译器,在 CPU 上进行本地调优。
TVMC 针对模型的参数空间进行查找,为算子尝试不同的装备,然后挑选渠道上运转最快的装备。虽然这是基于 CPU 和模型操作的引导式查找,但仍需求几个小时才能完结查找。查找的输出将保存到 resnet50-v2-7-autotuner_records.json 文件中,该文件之后会用于编译优化模型。
Tips 4 定义调优查找算法:
这个查找算法默认用 XGBoost Grid 算法进行引导。依据模型复杂度和可用时间,可挑选不同的算法。完好列表可检查 tvmc tune –help 。
对于消费级的 Skylake CPU,输出如下:
运用调优数据编译优化模型
从上述调优进程的输出文件 `resnet50-v2-7-autotuner_records.json 可获取调优记载。
该文件可用来:
-
作为进一步骤优的输入(经过 tvmc tune –tuning-records )
-
作为编译器的输入
履行 tvmc compile –tuning-records 指令让编译器利用这个成果为指定 target 上的模型生成高功用代码。检查 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 报告模型的运转时间(独立于 runtime 启动)。可大致了解调优对模型功用的提升程度。
例如,对 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
写在最终
本教程介绍了 TVMC( TVM 的指令行驱动程序),演示了怎么编译、运转和调优模型,还讨论了对输入和输出进行预处理和后处理的必要性。 调优后,演示怎么比较未优化和优化模型的功用。
本文档展现了一个在本地运用 ResNet-50 v2 的简单示例。然而,TVMC 支撑更多功用,包括交叉编译、长途履行和分析/基准测验。
用 tvmc –help 指令检查其他可用选项。
下个教程 Compiling and Optimizing a Model with the Python Interface 将介绍用 Python 接口的相同编译和优化步骤。
继续重视,不要错过~