segment-everything 0.1.0__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 (145) hide show
  1. segment_everything/__init__.py +5 -0
  2. segment_everything/augmentation/albumentations_helper.py +0 -0
  3. segment_everything/detect_and_segment.py +131 -0
  4. segment_everything/napari_helper.py +15 -0
  5. segment_everything/prompt_generator.py +188 -0
  6. segment_everything/py.typed +5 -0
  7. segment_everything/stacked_label_dataset.py +113 -0
  8. segment_everything/stacked_labels.py +428 -0
  9. segment_everything/vendored/PromptGuidedDecoder/Prompt_guided_Mask_Decoder.pt +0 -0
  10. segment_everything/vendored/__init__.py +5 -0
  11. segment_everything/vendored/dice.py +158 -0
  12. segment_everything/vendored/efficientvit/__init__.py +0 -0
  13. segment_everything/vendored/efficientvit/apps/__init__.py +0 -0
  14. segment_everything/vendored/efficientvit/apps/data_provider/__init__.py +7 -0
  15. segment_everything/vendored/efficientvit/apps/data_provider/augment/__init__.py +6 -0
  16. segment_everything/vendored/efficientvit/apps/data_provider/augment/bbox.py +30 -0
  17. segment_everything/vendored/efficientvit/apps/data_provider/augment/color_aug.py +78 -0
  18. segment_everything/vendored/efficientvit/apps/data_provider/base.py +254 -0
  19. segment_everything/vendored/efficientvit/apps/data_provider/random_resolution/__init__.py +6 -0
  20. segment_everything/vendored/efficientvit/apps/data_provider/random_resolution/_data_loader.py +1538 -0
  21. segment_everything/vendored/efficientvit/apps/data_provider/random_resolution/_data_worker.py +357 -0
  22. segment_everything/vendored/efficientvit/apps/data_provider/random_resolution/controller.py +100 -0
  23. segment_everything/vendored/efficientvit/apps/setup.py +150 -0
  24. segment_everything/vendored/efficientvit/apps/trainer/__init__.py +6 -0
  25. segment_everything/vendored/efficientvit/apps/trainer/base.py +318 -0
  26. segment_everything/vendored/efficientvit/apps/trainer/run_config.py +129 -0
  27. segment_everything/vendored/efficientvit/apps/utils/__init__.py +12 -0
  28. segment_everything/vendored/efficientvit/apps/utils/dist.py +32 -0
  29. segment_everything/vendored/efficientvit/apps/utils/ema.py +52 -0
  30. segment_everything/vendored/efficientvit/apps/utils/export.py +45 -0
  31. segment_everything/vendored/efficientvit/apps/utils/init.py +66 -0
  32. segment_everything/vendored/efficientvit/apps/utils/lr.py +52 -0
  33. segment_everything/vendored/efficientvit/apps/utils/metric.py +43 -0
  34. segment_everything/vendored/efficientvit/apps/utils/misc.py +101 -0
  35. segment_everything/vendored/efficientvit/apps/utils/opt.py +28 -0
  36. segment_everything/vendored/efficientvit/cls_model_zoo.py +79 -0
  37. segment_everything/vendored/efficientvit/clscore/__init__.py +0 -0
  38. segment_everything/vendored/efficientvit/clscore/data_provider/__init__.py +5 -0
  39. segment_everything/vendored/efficientvit/clscore/data_provider/imagenet.py +142 -0
  40. segment_everything/vendored/efficientvit/clscore/trainer/__init__.py +6 -0
  41. segment_everything/vendored/efficientvit/clscore/trainer/cls_run_config.py +18 -0
  42. segment_everything/vendored/efficientvit/clscore/trainer/cls_trainer.py +265 -0
  43. segment_everything/vendored/efficientvit/clscore/trainer/utils/__init__.py +7 -0
  44. segment_everything/vendored/efficientvit/clscore/trainer/utils/label_smooth.py +18 -0
  45. segment_everything/vendored/efficientvit/clscore/trainer/utils/metric.py +23 -0
  46. segment_everything/vendored/efficientvit/clscore/trainer/utils/mixup.py +67 -0
  47. segment_everything/vendored/efficientvit/models/__init__.py +0 -0
  48. segment_everything/vendored/efficientvit/models/efficientvit/__init__.py +8 -0
  49. segment_everything/vendored/efficientvit/models/efficientvit/backbone.py +380 -0
  50. segment_everything/vendored/efficientvit/models/efficientvit/cls.py +188 -0
  51. segment_everything/vendored/efficientvit/models/efficientvit/sam.py +181 -0
  52. segment_everything/vendored/efficientvit/models/efficientvit/seg.py +373 -0
  53. segment_everything/vendored/efficientvit/models/nn/__init__.py +8 -0
  54. segment_everything/vendored/efficientvit/models/nn/act.py +30 -0
  55. segment_everything/vendored/efficientvit/models/nn/drop.py +104 -0
  56. segment_everything/vendored/efficientvit/models/nn/norm.py +164 -0
  57. segment_everything/vendored/efficientvit/models/nn/ops.py +597 -0
  58. segment_everything/vendored/efficientvit/models/utils/__init__.py +7 -0
  59. segment_everything/vendored/efficientvit/models/utils/list.py +53 -0
  60. segment_everything/vendored/efficientvit/models/utils/network.py +73 -0
  61. segment_everything/vendored/efficientvit/models/utils/random.py +65 -0
  62. segment_everything/vendored/efficientvit/sam_model_zoo.py +45 -0
  63. segment_everything/vendored/efficientvit/seg_model_zoo.py +70 -0
  64. segment_everything/vendored/get_object_aware.py +26 -0
  65. segment_everything/vendored/mobilesamv2/__init__.py +16 -0
  66. segment_everything/vendored/mobilesamv2/automatic_mask_generator.py +415 -0
  67. segment_everything/vendored/mobilesamv2/build_sam.py +246 -0
  68. segment_everything/vendored/mobilesamv2/modeling/__init__.py +11 -0
  69. segment_everything/vendored/mobilesamv2/modeling/common.py +43 -0
  70. segment_everything/vendored/mobilesamv2/modeling/image_encoder.py +394 -0
  71. segment_everything/vendored/mobilesamv2/modeling/mask_decoder.py +213 -0
  72. segment_everything/vendored/mobilesamv2/modeling/prompt_encoder.py +217 -0
  73. segment_everything/vendored/mobilesamv2/modeling/sam.py +203 -0
  74. segment_everything/vendored/mobilesamv2/modeling/transformer.py +240 -0
  75. segment_everything/vendored/mobilesamv2/predictor.py +384 -0
  76. segment_everything/vendored/mobilesamv2/utils/__init__.py +5 -0
  77. segment_everything/vendored/mobilesamv2/utils/amg.py +347 -0
  78. segment_everything/vendored/mobilesamv2/utils/onnx.py +144 -0
  79. segment_everything/vendored/mobilesamv2/utils/transforms.py +103 -0
  80. segment_everything/vendored/object_detection/__init__.py +0 -0
  81. segment_everything/vendored/object_detection/ultralytics/__init__.py +5 -0
  82. segment_everything/vendored/object_detection/ultralytics/nn/__init__.py +9 -0
  83. segment_everything/vendored/object_detection/ultralytics/nn/autobackend.py +658 -0
  84. segment_everything/vendored/object_detection/ultralytics/nn/autoshape.py +397 -0
  85. segment_everything/vendored/object_detection/ultralytics/nn/modules/__init__.py +110 -0
  86. segment_everything/vendored/object_detection/ultralytics/nn/modules/block.py +304 -0
  87. segment_everything/vendored/object_detection/ultralytics/nn/modules/conv.py +297 -0
  88. segment_everything/vendored/object_detection/ultralytics/nn/modules/head.py +468 -0
  89. segment_everything/vendored/object_detection/ultralytics/nn/modules/transformer.py +378 -0
  90. segment_everything/vendored/object_detection/ultralytics/nn/modules/utils.py +78 -0
  91. segment_everything/vendored/object_detection/ultralytics/nn/tasks.py +1049 -0
  92. segment_everything/vendored/object_detection/ultralytics/prompt_mobilesamv2/__init__.py +6 -0
  93. segment_everything/vendored/object_detection/ultralytics/prompt_mobilesamv2/model.py +104 -0
  94. segment_everything/vendored/object_detection/ultralytics/prompt_mobilesamv2/predict.py +95 -0
  95. segment_everything/vendored/object_detection/ultralytics/yolo/__init__.py +5 -0
  96. segment_everything/vendored/object_detection/ultralytics/yolo/cfg/__init__.py +588 -0
  97. segment_everything/vendored/object_detection/ultralytics/yolo/cfg/default.yaml +117 -0
  98. segment_everything/vendored/object_detection/ultralytics/yolo/data/__init__.py +9 -0
  99. segment_everything/vendored/object_detection/ultralytics/yolo/data/annotator.py +53 -0
  100. segment_everything/vendored/object_detection/ultralytics/yolo/data/augment.py +899 -0
  101. segment_everything/vendored/object_detection/ultralytics/yolo/data/base.py +286 -0
  102. segment_everything/vendored/object_detection/ultralytics/yolo/data/build.py +213 -0
  103. segment_everything/vendored/object_detection/ultralytics/yolo/data/converter.py +358 -0
  104. segment_everything/vendored/object_detection/ultralytics/yolo/data/dataloaders/__init__.py +0 -0
  105. segment_everything/vendored/object_detection/ultralytics/yolo/data/dataloaders/stream_loaders.py +459 -0
  106. segment_everything/vendored/object_detection/ultralytics/yolo/data/dataset.py +274 -0
  107. segment_everything/vendored/object_detection/ultralytics/yolo/data/dataset_wrappers.py +53 -0
  108. segment_everything/vendored/object_detection/ultralytics/yolo/data/scripts/download_weights.sh +18 -0
  109. segment_everything/vendored/object_detection/ultralytics/yolo/data/scripts/get_coco.sh +60 -0
  110. segment_everything/vendored/object_detection/ultralytics/yolo/data/scripts/get_coco128.sh +17 -0
  111. segment_everything/vendored/object_detection/ultralytics/yolo/data/scripts/get_imagenet.sh +51 -0
  112. segment_everything/vendored/object_detection/ultralytics/yolo/data/utils.py +716 -0
  113. segment_everything/vendored/object_detection/ultralytics/yolo/engine/__init__.py +0 -0
  114. segment_everything/vendored/object_detection/ultralytics/yolo/engine/exporter.py +1214 -0
  115. segment_everything/vendored/object_detection/ultralytics/yolo/engine/model.py +641 -0
  116. segment_everything/vendored/object_detection/ultralytics/yolo/engine/predictor.py +461 -0
  117. segment_everything/vendored/object_detection/ultralytics/yolo/engine/results.py +741 -0
  118. segment_everything/vendored/object_detection/ultralytics/yolo/utils/__init__.py +893 -0
  119. segment_everything/vendored/object_detection/ultralytics/yolo/utils/autobatch.py +108 -0
  120. segment_everything/vendored/object_detection/ultralytics/yolo/utils/callbacks/__init__.py +5 -0
  121. segment_everything/vendored/object_detection/ultralytics/yolo/utils/callbacks/base.py +212 -0
  122. segment_everything/vendored/object_detection/ultralytics/yolo/utils/checks.py +547 -0
  123. segment_everything/vendored/object_detection/ultralytics/yolo/utils/dist.py +67 -0
  124. segment_everything/vendored/object_detection/ultralytics/yolo/utils/downloads.py +353 -0
  125. segment_everything/vendored/object_detection/ultralytics/yolo/utils/errors.py +12 -0
  126. segment_everything/vendored/object_detection/ultralytics/yolo/utils/files.py +100 -0
  127. segment_everything/vendored/object_detection/ultralytics/yolo/utils/instance.py +391 -0
  128. segment_everything/vendored/object_detection/ultralytics/yolo/utils/loss.py +579 -0
  129. segment_everything/vendored/object_detection/ultralytics/yolo/utils/metrics.py +1189 -0
  130. segment_everything/vendored/object_detection/ultralytics/yolo/utils/ops.py +870 -0
  131. segment_everything/vendored/object_detection/ultralytics/yolo/utils/patches.py +45 -0
  132. segment_everything/vendored/object_detection/ultralytics/yolo/utils/plotting.py +767 -0
  133. segment_everything/vendored/object_detection/ultralytics/yolo/utils/tal.py +276 -0
  134. segment_everything/vendored/object_detection/ultralytics/yolo/utils/torch_utils.py +684 -0
  135. segment_everything/vendored/object_detection/ultralytics/yolo/utils/tuner.py +54 -0
  136. segment_everything/vendored/object_detection/ultralytics/yolo/v8/__init__.py +5 -0
  137. segment_everything/vendored/object_detection/ultralytics/yolo/v8/detect/__init__.py +5 -0
  138. segment_everything/vendored/object_detection/ultralytics/yolo/v8/detect/predict.py +69 -0
  139. segment_everything/vendored/tinyvit/__init__.py +2 -0
  140. segment_everything/vendored/tinyvit/tiny_vit.py +867 -0
  141. segment_everything/weights_helper.py +124 -0
  142. segment_everything-0.1.0.dist-info/METADATA +53 -0
  143. segment_everything-0.1.0.dist-info/RECORD +145 -0
  144. segment_everything-0.1.0.dist-info/WHEEL +4 -0
  145. segment_everything-0.1.0.dist-info/licenses/LICENSE +28 -0
