ultralytics 8.3.190__py3-none-any.whl → 8.3.191__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.
Files changed (102) hide show
  1. tests/test_cuda.py +6 -5
  2. tests/test_exports.py +1 -6
  3. tests/test_python.py +1 -4
  4. tests/test_solutions.py +1 -1
  5. ultralytics/__init__.py +1 -1
  6. ultralytics/cfg/__init__.py +16 -14
  7. ultralytics/cfg/datasets/VisDrone.yaml +4 -4
  8. ultralytics/data/annotator.py +6 -6
  9. ultralytics/data/augment.py +53 -51
  10. ultralytics/data/base.py +15 -13
  11. ultralytics/data/build.py +7 -4
  12. ultralytics/data/converter.py +9 -10
  13. ultralytics/data/dataset.py +24 -22
  14. ultralytics/data/loaders.py +13 -11
  15. ultralytics/data/split.py +4 -3
  16. ultralytics/data/split_dota.py +14 -12
  17. ultralytics/data/utils.py +29 -23
  18. ultralytics/engine/exporter.py +2 -2
  19. ultralytics/engine/model.py +16 -14
  20. ultralytics/engine/predictor.py +8 -6
  21. ultralytics/engine/results.py +54 -52
  22. ultralytics/engine/trainer.py +7 -2
  23. ultralytics/engine/tuner.py +4 -3
  24. ultralytics/hub/google/__init__.py +7 -6
  25. ultralytics/hub/session.py +8 -6
  26. ultralytics/hub/utils.py +3 -4
  27. ultralytics/models/fastsam/model.py +8 -6
  28. ultralytics/models/nas/model.py +5 -3
  29. ultralytics/models/rtdetr/train.py +4 -3
  30. ultralytics/models/rtdetr/val.py +6 -4
  31. ultralytics/models/sam/amg.py +13 -10
  32. ultralytics/models/sam/model.py +3 -2
  33. ultralytics/models/sam/modules/blocks.py +21 -21
  34. ultralytics/models/sam/modules/decoders.py +11 -11
  35. ultralytics/models/sam/modules/encoders.py +25 -25
  36. ultralytics/models/sam/modules/memory_attention.py +9 -8
  37. ultralytics/models/sam/modules/sam.py +8 -10
  38. ultralytics/models/sam/modules/tiny_encoder.py +21 -20
  39. ultralytics/models/sam/modules/transformer.py +6 -5
  40. ultralytics/models/sam/modules/utils.py +7 -5
  41. ultralytics/models/sam/predict.py +32 -31
  42. ultralytics/models/utils/loss.py +29 -27
  43. ultralytics/models/utils/ops.py +10 -8
  44. ultralytics/models/yolo/classify/train.py +7 -5
  45. ultralytics/models/yolo/classify/val.py +10 -8
  46. ultralytics/models/yolo/detect/predict.py +1 -1
  47. ultralytics/models/yolo/detect/train.py +8 -6
  48. ultralytics/models/yolo/detect/val.py +21 -19
  49. ultralytics/models/yolo/model.py +14 -14
  50. ultralytics/models/yolo/obb/train.py +5 -3
  51. ultralytics/models/yolo/obb/val.py +11 -9
  52. ultralytics/models/yolo/pose/train.py +7 -5
  53. ultralytics/models/yolo/pose/val.py +11 -9
  54. ultralytics/models/yolo/segment/train.py +4 -5
  55. ultralytics/models/yolo/segment/val.py +12 -10
  56. ultralytics/models/yolo/world/train.py +9 -7
  57. ultralytics/models/yolo/yoloe/train.py +7 -6
  58. ultralytics/models/yolo/yoloe/val.py +10 -8
  59. ultralytics/nn/autobackend.py +17 -19
  60. ultralytics/nn/modules/block.py +12 -12
  61. ultralytics/nn/modules/conv.py +4 -3
  62. ultralytics/nn/modules/head.py +41 -37
  63. ultralytics/nn/modules/transformer.py +22 -21
  64. ultralytics/nn/tasks.py +2 -2
  65. ultralytics/nn/text_model.py +6 -5
  66. ultralytics/solutions/analytics.py +7 -5
  67. ultralytics/solutions/config.py +12 -10
  68. ultralytics/solutions/distance_calculation.py +3 -3
  69. ultralytics/solutions/heatmap.py +4 -2
  70. ultralytics/solutions/object_counter.py +5 -3
  71. ultralytics/solutions/parking_management.py +4 -2
  72. ultralytics/solutions/region_counter.py +7 -5
  73. ultralytics/solutions/similarity_search.py +5 -3
  74. ultralytics/solutions/solutions.py +38 -36
  75. ultralytics/solutions/streamlit_inference.py +8 -7
  76. ultralytics/trackers/bot_sort.py +11 -9
  77. ultralytics/trackers/byte_tracker.py +17 -15
  78. ultralytics/trackers/utils/gmc.py +4 -3
  79. ultralytics/utils/__init__.py +16 -88
  80. ultralytics/utils/autobatch.py +3 -2
  81. ultralytics/utils/autodevice.py +10 -10
  82. ultralytics/utils/benchmarks.py +11 -10
  83. ultralytics/utils/callbacks/comet.py +9 -9
  84. ultralytics/utils/checks.py +17 -26
  85. ultralytics/utils/export.py +12 -11
  86. ultralytics/utils/files.py +8 -7
  87. ultralytics/utils/git.py +139 -0
  88. ultralytics/utils/instance.py +8 -7
  89. ultralytics/utils/loss.py +15 -13
  90. ultralytics/utils/metrics.py +62 -62
  91. ultralytics/utils/ops.py +3 -2
  92. ultralytics/utils/patches.py +6 -4
  93. ultralytics/utils/plotting.py +18 -16
  94. ultralytics/utils/torch_utils.py +4 -2
  95. ultralytics/utils/tqdm.py +15 -12
  96. ultralytics/utils/triton.py +3 -2
  97. {ultralytics-8.3.190.dist-info → ultralytics-8.3.191.dist-info}/METADATA +1 -1
  98. {ultralytics-8.3.190.dist-info → ultralytics-8.3.191.dist-info}/RECORD +102 -101
  99. {ultralytics-8.3.190.dist-info → ultralytics-8.3.191.dist-info}/WHEEL +0 -0
  100. {ultralytics-8.3.190.dist-info → ultralytics-8.3.191.dist-info}/entry_points.txt +0 -0
  101. {ultralytics-8.3.190.dist-info → ultralytics-8.3.191.dist-info}/licenses/LICENSE +0 -0
  102. {ultralytics-8.3.190.dist-info → ultralytics-8.3.191.dist-info}/top_level.txt +0 -0
