在 VTA 上部署来自 Darknet 的预训练视觉检测模型
备注
单击 此处 下载完整的示例代码
作者:Hua Jiang
本教程提供了一个端到端 demo,介绍了如何在 VTA 加速器设计上运行 Darknet YoloV3-tiny 推理,执行图像检测任务。它展示了 Relay 作为一个前端编译器,可以执行量化(VTA 仅支持 int8/32 推理)以及计算图打包(为了在 core 中启用张量),从而为硬件 target 修改计算图。
安装依赖
要在 TVM 中使用 autotvm 包,需要安装额外的依赖(如果用的是 Python2,请将「3」更改为「2」):
pip3 install "Pillow<7"
支持 Darknet 解析的 YOLO-V3-tiny 模型依赖于 CFFI 和 CV2 库,因此要在执行此脚本之前安装 CFFI 和 CV2。
pip3 install cffi
pip3 install opencv-python
在 Python 代码中导入包:
from __future__ import absolute_import, print_function
import sys
import os
import time
import matplotlib.pyplot as plt
import numpy as np
import tvm
import vta
from tvm import rpc, autotvm, relay
from tvm.relay.testing import yolo_detection, darknet
from tvm.relay.testing.darknet import __darknetffi__
from tvm.contrib import graph_executor, utils
from tvm.contrib.download import download_testdata
from vta.testing import simulator
from vta.top import graph_pack
# 确保 TVM 是使用 RPC=1 编译的
assert tvm.runtime.enabled("rpc")
根据 Model Name 下载 yolo net 配置文件、权重文件、Darknet 库文件 ———————————————————————————-
MODEL_NAME = "yolov3-tiny"
REPO_URL = "https://github.com/dmlc/web-data/blob/main/darknet/"
cfg_path = download_testdata(
"https://github.com/pjreddie/darknet/blob/master/cfg/" + MODEL_NAME + ".cfg" + "?raw=true",
MODEL_NAME + ".cfg",
module="darknet",
)
weights_path = download_testdata(
"https://pjreddie.com/media/files/" + MODEL_NAME + ".weights" + "?raw=true",
MODEL_NAME + ".weights",
module="darknet",
)
if sys.platform in ["linux", "linux2"]:
darknet_lib_path = download_testdata(
REPO_URL + "lib/" + "libdarknet2.0.so" + "?raw=true", "libdarknet2.0.so", module="darknet"
)
elif sys.platform == "darwin":
darknet_lib_path = download_testdata(
REPO_URL + "lib_osx/" + "libdarknet_mac2.0.so" + "?raw=true",
"libdarknet_mac2.0.so",
module="darknet",
)
else:
raise NotImplementedError("Darknet lib is not supported on {} platform".format(sys.platform))
下载 YOLO 标签名称和对应插图
coco_path = download_testdata(
REPO_URL + "data/" + "coco.names" + "?raw=true", "coco.names", module="data"
)
font_path = download_testdata(
REPO_URL + "data/" + "arial.ttf" + "?raw=true", "arial.ttf", module="data"
)
with open(coco_path) as f:
content = f.readlines()
names = [x.strip() for x in content]
定义平台和模型 target
对比在 CPU 与 VTA 上执行,并定义模型。
# 从 3rdparty/vta-hw/config/vta_config.json 文件加载 VTA 参数
env = vta.get_env()
# 设置 ``device=arm_cpu``,在 CPU 上运行推理
# 设置 ``device=vta`` 在 FPGA 上运行推理
device = "vta"
target = env.target if device == "vta" else env.target_vta_cpu
pack_dict = {
"yolov3-tiny": ["nn.max_pool2d", "cast", 4, 186],
}
# 要编译的 Darknet 模型的名称
# ``start_pack`` 和 ``stop_pack`` 标签指示在哪里开始和结束计算图打包 Relay pass:换句话说,从哪里开始和结束转移到 VTA。
# 数字 4 表示 ``start_pack`` 索引是 4,数字 186 表示 ``stop_pack 索引`` 是 186,通过使用名称和索引号,可以在这里找到正确的开始/结束的位置是多个 ``nn.max_pool2d`` 或 ``cast``, print(mod.astext(show_meta_data=False)) 可以帮助查找算子名称和索引信息。
assert MODEL_NAME in pack_dict
获取远程执行
当 target 是「pynq」或其他 FPGA 后端时,重新配置 FPGA 和 runtime。若 target 是「sim」,则在本地执行。
if env.TARGET not in ["sim", "tsim"]:
# 若设置了环境变量,则从跟踪器节点获取远程。
# 要设置跟踪器,你需要遵循「为 VTA 自动调优卷积网络」教程。
tracker_host = os.environ.get("TVM_TRACKER_HOST", None)
tracker_port = os.environ.get("TVM_TRACKER_PORT", None)
# 否则,若有一个想要直接从主机编程的设备,请确保已将以下变量设置为你的板子的 IP。
device_host = os.environ.get("VTA_RPC_HOST", "192.168.2.99")
device_port = os.environ.get("VTA_RPC_PORT", "9091")
if not tracker_host or not tracker_port:
remote = rpc.connect(device_host, int(device_port))
else:
remote = autotvm.measure.request_remote(
env.TARGET, tracker_host, int(tracker_port), timeout=10000
)
# 重新配置 JIT runtime 和 FPGA
# 可以通过将路径传递给比特流文件,而非 None,使用自定义比特流对 FPGA 进行编程。
reconfig_start = time.time()
vta.reconfig_runtime(remote)
vta.program_fpga(remote, bitstream=None)
reconfig_time = time.time() - reconfig_start
print("Reconfigured FPGA and RPC runtime in {0:.2f}s!".format(reconfig_time))
# 在模拟模式下,本地托管 RPC 服务器。
else:
remote = rpc.LocalSession()
# 从远程获取执行上下文
ctx = remote.ext_dev(0) if device == "vta" else remote.cpu(0)