diff --git a/tools/accuracy_checker/accuracy_checker/adapters/README.md b/tools/accuracy_checker/accuracy_checker/adapters/README.md index d7eae48755..83d0247a07 100644 --- a/tools/accuracy_checker/accuracy_checker/adapters/README.md +++ b/tools/accuracy_checker/accuracy_checker/adapters/README.md @@ -99,6 +99,8 @@ AccuracyChecker supports following set of adapters: * `yolo_v8_detection` - converting output of YOLO v8 family pretrained for object detection to `DetectionPrediction`. * `conf_threshold` - minimal confidence for filtering valid detections (Optional, default 0.25). * `multi_label` - allow to use multiple labels for the same box coordinates (Optional, default True). +* `yolo26` - converting output of YOLO26 model to `DetectionPrediction` representation. + * `conf_threshold` - minimal confidence for filtering valid detections (Optional, default 0.25). * `lpr` - converting output of license plate recognition model to `CharacterRecognitionPrediction` representation. * `aocr` - converting output of attention-ocr model to `CharacterRecognitionPrediction`. * `output_blob` - name of output layer with predicted labels or string (Optional, if not provided, first founded output will be used). diff --git a/tools/accuracy_checker/accuracy_checker/adapters/__init__.py b/tools/accuracy_checker/accuracy_checker/adapters/__init__.py index 10c1a0d6d2..a5923e84dc 100644 --- a/tools/accuracy_checker/accuracy_checker/adapters/__init__.py +++ b/tools/accuracy_checker/accuracy_checker/adapters/__init__.py @@ -88,7 +88,8 @@ YoloxsAdapter, YolofAdapter, # for adapter registration, it should be imported and added to __all__ list - YoloV8DetectionAdapter + YoloV8DetectionAdapter, + Yolo26Adapter ) from .classification import ClassificationAdapter, MaskToBinaryClassification from .segmentation import ( @@ -188,6 +189,7 @@ 'YoloxsAdapter', 'YolofAdapter', 'YoloV8DetectionAdapter', + 'Yolo26Adapter', 'SSDAdapter', 'SSDAdapterMxNet', diff --git a/tools/accuracy_checker/accuracy_checker/adapters/yolo.py b/tools/accuracy_checker/accuracy_checker/adapters/yolo.py index 9133f51823..ba3ba54c63 100644 --- a/tools/accuracy_checker/accuracy_checker/adapters/yolo.py +++ b/tools/accuracy_checker/accuracy_checker/adapters/yolo.py @@ -963,3 +963,38 @@ def process(self, raw, identifiers, frame_meta): # DetectionPrediction(identifier, label, score, x_mins, y_mins, x_maxs, y_maxs, meta) result.append(DetectionPrediction(identifier, labels, conf, *box.T, meta)) return result + +class Yolo26Adapter(Adapter): + __provider__ = "yolo26" + + @classmethod + def parameters(cls): + params = super().parameters() + params.update({"conf_threshold": NumberField(value_type=float, optional=True, min_value=0, default=0.25, + description="Minimal confidence value for valid detections.")}) + return params + + def configure(self): + self.conf_threshold = self.get_value_from_config("conf_threshold") + + def process(self, raw, identifiers, frame_meta): + result = [] + raw_outputs = self._extract_predictions(raw, frame_meta) + prediction = raw_outputs[self.output_blob] + + # expected output format is box(x1, y1, x2, y2), confidence, class_id for each detected object + if len(prediction.shape) != 3 and prediction.shape[1] != 6: + raise ValueError("Output format should have 3 dimensions where the second dimension is 6, " + "but found shape {}".format(prediction.shape)) + + for identifier, output, meta in zip(identifiers, prediction, frame_meta): + boxes = output[:, :4] + confidences = output[:, 4] + classes = output[:, 5] + + min_conf = confidences.reshape(-1) > self.conf_threshold + boxes = boxes[min_conf] + confidences = confidences[min_conf] + classes = classes[min_conf] + result.append(DetectionPrediction(identifier, classes, confidences, *boxes.T, meta)) + return result diff --git a/tools/accuracy_checker/accuracy_checker/launcher/pytorch_launcher.py b/tools/accuracy_checker/accuracy_checker/launcher/pytorch_launcher.py index bab8b4349e..d6af02e2f3 100644 --- a/tools/accuracy_checker/accuracy_checker/launcher/pytorch_launcher.py +++ b/tools/accuracy_checker/accuracy_checker/launcher/pytorch_launcher.py @@ -32,7 +32,7 @@ CLASS_REGEX = r'(?:\w+)' MODULE_REGEX = r'(?:\w+)(?:(?:.\w+)*)' DEVICE_REGEX = r'(?Pcpu$|cuda)?' -CHECKPOINT_URL_REGEX = r'^https?://.*\.pth(\?.*)?(#.*)?$' +CHECKPOINT_URL_REGEX = r'^https?://.*\.pth?(\?.*)?(#.*)?$' SCALAR_INPUTS = ('input_ids', 'input_mask', 'segment_ids', 'attention_mask', 'token_type_ids') class PyTorchLauncher(Launcher): @@ -49,6 +49,9 @@ def parameters(cls): 'checkpoint_url': StringField( optional=True, regex=CHECKPOINT_URL_REGEX, description='Url link to pre-trained model checkpoint.' ), + 'checkpoint_weights_only': BoolField( + optional=True, default=True, description='Model checkpoint stored as weights only.' + ), 'state_key': StringField(optional=True, regex=r'\w+', description='pre-trained model checkpoint state key'), 'python_path': PathField( check_exists=True, is_directory=True, optional=True, @@ -108,6 +111,7 @@ def __init__(self, config_entry: dict, *args, **kwargs): checkpoint = config_entry.get('checkpoint') if checkpoint is None: checkpoint = config_entry.get('checkpoint_url') + self.checkpoint_weights_only = config_entry.get('checkpoint_weights_only', True) python_path = config_entry.get("python_path") @@ -174,9 +178,24 @@ def load_module(self, model_cls, module_args, module_kwargs, checkpoint=None, st if isinstance(checkpoint, str) and re.match(CHECKPOINT_URL_REGEX, checkpoint): checkpoint = urllib.request.urlretrieve(checkpoint)[0] # nosec B310 # disable urllib-urlopen check checkpoint = self._torch.load( - checkpoint, map_location=None if self.cuda else self._torch.device('cpu') + checkpoint, + map_location=None if self.cuda else self._torch.device('cpu'), + weights_only=self.checkpoint_weights_only ) state = checkpoint if not state_key else checkpoint[state_key] + + if not self.checkpoint_weights_only: + + state_dict_contains_model = ( + isinstance(state, dict) and + 'model' in state and + isinstance(state['model'], self._torch.nn.Module) + ) + + if state_dict_contains_model: + loaded_model = state['model'] + return self.prepare_module(loaded_model, model_cls) + if all(key.startswith('module.') for key in state): module = self._torch.nn.DataParallel(module) module.load_state_dict(state, strict=False) @@ -262,7 +281,13 @@ def predict(self, inputs, metadata=None, **kwargs): results = [] with self._torch.no_grad(): for batch_input in inputs: - if metadata[0].get('input_is_dict_type') or (isinstance(batch_input, dict) and 'input' in batch_input): + is_input_as_dict = metadata[0].get('input_is_dict_type') or isinstance(batch_input, dict) + if is_input_as_dict and 'input' in batch_input: + inp = batch_input['input'] + model_dtype = next(self.module.parameters()).dtype + if inp.dtype != model_dtype: + batch_input['input'] = inp.to(model_dtype) + outputs = self.module(batch_input['input']) else: outputs = self.module(**batch_input) diff --git a/tools/accuracy_checker/accuracy_checker/launcher/pytorch_launcher_readme.md b/tools/accuracy_checker/accuracy_checker/launcher/pytorch_launcher_readme.md index d32f5c560c..bd6e304fda 100644 --- a/tools/accuracy_checker/accuracy_checker/launcher/pytorch_launcher_readme.md +++ b/tools/accuracy_checker/accuracy_checker/launcher/pytorch_launcher_readme.md @@ -8,6 +8,7 @@ For enabling PyTorch launcher you need to add `framework: pytorch` in launchers * `module`- PyTorch network module for loading. * `checkpoint` - pre-trained model checkpoint (Optional). * `checkpoint_url` - url link to pre-trained model checkpoint (Optional). +* `checkpoint_weights_only` - boolean, use weights only model checkpoint (Optional, default `True`). * `state_key` - pre-trained model checkpoint state key (Optional). * `python_path` - appendix for PYTHONPATH for making network module visible in current python environment (Optional). * `module_args` - list of positional arguments for network module (Optional).