`ultralytics 8.2.61` fix `num_threads` for CPU training (#14544)

Signed-off-by: Glenn Jocher <glenn.jocher@ultralytics.com>
Co-authored-by: UltralyticsAssistant <web@ultralytics.com>
Co-authored-by: Glenn Jocher <glenn.jocher@ultralytics.com>
pull/14566/head v8.2.61
Laughing 4 months ago committed by GitHub
parent 8094df3c47
commit 47ff2b4a76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 39
      docs/build_docs.py
  2. 3
      mkdocs.yml
  3. 2
      ultralytics/__init__.py
  4. 310
      ultralytics/cfg/__init__.py
  5. 3
      ultralytics/utils/torch_utils.py

@ -30,6 +30,7 @@ import shutil
import subprocess
from pathlib import Path
from bs4 import BeautifulSoup
from tqdm import tqdm
os.environ["JUPYTER_PLATFORM_DIRS"] = "1" # fix DeprecationWarning: Jupyter is migrating to use standard platformdirs
@ -96,8 +97,6 @@ def update_html_head(script=""):
def update_subdir_edit_links(subdir="", docs_url=""):
"""Update the HTML head section of each file."""
from bs4 import BeautifulSoup
if str(subdir[0]) == "/":
subdir = str(subdir[0])[1:]
html_files = (SITE / subdir).rglob("*.html")
@ -153,7 +152,7 @@ def update_markdown_files(md_filepath: Path):
def update_docs_html():
"""Updates titles, edit links and head sections of HTML documentation for improved accessibility and relevance."""
"""Updates titles, edit links, head sections, and converts plaintext links in HTML documentation."""
update_page_title(SITE / "404.html", new_title="Ultralytics Docs - Not Found")
# Update edit links
@ -162,12 +161,46 @@ def update_docs_html():
docs_url="https://github.com/ultralytics/hub-sdk/tree/main/docs/",
)
# Convert plaintext links to HTML hyperlinks
files_modified = 0
for html_file in tqdm(SITE.rglob("*.html"), desc="Converting plaintext links"):
with open(html_file, "r", encoding="utf-8") as file:
content = file.read()
updated_content = convert_plaintext_links_to_html(content)
if updated_content != content:
with open(html_file, "w", encoding="utf-8") as file:
file.write(updated_content)
files_modified += 1
print(f"Modified plaintext links in {files_modified} files.")
# Update HTML file head section
script = ""
if any(script):
update_html_head(script)
def convert_plaintext_links_to_html(content):
"""Convert plaintext links to HTML hyperlinks in the main content area only."""
soup = BeautifulSoup(content, "html.parser")
# Find the main content area (adjust this selector based on your HTML structure)
main_content = soup.find("main") or soup.find("div", class_="md-content")
if not main_content:
return content # Return original content if main content area not found
modified = False
for paragraph in main_content.find_all(["p", "li"]): # Focus on paragraphs and list items
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"(https?://\S+)", r'<a href="\1">\1</a>', str(text_node)) # note: reject http?
if "<a" in new_text:
new_soup = BeautifulSoup(new_text, "html.parser")
text_node.replace_with(new_soup)
modified = True
return str(soup) if modified else content
def main():
"""Builds docs, updates titles and edit links, and prints local server command."""
prepare_docs_markdown()

@ -614,6 +614,9 @@ plugins:
handlers:
python:
options:
docstring_options:
ignore_init_summary: true
merge_init_into_class: true
docstring_style: google
show_root_heading: true
show_source: true

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