@@ -5,10 +5,12 @@ Ultralytics Results, Boxes and Masks classes for handling inference results.
5
5
  Usage: See https://docs.ultralytics.com/modes/predict/
6
6
  """
7
7
 
8
+ from __future__ import annotations
9
+
8
10
  from copy import deepcopy
9
11
  from functools import lru_cache
10
12
  from pathlib import Path
11
- from typing import Any, Dict, List, Optional, Tuple, Union
13
+ from typing import Any
12
14
 
13
15
  import numpy as np
14
16
  import torch
@@ -46,7 +48,7 @@ class BaseTensor(SimpleClass):
46
48
  >>> gpu_tensor = base_tensor.cuda()
47
49
  """
48
50
 
49
- def __init__(self, data: Union[torch.Tensor, np.ndarray], orig_shape: Tuple[int, int]) -> None:
51
+ def __init__(self, data: torch.Tensor | np.ndarray, orig_shape: tuple[int, int]) -> None:
50
52
  """
51
53
  Initialize BaseTensor with prediction data and the original shape of the image.
52
54
 
@@ -65,7 +67,7 @@ class BaseTensor(SimpleClass):
65
67
  self.orig_shape = orig_shape
66
68
 
67
69
  @property
68
- def shape(self) -> Tuple[int, ...]:
70
+ def shape(self) -> tuple[int, ...]:
69
71
  """
70
72
  Return the shape of the underlying data tensor.
71
73
 
@@ -239,13 +241,13 @@ class Results(SimpleClass, DataExportMixin):
239
241
  self,
240
242
  orig_img: np.ndarray,
241
243
  path: str,
242
- names: Dict[int, str],
243
- boxes: Optional[torch.Tensor] = None,
244
- masks: Optional[torch.Tensor] = None,
245
- probs: Optional[torch.Tensor] = None,
246
- keypoints: Optional[torch.Tensor] = None,
247
- obb: Optional[torch.Tensor] = None,
248
- speed: Optional[Dict[str, float]] = None,
244
+ names: dict[int, str],
245
+ boxes: torch.Tensor | None = None,
246
+ masks: torch.Tensor | None = None,
247
+ probs: torch.Tensor | None = None,
248
+ keypoints: torch.Tensor | None = None,
249
+ obb: torch.Tensor | None = None,
250
+ speed: dict[str, float] | None = None,
249
251
  ) -> None:
250
252
  """
251
253
  Initialize the Results class for storing and manipulating inference results.
@@ -324,11 +326,11 @@ class Results(SimpleClass, DataExportMixin):
324
326
 
325
327
  def update(
326
328
  self,
327
- boxes: Optional[torch.Tensor] = None,
328
- masks: Optional[torch.Tensor] = None,
329
- probs: Optional[torch.Tensor] = None,
330
- obb: Optional[torch.Tensor] = None,
331
- keypoints: Optional[torch.Tensor] = None,
329
+ boxes: torch.Tensor | None = None,
330
+ masks: torch.Tensor | None = None,
331
+ probs: torch.Tensor | None = None,
332
+ obb: torch.Tensor | None = None,
333
+ keypoints: torch.Tensor | None = None,
332
334
  ):
333
335
  """
