From 6eec39162a9f4153d1ce5f71102fdee3d64188ec Mon Sep 17 00:00:00 2001 From: Glenn Jocher Date: Thu, 19 Jan 2023 16:16:17 +0100 Subject: [PATCH] `ultralytics 8.0.11` bug fixes and performance improvements (#495) Co-authored-by: Laughing <61612323+Laughing-q@users.noreply.github.com> Co-authored-by: Ayush Chaurasia Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- docs/predict.md | 2 +- ultralytics/__init__.py | 2 +- ultralytics/yolo/data/dataloaders/v5loader.py | 2 +- ultralytics/yolo/data/dataset.py | 2 +- ultralytics/yolo/engine/results.py | 44 +++++++++++++++++++ ultralytics/yolo/utils/__init__.py | 2 +- ultralytics/yolo/v8/detect/train.py | 2 +- ultralytics/yolo/v8/segment/train.py | 2 +- 8 files changed, 51 insertions(+), 7 deletions(-) diff --git a/docs/predict.md b/docs/predict.md index ba47f76..0f85b95 100644 --- a/docs/predict.md +++ b/docs/predict.md @@ -14,7 +14,7 @@ Inference or prediction of a task returns a list of `Results` objects. Alternati === "Getting a Generator" ```python inputs = [img, img] # list of np arrays - results = model(inputs, stream="True") # Generator of Results objects + results = model(inputs, stream=True) # Generator of Results objects for result in results: boxes = results.boxes # Boxes object for bbox outputs masks = results.masks # Masks object for segmenation masks outputs diff --git a/ultralytics/__init__.py b/ultralytics/__init__.py index 911a7f6..0af7366 100644 --- a/ultralytics/__init__.py +++ b/ultralytics/__init__.py @@ -1,6 +1,6 @@ # Ultralytics YOLO 🚀, GPL-3.0 license -__version__ = "8.0.9" +__version__ = "8.0.11" from ultralytics.yolo.engine.model import YOLO from ultralytics.yolo.utils import ops diff --git a/ultralytics/yolo/data/dataloaders/v5loader.py b/ultralytics/yolo/data/dataloaders/v5loader.py index 54aa5e4..0f050aa 100644 --- a/ultralytics/yolo/data/dataloaders/v5loader.py +++ b/ultralytics/yolo/data/dataloaders/v5loader.py @@ -493,7 +493,7 @@ class LoadImagesAndLabels(Dataset): cache, exists = np.load(cache_path, allow_pickle=True).item(), True # load dict assert cache['version'] == self.cache_version # matches current version assert cache['hash'] == get_hash(self.label_files + self.im_files) # identical hash - except Exception: + except (FileNotFoundError, AssertionError): cache, exists = self.cache_labels(cache_path, prefix), False # run cache ops # Display cache diff --git a/ultralytics/yolo/data/dataset.py b/ultralytics/yolo/data/dataset.py index 218a385..c1b2ab6 100644 --- a/ultralytics/yolo/data/dataset.py +++ b/ultralytics/yolo/data/dataset.py @@ -105,7 +105,7 @@ class YOLODataset(BaseDataset): cache, exists = np.load(str(cache_path), allow_pickle=True).item(), True # load dict assert cache["version"] == self.cache_version # matches current version assert cache["hash"] == get_hash(self.label_files + self.im_files) # identical hash - except Exception: + except (FileNotFoundError, AssertionError): cache, exists = self.cache_labels(cache_path), False # run cache ops # Display cache diff --git a/ultralytics/yolo/engine/results.py b/ultralytics/yolo/engine/results.py index 38579f6..910abb1 100644 --- a/ultralytics/yolo/engine/results.py +++ b/ultralytics/yolo/engine/results.py @@ -95,6 +95,18 @@ class Results: return s + def __getattr__(self, attr): + name = self.__class__.__name__ + raise AttributeError(f""" + '{name}' object has no attribute '{attr}'. Valid '{name}' object attributes and properties are: + + Attributes: + boxes (Boxes, optional): A Boxes object containing the detection bounding boxes. + masks (Masks, optional): A Masks object containing the detection masks. + probs (torch.Tensor, optional): A tensor containing the detection class probabilities. + orig_shape (tuple, optional): Original image size. + """) + class Boxes: """ @@ -200,6 +212,25 @@ class Boxes: boxes = self.boxes[idx] return Boxes(boxes, self.orig_shape) + def __getattr__(self, attr): + name = self.__class__.__name__ + raise AttributeError(f""" + '{name}' object has no attribute '{attr}'. Valid '{name}' object attributes and properties are: + + Attributes: + boxes (torch.Tensor) or (numpy.ndarray): A tensor or numpy array containing the detection boxes, + with shape (num_boxes, 6). + orig_shape (torch.Tensor) or (numpy.ndarray): Original image size, in the format (height, width). + + Properties: + xyxy (torch.Tensor) or (numpy.ndarray): The boxes in xyxy format. + conf (torch.Tensor) or (numpy.ndarray): The confidence values of the boxes. + cls (torch.Tensor) or (numpy.ndarray): The class values of the boxes. + xywh (torch.Tensor) or (numpy.ndarray): The boxes in xywh format. + xyxyn (torch.Tensor) or (numpy.ndarray): The boxes in xyxy format normalized by original image size. + xywhn (torch.Tensor) or (numpy.ndarray): The boxes in xywh format normalized by original image size. + """) + class Masks: """ @@ -262,6 +293,19 @@ class Masks: masks = self.masks[idx] return Masks(masks, self.im_shape, self.orig_shape) + def __getattr__(self, attr): + name = self.__class__.__name__ + raise AttributeError(f""" + '{name}' object has no attribute '{attr}'. Valid '{name}' object attributes and properties are: + + Attributes: + masks (torch.Tensor): A tensor containing the detection masks, with shape (num_masks, height, width). + orig_shape (tuple): Original image size, in the format (height, width). + + Properties: + segments (list): A list of segments which includes x,y,w,h,label,confidence, and mask of each detection masks. + """) + if __name__ == "__main__": # test examples diff --git a/ultralytics/yolo/utils/__init__.py b/ultralytics/yolo/utils/__init__.py index 62e1b53..783c7a5 100644 --- a/ultralytics/yolo/utils/__init__.py +++ b/ultralytics/yolo/utils/__init__.py @@ -379,7 +379,7 @@ def set_sentry(dsn=None): release=ultralytics.__version__, send_default_pii=True, environment='production', # 'dev' or 'production' - ignore_errors=[KeyboardInterrupt, torch.cuda.OutOfMemoryError]) + ignore_errors=[KeyboardInterrupt]) def get_settings(file=USER_CONFIG_DIR / 'settings.yaml', version='0.0.1'): diff --git a/ultralytics/yolo/v8/detect/train.py b/ultralytics/yolo/v8/detect/train.py index ea817a9..e9449df 100644 --- a/ultralytics/yolo/v8/detect/train.py +++ b/ultralytics/yolo/v8/detect/train.py @@ -177,7 +177,7 @@ class Loss: anchor_points * stride_tensor, gt_labels, gt_bboxes, mask_gt) target_bboxes /= stride_tensor - target_scores_sum = target_scores.sum() + target_scores_sum = max(target_scores.sum(), 1) # cls loss # loss[1] = self.varifocal_loss(pred_scores, target_scores, target_labels) / target_scores_sum # VFL way diff --git a/ultralytics/yolo/v8/segment/train.py b/ultralytics/yolo/v8/segment/train.py index 845f3dc..ff97e1c 100644 --- a/ultralytics/yolo/v8/segment/train.py +++ b/ultralytics/yolo/v8/segment/train.py @@ -99,7 +99,7 @@ class SegLoss(Loss): pred_scores.detach().sigmoid(), (pred_bboxes.detach() * stride_tensor).type(gt_bboxes.dtype), anchor_points * stride_tensor, gt_labels, gt_bboxes, mask_gt) - target_scores_sum = target_scores.sum() + target_scores_sum = max(target_scores.sum(), 1) # cls loss # loss[1] = self.varifocal_loss(pred_scores, target_scores, target_labels) / target_scores_sum # VFL way