@ -190,27 +190,23 @@ def cfg2dict(cfg):
Convert a configuration object to a dictionary, whether it is a file path, a string, or a SimpleNamespace object.
Args:
cfg (str | Path | dict | SimpleNamespace): Configuration object to be converted to a dictionary. This may be a
cfg (str | Path | Dict | SimpleNamespace): Configuration object to be converted to a dictionary. This may be a
path to a configuration file, a dictionary, or a SimpleNamespace object.
Returns:
(dict): Configuration object in dictionary format.
(Dict): Configuration object in dictionary format.
Example:
```python
from ultralytics.cfg import cfg2dict
from types import SimpleNamespace
Examples:
Convert a YAML file path to a dictionary:
>>> config_dict = cfg2dict('config.yaml')
# Example usage with a file path
config_dict = cfg2dict('config.yaml')
Convert a SimpleNamespace to a dictionary:
>>> from types import SimpleNamespace
>>> config_sn = SimpleNamespace(param1='value1', param2='value2')
>>> config_dict = cfg2dict(config_sn)
# Example usage with a SimpleNamespace
config_sn = SimpleNamespace(param1='value1', param2='value2')
config_dict = cfg2dict(config_sn)
# Example usage with a dictionary (returns the same dictionary)
config_dict = cfg2dict({'param1': 'value1', 'param2': 'value2'})
```
Pass through an already existing dictionary:
>>> config_dict = cfg2dict({'param1': 'value1', 'param2': 'value2'})
Notes:
- If `cfg` is a path or a string, it will be loaded as YAML and converted to a dictionary.
@ -228,9 +224,8 @@ def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, ove
Load and merge configuration data from a file or dictionary, with optional overrides.
Args:
cfg (str | Path | dict | SimpleNamespace, optional): Configuration data source. Defaults to `DEFAULT_CFG_DICT`.
overrides (dict | None, optional): Dictionary containing key-value pairs to override the base configuration.
Defaults to None.
cfg (str | Path | Dict | SimpleNamespace): Configuration data source.
overrides (Dict | None): Dictionary containing key-value pairs to override the base configuration.
Returns:
(SimpleNamespace): Namespace containing the merged training arguments.
@ -238,23 +233,15 @@ def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, ove
Notes:
- If both `cfg` and `overrides` are provided, the values in `overrides` will take precedence.
- Special handling ensures alignment and correctness of the configuration, such as converting numeric `project`
and `name` to strings and validating the configuration keys and values.
Example:
```python
from ultralytics.cfg import get_cfg
and `name` to strings and validating configuration keys and values.
# Load default configuration
config = get_cfg()
# Load from a custom file with overrides
config = get_cfg('path/to/config.yaml', overrides={'epochs': 50, 'batch_size': 16})
```
Examples:
Load default configuration:
>>> from ultralytics import get_cfg
>>> config = get_cfg()
Configuration dictionary merged with overrides:
```python
{'epochs': 50, 'batch_size': 16, ...}
```
Load from a custom file with overrides:
>>> config = get_cfg('path/to/config.yaml', overrides={'epochs': 50, 'batch_size': 16})
"""
cfg = cfg2dict(cfg)
@ -282,7 +269,26 @@ def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, ove
def check_cfg(cfg, hard=True):
"""Validate Ultralytics configuration argument types and values, converting them if necessary."""
"""
Checks configuration argument types and values for the Ultralytics library, ensuring correctness and converting them
if necessary.
Args:
cfg (Dict): Configuration dictionary to validate.
hard (bool): If True, raises exceptions for invalid types and values; if False, attempts to convert them.
Examples:
Validate a configuration with a mix of valid and invalid values:
>>> config = {
... 'epochs': 50, # valid integer
... 'lr0': 0.01, # valid float
... 'momentum': 1.2, # invalid float (out of 0.0-1.0 range)
... 'save': 'true', # invalid bool
... }
>>> check_cfg(config, hard=False)
>>> print(config)
{'epochs': 50, 'lr0': 0.01, 'momentum': 1.2, 'save': False} # corrected 'save' key and retained other values
"""
for k, v in cfg.items():
if v is not None: # None values may be from optional args
if k in CFG_FLOAT_KEYS and not isinstance(v, (int, float)):
@ -318,7 +324,26 @@ def check_cfg(cfg, hard=True):
def get_save_dir(args, name=None):
"""Returns the directory path for saving outputs, derived from arguments or default settings."""
"""
Returns the directory path for saving outputs, derived from arguments or default settings.
Args:
args (SimpleNamespace): Namespace object containing configurations such as 'project', 'name', 'task', 'mode', and
'save_dir'.
name (str | None): Optional name for the output directory. If not provided, it defaults to 'args.name' or the
'args.mode'.
Returns:
(Path): Directory path where outputs should be saved.
Examples:
Generate a save directory using provided arguments
>>> from types import SimpleNamespace
>>> args = SimpleNamespace(project='my_project', task='detect', mode='train', exist_ok=True)
>>> save_dir = get_save_dir(args)
>>> print(save_dir)
my_project/detect/train
"""
if getattr(args, "save_dir", None):
save_dir = args.save_dir
@ -333,7 +358,18 @@ def get_save_dir(args, name=None):
def _handle_deprecation(custom):
"""Handles deprecated configuration keys by mapping them to current equivalents with deprecation warnings."""
"""
Handles deprecated configuration keys by mapping them to current equivalents with deprecation warnings.
Args:
custom (Dict): Configuration dictionary potentially containing deprecated keys.
Examples:
>>> custom_config = {"boxes": True, "hide_labels": "False", "line_thickness": 2}
>>> _handle_deprecation(custom_config)
>>> print(custom_config)
{'show_boxes': True, 'show_labels': True, 'line_width': 2}
"""
for key in custom.copy().keys():
if key == "boxes":
@ -354,35 +390,32 @@ def _handle_deprecation(custom):
def check_dict_alignment(base: Dict, custom: Dict, e=None):
"""
Check for key alignment between custom and base configuration dictionaries, catering for deprecated keys and
providing informative error messages for mismatched keys.
Check for key alignment between custom and base configuration dictionaries, handling deprecated keys and providing
informative error messages for mismatched keys.
Args:
base (dict): The base configuration dictionary containing valid keys.
custom (dict): The custom configuration dictionary to be checked for alignment.
e (Exception, optional): An optional error instance passed by the calling function. Default is None.
base (Dict): The base configuration dictionary containing valid keys.
custom (Dict): The custom configuration dictionary to be checked for alignment.
e (Exception | None): Optional error instance passed by the calling function. Default is None.
Raises:
SystemExit: Terminates the program execution if mismatched keys are found.
Notes:
- The function provides suggestions for mismatched keys based on their similarity to valid keys in the
base configuration.
- Deprecated keys in the custom configuration are automatically handled and replaced with their updated
equivalents.
- A detailed error message is printed for each mismatched key, helping users to quickly identify and correct
their custom configurations.
Example:
```python
base_cfg = {'epochs': 50, 'lr0': 0.01, 'batch_size': 16}
custom_cfg = {'epoch': 100, 'lr': 0.02, 'batch_size': 32}
try:
check_dict_alignment(base_cfg, custom_cfg)
except SystemExit:
# Handle the error or correct the configuration
```
- The function suggests corrections for mismatched keys based on similarity to valid keys.
- Deprecated keys in the custom configuration are automatically replaced with their updated equivalents.
- Detailed error messages are printed for each mismatched key to help users identify and correct their custom
configurations.
Examples:
>>> base_cfg = {'epochs': 50, 'lr0': 0.01, 'batch_size': 16}
>>> custom_cfg = {'epoch': 100, 'lr': 0.02, 'batch_size': 32}
>>> try:
... check_dict_alignment(base_cfg, custom_cfg)
... except SystemExit:
... # Handle the error or correct the configuration
... pass
"""
custom = _handle_deprecation(custom)
base_keys, custom_keys = (set(x.keys()) for x in (base, custom))
@ -401,30 +434,29 @@ def check_dict_alignment(base: Dict, custom: Dict, e=None):
def merge_equals_args(args: List[str]) -> List[str]:
"""
Merges arguments around isolated '=' args in a list of strings. The function considers cases where the first
argument ends with '=' or the second starts with '=', as well as when the middle one is an equals sign.
Merges arguments around isolated '=' in a list of strings.
Args:
args (List[str]): A list of strings where each element is an argument.
args (List[str]): A list of strings where each element represents an argument.
Returns:
(List[str]): A list of strings where the arguments around isolated '=' are merged.
Example:
The function modifies the argument list as follows:
```python
args = ["arg1", "=", "value"]
new_args = merge_equals_args(args)
print(new_args) # Output: ["arg1=value"]
args = ["arg1=", "value"]
new_args = merge_equals_args(args)
print(new_args) # Output: ["arg1=value"]
args = ["arg1", "=value"]
new_args = merge_equals_args(args)
print(new_args) # Output: ["arg1=value"]
```
Examples:
Merge arguments where equals sign is separated:
>>> args = ["arg1", "=", "value"]
>>> merge_equals_args(args)
["arg1=value"]
Merge arguments where equals sign is at the end of the first argument:
>>> args = ["arg1=", "value"]
>>> merge_equals_args(args)
["arg1=value"]
Merge arguments where equals sign is at the beginning of the second argument:
>>> args = ["arg1", "=value"]
>>> merge_equals_args(args)
["arg1=value"]
"""
new_args = []
for i, arg in enumerate(args):
@ -445,16 +477,13 @@ def handle_yolo_hub(args: List[str]) -> None:
"""
Handle Ultralytics HUB command-line interface (CLI) commands.
This function processes Ultralytics HUB CLI commands such as login and logout. It should be called when executing
a script with arguments related to HUB authentication.
This function processes Ultralytics HUB CLI commands such as login and logout. It should be called when executing a
script with arguments related to HUB authentication.
Args:
args (List[str]): A list of command line arguments.
Returns:
None
Example:
Examples:
```bash
yolo hub login YOUR_API_KEY
```
@ -480,13 +509,9 @@ def handle_yolo_settings(args: List[str]) -> None:
Args:
args (List[str]): A list of command line arguments for YOLO settings management.
Returns:
None
Example:
```bash
yolo settings reset
```
Examples:
Reset YOLO settings:
>>> yolo settings reset
Notes:
For more information on handling YOLO settings, visit:
@ -511,21 +536,58 @@ def handle_yolo_settings(args: List[str]) -> None:
def handle_explorer():
"""Open the Ultralytics Explorer GUI for dataset exploration and analysis."""
"""
Open the Ultralytics Explorer GUI for dataset exploration and analysis.
This function launches a graphical user interface that provides tools for interacting with and analyzing datasets
using the Ultralytics Explorer API.
Examples:
Start the Ultralytics Explorer:
>>> handle_explorer()
"""
checks.check_requirements("streamlit>=1.29.0")
LOGGER.info("💡 Loading Explorer dashboard...")
subprocess.run(["streamlit", "run", ROOT / "data/explorer/gui/dash.py", "--server.maxMessageSize", "2048"])
def handle_streamlit_inference():
"""Open the Ultralytics Live Inference streamlit app for real time object detection."""
"""
Open the Ultralytics Live Inference streamlit app for real-time object detection.
This function initializes and runs a Streamlit application designed for performing live object detection using
Ultralytics models.
References:
- Streamlit documentation: https://docs.streamlit.io/
- Ultralytics: https://docs.ultralytics.com
Examples:
To run the live inference Streamlit app, execute:
>>> handle_streamlit_inference()
"""
checks.check_requirements("streamlit>=1.29.0")
LOGGER.info("💡 Loading Ultralytics Live Inference app...")
subprocess.run(["streamlit", "run", ROOT / "solutions/streamlit_inference.py", "--server.headless", "true"])
def parse_key_value_pair(pair):
"""Parse one 'key=value' pair and return key and value."""
"""
Parse a 'key=value' pair and return the key and value.
Args:
pair (str): The 'key=value' string to be parsed.
Returns:
(tuple[str, str]): A tuple containing the key and value as separate strings.
Examples:
>>> key, value = parse_key_value_pair("model=yolov8n.pt")
>>> key
'model'
>>> value
'yolov8n.pt
"""
k, v = pair.split("=", 1) # split on first '=' sign
k, v = k.strip(), v.strip() # remove spaces
assert v, f"missing '{k}' value"
@ -533,7 +595,29 @@ def parse_key_value_pair(pair):
def smart_value(v):
"""Convert a string to its appropriate type (int, float, bool, None, etc.)."""
"""
Convert a string representation of a value into its appropriate Python type (int, float, bool, None, etc.).
Args:
v (str): String representation of the value to be converted.
Returns:
(Any): The converted value, which can be of type int, float, bool, None, or the original string if no conversion
is applicable.
Examples:
Convert a string to various types:
>>> smart_value("42")
42
>>> smart_value("3.14")
3.14
>>> smart_value("True")
True
>>> smart_value("None")
None
>>> smart_value("some_string")
'some_string'
"""
v_lower = v.lower()
if v_lower == "none":
return None
@ -551,31 +635,26 @@ def entrypoint(debug=""):
"""
Ultralytics entrypoint function for parsing and executing command-line arguments.
This function serves as the main entry point for the Ultralytics CLI, parsing command-line arguments and
This function serves as the main entry point for the Ultralytics CLI, parsing command-line arguments and
executing the corresponding tasks such as training, validation, prediction, exporting models, and more.
Args:
debug (str, optional): Space-separated string of command-line arguments for debugging purposes. Default is "".
debug (str, optional): Space-separated string of command-line arguments for debugging purposes.
Returns:
(None): This function does not return any value.
Examples:
Train a detection model for 10 epochs with an initial learning_rate of 0.01:
>>> entrypoint("train data=coco8.yaml model=yolov8n.pt epochs=10 lr0=0.01")
Predict a YouTube video using a pretrained segmentation model at image size 320:
>>> entrypoint("predict model=yolov8n-seg.pt source='https://youtu.be/LNwODJXcvt4' imgsz=320")
Validate a pretrained detection model at batch-size 1 and image size 640:
>>> entrypoint("val model=yolov8n.pt data=coco8.yaml batch=1 imgsz=640")
Notes:
- For a list of all available commands and their arguments, see the provided help messages and the Ultralytics
documentation at https://docs.ultralytics.com.
- If no arguments are passed, the function will display the usage help message.
Example:
```python
# Train a detection model for 10 epochs with an initial learning_rate of 0.01
entrypoint("train data=coco8.yaml model=yolov8n.pt epochs=10 lr0=0.01")
# Predict a YouTube video using a pretrained segmentation model at image size 320
entrypoint("predict model=yolov8n-seg.pt source='https://youtu.be/LNwODJXcvt4' imgsz=320")
# Validate a pretrained detection model at batch-size 1 and image size 640
entrypoint("val model=yolov8n.pt data=coco8.yaml batch=1 imgsz=640")
```
"""
args = (debug.split(" ") if debug else ARGV)[1:]
if not args: # no arguments passed
@ -713,7 +792,18 @@ def entrypoint(debug=""):
# Special modes --------------------------------------------------------------------------------------------------------
def copy_default_cfg():
"""Copy and create a new default configuration file with '_copy' appended to its name, providing usage example."""
"""
Copy and create a new default configuration file with '_copy' appended to its name, providing a usage example.
This function duplicates the existing default configuration file and appends '_copy' to its name in the current
working directory.
Examples:
Copy the default configuration file and use it in a YOLO command:
>>> copy_default_cfg()
>>> # Example YOLO command with this new custom cfg:
>>> # yolo cfg='default_copy.yaml' imgsz=320 batch=8
"""
new_file = Path.cwd() / DEFAULT_CFG_PATH.name.replace(".yaml", "_copy.yaml")
shutil.copy2(DEFAULT_CFG_PATH, new_file)
LOGGER.info(

@ -21,6 +21,7 @@ from ultralytics.utils import (
DEFAULT_CFG_DICT,
DEFAULT_CFG_KEYS,
LOGGER,
NUM_THREADS,
PYTHON_VERSION,
TORCHVISION_VERSION,
__version__,
@ -172,6 +173,8 @@ def select_device(device="", batch=0, newline=False, verbose=True):
s += f"CPU ({get_cpu_info()})\n"
arg = "cpu"
if arg in {"cpu", "mps"}:
torch.set_num_threads(NUM_THREADS) # reset OMP_NUM_THREADS for cpu training
if verbose:
LOGGER.info(s if newline else s.rstrip())
return torch.device(arg)

Loading…
Cancel
Save