334
336
  Update the Results object with new detection data.
@@ -473,12 +475,12 @@ class Results(SimpleClass, DataExportMixin):
473
475
  def plot(
474
476
  self,
475
477
  conf: bool = True,
476
- line_width: Optional[float] = None,
477
- font_size: Optional[float] = None,
478
+ line_width: float | None = None,
479
+ font_size: float | None = None,
478
480
  font: str = "Arial.ttf",
479
481
  pil: bool = False,
480
- img: Optional[np.ndarray] = None,
481
- im_gpu: Optional[torch.Tensor] = None,
482
+ img: np.ndarray | None = None,
483
+ im_gpu: torch.Tensor | None = None,
482
484
  kpt_radius: int = 5,
483
485
  kpt_line: bool = True,
484
486
  labels: bool = True,
@@ -487,9 +489,9 @@ class Results(SimpleClass, DataExportMixin):
487
489
  probs: bool = True,
488
490
  show: bool = False,
489
491
  save: bool = False,
490
- filename: Optional[str] = None,
492
+ filename: str | None = None,
491
493
  color_mode: str = "class",
492
- txt_color: Tuple[int, int, int] = (255, 255, 255),
494
+ txt_color: tuple[int, int, int] = (255, 255, 255),
493
495
  ) -> np.ndarray:
494
496
  """
495
497
  Plot detection results on an input RGB image.
@@ -629,7 +631,7 @@ class Results(SimpleClass, DataExportMixin):
629
631
  """
630
632
  self.plot(show=True, *args, **kwargs)
631
633
 
632
- def save(self, filename: Optional[str] = None, *args, **kwargs) -> str:
634
+ def save(self, filename: str | None = None, *args, **kwargs) -> str:
633
635
  """
634
636
  Save annotated inference results image to file.
635
637
 
@@ -690,7 +692,7 @@ class Results(SimpleClass, DataExportMixin):
690
692
  counts = boxes.cls.int().bincount()
691
693
  return "".join(f"{n} {self.names[i]}{'s' * (n > 1)}, " for i, n in enumerate(counts) if n > 0)
692
694
 
693
- def save_txt(self, txt_file: Union[str, Path], save_conf: bool = False) -> str:
695
+ def save_txt(self, txt_file: str | Path, save_conf: bool = False) -> str:
694
696
  """
695
697
  Save detection results to a text file.
696
698
 
@@ -747,7 +749,7 @@ class Results(SimpleClass, DataExportMixin):
747
749
 
748
750
  return str(txt_file)
749
751
 
750
- def save_crop(self, save_dir: Union[str, Path], file_name: Union[str, Path] = Path("im.jpg")):
752
+ def save_crop(self, save_dir: str | Path, file_name: str | Path = Path("im.jpg")):
751
753
  """
752
754
  Save cropped detection images to specified directory.
753
755
 
@@ -783,7 +785,7 @@ class Results(SimpleClass, DataExportMixin):
783
785
  BGR=True,
784
786
  )
785
787
 
786
- def summary(self, normalize: bool = False, decimals: int = 5) -> List[Dict[str, Any]]:
788
+ def summary(self, normalize: bool = False, decimals: int = 5) -> list[dict[str, Any]]:
787
789
  """
788
790
  Convert inference results to a summarized dictionary with optional normalization for box coordinates.
789
791
 
@@ -887,7 +889,7 @@ class Boxes(BaseTensor):
887
889
  >>> print(boxes.xywhn)
888
890
  """
889
891
 
890
- def __init__(self, boxes: Union[torch.Tensor, np.ndarray], orig_shape: Tuple[int, int]) -> None:
892
+ def __init__(self, boxes: torch.Tensor | np.ndarray, orig_shape: tuple[int, int]) -> None:
891
893
  """
892
894
  Initialize the Boxes class with detection box data and the original image shape.
893
895
 
@@ -923,7 +925,7 @@ class Boxes(BaseTensor):
923
925
  self.orig_shape = orig_shape
924
926
 
925
927
  @property
926
- def xyxy(self) -> Union[torch.Tensor, np.ndarray]:
928
+ def xyxy(self) -> torch.Tensor | np.ndarray:
927
929
  """
928
930
  Return bounding boxes in [x1, y1, x2, y2] format.
929
931
 
@@ -940,7 +942,7 @@ class Boxes(BaseTensor):
940
942
  return self.data[:, :4]
941
943
 
942
944
  @property
943
- def conf(self) -> Union[torch.Tensor, np.ndarray]:
945
+ def conf(self) -> torch.Tensor | np.ndarray:
944
946
  """
