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]

Reply via email to