guest2180 commented on issue #19887: URL: https://github.com/apache/tvm/issues/19887#issuecomment-4828975079
@tlopex ### Repro model Official Ultralytics model: - `https://github.com/ultralytics/assets/releases/download/v8.3.0/yolo11n.onnx` ### Repro script ```python from __future__ import annotations import argparse import os import traceback from collections import Counter from pathlib import Path import onnx import tvm from tvm import relax from tvm.relax.dpl import is_op, wildcard from tvm.relax.frontend.onnx import from_onnx TRT_LIB_DIR = "/usr/local/TensorRT-10.16.1.11/lib" DEFAULT_ONNX = Path("/home/perception/yolo11n_repro/yolo11n.onnx") INPUT_NAME = "images" INPUT_SHAPE = [1, 3, 640, 640] def ensure_tensorrt_library_path() -> None: if not os.path.isdir(TRT_LIB_DIR): return current = os.environ.get("LD_LIBRARY_PATH", "") parts = [p for p in current.split(":") if p] if TRT_LIB_DIR not in parts: os.environ["LD_LIBRARY_PATH"] = f"{TRT_LIB_DIR}:{current}" if current else TRT_LIB_DIR def inspect_onnx_model(onnx_path: Path) -> dict[str, object]: model = onnx.load(str(onnx_path)) return { "model": model, "inputs": [ (value.name, [dim.dim_value or dim.dim_param for dim in value.type.tensor_type.shape.dim]) for value in model.graph.input ], "outputs": [ (value.name, [dim.dim_value or dim.dim_param for dim in value.type.tensor_type.shape.dim]) for value in model.graph.output ], "node_count": len(model.graph.node), "opset": [(item.domain or "ai.onnx", item.version) for item in model.opset_import], "ops": Counter(node.op_type for node in model.graph.node), } def build_base_patterns() -> list[tuple[str, object]]: return [ ("tensorrt.nn.conv2d", is_op("relax.nn.conv2d")(wildcard(), wildcard())), ("tensorrt.nn.conv2d_transpose", is_op("relax.nn.conv2d_transpose")(wildcard(), wildcard())), ("tensorrt.add", is_op("relax.add")(wildcard(), wildcard())), ("tensorrt.subtract", is_op("relax.subtract")(wildcard(), wildcard())), ("tensorrt.multiply", is_op("relax.multiply")(wildcard(), wildcard())), ("tensorrt.divide", is_op("relax.divide")(wildcard(), wildcard())), ("tensorrt.sigmoid", is_op("relax.sigmoid")(wildcard())), ("tensorrt.nn.softmax", is_op("relax.nn.softmax")(wildcard())), ("tensorrt.nn.max_pool2d", is_op("relax.nn.max_pool2d")(wildcard())), ("tensorrt.nn.avg_pool2d", is_op("relax.nn.avg_pool2d")(wildcard())), ] def build_extra_pattern(name: str) -> tuple[str, object]: mapping = { "relu": ("tensorrt.nn.relu", is_op("relax.nn.relu")(wildcard())), "concat": ("tensorrt.concatenate", is_op("relax.concat")(wildcard())), "split": ("tensorrt.split", is_op("relax.split")(wildcard())), "exp": ("tensorrt.exp", is_op("relax.exp")(wildcard())), "atan": ("tensorrt.atan", is_op("relax.atan")(wildcard())), "resize2d": ("tensorrt.image.resize2d", is_op("relax.image.resize2d")(wildcard())), "permute_dims": ("tensorrt.permute_dims", is_op("relax.permute_dims")(wildcard())), "reshape": ("tensorrt.reshape", is_op("relax.reshape")(wildcard())), "expand_dims": ("tensorrt.expand_dims", is_op("relax.expand_dims")(wildcard())), } return mapping[name] def count_trt_regions(mod: tvm.IRModule) -> int: count = 0 for _, func in mod.functions.items(): attrs = getattr(func, "attrs", None) if attrs is None: continue try: if attrs["Codegen"] == "tensorrt": count += 1 except Exception: pass return count def try_patterns(onnx_path: Path, extra_names: list[str]) -> dict[str, object]: info = inspect_onnx_model(onnx_path) patterns = build_base_patterns() + [build_extra_pattern(name) for name in extra_names] result: dict[str, object] = {"extras": list(extra_names)} try: mod = from_onnx(info["model"], shape_dict={INPUT_NAME: INPUT_SHAPE}) fused = relax.transform.FuseOpsByPattern(patterns)(mod) merged = relax.transform.MergeCompositeFunctions()(fused) result["trt_regions"] = count_trt_regions(merged) _ = relax.transform.RunCodegen()(merged) result["status"] = "ok" except Exception as err: result["status"] = "failed" result["error"] = str(err) result["trace"] = traceback.format_exc() return result def print_model_summary(onnx_path: Path) -> None: info = inspect_onnx_model(onnx_path) print(f"onnx={onnx_path}") print(f"inputs={info['inputs']}") print(f"outputs={info['outputs']}") print(f"nodes={info['node_count']}") print(f"opset={info['opset']}") print(f"top_ops={info['ops'].most_common(12)}") def run_baseline(onnx_path: Path) -> int: print("mode=baseline") result = try_patterns(onnx_path, []) if result["status"] == "ok": print(f"baseline=OK trt_regions={result['trt_regions']}") return 0 print(f"baseline=FAIL trt_regions={result.get('trt_regions', 'n/a')}") print(f"baseline_error={result['error']}") return 1 def run_pattern_scan(onnx_path: Path) -> int: print("mode=pattern_scan") scan_items = [ "concat", "split", "resize2d", "permute_dims", "reshape", "expand_dims", "relu", "exp", "atan", ] serializer_hits = 0 for name in scan_items: result = try_patterns(onnx_path, [name]) if result["status"] == "ok": print(f"scan[{name}]=OK trt_regions={result['trt_regions']}") continue error = str(result.get("error", "")) if "Cannot find the name of the constant" in error: serializer_hits += 1 kind = "SERIALIZER_CONST_NAME" else: kind = "OTHER_FAIL" print(f"scan[{name}]={kind} trt_regions={result.get('trt_regions', 'n/a')}") print(f"scan_error[{name}]={error}") print(f"serializer_const_name_hits={serializer_hits}") return 0 def main() -> int: parser = argparse.ArgumentParser(description="Minimal YOLO11n TensorRT BYOC serializer repro") parser.add_argument("--onnx", type=Path, default=DEFAULT_ONNX) parser.add_argument("--mode", choices=["baseline", "pattern_scan"], default="pattern_scan") args = parser.parse_args() ensure_tensorrt_library_path() print_model_summary(args.onnx) if args.mode == "baseline": return run_baseline(args.onnx) return run_pattern_scan(args.onnx) if __name__ == "__main__": raise SystemExit(main()) ``` ### Repro command ```bash python repro_yolo11n_byoc.py --mode pattern_scan ``` `--mode baseline` runs the same graph with only the stable base TensorRT patterns, as a control case. ### Observed result ```text scan[concat]=SERIALIZER_CONST_NAME trt_regions=21 scan_error[concat]=Check failed: (name != constant_names_.end()) is false: Cannot find the name of the constant: metadata["relax.expr.Constant"][0] scan[split]=SERIALIZER_CONST_NAME trt_regions=44 scan_error[split]=Check failed: (name != constant_names_.end()) is false: Cannot find the name of the constant: metadata["relax.expr.Constant"][0] scan[resize2d]=OK trt_regions=42 scan[permute_dims]=OK trt_regions=44 ``` ### Interpretation - `concat` / `split` reproduce a serializer constant-name failure - `resize2d` / `permute_dims` do not reproduce that same failure on this model - In our smaller handcrafted repros, `resize2d` / `permute_dims` still hit unsupported offload/codegen paths So these currently look like two different TensorRT BYOC issues, not one. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
