dgenerate-ultralytics-headless 8.3.186__py3-none-any.whl → 8.3.189__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 (28) hide show
  1. {dgenerate_ultralytics_headless-8.3.186.dist-info → dgenerate_ultralytics_headless-8.3.189.dist-info}/METADATA +6 -6
  2. {dgenerate_ultralytics_headless-8.3.186.dist-info → dgenerate_ultralytics_headless-8.3.189.dist-info}/RECORD +28 -28
  3. tests/test_python.py +2 -10
  4. ultralytics/__init__.py +1 -1
  5. ultralytics/cfg/datasets/SKU-110K.yaml +2 -2
  6. ultralytics/engine/exporter.py +4 -4
  7. ultralytics/engine/results.py +1 -4
  8. ultralytics/engine/trainer.py +3 -3
  9. ultralytics/models/rtdetr/val.py +3 -1
  10. ultralytics/models/sam/__init__.py +8 -2
  11. ultralytics/models/sam/modules/sam.py +6 -6
  12. ultralytics/models/sam/predict.py +363 -6
  13. ultralytics/models/yolo/detect/val.py +13 -2
  14. ultralytics/models/yolo/obb/val.py +3 -1
  15. ultralytics/models/yolo/segment/val.py +0 -3
  16. ultralytics/nn/autobackend.py +6 -3
  17. ultralytics/nn/tasks.py +2 -2
  18. ultralytics/utils/__init__.py +39 -94
  19. ultralytics/utils/benchmarks.py +16 -9
  20. ultralytics/utils/callbacks/wb.py +9 -3
  21. ultralytics/utils/downloads.py +44 -38
  22. ultralytics/utils/plotting.py +13 -20
  23. ultralytics/utils/torch_utils.py +50 -47
  24. ultralytics/utils/tqdm.py +25 -37
  25. {dgenerate_ultralytics_headless-8.3.186.dist-info → dgenerate_ultralytics_headless-8.3.189.dist-info}/WHEEL +0 -0
  26. {dgenerate_ultralytics_headless-8.3.186.dist-info → dgenerate_ultralytics_headless-8.3.189.dist-info}/entry_points.txt +0 -0
  27. {dgenerate_ultralytics_headless-8.3.186.dist-info → dgenerate_ultralytics_headless-8.3.189.dist-info}/licenses/LICENSE +0 -0
  28. {dgenerate_ultralytics_headless-8.3.186.dist-info → dgenerate_ultralytics_headless-8.3.189.dist-info}/top_level.txt +0 -0
@@ -250,68 +250,71 @@ def time_sync():
250
250
 
251
251
 
252
252
  def fuse_conv_and_bn(conv, bn):
253
- """Fuse Conv2d() and BatchNorm2d() layers."""
254
- fusedconv = (
255
- nn.Conv2d(
256
- conv.in_channels,
257
- conv.out_channels,
258
- kernel_size=conv.kernel_size,
259
- stride=conv.stride,
260
- padding=conv.padding,
261
- dilation=conv.dilation,
262
- groups=conv.groups,
263
- bias=True,
264
- )
265
- .requires_grad_(False)
266
- .to(conv.weight.device)
267
- )
253
+ """
254
+ Fuse Conv2d and BatchNorm2d layers for inference optimization.
255
+
256
+ Args:
257
+ conv (nn.Conv2d): Convolutional layer to fuse.
258
+ bn (nn.BatchNorm2d): Batch normalization layer to fuse.
259
+
260
+ Returns:
261
+ (nn.Conv2d): The fused convolutional layer with gradients disabled.
268
262
 
269
- # Prepare filters
263
+ Example:
264
+ >>> conv = nn.Conv2d(3, 16, 3)
265
+ >>> bn = nn.BatchNorm2d(16)
266
+ >>> fused_conv = fuse_conv_and_bn(conv, bn)
267
+ """
268
+ # Compute fused weights
270
269
  w_conv = conv.weight.view(conv.out_channels, -1)
271
270
  w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var)))
272
- fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.shape))
271
+ conv.weight.data = torch.mm(w_bn, w_conv).view(conv.weight.shape)
273
272
 