945
947
  Return the confidence scores for each detection box.
946
948
 
@@ -957,7 +959,7 @@ class Boxes(BaseTensor):
957
959
  return self.data[:, -2]
958
960
 
959
961
  @property
960
- def cls(self) -> Union[torch.Tensor, np.ndarray]:
962
+ def cls(self) -> torch.Tensor | np.ndarray:
961
963
  """
962
964
  Return the class ID tensor representing category predictions for each bounding box.
963
965
 
@@ -974,7 +976,7 @@ class Boxes(BaseTensor):
974
976
  return self.data[:, -1]
975
977
 
976
978
  @property
977
- def id(self) -> Optional[Union[torch.Tensor, np.ndarray]]:
979
+ def id(self) -> torch.Tensor | np.ndarray | None:
978
980
  """
979
981
  Return the tracking IDs for each detection box if available.
980
982
 
@@ -1000,7 +1002,7 @@ class Boxes(BaseTensor):
1000
1002
 
1001
1003
  @property
1002
1004
  @lru_cache(maxsize=2)
1003
- def xywh(self) -> Union[torch.Tensor, np.ndarray]:
1005
+ def xywh(self) -> torch.Tensor | np.ndarray:
1004
1006
  """
1005
1007
  Convert bounding boxes from [x1, y1, x2, y2] format to [x, y, width, height] format.
1006
1008
 
@@ -1021,7 +1023,7 @@ class Boxes(BaseTensor):
1021
1023
 
1022
1024
  @property
1023
1025
  @lru_cache(maxsize=2)
1024
- def xyxyn(self) -> Union[torch.Tensor, np.ndarray]:
1026
+ def xyxyn(self) -> torch.Tensor | np.ndarray:
1025
1027
  """
1026
1028
  Return normalized bounding box coordinates relative to the original image size.
1027
1029
 
@@ -1045,7 +1047,7 @@ class Boxes(BaseTensor):
1045
1047
 
1046
1048
  @property
1047
1049
  @lru_cache(maxsize=2)
1048
- def xywhn(self) -> Union[torch.Tensor, np.ndarray]:
1050
+ def xywhn(self) -> torch.Tensor | np.ndarray:
1049
1051
  """
1050
1052
  Return normalized bounding boxes in [x, y, width, height] format.
1051
1053
 
@@ -1096,7 +1098,7 @@ class Masks(BaseTensor):
1096
1098
  >>> normalized_coords = masks.xyn
1097
1099
  """
1098
1100
 
1099
- def __init__(self, masks: Union[torch.Tensor, np.ndarray], orig_shape: Tuple[int, int]) -> None:
1101
+ def __init__(self, masks: torch.Tensor | np.ndarray, orig_shape: tuple[int, int]) -> None:
1100
1102
  """
1101
1103
  Initialize the Masks class with detection mask data and the original image shape.
1102
1104
 
@@ -1117,7 +1119,7 @@ class Masks(BaseTensor):
1117
1119
 
1118
1120
  @property
1119
1121
  @lru_cache(maxsize=1)
1120
- def xyn(self) -> List[np.ndarray]:
1122
+ def xyn(self) -> list[np.ndarray]:
1121
1123
  """
1122
1124
  Return normalized xy-coordinates of the segmentation masks.
1123
1125
 
@@ -1142,7 +1144,7 @@ class Masks(BaseTensor):
1142
1144
 
1143
1145
  @property
1144
1146
  @lru_cache(maxsize=1)
1145
- def xy(self) -> List[np.ndarray]:
1147
+ def xy(self) -> list[np.ndarray]:
1146
1148
  """
1147
1149
  Return the [x, y] pixel coordinates for each segment in the mask tensor.
1148
1150
 
@@ -1200,7 +1202,7 @@ class Keypoints(BaseTensor):
1200
1202
  >>> keypoints_cpu = keypoints.cpu() # Move keypoints to CPU
1201
1203
  """
1202
1204
 
1203
- def __init__(self, keypoints: Union[torch.Tensor, np.ndarray], orig_shape: Tuple[int, int]) -> None:
1205
+ def __init__(self, keypoints: torch.Tensor | np.ndarray, orig_shape: tuple[int, int]) -> None:
1204
1206
  """
1205
1207
  Initialize the Keypoints object with detection keypoints and original image dimensions.
1206
1208
 
@@ -1225,7 +1227,7 @@ class Keypoints(BaseTensor):
1225
1227
 
1226
1228
  @property
1227
1229
  @lru_cache(maxsize=1)
1228
- def xy(self) -> Union[torch.Tensor, np.ndarray]:
1230
+ def xy(self) -> torch.Tensor | np.ndarray:
1229
1231
  """
