ultralytics 8.0.237__py3-none-any.whl → 8.0.239__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ultralytics might be problematic. Click here for more details.

Files changed (137) hide show
  1. ultralytics/__init__.py +2 -2
  2. ultralytics/cfg/__init__.py +241 -138
  3. ultralytics/cfg/datasets/DOTAv1.5.yaml +1 -1
  4. ultralytics/cfg/datasets/DOTAv1.yaml +1 -1
  5. ultralytics/cfg/datasets/dota8.yaml +34 -0
  6. ultralytics/data/__init__.py +9 -2
  7. ultralytics/data/annotator.py +4 -4
  8. ultralytics/data/augment.py +186 -169
  9. ultralytics/data/base.py +54 -48
  10. ultralytics/data/build.py +34 -23
  11. ultralytics/data/converter.py +242 -70
  12. ultralytics/data/dataset.py +117 -95
  13. ultralytics/data/explorer/__init__.py +5 -0
  14. ultralytics/data/explorer/explorer.py +170 -97
  15. ultralytics/data/explorer/gui/__init__.py +1 -0
  16. ultralytics/data/explorer/gui/dash.py +146 -76
  17. ultralytics/data/explorer/utils.py +87 -25
  18. ultralytics/data/loaders.py +75 -62
  19. ultralytics/data/split_dota.py +44 -36
  20. ultralytics/data/utils.py +160 -142
  21. ultralytics/engine/exporter.py +348 -292
  22. ultralytics/engine/model.py +102 -66
  23. ultralytics/engine/predictor.py +74 -55
  24. ultralytics/engine/results.py +63 -40
  25. ultralytics/engine/trainer.py +192 -144
  26. ultralytics/engine/tuner.py +66 -59
  27. ultralytics/engine/validator.py +31 -26
  28. ultralytics/hub/__init__.py +54 -31
  29. ultralytics/hub/auth.py +28 -25
  30. ultralytics/hub/session.py +282 -133
  31. ultralytics/hub/utils.py +64 -42
  32. ultralytics/models/__init__.py +1 -1
  33. ultralytics/models/fastsam/__init__.py +1 -1
  34. ultralytics/models/fastsam/model.py +6 -6
  35. ultralytics/models/fastsam/predict.py +3 -2
  36. ultralytics/models/fastsam/prompt.py +55 -48
  37. ultralytics/models/fastsam/val.py +1 -1
  38. ultralytics/models/nas/__init__.py +1 -1
  39. ultralytics/models/nas/model.py +9 -8
  40. ultralytics/models/nas/predict.py +8 -6
  41. ultralytics/models/nas/val.py +11 -9
  42. ultralytics/models/rtdetr/__init__.py +1 -1
  43. ultralytics/models/rtdetr/model.py +11 -9
  44. ultralytics/models/rtdetr/train.py +18 -16
  45. ultralytics/models/rtdetr/val.py +25 -19
  46. ultralytics/models/sam/__init__.py +1 -1
  47. ultralytics/models/sam/amg.py +13 -14
  48. ultralytics/models/sam/build.py +44 -42
  49. ultralytics/models/sam/model.py +6 -6
  50. ultralytics/models/sam/modules/decoders.py +6 -4
  51. ultralytics/models/sam/modules/encoders.py +37 -35
  52. ultralytics/models/sam/modules/sam.py +5 -4
  53. ultralytics/models/sam/modules/tiny_encoder.py +95 -73
  54. ultralytics/models/sam/modules/transformer.py +3 -2
  55. ultralytics/models/sam/predict.py +39 -27
  56. ultralytics/models/utils/loss.py +99 -95
  57. ultralytics/models/utils/ops.py +34 -31
  58. ultralytics/models/yolo/__init__.py +1 -1
  59. ultralytics/models/yolo/classify/__init__.py +1 -1
  60. ultralytics/models/yolo/classify/predict.py +8 -6
  61. ultralytics/models/yolo/classify/train.py +37 -31
  62. ultralytics/models/yolo/classify/val.py +26 -24
  63. ultralytics/models/yolo/detect/__init__.py +1 -1
  64. ultralytics/models/yolo/detect/predict.py +8 -6
  65. ultralytics/models/yolo/detect/train.py +47 -37
  66. ultralytics/models/yolo/detect/val.py +100 -82
  67. ultralytics/models/yolo/model.py +31 -25
  68. ultralytics/models/yolo/obb/__init__.py +1 -1
  69. ultralytics/models/yolo/obb/predict.py +13 -12
  70. ultralytics/models/yolo/obb/train.py +3 -3
  71. ultralytics/models/yolo/obb/val.py +80 -58
  72. ultralytics/models/yolo/pose/__init__.py +1 -1
  73. ultralytics/models/yolo/pose/predict.py +17 -12
  74. ultralytics/models/yolo/pose/train.py +28 -25
  75. ultralytics/models/yolo/pose/val.py +91 -64
  76. ultralytics/models/yolo/segment/__init__.py +1 -1
  77. ultralytics/models/yolo/segment/predict.py +10 -8
  78. ultralytics/models/yolo/segment/train.py +16 -15
  79. ultralytics/models/yolo/segment/val.py +90 -68
  80. ultralytics/nn/__init__.py +26 -6
  81. ultralytics/nn/autobackend.py +144 -112
  82. ultralytics/nn/modules/__init__.py +96 -13
  83. ultralytics/nn/modules/block.py +28 -7
  84. ultralytics/nn/modules/conv.py +41 -23
  85. ultralytics/nn/modules/head.py +67 -59
  86. ultralytics/nn/modules/transformer.py +49 -32
  87. ultralytics/nn/modules/utils.py +20 -15
  88. ultralytics/nn/tasks.py +215 -141
  89. ultralytics/solutions/ai_gym.py +59 -47
  90. ultralytics/solutions/distance_calculation.py +22 -15
  91. ultralytics/solutions/heatmap.py +76 -54
  92. ultralytics/solutions/object_counter.py +46 -39
  93. ultralytics/solutions/speed_estimation.py +13 -16
  94. ultralytics/trackers/__init__.py +1 -1
  95. ultralytics/trackers/basetrack.py +1 -0
  96. ultralytics/trackers/bot_sort.py +2 -1
  97. ultralytics/trackers/byte_tracker.py +10 -7
  98. ultralytics/trackers/track.py +7 -7
  99. ultralytics/trackers/utils/gmc.py +25 -25
  100. ultralytics/trackers/utils/kalman_filter.py +85 -42
  101. ultralytics/trackers/utils/matching.py +8 -7
  102. ultralytics/utils/__init__.py +173 -151
  103. ultralytics/utils/autobatch.py +10 -10
  104. ultralytics/utils/benchmarks.py +76 -86
  105. ultralytics/utils/callbacks/__init__.py +1 -1
  106. ultralytics/utils/callbacks/base.py +29 -29
  107. ultralytics/utils/callbacks/clearml.py +51 -43
  108. ultralytics/utils/callbacks/comet.py +81 -66
  109. ultralytics/utils/callbacks/dvc.py +33 -26
  110. ultralytics/utils/callbacks/hub.py +44 -26
  111. ultralytics/utils/callbacks/mlflow.py +31 -24
  112. ultralytics/utils/callbacks/neptune.py +35 -25
  113. ultralytics/utils/callbacks/raytune.py +9 -4
  114. ultralytics/utils/callbacks/tensorboard.py +16 -11
  115. ultralytics/utils/callbacks/wb.py +39 -33
  116. ultralytics/utils/checks.py +189 -141
  117. ultralytics/utils/dist.py +15 -12
  118. ultralytics/utils/downloads.py +112 -96
  119. ultralytics/utils/errors.py +1 -1
  120. ultralytics/utils/files.py +11 -11
  121. ultralytics/utils/instance.py +22 -22
  122. ultralytics/utils/loss.py +117 -67
  123. ultralytics/utils/metrics.py +224 -158
  124. ultralytics/utils/ops.py +39 -29
  125. ultralytics/utils/patches.py +3 -3
  126. ultralytics/utils/plotting.py +217 -120
  127. ultralytics/utils/tal.py +19 -13
  128. ultralytics/utils/torch_utils.py +138 -109
  129. ultralytics/utils/triton.py +12 -10
  130. ultralytics/utils/tuner.py +49 -47
  131. {ultralytics-8.0.237.dist-info → ultralytics-8.0.239.dist-info}/METADATA +5 -4
  132. ultralytics-8.0.239.dist-info/RECORD +188 -0
  133. ultralytics-8.0.237.dist-info/RECORD +0 -187
  134. {ultralytics-8.0.237.dist-info → ultralytics-8.0.239.dist-info}/LICENSE +0 -0
  135. {ultralytics-8.0.237.dist-info → ultralytics-8.0.239.dist-info}/WHEEL +0 -0
  136. {ultralytics-8.0.237.dist-info → ultralytics-8.0.239.dist-info}/entry_points.txt +0 -0
  137. {ultralytics-8.0.237.dist-info → ultralytics-8.0.239.dist-info}/top_level.txt +0 -0