@@ -0,0 +1,893 @@
1
+ # Ultralytics YOLO 🚀, AGPL-3.0 license
2
+
3
+ import contextlib
4
+ import inspect
5
+ import logging.config
6
+ import os
7
+ import platform
8
+ import re
9
+ import subprocess
10
+ import sys
11
+ import threading
12
+ import urllib
13
+ import uuid
14
+ from pathlib import Path
15
+ from types import SimpleNamespace
16
+ from typing import Union
17
+
18
+ import cv2
19
+ import matplotlib.pyplot as plt
20
+ import numpy as np
21
+ import torch
22
+ import yaml
23
+
24
+ from ... import __version__
25
+
26
+ # PyTorch Multi-GPU DDP Constants
27
+ RANK = int(os.getenv("RANK", -1))
28
+ LOCAL_RANK = int(
29
+ os.getenv("LOCAL_RANK", -1)
30
+ ) # https://pytorch.org/docs/stable/elastic/run.html
31
+ WORLD_SIZE = int(os.getenv("WORLD_SIZE", 1))
32
+
33
+ # Other Constants
34
+ FILE = Path(__file__).resolve()
35
+ ROOT = FILE.parents[2] # YOLO
36
+ DEFAULT_CFG_PATH = ROOT / "yolo/cfg/default.yaml"
37
+ NUM_THREADS = min(
38
+ 8, max(1, os.cpu_count() - 1)
39
+ ) # number of YOLOv5 multiprocessing threads
40
+ AUTOINSTALL = (
41
+ str(os.getenv("YOLO_AUTOINSTALL", True)).lower() == "true"
42
+ ) # global auto-install mode
43
+ VERBOSE = (
44
+ str(os.getenv("YOLO_VERBOSE", True)).lower() == "true"
45
+ ) # global verbose mode
46
+ TQDM_BAR_FORMAT = "{l_bar}{bar:10}{r_bar}" # tqdm bar format
47
+ LOGGING_NAME = "ultralytics"
48
+ MACOS, LINUX, WINDOWS = (
49
+ platform.system() == x for x in ["Darwin", "Linux", "Windows"]
50
+ ) # environment booleans
51
+ HELP_MSG = """
52
+ Usage examples for running YOLOv8:
53
+
54
+ 1. Install the ultralytics package:
55
+
56
+ pip install ultralytics
57
+
58
+ 2. Use the Python SDK:
59
+
60
+ from ultralytics import YOLO
61
+
62
+ # Load a model
63
+ model = YOLO('yolov8n.yaml') # build a new model from scratch
64
+ model = YOLO("yolov8n.pt") # load a pretrained model (recommended for training)
65
+
66
+ # Use the model
67
+ results = model.train(data="coco128.yaml", epochs=3) # train the model
68
+ results = model.val() # evaluate model performance on the validation set
69
+ results = model('https://ultralytics.com/images/bus.jpg') # predict on an image
70
+ success = model.export(format='onnx') # export the model to ONNX format
71
+
72
+ 3. Use the command line interface (CLI):
73
+
74
+ YOLOv8 'yolo' CLI commands use the following syntax:
75
+
76
+ yolo TASK MODE ARGS
77
+
78
+ Where TASK (optional) is one of [detect, segment, classify]
79
+ MODE (required) is one of [train, val, predict, export]
80
+ ARGS (optional) are any number of custom 'arg=value' pairs like 'imgsz=320' that override defaults.
81
+ See all ARGS at https://docs.ultralytics.com/usage/cfg or with 'yolo cfg'
82
+
83
+ - Train a detection model for 10 epochs with an initial learning_rate of 0.01
84
+ yolo detect train data=coco128.yaml model=yolov8n.pt epochs=10 lr0=0.01
85
+
86
+ - Predict a YouTube video using a pretrained segmentation model at image size 320:
87
+ yolo segment predict model=yolov8n-seg.pt source='https://youtu.be/Zgi9g1ksQHc' imgsz=320
88
+
89
+ - Val a pretrained detection model at batch-size 1 and image size 640:
90
+ yolo detect val model=yolov8n.pt data=coco128.yaml batch=1 imgsz=640
91
+
92
+ - Export a YOLOv8n classification model to ONNX format at image size 224 by 128 (no TASK required)
93
+ yolo export model=yolov8n-cls.pt format=onnx imgsz=224,128
94
+
95
+ - Run special commands:
96
+ yolo help
97
+ yolo checks
98
+ yolo version
99
+ yolo settings
100
+ yolo copy-cfg
101
+ yolo cfg
102
+
103
+ Docs: https://docs.ultralytics.com
104
+ Community: https://community.ultralytics.com
105
+ GitHub: https://github.com/ultralytics/ultralytics
106
+ """
107
+
108
+ # Settings
109
+ torch.set_printoptions(linewidth=320, precision=4, profile="default")
110
+ np.set_printoptions(
111
+ linewidth=320, formatter={"float_kind": "{:11.5g}".format}
112
+ ) # format short g, %precision=5
113
+ cv2.setNumThreads(
114
+ 0
115
+ ) # prevent OpenCV from multithreading (incompatible with PyTorch DataLoader)
116
+ os.environ["NUMEXPR_MAX_THREADS"] = str(NUM_THREADS) # NumExpr max threads
117
+ os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":4096:8" # for deterministic training
118
+ os.environ["TF_CPP_MIN_LOG_LEVEL"] = (
119
+ "2" # suppress verbose TF compiler warnings in Colab
120
+ )
121
+
122
+
123
+ class SimpleClass:
124
+ """
125
+ Ultralytics SimpleClass is a base class providing helpful string representation, error reporting, and attribute
126
+ access methods for easier debugging and usage.
127
+ """
128
+
129
+ def __str__(self):
130
+ """Return a human-readable string representation of the object."""
131
+ attr = []
132
+ for a in dir(self):
133
+ v = getattr(self, a)
134
+ if not callable(v) and not a.startswith("_"):
135
+ if isinstance(v, SimpleClass):
136
+ # Display only the module and class name for subclasses
137
+ s = f"{a}: {v.__module__}.{v.__class__.__name__} object"
138
+ else:
139
+ s = f"{a}: {repr(v)}"
140
+ attr.append(s)
141
+ return (
142
+ f"{self.__module__}.{self.__class__.__name__} object with attributes:\n\n"
143
+ + "\n".join(attr)
144
+ )
145
+
146
+ def __repr__(self):
147
+ """Return a machine-readable string representation of the object."""
148
+ return self.__str__()
149
+
150
+ def __getattr__(self, attr):
151
+ """Custom attribute access error message with helpful information."""
152
+ name = self.__class__.__name__
153
+ raise AttributeError(
154
+ f"'{name}' object has no attribute '{attr}'. See valid attributes below.\n{self.__doc__}"
155
+ )
156
+
157
+
158
+ class IterableSimpleNamespace(SimpleNamespace):
159
+ """
160
+ Ultralytics IterableSimpleNamespace is an extension class of SimpleNamespace that adds iterable functionality and
161
+ enables usage with dict() and for loops.
162
+ """
163
+
164
+ def __iter__(self):
165
+ """Return an iterator of key-value pairs from the namespace's attributes."""
166
+ return iter(vars(self).items())
167
+
168
+ def __str__(self):
169
+ """Return a human-readable string representation of the object."""
170
+ return "\n".join(f"{k}={v}" for k, v in vars(self).items())
171
+
172
+ def __getattr__(self, attr):
173
+ """Custom attribute access error message with helpful information."""
174
+ name = self.__class__.__name__
175
+ raise AttributeError(
176
+ f"""
177
+ '{name}' object has no attribute '{attr}'. This may be caused by a modified or out of date ultralytics
178
+ 'default.yaml' file.\nPlease update your code with 'pip install -U ultralytics' and if necessary replace
179
+ {DEFAULT_CFG_PATH} with the latest version from
180
+ https://github.com/ultralytics/ultralytics/blob/main/ultralytics/yolo/cfg/default.yaml
181
+ """
182
+ )
183
+
184
+ def get(self, key, default=None):
185
+ """Return the value of the specified key if it exists; otherwise, return the default value."""
186
+ return getattr(self, key, default)
187
+
188
+
189
+ def plt_settings(rcparams=None, backend="Agg"):
190
+ """
191
+ Decorator to temporarily set rc parameters and the backend for a plotting function.
192
+
193
+ Usage:
194
+ decorator: @plt_settings({"font.size": 12})
195
+ context manager: with plt_settings({"font.size": 12}):
196
+
197
+ Args:
198
+ rcparams (dict): Dictionary of rc parameters to set.
199
+ backend (str, optional): Name of the backend to use. Defaults to 'Agg'.
200
+
201
+ Returns:
202
+ (Callable): Decorated function with temporarily set rc parameters and backend. This decorator can be
203
+ applied to any function that needs to have specific matplotlib rc parameters and backend for its execution.
204
+ """
205
+
206
+ if rcparams is None:
207
+ rcparams = {"font.size": 11}
208
+
209
+ def decorator(func):
210
+ """Decorator to apply temporary rc parameters and backend to a function."""
211
+
212
+ def wrapper(*args, **kwargs):
213
+ """Sets rc parameters and backend, calls the original function, and restores the settings."""
214
+ original_backend = plt.get_backend()
215
+ plt.switch_backend(backend)
216
+
217
+ with plt.rc_context(rcparams):
218
+ result = func(*args, **kwargs)
219
+
220
+ plt.switch_backend(original_backend)
221
+ return result
222
+
223
+ return wrapper
224
+
225
+ return decorator
226
+
227
+
228
+ def set_logging(name=LOGGING_NAME, verbose=True):
229
+ """Sets up logging for the given name."""
230
+ rank = int(os.getenv("RANK", -1)) # rank in world for Multi-GPU trainings
231
+ level = logging.INFO if verbose and rank in {-1, 0} else logging.ERROR
232
+ logging.config.dictConfig(
233
+ {
234
+ "version": 1,
235
+ "disable_existing_loggers": False,
236
+ "formatters": {name: {"format": "%(message)s"}},
237
+ "handlers": {
238
+ name: {
239
+ "class": "logging.StreamHandler",
240
+ "formatter": name,
241
+ "level": level,
242
+ }
243
+ },
244
+ "loggers": {
245
+ name: {"level": level, "handlers": [name], "propagate": False}
246
+ },
247
+ }
248
+ )
249
+
250
+
251
+ def emojis(string=""):
252
+ """Return platform-dependent emoji-safe version of string."""
253
+ return string.encode().decode("ascii", "ignore") if WINDOWS else string
254
+
255
+
256
+ class EmojiFilter(logging.Filter):
257
+ """
258
+ A custom logging filter class for removing emojis in log messages.
259
+
260
+ This filter is particularly useful for ensuring compatibility with Windows terminals
261
+ that may not support the display of emojis in log messages.
262
+ """
263
+
264
+ def filter(self, record):
265
+ """Filter logs by emoji unicode characters on windows."""
266
+ record.msg = emojis(record.msg)
267
+ return super().filter(record)
268
+
269
+
270
+ # Set logger
271
+ set_logging(LOGGING_NAME, verbose=VERBOSE) # run before defining LOGGER
272
+ LOGGER = logging.getLogger(
273
+ LOGGING_NAME
274
+ ) # define globally (used in train.py, val.py, detect.py, etc.)
275
+ if WINDOWS: # emoji-safe logging
276
+ LOGGER.addFilter(EmojiFilter())
277
+
278
+
279
+ def yaml_save(file="data.yaml", data=None):
280
+ """
281
+ Save YAML data to a file.
282
+
283
+ Args:
284
+ file (str, optional): File name. Default is 'data.yaml'.
285
+ data (dict): Data to save in YAML format.
286
+
287
+ Returns:
288
+ (None): Data is saved to the specified file.
289
+ """
290
+ if data is None:
291
+ data = {}
292
+ file = Path(file)
293
+ if not file.parent.exists():
294
+ # Create parent directories if they don't exist
295
+ file.parent.mkdir(parents=True, exist_ok=True)
296
+
297
+ # Convert Path objects to strings
298
+ for k, v in data.items():
299
+ if isinstance(v, Path):
300
+ data[k] = str(v)
301
+
302
+ # Dump data to file in YAML format
303
+ with open(file, "w") as f:
304
+ yaml.safe_dump(data, f, sort_keys=False, allow_unicode=True)
305
+
306
+
307
+ def yaml_load(file="data.yaml", append_filename=False):
308
+ """
309
+ Load YAML data from a file.
310
+
311
+ Args:
312
+ file (str, optional): File name. Default is 'data.yaml'.
313
+ append_filename (bool): Add the YAML filename to the YAML dictionary. Default is False.
314
+
315
+ Returns:
316
+ (dict): YAML data and file name.
317
+ """
318
+ with open(file, errors="ignore", encoding="utf-8") as f:
319
+ s = f.read() # string
320
+
321
+ # Remove special characters
322
+ if not s.isprintable():
323
+ s = re.sub(
324
+ r"[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010ffff]+",
325
+ "",
326
+ s,
327
+ )
328
+
329
+ # Add YAML filename to dict and return
330
+ return (
331
+ {**yaml.safe_load(s), "yaml_file": str(file)}
332
+ if append_filename
333
+ else yaml.safe_load(s)
334
+ )
335
+
336
+
337
+ def yaml_print(yaml_file: Union[str, Path, dict]) -> None:
338
+ """
339
+ Pretty prints a yaml file or a yaml-formatted dictionary.
340
+
341
+ Args:
342
+ yaml_file: The file path of the yaml file or a yaml-formatted dictionary.
343
+
344
+ Returns:
345
+ None
346
+ """
347
+ yaml_dict = (
348
+ yaml_load(yaml_file)
349
+ if isinstance(yaml_file, (str, Path))
350
+ else yaml_file
351
+ )
352
+ dump = yaml.dump(yaml_dict, sort_keys=False, allow_unicode=True)
353
+ LOGGER.info(f"Printing '{colorstr('bold', 'black', yaml_file)}'\n\n{dump}")
354
+
355
+
356
+ # Default configuration
357
+ DEFAULT_CFG_DICT = yaml_load(DEFAULT_CFG_PATH)
358
+ for k, v in DEFAULT_CFG_DICT.items():
359
+ if isinstance(v, str) and v.lower() == "none":
360
+ DEFAULT_CFG_DICT[k] = None
361
+ DEFAULT_CFG_KEYS = DEFAULT_CFG_DICT.keys()
362
+ DEFAULT_CFG = IterableSimpleNamespace(**DEFAULT_CFG_DICT)
363
+
364
+
365
+ def is_colab():
366
+ """
367
+ Check if the current script is running inside a Google Colab notebook.
368
+
369
+ Returns:
370
+ (bool): True if running inside a Colab notebook, False otherwise.
371
+ """
372
+ return (
373
+ "COLAB_RELEASE_TAG" in os.environ
374
+ or "COLAB_BACKEND_VERSION" in os.environ
375
+ )
376
+
377
+
378
+ def is_kaggle():
379
+ """
380
+ Check if the current script is running inside a Kaggle kernel.
381
+
382
+ Returns:
383
+ (bool): True if running inside a Kaggle kernel, False otherwise.
384
+ """
385
+ return (
386
+ os.environ.get("PWD") == "/kaggle/working"
387
+ and os.environ.get("KAGGLE_URL_BASE") == "https://www.kaggle.com"
388
+ )
389
+
390
+
391
+ def is_jupyter():
392
+ """
393
+ Check if the current script is running inside a Jupyter Notebook.
394
+ Verified on Colab, Jupyterlab, Kaggle, Paperspace.
395
+
396
+ Returns:
397
+ (bool): True if running inside a Jupyter Notebook, False otherwise.
398
+ """
399
+ with contextlib.suppress(Exception):
400
+ from IPython import get_ipython
401
+
402
+ return get_ipython() is not None
403
+ return False
404
+
405
+
406
+ def is_docker() -> bool:
407
+ """
408
+ Determine if the script is running inside a Docker container.
409
+
410
+ Returns:
411
+ (bool): True if the script is running inside a Docker container, False otherwise.
412
+ """
413
+ file = Path("/proc/self/cgroup")
414
+ if file.exists():
415
+ with open(file) as f:
416
+ return "docker" in f.read()
417
+ else:
418
+ return False
419
+
420
+
421
+ def is_online() -> bool:
422
+ """
423
+ Check internet connectivity by attempting to connect to a known online host.
424
+
425
+ Returns:
426
+ (bool): True if connection is successful, False otherwise.
427
+ """
428
+ import socket
429
+
430
+ for host in (
431
+ "1.1.1.1",
432
+ "8.8.8.8",
433
+ "223.5.5.5",
434
+ ): # Cloudflare, Google, AliDNS:
435
+ try:
436
+ test_connection = socket.create_connection(
437
+ address=(host, 53), timeout=2
438
+ )
439
+ except (socket.timeout, socket.gaierror, OSError):
440
+ continue
441
+ else:
442
+ # If the connection was successful, close it to avoid a ResourceWarning
443
+ test_connection.close()
444
+ return True
445
+ return False
446
+
447
+
448
+ ONLINE = is_online()
449
+
450
+
451
+ def is_pip_package(filepath: str = __name__) -> bool:
452
+ """
453
+ Determines if the file at the given filepath is part of a pip package.
454
+
455
+ Args:
456
+ filepath (str): The filepath to check.
457
+
458
+ Returns:
459
+ (bool): True if the file is part of a pip package, False otherwise.
460
+ """
461
+ import importlib.util
462
+
463
+ # Get the spec for the module
464
+ spec = importlib.util.find_spec(filepath)
465
+
466
+ # Return whether the spec is not None and the origin is not None (indicating it is a package)
467
+ return spec is not None and spec.origin is not None
468
+
469
+
470
+ def is_dir_writeable(dir_path: Union[str, Path]) -> bool:
471
+ """
472
+ Check if a directory is writeable.
473
+
474
+ Args:
475
+ dir_path (str | Path): The path to the directory.
476
+
477
+ Returns:
478
+ (bool): True if the directory is writeable, False otherwise.
479
+ """
480
+ return os.access(str(dir_path), os.W_OK)
481
+
482
+
483
+ def is_pytest_running():
484
+ """
485
+ Determines whether pytest is currently running or not.
486
+
487
+ Returns:
488
+ (bool): True if pytest is running, False otherwise.
489
+ """
490
+ return (
491
+ ("PYTEST_CURRENT_TEST" in os.environ)
492
+ or ("pytest" in sys.modules)
493
+ or ("pytest" in Path(sys.argv[0]).stem)
494
+ )
495
+
496
+
497
+ def is_github_actions_ci() -> bool:
498
+ """
499
+ Determine if the current environment is a GitHub Actions CI Python runner.
500
+
501
+ Returns:
502
+ (bool): True if the current environment is a GitHub Actions CI Python runner, False otherwise.
503
+ """
504
+ return (
505
+ "GITHUB_ACTIONS" in os.environ
506
+ and "RUNNER_OS" in os.environ
507
+ and "RUNNER_TOOL_CACHE" in os.environ
508
+ )
509
+
510
+
511
+ def is_git_dir():
512
+ """
513
+ Determines whether the current file is part of a git repository.
514
+ If the current file is not part of a git repository, returns None.
515
+
516
+ Returns:
517
+ (bool): True if current file is part of a git repository.
518
+ """
519
+ return get_git_dir() is not None
520
+
521
+
522
+ def get_git_dir():
523
+ """
524
+ Determines whether the current file is part of a git repository and if so, returns the repository root directory.
525
+ If the current file is not part of a git repository, returns None.
526
+
527
+ Returns:
528
+ (Path | None): Git root directory if found or None if not found.
529
+ """
530
+ for d in Path(__file__).parents:
531
+ if (d / ".git").is_dir():
532
+ return d
533
+ return None # no .git dir found
534
+
535
+
536
+ def get_git_origin_url():
537
+ """
538
+ Retrieves the origin URL of a git repository.
539
+
540
+ Returns:
541
+ (str | None): The origin URL of the git repository.
542
+ """
543
+ if is_git_dir():
544
+ with contextlib.suppress(subprocess.CalledProcessError):
545
+ origin = subprocess.check_output(
546
+ ["git", "config", "--get", "remote.origin.url"]
547
+ )
548
+ return origin.decode().strip()
549
+ return None # if not git dir or on error
550
+
551
+
552
+ def get_git_branch():
553
+ """
554
+ Returns the current git branch name. If not in a git repository, returns None.
555
+
556
+ Returns:
557
+ (str | None): The current git branch name.
558
+ """
559
+ if is_git_dir():
560
+ with contextlib.suppress(subprocess.CalledProcessError):
561
+ origin = subprocess.check_output(
562
+ ["git", "rev-parse", "--abbrev-ref", "HEAD"]
563
+ )
564
+ return origin.decode().strip()
565
+ return None # if not git dir or on error
566
+
567
+
568
+ def get_default_args(func):
569
+ """Returns a dictionary of default arguments for a function.
570
+
571
+ Args:
572
+ func (callable): The function to inspect.
573
+
574
+ Returns:
575
+ (dict): A dictionary where each key is a parameter name, and each value is the default value of that parameter.
576
+ """
577
+ signature = inspect.signature(func)
578
+ return {
579
+ k: v.default
580
+ for k, v in signature.parameters.items()
581
+ if v.default is not inspect.Parameter.empty
582
+ }
583
+
584
+
585
+ def get_user_config_dir(sub_dir="Ultralytics"):
586
+ """
587
+ Get the user config directory.
588
+
589
+ Args:
590
+ sub_dir (str): The name of the subdirectory to create.
591
+
592
+ Returns:
593
+ (Path): The path to the user config directory.
594
+ """
595
+ # Return the appropriate config directory for each operating system
596
+ if WINDOWS:
597
+ path = Path.home() / "AppData" / "Roaming" / sub_dir
598
+ elif MACOS: # macOS
599
+ path = Path.home() / "Library" / "Application Support" / sub_dir
600
+ elif LINUX:
601
+ path = Path.home() / ".config" / sub_dir
602
+ else:
603
+ raise ValueError(f"Unsupported operating system: {platform.system()}")
604
+
605
+ # GCP and AWS lambda fix, only /tmp is writeable
606
+ if not is_dir_writeable(str(path.parent)):
607
+ path = Path("/tmp") / sub_dir
608
+ LOGGER.warning(
609
+ f"WARNING ⚠️ user config directory is not writeable, defaulting to '{path}'."
610
+ )
611
+
612
+ # Create the subdirectory if it does not exist
613
+ path.mkdir(parents=True, exist_ok=True)
614
+
615
+ return path
616
+
617
+
618
+ USER_CONFIG_DIR = Path(
619
+ os.getenv("YOLO_CONFIG_DIR", get_user_config_dir())
620
+ ) # Ultralytics settings dir
621
+ SETTINGS_YAML = USER_CONFIG_DIR / "settings.yaml"
622
+
623
+
624
+ def colorstr(*input):
625
+ """Colors a string https://en.wikipedia.org/wiki/ANSI_escape_code, i.e. colorstr('blue', 'hello world')."""
626
+ *args, string = (
627
+ input if len(input) > 1 else ("blue", "bold", input[0])
628
+ ) # color arguments, string
629
+ colors = {
630
+ "black": "\033[30m", # basic colors
631
+ "red": "\033[31m",
632
+ "green": "\033[32m",
633
+ "yellow": "\033[33m",
634
+ "blue": "\033[34m",
635
+ "magenta": "\033[35m",
636
+ "cyan": "\033[36m",
637
+ "white": "\033[37m",
638
+ "bright_black": "\033[90m", # bright colors
639
+ "bright_red": "\033[91m",
640
+ "bright_green": "\033[92m",
641
+ "bright_yellow": "\033[93m",
642
+ "bright_blue": "\033[94m",
643
+ "bright_magenta": "\033[95m",
644
+ "bright_cyan": "\033[96m",
645
+ "bright_white": "\033[97m",
646
+ "end": "\033[0m", # misc
647
+ "bold": "\033[1m",
648
+ "underline": "\033[4m",
649
+ }
650
+ return "".join(colors[x] for x in args) + f"{string}" + colors["end"]
651
+
652
+
653
+ class TryExcept(contextlib.ContextDecorator):
654
+ """YOLOv8 TryExcept class. Usage: @TryExcept() decorator or 'with TryExcept():' context manager."""
655
+
656
+ def __init__(self, msg="", verbose=True):
657
+ """Initialize TryExcept class with optional message and verbosity settings."""
658
+ self.msg = msg
659
+ self.verbose = verbose
660
+
661
+ def __enter__(self):
662
+ """Executes when entering TryExcept context, initializes instance."""
663
+ pass
664
+
665
+ def __exit__(self, exc_type, value, traceback):
666
+ """Defines behavior when exiting a 'with' block, prints error message if necessary."""
667
+ if self.verbose and value:
668
+ print(emojis(f"{self.msg}{': ' if self.msg else ''}{value}"))
669
+ return True
670
+
671
+
672
+ def threaded(func):
673
+ """Multi-threads a target function and returns thread. Usage: @threaded decorator."""
674
+
675
+ def wrapper(*args, **kwargs):
676
+ """Multi-threads a given function and returns the thread."""
677
+ thread = threading.Thread(
678
+ target=func, args=args, kwargs=kwargs, daemon=True
679
+ )
680
+ thread.start()
681
+ return thread
682
+
683
+ return wrapper
684
+
685
+
686
+ def set_sentry():
687
+ """
688
+ Initialize the Sentry SDK for error tracking and reporting. Only used if sentry_sdk package is installed and
689
+ sync=True in settings. Run 'yolo settings' to see and update settings YAML file.
690
+
691
+ Conditions required to send errors (ALL conditions must be met or no errors will be reported):
692
+ - sentry_sdk package is installed
693
+ - sync=True in YOLO settings
694
+ - pytest is not running
695
+ - running in a pip package installation
696
+ - running in a non-git directory
697
+ - running with rank -1 or 0
698
+ - online environment
699
+ - CLI used to run package (checked with 'yolo' as the name of the main CLI command)
700
+
701
+ The function also configures Sentry SDK to ignore KeyboardInterrupt and FileNotFoundError
702
+ exceptions and to exclude events with 'out of memory' in their exception message.
703
+
704
+ Additionally, the function sets custom tags and user information for Sentry events.
705
+ """
706
+
707
+ def before_send(event, hint):
708
+ """
709
+ Modify the event before sending it to Sentry based on specific exception types and messages.
710
+
711
+ Args:
712
+ event (dict): The event dictionary containing information about the error.
713
+ hint (dict): A dictionary containing additional information about the error.
714
+
715
+ Returns:
716
+ dict: The modified event or None if the event should not be sent to Sentry.
717
+ """
718
+ if "exc_info" in hint:
719
+ exc_type, exc_value, tb = hint["exc_info"]
720
+ if exc_type in (
721
+ KeyboardInterrupt,
722
+ FileNotFoundError,
723
+ ) or "out of memory" in str(exc_value):
724
+ return None # do not send event
725
+
726
+ event["tags"] = {
727
+ "sys_argv": sys.argv[0],
728
+ "sys_argv_name": Path(sys.argv[0]).name,
729
+ "install": (
730
+ "git"
731
+ if is_git_dir()
732
+ else "pip" if is_pip_package() else "other"
733
+ ),
734
+ "os": ENVIRONMENT,
735
+ }
736
+ return event
737
+
738
+ if (
739
+ SETTINGS["sync"]
740
+ and RANK in (-1, 0)
741
+ and Path(sys.argv[0]).name == "yolo"
742
+ and not TESTS_RUNNING
743
+ and ONLINE
744
+ and is_pip_package()
745
+ and not is_git_dir()
746
+ ):
747
+
748
+ # If sentry_sdk package is not installed then return and do not use Sentry
749
+ try:
750
+ import sentry_sdk # noqa
751
+ except ImportError:
752
+ return
753
+
754
+ sentry_sdk.init(
755
+ dsn="https://5ff1556b71594bfea135ff0203a0d290@o4504521589325824.ingest.sentry.io/4504521592406016",
756
+ debug=False,
757
+ traces_sample_rate=1.0,
758
+ release=__version__,
759
+ environment="production", # 'dev' or 'production'
760
+ before_send=before_send,
761
+ ignore_errors=[KeyboardInterrupt, FileNotFoundError],
762
+ )
763
+ sentry_sdk.set_user(
764
+ {"id": SETTINGS["uuid"]}
765
+ ) # SHA-256 anonymized UUID hash
766
+
767
+ # Disable all sentry logging
768
+ for logger in "sentry_sdk", "sentry_sdk.errors":
769
+ logging.getLogger(logger).setLevel(logging.CRITICAL)
770
+
771
+
772
+ def get_settings(file=SETTINGS_YAML, version="0.0.3"):
773
+ """
774
+ Loads a global Ultralytics settings YAML file or creates one with default values if it does not exist.
775
+
776
+ Args:
777
+ file (Path): Path to the Ultralytics settings YAML file. Defaults to 'settings.yaml' in the USER_CONFIG_DIR.
778
+ version (str): Settings version. If min settings version not met, new default settings will be saved.
779
+
780
+ Returns:
781
+ (dict): Dictionary of settings key-value pairs.
782
+ """
783
+ import hashlib
784
+
785
+ from ..utils.checks import check_version
786
+ from ..utils.torch_utils import torch_distributed_zero_first
787
+
788
+ git_dir = get_git_dir()
789
+ root = git_dir or Path()
790
+ datasets_root = (
791
+ root.parent if git_dir and is_dir_writeable(root.parent) else root
792
+ ).resolve()
793
+ defaults = {
794
+ "datasets_dir": str(
795
+ datasets_root / "datasets"
796
+ ), # default datasets directory.
797
+ "weights_dir": str(root / "weights"), # default weights directory.
798
+ "runs_dir": str(root / "runs"), # default runs directory.
799
+ "uuid": hashlib.sha256(
800
+ str(uuid.getnode()).encode()
801
+ ).hexdigest(), # SHA-256 anonymized UUID hash
802
+ "sync": True, # sync analytics to help with YOLO development
803
+ "api_key": "", # Ultralytics HUB API key (https://hub.ultralytics.com/)
804
+ "settings_version": version,
805
+ } # Ultralytics settings version
806
+
807
+ with torch_distributed_zero_first(RANK):
808
+ if not file.exists():
809
+ yaml_save(file, defaults)
810
+ settings = yaml_load(file)
811
+
812
+ # Check that settings keys and types match defaults
813
+ correct = (
814
+ settings
815
+ and settings.keys() == defaults.keys()
816
+ and all(
817
+ type(a) == type(b)
818
+ for a, b in zip(settings.values(), defaults.values())
819
+ )
820
+ and check_version(settings["settings_version"], version)
821
+ )
822
+ if not correct:
823
+ settings = defaults # merge **defaults with **settings (prefer **settings)
824
+ yaml_save(file, settings) # save updated defaults
825
+
826
+ return settings
827
+
828
+
829
+ def set_settings(kwargs, file=SETTINGS_YAML):
830
+ """
831
+ Function that runs on a first-time ultralytics package installation to set up global settings and create necessary
832
+ directories.
833
+ """
834
+ SETTINGS.update(kwargs)
835
+ yaml_save(file, SETTINGS)
836
+
837
+
838
+ def deprecation_warn(arg, new_arg, version=None):
839
+ """Issue a deprecation warning when a deprecated argument is used, suggesting an updated argument."""
840
+ if not version:
841
+ version = (
842
+ float(__version__[:3]) + 0.2
843
+ ) # deprecate after 2nd major release
844
+ LOGGER.warning(
845
+ f"WARNING ⚠️ '{arg}' is deprecated and will be removed in 'ultralytics {version}' in the future. "
846
+ f"Please use '{new_arg}' instead."
847
+ )
848
+
849
+
850
+ def clean_url(url):
851
+ """Strip auth from URL, i.e. https://url.com/file.txt?auth -> https://url.com/file.txt."""
852
+ url = str(Path(url)).replace(":/", "://") # Pathlib turns :// -> :/
853
+ return urllib.parse.unquote(url).split("?")[
854
+ 0
855
+ ] # '%2F' to '/', split https://url.com/file.txt?auth
856
+
857
+
858
+ def url2file(url):
859
+ """Convert URL to filename, i.e. https://url.com/file.txt?auth -> file.txt."""
860
+ return Path(clean_url(url)).name
861
+
862
+
863
+ # Run below code on yolo/utils init ------------------------------------------------------------------------------------
864
+
865
+ # Check first-install steps
866
+ PREFIX = colorstr("Ultralytics: ")
867
+ SETTINGS = get_settings()
868
+ DATASETS_DIR = Path(SETTINGS["datasets_dir"]) # global datasets directory
869
+ ENVIRONMENT = (
870
+ "Colab"
871
+ if is_colab()
872
+ else (
873
+ "Kaggle"
874
+ if is_kaggle()
875
+ else (
876
+ "Jupyter"
877
+ if is_jupyter()
878
+ else "Docker" if is_docker() else platform.system()
879
+ )
880
+ )
881
+ )
882
+ TESTS_RUNNING = is_pytest_running() or is_github_actions_ci()
883
+ set_sentry()
884
+
885
+ # Apply monkey patches if the script is being run from within the parent directory of the script's location
886
+ from .patches import imread, imshow, imwrite
887
+
888
+ # torch.save = torch_save
889
+ if (
890
+ Path(inspect.stack()[0].filename).parent.parent.as_posix()
891
+ in inspect.stack()[-1].filename
892
+ ):
893
+ cv2.imread, cv2.imwrite, cv2.imshow = imread, imwrite, imshow