1230
1232
  Return x, y coordinates of keypoints.
1231
1233
 
@@ -1249,7 +1251,7 @@ class Keypoints(BaseTensor):
1249
1251
 
1250
1252
  @property
1251
1253
  @lru_cache(maxsize=1)
1252
- def xyn(self) -> Union[torch.Tensor, np.ndarray]:
1254
+ def xyn(self) -> torch.Tensor | np.ndarray:
1253
1255
  """
1254
1256
  Return normalized coordinates (x, y) of keypoints relative to the original image size.
1255
1257
 
@@ -1271,7 +1273,7 @@ class Keypoints(BaseTensor):
1271
1273
 
1272
1274
  @property
1273
1275
  @lru_cache(maxsize=1)
1274
- def conf(self) -> Optional[Union[torch.Tensor, np.ndarray]]:
1276
+ def conf(self) -> torch.Tensor | np.ndarray | None:
1275
1277
  """
1276
1278
  Return confidence values for each keypoint.
1277
1279
 
@@ -1322,7 +1324,7 @@ class Probs(BaseTensor):
1322
1324
  tensor([0.6000, 0.3000, 0.1000])
1323
1325
  """
1324
1326
 
1325
- def __init__(self, probs: Union[torch.Tensor, np.ndarray], orig_shape: Optional[Tuple[int, int]] = None) -> None:
1327
+ def __init__(self, probs: torch.Tensor | np.ndarray, orig_shape: tuple[int, int] | None = None) -> None:
1326
1328
  """
1327
1329
  Initialize the Probs class with classification probabilities.
1328
1330
 
@@ -1372,7 +1374,7 @@ class Probs(BaseTensor):
1372
1374
 
1373
1375
  @property
1374
1376
  @lru_cache(maxsize=1)
1375
- def top5(self) -> List[int]:
1377
+ def top5(self) -> list[int]:
1376
1378
  """
1377
1379
  Return the indices of the top 5 class probabilities.
1378
1380
 
@@ -1388,7 +1390,7 @@ class Probs(BaseTensor):
1388
1390
 
1389
1391
  @property
1390
1392
  @lru_cache(maxsize=1)
1391
- def top1conf(self) -> Union[torch.Tensor, np.ndarray]:
1393
+ def top1conf(self) -> torch.Tensor | np.ndarray:
1392
1394
  """
1393
1395
  Return the confidence score of the highest probability class.
1394
1396
 
@@ -1408,7 +1410,7 @@ class Probs(BaseTensor):
1408
1410
 
1409
1411
  @property
1410
1412
  @lru_cache(maxsize=1)
1411
- def top5conf(self) -> Union[torch.Tensor, np.ndarray]:
1413
+ def top5conf(self) -> torch.Tensor | np.ndarray:
1412
1414
  """
1413
1415
  Return confidence scores for the top 5 classification predictions.
1414
1416
 
@@ -1463,7 +1465,7 @@ class OBB(BaseTensor):
1463
1465
  >>> print(obb.cls)
1464
1466
  """
1465
1467
 
1466
- def __init__(self, boxes: Union[torch.Tensor, np.ndarray], orig_shape: Tuple[int, int]) -> None:
1468
+ def __init__(self, boxes: torch.Tensor | np.ndarray, orig_shape: tuple[int, int]) -> None:
1467
1469
  """
1468
1470
  Initialize an OBB (Oriented Bounding Box) instance with oriented bounding box data and original image shape.
1469
1471
 
@@ -1500,7 +1502,7 @@ class OBB(BaseTensor):
1500
1502
  self.orig_shape = orig_shape
1501
1503
 
1502
1504
  @property
1503
- def xywhr(self) -> Union[torch.Tensor, np.ndarray]:
1505
+ def xywhr(self) -> torch.Tensor | np.ndarray:
1504
1506
  """
1505
1507
  Return boxes in [x_center, y_center, width, height, rotation] format.
1506
1508
 
@@ -1518,7 +1520,7 @@ class OBB(BaseTensor):
1518
1520
  return self.data[:, :5]
1519
1521
 
1520
1522
  @property
1521
- def conf(self) -> Union[torch.Tensor, np.ndarray]:
1523
+ def conf(self) -> torch.Tensor | np.ndarray:
1522
1524
  """
1523
1525
  Return the confidence scores for Oriented Bounding Boxes (OBBs).
1524
1526
 
@@ -1538,7 +1540,7 @@ class OBB(BaseTensor):
1538
1540
  return self.data[:, -2]
1539
1541
 
1540
1542
  @property
1541
- def cls(self) -> Union[torch.Tensor, np.ndarray]:
1543
+ def cls(self) -> torch.Tensor | np.ndarray:
1542
1544
  """
1543
1545
  Return the class values of the oriented bounding boxes.