ultralytics/utils/ops.py CHANGED
@@ -52,7 +52,7 @@ class Profile(contextlib.ContextDecorator):
52
52
 
53
53
  def __str__(self):
54
54
  """Returns a human-readable string representing the accumulated elapsed time in the profiler."""
55
- return f'Elapsed time is {self.t} s'
55
+ return f"Elapsed time is {self.t} s"
56
56
 
57
57
  def time(self):
58
58
  """Get current time."""
@@ -76,9 +76,13 @@ def segment2box(segment, width=640, height=640):
76
76
  # Convert 1 segment label to 1 box label, applying inside-image constraint, i.e. (xy1, xy2, ...) to (xyxy)
77
77
  x, y = segment.T # segment xy
78
78
  inside = (x >= 0) & (y >= 0) & (x <= width) & (y <= height)
79
- x, y, = x[inside], y[inside]
80
- return np.array([x.min(), y.min(), x.max(), y.max()], dtype=segment.dtype) if any(x) else np.zeros(
81
- 4, dtype=segment.dtype) # xyxy
79
+ x = x[inside]
80
+ y = y[inside]
81
+ return (
82
+ np.array([x.min(), y.min(), x.max(), y.max()], dtype=segment.dtype)
83
+ if any(x)
84
+ else np.zeros(4, dtype=segment.dtype)
85
+ ) # xyxy
82
86
 
