From f2ed85790fedb1dcfe3fccccc497c6a0ba571e01 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 1 Aug 2023 14:58:14 +0200 Subject: [PATCH 1/3] [Snyk] Security upgrade numpy from 1.21.3 to 1.22.2 (#4090) Co-authored-by: snyk-bot --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index b2e4684ca8..7a457ddade 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,7 @@ # Base ---------------------------------------- matplotlib>=3.2.2 +numpy>=1.22.2 # pinned by Snyk to avoid a vulnerability opencv-python>=4.6.0 pillow>=7.1.2 pyyaml>=5.3.1 From b507e3a03260bc333474641b7d36aaabb736b8af Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 1 Aug 2023 15:41:09 +0200 Subject: [PATCH 2/3] Support both `*.yml` and `*.yaml` files (#4086) Co-authored-by: ChristopherRogers1991 Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sungjoo(Dennis) Hwang <48212469+Denny-Hwang@users.noreply.github.com> --- docs/models/yolov8.md | 12 ++++++------ ultralytics/engine/exporter.py | 2 +- ultralytics/engine/model.py | 2 +- ultralytics/engine/trainer.py | 2 +- ultralytics/engine/validator.py | 2 +- ultralytics/models/fastsam/model.py | 2 +- ultralytics/models/nas/model.py | 2 +- ultralytics/models/rtdetr/model.py | 4 ++-- ultralytics/models/yolo/classify/train.py | 2 +- ultralytics/utils/benchmarks.py | 4 ++-- 10 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/models/yolov8.md b/docs/models/yolov8.md index 240be83d3b..882fc4cf08 100644 --- a/docs/models/yolov8.md +++ b/docs/models/yolov8.md @@ -21,12 +21,12 @@ YOLOv8 is the latest iteration in the YOLO series of real-time object detectors, ## Supported Tasks -| Model Type | Pre-trained Weights | Task | -|-------------|------------------------------------------------------------------------------------------------------------------|-----------------------| -| YOLOv8 | `yolov8n.pt`, `yolov8s.pt`, `yolov8m.pt`, `yolov8l.pt`, `yolov8x.pt` | Detection | -| YOLOv8-seg | `yolov8n-seg.pt`, `yolov8s-seg.pt`, `yolov8m-seg.pt`, `yolov8l-seg.pt`, `yolov8x-seg.pt` | Instance Segmentation | -| YOLOv8-pose | `yolov8n-pose.pt`, `yolov8s-pose.pt`, `yolov8m-pose.pt`, `yolov8l-pose.pt`, `yolov8x-pose.pt` ,`yolov8x-pose-p6` | Pose/Keypoints | -| YOLOv8-cls | `yolov8n-cls.pt`, `yolov8s-cls.pt`, `yolov8m-cls.pt`, `yolov8l-cls.pt`, `yolov8x-cls.pt` | Classification | +| Model Type | Pre-trained Weights | Task | +|-------------|---------------------------------------------------------------------------------------------------------------------|-----------------------| +| YOLOv8 | `yolov8n.pt`, `yolov8s.pt`, `yolov8m.pt`, `yolov8l.pt`, `yolov8x.pt` | Detection | +| YOLOv8-seg | `yolov8n-seg.pt`, `yolov8s-seg.pt`, `yolov8m-seg.pt`, `yolov8l-seg.pt`, `yolov8x-seg.pt` | Instance Segmentation | +| YOLOv8-pose | `yolov8n-pose.pt`, `yolov8s-pose.pt`, `yolov8m-pose.pt`, `yolov8l-pose.pt`, `yolov8x-pose.pt`, `yolov8x-pose-p6.pt` | Pose/Keypoints | +| YOLOv8-cls | `yolov8n-cls.pt`, `yolov8s-cls.pt`, `yolov8m-cls.pt`, `yolov8l-cls.pt`, `yolov8x-cls.pt` | Classification | ## Supported Modes diff --git a/ultralytics/engine/exporter.py b/ultralytics/engine/exporter.py index 9c97979ee0..5b26643c92 100644 --- a/ultralytics/engine/exporter.py +++ b/ultralytics/engine/exporter.py @@ -177,7 +177,7 @@ class Exporter: im = torch.zeros(self.args.batch, 3, *self.imgsz).to(self.device) file = Path( getattr(model, 'pt_path', None) or getattr(model, 'yaml_file', None) or model.yaml.get('yaml_file', '')) - if file.suffix == '.yaml': + if file.suffix in ('.yaml', '.yml'): file = Path(file.name) # Update model diff --git a/ultralytics/engine/model.py b/ultralytics/engine/model.py index 68891bfd3c..8a8d59721f 100644 --- a/ultralytics/engine/model.py +++ b/ultralytics/engine/model.py @@ -88,7 +88,7 @@ class Model: suffix = Path(model).suffix if not suffix and Path(model).stem in GITHUB_ASSET_STEMS: model, suffix = Path(model).with_suffix('.pt'), '.pt' # add suffix, i.e. yolov8n -> yolov8n.pt - if suffix == '.yaml': + if suffix in ('.yaml', '.yml'): self._new(model, task) else: self._load(model, task) diff --git a/ultralytics/engine/trainer.py b/ultralytics/engine/trainer.py index 5c034cfc0d..9532d307ac 100644 --- a/ultralytics/engine/trainer.py +++ b/ultralytics/engine/trainer.py @@ -119,7 +119,7 @@ class BaseTrainer: try: if self.args.task == 'classify': self.data = check_cls_dataset(self.args.data) - elif self.args.data.endswith('.yaml') or self.args.task in ('detect', 'segment'): + elif self.args.data.split('.')[-1] in ('yaml', 'yml') or self.args.task in ('detect', 'segment'): self.data = check_det_dataset(self.args.data) if 'yaml_file' in self.data: self.args.data = self.data['yaml_file'] # for validating 'yolo train data=url.zip' usage diff --git a/ultralytics/engine/validator.py b/ultralytics/engine/validator.py index e1382cd49f..2b08912cd4 100644 --- a/ultralytics/engine/validator.py +++ b/ultralytics/engine/validator.py @@ -126,7 +126,7 @@ class BaseValidator: self.args.batch = 1 # export.py models default to batch-size 1 LOGGER.info(f'Forcing batch=1 square inference (1,3,{imgsz},{imgsz}) for non-PyTorch models') - if isinstance(self.args.data, str) and self.args.data.endswith('.yaml'): + if isinstance(self.args.data, str) and self.args.data.split('.')[-1] in ('yaml', 'yml'): self.data = check_det_dataset(self.args.data) elif self.args.task == 'classify': self.data = check_cls_dataset(self.args.data, split=self.args.split) diff --git a/ultralytics/models/fastsam/model.py b/ultralytics/models/fastsam/model.py index 6cfedc4ae4..a4bfada16a 100644 --- a/ultralytics/models/fastsam/model.py +++ b/ultralytics/models/fastsam/model.py @@ -23,7 +23,7 @@ class FastSAM(Model): """Call the __init__ method of the parent class (YOLO) with the updated default model""" if model == 'FastSAM.pt': model = 'FastSAM-x.pt' - assert Path(model).suffix != '.yaml', 'FastSAM models only support pre-trained models.' + assert Path(model).suffix not in ('.yaml', '.yml'), 'FastSAM models only support pre-trained models.' super().__init__(model=model, task='segment') @property diff --git a/ultralytics/models/nas/model.py b/ultralytics/models/nas/model.py index 518a7c81f8..1f7cd351fe 100644 --- a/ultralytics/models/nas/model.py +++ b/ultralytics/models/nas/model.py @@ -23,7 +23,7 @@ from .val import NASValidator class NAS(Model): def __init__(self, model='yolo_nas_s.pt') -> None: - assert Path(model).suffix != '.yaml', 'YOLO-NAS models only support pre-trained models.' + assert Path(model).suffix not in ('.yaml', '.yml'), 'YOLO-NAS models only support pre-trained models.' super().__init__(model, task='detect') @smart_inference_mode() diff --git a/ultralytics/models/rtdetr/model.py b/ultralytics/models/rtdetr/model.py index 5612a04021..aa99f9da67 100644 --- a/ultralytics/models/rtdetr/model.py +++ b/ultralytics/models/rtdetr/model.py @@ -16,8 +16,8 @@ class RTDETR(Model): """ def __init__(self, model='rtdetr-l.pt') -> None: - if model and not model.endswith('.pt') and not model.endswith('.yaml'): - raise NotImplementedError('RT-DETR only supports creating from pt file or yaml file.') + if model and not model.split('.')[-1] in ('pt', 'yaml', 'yml'): + raise NotImplementedError('RT-DETR only supports creating from *.pt file or *.yaml file.') super().__init__(model=model, task='detect') @property diff --git a/ultralytics/models/yolo/classify/train.py b/ultralytics/models/yolo/classify/train.py index 0494708a67..eda92ad9d1 100644 --- a/ultralytics/models/yolo/classify/train.py +++ b/ultralytics/models/yolo/classify/train.py @@ -57,7 +57,7 @@ class ClassificationTrainer(BaseTrainer): self.model, _ = attempt_load_one_weight(model, device='cpu') for p in self.model.parameters(): p.requires_grad = True # for training - elif model.endswith('.yaml'): + elif model.split('.')[-1] in ('yaml', 'yml'): self.model = self.get_model(cfg=model) elif model in torchvision.models.__dict__: self.model = torchvision.models.__dict__[model](weights='IMAGENET1K_V1' if self.args.pretrained else None) diff --git a/ultralytics/utils/benchmarks.py b/ultralytics/utils/benchmarks.py index 7a67e4f0c3..7dfadce574 100644 --- a/ultralytics/utils/benchmarks.py +++ b/ultralytics/utils/benchmarks.py @@ -192,7 +192,7 @@ class ProfileModels: output = [] for file in files: engine_file = file.with_suffix('.engine') - if file.suffix in ('.pt', '.yaml'): + if file.suffix in ('.pt', '.yaml', '.yml'): model = YOLO(str(file)) model.fuse() # to report correct params and GFLOPs in model.info() model_info = model.info() @@ -229,7 +229,7 @@ class ProfileModels: if path.is_dir(): extensions = ['*.pt', '*.onnx', '*.yaml'] files.extend([file for ext in extensions for file in glob.glob(str(path / ext))]) - elif path.suffix in {'.pt', '.yaml'}: # add non-existing + elif path.suffix in ('.pt', '.yaml', '.yml'): # add non-existing files.append(str(path)) else: files.extend(glob.glob(str(path))) From c3c27b019a9516a9b2c78c291b61ef7cf97ff7f3 Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Tue, 1 Aug 2023 20:26:10 +0200 Subject: [PATCH 3/3] `ultralytics 8.0.146` fix SettingsManager un-needed write ops (#4101) Co-authored-by: snyk-bot --- ultralytics/__init__.py | 2 +- ultralytics/cfg/__init__.py | 2 +- ultralytics/utils/__init__.py | 29 +++-------------------------- 3 files changed, 5 insertions(+), 28 deletions(-) diff --git a/ultralytics/__init__.py b/ultralytics/__init__.py index b18d89ca81..3d46395c86 100644 --- a/ultralytics/__init__.py +++ b/ultralytics/__init__.py @@ -1,6 +1,6 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license -__version__ = '8.0.145' +__version__ = '8.0.146' from ultralytics.hub import start from ultralytics.models import RTDETR, SAM, YOLO diff --git a/ultralytics/cfg/__init__.py b/ultralytics/cfg/__init__.py index 05797e7ce3..87b9195bdd 100644 --- a/ultralytics/cfg/__init__.py +++ b/ultralytics/cfg/__init__.py @@ -253,7 +253,7 @@ def handle_yolo_settings(args: List[str]) -> None: SETTINGS_YAML.unlink() # delete the settings file SETTINGS.reset() # create new settings LOGGER.info('Settings reset successfully') # inform the user that settings have been reset - else: + else: # save a new setting new = dict(parse_key_value_pair(a) for a in args) check_dict_alignment(SETTINGS, new) SETTINGS.update(new) diff --git a/ultralytics/utils/__init__.py b/ultralytics/utils/__init__.py index aae007cb96..a7ada261b9 100644 --- a/ultralytics/utils/__init__.py +++ b/ultralytics/utils/__init__.py @@ -714,24 +714,6 @@ def set_sentry(): logging.getLogger(logger).setLevel(logging.CRITICAL) -def update_dict_recursive(d, u): - """ - Recursively updates the dictionary `d` with the key-value pairs from the dictionary `u` without overwriting - entire sub-dictionaries. Note that function recursion is intended and not a problem, as this allows for updating - nested dictionaries at any arbitrary depth. - - Args: - d (dict): The dictionary to be updated. - u (dict): The dictionary to update `d` with. - - Returns: - (dict): The recursively updated dictionary. - """ - for k, v in u.items(): - d[k] = update_dict_recursive(d.get(k, {}), v) if isinstance(v, dict) else v - return d - - class SettingsManager(dict): """ Manages Ultralytics settings stored in a YAML file. @@ -792,20 +774,15 @@ class SettingsManager(dict): def load(self): """Loads settings from the YAML file.""" - self.update(yaml_load(self.file)) + super().update(yaml_load(self.file)) def save(self): """Saves the current settings to the YAML file.""" yaml_save(self.file, dict(self)) def update(self, *args, **kwargs): - """Updates a setting value in the current settings and saves the settings.""" - new = dict(*args, **kwargs) - if any(isinstance(v, dict) for v in new.values()): - update_dict_recursive(self, new) - else: - # super().update(*args, **kwargs) - super().update(new) + """Updates a setting value in the current settings.""" + super().update(*args, **kwargs) self.save() def reset(self):