1544
1546
 
@@ -1556,7 +1558,7 @@ class OBB(BaseTensor):
1556
1558
  return self.data[:, -1]
1557
1559
 
1558
1560
  @property
1559
- def id(self) -> Optional[Union[torch.Tensor, np.ndarray]]:
1561
+ def id(self) -> torch.Tensor | np.ndarray | None:
1560
1562
  """
1561
1563
  Return the tracking IDs of the oriented bounding boxes (if available).
1562
1564
 
@@ -1576,7 +1578,7 @@ class OBB(BaseTensor):
1576
1578
 
1577
1579
  @property
1578
1580
  @lru_cache(maxsize=2)
1579
- def xyxyxyxy(self) -> Union[torch.Tensor, np.ndarray]:
1581
+ def xyxyxyxy(self) -> torch.Tensor | np.ndarray:
1580
1582
  """
1581
1583
  Convert OBB format to 8-point (xyxyxyxy) coordinate format for rotated bounding boxes.
1582
1584
 
@@ -1595,7 +1597,7 @@ class OBB(BaseTensor):
1595
1597
 
1596
1598
  @property
1597
1599
  @lru_cache(maxsize=2)
1598
- def xyxyxyxyn(self) -> Union[torch.Tensor, np.ndarray]:
1600
+ def xyxyxyxyn(self) -> torch.Tensor | np.ndarray:
1599
1601
  """
1600
1602
  Convert rotated bounding boxes to normalized xyxyxyxy format.
1601
1603
 
@@ -1617,7 +1619,7 @@ class OBB(BaseTensor):
1617
1619
 
1618
1620
  @property
1619
1621
  @lru_cache(maxsize=2)
1620
- def xyxy(self) -> Union[torch.Tensor, np.ndarray]:
1622
+ def xyxy(self) -> torch.Tensor | np.ndarray:
1621
1623
  """
1622
1624
  Convert oriented bounding boxes (OBB) to axis-aligned bounding boxes in xyxy format.
1623
1625
 
@@ -27,6 +27,7 @@ from ultralytics.data.utils import check_cls_dataset, check_det_dataset
27
27
  from ultralytics.nn.tasks import attempt_load_one_weight, attempt_load_weights
28
28
  from ultralytics.utils import (
29
29
  DEFAULT_CFG,
30
+ GIT,
30
31
  LOCAL_RANK,
31
32
  LOGGER,
32
33
  RANK,
@@ -36,7 +37,6 @@ from ultralytics.utils import (
36
37
  clean_url,
37
38
  colorstr,
38
39
  emojis,
39
- get_git_commit,
40
40
  )
41
41
  from ultralytics.utils.autobatch import check_train_batch_size
42
42
  from ultralytics.utils.checks import check_amp, check_file, check_imgsz, check_model_file_from_stem, print_args
@@ -573,7 +573,12 @@ class BaseTrainer:
573
573
  "train_results": self.read_results_csv(),
574
574
  "date": datetime.now().isoformat(),
575
575
  "version": __version__,
576
- "git_commit": get_git_commit(),
576
+ "git": {
577
+ "root": str(GIT.root),
578
+ "branch": GIT.branch,
579
+ "commit": GIT.commit,
580
+ "origin": GIT.origin,
581
+ },
577
582
  "license": "AGPL-3.0 (https://ultralytics.com/license)",
578
583
  "docs": "https://docs.ultralytics.com",
579
584
  },
@@ -14,11 +14,12 @@ Examples:
14
14
  >>> model.tune(data="coco8.yaml", epochs=10, iterations=300, optimizer="AdamW", plots=False, save=False, val=False)
15
15
  """
16
16
 
17
+ from __future__ import annotations
18
+
17
19
  import random
18
20
  import shutil
19
21
  import subprocess
20
22
  import time
21
- from typing import Dict, List, Optional
22
23
 
23
24
  import numpy as np
24
25
 
@@ -59,7 +60,7 @@ class Tuner:
59
60
  >>> model.tune(space={key1: val1, key2: val2}) # custom search space dictionary
60
61
  """
61
62
 
62
- def __init__(self, args=DEFAULT_CFG, _callbacks: Optional[List] = None):
63
+ def __init__(self, args=DEFAULT_CFG, _callbacks: list | None = None):
63
64
  """
64
65
  Initialize the Tuner with configurations.
65
66
 
@@ -109,7 +110,7 @@ class Tuner:
109
110
 
110
111
  def _mutate(
111
112
  self, parent: str = "single", n: int = 5, mutation: float = 0.8, sigma: float = 0.2
112
- ) -> Dict[str, float]:
113
+ ) -> dict[str, float]:
113
114
  """
114
115
  Mutate hyperparameters based on bounds and scaling factors specified in `self.space`.
115
116
 
