Skip to content

Commit 93e8e94

Browse files
authored
feature: support native YOLO .pt models while ensuring compatibility with Torchvision models (#495)
* feature: support native YOLO .pt models with centralized output normalization * feature: support native YOLO .pt models while ensuring compatibility with Torchvision models * Removed dtype extraction and subsequent casting in DetectionModelWrapper
1 parent 945c33a commit 93e8e94

1 file changed

Lines changed: 40 additions & 16 deletions

File tree

perceptionmetrics/models/torch_detection.py

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -268,27 +268,51 @@ def __init__(
268268
try:
269269
model = torch.jit.load(model, map_location=self.device)
270270
model_type = "compiled"
271-
except RuntimeError:
271+
except Exception:
272272
try:
273-
model = torch.load(
274-
model, map_location=self.device, weights_only=False
275-
)
273+
loaded = torch.load(model, map_location=self.device, weights_only=False)
274+
# Handle Ultralytics/YOLO-style dict checkpoints
275+
if isinstance(loaded, dict):
276+
candidate = loaded.get("ema") or loaded.get("model")
277+
if candidate is None or not hasattr(candidate, "forward"):
278+
raise ValueError(
279+
"""
280+
The loaded .pt file is a dictionary but doesn't contain a valid model under keys 'model' or 'ema'. Please export to TorchScript for better compatibility.
281+
"""
282+
)
283+
model = candidate
284+
else:
285+
model = loaded
276286
model_type = "native"
277-
except Exception as e:
278-
raise ValueError(
279-
f"Failed to load model. "
280-
f"Ensure it is a valid PyTorch or TorchScript model. Error : {e}"
281-
)
282-
283-
elif isinstance(model, torch.nn.Module):
284-
model_fname = None
285-
model_type = "native"
286-
else:
287-
raise ValueError("Model must be a filename or a torch.nn.Module")
287+
# Fallback for missing Ultralytics dependency
288+
except (ModuleNotFoundError, AttributeError) as e:
289+
raise ImportError(
290+
f"Failed to load native .pt model. This often happens if the 'ultralytics' "
291+
f"library is missing or incompatible. \nOriginal error: {e}\n"
292+
f"SUGGESTION: 'pip install ultralytics' or export your model to TorchScript."
293+
) from e
288294

289295
# Init parent class
290296
super().__init__(model, model_type, model_cfg, ontology_fname, model_fname)
291-
self.model = self.model.to(self.device).eval()
297+
298+
# Define the Wrapper with DType Alignment
299+
class DetectionModelWrapper(torch.nn.Module):
300+
def __init__(self, model):
301+
super().__init__()
302+
self.inner_model = model
303+
304+
# Handle input precision, tuple extraction, and output precision
305+
def forward(self, x):
306+
out = self.inner_model(x)
307+
# Only unwrap TUPLES (native YOLO .pt)
308+
# Avoid unwrapping LISTS (torchvision Mask R-CNN)
309+
if isinstance(out, tuple) and len(out) > 0:
310+
out = out[0]
311+
if isinstance(out, torch.Tensor):
312+
return out.float()
313+
return out
314+
315+
self.model = DetectionModelWrapper(self.model).to(self.device).float().eval()
292316

293317
# Load post-processing functions for specific model formats
294318
self.model_format = self.model_cfg.get("model_format", "torchvision")

0 commit comments

Comments
 (0)