`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>
pull/4987/head v8.0.182
Glenn Jocher 1 year ago committed by GitHub
parent 0cf82f5040
commit 28569ced8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      .github/ISSUE_TEMPLATE/bug-report.yml
  2. 4
      docker/Dockerfile-runner
  3. 12
      docs/reference/utils/checks.md
  4. 2
      ultralytics/__init__.py
  5. 2
      ultralytics/cfg/__init__.py
  6. 4
      ultralytics/engine/exporter.py
  7. 2
      ultralytics/models/fastsam/prompt.py
  8. 5
      ultralytics/utils/callbacks/base.py
  9. 117
      ultralytics/utils/checks.py
  10. 4
      ultralytics/utils/torch_utils.py

@ -25,13 +25,14 @@ body:
Please select the part of YOLOv8 where you found the bug.
multiple: true
options:
- "Training"
- "Validation"
- "Detection"
- "Install"
- "Train"
- "Val"
- "Predict"
- "Export"
- "PyTorch Hub"
- "Multi-GPU"
- "Evolution"
- "Augmentation"
- "Hyperparameter Tuning"
- "Integrations"
- "Other"
validations:
@ -51,9 +52,19 @@ body:
label: Environment
description: Please specify the software and hardware you used to produce the bug.
placeholder: |
- YOLO: Ultralytics YOLOv8.0.21 🚀 Python-3.8.10 torch-1.13.1+cu117 CUDA:0 (A100-SXM-80GB, 81251MiB)
- OS: Ubuntu 20.04
- Python: 3.8.10
Paste output of `yolo checks` or `ultralytics.checks()` commands:
```
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:
required: false

@ -9,8 +9,8 @@ FROM ultralytics/ultralytics:latest
WORKDIR /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 && \
curl -o $FILENAME -L https://github.com/actions/runner/releases/download/v2.308.0/$FILENAME && \
RUN FILENAME=actions-runner-linux-x64-2.309.0.tar.gz && \
curl -o $FILENAME -L https://github.com/actions/runner/releases/download/v2.309.0/$FILENAME && \
tar xzf $FILENAME && \
rm $FILENAME

@ -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 🙏!
---
## ::: ultralytics.utils.checks.parse_requirements
<br><br>
---
## ::: ultralytics.utils.checks.parse_version
<br><br>
---
## ::: ultralytics.utils.checks.is_ascii
<br><br>
@ -69,6 +77,10 @@ keywords: Ultralytics, utility checks, ASCII, check_version, pip_update, check_p
## ::: ultralytics.utils.checks.check_yolo
<br><br>
---
## ::: ultralytics.utils.checks.collect_system_info
<br><br>
---
## ::: ultralytics.utils.checks.check_amp
<br><br>

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

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

@ -143,6 +143,9 @@ class Exporter:
_callbacks (list, optional): List of callback functions. Defaults to None.
"""
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()
callbacks.add_integration_callbacks(self)
@ -155,7 +158,6 @@ class Exporter:
if format in ('tensorrt', 'trt'): # 'engine' aliases
format = 'engine'
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'
fmts = tuple(export_formats()['Argument'][1:]) # available export formats
flags = [x == format for x in fmts]

@ -143,7 +143,7 @@ class FastSAMPrompt:
save_path = Path(output) / result_name
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)
plt.close()
pbar.set_description(f'Saving {result_name} to {save_path}')

@ -213,11 +213,6 @@ def add_integration_callbacks(instance):
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])
# 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
for callbacks in callbacks_list:
for k, v in callbacks.items():

@ -9,20 +9,60 @@ import platform
import re
import shutil
import subprocess
import sys
import time
from importlib.metadata import PackageNotFoundError, version
from pathlib import Path
from typing import Optional
import cv2
import numpy as np
import pkg_resources as pkg
import requests
import torch
from matplotlib import font_manager
from ultralytics.utils import (ASSETS, AUTOINSTALL, LINUX, LOGGER, ONLINE, ROOT, USER_CONFIG_DIR, ThreadingLocked,
TryExcept, clean_url, colorstr, downloads, emojis, is_colab, is_docker, is_jupyter,
is_kaggle, is_online, is_pip_package, url2file)
from ultralytics.utils import (ASSETS, AUTOINSTALL, LINUX, LOGGER, ONLINE, ROOT, USER_CONFIG_DIR, SimpleNamespace,
ThreadingLocked, TryExcept, clean_url, colorstr, downloads, emojis, is_colab, is_docker,
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:
@ -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_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}']
result = True
for constraint in constraints:
op, version = re.match(r'([<>!=]{1,2})\s*(\d+\.\d+)', constraint).groups()
version = pkg.parse_version(version)
if op == '==' and current != version:
op, v = re.match(r'([<>!=]{1,2})\s*(\d+\.\d+)', constraint).groups()
# v = pkg.parse_version(v)
v = parse_version(v) # '1.2.3' -> (1, 2, 3)
if op == '==' and current != v:
result = False
elif op == '!=' and current == version:
elif op == '!=' and current == v:
result = False
elif op == '>=' and not (current >= version):
elif op == '>=' and not (current >= v):
result = False
elif op == '<=' and not (current <= version):
elif op == '<=' and not (current <= v):
result = False
elif op == '>' and not (current > version):
elif op == '>' and not (current > v):
result = False
elif op == '<' and not (current < version):
elif op == '<' and not (current < v):
result = False
if not result:
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):
from ultralytics import __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 😃 '
f"Update with 'pip install -U ultralytics'")
return True
@ -253,29 +302,25 @@ def check_requirements(requirements=ROOT.parent / 'requirements.txt', exclude=()
check_requirements(['numpy', 'ultralytics>=8.0.0'])
```
"""
prefix = colorstr('red', 'bold', 'requirements:')
check_python() # check python version
check_torchvision() # check torch-torchvision compatibility
if isinstance(requirements, Path): # requirements.txt file
file = requirements.resolve()
assert file.exists(), f'{prefix} {file} not found, check failed.'
with file.open() as f:
requirements = [f'{x.name}{x.specifier}' for x in pkg.parse_requirements(f) if x.name not in exclude]
requirements = [f'{x.name}{x.specifier}' for x in parse_requirements(file) if x.name not in exclude]
elif isinstance(requirements, str):
requirements = [requirements]
pkgs = []
for r in requirements:
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:
pkg.require(r_stripped) # exception if requirements not met
except pkg.DistributionNotFound:
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:
assert check_version(version(name), required) # exception if requirements not met
except (AssertionError, PackageNotFoundError):
pkgs.append(r)
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}')
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):
"""
This function checks the PyTorch Automatic Mixed Precision (AMP) functionality of a YOLOv8 model.

@ -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.
Returns:
torch.device: Selected device.
(torch.device): Selected device.
Raises:
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:
>>> select_device('cuda:0')

Loading…
Cancel
Save