Merge branch 'main' into cli-info

cli-info
Burhan 2 months ago committed by GitHub
commit ff499baa17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      docs/build_docs.py
  2. 2
      ultralytics/__init__.py
  3. 56
      ultralytics/cfg/__init__.py
  4. 6
      ultralytics/hub/__init__.py
  5. 2
      ultralytics/hub/auth.py
  6. 17
      ultralytics/nn/modules/head.py
  7. 9
      ultralytics/nn/tasks.py
  8. 2
      ultralytics/utils/__init__.py

@ -199,7 +199,7 @@ def convert_plaintext_links_to_html(content):
for text_node in paragraph.find_all(string=True, recursive=False): for text_node in paragraph.find_all(string=True, recursive=False):
if text_node.parent.name not in {"a", "code"}: # Ignore links and code blocks if text_node.parent.name not in {"a", "code"}: # Ignore links and code blocks
new_text = re.sub( new_text = re.sub(
r'\b(https?://(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(?:/[a-zA-Z0-9\-._~:/?#[\]@!$&\'()*+,;=%]*)?)(?<![.,:;\'"])', r'(https?://[^\s()<>]+(?:\.[^\s()<>]+)+)(?<![.,:;\'"])',
r'<a href="\1">\1</a>', r'<a href="\1">\1</a>',
str(text_node), str(text_node),
) )

@ -1,6 +1,6 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license # Ultralytics YOLO 🚀, AGPL-3.0 license
__version__ = "8.3.16" __version__ = "8.3.18"
import os import os

@ -439,34 +439,60 @@ def check_dict_alignment(base: Dict, custom: Dict, e=None):
def merge_equals_args(args: List[str]) -> List[str]: def merge_equals_args(args: List[str]) -> List[str]:
""" """
Merges arguments around isolated '=' in a list of strings, handling three cases: Merges arguments around isolated '=' in a list of strings and joins fragments with brackets.
1. ['arg', '=', 'val'] becomes ['arg=val'],
2. ['arg=', 'val'] becomes ['arg=val'], This function handles the following cases:
3. ['arg', '=val'] becomes ['arg=val']. 1. ['arg', '=', 'val'] becomes ['arg=val']
2. ['arg=', 'val'] becomes ['arg=val']
3. ['arg', '=val'] becomes ['arg=val']
4. Joins fragments with brackets, e.g., ['imgsz=[3,', '640,', '640]'] becomes ['imgsz=[3,640,640]']
Args: Args:
args (List[str]): A list of strings where each element represents an argument. args (List[str]): A list of strings where each element represents an argument or fragment.
Returns: Returns:
(List[str]): A list of strings where the arguments around isolated '=' are merged. List[str]: A list of strings where the arguments around isolated '=' are merged and fragments with brackets are joined.
Examples: Examples:
>>> args = ["arg1", "=", "value", "arg2=", "value2", "arg3", "=value3"] >>> args = ["arg1", "=", "value", "arg2=", "value2", "arg3", "=value3", "imgsz=[3,", "640,", "640]"]
>>> merge_equals_args(args) >>> merge_and_join_args(args)
['arg1=value', 'arg2=value2', 'arg3=value3'] ['arg1=value', 'arg2=value2', 'arg3=value3', 'imgsz=[3,640,640]']
""" """
new_args = [] new_args = []
for i, arg in enumerate(args): current = ""
depth = 0
i = 0
while i < len(args):
arg = args[i]
# Handle equals sign merging
if arg == "=" and 0 < i < len(args) - 1: # merge ['arg', '=', 'val'] if arg == "=" and 0 < i < len(args) - 1: # merge ['arg', '=', 'val']
new_args[-1] += f"={args[i + 1]}" new_args[-1] += f"={args[i + 1]}"
del args[i + 1] i += 2
continue
elif arg.endswith("=") and i < len(args) - 1 and "=" not in args[i + 1]: # merge ['arg=', 'val'] elif arg.endswith("=") and i < len(args) - 1 and "=" not in args[i + 1]: # merge ['arg=', 'val']
new_args.append(f"{arg}{args[i + 1]}") new_args.append(f"{arg}{args[i + 1]}")
del args[i + 1] i += 2
continue
elif arg.startswith("=") and i > 0: # merge ['arg', '=val'] elif arg.startswith("=") and i > 0: # merge ['arg', '=val']
new_args[-1] += arg new_args[-1] += arg
else: i += 1
new_args.append(arg) continue
# Handle bracket joining
depth += arg.count("[") - arg.count("]")
current += arg
if depth == 0:
new_args.append(current)
current = ""
i += 1
# Append any remaining current string
if current:
new_args.append(current)
return new_args return new_args
@ -483,7 +509,7 @@ def handle_yolo_hub(args: List[str]) -> None:
Examples: Examples:
```bash ```bash
yolo hub login YOUR_API_KEY yolo login YOUR_API_KEY
``` ```
Notes: Notes:

