端到端优化模型

本教程演示了如何使用 Apache TVM 优化机器学习模型。我们将使用 PyTorch 的预训练 ResNet-18 模型,并使用 TVM 的 Relax API 对其进行端到端优化。请注意,默认的端到端优化可能不适用于复杂模型。

准备工作

首先,我们准备模型和输入信息。我们使用 PyTorch 的预训练 ResNet-18 模型。

import os
import numpy as np
import torch
from torch.export import export
from torchvision.models.resnet import ResNet18_Weights, resnet18

torch_model = resnet18(weights=ResNet18_Weights.DEFAULT).eval()
Downloading: "https://download.pytorch.org/models/resnet18-f37072fd.pth" to /workspace/.cache/torch/hub/checkpoints/resnet18-f37072fd.pth

  0%|          | 0.00/44.7M [00:00<?, ?B/s]
 36%|███▋      | 16.2M/44.7M [00:00<00:00, 170MB/s]
 87%|████████▋ | 38.8M/44.7M [00:00<00:00, 208MB/s]
100%|██████████| 44.7M/44.7M [00:00<00:00, 206MB/s]

回顾整体流程

../../_static/downloads/tvm_overall_flow.svg

整体流程包括以下步骤

  • 构建或导入模型:构建神经网络模型或从其他框架(例如 PyTorch、ONNX)导入预训练模型,并创建 TVM IRModule,其中包含编译所需的所有信息,包括用于计算图的高级 Relax 函数,以及用于张量程序的低级 TensorIR 函数。

  • 执行可组合的优化:执行一系列优化转换,例如图优化、张量程序优化和库调度。

  • 构建和通用部署:将优化后的模型构建为可部署到通用运行时的模块,并在不同的设备(例如 CPU、GPU 或其他加速器)上执行它。

将模型转换为 IRModule

下一步,我们使用 Relax 前端为 PyTorch 将模型转换为 IRModule,以便进一步优化。

import tvm
from tvm import relax
from tvm.relax.frontend.torch import from_exported_program

# Give an example argument to torch.export
example_args = (torch.randn(1, 3, 224, 224, dtype=torch.float32),)

# Skip running in CI environment
IS_IN_CI = os.getenv("CI", "") == "true"

if not IS_IN_CI:
    # Convert the model to IRModule
    with torch.no_grad():
        exported_program = export(torch_model, example_args)
        mod = from_exported_program(exported_program, keep_params_as_input=True)

    mod, params = relax.frontend.detach_params(mod)
    mod.show()

IRModule 优化

Apache TVM Unity 提供了一种灵活的方式来优化 IRModule。围绕 IRModule 优化的所有内容都可以与现有的 pipeline 组合。请注意,每个转换都可以通过 tvm.ir.transform.Sequential 组合成一个优化 pipeline。

在本教程中,我们专注于通过自动调优对模型进行端到端优化。我们利用 MetaSchedule 调优模型并将调优日志存储到数据库中。我们还将数据库应用于模型以获得最佳性能。

TOTAL_TRIALS = 8000  # Change to 20000 for better performance if needed
target = tvm.target.Target("nvidia/geforce-rtx-3090-ti")  # Change to your target device
work_dir = "tuning_logs"

if not IS_IN_CI:
    mod = relax.get_pipeline("static_shape_tuning", target=target, total_trials=TOTAL_TRIALS)(mod)

    # Only show the main function
    mod["main"].show()

构建和部署

最后,我们构建优化后的模型并将其部署到目标设备。我们在 CI 环境中跳过此步骤。

if not IS_IN_CI:
    ex = tvm.compile(mod, target="cuda")
    dev = tvm.device("cuda", 0)
    vm = relax.VirtualMachine(ex, dev)
    # Need to allocate data and params on GPU device
    gpu_data = tvm.nd.array(np.random.rand(1, 3, 224, 224).astype("float32"), dev)
    gpu_params = [tvm.nd.array(p, dev) for p in params["main"]]
    gpu_out = vm["main"](gpu_data, *gpu_params).numpy()

    print(gpu_out.shape)

由 Sphinx-Gallery 生成的图库