mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-05-14 20:48:00 +00:00
657 lines
19 KiB
Text
657 lines
19 KiB
Text
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "72476497",
|
|
"metadata": {},
|
|
"source": [
|
|
"# ONNX Runtime: Tutorial for TVM execution provider\n",
|
|
"\n",
|
|
"This notebook shows a simple example for model inference with TVM EP.\n",
|
|
"\n",
|
|
"\n",
|
|
"#### Tutorial Roadmap:\n",
|
|
"1. Prerequistes\n",
|
|
"2. Accuracy check for TVM EP\n",
|
|
"3. Configuration options\n",
|
|
"4. Support precompiled model"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "9345cbab",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 1. Prerequistes\n",
|
|
"\n",
|
|
"Make sure that you have installed all the necessary dependencies described in the corresponding paragraph of the documentation.\n",
|
|
"\n",
|
|
"Also, make sure you have the `tvm` and `onnxruntime-tvm` packages in your pip environment. \n",
|
|
"\n",
|
|
"If you are using `PYTHONPATH` variable expansion, make sure it contains the following paths: `<path_to_msft_onnxrt>/onnxruntime/cmake/external/tvm_update/python` and `<path_to_msft_onnxrt>/onnxruntime/build/Linux/Release`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "da4ca21f",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Common import\n",
|
|
"\n",
|
|
"These packages can be delivered from standard `pip`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "0f072875",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import os\n",
|
|
"import onnx\n",
|
|
"import tempfile\n",
|
|
"import numpy as np\n",
|
|
"from typing import List, AnyStr\n",
|
|
"from onnx import ModelProto, helper, checker, mapping"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "118670aa",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Specialized import\n",
|
|
"\n",
|
|
"It is better to collect these packages from source code in order to clearly understand what is available to you right now."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "a5502966",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import onnxruntime\n",
|
|
"\n",
|
|
"import tvm\n",
|
|
"import tvm.relay\n",
|
|
"import tvm.testing\n",
|
|
"import tvm.runtime\n",
|
|
"import tvm.runtime.vm\n",
|
|
"import tvm.relay.backend.vm\n",
|
|
"import tvm.contrib.download"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b7313183",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Helper functions for working with ONNX ModelProto\n",
|
|
"\n",
|
|
"This set of helper functions allows you to recognize the meta information of the models. This information is needed for more versatile processing of ONNX models."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "7d0a36e8",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def get_onnx_input_names(model: ModelProto) -> List[AnyStr]:\n",
|
|
" inputs = [node.name for node in model.graph.input]\n",
|
|
" initializer = [node.name for node in model.graph.initializer]\n",
|
|
" inputs = list(set(inputs) - set(initializer))\n",
|
|
" return sorted(inputs)\n",
|
|
"\n",
|
|
"\n",
|
|
"def get_onnx_output_names(model: ModelProto) -> List[AnyStr]:\n",
|
|
" return [node.name for node in model.graph.output]\n",
|
|
"\n",
|
|
"\n",
|
|
"def get_onnx_input_types(model: ModelProto) -> List[np.dtype]:\n",
|
|
" input_names = get_onnx_input_names(model)\n",
|
|
" return [\n",
|
|
" mapping.TENSOR_TYPE_TO_NP_TYPE[node.type.tensor_type.elem_type]\n",
|
|
" for node in sorted(model.graph.input, key=lambda node: node.name) if node.name in input_names\n",
|
|
" ]\n",
|
|
"\n",
|
|
"\n",
|
|
"def get_onnx_input_shapes(model: ModelProto) -> List[List[int]]:\n",
|
|
" input_names = get_onnx_input_names(model)\n",
|
|
" return [\n",
|
|
" [dv.dim_value for dv in node.type.tensor_type.shape.dim]\n",
|
|
" for node in sorted(model.graph.input, key=lambda node: node.name) if node.name in input_names\n",
|
|
" ]\n",
|
|
"\n",
|
|
"\n",
|
|
"def get_random_model_inputs(model: ModelProto) -> List[np.ndarray]:\n",
|
|
" input_shapes = get_onnx_input_shapes(model)\n",
|
|
" input_types = get_onnx_input_types(model)\n",
|
|
" assert len(input_types) == len(input_shapes)\n",
|
|
" inputs = [np.random.uniform(size=shape).astype(dtype) for shape, dtype in zip(input_shapes, input_types)]\n",
|
|
" return inputs"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "f0de1682",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Wrapper helper functions for Inference\n",
|
|
"\n",
|
|
"Wrapper helper functions for running model inference using ONNX Runtime EP."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"id": "258ce9e9",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def get_onnxruntime_output(model: ModelProto, inputs: List, provider_name: AnyStr) -> np.ndarray:\n",
|
|
" output_names = get_onnx_output_names(model)\n",
|
|
" input_names = get_onnx_input_names(model)\n",
|
|
" assert len(input_names) == len(inputs)\n",
|
|
" input_dict = {input_name: input_value for input_name, input_value in zip(input_names, inputs)}\n",
|
|
"\n",
|
|
" inference_session = onnxruntime.InferenceSession(model.SerializeToString(), providers=[provider_name])\n",
|
|
" output = inference_session.run(output_names, input_dict)\n",
|
|
"\n",
|
|
" # Unpack output if there's only a single value.\n",
|
|
" if len(output) == 1:\n",
|
|
" output = output[0]\n",
|
|
" return output\n",
|
|
"\n",
|
|
"\n",
|
|
"def get_cpu_onnxruntime_output(model: ModelProto, inputs: List) -> np.ndarray:\n",
|
|
" return get_onnxruntime_output(model, inputs, \"CPUExecutionProvider\")\n",
|
|
"\n",
|
|
"\n",
|
|
"def get_tvm_onnxruntime_output(model: ModelProto, inputs: List) -> np.ndarray:\n",
|
|
" return get_onnxruntime_output(model, inputs, \"TvmExecutionProvider\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "cc17d3b2",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Helper function for checking accuracy\n",
|
|
"\n",
|
|
"This function uses the TVM API to compare two output tensors. The tensor obtained using the `CPUExecutionProvider` is used as a reference.\n",
|
|
"\n",
|
|
"If a mismatch is found between tensors, an appropriate exception will be thrown."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "4e598907",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def verify_outputs(\n",
|
|
" lhs: List[np.ndarray],\n",
|
|
" rhs: List[np.ndarray],\n",
|
|
" rtol: float = 5e-5,\n",
|
|
" atol: float = 5e-5\n",
|
|
") -> None:\n",
|
|
" for lhs_tensor, rhs_tensor in zip(lhs, rhs):\n",
|
|
" tvm.testing.assert_allclose(lhs_tensor, rhs_tensor, rtol=rtol, atol=atol)\n",
|
|
" assert lhs_tensor.dtype == rhs_tensor.dtype\n",
|
|
" print(\"Same output, congratulations!\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"id": "f33a372b",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def verify_with_ort_with_inputs(\n",
|
|
" model,\n",
|
|
" inputs,\n",
|
|
" out_shape=None,\n",
|
|
" opset=None,\n",
|
|
" freeze_params=False,\n",
|
|
" dtype=\"float32\",\n",
|
|
" rtol=1e-5,\n",
|
|
" atol=1e-5,\n",
|
|
" opt_level=1,\n",
|
|
"):\n",
|
|
" if opset is not None:\n",
|
|
" model.opset_import[0].version = opset\n",
|
|
"\n",
|
|
" ort_out = get_cpu_onnxruntime_output(model, inputs)\n",
|
|
" tvm_out = get_tvm_onnxruntime_output(model, inputs)\n",
|
|
" verify_outputs(ort_out, tvm_out, rtol, atol)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "8c62b01a",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Helper functions for download models\n",
|
|
"\n",
|
|
"These functions use the TVM API to download models from the ONNX Model Zoo."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"id": "324c00e7",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"BASE_MODEL_URL = \"https://github.com/onnx/models/raw/master/\"\n",
|
|
"MODEL_URL_COLLECTION = {\n",
|
|
" \"ResNet50-v1\": \"vision/classification/resnet/model/resnet50-v1-7.onnx\",\n",
|
|
" \"ResNet50-v2\": \"vision/classification/resnet/model/resnet50-v2-7.onnx\",\n",
|
|
" \"SqueezeNet-v1.1\": \"vision/classification/squeezenet/model/squeezenet1.1-7.onnx\",\n",
|
|
" \"SqueezeNet-v1.0\": \"vision/classification/squeezenet/model/squeezenet1.0-7.onnx\",\n",
|
|
" \"Inception-v1\": \"vision/classification/inception_and_googlenet/inception_v1/model/inception-v1-7.onnx\",\n",
|
|
" \"Inception-v2\": \"vision/classification/inception_and_googlenet/inception_v2/model/inception-v2-7.onnx\",\n",
|
|
"}\n",
|
|
"\n",
|
|
"\n",
|
|
"def get_model_url(model_name):\n",
|
|
" return BASE_MODEL_URL + MODEL_URL_COLLECTION[model_name]\n",
|
|
"\n",
|
|
"\n",
|
|
"def get_name_from_url(url):\n",
|
|
" return url[url.rfind(\"/\") + 1 :].strip()\n",
|
|
"\n",
|
|
"\n",
|
|
"def find_of_download(model_name):\n",
|
|
" model_url = get_model_url(model_name)\n",
|
|
" model_file_name = get_name_from_url(model_url)\n",
|
|
" return tvm.contrib.download.download_testdata(model_url, model_file_name, module=\"models\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "90fb7c5c",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 2. Accuracy check for TVM EP \n",
|
|
"\n",
|
|
"This section will check the accuracy. The check will be to compare the output tensors for `CPUExecutionProvider` and `TvmExecutionProvider`. See the description of `verify_with_ort_with_inputs` function used above.\n",
|
|
"\n",
|
|
"\n",
|
|
"### Check for simple architectures"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "c739ed5c",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def get_two_input_model(op_name: AnyStr) -> ModelProto:\n",
|
|
" dtype = \"float32\"\n",
|
|
" in_shape = [1, 2, 3, 3]\n",
|
|
" in_type = mapping.NP_TYPE_TO_TENSOR_TYPE[np.dtype(dtype)]\n",
|
|
" out_shape = in_shape\n",
|
|
" out_type = in_type\n",
|
|
"\n",
|
|
" layer = helper.make_node(op_name, [\"in1\", \"in2\"], [\"out\"])\n",
|
|
" graph = helper.make_graph(\n",
|
|
" [layer],\n",
|
|
" \"two_input_test\",\n",
|
|
" inputs=[\n",
|
|
" helper.make_tensor_value_info(\"in1\", in_type, in_shape),\n",
|
|
" helper.make_tensor_value_info(\"in2\", in_type, in_shape),\n",
|
|
" ],\n",
|
|
" outputs=[\n",
|
|
" helper.make_tensor_value_info(\n",
|
|
" \"out\", out_type, out_shape\n",
|
|
" )\n",
|
|
" ],\n",
|
|
" )\n",
|
|
" model = helper.make_model(graph, producer_name=\"two_input_test\")\n",
|
|
" checker.check_model(model, full_check=True)\n",
|
|
" return model"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "7048ee6d",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Same output, congratulations!\n",
|
|
"****************** Success! ******************\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"onnx_model = get_two_input_model(\"Add\")\n",
|
|
"inputs = get_random_model_inputs(onnx_model)\n",
|
|
"verify_with_ort_with_inputs(onnx_model, inputs)\n",
|
|
"print(\"****************** Success! ******************\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "52c880f4",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Check for DNN architectures "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 10,
|
|
"id": "f5d465dc",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def get_onnx_model(model_name):\n",
|
|
" model_path = find_of_download(model_name)\n",
|
|
" onnx_model = onnx.load(model_path)\n",
|
|
" return onnx_model"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"id": "68daac7e",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"One or more operators have not been tuned. Please tune your model for better performance. Use DEBUG logging level to see more details.\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Same output, congratulations!\n",
|
|
"****************** Success! ******************\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"model_name = \"ResNet50-v1\"\n",
|
|
"\n",
|
|
"onnx_model = get_onnx_model(model_name)\n",
|
|
"inputs = get_random_model_inputs(onnx_model)\n",
|
|
"verify_with_ort_with_inputs(onnx_model, inputs)\n",
|
|
"print(\"****************** Success! ******************\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "e27f64a2",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 3. Configuration options\n",
|
|
"\n",
|
|
"This section shows how you can configure TVM EP using custom options. For more details on the options used, see the corresponding section of the documentation."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 12,
|
|
"id": "a053f59f",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"provider_name = \"TvmExecutionProvider\"\n",
|
|
"provider_options = dict(\n",
|
|
" target=\"llvm -mtriple=x86_64-linux-gnu\",\n",
|
|
" target_host=\"llvm -mtriple=x86_64-linux-gnu\",\n",
|
|
" opt_level=3,\n",
|
|
" freeze_weights=True,\n",
|
|
" tuning_file_path=\"\",\n",
|
|
" tuning_type=\"Ansor\",\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 13,
|
|
"id": "3f6e6f01",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"model_name = \"ResNet50-v1\"\n",
|
|
"onnx_model = get_onnx_model(model_name)\n",
|
|
"input_dict = {\n",
|
|
" input_name: input_value for input_name, input_value in zip(\n",
|
|
" get_onnx_input_names(onnx_model),\n",
|
|
" get_random_model_inputs(onnx_model),\n",
|
|
" )\n",
|
|
"}\n",
|
|
"output_names = get_onnx_output_names(onnx_model)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 14,
|
|
"id": "85ab83f2",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"****************** Output shape: (1, 1000) ******************\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"tvm_session = onnxruntime.InferenceSession(\n",
|
|
" onnx_model.SerializeToString(),\n",
|
|
" providers=[provider_name],\n",
|
|
" provider_options=[provider_options],\n",
|
|
")\n",
|
|
"output = tvm_session.run(output_names, input_dict)[0]\n",
|
|
"print(f\"****************** Output shape: {output.shape} ******************\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b704374b",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 4. Support precompiled model\n",
|
|
"\n",
|
|
"Wrapper functions that allow you to compile the model and save it in the desired format."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 15,
|
|
"id": "8150942b",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def compile_virtual_machine(model: onnx.ModelProto, target_str: AnyStr) -> tvm.runtime.vm.Executable:\n",
|
|
" ir_mod, params = tvm.relay.frontend.from_onnx(\n",
|
|
" model,\n",
|
|
" opset=model.opset_import[0].version,\n",
|
|
" freeze_params=True,\n",
|
|
" )\n",
|
|
" target = tvm.target.Target(target=target_str, host=target_str)\n",
|
|
" return tvm.relay.backend.vm.compile(ir_mod, target)\n",
|
|
"\n",
|
|
"\n",
|
|
"def serialize_virtual_machine(vm_exec: tvm.runtime.vm.Executable) -> AnyStr:\n",
|
|
" temp_directory = tempfile.mkdtemp()\n",
|
|
" path_consts = os.path.join(temp_directory, \"consts\")\n",
|
|
" vm_exec.move_late_bound_consts(path_consts, byte_limit=256)\n",
|
|
" lib_path = os.path.join(temp_directory, f\"model.so\")\n",
|
|
" code_path = os.path.join(temp_directory, f\"model.ro\")\n",
|
|
" code, lib = vm_exec.save()\n",
|
|
" lib.export_library(lib_path)\n",
|
|
" with open(code_path, \"wb\") as fo:\n",
|
|
" fo.write(code)\n",
|
|
" return temp_directory"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "9cbb987e",
|
|
"metadata": {},
|
|
"source": [
|
|
"Preparation of the ONNX model."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 16,
|
|
"id": "febb9d72",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"model_name = \"ResNet50-v1\"\n",
|
|
"onnx_model = get_onnx_model(model_name)\n",
|
|
"input_dict = {\n",
|
|
" input_name: input_value for input_name, input_value in zip(\n",
|
|
" get_onnx_input_names(onnx_model),\n",
|
|
" get_random_model_inputs(onnx_model),\n",
|
|
" )\n",
|
|
"}\n",
|
|
"output_names = get_onnx_output_names(onnx_model)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b05b251a",
|
|
"metadata": {},
|
|
"source": [
|
|
"Compiling the ONNX model using `VirtualMachine` (TVM)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 17,
|
|
"id": "b4b999ee",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"compiled_vm_exec = compile_virtual_machine(onnx_model, target_str=\"llvm\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 18,
|
|
"id": "e3408c15",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"so_folder = serialize_virtual_machine(compiled_vm_exec)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "311405e8",
|
|
"metadata": {},
|
|
"source": [
|
|
"Preparing `ProviderOptions` and launching `TVM EP` inference.\n",
|
|
"\n",
|
|
"In order to use the precompiled model, you only need to pass two options:\n",
|
|
"* **executor** - `vm` (`VirtualMachine`) must be used as a value (this functionality is not supported for `GraphExecutor`);\n",
|
|
"* **so_folder** - as a value, you must pass the path to the directory where the files of the precompiled model are located."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 19,
|
|
"id": "8927293c",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"provider_name = \"TvmExecutionProvider\"\n",
|
|
"provider_options = dict(\n",
|
|
" executor=\"vm\",\n",
|
|
" so_folder=so_folder,\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 20,
|
|
"id": "d7532863",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"tvm_session = onnxruntime.InferenceSession(\n",
|
|
" onnx_model.SerializeToString(),\n",
|
|
" providers=[provider_name],\n",
|
|
" provider_options=[provider_options],\n",
|
|
")\n",
|
|
"tvm_output = tvm_session.run(output_names, input_dict)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "1c0b983e",
|
|
"metadata": {},
|
|
"source": [
|
|
"Let's make sure that the output values match those that can be obtained through `CPUExecutionProvider`:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 21,
|
|
"id": "c3de2299",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Same output, congratulations!\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"verify_outputs(\n",
|
|
" tvm_output[0],\n",
|
|
" get_cpu_onnxruntime_output(\n",
|
|
" onnx_model,\n",
|
|
" input_dict.values()\n",
|
|
" ),\n",
|
|
")"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3 (ipykernel)",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.8.10"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|