From 6f37e6ca20f34e12e7660fee4aedf574fd4b9289 Mon Sep 17 00:00:00 2001 From: Shushi Hong <820958424@qq.com> Date: Sat, 1 Nov 2025 12:30:54 -0400 Subject: [PATCH 1/3] Replace relax.build with tvm.compile in export script --- .../tutorials/export_and_load_executable.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/how_to/tutorials/export_and_load_executable.py b/docs/how_to/tutorials/export_and_load_executable.py index 81e9bb0ef4d1..530a84f4a528 100644 --- a/docs/how_to/tutorials/export_and_load_executable.py +++ b/docs/how_to/tutorials/export_and_load_executable.py @@ -126,7 +126,7 @@ def forward(self, data: torch.Tensor) -> torch.Tensor: # type: ignore[override] built_mod = pipeline(mod) # Build without params - we'll pass them at runtime - executable = relax.build(built_mod, target=TARGET) + executable = tvm.compile(built_mod, target=TARGET) library_path = ARTIFACT_DIR / "mlp_cpu.so" executable.export_library(str(library_path), workspace_dir=str(ARTIFACT_DIR)) @@ -176,7 +176,10 @@ def forward(self, data: torch.Tensor) -> torch.Tensor: # type: ignore[override] # TVM returns Array objects for tuple outputs, access via indexing. # For models imported from PyTorch, outputs are typically tuples (even for single outputs). # For ONNX models, outputs may be a single Tensor directly. - result_tensor = tvm_output[0] if isinstance(tvm_output, (tuple, list)) else tvm_output + if hasattr(tvm_output, "__len__") and len(tvm_output) > 0: + result_tensor = tvm_output[0] + else: + result_tensor = tvm_output print("VM output shape:", result_tensor.shape) print("VM output type:", type(tvm_output), "->", type(result_tensor)) @@ -209,7 +212,7 @@ def forward(self, data: torch.Tensor) -> torch.Tensor: # type: ignore[override] # # mod = from_exported_program(exported_program, keep_params_as_input=False) # # Parameters are now embedded as constants in the module -# executable = relax.build(built_mod, target=TARGET) +# executable = tvm.compile(built_mod, target=TARGET) # # Runtime: vm["main"](input) # No need to pass params! # # This creates a single-file deployment (only the ``.so`` is needed), but you @@ -262,7 +265,10 @@ def forward(self, data: torch.Tensor) -> torch.Tensor: # type: ignore[override] # # # Step 6: Extract result (output may be tuple or single Tensor) # # PyTorch models typically return tuples, ONNX models may return a single Tensor -# result = output[0] if isinstance(output, (tuple, list)) else output +# if hasattr(tvm_output, "__len__") and len(tvm_output) > 0: +# result_tensor = tvm_output[0] +# else: +# result_tensor = tvm_output # # print("Prediction shape:", result.shape) # print("Predicted class:", np.argmax(result.numpy())) @@ -332,7 +338,7 @@ def forward(self, data: torch.Tensor) -> torch.Tensor: # type: ignore[override] # # # Step 1: Cross-compile for ARM target (on local machine) # TARGET = tvm.target.Target("llvm -mtriple=aarch64-linux-gnu") -# executable = relax.build(built_mod, target=TARGET) +# executable = tvm.compile(built_mod, target=TARGET) # executable.export_library("mlp_arm.so") # # # Step 2: Connect to remote device RPC server From 0f222350a6fd8f3e4cec31e93aa5febf8a0e2de6 Mon Sep 17 00:00:00 2001 From: Shushi Hong <820958424@qq.com> Date: Sat, 1 Nov 2025 15:58:21 -0400 Subject: [PATCH 2/3] Remove unnecessary print statement in export script Remove print statement for skipping model conversion. --- docs/how_to/tutorials/export_and_load_executable.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/how_to/tutorials/export_and_load_executable.py b/docs/how_to/tutorials/export_and_load_executable.py index 530a84f4a528..0b8ba75d2621 100644 --- a/docs/how_to/tutorials/export_and_load_executable.py +++ b/docs/how_to/tutorials/export_and_load_executable.py @@ -89,9 +89,6 @@ def forward(self, data: torch.Tensor) -> torch.Tensor: # type: ignore[override] else: # pragma: no cover TorchMLP = None # type: ignore[misc, assignment] -if not RUN_EXAMPLE: - print("Skip model conversion because PyTorch is unavailable or we are in CI.") - if RUN_EXAMPLE: torch_model = TorchMLP().eval() example_args = (torch.randn(1, 1, 28, 28, dtype=torch.float32),) From f298ffe484599210a4bc74565b06d9c98bd503a8 Mon Sep 17 00:00:00 2001 From: Shushi Hong <820958424@qq.com> Date: Sat, 1 Nov 2025 16:31:39 -0400 Subject: [PATCH 3/3] Update output handling for TVM results --- docs/how_to/tutorials/export_and_load_executable.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/how_to/tutorials/export_and_load_executable.py b/docs/how_to/tutorials/export_and_load_executable.py index 0b8ba75d2621..9665db48cb5b 100644 --- a/docs/how_to/tutorials/export_and_load_executable.py +++ b/docs/how_to/tutorials/export_and_load_executable.py @@ -173,7 +173,7 @@ def forward(self, data: torch.Tensor) -> torch.Tensor: # type: ignore[override] # TVM returns Array objects for tuple outputs, access via indexing. # For models imported from PyTorch, outputs are typically tuples (even for single outputs). # For ONNX models, outputs may be a single Tensor directly. - if hasattr(tvm_output, "__len__") and len(tvm_output) > 0: + if isinstance(tvm_output, tvm.ir.Array) and len(tvm_output) > 0: result_tensor = tvm_output[0] else: result_tensor = tvm_output @@ -262,7 +262,7 @@ def forward(self, data: torch.Tensor) -> torch.Tensor: # type: ignore[override] # # # Step 6: Extract result (output may be tuple or single Tensor) # # PyTorch models typically return tuples, ONNX models may return a single Tensor -# if hasattr(tvm_output, "__len__") and len(tvm_output) > 0: +# if isinstance(tvm_output, tvm.ir.Array) and len(tvm_output) > 0: # result_tensor = tvm_output[0] # else: # result_tensor = tvm_output