@ -63,13 +63,13 @@ def login(api_key: str = None, save=True) -> bool:
return True return True
else: else:
# Failed to authenticate with HUB # Failed to authenticate with HUB
LOGGER.info(f"{PREFIX}Get API key from {api_key_url} and then run 'yolo hub login API_KEY'") LOGGER.info(f"{PREFIX}Get API key from {api_key_url} and then run 'yolo login API_KEY'")
return False return False
def logout(): def logout():
""" """
Log out of Ultralytics HUB by removing the API key from the settings file. To log in again, use 'yolo hub login'. Log out of Ultralytics HUB by removing the API key from the settings file. To log in again, use 'yolo login'.
Example: Example:
```python ```python
@ -79,7 +79,7 @@ def logout():
``` ```
""" """
SETTINGS["api_key"] = "" SETTINGS["api_key"] = ""
LOGGER.info(f"{PREFIX}logged out ✅. To log in again, use 'yolo hub login'.") LOGGER.info(f"{PREFIX}logged out ✅. To log in again, use 'yolo login'.")
def reset_model(model_id=""): def reset_model(model_id=""):

@ -68,7 +68,7 @@ class Auth:
if verbose: if verbose:
LOGGER.info(f"{PREFIX}New authentication successful ✅") LOGGER.info(f"{PREFIX}New authentication successful ✅")
elif verbose: elif verbose:
LOGGER.info(f"{PREFIX}Get API key from {API_KEY_URL} and then run 'yolo hub login API_KEY'") LOGGER.info(f"{PREFIX}Get API key from {API_KEY_URL} and then run 'yolo login API_KEY'")
def request_api_key(self, max_attempts=3): def request_api_key(self, max_attempts=3):
""" """

@ -28,6 +28,7 @@ class Detect(nn.Module):
shape = None shape = None
anchors = torch.empty(0) # init anchors = torch.empty(0) # init
strides = torch.empty(0) # init strides = torch.empty(0) # init
legacy = False # backward compatibility for v3/v5/v8/v9 models
def __init__(self, nc=80, ch=()): def __init__(self, nc=80, ch=()):
"""Initializes the YOLO detection layer with specified number of classes and channels.""" """Initializes the YOLO detection layer with specified number of classes and channels."""
@ -41,13 +42,17 @@ class Detect(nn.Module):
self.cv2 = nn.ModuleList( self.cv2 = nn.ModuleList(
nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch
) )
self.cv3 = nn.ModuleList( self.cv3 = (
nn.Sequential( nn.ModuleList(nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch)
nn.Sequential(DWConv(x, x, 3), Conv(x, c3, 1)), if self.legacy
nn.Sequential(DWConv(c3, c3, 3), Conv(c3, c3, 1)), else nn.ModuleList(
nn.Conv2d(c3, self.nc, 1), nn.Sequential(
nn.Sequential(DWConv(x, x, 3), Conv(x, c3, 1)),
nn.Sequential(DWConv(c3, c3, 3), Conv(c3, c3, 1)),
nn.Conv2d(c3, self.nc, 1),
)
for x in ch
) )
for x in ch
) )
self.dfl = DFL(self.reg_max) if self.reg_max > 1 else nn.Identity() self.dfl = DFL(self.reg_max) if self.reg_max > 1 else nn.Identity()

@ -936,6 +936,7 @@ def parse_model(d, ch, verbose=True): # model_dict, input_channels(3)
import ast import ast
# Args # Args
legacy = True # backward compatibility for v3/v5/v8/v9 models
max_channels = float("inf") max_channels = float("inf")
nc, act, scales = (d.get(x) for x in ("nc", "activation", "scales")) nc, act, scales = (d.get(x) for x in ("nc", "activation", "scales"))
depth, width, kpt_shape = (d.get(x, 1.0) for x in ("depth_multiple", "width_multiple", "kpt_shape")) depth, width, kpt_shape = (d.get(x, 1.0) for x in ("depth_multiple", "width_multiple", "kpt_shape"))
@ -1027,8 +1028,10 @@ def parse_model(d, ch, verbose=True): # model_dict, input_channels(3)
}: }:
args.insert(2, n) # number of repeats args.insert(2, n) # number of repeats
n = 1 n = 1
if m is C3k2 and scale in "mlx": # for M/L/X sizes if m is C3k2: # for M/L/X sizes
args[3] = True legacy = False
if scale in "mlx":
args[3] = True
elif m is AIFI: elif m is AIFI:
args = [ch[f], *args] args = [ch[f], *args]
elif m in {HGStem, HGBlock}: elif m in {HGStem, HGBlock}:
@ -1047,6 +1050,8 @@ def parse_model(d, ch, verbose=True): # model_dict, input_channels(3)
args.append([ch[x] for x in f]) args.append([ch[x] for x in f])
if m is Segment: if m is Segment:
args[2] = make_divisible(min(args[2], max_channels) * width, 8) args[2] = make_divisible(min(args[2], max_channels) * width, 8)
if m in {Detect, Segment, Pose, OBB}:
m.legacy = legacy
elif m is RTDETRDecoder: # special case, channels arg must be passed in index 1 elif m is RTDETRDecoder: # special case, channels arg must be passed in index 1
args.insert(1, [ch[x] for x in f]) args.insert(1, [ch[x] for x in f])
elif m is CBLinear: elif m is CBLinear:

@ -571,7 +571,7 @@ def is_jupyter():
Returns: Returns:
(bool): True if running inside a Jupyter Notebook, False otherwise. (bool): True if running inside a Jupyter Notebook, False otherwise.
""" """
return "get_ipython" in locals() return "get_ipython" in globals()
def is_docker() -> bool: def is_docker() -> bool:

Loading…
Cancel
Save