diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 68c195ca..33cf782b 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -23,7 +23,7 @@ jobs: markdown: true # format Markdown and YAML spelling: true # check spelling links: false # check broken links - summary: true # print PR summary with GPT4 (requires 'openai_api_key' or 'openai_azure_api_key' and 'openai_azure_endpoint') + summary: true # print PR summary with GPT4 (requires 'openai_api_key' or 'openai_azure_api_key' and 'openai_azure_endpoint') openai_azure_api_key: ${{ secrets.OPENAI_AZURE_API_KEY }} openai_azure_endpoint: ${{ secrets.OPENAI_AZURE_ENDPOINT }} # openai_api_key: ${{ secrets.OPENAI_API_KEY }} diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 1db82304..e257bae0 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -71,40 +71,40 @@ extra: # version: analytics: provider: google property: G-2M5EHKC0BH -# alternate: # language drop-down -# - name: 🇬🇧 English -# link: / -# lang: en -# - name: 🇨🇳 简体中文 -# link: /zh/ -# lang: zh -# - name: 🇰🇷 한국어 -# link: /ko/ -# lang: ko -# - name: 🇯🇵 日本語 -# link: /ja/ -# lang: ja -# - name: 🇷🇺 Русский -# link: /ru/ -# lang: ru -# - name: 🇩🇪 Deutsch -# link: /de/ -# lang: de -# - name: 🇫🇷 Français -# link: /fr/ -# lang: fr -# - name: 🇪🇸 Español -# link: /es/ -# lang: es -# - name: 🇵🇹 Português -# link: /pt/ -# lang: pt -# - name: 🇮🇳 हिन्दी -# link: /hi/ -# lang: hi -# - name: 🇸🇦 العربية -# link: /ar/ -# lang: ar + # alternate: # language drop-down + # - name: 🇬🇧 English + # link: / + # lang: en + # - name: 🇨🇳 简体中文 + # link: /zh/ + # lang: zh + # - name: 🇰🇷 한국어 + # link: /ko/ + # lang: ko + # - name: 🇯🇵 日本語 + # link: /ja/ + # lang: ja + # - name: 🇷🇺 Русский + # link: /ru/ + # lang: ru + # - name: 🇩🇪 Deutsch + # link: /de/ + # lang: de + # - name: 🇫🇷 Français + # link: /fr/ + # lang: fr + # - name: 🇪🇸 Español + # link: /es/ + # lang: es + # - name: 🇵🇹 Português + # link: /pt/ + # lang: pt + # - name: 🇮🇳 हिन्दी + # link: /hi/ + # lang: hi + # - name: 🇸🇦 العربية + # link: /ar/ + # lang: ar social: - icon: fontawesome/brands/github link: https://github.com/ultralytics diff --git a/ultralytics/__init__.py b/ultralytics/__init__.py index 650d3c5d..51f7eb46 100644 --- a/ultralytics/__init__.py +++ b/ultralytics/__init__.py @@ -1,6 +1,6 @@ # Ultralytics YOLO 🚀, AGPL-3.0 license -__version__ = "8.1.2" +__version__ = "8.1.3" from ultralytics.data.explorer.explorer import Explorer from ultralytics.models import RTDETR, SAM, YOLO diff --git a/ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml b/ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml new file mode 100644 index 00000000..6867f888 --- /dev/null +++ b/ultralytics/cfg/models/v8/yolov8-cls-resnet101.yaml @@ -0,0 +1,25 @@ +# Ultralytics YOLO 🚀, AGPL-3.0 license +# YOLOv8-cls image classification model. For Usage examples see https://docs.ultralytics.com/tasks/classify + +# Parameters +nc: 1000 # number of classes +scales: # model compound scaling constants, i.e. 'model=yolov8n-cls.yaml' will call yolov8-cls.yaml with scale 'n' + # [depth, width, max_channels] + n: [0.33, 0.25, 1024] + s: [0.33, 0.50, 1024] + m: [0.67, 0.75, 1024] + l: [1.00, 1.00, 1024] + x: [1.00, 1.25, 1024] + +# YOLOv8.0n backbone +backbone: + # [from, repeats, module, args] + - [-1, 1, ResNetLayer, [3, 64, 1, True, 1]] # 0-P1/2 + - [-1, 1, ResNetLayer, [64, 64, 1, False, 3]] # 1-P2/4 + - [-1, 1, ResNetLayer, [256, 128, 2, False, 4]] # 2-P3/8 + - [-1, 1, ResNetLayer, [512, 256, 2, False, 23]] # 3-P4/16 + - [-1, 1, ResNetLayer, [1024, 512, 2, False, 3]] # 4-P5/32 + +# YOLOv8.0n head +head: + - [-1, 1, Classify, [nc]] # Classify diff --git a/ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml b/ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml new file mode 100644 index 00000000..8ffd111f --- /dev/null +++ b/ultralytics/cfg/models/v8/yolov8-cls-resnet50.yaml @@ -0,0 +1,25 @@ +# Ultralytics YOLO 🚀, AGPL-3.0 license +# YOLOv8-cls image classification model. For Usage examples see https://docs.ultralytics.com/tasks/classify + +# Parameters +nc: 1000 # number of classes +scales: # model compound scaling constants, i.e. 'model=yolov8n-cls.yaml' will call yolov8-cls.yaml with scale 'n' + # [depth, width, max_channels] + n: [0.33, 0.25, 1024] + s: [0.33, 0.50, 1024] + m: [0.67, 0.75, 1024] + l: [1.00, 1.00, 1024] + x: [1.00, 1.25, 1024] + +# YOLOv8.0n backbone +backbone: + # [from, repeats, module, args] + - [-1, 1, ResNetLayer, [3, 64, 1, True, 1]] # 0-P1/2 + - [-1, 1, ResNetLayer, [64, 64, 1, False, 3]] # 1-P2/4 + - [-1, 1, ResNetLayer, [256, 128, 2, False, 4]] # 2-P3/8 + - [-1, 1, ResNetLayer, [512, 256, 2, False, 6]] # 3-P4/16 + - [-1, 1, ResNetLayer, [1024, 512, 2, False, 3]] # 4-P5/32 + +# YOLOv8.0n head +head: + - [-1, 1, Classify, [nc]] # Classify diff --git a/ultralytics/engine/model.py b/ultralytics/engine/model.py index 4916356b..745ec4a3 100644 --- a/ultralytics/engine/model.py +++ b/ultralytics/engine/model.py @@ -52,13 +52,14 @@ class Model(nn.Module): list(ultralytics.engine.results.Results): The prediction results. """ - def __init__(self, model: Union[str, Path] = "yolov8n.pt", task=None) -> None: + def __init__(self, model: Union[str, Path] = "yolov8n.pt", task=None, verbose=False) -> None: """ Initializes the YOLO model. Args: model (Union[str, Path], optional): Path or name of the model to load or create. Defaults to 'yolov8n.pt'. task (Any, optional): Task type for the YOLO model. Defaults to None. + verbose (bool, optional): Whether to enable verbose mode. """ super().__init__() self.callbacks = callbacks.get_default_callbacks() @@ -77,6 +78,7 @@ class Model(nn.Module): # Check if Ultralytics HUB model from https://hub.ultralytics.com if self.is_hub_model(model): # Fetch model from HUB + checks.check_requirements("hub-sdk>0.0.2") self.session = self._get_hub_session(model) model = self.session.model_file @@ -89,9 +91,9 @@ class Model(nn.Module): # Load or create new YOLO model model = checks.check_model_file_from_stem(model) # add suffix, i.e. yolov8n -> yolov8n.pt if Path(model).suffix in (".yaml", ".yml"): - self._new(model, task) + self._new(model, task=task, verbose=verbose) else: - self._load(model, task) + self._load(model, task=task) self.model_name = model @@ -126,7 +128,7 @@ class Model(nn.Module): ) ) - def _new(self, cfg: str, task=None, model=None, verbose=True): + def _new(self, cfg: str, task=None, model=None, verbose=False): """ Initializes a new model and infers the task type from the model definitions. @@ -381,8 +383,8 @@ class Model(nn.Module): # Check model was created if not getattr(self.session.model, "id", None): self.session = None - except PermissionError: - # Ignore permission error + except (PermissionError, ModuleNotFoundError): + # Ignore PermissionError and ModuleNotFoundError which indicates hub-sdk not installed pass self.trainer.hub_session = self.session # attach optional HUB session diff --git a/ultralytics/hub/session.py b/ultralytics/hub/session.py index bc01bf55..b12f7b14 100644 --- a/ultralytics/hub/session.py +++ b/ultralytics/hub/session.py @@ -42,8 +42,8 @@ class HUBTrainingSession: Raises: ValueError: If the provided model identifier is invalid. ConnectionError: If connecting with global API key is not supported. + ModuleNotFoundError: If hub-sdk package is not installed. """ - checks.check_requirements("hub-sdk>=0.0.2") from hub_sdk import HUBClient self.rate_limits = { diff --git a/ultralytics/utils/plotting.py b/ultralytics/utils/plotting.py index e5c0c415..3028ed14 100644 --- a/ultralytics/utils/plotting.py +++ b/ultralytics/utils/plotting.py @@ -256,7 +256,7 @@ class Annotator: # Convert to numpy first self.im = np.asarray(self.im).copy() nkpt, ndim = kpts.shape - is_pose = nkpt == 17 and ndim == 3 + is_pose = nkpt == 17 and ndim in {2, 3} kpt_line &= is_pose # `kpt_line=True` for now only supports human pose plotting for i, k in enumerate(kpts): color_k = [int(x) for x in self.kpt_color[i]] if is_pose else colors(i)