TVM部署预定义模型
TVM部署預定義模型
本文通過深度學習框架量化的模型加載到TVM中。預量化的模型導入是在TVM中提供的量化支持之一。
本文演示如何加載和運行由PyTorch,MXNet和TFLite量化的模型。加載后,可以在任何TVM支持的硬件上運行已編譯的量化模型。
首先,必要輸入
from PIL import Image
import numpy as np
import torch
from torchvision.models.quantization import mobilenet as qmobilenet
import tvm
from tvm import relay
from tvm.contrib.download import download_testdata
幫助程序功能來運行演示
def get_transform():
import torchvision.transforms as transforms
normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
return transforms.Compose([transforms.Resize(256),transforms.CenterCrop(224),transforms.ToTensor(),normalize,]
)
def get_real_image(im_height, im_width):
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”)
return Image.open(img_path).resize((im_height, im_width))
def get_imagenet_input():
im = get_real_image(224, 224)
preprocess = get_transform()
pt_tensor = preprocess(im)
return np.expand_dims(pt_tensor.numpy(), 0)
def get_synset():
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:
return eval(f.read())
def run_tvm_model(mod, params, input_name, inp, target=“llvm”):
with tvm.transform.PassContext(opt_level=3):
lib = relay.build(mod, target=target, params=params)
runtime = tvm.contrib.graph_runtime.GraphModule(lib["default"](tvm.context(target, 0)))runtime.set_input(input_name, inp)
runtime.run()
return runtime.get_output(0).asnumpy(), runtime
從標簽到類名的映射,以驗證以下模型的輸出是否合理
synset = get_synset()
輸出:
File /workspace/.tvm_test_data/data/imagenet1000_clsid_to_human.txt exists, skip.
每個人最喜歡的貓形象進行演示
inp = get_imagenet_input()
輸出:
File /workspace/.tvm_test_data/data/cat.png exists, skip.
部署量化的PyTorch模型
首先,演示如何使用PyTorch前端加載由PyTorch量化的深度學習模型。
參考下面的PyTorch靜態量化教程,以了解其量化工作流程。 https://pytorch.org/tutorials/advanced/static_quantization_tutorial.html
使用此功能來量化PyTorch模型。此函數采用浮點模型并將其轉換為uint8。該模型是按通道量化的。
def quantize_model(model, inp):
model.fuse_model()
model.qconfig = torch.quantization.get_default_qconfig(“fbgemm”)
torch.quantization.prepare(model, inplace=True)
# Dummy calibration
model(inp)
torch.quantization.convert(model, inplace=True)
來自Torchvision的負載量化就緒,預訓練的Mobilenet v2模型
選擇mobilenet v2,該模型是通過量化訓練的。其它型號需要完整的訓練后校準。
qmodel = qmobilenet.mobilenet_v2(pretrained=True).eval()
量化,跟蹤和運行PyTorch Mobilenet v2模型
pt_inp = torch.from_numpy(inp)
quantize_model(qmodel, pt_inp)
script_module = torch.jit.trace(qmodel, pt_inp).eval()
with torch.no_grad():
pt_result = script_module(pt_inp).numpy()
輸出:
/usr/local/lib/python3.6/dist-packages/torch/quantization/observer.py:121: UserWarning: Please use quant_min and quant_max to specify the range for observers. reduce_range will be deprecated in a future release of PyTorch.
reduce_range will be deprecated in a future release of PyTorch."
/usr/local/lib/python3.6/dist-packages/torch/quantization/observer.py:990: UserWarning: must run observer before calling calculate_qparams. Returning default scale and zero point
Returning default scale and zero point "
使用PyTorch前端將量化的Mobilenet v2轉換為Relay-QNN
PyTorch前端,將量化的PyTorch模型轉換為充實了量化算子的等效Relay 模塊。稱這種表示為Relay QNN方言。
可以打印前端的輸出,以查看量化模型的表示方式。
會看到特定于量化的算子,例如qnn.quantize,qnn.dequantize,qnn.requantize和qnn.conv2d等。
input_name = “input” # the input name can be be arbitrary for PyTorch frontend.
input_shapes = [(input_name, (1, 3, 224, 224))]
mod, params = relay.frontend.from_pytorch(script_module, input_shapes)
print(mod) # comment in to see the QNN IR dump
編譯并運行Relay 模塊
一旦獲得量化的Relay 模塊,其余的工作流程與運行浮點模型相同。
在Under the hood下,量化專用算子在編譯之前被降低為一系列標準Relay 算子。
tvm_result, rt_mod = run_tvm_model(mod, params, input_name, inp, target=“llvm”)
比較輸出標簽
應該看到打印出相同的標簽。
pt_top3_labels = np.argsort(pt_result[0])[::-1][:3]
tvm_top3_labels = np.argsort(tvm_result[0])[::-1][:3]
print(“PyTorch top3 labels:”, [synset[label] for label in pt_top3_labels])
print(“TVM top3 labels:”, [synset[label] for label in tvm_top3_labels])
輸出:
PyTorch top3 labels: [‘tiger cat’, ‘Egyptian cat’, ‘lynx, catamount’]
TVM top3 labels: [‘tiger cat’, ‘Egyptian cat’, ‘tabby, tabby cat’]
由于數值上的差異,通常預計原始浮點輸出不會相同。打印來自mobilenet v2的1000個輸出中有多少個浮點輸出值相同。
print("%d in 1000 raw floating outputs identical." % np.sum(tvm_result[0] == pt_result[0]))
輸出:
132 in 1000 raw floating outputs identical.
衡量性能
給出一個示例,說明如何測量TVM編譯模型的性能。
n_repeat = 100 # should be bigger to make the measurement more accurate
ctx = tvm.cpu(0)
ftimer = rt_mod.module.time_evaluator(“run”, ctx, number=1, repeat=n_repeat)
prof_res = np.array(ftimer().results) * 1e3
print(“Elapsed average ms:”, np.mean(prof_res))
輸出:
Elapsed average ms: 20.436994119999998
筆記
推薦此方法的原因如下:
? 測量是在C ++中完成的,因此沒有Python開銷
? 包括warm up runs
? 可以使用相同的方法在遠程設備(Android等)上進行配置文件。
筆記
除非硬件對快速8位指令有特殊支持,否則量化模型不會比FP32模型快。如果沒有快速的8位指令,即使模型本身是8位,TVM也會以16位進行量化卷積。
對于x86,在具有AVX512指令集的CPU上可以實現最佳性能。在這種情況下,TVM將最快可用的8位指令用于給定目標。這包括對VNNI 8位點產品指令(CascadeLake或更高版本)的支持。
此外,以下有關CPU性能的一般技巧同樣適用:
? 將環境變量TVM_NUM_THREADS設置為物理核心數number of physical cores
? 選擇最適合硬件的目標,例如“ llvm -mcpu = skylake-avx512”或“ llvm -mcpu = cascadelake”(將有更多帶有AVX512的CPU)
總結
以上是生活随笔為你收集整理的TVM部署预定义模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Relay外部库使用
- 下一篇: GPU自动调度卷积层