274
- # Prepare spatial bias
275
- b_conv = (
276
- torch.zeros(conv.weight.shape[0], dtype=conv.weight.dtype, device=conv.weight.device)
277
- if conv.bias is None
278
- else conv.bias
279
- )
273
+ # Compute fused bias
274
+ b_conv = torch.zeros(conv.out_channels, device=conv.weight.device) if conv.bias is None else conv.bias
280
275
  b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps))
281
- fusedconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn)
276
+ fused_bias = torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn
277
+
278
+ if conv.bias is None:
279
+ conv.register_parameter("bias", nn.Parameter(fused_bias))
280
+ else:
281
+ conv.bias.data = fused_bias
282
282
 
283
- return fusedconv
283
+ return conv.requires_grad_(False)
284
284
 
285
285
 
286
286
  def fuse_deconv_and_bn(deconv, bn):
287
- """Fuse ConvTranspose2d() and BatchNorm2d() layers."""
288
- fuseddconv = (
289
- nn.ConvTranspose2d(
290
- deconv.in_channels,
291
- deconv.out_channels,
292
- kernel_size=deconv.kernel_size,
293
- stride=deconv.stride,
294
- padding=deconv.padding,
295
- output_padding=deconv.output_padding,
296
- dilation=deconv.dilation,
297
- groups=deconv.groups,
298
- bias=True,
299
- )
300
- .requires_grad_(False)
301
- .to(deconv.weight.device)
302
- )
287
+ """
288
+ Fuse ConvTranspose2d and BatchNorm2d layers for inference optimization.
303
289
 
304
- # Prepare filters
290
+ Args:
291
+ deconv (nn.ConvTranspose2d): Transposed convolutional layer to fuse.
292
+ bn (nn.BatchNorm2d): Batch normalization layer to fuse.
293
+
294
+ Returns:
295
+ (nn.ConvTranspose2d): The fused transposed convolutional layer with gradients disabled.
296
+
297
+ Example:
298
+ >>> deconv = nn.ConvTranspose2d(16, 3, 3)
299
+ >>> bn = nn.BatchNorm2d(3)
300
+ >>> fused_deconv = fuse_deconv_and_bn(deconv, bn)
301
+ """
302
+ # Compute fused weights
305
303
  w_deconv = deconv.weight.view(deconv.out_channels, -1)
306
304
  w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var)))
307
- fuseddconv.weight.copy_(torch.mm(w_bn, w_deconv).view(fuseddconv.weight.shape))
305
+ deconv.weight.data = torch.mm(w_bn, w_deconv).view(deconv.weight.shape)
308
306
 
309
- # Prepare spatial bias
310
- b_conv = torch.zeros(deconv.weight.shape[1], device=deconv.weight.device) if deconv.bias is None else deconv.bias
307
+ # Compute fused bias
308
+ b_conv = torch.zeros(deconv.out_channels, device=deconv.weight.device) if deconv.bias is None else deconv.bias
311
309
  b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps))
312
- fuseddconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn)
310
+ fused_bias = torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn
311
+
312
+ if deconv.bias is None:
313
+ deconv.register_parameter("bias", nn.Parameter(fused_bias))
314
+ else:
315
+ deconv.bias.data = fused_bias
313
316
 
314
- return fuseddconv
317
+ return deconv.requires_grad_(False)
315
318
 
316
319
 
317
320
  def model_info(model, detailed=False, verbose=True, imgsz=640):
ultralytics/utils/tqdm.py CHANGED
@@ -10,7 +10,7 @@ from typing import IO, Any
10
10
 
11
11
 
12
12
  @lru_cache(maxsize=1)
13
- def is_noninteractive_console():
13
+ def is_noninteractive_console() -> bool:
14
14
  """Check for known non-interactive console environments."""
15
15
  return "GITHUB_ACTIONS" in os.environ or "RUNPOD_POD_ID" in os.environ
16
16
 
@@ -128,7 +128,7 @@ class TQDM:
128
128
 
129
129
  self.iterable = iterable
130
130
  self.desc = desc or ""
131
- self.total = total if total is not None else (len(iterable) if hasattr(iterable, "__len__") else None)
131
+ self.total = total or (len(iterable) if hasattr(iterable, "__len__") else None) or None # prevent total=0
132
132
  self.disable = disable
133
133
  self.unit = unit
