From 805a8748c7b1afb7cdb0c9af215ff99115242d9f Mon Sep 17 00:00:00 2001 From: alisajil Date: Sun, 2 Aug 2026 08:56:11 +0530 Subject: [PATCH] fix: refresh ONNX shape info after export passes, guard empty powermetrics line OnnxOptimizer's Gather-squeeze QNN workaround hand-crafts a value_info entry without keeping the rest of the graph's shape info in sync. onnxruntime tolerates the resulting inconsistency but AI Hub's strict onnx.checker rejects it (ShapeInferenceError: rank mismatch). Refresh value_info from scratch at the end of every optimization pass instead of patching individual exported artifacts by hand each time this comes up. Also guard PowerMetricsCollector._run_apple against an empty stdout line from the powermetrics subprocess, which crashed a background thread with an IndexError. Co-Authored-By: Claude Sonnet 5 --- video/conversion/_exporter/_onnx_utils.py | 11 +++++++++++ video/conversion/_powermetrics.py | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/video/conversion/_exporter/_onnx_utils.py b/video/conversion/_exporter/_onnx_utils.py index 5c7acf3..b5554cc 100644 --- a/video/conversion/_exporter/_onnx_utils.py +++ b/video/conversion/_exporter/_onnx_utils.py @@ -4,6 +4,7 @@ import numpy as np import onnx import onnxscript +from onnx import shape_inference from onnxscript import ir DEFAULT_ONNX_PASSES = [ @@ -57,6 +58,16 @@ def optimize(self, passes=DEFAULT_ONNX_PASSES): self._qc_workaround_clip_min_only() else: raise ValueError(f"Unknown pass: {pass_name}") + + # Passes like qc_workaround_squeeze_gather_4d hand-craft new tensors + # and value_info entries without keeping the rest of the graph's + # shape info in sync. onnxruntime tolerates the resulting + # inconsistency, but AI Hub's strict onnx.checker rejects it with + # e.g. "Inferred shape and existing shape differ in rank: (2) vs + # (4)". Rebuild value_info from scratch so every saved model is + # internally consistent, regardless of which passes ran. + del self._model.graph.value_info[:] + self._model = shape_inference.infer_shapes(self._model) return self._model def _replace_reciprocal_op(self): diff --git a/video/conversion/_powermetrics.py b/video/conversion/_powermetrics.py index 852ae2b..6dc762e 100644 --- a/video/conversion/_powermetrics.py +++ b/video/conversion/_powermetrics.py @@ -82,7 +82,7 @@ def _run_apple(self): break line = process.stdout.readline() - if line[0] == 0: + if line and line[0] == 0: d = b"".join(buffer) data = plistlib.loads(d) row = PowermetricsSample(