83
87
 
84
88
  def scale_boxes(img1_shape, boxes, img0_shape, ratio_pad=None, padding=True, xywh=False):
@@ -101,8 +105,10 @@ def scale_boxes(img1_shape, boxes, img0_shape, ratio_pad=None, padding=True, xyw
101
105
  """
102
106
  if ratio_pad is None: # calculate from img0_shape
103
107
  gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new
104
- pad = round((img1_shape[1] - img0_shape[1] * gain) / 2 - 0.1), round(
105
- (img1_shape[0] - img0_shape[0] * gain) / 2 - 0.1) # wh padding
108
+ pad = (
109
+ round((img1_shape[1] - img0_shape[1] * gain) / 2 - 0.1),
110
+ round((img1_shape[0] - img0_shape[0] * gain) / 2 - 0.1),
111
+ ) # wh padding
106
112
  else:
107
113
  gain = ratio_pad[0][0]
108
114
  pad = ratio_pad[1]
@@ -145,7 +151,7 @@ def nms_rotated(boxes, scores, threshold=0.45):
145
151
  Returns:
146
152
  """
147
153
  if len(boxes) == 0:
148
- return np.empty((0, ), dtype=np.int8)
154
+ return np.empty((0,), dtype=np.int8)
149
155
  sorted_idx = torch.argsort(scores, descending=True)
150
156
  boxes = boxes[sorted_idx]
151
157
  ious = batch_probiou(boxes, boxes).triu_(diagonal=1)
@@ -199,8 +205,8 @@ def non_max_suppression(
199
205
  """
200
206
 
201
207
  # Checks
202
- assert 0 <= conf_thres <= 1, f'Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0'
203
- assert 0 <= iou_thres <= 1, f'Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0'
208
+ assert 0 <= conf_thres <= 1, f"Invalid Confidence threshold {conf_thres}, valid values are between 0.0 and 1.0"
209
+ assert 0 <= iou_thres <= 1, f"Invalid IoU {iou_thres}, valid values are between 0.0 and 1.0"
204
210
  if isinstance(prediction, (list, tuple)): # YOLOv8 model in validation model, output = (inference_out, loss_out)
205
211
  prediction = prediction[0] # select only inference output
206
212
 
@@ -263,7 +269,7 @@ def non_max_suppression(
263
269
  c = x[:, 5:6] * (0 if agnostic else max_wh) # classes
264
270
  scores = x[:, 4] # scores
265
271
  if rotated:
266
- boxes = torch.cat((x[:, :2] + c, x[:, 2:4], x[:, -2:-1]), dim=-1) # xywhr
272
+ boxes = torch.cat((x[:, :2] + c, x[:, 2:4], x[:, -1:]), dim=-1) # xywhr
267
273
  i = nms_rotated(boxes, scores, iou_thres)
268
274
  else:
269
275
  boxes = x[:, :4] + c # boxes (offset by class)
@@ -284,7 +290,7 @@ def non_max_suppression(
284
290
 
285
291
  output[xi] = x[i]
286
292
  if (time.time() - t) > time_limit:
287
- LOGGER.warning(f'WARNING ⚠️ NMS time limit {time_limit:.3f}s exceeded')
293
+ LOGGER.warning(f"WARNING ⚠️ NMS time limit {time_limit:.3f}s exceeded")
288
294
  break # time limit exceeded
289
295
 
290
296
  return output
@@ -378,7 +384,7 @@ def xyxy2xywh(x):
378
384
  Returns:
379
385
  y (np.ndarray | torch.Tensor): The bounding box coordinates in (x, y, width, height) format.
380
386
  """
381
- assert x.shape[-1] == 4, f'input shape last dimension expected 4 but input shape is {x.shape}'
387
+ assert x.shape[-1] == 4, f"input shape last dimension expected 4 but input shape is {x.shape}"
382
388
  y = torch.empty_like(x) if isinstance(x, torch.Tensor) else np.empty_like(x) # faster than clone/copy
383
389
  y[..., 0] = (x[..., 0] + x[..., 2]) / 2 # x center
384
390
  y[..., 1] = (x[..., 1] + x[..., 3]) / 2 # y center
@@ -398,7 +404,7 @@ def xywh2xyxy(x):
398
404
  Returns:
399
405
  y (np.ndarray | torch.Tensor): The bounding box coordinates in (x1, y1, x2, y2) format.
400
406
  """
401
- assert x.shape[-1] == 4, f'input shape last dimension expected 4 but input shape is {x.shape}'
407
+ assert x.shape[-1] == 4, f"input shape last dimension expected 4 but input shape is {x.shape}"
402
408
  y = torch.empty_like(x) if isinstance(x, torch.Tensor) else np.empty_like(x) # faster than clone/copy
403
409
  dw = x[..., 2] / 2 # half-width
404
410
  dh = x[..., 3] / 2 # half-height
@@ -423,7 +429,7 @@ def xywhn2xyxy(x, w=640, h=640, padw=0, padh=0):
423
429
  y (np.ndarray | torch.Tensor): The coordinates of the bounding box in the format [x1, y1, x2, y2] where
424
430
  x1,y1 is the top-left corner, x2,y2 is the bottom-right corner of the bounding box.
425
431
  """
426
- assert x.shape[-1] == 4, f'input shape last dimension expected 4 but input shape is {x.shape}'
432
+ assert x.shape[-1] == 4, f"input shape last dimension expected 4 but input shape is {x.shape}"
427
433
  y = torch.empty_like(x) if isinstance(x, torch.Tensor) else np.empty_like(x) # faster than clone/copy
428
434
  y[..., 0] = w * (x[..., 0] - x[..., 2] / 2) + padw # top left x
429
435
  y[..., 1] = h * (x[..., 1] - x[..., 3] / 2) + padh # top left y
@@ -449,7 +455,7 @@ def xyxy2xywhn(x, w=640, h=640, clip=False, eps=0.0):
449
455
  """
450
456
  if clip:
451
457
  x = clip_boxes(x, (h - eps, w - eps))
452
- assert x.shape[-1] == 4, f'input shape last dimension expected 4 but input shape is {x.shape}'
458
+ assert x.shape[-1] == 4, f"input shape last dimension expected 4 but input shape is {x.shape}"
453
459
  y = torch.empty_like(x) if isinstance(x, torch.Tensor) else np.empty_like(x) # faster than clone/copy
454
460
  y[..., 0] = ((x[..., 0] + x[..., 2]) / 2) / w # x center
455
461
  y[..., 1] = ((x[..., 1] + x[..., 3]) / 2) / h # y center
@@ -526,8 +532,11 @@ def xyxyxyxy2xywhr(corners):
526
532
  # especially some objects are cut off by augmentations in dataloader.
527
533
  (x, y), (w, h), angle = cv2.minAreaRect(pts)
528
534
  rboxes.append([x, y, w, h, angle / 180 * np.pi])
529
- rboxes = torch.tensor(rboxes, device=corners.device, dtype=corners.dtype) if is_torch else np.asarray(
530
- rboxes, dtype=points.dtype)
535
+ rboxes = (
536
+ torch.tensor(rboxes, device=corners.device, dtype=corners.dtype)
537
+ if is_torch
538
+ else np.asarray(rboxes, dtype=points.dtype)
539
+ )
531
540
  return rboxes
532
541
 
533
542
 
@@ -546,7 +555,7 @@ def xywhr2xyxyxyxy(center):
546
555
  cos, sin = (np.cos, np.sin) if is_numpy else (torch.cos, torch.sin)
547
556
 
548
557
  ctr = center[..., :2]
549
- w, h, angle = (center[..., i:i + 1] for i in range(2, 5))
558
+ w, h, angle = (center[..., i : i + 1] for i in range(2, 5))
550
559
  cos_value, sin_value = cos(angle), sin(angle)
551
560
  vec1 = [w / 2 * cos_value, w / 2 * sin_value]
552
561
  vec2 = [-h / 2 * sin_value, h / 2 * cos_value]
@@ -607,8 +616,9 @@ def resample_segments(segments, n=1000):
607
616
  s = np.concatenate((s, s[0:1, :]), axis=0)
608
617
  x = np.linspace(0, len(s) - 1, n)
609
618
  xp = np.arange(len(s))
610
- segments[i] = np.concatenate([np.interp(x, xp, s[:, i]) for i in range(2)],
611
- dtype=np.float32).reshape(2, -1).T # segment xy
619
+ segments[i] = (
620
+ np.concatenate([np.interp(x, xp, s[:, i]) for i in range(2)], dtype=np.float32).reshape(2, -1).T
621
+ ) # segment xy
612
622
  return segments
613
623
 
614
624
 
@@ -647,7 +657,7 @@ def process_mask_upsample(protos, masks_in, bboxes, shape):
647
657
  """
648
658
  c, mh, mw = protos.shape # CHW
649
659
  masks = (masks_in @ protos.float().view(c, -1)).sigmoid().view(-1, mh, mw)
650
- masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW
660
+ masks = F.interpolate(masks[None], shape, mode="bilinear", align_corners=False)[0] # CHW
651
661
  masks = crop_mask(masks, bboxes) # CHW
652
662
  return masks.gt_(0.5)
653
663
 
@@ -680,7 +690,7 @@ def process_mask(protos, masks_in, bboxes, shape, upsample=False):
680
690
 
681
691
  masks = crop_mask(masks, downsampled_bboxes) # CHW
682
692
  if upsample:
683
- masks = F.interpolate(masks[None], shape, mode='bilinear', align_corners=False)[0] # CHW
693
+ masks = F.interpolate(masks[None], shape, mode="bilinear", align_corners=False)[0] # CHW
684
694
  return masks.gt_(0.5)
685
695
 
686
696
 
@@ -724,7 +734,7 @@ def scale_masks(masks, shape, padding=True):
724
734
  bottom, right = (int(round(mh - pad[1] + 0.1)), int(round(mw - pad[0] + 0.1)))
725
735
  masks = masks[..., top:bottom, left:right]
726
736
 
727
- masks = F.interpolate(masks, shape, mode='bilinear', align_corners=False) # NCHW
737
+ masks = F.interpolate(masks, shape, mode="bilinear", align_corners=False) # NCHW
728
738
  return masks
729
739
 
730
740
 
@@ -763,7 +773,7 @@ def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None, normalize=False
763
773
  return coords
764
774
 
765
775
 
766
- def masks2segments(masks, strategy='largest'):
776
+ def masks2segments(masks, strategy="largest"):
767
777
  """
768
778
  It takes a list of masks(n,h,w) and returns a list of segments(n,xy)
769
779
 
@@ -775,16 +785,16 @@ def masks2segments(masks, strategy='largest'):
775
785
  segments (List): list of segment masks
776
786
  """
777
787
  segments = []
778
- for x in masks.int().cpu().numpy().astype('uint8'):
788
+ for x in masks.int().cpu().numpy().astype("uint8"):
779
789
  c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
780
790
  if c:
781
- if strategy == 'concat': # concatenate all segments
791
+ if strategy == "concat": # concatenate all segments
782
792
  c = np.concatenate([x.reshape(-1, 2) for x in c])
783
- elif strategy == 'largest': # select largest segment
793
+ elif strategy == "largest": # select largest segment
784
794
  c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2)
785
795
  else:
786
796
  c = np.zeros((0, 2)) # no segments found
787
- segments.append(c.astype('float32'))
797
+ segments.append(c.astype("float32"))
788
798
  return segments
789
799
 
790
800
 
@@ -811,4 +821,4 @@ def clean_str(s):
811
821
  Returns:
812
822
  (str): a string with special characters replaced by an underscore _
813
823
  """
814
- return re.sub(pattern='[|@#!¡·$€%&()=?¿^*;:,¨´><+]', repl='_', string=s)
824
+ return re.sub(pattern="[|@#!¡·$€%&()=?¿^*;:,¨´><+]", repl="_", string=s)
@@ -52,7 +52,7 @@ def imshow(winname: str, mat: np.ndarray):
52
52
  winname (str): Name of the window.
53
53
  mat (np.ndarray): Image to be shown.
54
54
  """
55
- _imshow(winname.encode('unicode_escape').decode(), mat)
55
+ _imshow(winname.encode("unicode_escape").decode(), mat)
56
56
 
57
57
 
58
58
  # PyTorch functions ----------------------------------------------------------------------------------------------------
@@ -72,6 +72,6 @@ def torch_save(*args, **kwargs):
72
72
  except ImportError:
73
73
  import pickle
74
74
 
75
- if 'pickle_module' not in kwargs:
76
- kwargs['pickle_module'] = pickle # noqa
75
+ if "pickle_module" not in kwargs:
76
+ kwargs["pickle_module"] = pickle # noqa
77
77
  return _torch_save(*args, **kwargs)