@@ -1,9 +1,10 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import concurrent.futures
4
6
  import statistics
5
7
  import time
6
- from typing import List, Optional, Tuple
7
8
 
8
9
 
9
10
  class GCPRegions:
@@ -71,16 +72,16 @@ class GCPRegions:
71
72
  "us-west4": (2, "Las Vegas", "United States"),
72
73
  }
73
74
 
74
- def tier1(self) -> List[str]:
75
+ def tier1(self) -> list[str]:
75
76
  """Return a list of GCP regions classified as tier 1 based on predefined criteria."""
76
77
  return [region for region, info in self.regions.items() if info[0] == 1]
77
78
 
78
- def tier2(self) -> List[str]:
79
+ def tier2(self) -> list[str]:
79
80
  """Return a list of GCP regions classified as tier 2 based on predefined criteria."""
80
81
  return [region for region, info in self.regions.items() if info[0] == 2]
81
82
 
82
83
  @staticmethod
83
- def _ping_region(region: str, attempts: int = 1) -> Tuple[str, float, float, float, float]:
84
+ def _ping_region(region: str, attempts: int = 1) -> tuple[str, float, float, float, float]:
84
85
  """
85
86
  Ping a specified GCP region and measure network latency statistics.
86
87
 
@@ -122,9 +123,9 @@ class GCPRegions:
122
123
  self,
123
124
  top: int = 1,
124
125
  verbose: bool = False,
125
- tier: Optional[int] = None,
126
+ tier: int | None = None,
126
127
  attempts: int = 1,
127
- ) -> List[Tuple[str, float, float, float, float]]:
128
+ ) -> list[tuple[str, float, float, float, float]]:
128
129
  """
129
130
  Determine the GCP regions with the lowest latency based on ping tests.
130
131
 
@@ -1,11 +1,13 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import shutil
4
6
  import threading
5
7
  import time
6
8
  from http import HTTPStatus
7
9
  from pathlib import Path
8
- from typing import Any, Dict, Optional
10
+ from typing import Any
9
11
  from urllib.parse import parse_qs, urlparse
10
12
 
11
13
  from ultralytics import __version__
@@ -90,7 +92,7 @@ class HUBTrainingSession:
90
92
  )
91
93
 
92
94
  @classmethod
93
- def create_session(cls, identifier: str, args: Optional[Dict[str, Any]] = None):
95
+ def create_session(cls, identifier: str, args: dict[str, Any] | None = None):
94
96
  """
95
97
  Create an authenticated HUBTrainingSession or return None.
96
98
 
@@ -137,7 +139,7 @@ class HUBTrainingSession:
137
139
  self.model.start_heartbeat(self.rate_limits["heartbeat"])
138
140
  LOGGER.info(f"{PREFIX}View model at {self.model_url} 🚀")
139
141
 
140
- def create_model(self, model_args: Dict[str, Any]):
142
+ def create_model(self, model_args: dict[str, Any]):
141
143
  """
142
144
  Initialize a HUB training session with the specified model arguments.
143
145
 
@@ -204,7 +206,7 @@ class HUBTrainingSession:
204
206
  HUBModelError: If the identifier format is not recognized.
