ultralytics 8.0.182 remove deprecated pkg_resources (#4979)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Glenn Jocher 2023-09-19 20:16:38 +02:00 committed by GitHub
parent 0cf82f5040
commit 28569ced8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 134 additions and 45 deletions

View File

@ -25,13 +25,14 @@ body:
Please select the part of YOLOv8 where you found the bug. Please select the part of YOLOv8 where you found the bug.
multiple: true multiple: true
options: options:
- "Training" - "Install"
- "Validation" - "Train"
- "Detection" - "Val"
- "Predict"
- "Export" - "Export"
- "PyTorch Hub"
- "Multi-GPU" - "Multi-GPU"
- "Evolution" - "Augmentation"
- "Hyperparameter Tuning"
- "Integrations" - "Integrations"
- "Other" - "Other"
validations: validations:
@ -51,9 +52,19 @@ body:
label: Environment label: Environment
description: Please specify the software and hardware you used to produce the bug. description: Please specify the software and hardware you used to produce the bug.
placeholder: | placeholder: |
- YOLO: Ultralytics YOLOv8.0.21 🚀 Python-3.8.10 torch-1.13.1+cu117 CUDA:0 (A100-SXM-80GB, 81251MiB) Paste output of `yolo checks` or `ultralytics.checks()` commands:
- OS: Ubuntu 20.04 ```
- Python: 3.8.10 Ultralytics YOLOv8.0.181 🚀 Python-3.11.2 torch-2.0.1 CPU (Apple M2)
Setup complete ✅ (8 CPUs, 16.0 GB RAM, 266.5/460.4 GB disk)
OS macOS-13.5.2
Environment Jupyter
Python 3.11.2
Install git
RAM 16.00 GB
CPU Apple M2
CUDA None
```
validations: validations:
required: false required: false

View File

@ -9,8 +9,8 @@ FROM ultralytics/ultralytics:latest
WORKDIR /actions-runner WORKDIR /actions-runner
# Download and unpack the latest runner from https://github.com/actions/runner # Download and unpack the latest runner from https://github.com/actions/runner
RUN FILENAME=actions-runner-linux-x64-2.308.0.tar.gz && \ RUN FILENAME=actions-runner-linux-x64-2.309.0.tar.gz && \
curl -o $FILENAME -L https://github.com/actions/runner/releases/download/v2.308.0/$FILENAME && \ curl -o $FILENAME -L https://github.com/actions/runner/releases/download/v2.309.0/$FILENAME && \
tar xzf $FILENAME && \ tar xzf $FILENAME && \
rm $FILENAME rm $FILENAME

View File

@ -9,6 +9,14 @@ keywords: Ultralytics, utility checks, ASCII, check_version, pip_update, check_p
Full source code for this file is available at [https://github.com/ultralytics/ultralytics/blob/main/ultralytics/utils/checks.py](https://github.com/ultralytics/ultralytics/blob/main/ultralytics/utils/checks.py). Help us fix any issues you see by submitting a [Pull Request](https://docs.ultralytics.com/help/contributing/) 🛠️. Thank you 🙏! Full source code for this file is available at [https://github.com/ultralytics/ultralytics/blob/main/ultralytics/utils/checks.py](https://github.com/ultralytics/ultralytics/blob/main/ultralytics/utils/checks.py). Help us fix any issues you see by submitting a [Pull Request](https://docs.ultralytics.com/help/contributing/) 🛠️. Thank you 🙏!
---
## ::: ultralytics.utils.checks.parse_requirements
<br><br>
---
## ::: ultralytics.utils.checks.parse_version
<br><br>
--- ---
## ::: ultralytics.utils.checks.is_ascii ## ::: ultralytics.utils.checks.is_ascii
<br><br> <br><br>
@ -69,6 +77,10 @@ keywords: Ultralytics, utility checks, ASCII, check_version, pip_update, check_p
## ::: ultralytics.utils.checks.check_yolo ## ::: ultralytics.utils.checks.check_yolo
<br><br> <br><br>
---
## ::: ultralytics.utils.checks.collect_system_info
<br><br>
--- ---
## ::: ultralytics.utils.checks.check_amp ## ::: ultralytics.utils.checks.check_amp
<br><br> <br><br>

View File

@ -1,6 +1,6 @@
# Ultralytics YOLO 🚀, AGPL-3.0 license # Ultralytics YOLO 🚀, AGPL-3.0 license
__version__ = '8.0.181' __version__ = '8.0.182'
from ultralytics.models import RTDETR, SAM, YOLO from ultralytics.models import RTDETR, SAM, YOLO
from ultralytics.models.fastsam import FastSAM from ultralytics.models.fastsam import FastSAM

View File

@ -333,7 +333,7 @@ def entrypoint(debug=''):
special = { special = {
'help': lambda: LOGGER.info(CLI_HELP_MSG), 'help': lambda: LOGGER.info(CLI_HELP_MSG),
'checks': checks.check_yolo, 'checks': checks.collect_system_info,
'version': lambda: LOGGER.info(__version__), 'version': lambda: LOGGER.info(__version__),
'settings': lambda: handle_yolo_settings(args[1:]), 'settings': lambda: handle_yolo_settings(args[1:]),
'cfg': lambda: yaml_print(DEFAULT_CFG_PATH), 'cfg': lambda: yaml_print(DEFAULT_CFG_PATH),

View File

@ -143,6 +143,9 @@ class Exporter:
_callbacks (list, optional): List of callback functions. Defaults to None. _callbacks (list, optional): List of callback functions. Defaults to None.
""" """
self.args = get_cfg(cfg, overrides) self.args = get_cfg(cfg, overrides)
if self.args.format.lower() in ('coreml', 'mlmodel'): # fix attempt for protobuf<3.20.x errors
os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'python' # must run before TensorBoard callback
self.callbacks = _callbacks or callbacks.get_default_callbacks() self.callbacks = _callbacks or callbacks.get_default_callbacks()
callbacks.add_integration_callbacks(self) callbacks.add_integration_callbacks(self)
@ -155,7 +158,6 @@ class Exporter:
if format in ('tensorrt', 'trt'): # 'engine' aliases if format in ('tensorrt', 'trt'): # 'engine' aliases
format = 'engine' format = 'engine'
if format in ('mlmodel', 'mlpackage', 'mlprogram', 'apple', 'ios', 'coreml'): # 'coreml' aliases if format in ('mlmodel', 'mlpackage', 'mlprogram', 'apple', 'ios', 'coreml'): # 'coreml' aliases
os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'python' # fix attempt for protobuf<3.20.x errors
format = 'coreml' format = 'coreml'
fmts = tuple(export_formats()['Argument'][1:]) # available export formats fmts = tuple(export_formats()['Argument'][1:]) # available export formats
flags = [x == format for x in fmts] flags = [x == format for x in fmts]

View File

@ -143,7 +143,7 @@ class FastSAMPrompt:
save_path = Path(output) / result_name save_path = Path(output) / result_name
save_path.parent.mkdir(exist_ok=True, parents=True) save_path.parent.mkdir(exist_ok=True, parents=True)
image = Image.frombytes('RGB', fig.canvas.get_width_height(), fig.canvas.tostring_rgb()) image = Image.frombytes('RGB', fig.canvas.get_width_height(), fig.canvas.buffer_rgba())
image.save(save_path) image.save(save_path)
plt.close() plt.close()
pbar.set_description(f'Saving {result_name} to {save_path}') pbar.set_description(f'Saving {result_name} to {save_path}')

View File

@ -213,11 +213,6 @@ def add_integration_callbacks(instance):
from .wb import callbacks as wb_cb from .wb import callbacks as wb_cb
callbacks_list.extend([clear_cb, comet_cb, dvc_cb, mlflow_cb, neptune_cb, tune_cb, tb_cb, wb_cb]) callbacks_list.extend([clear_cb, comet_cb, dvc_cb, mlflow_cb, neptune_cb, tune_cb, tb_cb, wb_cb])
# Load export callbacks (patch to avoid CoreML protobuf error)
if 'Exporter' in instance.__class__.__name__:
from .tensorboard import callbacks as tb_cb
callbacks_list.append(tb_cb)
# Add the callbacks to the callbacks dictionary # Add the callbacks to the callbacks dictionary
for callbacks in callbacks_list: for callbacks in callbacks_list:
for k, v in callbacks.items(): for k, v in callbacks.items():

View File

@ -9,20 +9,60 @@ import platform
import re import re
import shutil import shutil
import subprocess import subprocess
import sys
import time import time
from importlib.metadata import PackageNotFoundError, version
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
import cv2 import cv2
import numpy as np import numpy as np
import pkg_resources as pkg
import requests import requests
import torch import torch
from matplotlib import font_manager from matplotlib import font_manager
from ultralytics.utils import (ASSETS, AUTOINSTALL, LINUX, LOGGER, ONLINE, ROOT, USER_CONFIG_DIR, ThreadingLocked, from ultralytics.utils import (ASSETS, AUTOINSTALL, LINUX, LOGGER, ONLINE, ROOT, USER_CONFIG_DIR, SimpleNamespace,
TryExcept, clean_url, colorstr, downloads, emojis, is_colab, is_docker, is_jupyter, ThreadingLocked, TryExcept, clean_url, colorstr, downloads, emojis, is_colab, is_docker,
is_kaggle, is_online, is_pip_package, url2file) is_jupyter, is_kaggle, is_online, is_pip_package, url2file)
def parse_requirements(file_path=ROOT.parent / 'requirements.txt'):
"""
Parse a requirements.txt file, ignoring lines that start with '#' and any text after '#'.
Args:
file_path (Path): Path to the requirements.txt file.
Returns:
(List[Dict[str, str]]): List of parsed requirements as dictionaries with `name` and `specifier` keys.
"""
requirements = []
for line in Path(file_path).read_text().splitlines():
line = line.strip()
if line and not line.startswith('#'):
line = line.split('#')[0].strip() # ignore inline comments
match = re.match(r'([a-zA-Z0-9-_]+)([<>!=~]+.*)?', line)
if match:
requirements.append(SimpleNamespace(name=match[1], specifier=match[2].strip() if match[2] else ''))
return requirements
def parse_version(v='0.0.0') -> tuple:
"""
Convert a version string to a tuple of integers, also returning any extra non-numeric string attached to the version.
Args:
v (str): Version string, i.e. '2.0.1+cpu'
Returns:
(tuple): Tuple of integers representing the numeric part of the version and the extra string, i.e. (2, 0, 1)
"""
correct = [True if x == '.' else x.isdigit() for x in v] # first non-number index
if False in correct:
v = v[:correct.index(False)]
return tuple(map(int, v.split('.'))) # '2.0.1+cpu' -> (2, 0, 1)
def is_ascii(s) -> bool: def is_ascii(s) -> bool:
@ -121,24 +161,33 @@ def check_version(current: str = '0.0.0',
# check if current version is between 20.04 (inclusive) and 22.04 (exclusive) # check if current version is between 20.04 (inclusive) and 22.04 (exclusive)
check_version(current='21.10', required='>20.04,<22.04') check_version(current='21.10', required='>20.04,<22.04')
""" """
current = pkg.parse_version(current) if not required:
return True # in case required is '' or None
# import pkg_resources as pkg
# current = pkg.parse_version(current)
current = parse_version(current) # '1.2.3' -> (1, 2, 3)
constraints = re.findall(r'([<>!=]{1,2}\s*\d+\.\d+)', required) or [f'>={required}'] constraints = re.findall(r'([<>!=]{1,2}\s*\d+\.\d+)', required) or [f'>={required}']
result = True result = True
for constraint in constraints: for constraint in constraints:
op, version = re.match(r'([<>!=]{1,2})\s*(\d+\.\d+)', constraint).groups() op, v = re.match(r'([<>!=]{1,2})\s*(\d+\.\d+)', constraint).groups()
version = pkg.parse_version(version)
if op == '==' and current != version: # v = pkg.parse_version(v)
v = parse_version(v) # '1.2.3' -> (1, 2, 3)
if op == '==' and current != v:
result = False result = False
elif op == '!=' and current == version: elif op == '!=' and current == v:
result = False result = False
elif op == '>=' and not (current >= version): elif op == '>=' and not (current >= v):
result = False result = False
elif op == '<=' and not (current <= version): elif op == '<=' and not (current <= v):
result = False result = False
elif op == '>' and not (current > version): elif op == '>' and not (current > v):
result = False result = False
elif op == '<' and not (current < version): elif op == '<' and not (current < v):
result = False result = False
if not result: if not result:
warning_message = f'WARNING ⚠️ {name}{op}{required} is required, but {name}=={current} is currently installed' warning_message = f'WARNING ⚠️ {name}{op}{required} is required, but {name}=={current} is currently installed'
@ -177,7 +226,7 @@ def check_pip_update_available():
with contextlib.suppress(Exception): with contextlib.suppress(Exception):
from ultralytics import __version__ from ultralytics import __version__
latest = check_latest_pypi_version() latest = check_latest_pypi_version()
if pkg.parse_version(__version__) < pkg.parse_version(latest): # update is available if check_version(__version__, f'<{latest}'): # check if current version is < latest version
LOGGER.info(f'New https://pypi.org/project/ultralytics/{latest} available 😃 ' LOGGER.info(f'New https://pypi.org/project/ultralytics/{latest} available 😃 '
f"Update with 'pip install -U ultralytics'") f"Update with 'pip install -U ultralytics'")
return True return True
@ -253,29 +302,25 @@ def check_requirements(requirements=ROOT.parent / 'requirements.txt', exclude=()
check_requirements(['numpy', 'ultralytics>=8.0.0']) check_requirements(['numpy', 'ultralytics>=8.0.0'])
``` ```
""" """
prefix = colorstr('red', 'bold', 'requirements:') prefix = colorstr('red', 'bold', 'requirements:')
check_python() # check python version check_python() # check python version
check_torchvision() # check torch-torchvision compatibility check_torchvision() # check torch-torchvision compatibility
if isinstance(requirements, Path): # requirements.txt file if isinstance(requirements, Path): # requirements.txt file
file = requirements.resolve() file = requirements.resolve()
assert file.exists(), f'{prefix} {file} not found, check failed.' assert file.exists(), f'{prefix} {file} not found, check failed.'
with file.open() as f: requirements = [f'{x.name}{x.specifier}' for x in parse_requirements(file) if x.name not in exclude]
requirements = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements(f) if x.name not in exclude]
elif isinstance(requirements, str): elif isinstance(requirements, str):
requirements = [requirements] requirements = [requirements]
pkgs = [] pkgs = []
for r in requirements: for r in requirements:
r_stripped = r.split('/')[-1].replace('.git', '') # replace git+https://org/repo.git -> 'repo' r_stripped = r.split('/')[-1].replace('.git', '') # replace git+https://org/repo.git -> 'repo'
match = re.match(r'([a-zA-Z0-9-_]+)([<>!=~]+.*)?', r_stripped)
name, required = match[1], match[2].strip() if match[2] else ''
try: try:
pkg.require(r_stripped) # exception if requirements not met assert check_version(version(name), required) # exception if requirements not met
except pkg.DistributionNotFound: except (AssertionError, PackageNotFoundError):
try: # attempt to import (slower but more accurate)
import importlib
importlib.import_module(next(pkg.parse_requirements(r_stripped)).name)
except ImportError:
pkgs.append(r)
except pkg.VersionConflict:
pkgs.append(r) pkgs.append(r)
s = ' '.join(f'"{x}"' for x in pkgs) # console string s = ' '.join(f'"{x}"' for x in pkgs) # console string
@ -430,6 +475,30 @@ def check_yolo(verbose=True, device=''):
LOGGER.info(f'Setup complete ✅ {s}') LOGGER.info(f'Setup complete ✅ {s}')
def collect_system_info():
"""Collect and print relevant system information including OS, Python, RAM, CPU, and CUDA."""
import psutil
from ultralytics.utils import ENVIRONMENT, is_git_dir
from ultralytics.utils.torch_utils import get_cpu_info
ram_info = psutil.virtual_memory().total / (1024 ** 3) # Convert bytes to GB
check_yolo()
LOGGER.info(f"\n{'OS':<20}{platform.platform()}\n"
f"{'Environment':<20}{ENVIRONMENT}\n"
f"{'Python':<20}{sys.version.split()[0]}\n"
f"{'Install':<20}{'git' if is_git_dir() else 'pip' if is_pip_package() else 'other'}\n"
f"{'RAM':<20}{ram_info:.2f} GB\n"
f"{'CPU':<20}{get_cpu_info()}\n"
f"{'CUDA':<20}{torch.version.cuda if torch and torch.cuda.is_available() else None}\n")
for r in parse_requirements():
current = version(r.name)
is_met = '' if check_version(current, r.specifier) else ''
LOGGER.info(f'{r.name:<20}{is_met}{current}{r.specifier}')
def check_amp(model): def check_amp(model):
""" """
This function checks the PyTorch Automatic Mixed Precision (AMP) functionality of a YOLOv8 model. This function checks the PyTorch Automatic Mixed Precision (AMP) functionality of a YOLOv8 model.

View File

@ -76,11 +76,11 @@ def select_device(device='', batch=0, newline=False, verbose=True):
verbose (bool, optional): If True, logs the device information. Defaults to True. verbose (bool, optional): If True, logs the device information. Defaults to True.
Returns: Returns:
torch.device: Selected device. (torch.device): Selected device.
Raises: Raises:
ValueError: If the specified device is not available or if the batch size is not a multiple of the number of ValueError: If the specified device is not available or if the batch size is not a multiple of the number of
devices when using multiple GPUs. devices when using multiple GPUs.
Examples: Examples:
>>> select_device('cuda:0') >>> select_device('cuda:0')