134
134
  self.unit_scale = unit_scale
@@ -158,7 +158,7 @@ class TQDM:
158
158
  if not self.disable and self.total is not None and not self.noninteractive:
159
159
  self._display()
160
160
 
161
- def _format_rate(self, rate):
161
+ def _format_rate(self, rate: float) -> str:
162
162
  """Format rate with proper units and reasonable precision."""
163
163
  if rate <= 0:
164
164
  return ""
@@ -180,7 +180,7 @@ class TQDM:
180
180
  precision = ".1f" if rate >= 1 else ".2f"
181
181
  return f"{rate:{precision}}{self.unit}/s"
182
182
 
183
- def _format_num(self, num):
183
+ def _format_num(self, num: int) -> str:
184
184
  """Format number with optional unit scaling."""
185
185
  if not self.unit_scale or self.unit not in ("B", "bytes"):
186
186
  return str(num)
@@ -191,7 +191,7 @@ class TQDM:
191
191
  num /= self.unit_divisor
192
192
  return f"{num:.1f}PB"
193
193
 
194
- def _format_time(self, seconds):
194
+ def _format_time(self, seconds: float) -> str:
195
195
  """Format time duration."""
196
196
  if seconds < 60:
197
197
  return f"{seconds:.1f}s"
@@ -201,7 +201,7 @@ class TQDM:
201
201
  h, m = int(seconds // 3600), int((seconds % 3600) // 60)
202
202
  return f"{h}:{m:02d}:{seconds % 60:02.0f}"
203
203
 
204
- def _generate_bar(self, width=12):
204
+ def _generate_bar(self, width: int = 12) -> str:
205
205
  """Generate progress bar."""
206
206
  if self.total is None:
207
207
  return "━" * width if self.closed else "─" * width
@@ -213,7 +213,7 @@ class TQDM:
213
213
  bar = bar[:filled] + "╸" + bar[filled + 1 :]
214
214
  return bar
215
215
 
216
- def _should_update(self, dt, dn):
216
+ def _should_update(self, dt: float, dn: int) -> bool:
217
217
  """Check if display should update."""
218
218
  if self.noninteractive:
219
219
  return False
@@ -223,7 +223,7 @@ class TQDM:
223
223
 
224
224
  return dt >= self.mininterval
225
225
 
226
- def _display(self, final=False):
226
+ def _display(self, final: bool = False) -> None:
227
227
  """Display progress bar."""
228
228
  if self.disable or (self.closed and not final):
229
229
  return
@@ -296,26 +296,26 @@ class TQDM:
296
296
  except Exception:
297
297
  pass
298
298
 
299
- def update(self, n=1):
299
+ def update(self, n: int = 1) -> None:
300
300
  """Update progress by n steps."""
301
301
  if not self.disable and not self.closed:
302
302
  self.n += n
303
303
  self._display()
304
304
 
305
- def set_description(self, desc):
305
+ def set_description(self, desc: str | None) -> None:
306
306
  """Set description."""
307
307
  self.desc = desc or ""
308
308
  if not self.disable:
309
309
  self._display()
310
310
 
311
- def set_postfix(self, **kwargs):
311
+ def set_postfix(self, **kwargs: Any) -> None:
312
312
  """Set postfix (appends to description)."""
313
313
  if kwargs:
314
314
  postfix = ", ".join(f"{k}={v}" for k, v in kwargs.items())
315
315
  base_desc = self.desc.split(" | ")[0] if " | " in self.desc else self.desc
316
316
  self.set_description(f"{base_desc} | {postfix}")
317
317
 
318
- def close(self):
318
+ def close(self) -> None:
319
319
  """Close progress bar."""
320
320
  if self.closed:
321
321
  return
@@ -339,15 +339,15 @@ class TQDM:
339
339
  except Exception:
340
340
  pass
341
341
 
342
- def __enter__(self):
342
+ def __enter__(self) -> TQDM:
343
343
  """Enter context manager."""
344
344
  return self
345
345
 
346
- def __exit__(self, *args):
346
+ def __exit__(self, *args: Any) -> None:
347
347
  """Exit context manager and close progress bar."""
348
348
  self.close()
349
349
 
350
- def __iter__(self):
350
+ def __iter__(self) -> Any:
351
351
  """Iterate over the wrapped iterable with progress updates."""
352
352
  if self.iterable is None:
353
353
  raise TypeError("'NoneType' object is not iterable")
@@ -359,19 +359,19 @@ class TQDM:
359
359
  finally:
360
360
  self.close()
361
361
 
362
- def __del__(self):
362
+ def __del__(self) -> None:
363
363
  """Destructor to ensure cleanup."""
364
364
  try:
365
365
  self.close()
366
366
  except Exception:
367
367
  pass
368
368
 
369
- def refresh(self):
369
+ def refresh(self) -> None:
370
370
  """Refresh display."""
371
371
  if not self.disable:
372
372
  self._display()
373
373
 
374
- def clear(self):
374
+ def clear(self) -> None:
375
375
  """Clear progress bar."""
376
376
  if not self.disable:
377
377
  try:
@@ -381,7 +381,7 @@ class TQDM:
381
381
  pass
382
382
 
383
383
  @staticmethod
384
- def write(s, file=None, end="\n"):
384
+ def write(s: str, file: IO[str] | None = None, end: str = "\n") -> None:
385
385
  """Static method to write without breaking progress bar."""
386
386
  file = file or sys.stdout
387
387
  try:
@@ -394,14 +394,11 @@ class TQDM:
394
394
  if __name__ == "__main__":
395
395
  import time
396
396
 
397
- # Example 1: Basic usage with known total
398
397
  print("1. Basic progress bar with known total:")
399
- for i in TQDM(range(20), desc="Known total"):
398
+ for i in TQDM(range(0), desc="Known total"):
400
399
  time.sleep(0.05)
401
- print()
402
400
 
403
- # Example 2: Manual updates with known total
404
- print("2. Manual updates with known total:")
401
+ print("\n2. Manual updates with known total:")
405
402
  pbar = TQDM(total=30, desc="Manual updates", unit="files")
406
403
  for i in range(30):
407
404
  time.sleep(0.03)
@@ -409,10 +406,8 @@ if __name__ == "__main__":
409
406
  if i % 10 == 9:
410
407
  pbar.set_description(f"Processing batch {i // 10 + 1}")
411
408
  pbar.close()
412
- print()
413
409
 
414
- # Example 3: Unknown total - this was the problematic case
415
- print("3. Progress bar with unknown total:")
410
+ print("\n3. Progress bar with unknown total:")
416
411
  pbar = TQDM(desc="Unknown total", unit="items")
417
412
  for i in range(25):
418
413
  time.sleep(0.08)
@@ -420,18 +415,14 @@ if __name__ == "__main__":
420
415
  if i % 5 == 4:
421
416
  pbar.set_postfix(processed=i + 1, status="OK")
422
417
  pbar.close()
423
- print()
424
418
 
425
- # Example 4: Context manager with unknown total
426
- print("4. Context manager with unknown total:")
419
+ print("\n4. Context manager with unknown total:")
427
420
  with TQDM(desc="Processing stream", unit="B", unit_scale=True, unit_divisor=1024) as pbar:
428
421
  for i in range(30):
429
422
  time.sleep(0.1)
430
423
  pbar.update(1024 * 1024 * i) # Simulate processing MB of data
431
- print()
432
424
 
433
- # Example 5: Generator with unknown length
434
- print("5. Iterator with unknown length:")
425
+ print("\n5. Iterator with unknown length:")
435
426
 
436
427
  def data_stream():
437
428
  """Simulate a data stream of unknown length."""
@@ -442,10 +433,8 @@ if __name__ == "__main__":
442
433
 
443
434
  for chunk in TQDM(data_stream(), desc="Stream processing", unit="chunks"):
444
435
  time.sleep(0.1)
445
- print()
446
436
 
447
- # Example 6: File-like processing simulation
448
- print("6. File processing simulation (unknown size):")
437
+ print("\n6. File processing simulation (unknown size):")
449
438
 
450
439
  def process_files():
451
440
  """Simulate processing files of unknown count."""
@@ -459,4 +448,3 @@ if __name__ == "__main__":
459
448
  pbar.update(1)
460
449
  pbar.set_description(f"Processing {filename}")
461
450
  pbar.close()
462
- print()