`ultralytics 8.0.141` create new SettingsManager (#3790)

single_channel
Glenn Jocher 1 year ago committed by GitHub
parent 42afe772d5
commit 20f5efd40a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -60,7 +60,7 @@ repos:
hooks: hooks:
- id: codespell - id: codespell
args: args:
- --ignore-words-list=crate,nd,strack,dota - --ignore-words-list=crate,nd,strack,dota,ane
# - repo: https://github.com/asottile/yesqa # - repo: https://github.com/asottile/yesqa
# rev: v1.4.0 # rev: v1.4.0

@ -234,14 +234,14 @@ We love your input! YOLOv5 and YOLOv8 would not be possible without help from ou
## <div align="center">License</div> ## <div align="center">License</div>
YOLOv8 is available under two different licenses: Ultralytics offers two licensing options to accommodate diverse use cases:
- **AGPL-3.0 License**: See [LICENSE](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) file for details. - **AGPL-3.0 License**: This [OSI-approved](https://opensource.org/licenses/) open-source license is ideal for students and enthusiasts, promoting open collaboration and knowledge sharing. See the [LICENSE](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) file for more details.
- **Enterprise License**: Provides greater flexibility for commercial product development without the open-source requirements of AGPL-3.0. Typical use cases are embedding Ultralytics software and AI models in commercial products and applications. Request an Enterprise License at [Ultralytics Licensing](https://ultralytics.com/license). - **Enterprise License**: Designed for commercial use, this license permits seamless integration of Ultralytics software and AI models into commercial goods and services, bypassing the open-source requirements of AGPL-3.0. If your scenario involves embedding our solutions into a commercial offering, reach out through [Ultralytics Licensing](https://ultralytics.com/license).
## <div align="center">Contact</div> ## <div align="center">Contact</div>
For YOLOv8 bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/ultralytics/issues), and join our [Discord](https://discord.gg/2wNGbc6g9X) community for questions and discussions! For Ultralytics bug reports and feature requests please visit [GitHub Issues](https://github.com/ultralytics/ultralytics/issues), and join our [Discord](https://discord.gg/2wNGbc6g9X) community for questions and discussions!
<br> <br>
<div align="center"> <div align="center">

@ -233,14 +233,14 @@ success = model.export(format="onnx") # 将模型导出为 ONNX 格式
## <div align="center">许可证</div> ## <div align="center">许可证</div>
YOLOv8 提供两种不同的许可证 Ultralytics 提供两种许可证选项以适应各种使用场景
- **AGPL-3.0 许可证**详细信息请参阅 [LICENSE](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) 文件。 - **AGPL-3.0 许可证**这个[OSI 批准](https://opensource.org/licenses/)的开源许可证非常适合学生和爱好者,可以推动开放的协作和知识分享。请查看[LICENSE](https://github.com/ultralytics/ultralytics/blob/main/LICENSE) 文件以了解更多细节
- **企业许可证**为商业产品开发提供更大的灵活性,无需遵循 AGPL-3.0 的开源要求。典型的用例是将 Ultralytics 软件和 AI 模型嵌入商业产品和应用中。在 [Ultralytics 授权](https://ultralytics.com/license) 处申请企业许可证 - **企业许可证**专为商业用途设计,该许可证允许将 Ultralytics 的软件和 AI 模型无缝集成到商业产品和服务中,从而绕过 AGPL-3.0 的开源要求。如果您的场景涉及将我们的解决方案嵌入到商业产品中,请通过 [Ultralytics Licensing](https://ultralytics.com/license)与我们联系
## <div align="center">联系方式</div> ## <div align="center">联系方式</div>
对于 YOLOv8 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/ultralytics/issues),并加入我们的 [Discord](https://discord.gg/2wNGbc6g9X) 社区进行问题和讨论! 对于 Ultralytics 的错误报告和功能请求,请访问 [GitHub Issues](https://github.com/ultralytics/ultralytics/issues),并加入我们的 [Discord](https://discord.gg/2wNGbc6g9X) 社区进行问题和讨论!
<br> <br>
<div align="center"> <div align="center">

@ -21,8 +21,8 @@ def extract_classes_and_functions(filepath):
with open(filepath, 'r') as file: with open(filepath, 'r') as file:
content = file.read() content = file.read()
class_pattern = r"(?:^|\n)class\s(\w+)(?:\(|:)" class_pattern = r'(?:^|\n)class\s(\w+)(?:\(|:)'
func_pattern = r"(?:^|\n)def\s(\w+)\(" func_pattern = r'(?:^|\n)def\s(\w+)\('
classes = re.findall(class_pattern, content) classes = re.findall(class_pattern, content)
functions = re.findall(func_pattern, content) functions = re.findall(func_pattern, content)
@ -34,18 +34,21 @@ def create_markdown(py_filepath, module_path, classes, functions):
md_filepath = py_filepath.with_suffix('.md') md_filepath = py_filepath.with_suffix('.md')
# Read existing content and keep header content between first two --- # Read existing content and keep header content between first two ---
header_content = "" header_content = ''
if md_filepath.exists(): if md_filepath.exists():
with open(md_filepath, 'r') as file: with open(md_filepath, 'r') as file:
existing_content = file.read() existing_content = file.read()
header_parts = existing_content.split('---', 2) header_parts = existing_content.split('---')
if 'description:' in header_parts or 'comments:' in header_parts and len(header_parts) >= 3: for part in header_parts:
header_content = f"{header_parts[0]}---{header_parts[1]}---\n\n" if 'description:' in part or 'comments:' in part:
header_content += f'---{part}---\n\n'
module_path = module_path.replace('.__init__', '') module_path = module_path.replace('.__init__', '')
md_content = [f"## {class_name}\n---\n### ::: {module_path}.{class_name}\n<br><br>\n" for class_name in classes] md_content = [f'## {class_name}\n---\n### ::: {module_path}.{class_name}\n<br><br>\n' for class_name in classes]
md_content.extend(f"## {func_name}\n---\n### ::: {module_path}.{func_name}\n<br><br>\n" for func_name in functions) md_content.extend(f'## {func_name}\n---\n### ::: {module_path}.{func_name}\n<br><br>\n' for func_name in functions)
md_content = header_content + "\n".join(md_content) md_content = header_content + '\n'.join(md_content)
if not md_content.endswith('\n'):
md_content += '\n'
os.makedirs(os.path.dirname(md_filepath), exist_ok=True) os.makedirs(os.path.dirname(md_filepath), exist_ok=True)
with open(md_filepath, 'w') as file: with open(md_filepath, 'w') as file:
@ -81,11 +84,11 @@ def create_nav_menu_yaml(nav_items):
nav_tree_sorted = sort_nested_dict(nav_tree) nav_tree_sorted = sort_nested_dict(nav_tree)
def _dict_to_yaml(d, level=0): def _dict_to_yaml(d, level=0):
yaml_str = "" yaml_str = ''
indent = " " * level indent = ' ' * level
for k, v in d.items(): for k, v in d.items():
if isinstance(v, dict): if isinstance(v, dict):
yaml_str += f"{indent}- {k}:\n{_dict_to_yaml(v, level + 1)}" yaml_str += f'{indent}- {k}:\n{_dict_to_yaml(v, level + 1)}'
else: else:
yaml_str += f"{indent}- {k}: {str(v).replace('docs/', '')}\n" yaml_str += f"{indent}- {k}: {str(v).replace('docs/', '')}\n"
return yaml_str return yaml_str
@ -99,7 +102,7 @@ def main():
nav_items = [] nav_items = []
for root, _, files in os.walk(CODE_DIR): for root, _, files in os.walk(CODE_DIR):
for file in files: for file in files:
if file.endswith(".py"): if file.endswith('.py'):
py_filepath = Path(root) / file py_filepath = Path(root) / file
classes, functions = extract_classes_and_functions(py_filepath) classes, functions = extract_classes_and_functions(py_filepath)
@ -113,5 +116,5 @@ def main():
create_nav_menu_yaml(nav_items) create_nav_menu_yaml(nav_items)
if __name__ == "__main__": if __name__ == '__main__':
main() main()

@ -181,3 +181,90 @@ For example, users can load a model, train it, evaluate its performance on a val
``` ```
[Python Guide](usage/python.md){.md-button .md-button--primary} [Python Guide](usage/python.md){.md-button .md-button--primary}
## Ultralytics Settings
The Ultralytics library provides a powerful settings management system to enable fine-grained control over your experiments. By making use of the `SettingsManager` housed within the `ultralytics.utils` module, users can readily access and alter their settings. These are stored in a YAML file and can be viewed or modified either directly within the Python environment or via the Command-Line Interface (CLI).
### Inspecting Settings
To gain insight into the current configuration of your settings, you can view them directly:
!!! example "View settings"
=== "Python"
You can use Python to view your settings. Start by importing the `settings` object from the `ultralytics` module. Print and return settings using the following commands:
```python
from ultralytics import settings
# View all settings
print(settings)
# Return a specific setting
value = settings['runs_dir']
```
=== "CLI"
Alternatively, the command-line interface allows you to check your settings with a simple command:
```bash
yolo settings
```
### Modifying Settings
Ultralytics allows users to easily modify their settings. Changes can be performed in the following ways:
!!! example "Update settings"
=== "Python"
Within the Python environment, call the `update` method on the `settings` object to change your settings:
```python
from ultralytics import settings
# Update a setting
settings.update({'runs_dir': '/path/to/runs'})
# Update multiple settings
settings.update({'runs_dir': '/path/to/runs', 'tensorboard': False})
# Reset settings to default values
settings.reset()
```
=== "CLI"
If you prefer using the command-line interface, the following command will allow you to modify your settings:
```bash
# Update a setting
yolo settings runs_dir='/path/to/runs'
# Update multiple settings
yolo settings runs_dir='/path/to/runs' tensorboard=False
# Reset settings to default values
yolo settings reset
```
### Understanding Settings
The table below provides an overview of the settings available for adjustment within Ultralytics. Each setting is outlined along with an example value, the data type, and a brief description.
| Name | Example Value | Data Type | Description |
|--------------------|-----------------------|-----------|------------------------------------------------------------------------------------------------------------------|
| `settings_version` | `'0.0.4'` | `str` | Ultralytics _settings_ version (different from Ultralytics [pip](https://pypi.org/project/ultralytics/) version) |
| `datasets_dir` | `'/path/to/datasets'` | `str` | The directory where the datasets are stored |
| `weights_dir` | `'/path/to/weights'` | `str` | The directory where the model weights are stored |
| `runs_dir` | `'/path/to/runs'` | `str` | The directory where the experiment runs are stored |
| `uuid` | `'a1b2c3d4'` | `str` | The unique identifier for the current settings |
| `sync` | `True` | `bool` | Whether to sync analytics and crashes to HUB |
| `api_key` | `''` | `str` | Ultralytics HUB [API Key](https://hub.ultralytics.com/settings?tab=api+keys) |
| `clearml` | `True` | `bool` | Whether to use ClearML logging |
| `comet` | `True` | `bool` | Whether to use [Comet ML](https://bit.ly/yolov8-readme-comet) for experiment tracking and visualization |
| `dvc` | `True` | `bool` | Whether to use DVC for version control |
| `hub` | `True` | `bool` | Whether to use [Ultralytics HUB](https://hub.ultralytics.com) integration |
| `mlflow` | `True` | `bool` | Whether to use MLFlow for experiment tracking |
| `neptune` | `True` | `bool` | Whether to use Neptune for experiment tracking |
| `raytune` | `True` | `bool` | Whether to use Ray Tune for hyperparameter tuning |
| `tensorboard` | `True` | `bool` | Whether to use TensorBoard for visualization |
| `wandb` | `True` | `bool` | Whether to use Weights & Biases logging |
As you navigate through your projects or experiments, be sure to revisit these settings to ensure that they are optimally configured for your needs.

@ -18,9 +18,9 @@ keywords: Ultralytics, YOLO, Configuration, cfg2dict, handle_deprecation, merge_
### ::: ultralytics.cfg._handle_deprecation ### ::: ultralytics.cfg._handle_deprecation
<br><br> <br><br>
## check_cfg_mismatch ## check_dict_alignment
--- ---
### ::: ultralytics.cfg.check_cfg_mismatch ### ::: ultralytics.cfg.check_dict_alignment
<br><br> <br><br>
## merge_equals_args ## merge_equals_args
@ -38,6 +38,16 @@ keywords: Ultralytics, YOLO, Configuration, cfg2dict, handle_deprecation, merge_
### ::: ultralytics.cfg.handle_yolo_settings ### ::: ultralytics.cfg.handle_yolo_settings
<br><br> <br><br>
## parse_key_value_pair
---
### ::: ultralytics.cfg.parse_key_value_pair
<br><br>
## smart_value
---
### ::: ultralytics.cfg.smart_value
<br><br>
## entrypoint ## entrypoint
--- ---
### ::: ultralytics.cfg.entrypoint ### ::: ultralytics.cfg.entrypoint

@ -1,8 +1,3 @@
---
description: Explore Ultralytics YOLO docs to understand task-specific models like DetectionModel, PoseModel, RTDETRDetectionModel and more. Plus, learn about ensemble, model loading.
keywords: Ultralytics, YOLO docs, DetectionModel, SegmentationModel, ClassificationModel, Ensemble, torch_safe_load, yaml_model_load, guess_model_task
---
## BaseModel ## BaseModel
--- ---
### ::: ultralytics.nn.tasks.BaseModel ### ::: ultralytics.nn.tasks.BaseModel

@ -28,6 +28,11 @@ keywords: Ultralytics, Utils, utilitarian functions, colorstr, yaml_save, set_lo
### ::: ultralytics.utils.TryExcept ### ::: ultralytics.utils.TryExcept
<br><br> <br><br>
## SettingsManager
---
### ::: ultralytics.utils.SettingsManager
<br><br>
## plt_settings ## plt_settings
--- ---
### ::: ultralytics.utils.plt_settings ### ::: ultralytics.utils.plt_settings
@ -148,14 +153,9 @@ keywords: Ultralytics, Utils, utilitarian functions, colorstr, yaml_save, set_lo
### ::: ultralytics.utils.set_sentry ### ::: ultralytics.utils.set_sentry
<br><br> <br><br>
## get_settings ## update_dict_recursive
---
### ::: ultralytics.utils.get_settings
<br><br>
## set_settings
--- ---
### ::: ultralytics.utils.set_settings ### ::: ultralytics.utils.update_dict_recursive
<br><br> <br><br>
## deprecation_warn ## deprecation_warn

@ -8,6 +8,11 @@ keywords: Ultralytics, utility functions, file operations, working directory, fi
### ::: ultralytics.utils.files.WorkingDirectory ### ::: ultralytics.utils.files.WorkingDirectory
<br><br> <br><br>
## spaces_in_path
---
### ::: ultralytics.utils.files.spaces_in_path
<br><br>
## increment_path ## increment_path
--- ---
### ::: ultralytics.utils.files.increment_path ### ::: ultralytics.utils.files.increment_path

@ -74,7 +74,7 @@ Where:
!!! warning "Warning" !!! warning "Warning"
Arguments must be passed as `arg=val` pairs, split by an equals `=` sign and delimited by spaces ` ` between pairs. Do not use `--` argument prefixes or commas `,` beteen arguments. Arguments must be passed as `arg=val` pairs, split by an equals `=` sign and delimited by spaces ` ` between pairs. Do not use `--` argument prefixes or commas `,` between arguments.
- `yolo predict model=yolov8n.pt imgsz=640 conf=0.25` &nbsp; - `yolo predict model=yolov8n.pt imgsz=640 conf=0.25` &nbsp;
- `yolo predict model yolov8n.pt imgsz 640 conf 0.25` &nbsp; - `yolo predict model yolov8n.pt imgsz 640 conf 0.25` &nbsp;

@ -29,7 +29,7 @@ To install the required packages, run:
!!! tip "Installation" !!! tip "Installation"
```bash ```bash
# Install and update Ultralytics and Ray Tune pacakges # Install and update Ultralytics and Ray Tune packages
pip install -U ultralytics 'ray[tune]' pip install -U ultralytics 'ray[tune]'
# Optionally install W&B for logging # Optionally install W&B for logging

@ -1,13 +1,14 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license # Ultralytics YOLO 🚀, AGPL-3.0 license
__version__ = '8.0.140' __version__ = '8.0.141'
from ultralytics.engine.model import YOLO from ultralytics.engine.model import YOLO
from ultralytics.hub import start from ultralytics.hub import start
from ultralytics.models import RTDETR, SAM from ultralytics.models import RTDETR, SAM
from ultralytics.models.fastsam import FastSAM from ultralytics.models.fastsam import FastSAM
from ultralytics.models.nas import NAS from ultralytics.models.nas import NAS
from ultralytics.utils import SETTINGS as settings
from ultralytics.utils.checks import check_yolo as checks from ultralytics.utils.checks import check_yolo as checks
from ultralytics.utils.downloads import download from ultralytics.utils.downloads import download
__all__ = '__version__', 'YOLO', 'NAS', 'SAM', 'FastSAM', 'RTDETR', 'checks', 'download', 'start' # allow simpler import __all__ = '__version__', 'YOLO', 'NAS', 'SAM', 'FastSAM', 'RTDETR', 'checks', 'download', 'start', 'settings' # allow simpler import

@ -9,9 +9,9 @@ from pathlib import Path
from types import SimpleNamespace from types import SimpleNamespace
from typing import Dict, List, Union from typing import Dict, List, Union
from ultralytics.utils import (DEFAULT_CFG, DEFAULT_CFG_DICT, DEFAULT_CFG_PATH, LOGGER, ROOT, USER_CONFIG_DIR, from ultralytics.utils import (DEFAULT_CFG, DEFAULT_CFG_DICT, DEFAULT_CFG_PATH, LOGGER, ROOT, SETTINGS, SETTINGS_YAML,
IterableSimpleNamespace, __version__, checks, colorstr, deprecation_warn, get_settings, IterableSimpleNamespace, __version__, checks, colorstr, deprecation_warn, yaml_load,
yaml_load, yaml_print) yaml_print)
# Define valid tasks and modes # Define valid tasks and modes
MODES = 'train', 'val', 'predict', 'export', 'track', 'benchmark' MODES = 'train', 'val', 'predict', 'export', 'track', 'benchmark'
@ -28,7 +28,6 @@ TASK2METRIC = {
'classify': 'metrics/accuracy_top1', 'classify': 'metrics/accuracy_top1',
'pose': 'metrics/mAP50-95(P)'} 'pose': 'metrics/mAP50-95(P)'}
CLI_HELP_MSG = \ CLI_HELP_MSG = \
f""" f"""
Arguments received: {str(['yolo'] + sys.argv[1:])}. Ultralytics 'yolo' commands use the following syntax: Arguments received: {str(['yolo'] + sys.argv[1:])}. Ultralytics 'yolo' commands use the following syntax:
@ -111,7 +110,7 @@ def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, ove
# Merge overrides # Merge overrides
if overrides: if overrides:
overrides = cfg2dict(overrides) overrides = cfg2dict(overrides)
check_cfg_mismatch(cfg, overrides) check_dict_alignment(cfg, overrides)
cfg = {**cfg, **overrides} # merge cfg and overrides dicts (prefer overrides) cfg = {**cfg, **overrides} # merge cfg and overrides dicts (prefer overrides)
# Special handling for numeric project/name # Special handling for numeric project/name
@ -147,9 +146,7 @@ def get_cfg(cfg: Union[str, Path, Dict, SimpleNamespace] = DEFAULT_CFG_DICT, ove
def _handle_deprecation(custom): def _handle_deprecation(custom):
""" """Hardcoded function to handle deprecated config keys"""
Hardcoded function to handle deprecated config keys
"""
for key in custom.copy().keys(): for key in custom.copy().keys():
if key == 'hide_labels': if key == 'hide_labels':
@ -165,7 +162,7 @@ def _handle_deprecation(custom):
return custom return custom
def check_cfg_mismatch(base: Dict, custom: Dict, e=None): def check_dict_alignment(base: Dict, custom: Dict, e=None):
""" """
This function checks for any mismatched keys between a custom configuration list and a base configuration list. This function checks for any mismatched keys between a custom configuration list and a base configuration list.
If any mismatched keys are found, the function prints out similar keys from the base list and exits the program. If any mismatched keys are found, the function prints out similar keys from the base list and exits the program.
@ -175,13 +172,13 @@ def check_cfg_mismatch(base: Dict, custom: Dict, e=None):
base (dict): a dictionary of base configuration options base (dict): a dictionary of base configuration options
""" """
custom = _handle_deprecation(custom) custom = _handle_deprecation(custom)
base, custom = (set(x.keys()) for x in (base, custom)) base_keys, custom_keys = (set(x.keys()) for x in (base, custom))
mismatched = [x for x in custom if x not in base] mismatched = [k for k in custom_keys if k not in base_keys]
if mismatched: if mismatched:
string = '' string = ''
for x in mismatched: for x in mismatched:
matches = get_close_matches(x, base) # key list matches = get_close_matches(x, base_keys) # key list
matches = [f'{k}={DEFAULT_CFG_DICT[k]}' if DEFAULT_CFG_DICT.get(k) is not None else k for k in matches] matches = [f'{k}={base[k]}' if base.get(k) is not None else k for k in matches]
match_str = f'Similar arguments are i.e. {matches}.' if matches else '' match_str = f'Similar arguments are i.e. {matches}.' if matches else ''
string += f"'{colorstr('red', 'bold', x)}' is not a valid YOLO argument. {match_str}\n" string += f"'{colorstr('red', 'bold', x)}' is not a valid YOLO argument. {match_str}\n"
raise SyntaxError(string + CLI_HELP_MSG) from e raise SyntaxError(string + CLI_HELP_MSG) from e
@ -251,12 +248,39 @@ def handle_yolo_settings(args: List[str]) -> None:
Example: Example:
python my_script.py yolo settings reset python my_script.py yolo settings reset
""" """
path = USER_CONFIG_DIR / 'settings.yaml' # get SETTINGS YAML file path if any(args):
if any(args) and args[0] == 'reset': if args[0] == 'reset':
path.unlink() # delete the settings file SETTINGS_YAML.unlink() # delete the settings file
get_settings() # create new settings SETTINGS.reset() # create new settings
LOGGER.info('Settings reset successfully') # inform the user that settings have been reset LOGGER.info('Settings reset successfully') # inform the user that settings have been reset
yaml_print(path) # print the current settings else:
new = dict(parse_key_value_pair(a) for a in args)
check_dict_alignment(SETTINGS, new)
SETTINGS.update(new)
yaml_print(SETTINGS_YAML) # print the current settings
def parse_key_value_pair(pair):
"""Parse one 'key=value' pair and return key and value."""
re.sub(r' *= *', '=', pair) # remove spaces around equals sign
k, v = pair.split('=', 1) # split on first '=' sign
assert v, f"missing '{k}' value"
return k, smart_value(v)
def smart_value(v):
"""Convert a string to an underlying type such as int, float, bool, etc."""
if v.lower() == 'none':
return None
elif v.lower() == 'true':
return True
elif v.lower() == 'false':
return False
else:
with contextlib.suppress(Exception):
return eval(v)
return v
def entrypoint(debug=''): def entrypoint(debug=''):
@ -305,25 +329,14 @@ def entrypoint(debug=''):
a = a[:-1] a = a[:-1]
if '=' in a: if '=' in a:
try: try:
re.sub(r' *= *', '=', a) # remove spaces around equals sign k, v = parse_key_value_pair(a)
k, v = a.split('=', 1) # split on first '=' sign
assert v, f"missing '{k}' value"
if k == 'cfg': # custom.yaml passed if k == 'cfg': # custom.yaml passed
LOGGER.info(f'Overriding {DEFAULT_CFG_PATH} with {v}') LOGGER.info(f'Overriding {DEFAULT_CFG_PATH} with {v}')
overrides = {k: val for k, val in yaml_load(checks.check_yaml(v)).items() if k != 'cfg'} overrides = {k: val for k, val in yaml_load(checks.check_yaml(v)).items() if k != 'cfg'}
else: else:
if v.lower() == 'none':
v = None
elif v.lower() == 'true':
v = True
elif v.lower() == 'false':
v = False
else:
with contextlib.suppress(Exception):
v = eval(v)
overrides[k] = v overrides[k] = v
except (NameError, SyntaxError, ValueError, AssertionError) as e: except (NameError, SyntaxError, ValueError, AssertionError) as e:
check_cfg_mismatch(full_args_dict, {a: ''}, e) check_dict_alignment(full_args_dict, {a: ''}, e)
elif a in TASKS: elif a in TASKS:
overrides['task'] = a overrides['task'] = a
@ -338,13 +351,13 @@ def entrypoint(debug=''):
raise SyntaxError(f"'{colorstr('red', 'bold', a)}' is a valid YOLO argument but is missing an '=' sign " raise SyntaxError(f"'{colorstr('red', 'bold', a)}' is a valid YOLO argument but is missing an '=' sign "
f"to set its value, i.e. try '{a}={DEFAULT_CFG_DICT[a]}'\n{CLI_HELP_MSG}") f"to set its value, i.e. try '{a}={DEFAULT_CFG_DICT[a]}'\n{CLI_HELP_MSG}")
else: else:
check_cfg_mismatch(full_args_dict, {a: ''}) check_dict_alignment(full_args_dict, {a: ''})
# Check keys # Check keys
check_cfg_mismatch(full_args_dict, overrides) check_dict_alignment(full_args_dict, overrides)
# Mode # Mode
mode = overrides.get('mode', None) mode = overrides.get('mode')
if mode is None: if mode is None:
mode = DEFAULT_CFG.mode or 'predict' mode = DEFAULT_CFG.mode or 'predict'
LOGGER.warning(f"WARNING ⚠️ 'mode' is missing. Valid modes are {MODES}. Using default 'mode={mode}'.") LOGGER.warning(f"WARNING ⚠️ 'mode' is missing. Valid modes are {MODES}. Using default 'mode={mode}'.")

@ -3,7 +3,7 @@
import requests import requests
from ultralytics.hub.utils import HUB_API_ROOT, PREFIX, request_with_credentials from ultralytics.hub.utils import HUB_API_ROOT, PREFIX, request_with_credentials
from ultralytics.utils import LOGGER, SETTINGS, emojis, is_colab, set_settings from ultralytics.utils import LOGGER, SETTINGS, emojis, is_colab
API_KEY_URL = 'https://hub.ultralytics.com/settings?tab=api+keys' API_KEY_URL = 'https://hub.ultralytics.com/settings?tab=api+keys'
@ -45,7 +45,7 @@ class Auth:
# Update SETTINGS with the new API key after successful authentication # Update SETTINGS with the new API key after successful authentication
if success: if success:
set_settings({'api_key': self.api_key}) SETTINGS.update({'api_key': self.api_key})
# Log that the new login was successful # Log that the new login was successful
if verbose: if verbose:
LOGGER.info(f'{PREFIX}New authentication successful ✅') LOGGER.info(f'{PREFIX}New authentication successful ✅')

@ -713,62 +713,105 @@ def set_sentry():
logging.getLogger(logger).setLevel(logging.CRITICAL) logging.getLogger(logger).setLevel(logging.CRITICAL)
def get_settings(file=SETTINGS_YAML, version='0.0.3'): def update_dict_recursive(d, u):
""" """
Loads a global Ultralytics settings YAML file or creates one with default values if it does not exist. Recursively updates the dictionary `d` with the key-value pairs from the dictionary `u` without overwriting
entire sub-dictionaries. Note that function recursion is intended and not a problem, as this allows for updating
nested dictionaries at any arbitrary depth.
Args: Args:
file (Path): Path to the Ultralytics settings YAML file. Defaults to 'settings.yaml' in the USER_CONFIG_DIR. d (dict): The dictionary to be updated.
version (str): Settings version. If min settings version not met, new default settings will be saved. u (dict): The dictionary to update `d` with.
Returns: Returns:
(dict): Dictionary of settings key-value pairs. (dict): The recursively updated dictionary.
""" """
import hashlib for k, v in u.items():
d[k] = update_dict_recursive(d.get(k, {}), v) if isinstance(v, dict) else v
return d
from ultralytics.utils.checks import check_version
from ultralytics.utils.torch_utils import torch_distributed_zero_first
git_dir = get_git_dir() class SettingsManager(dict):
root = git_dir or Path() """
datasets_root = (root.parent if git_dir and is_dir_writeable(root.parent) else root).resolve() Manages Ultralytics settings stored in a YAML file.
defaults = {
'datasets_dir': str(datasets_root / 'datasets'), # default datasets directory.
'weights_dir': str(root / 'weights'), # default weights directory.
'runs_dir': str(root / 'runs'), # default runs directory.
'uuid': hashlib.sha256(str(uuid.getnode()).encode()).hexdigest(), # SHA-256 anonymized UUID hash
'sync': True, # sync analytics to help with YOLO development
'api_key': '', # Ultralytics HUB API key (https://hub.ultralytics.com/)
'settings_version': version} # Ultralytics settings version
with torch_distributed_zero_first(RANK):
if not file.exists():
yaml_save(file, defaults)
settings = yaml_load(file)
# Check that settings keys and types match defaults
correct = \
settings \
and settings.keys() == defaults.keys() \
and all(type(a) == type(b) for a, b in zip(settings.values(), defaults.values())) \
and check_version(settings['settings_version'], version)
if not correct:
LOGGER.warning('WARNING ⚠️ Ultralytics settings reset to defaults. This is normal and may be due to a '
'recent ultralytics package update, but may have overwritten previous settings. '
f"\nView and update settings with 'yolo settings' or at '{file}'")
settings = defaults # merge **defaults with **settings (prefer **settings)
yaml_save(file, settings) # save updated defaults
return settings
Args:
file (str | Path): Path to the Ultralytics settings YAML file. Default is USER_CONFIG_DIR / 'settings.yaml'.
version (str): Settings version. In case of local version mismatch, new default settings will be saved.
"""
def __init__(self, file=SETTINGS_YAML, version='0.0.4'):
import copy
import hashlib
from ultralytics.utils.checks import check_version
from ultralytics.utils.torch_utils import torch_distributed_zero_first
git_dir = get_git_dir()
root = git_dir or Path()
datasets_root = (root.parent if git_dir and is_dir_writeable(root.parent) else root).resolve()
self.file = Path(file)
self.version = version
self.defaults = {
'settings_version': version,
'datasets_dir': str(datasets_root / 'datasets'),
'weights_dir': str(root / 'weights'),
'runs_dir': str(root / 'runs'),
'uuid': hashlib.sha256(str(uuid.getnode()).encode()).hexdigest(),
'sync': True,
'api_key': '',
'clearml': True, # integrations
'comet': True,
'dvc': True,
'hub': True,
'mlflow': True,
'neptune': True,
'raytune': True,
'tensorboard': True,
'wandb': True}
super().__init__(copy.deepcopy(self.defaults))
with torch_distributed_zero_first(RANK):
if not self.file.exists():
self.save()
self.load()
correct_keys = self.keys() == self.defaults.keys()
correct_types = all(type(a) == type(b) for a, b in zip(self.values(), self.defaults.values()))
correct_version = check_version(self['settings_version'], self.version)
if not (correct_keys and correct_types and correct_version):
LOGGER.warning(
'WARNING ⚠️ Ultralytics settings reset to default values. This may be due to a possible problem '
'with your settings or a recent ultralytics package update. '
f"\nView settings with 'yolo settings' or at '{self.file}'"
"\nUpdate settings with 'yolo settings key=value', i.e. 'yolo settings runs_dir=path/to/dir'.")
self.reset()
def load(self):
"""Loads settings from the YAML file."""
self.update(yaml_load(self.file))
def save(self):
"""Saves the current settings to the YAML file."""
yaml_save(self.file, dict(self))
def update(self, *args, **kwargs):
"""Updates a setting value in the current settings and saves the settings."""
new = dict(*args, **kwargs)
if any(isinstance(v, dict) for v in new.values()):
update_dict_recursive(self, new)
else:
# super().update(*args, **kwargs)
super().update(new)
self.save()
def set_settings(kwargs, file=SETTINGS_YAML): def reset(self):
""" """Resets the settings to default and saves them."""
Function that runs on a first-time ultralytics package installation to set up global settings and create necessary self.clear()
directories. self.update(self.defaults)
""" self.save()
SETTINGS.update(kwargs)
yaml_save(file, SETTINGS)
def deprecation_warn(arg, new_arg, version=None): def deprecation_warn(arg, new_arg, version=None):
@ -794,7 +837,7 @@ def url2file(url):
# Check first-install steps # Check first-install steps
PREFIX = colorstr('Ultralytics: ') PREFIX = colorstr('Ultralytics: ')
SETTINGS = get_settings() SETTINGS = SettingsManager() # initialize settings
DATASETS_DIR = Path(SETTINGS['datasets_dir']) # global datasets directory DATASETS_DIR = Path(SETTINGS['datasets_dir']) # global datasets directory
ENVIRONMENT = 'Colab' if is_colab() else 'Kaggle' if is_kaggle() else 'Jupyter' if is_jupyter() else \ ENVIRONMENT = 'Colab' if is_colab() else 'Kaggle' if is_kaggle() else 'Jupyter' if is_jupyter() else \
'Docker' if is_docker() else platform.system() 'Docker' if is_docker() else platform.system()

@ -5,7 +5,7 @@ import re
import matplotlib.image as mpimg import matplotlib.image as mpimg
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from ultralytics.utils import LOGGER, TESTS_RUNNING from ultralytics.utils import LOGGER, SETTINGS, TESTS_RUNNING
from ultralytics.utils.torch_utils import model_info_for_loggers from ultralytics.utils.torch_utils import model_info_for_loggers
try: try:
@ -16,6 +16,7 @@ try:
assert hasattr(clearml, '__version__') # verify package is not directory assert hasattr(clearml, '__version__') # verify package is not directory
assert not TESTS_RUNNING # do not log pytest assert not TESTS_RUNNING # do not log pytest
assert SETTINGS['clearml'] is True # verify integration is enabled
except (ImportError, AssertionError): except (ImportError, AssertionError):
clearml = None clearml = None

@ -3,7 +3,7 @@
import os import os
from pathlib import Path from pathlib import Path
from ultralytics.utils import LOGGER, RANK, TESTS_RUNNING, ops from ultralytics.utils import LOGGER, RANK, SETTINGS, TESTS_RUNNING, ops
from ultralytics.utils.torch_utils import model_info_for_loggers from ultralytics.utils.torch_utils import model_info_for_loggers
try: try:
@ -11,6 +11,7 @@ try:
assert not TESTS_RUNNING # do not log pytest assert not TESTS_RUNNING # do not log pytest
assert hasattr(comet_ml, '__version__') # verify package is not directory assert hasattr(comet_ml, '__version__') # verify package is not directory
assert SETTINGS['comet'] is True # verify integration is enabled
except (ImportError, AssertionError): except (ImportError, AssertionError):
comet_ml = None comet_ml = None

@ -3,7 +3,7 @@ import os
import pkg_resources as pkg import pkg_resources as pkg
from ultralytics.utils import LOGGER, TESTS_RUNNING from ultralytics.utils import LOGGER, SETTINGS, TESTS_RUNNING
from ultralytics.utils.torch_utils import model_info_for_loggers from ultralytics.utils.torch_utils import model_info_for_loggers
try: try:
@ -12,6 +12,7 @@ try:
import dvclive import dvclive
assert not TESTS_RUNNING # do not log pytest assert not TESTS_RUNNING # do not log pytest
assert SETTINGS['dvc'] is True # verify integration is enabled
ver = version('dvclive') ver = version('dvclive')
if pkg.parse_version(ver) < pkg.parse_version('2.11.0'): if pkg.parse_version(ver) < pkg.parse_version('2.11.0'):

@ -4,7 +4,7 @@ import json
from time import time from time import time
from ultralytics.hub.utils import PREFIX, events from ultralytics.hub.utils import PREFIX, events
from ultralytics.utils import LOGGER from ultralytics.utils import LOGGER, SETTINGS
from ultralytics.utils.torch_utils import model_info_for_loggers from ultralytics.utils.torch_utils import model_info_for_loggers
@ -84,4 +84,4 @@ callbacks = {
'on_train_start': on_train_start, 'on_train_start': on_train_start,
'on_val_start': on_val_start, 'on_val_start': on_val_start,
'on_predict_start': on_predict_start, 'on_predict_start': on_predict_start,
'on_export_start': on_export_start} 'on_export_start': on_export_start} if SETTINGS['hub'] is True else {} # verify enabled

@ -4,13 +4,14 @@ import os
import re import re
from pathlib import Path from pathlib import Path
from ultralytics.utils import LOGGER, TESTS_RUNNING, colorstr from ultralytics.utils import LOGGER, SETTINGS, TESTS_RUNNING, colorstr
try: try:
import mlflow import mlflow
assert not TESTS_RUNNING # do not log pytest assert not TESTS_RUNNING # do not log pytest
assert hasattr(mlflow, '__version__') # verify package is not directory assert hasattr(mlflow, '__version__') # verify package is not directory
assert SETTINGS['mlflow'] is True # verify integration is enabled
except (ImportError, AssertionError): except (ImportError, AssertionError):
mlflow = None mlflow = None

@ -3,7 +3,7 @@
import matplotlib.image as mpimg import matplotlib.image as mpimg
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from ultralytics.utils import LOGGER, TESTS_RUNNING from ultralytics.utils import LOGGER, SETTINGS, TESTS_RUNNING
from ultralytics.utils.torch_utils import model_info_for_loggers from ultralytics.utils.torch_utils import model_info_for_loggers
try: try:
@ -12,6 +12,7 @@ try:
assert not TESTS_RUNNING # do not log pytest assert not TESTS_RUNNING # do not log pytest
assert hasattr(neptune, '__version__') assert hasattr(neptune, '__version__')
assert SETTINGS['neptune'] is True # verify integration is enabled
except (ImportError, AssertionError): except (ImportError, AssertionError):
neptune = None neptune = None

@ -1,9 +1,13 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license # Ultralytics YOLO 🚀, AGPL-3.0 license
from ultralytics.utils import SETTINGS
try: try:
import ray import ray
from ray import tune from ray import tune
from ray.air import session from ray.air import session
assert SETTINGS['raytune'] is True # verify integration is enabled
except (ImportError, AssertionError): except (ImportError, AssertionError):
tune = None tune = None

@ -1,11 +1,12 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license # Ultralytics YOLO 🚀, AGPL-3.0 license
from ultralytics.utils import LOGGER, TESTS_RUNNING, colorstr from ultralytics.utils import LOGGER, SETTINGS, TESTS_RUNNING, colorstr
try: try:
from torch.utils.tensorboard import SummaryWriter from torch.utils.tensorboard import SummaryWriter
assert not TESTS_RUNNING # do not log pytest assert not TESTS_RUNNING # do not log pytest
assert SETTINGS['tensorboard'] is True # verify integration is enabled
# TypeError for handling 'Descriptors cannot not be created directly.' protobuf errors in Windows # TypeError for handling 'Descriptors cannot not be created directly.' protobuf errors in Windows
except (ImportError, AssertionError, TypeError): except (ImportError, AssertionError, TypeError):

@ -1,5 +1,5 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license # Ultralytics YOLO 🚀, AGPL-3.0 license
from ultralytics.utils import TESTS_RUNNING from ultralytics.utils import SETTINGS, TESTS_RUNNING
from ultralytics.utils.torch_utils import model_info_for_loggers from ultralytics.utils.torch_utils import model_info_for_loggers
try: try:
@ -7,6 +7,7 @@ try:
assert hasattr(wb, '__version__') assert hasattr(wb, '__version__')
assert not TESTS_RUNNING # do not log pytest assert not TESTS_RUNNING # do not log pytest
assert SETTINGS['wandb'] is True # verify integration is enabled
except (ImportError, AssertionError): except (ImportError, AssertionError):
wb = None wb = None
@ -16,7 +17,7 @@ _processed_plots = {}
def _log_plots(plots, step): def _log_plots(plots, step):
for name, params in plots.items(): for name, params in plots.items():
timestamp = params['timestamp'] timestamp = params['timestamp']
if _processed_plots.get(name, None) != timestamp: if _processed_plots.get(name) != timestamp:
wb.run.log({name.stem: wb.Image(str(name))}, step=step) wb.run.log({name.stem: wb.Image(str(name))}, step=step)
_processed_plots[name] = timestamp _processed_plots[name] = timestamp

@ -38,7 +38,7 @@ def spaces_in_path(path):
path (str | Path): The original path. path (str | Path): The original path.
Yields: Yields:
Path: Temporary path with spaces replaced by underscores if spaces were present, otherwise the original path. (Path): Temporary path with spaces replaced by underscores if spaces were present, otherwise the original path.
Examples: Examples:
with spaces_in_path('/path/with spaces') as new_path: with spaces_in_path('/path/with spaces') as new_path:

Loading…
Cancel
Save