205
207
  """
206
208
  api_key, model_id, filename = None, None, None
207
- if str(identifier).endswith((".pt", ".yaml")):
209
+ if identifier.endswith((".pt", ".yaml")):
208
210
  filename = identifier
209
211
  elif identifier.startswith(f"{HUB_WEB_ROOT}/models/"):
210
212
  parsed_url = urlparse(identifier)
@@ -254,8 +256,8 @@ class HUBTrainingSession:
254
256
  timeout: int = 30,
255
257
  thread: bool = True,
256
258
  verbose: bool = True,
257
- progress_total: Optional[int] = None,
258
- stream_response: Optional[bool] = None,
259
+ progress_total: int | None = None,
260
+ stream_response: bool | None = None,
259
261
  *args,
260
262
  **kwargs,
261
263
  ):
ultralytics/hub/utils.py CHANGED
@@ -11,8 +11,8 @@ from ultralytics import __version__
11
11
  from ultralytics.utils import (
12
12
  ARGV,
13
13
  ENVIRONMENT,
14
+ GIT,
14
15
  IS_COLAB,
15
- IS_GIT_DIR,
16
16
  IS_PIP_PACKAGE,
17
17
  LOGGER,
18
18
  ONLINE,
@@ -23,7 +23,6 @@ from ultralytics.utils import (
23
23
  TQDM,
24
24
  TryExcept,
25
25
  colorstr,
26
- get_git_origin_url,
27
26
  )
28
27
  from ultralytics.utils.downloads import GITHUB_ASSETS_NAMES
29
28
  from ultralytics.utils.torch_utils import get_cpu_info
@@ -205,7 +204,7 @@ class Events:
205
204
  self.t = 0.0 # rate limit timer (seconds)
206
205
  self.metadata = {
207
206
  "cli": Path(ARGV[0]).name == "yolo",
208
- "install": "git" if IS_GIT_DIR else "pip" if IS_PIP_PACKAGE else "other",
207
+ "install": "git" if GIT.is_repo else "pip" if IS_PIP_PACKAGE else "other",
209
208
  "python": PYTHON_VERSION.rsplit(".", 1)[0], # i.e. 3.13
210
209
  "CPU": get_cpu_info(),
211
210
  # "GPU": get_gpu_info(index=0) if cuda else None,
@@ -219,7 +218,7 @@ class Events:
219
218
  and RANK in {-1, 0}
220
219
  and not TESTS_RUNNING
221
220
  and ONLINE
222
- and (IS_PIP_PACKAGE or get_git_origin_url() == "https://github.com/ultralytics/ultralytics.git")
221
+ and (IS_PIP_PACKAGE or GIT.origin == "https://github.com/ultralytics/ultralytics.git")
223
222
  )
224
223
 
225
224
  def __call__(self, cfg, device=None):
@@ -1,7 +1,9 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  from pathlib import Path
4
- from typing import Any, Dict, List, Optional
6
+ from typing import Any
5
7
 
6
8
  from ultralytics.engine.model import Model
7
9
 
@@ -45,10 +47,10 @@ class FastSAM(Model):
45
47
  self,
46
48
  source,
47
49
  stream: bool = False,
48
- bboxes: Optional[List] = None,
49
- points: Optional[List] = None,
50
- labels: Optional[List] = None,
51
- texts: Optional[List] = None,
50
+ bboxes: list | None = None,
51
+ points: list | None = None,
52
+ labels: list | None = None,
53
+ texts: list | None = None,
52
54
  **kwargs: Any,
53
55
  ):
54
56
  """
@@ -74,6 +76,6 @@ class FastSAM(Model):
74
76
  return super().predict(source, stream, prompts=prompts, **kwargs)
75
77
 
76
78
  @property
77
- def task_map(self) -> Dict[str, Dict[str, Any]]:
79
+ def task_map(self) -> dict[str, dict[str, Any]]:
78
80
  """Returns a dictionary mapping segment task to corresponding predictor and validator classes."""
79
81
  return {"segment": {"predictor": FastSAMPredictor, "validator": FastSAMValidator}}
@@ -1,7 +1,9 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  from pathlib import Path
4
- from typing import Any, Dict
6
+ from typing import Any
5
7
 
6
8
  import torch
7
9
 
@@ -80,7 +82,7 @@ class NAS(Model):
80
82
  self.model.args = {**DEFAULT_CFG_DICT, **self.overrides} # for export()
81
83
  self.model.eval()
82
84
 
83
- def info(self, detailed: bool = False, verbose: bool = True) -> Dict[str, Any]:
85
+ def info(self, detailed: bool = False, verbose: bool = True) -> dict[str, Any]:
84
86
  """
85
87
  Log model information.
86
88
 
@@ -94,6 +96,6 @@ class NAS(Model):
94
96
  return model_info(self.model, detailed=detailed, verbose=verbose, imgsz=640)
95
97
 
96
98
  @property
97
- def task_map(self) -> Dict[str, Dict[str, Any]]:
99
+ def task_map(self) -> dict[str, dict[str, Any]]:
98
100
  """Return a dictionary mapping tasks to respective predictor and validator classes."""
99
101
  return {"detect": {"predictor": NASPredictor, "validator": NASValidator}}
@@ -1,7 +1,8 @@
1
1
  # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  from copy import copy
4
- from typing import Optional
5
6
 
6
7
  from ultralytics.models.yolo.detect import DetectionTrainer
7
8
  from ultralytics.nn.tasks import RTDETRDetectionModel
@@ -41,7 +42,7 @@ class RTDETRTrainer(DetectionTrainer):
41
42
  >>> trainer.train()
42
43
  """
43
44
 
44
- def get_model(self, cfg: Optional[dict] = None, weights: Optional[str] = None, verbose: bool = True):
45
+ def get_model(self, cfg: dict | None = None, weights: str | None = None, verbose: bool = True):
45
46
  """
46
47
  Initialize and return an RT-DETR model for object detection tasks.
47
48
 
@@ -58,7 +59,7 @@ class RTDETRTrainer(DetectionTrainer):
58
59
  model.load(weights)
59
60
  return model
60
61
 
61
- def build_dataset(self, img_path: str, mode: str = "val", batch: Optional[int] = None):
62
+ def build_dataset(self, img_path: str, mode: str = "val", batch: int | None = None):
62
63
  """
63
64
  Build and return an RT-DETR dataset for training or validation.
64
65