blob: e7d44fe90d898ee572f415a36b2f8c6e9017021b [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ruff: noqa: E722
"""Test Pipeline in MSC."""
import json
import pytest
import torch
import tvm.testing
from tvm.contrib.msc.core import utils as msc_utils
from tvm.contrib.msc.core.utils.namespace import MSCFramework
from tvm.contrib.msc.pipeline import MSCManager, TorchDynamic
requires_tensorrt = pytest.mark.skipif(
tvm.get_global_func("relax.ext.tensorrt", True) is None,
reason="TENSORRT is not enabled",
)
def _get_config(model_type, compile_type, inputs, outputs, dynamic=False, atol=1e-1, rtol=1e-1):
"""Get msc config"""
path = "test_pipe_{}_{}_{}".format(model_type, compile_type, "dynamic" if dynamic else "static")
return {
"workspace": msc_utils.msc_dir(path, keep_history=False),
"verbose": "critical",
"model_type": model_type,
"inputs": inputs,
"outputs": outputs,
"dataset": {"prepare": {"loader": "from_random", "max_iter": 5}},
"prepare": {"profile": {"benchmark": {"repeat": 10}}},
"baseline": {
"run_type": model_type,
"profile": {"check": {"atol": atol, "rtol": rtol}, "benchmark": {"repeat": 10}},
},
"compile": {
"run_type": compile_type,
"profile": {"check": {"atol": atol, "rtol": rtol}, "benchmark": {"repeat": 10}},
},
}
def _get_torch_model(name, training=False):
"""Get model from torch vision"""
# pylint: disable=import-outside-toplevel
try:
import torchvision
model = getattr(torchvision.models, name)()
if training:
model = model.train()
else:
model = model.eval()
return model
except: # pylint: disable=bare-except
print("please install torchvision package")
return None
def _check_pipeline(pipeline, expected_info, dynamic=False):
"""Check the pipeline results"""
passed, err = True, ""
if not pipeline.report["success"]:
passed = False
err = f"Failed to run pipe for {pipeline.model_type} -> {pipeline.compile_type}"
if not dynamic:
model_info = pipeline.get_runtime().model_info
if not msc_utils.dict_equal(model_info, expected_info):
passed = False
err = f"Model info {model_info} mismatch with expected {expected_info}"
pipeline.destory()
if not passed:
raise Exception(f"{err}\nReport:{json.dumps(pipeline.report, indent=2)}")
def _test_from_torch(
compile_type, expected_info, training=False, dynamic=False, atol=1e-1, rtol=1e-1
):
if dynamic and not hasattr(torch, "compile"):
return
torch_model = _get_torch_model("resnet50", training)
if torch_model:
if torch.cuda.is_available():
torch_model = torch_model.to(torch.device("cuda:0"))
config = _get_config(
MSCFramework.TORCH,
compile_type,
inputs=[["input_0", [1, 3, 224, 224], "float32"]],
outputs=["output"],
dynamic=dynamic,
atol=atol,
rtol=rtol,
)
pipeline = TorchDynamic(torch_model, config) if dynamic else MSCManager(torch_model, config)
pipeline.run_pipe()
_check_pipeline(pipeline, expected_info, dynamic)
@pytest.mark.parametrize("dynamic", [False])
def test_tvm_pipeline(dynamic):
"""Test pipeline for tvm"""
model_info = {
"inputs": [
{"name": "input_0", "shape": [1, 3, 224, 224], "dtype": "float32", "layout": "NCHW"}
],
"outputs": [{"name": "output", "shape": [1, 1000], "dtype": "float32", "layout": "NW"}],
"nodes": {
"total": 229,
"input": 1,
"nn.conv2d": 53,
"nn.batch_norm": 53,
"get_item": 53,
"nn.relu": 49,
"nn.max_pool2d": 1,
"add": 16,
"nn.adaptive_avg_pool2d": 1,
"reshape": 1,
"msc.linear_bias": 1,
},
}
_test_from_torch(MSCFramework.TVM, model_info, training=False, dynamic=dynamic)
if not dynamic:
model_info = {
"inputs": [
{"name": "input", "shape": [1, 224, 224, 3], "dtype": "float32", "layout": "NHWC"}
],
"outputs": [
{
"name": "MobilenetV2/Predictions/Reshape_1:0",
"shape": [1, 1001],
"dtype": "float32",
"layout": "NC",
}
],
"nodes": {
"total": 138,
"input": 1,
"msc.conv2d_bias": 36,
"clip": 35,
"nn.conv2d": 17,
"nn.batch_norm": 17,
"get_item": 17,
"add": 10,
"nn.avg_pool2d": 1,
"squeeze": 1,
"reshape": 2,
"nn.softmax": 1,
},
}
@pytest.mark.parametrize("dynamic", [False])
def test_torch_pipeline(dynamic):
"""Test pipeline for torch"""
model_info = {
"inputs": [
{"name": "input_0", "shape": [1, 3, 224, 224], "dtype": "float32", "layout": "NCHW"}
],
"outputs": [{"name": "output", "shape": [1, 1000], "dtype": "float32", "layout": "NW"}],
"nodes": {
"total": 229,
"input": 1,
"nn.conv2d": 53,
"nn.batch_norm": 53,
"get_item": 53,
"nn.relu": 49,
"nn.max_pool2d": 1,
"add": 16,
"nn.adaptive_avg_pool2d": 1,
"reshape": 1,
"msc.linear_bias": 1,
},
}
_test_from_torch(MSCFramework.TORCH, model_info, training=False, dynamic=dynamic)
@requires_tensorrt
@pytest.mark.parametrize("dynamic", [False])
def test_tensorrt_pipeline(dynamic):
"""Test pipeline for tensorrt"""
model_info = {
"inputs": [
{"name": "input_0", "shape": [1, 3, 224, 224], "dtype": "float32", "layout": "NCHW"}
],
"outputs": [{"name": "output", "shape": [1, 1000], "dtype": "float32", "layout": ""}],
"nodes": {"total": 2, "input": 1, "msc_tensorrt": 1},
}
_test_from_torch(MSCFramework.TENSORRT, model_info, training=False, dynamic=dynamic)
if __name__ == "__main__":
tvm.testing.main()