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):
if text_node.parent.name not in {"a", "code"}: # Ignore links and code blocks
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>',
str(text_node),
)

@ -1,6 +1,6 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license
__version__ = "8.3.16"
__version__ = "8.3.18"
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]:
"""
Merges arguments around isolated '=' in a list of strings, handling three cases:
1. ['arg', '=', 'val'] becomes ['arg=val'],
2. ['arg=', 'val'] becomes ['arg=val'],
3. ['arg', '=val'] becomes ['arg=val'].
Merges arguments around isolated '=' in a list of strings and joins fragments with brackets.
This function handles the following cases:
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 (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:
(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:
>>> args = ["arg1", "=", "value", "arg2=", "value2", "arg3", "=value3"]
>>> merge_equals_args(args)
['arg1=value', 'arg2=value2', 'arg3=value3']
>>> args = ["arg1", "=", "value", "arg2=", "value2", "arg3", "=value3", "imgsz=[3,", "640,", "640]"]
>>> merge_and_join_args(args)
['arg1=value', 'arg2=value2', 'arg3=value3', 'imgsz=[3,640,640]']
"""
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']
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']
new_args.append(f"{arg}{args[i + 1]}")
del args[i + 1]
i += 2
continue
elif arg.startswith("=") and i > 0: # merge ['arg', '=val']
new_args[-1] += arg
else:
new_args.append(arg)
i += 1
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
@ -483,7 +509,7 @@ def handle_yolo_hub(args: List[str]) -> None:
Examples:
```bash
yolo hub login YOUR_API_KEY
yolo login YOUR_API_KEY
```
Notes:

@ -63,13 +63,13 @@ def login(api_key: str = None, save=True) -> bool:
return True
else:
# 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
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:
```python
@ -79,7 +79,7 @@ def logout():
```
"""
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=""):

@ -68,7 +68,7 @@ class Auth:
if verbose:
LOGGER.info(f"{PREFIX}New authentication successful ✅")
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):
"""

@ -28,6 +28,7 @@ class Detect(nn.Module):
shape = None
anchors = 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=()):
"""Initializes the YOLO detection layer with specified number of classes and channels."""
@ -41,13 +42,17 @@ class Detect(nn.Module):
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
)
self.cv3 = nn.ModuleList(
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),
self.cv3 = (
nn.ModuleList(nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch)
if self.legacy
else nn.ModuleList(
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()

@ -936,6 +936,7 @@ def parse_model(d, ch, verbose=True): # model_dict, input_channels(3)
import ast
# Args
legacy = True # backward compatibility for v3/v5/v8/v9 models
max_channels = float("inf")
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"))
@ -1027,8 +1028,10 @@ def parse_model(d, ch, verbose=True): # model_dict, input_channels(3)
}:
args.insert(2, n) # number of repeats
n = 1
if m is C3k2 and scale in "mlx": # for M/L/X sizes
args[3] = True
if m is C3k2: # for M/L/X sizes
legacy = False
if scale in "mlx":
args[3] = True
elif m is AIFI:
args = [ch[f], *args]
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])
if m is Segment:
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
args.insert(1, [ch[x] for x in f])
elif m is CBLinear:

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

Loading…
Cancel
Save