使用 TVMC 編譯和最佳化模型

內容一覽:本節講解使用 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命令)來訪問命令列驅動功能。

本教程用tvmcpython -m tvm.driver.tvmc來打開 TVMC 命令列。

使用如下命令查看幫助頁:

tvmc --help

tvmc可用的 TVM 的主要功能來自子命令compileruntune。使用tvmc–help查看給定子命令的特定選項。

本教程將介紹這些命令,開始前請先下載一個預訓練的模型。

獲取模型

在本教程中,我們將使用 ResNet-50 v2。ResNet-50 是一個用來對圖像進行分類的 50 層深的卷積神經網路。接下來要用的模型,已經在超過100萬張具有1000種不同分類的圖像上,進行了預訓練。該網路的輸入圖像的大小為224×224。

推薦下載 Netron(免費的 ML 模型查看器)來更深入地探索 ResNet-50 模型的組織結構。

下載 Netron:https://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,輸出如下:

調優 session 需要很長時間,因此tvmc tune提供了許多選項來自定義調優過程,包括重複次數(例如–repeat–number)、要用的調優演算法等。查看tvmc tune –help了解更多資訊。

使用調優資料編譯最佳化模型

從上述調優過程的輸出檔案`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 接口的相同編譯和最佳化步驟。

點選下方的閱讀原文可查看所有原始文件。持續關注,不要錯過~

相關文章

AI 加碼,超光學進入狂飆時代

AI 加碼,超光學進入狂飆時代

內容一覽:近年來,為了突破傳統光學研究的侷限性,光學與物理學交叉領域的一個新興技術超光學出現,並且展現出巨大的市場前景。在這門技術高速發展的...