dgenerate-ultralytics-headless 8.3.185__py3-none-any.whl → 8.3.187__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 (31) hide show
  1. {dgenerate_ultralytics_headless-8.3.185.dist-info → dgenerate_ultralytics_headless-8.3.187.dist-info}/METADATA +6 -8
  2. {dgenerate_ultralytics_headless-8.3.185.dist-info → dgenerate_ultralytics_headless-8.3.187.dist-info}/RECORD +31 -30
  3. tests/test_python.py +2 -10
  4. ultralytics/__init__.py +1 -1
  5. ultralytics/cfg/datasets/Argoverse.yaml +2 -2
  6. ultralytics/cfg/datasets/Objects365.yaml +3 -3
  7. ultralytics/cfg/datasets/SKU-110K.yaml +4 -4
  8. ultralytics/cfg/datasets/VOC.yaml +2 -4
  9. ultralytics/cfg/datasets/VisDrone.yaml +2 -2
  10. ultralytics/cfg/datasets/xView.yaml +2 -2
  11. ultralytics/data/build.py +2 -2
  12. ultralytics/data/utils.py +0 -2
  13. ultralytics/engine/exporter.py +4 -1
  14. ultralytics/engine/results.py +1 -4
  15. ultralytics/engine/trainer.py +3 -3
  16. ultralytics/models/sam/__init__.py +8 -2
  17. ultralytics/models/sam/modules/sam.py +6 -6
  18. ultralytics/models/sam/predict.py +363 -6
  19. ultralytics/solutions/region_counter.py +3 -2
  20. ultralytics/utils/__init__.py +25 -162
  21. ultralytics/utils/autodevice.py +1 -1
  22. ultralytics/utils/benchmarks.py +9 -8
  23. ultralytics/utils/callbacks/wb.py +9 -3
  24. ultralytics/utils/downloads.py +29 -19
  25. ultralytics/utils/logger.py +10 -11
  26. ultralytics/utils/plotting.py +13 -20
  27. ultralytics/utils/tqdm.py +462 -0
  28. {dgenerate_ultralytics_headless-8.3.185.dist-info → dgenerate_ultralytics_headless-8.3.187.dist-info}/WHEEL +0 -0
  29. {dgenerate_ultralytics_headless-8.3.185.dist-info → dgenerate_ultralytics_headless-8.3.187.dist-info}/entry_points.txt +0 -0
  30. {dgenerate_ultralytics_headless-8.3.185.dist-info → dgenerate_ultralytics_headless-8.3.187.dist-info}/licenses/LICENSE +0 -0
  31. {dgenerate_ultralytics_headless-8.3.185.dist-info → dgenerate_ultralytics_headless-8.3.187.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,462 @@
1
+ # Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import sys
7
+ import time
8
+ from functools import lru_cache
9
+ from typing import IO, Any
10
+
11
+
12
+ @lru_cache(maxsize=1)
13
+ def is_noninteractive_console():
14
+ """Check for known non-interactive console environments."""
15
+ return "GITHUB_ACTIONS" in os.environ or "RUNPOD_POD_ID" in os.environ
16
+
17
+
18
+ class TQDM:
19
+ """
20
+ Lightweight zero-dependency progress bar for Ultralytics.
21
+
22
+ Provides clean, rich-style progress bars suitable for various environments including Weights & Biases,
23
+ console outputs, and other logging systems. Features zero external dependencies, clean single-line output,
24
+ rich-style progress bars with Unicode block characters, context manager support, iterator protocol support,
25
+ and dynamic description updates.
26
+
27
+ Attributes:
28
+ iterable (object): Iterable to wrap with progress bar.
29
+ desc (str): Prefix description for the progress bar.
30
+ total (int): Expected number of iterations.
31
+ disable (bool): Whether to disable the progress bar.
32
+ unit (str): String for units of iteration.
33
+ unit_scale (bool): Auto-scale units flag.
34
+ unit_divisor (int): Divisor for unit scaling.
35
+ leave (bool): Whether to leave the progress bar after completion.
36
+ mininterval (float): Minimum time interval between updates.
37
+ initial (int): Initial counter value.
38
+ n (int): Current iteration count.
39
+ closed (bool): Whether the progress bar is closed.
40
+ bar_format (str): Custom bar format string.
41
+ file (object): Output file stream.
42
+
43
+ Methods:
44
+ update: Update progress by n steps.
45
+ set_description: Set or update the description.
46
+ set_postfix: Set postfix for the progress bar.
47
+ close: Close the progress bar and clean up.
48
+ refresh: Refresh the progress bar display.
49
+ clear: Clear the progress bar from display.
50
+ write: Write a message without breaking the progress bar.
51
+
52
+ Examples:
53
+ Basic usage with iterator:
54
+ >>> for i in TQDM(range(100)):
55
+ ... time.sleep(0.01)
56
+
57
+ With custom description:
58
+ >>> pbar = TQDM(range(100), desc="Processing")
59
+ >>> for i in pbar:
60
+ ... pbar.set_description(f"Processing item {i}")
61
+
62
+ Context manager usage:
63
+ >>> with TQDM(total=100, unit="B", unit_scale=True) as pbar:
64
+ ... for i in range(100):
65
+ ... pbar.update(1)
66
+
67
+ Manual updates:
68
+ >>> pbar = TQDM(total=100, desc="Training")
69
+ >>> for epoch in range(100):
70
+ ... # Do work
71
+ ... pbar.update(1)
72
+ >>> pbar.close()
73
+ """
74
+
75
+ # Constants
76
+ MIN_RATE_CALC_INTERVAL = 0.01 # Minimum time interval for rate calculation
77
+ RATE_SMOOTHING_FACTOR = 0.3 # Factor for exponential smoothing of rates
78
+ MAX_SMOOTHED_RATE = 1000000 # Maximum rate to apply smoothing to
79
+ NONINTERACTIVE_MIN_INTERVAL = 60.0 # Minimum interval for non-interactive environments
80
+
81
+ def __init__(
82
+ self,
83
+ iterable: Any = None,
84
+ desc: str | None = None,
85
+ total: int | None = None,
86
+ leave: bool = True,
87
+ file: IO[str] | None = None,
88
+ mininterval: float = 0.1,
89
+ disable: bool | None = None,
90
+ unit: str = "it",
91
+ unit_scale: bool = False,
92
+ unit_divisor: int = 1000,
93
+ bar_format: str | None = None,
94
+ initial: int = 0,
95
+ **kwargs, # Accept unused args for compatibility
96
+ ) -> None:
97
+ """
98
+ Initialize the TQDM progress bar with specified configuration options.
99
+
100
+ Args:
101
+ iterable (object, optional): Iterable to wrap with progress bar.
102
+ desc (str, optional): Prefix description for the progress bar.
103
+ total (int, optional): Expected number of iterations.
104
+ leave (bool, optional): Whether to leave the progress bar after completion.
105
+ file (object, optional): Output file stream for progress display.
106
+ mininterval (float, optional): Minimum time interval between updates (default 0.1s, 60s in GitHub Actions).
107
+ disable (bool, optional): Whether to disable the progress bar. Auto-detected if None.
108
+ unit (str, optional): String for units of iteration (default "it" for items).
109
+ unit_scale (bool, optional): Auto-scale units for bytes/data units.
110
+ unit_divisor (int, optional): Divisor for unit scaling (default 1000).
111
+ bar_format (str, optional): Custom bar format string.
112
+ initial (int, optional): Initial counter value.
113
+ **kwargs (Any): Additional keyword arguments for compatibility (ignored).
114
+
115
+ Examples:
116
+ >>> pbar = TQDM(range(100), desc="Processing")
117
+ >>> with TQDM(total=1000, unit="B", unit_scale=True) as pbar:
118
+ ... pbar.update(1024) # Updates by 1KB
119
+ """
120
+ # Disable if not verbose
121
+ if disable is None:
122
+ try:
123
+ from ultralytics.utils import LOGGER, VERBOSE
124
+
125
+ disable = not VERBOSE or LOGGER.getEffectiveLevel() > 20
126
+ except ImportError:
127
+ disable = False
128
+
129
+ self.iterable = iterable
130
+ self.desc = desc or ""
131
+ self.total = total if total is not None else (len(iterable) if hasattr(iterable, "__len__") else None)
132
+ self.disable = disable
133
+ self.unit = unit
134
+ self.unit_scale = unit_scale
135
+ self.unit_divisor = unit_divisor
136
+ self.leave = leave
137
+ self.noninteractive = is_noninteractive_console()
138
+ self.mininterval = max(mininterval, self.NONINTERACTIVE_MIN_INTERVAL) if self.noninteractive else mininterval
139
+ self.initial = initial
140
+
141
+ # Set bar format based on whether we have a total
142
+ if self.total is not None:
143
+ self.bar_format = bar_format or "{desc}: {percentage:3.0f}% {bar} {n_fmt}/{total_fmt} {rate_fmt} {elapsed}"
144
+ else:
145
+ self.bar_format = bar_format or "{desc}: {bar} {n_fmt} {rate_fmt} {elapsed}"
146
+
147
+ self.file = file or sys.stdout
148
+
149
+ # Internal state
150
+ self.n = self.initial
151
+ self.last_print_n = self.initial
152
+ self.last_print_t = time.time()
153
+ self.start_t = time.time()
154
+ self.last_rate = 0
155
+ self.closed = False
156
+
157
+ # Display initial bar if we have total and not disabled
158
+ if not self.disable and self.total is not None and not self.noninteractive:
159
+ self._display()
160
+
161
+ def _format_rate(self, rate):
162
+ """Format rate with proper units and reasonable precision."""
163
+ if rate <= 0:
164
+ return ""
165
+
166
+ # For bytes with scaling, use binary units
167
+ if self.unit in ("B", "bytes") and self.unit_scale:
168
+ for threshold, unit in [(1024**3, "GB/s"), (1024**2, "MB/s"), (1024, "KB/s")]:
169
+ if rate >= threshold:
170
+ return f"{rate / threshold:.1f}{unit}"
171
+ return f"{rate:.1f}B/s"
172
+
173
+ # For other scalable units, use decimal units
174
+ if self.unit_scale and self.unit in ("it", "items", ""):
175
+ for threshold, prefix in [(1000000, "M"), (1000, "K")]:
176
+ if rate >= threshold:
177
+ return f"{rate / threshold:.1f}{prefix}{self.unit}/s"
178
+
179
+ # Default formatting
180
+ precision = ".1f" if rate >= 1 else ".2f"
181
+ return f"{rate:{precision}}{self.unit}/s"
182
+
183
+ def _format_num(self, num):
184
+ """Format number with optional unit scaling."""
185
+ if not self.unit_scale or self.unit not in ("B", "bytes"):
186
+ return str(num)
187
+
188
+ for unit in ["", "K", "M", "G", "T"]:
189
+ if abs(num) < self.unit_divisor:
190
+ return f"{num:3.1f}{unit}B" if unit else f"{num:.0f}B"
191
+ num /= self.unit_divisor
192
+ return f"{num:.1f}PB"
193
+
194
+ def _format_time(self, seconds):
195
+ """Format time duration."""
196
+ if seconds < 60:
197
+ return f"{seconds:.1f}s"
198
+ elif seconds < 3600:
199
+ return f"{int(seconds // 60)}:{seconds % 60:02.0f}"
200
+ else:
201
+ h, m = int(seconds // 3600), int((seconds % 3600) // 60)
202
+ return f"{h}:{m:02d}:{seconds % 60:02.0f}"
203
+
204
+ def _generate_bar(self, width=12):
205
+ """Generate progress bar."""
206
+ if self.total is None:
207
+ return "━" * width if self.closed else "─" * width
208
+
209
+ frac = min(1.0, self.n / self.total)
210
+ filled = int(frac * width)
211
+ bar = "━" * filled + "─" * (width - filled)
212
+ if filled < width and frac * width - filled > 0.5:
213
+ bar = bar[:filled] + "╸" + bar[filled + 1 :]
214
+ return bar
215
+
216
+ def _should_update(self, dt, dn):
217
+ """Check if display should update."""
218
+ if self.noninteractive:
219
+ return False
220
+
221
+ if self.total is not None and self.n >= self.total:
222
+ return True
223
+
224
+ return dt >= self.mininterval
225
+
226
+ def _display(self, final=False):
227
+ """Display progress bar."""
228
+ if self.disable or (self.closed and not final):
229
+ return
230
+
231
+ current_time = time.time()
232
+ dt = current_time - self.last_print_t
233
+ dn = self.n - self.last_print_n
234
+
235
+ if not final and not self._should_update(dt, dn):
236
+ return
237
+
238
+ # Calculate rate (avoid crazy numbers)
239
+ if dt > self.MIN_RATE_CALC_INTERVAL: # Only calculate rate if enough time has passed
240
+ rate = dn / dt
241
+ # Smooth rate for reasonable values, use raw rate for very high values
242
+ if rate < self.MAX_SMOOTHED_RATE:
243
+ self.last_rate = self.RATE_SMOOTHING_FACTOR * rate + (1 - self.RATE_SMOOTHING_FACTOR) * self.last_rate
244
+ rate = self.last_rate
245
+ else:
246
+ rate = self.last_rate
247
+
248
+ # At completion, use the overall rate for more accurate display
249
+ if self.n >= (self.total or float("inf")) and self.total and self.total > 0:
250
+ overall_elapsed = current_time - self.start_t
251
+ if overall_elapsed > 0:
252
+ rate = self.n / overall_elapsed
253
+
254
+ # Update counters
255
+ self.last_print_n = self.n
256
+ self.last_print_t = current_time
257
+ elapsed = current_time - self.start_t
258
+
259
+ # Build progress components
260
+ if self.total is not None:
261
+ percentage = (self.n / self.total) * 100
262
+ # For bytes with unit scaling, avoid repeating units: show "5.4/5.4MB" not "5.4MB/5.4MB"
263
+ n_fmt = self._format_num(self.n)
264
+ total_fmt = self._format_num(self.total)
265
+ if self.unit_scale and self.unit in ("B", "bytes"):
266
+ n_fmt = n_fmt.rstrip("KMGTPB") # Remove unit suffix from current
267
+ else:
268
+ percentage = 0
269
+ n_fmt = self._format_num(self.n)
270
+ total_fmt = "?"
271
+
272
+ elapsed_str = self._format_time(elapsed)
273
+ rate_fmt = self._format_rate(rate) or (self._format_rate(self.n / elapsed) if elapsed > 0 else "")
274
+
275
+ # Format progress string
276
+ progress_str = self.bar_format.format(
277
+ desc=self.desc,
278
+ percentage=percentage,
279
+ bar=self._generate_bar(),
280
+ n_fmt=n_fmt,
281
+ total_fmt=total_fmt,
282
+ rate_fmt=rate_fmt,
283
+ elapsed=elapsed_str,
284
+ unit=self.unit,
285
+ )
286
+
287
+ # Write to output
288
+ try:
289
+ if self.noninteractive:
290
+ # In non-interactive environments, avoid carriage return which creates empty lines
291
+ self.file.write(progress_str)
292
+ else:
293
+ # In interactive terminals, use carriage return and clear line for updating display
294
+ self.file.write(f"\r\033[K{progress_str}")
295
+ self.file.flush()
296
+ except Exception:
297
+ pass
298
+
299
+ def update(self, n=1):
300
+ """Update progress by n steps."""
301
+ if not self.disable and not self.closed:
302
+ self.n += n
303
+ self._display()
304
+
305
+ def set_description(self, desc):
306
+ """Set description."""
307
+ self.desc = desc or ""
308
+ if not self.disable:
309
+ self._display()
310
+
311
+ def set_postfix(self, **kwargs):
312
+ """Set postfix (appends to description)."""
313
+ if kwargs:
314
+ postfix = ", ".join(f"{k}={v}" for k, v in kwargs.items())
315
+ base_desc = self.desc.split(" | ")[0] if " | " in self.desc else self.desc
316
+ self.set_description(f"{base_desc} | {postfix}")
317
+
318
+ def close(self):
319
+ """Close progress bar."""
320
+ if self.closed:
321
+ return
322
+
323
+ self.closed = True # Set before final display
324
+
325
+ if not self.disable:
326
+ # Final display
327
+ if self.total and self.n >= self.total:
328
+ self.n = self.total
329
+ self._display(final=True)
330
+
331
+ # Cleanup
332
+ if self.leave:
333
+ self.file.write("\n")
334
+ else:
335
+ self.file.write("\r\033[K")
336
+
337
+ try:
338
+ self.file.flush()
339
+ except Exception:
340
+ pass
341
+
342
+ def __enter__(self):
343
+ """Enter context manager."""
344
+ return self
345
+
346
+ def __exit__(self, *args):
347
+ """Exit context manager and close progress bar."""
348
+ self.close()
349
+
350
+ def __iter__(self):
351
+ """Iterate over the wrapped iterable with progress updates."""
352
+ if self.iterable is None:
353
+ raise TypeError("'NoneType' object is not iterable")
354
+
355
+ try:
356
+ for item in self.iterable:
357
+ yield item
358
+ self.update(1)
359
+ finally:
360
+ self.close()
361
+
362
+ def __del__(self):
363
+ """Destructor to ensure cleanup."""
364
+ try:
365
+ self.close()
366
+ except Exception:
367
+ pass
368
+
369
+ def refresh(self):
370
+ """Refresh display."""
371
+ if not self.disable:
372
+ self._display()
373
+
374
+ def clear(self):
375
+ """Clear progress bar."""
376
+ if not self.disable:
377
+ try:
378
+ self.file.write("\r\033[K")
379
+ self.file.flush()
380
+ except Exception:
381
+ pass
382
+
383
+ @staticmethod
384
+ def write(s, file=None, end="\n"):
385
+ """Static method to write without breaking progress bar."""
386
+ file = file or sys.stdout
387
+ try:
388
+ file.write(s + end)
389
+ file.flush()
390
+ except Exception:
391
+ pass
392
+
393
+
394
+ if __name__ == "__main__":
395
+ import time
396
+
397
+ # Example 1: Basic usage with known total
398
+ print("1. Basic progress bar with known total:")
399
+ for i in TQDM(range(20), desc="Known total"):
400
+ time.sleep(0.05)
401
+ print()
402
+
403
+ # Example 2: Manual updates with known total
404
+ print("2. Manual updates with known total:")
405
+ pbar = TQDM(total=30, desc="Manual updates", unit="files")
406
+ for i in range(30):
407
+ time.sleep(0.03)
408
+ pbar.update(1)
409
+ if i % 10 == 9:
410
+ pbar.set_description(f"Processing batch {i // 10 + 1}")
411
+ pbar.close()
412
+ print()
413
+
414
+ # Example 3: Unknown total - this was the problematic case
415
+ print("3. Progress bar with unknown total:")
416
+ pbar = TQDM(desc="Unknown total", unit="items")
417
+ for i in range(25):
418
+ time.sleep(0.08)
419
+ pbar.update(1)
420
+ if i % 5 == 4:
421
+ pbar.set_postfix(processed=i + 1, status="OK")
422
+ pbar.close()
423
+ print()
424
+
425
+ # Example 4: Context manager with unknown total
426
+ print("4. Context manager with unknown total:")
427
+ with TQDM(desc="Processing stream", unit="B", unit_scale=True, unit_divisor=1024) as pbar:
428
+ for i in range(30):
429
+ time.sleep(0.1)
430
+ pbar.update(1024 * 1024 * i) # Simulate processing MB of data
431
+ print()
432
+
433
+ # Example 5: Generator with unknown length
434
+ print("5. Iterator with unknown length:")
435
+
436
+ def data_stream():
437
+ """Simulate a data stream of unknown length."""
438
+ import random
439
+
440
+ for i in range(random.randint(10, 20)):
441
+ yield f"data_chunk_{i}"
442
+
443
+ for chunk in TQDM(data_stream(), desc="Stream processing", unit="chunks"):
444
+ time.sleep(0.1)
445
+ print()
446
+
447
+ # Example 6: File-like processing simulation
448
+ print("6. File processing simulation (unknown size):")
449
+
450
+ def process_files():
451
+ """Simulate processing files of unknown count."""
452
+ files = [f"file_{i}.txt" for i in range(18)]
453
+ return files
454
+
455
+ pbar = TQDM(desc="Scanning files", unit="files")
456
+ files = process_files()
457
+ for i, filename in enumerate(files):
458
+ time.sleep(0.06)
459
+ pbar.update(1)
460
+ pbar.set_description(f"Processing {filename}")
461
+ pbar.close()
462
+ print()