diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index ae2554017a..4e26df06da 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -1,10 +1,14 @@
-name: Build Docs for the latest
+# This workflow is purely for validating the docs build.
+name: Build Docs Validation
on:
workflow_dispatch: # run on request (no need for PR)
- push:
- branches:
- - develop
+ pull_request:
+ paths:
+ - "docs/**"
+ - "src/**"
+ - "pyproject.toml"
+ - ".readthedocs.yaml"
# Declare default permissions as read only.
permissions: read-all
@@ -12,8 +16,6 @@ permissions: read-all
jobs:
Build-Docs:
runs-on: ubuntu-24.04
- permissions:
- contents: write
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
@@ -26,54 +28,7 @@ jobs:
pip install '.[ci_tox]'
- name: Build-Docs
run: tox -e build-doc
- - name: Create gh-pages branch
+ - name: Check docs build
run: |
- if [[ ${{github.event_name}} == 'workflow_dispatch' ]]; then
- echo RELEASE_VERSION="test_build" >> $GITHUB_ENV
- else
- echo RELEASE_VERSION=${GITHUB_REF#refs/*/} >> $GITHUB_ENV
- fi
- echo SOURCE_NAME=${GITHUB_REF#refs/*/} >> $GITHUB_OUTPUT
- echo SOURCE_BRANCH=${GITHUB_REF#refs/heads/} >> $GITHUB_OUTPUT
- echo SOURCE_TAG=${GITHUB_REF#refs/tags/} >> $GITHUB_OUTPUT
-
- existed_in_remote=$(git ls-remote --heads origin gh-pages)
-
- if [[ -z ${existed_in_remote} ]]; then
- echo "Creating gh-pages branch"
- git config --local user.email "action@github.com"
- git config --local user.name "GitHub Action"
- git checkout --orphan gh-pages
- git reset --hard
- touch .nojekyll
- git add .nojekyll
- git commit -m "Initializing gh-pages branch"
- git push origin gh-pages
- git checkout ${{steps.branch_name.outputs.SOURCE_NAME}}
- echo "Created gh-pages branch"
- else
- echo "Branch gh-pages already exists"
- fi
- - name: Commit docs to gh-pages branch
- run: |
- git fetch
- git checkout gh-pages
- mkdir -p /tmp/docs_build
- cp -r docs/build/html/* /tmp/docs_build/
- rm -rf ${{ env.RELEASE_VERSION }}/*
- echo '
' > index.html
- mkdir -p ${{ env.RELEASE_VERSION }}
- cp -r /tmp/docs_build/* ./${{ env.RELEASE_VERSION }}
- rm -rf /tmp/docs_build
- git config --local user.email "action@github.com"
- git config --local user.name "GitHub Action"
- if [[ ${{ env.RELEASE_VERSION }} != 'test_build' ]]; then
- ln -sfn ${{ env.RELEASE_VERSION }} latest
- fi
- git add ./latest ${{ env.RELEASE_VERSION }}
- git commit -m "Update documentation" -a || true
- - name: Push changes
- uses: ad-m/github-push-action@fcea09907c44d7a7a3331c9c04080d55d87c95fe # master
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
- branch: gh-pages
+ echo "Documentation built successfully!"
+ echo "Check docs/build/html/index.html for local preview"
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
new file mode 100644
index 0000000000..a6d7b4bcfd
--- /dev/null
+++ b/.readthedocs.yaml
@@ -0,0 +1,24 @@
+# ReadTheDocs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+version: 2
+
+# Set the OS, Python version and other tools you might need
+build:
+ os: ubuntu-22.04
+ tools:
+ python: "3.12"
+
+# Build documentation in the "docs/" directory with Sphinx
+sphinx:
+ configuration: docs/source/conf.py
+
+# Declare the Python requirements required to build your documentation
+python:
+ install:
+ - method: pip
+ path: .
+ extra_requirements:
+ - docs
+# Support for multiple versions (this is one of the main benefits of ReadTheDocs)
+# You can configure this later in the ReadTheDocs dashboard
diff --git a/docs/source/_static/logos/geti-favicon-64.png b/docs/source/_static/logos/geti-favicon-64.png
new file mode 100644
index 0000000000..4e21643bc4
Binary files /dev/null and b/docs/source/_static/logos/geti-favicon-64.png differ
diff --git a/docs/source/_static/redirects/guide-homepage-redirect.html b/docs/source/_static/redirects/guide-homepage-redirect.html
deleted file mode 100644
index ae5857ac19..0000000000
--- a/docs/source/_static/redirects/guide-homepage-redirect.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 5085dd0098..bfcf351a3f 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -1,15 +1,14 @@
-# Configuration file for the Sphinx documentation builder.
-#
-# This file only contains a selection of the most common options. For a full
-# list see the documentation:
-# https://www.sphinx-doc.org/en/master/usage/configuration.html
+"""Configuration file for the Sphinx documentation builder.
-# -- Path setup -------------------------------------------------------------- #
+For the full list of built-in configuration values, see the documentation:
+https://www.sphinx-doc.org/en/master/usage/configuration.html
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-#
+-- Project information -----------------------------------------------------
+https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+"""
+
+# Copyright (C) 2022-2025 Intel Corporation
+# SPDX-License-Identifier: Apache-2.0
import os
import sys
@@ -44,7 +43,6 @@
"sphinx_design",
"myst_parser", # Enhanced markdown support
"sphinx.ext.todo", # Support for TODO items
- "sphinx.ext.githubpages", # GitHub Pages support
"sphinx.ext.coverage", # Documentation coverage check
]
@@ -58,11 +56,6 @@
"tasklist",
]
-source_suffix = {
- ".rst": "restructuredtext",
- ".md": "markdown",
-}
-
suppress_warnings = [
"ref.python",
"autosectionlabel.*",
@@ -80,37 +73,10 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-html_theme = "pydata_sphinx_theme"
+html_theme = "sphinx_book_theme"
html_static_path = ["_static"]
-
-# Show source link & copyright
-html_show_sourcelink = True
-html_show_sphinx = False
-html_show_copyright = True
-html_copy_source = True
-
-
-html_theme_options = {
- "navbar_center": [],
- "navbar_end": ["search-field.html", "theme-switcher.html", "navbar-icon-links.html"],
- "search_bar_text": "Search",
- "logo": {
- "image_light": "logos/otx-logo.png",
- "image_dark": "logos/otx-logo.png",
- },
- "icon_links": [
- {
- "name": "GitHub",
- "url": "https://github.com/open-edge-platform/training_extensions",
- "icon": "fab fa-github",
- "type": "fontawesome",
- },
- ],
- "use_edit_page_button": True,
- "show_nav_level": 3,
- "navigation_depth": 6,
- "show_toc_level": 3,
-}
+html_logo = "_static/logos/otx-logo.png"
+html_favicon = "_static/logos/geti-favicon-64.png"
html_context = {
"github_user": "open-edge-platform",
@@ -119,10 +85,6 @@
"doc_path": "docs/source/",
}
-html_css_files = [
- "css/custom.css",
-]
-
# -- Extension configuration -------------------------------------------------
autodoc_docstring_signature = True
autodoc_member_order = "bysource"
diff --git a/docs/source/guide/explanation/algorithms/anomaly/index.rst b/docs/source/guide/explanation/algorithms/anomaly/index.rst
index 18a4fedf60..ae20ab32c1 100644
--- a/docs/source/guide/explanation/algorithms/anomaly/index.rst
+++ b/docs/source/guide/explanation/algorithms/anomaly/index.rst
@@ -77,15 +77,15 @@ Models
******
As mentioned above, the goal of visual anomaly detection is to learn a representation of normal behaviour in the data and then identify instances that deviate from this normal behaviour. OpenVINO Training Extensions supports several deep learning approaches to this task, including the following:
-+--------+-------------------------------------------------------------------------------------------------------------------+----------------------+-----------------+
-| Name | Recipe | Complexity (GFLOPs) | Model size (MB) |
-+========+===================================================================================================================+======================+=================+
++--------+----------------------------------------------------------------------------------------------------------------------+----------------------+-----------------+
+| Name | Recipe | Complexity (GFLOPs) | Model size (MB) |
++========+======================================================================================================================+======================+=================+
| PADIM | `padim `_ | 3.9 | 168.4 |
-+--------+-------------------------------------------------------------------------------------------------------------------+----------------------+-----------------+
++--------+----------------------------------------------------------------------------------------------------------------------+----------------------+-----------------+
| STFPM | `stfpm `_ | 5.6 | 21.1 |
-+--------+-------------------------------------------------------------------------------------------------------------------+----------------------+-----------------+
++--------+----------------------------------------------------------------------------------------------------------------------+----------------------+-----------------+
| U-Flow | `uflow `_ | 59.6 | 62.88 |
-+--------+-------------------------------------------------------------------------------------------------------------------+----------------------+-----------------+
++--------+----------------------------------------------------------------------------------------------------------------------+----------------------+-----------------+
Clustering-based Models
@@ -161,12 +161,13 @@ Normalizing Flow Models
Normalizing Flow models use invertible neural networks to transform image features into a simpler distribution, like a Gaussian. During inference, the Flow network is used to compute the likelihood of the input image under the learned distribution, assigning low probabilities to anomalous samples. OpenVINO Training Extensions currently supports `U-Flow: Unsupervised Anomaly Detection via Normalizing Flow `_.
U-Flow
-^^^^^
+^^^^^^
-.. figure:: ../../../../../utils/images/uflow.png
- :width: 600
- :align: center
- :alt: Anomaly Task Types
+.. # TODO: Add U-Flow figure when uflow.png image is available
+.. # figure:: ../../../../../utils/images/uflow.png
+.. # :width: 600
+.. # :align: center
+.. # :alt: U-Flow Architecture
U-Flow consists of four stages.
diff --git a/docs/source/guide/explanation/algorithms/classification/multi_class_classification.rst b/docs/source/guide/explanation/algorithms/classification/multi_class_classification.rst
index e558c4eee0..b15a11ef75 100644
--- a/docs/source/guide/explanation/algorithms/classification/multi_class_classification.rst
+++ b/docs/source/guide/explanation/algorithms/classification/multi_class_classification.rst
@@ -55,25 +55,25 @@ Models
We support the following ready-to-use model recipes:
-+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
-| Model Name | Complexity (GFLOPs) | Model params (M)|
-+==================================================================================================================================================================================================================+=====================+=================+
-| `MobileNet-V3-large `_ | 0.86 | 2.97 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
-| `MobileNet-V3-small `_ | 0.22 | 0.93 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
-| `EfficinetNet-B0 `_ | 1.52 | 4.09 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
-| `EfficientNet-B3 `_ | 3.84 | 10.70 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
-| `EfficientNet-V2-S `_ | 5.76 | 20.23 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
-| `EfficientNet-V2-l `_ | 48.92 | 117.23 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
-| `DeiT-Tiny `_ | 2.51 | 22.0 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
-| `DINO-V2 `_ | 12.46 | 88.0 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+
++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+-------------------+
+| Model Name | Complexity (GFLOPs) | Model params (M) |
++=============================================================================================================================================================================+======================+===================+
+| `MobileNet-V3-large `_ | 0.86 | 2.97 |
++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+-------------------+
+| `MobileNet-V3-small `_ | 0.22 | 0.93 |
++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+-------------------+
+| `EfficinetNet-B0 `_ | 1.52 | 4.09 |
++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+-------------------+
+| `EfficientNet-B3 `_ | 3.84 | 10.70 |
++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+-------------------+
+| `EfficientNet-V2-S `_ | 5.76 | 20.23 |
++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+-------------------+
+| `EfficientNet-V2-l `_ | 48.92 | 117.23 |
++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+-------------------+
+| `DeiT-Tiny `_ | 2.51 | 22.0 |
++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+-------------------+
+| `DINO-V2 `_ | 12.46 | 88.0 |
++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+-------------------+
`MobileNet-V3 `_ is the best choice when training time and computational cost are in priority, nevertheless, this recipe provides competitive accuracy as well.
`EfficientNet-B0/B3 `_ consumes more Flops compared to MobileNet, providing better performance on large datasets.
diff --git a/docs/source/guide/explanation/algorithms/object_detection/object_detection.rst b/docs/source/guide/explanation/algorithms/object_detection/object_detection.rst
index 3856529da4..61b598ee9e 100644
--- a/docs/source/guide/explanation/algorithms/object_detection/object_detection.rst
+++ b/docs/source/guide/explanation/algorithms/object_detection/object_detection.rst
@@ -56,25 +56,25 @@ Models
We support the following ready-to-use model recipes:
-+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
-| Recipe ID | Name | Complexity (GFLOPs) | Model size (MB) |
-+============================================================================================================================================================+=====================+=====================+=================+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
+| Recipe ID | Name | Complexity (GFLOPs) | Model size (MB) |
++===============================================================================================================================================================+=====================+=====================+=================+
| `Custom_Object_Detection_YOLOX `_ | YOLOX-TINY | 6.5 | 20.4 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
| `Object_Detection_YOLOX_S `_ | YOLOX_S | 33.51 | 46.0 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
| `Object_Detection_YOLOX_L `_ | YOLOX_L | 194.57 | 207.0 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
| `Object_Detection_YOLOX_X `_ | YOLOX_X | 352.42 | 378.0 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
| `Custom_Object_Detection_Gen3_SSD `_ | SSD | 9.4 | 7.6 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
| `Custom_Object_Detection_Gen3_ATSS `_ | MobileNetV2-ATSS | 20.6 | 9.1 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
| `Object_Detection_ResNeXt101_ATSS `_ | ResNeXt101-ATSS | 434.75 | 344.0 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
| `D-Fine X Detection ` | D-Fine X | 202.486 | 240.0 |
-+------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
++---------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+---------------------+-----------------+
Above table can be found using the following command
diff --git a/docs/source/guide/explanation/algorithms/segmentation/instance_segmentation.rst b/docs/source/guide/explanation/algorithms/segmentation/instance_segmentation.rst
index 87373ba2b3..81e359ac50 100644
--- a/docs/source/guide/explanation/algorithms/segmentation/instance_segmentation.rst
+++ b/docs/source/guide/explanation/algorithms/segmentation/instance_segmentation.rst
@@ -55,13 +55,13 @@ We support the following ready-to-use model recipes:
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------+---------------------+-----------------+
| Model Recipe | Name | Complexity (GFLOPs) | Model size (MB) |
+===============================================================================================================================================================================================================+============================+=====================+=================+
-| `Instance Segmentation MaskRCNN EfficientNetB2B `_ | MaskRCNN-EfficientNetB2B | 68.48 | 13.27 |
+| `Instance Segmentation MaskRCNN EfficientNetB2B `_ | MaskRCNN-EfficientNetB2B | 68.48 | 13.27 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------+---------------------+-----------------+
-| `Instance Segmentation MaskRCNN ResNet50 `_ | MaskRCNN-ResNet50 | 533.80 | 177.90 |
+| `Instance Segmentation MaskRCNN ResNet50 `_ | MaskRCNN-ResNet50 | 533.80 | 177.90 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------+---------------------+-----------------+
-| `Instance Segmentation MaskRCNN SwinT `_ | MaskRCNN-SwinT | 566 | 191.46 |
+| `Instance Segmentation MaskRCNN SwinT `_ | MaskRCNN-SwinT | 566 | 191.46 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------+---------------------+-----------------+
-| `Instance Segmentation RTMDet-Inst Tiny `_ | RTMDet-Ins-tiny | 52.86 | 22.8 |
+| `Instance Segmentation RTMDet-Inst Tiny `_ | RTMDet-Ins-tiny | 52.86 | 22.8 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------+---------------------+-----------------+
Above table can be found using the following command
diff --git a/docs/source/guide/explanation/algorithms/segmentation/semantic_segmentation.rst b/docs/source/guide/explanation/algorithms/segmentation/semantic_segmentation.rst
index 8d1cae84d1..e532d8ba7a 100644
--- a/docs/source/guide/explanation/algorithms/segmentation/semantic_segmentation.rst
+++ b/docs/source/guide/explanation/algorithms/segmentation/semantic_segmentation.rst
@@ -51,19 +51,19 @@ We support the following ready-to-use model recipes:
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+-----------------+-----------------+
| Recipe Path | Complexity (GFLOPs) | Model size (M) | FPS (GPU) | iter time (sec) |
+======================================================================================================================================================================================+=====================+=================+=================+=================+
-| `Lite-HRNet-s-mod2 `_ | 1.44 | 0.82 | 37.68 | 0.151 |
+| `Lite-HRNet-s-mod2 `_ | 1.44 | 0.82 | 37.68 | 0.151 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+-----------------+-----------------+
-| `Lite-HRNet-18-mod2 `_ | 2.63 | 1.10 | 31.17 | 0.176 |
+| `Lite-HRNet-18-mod2 `_ | 2.63 | 1.10 | 31.17 | 0.176 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+-----------------+-----------------+
-| `Lite-HRNet-x-mod3 `_ | 9.20 | 1.50 | 15.07 | 0.347 |
+| `Lite-HRNet-x-mod3 `_ | 9.20 | 1.50 | 15.07 | 0.347 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+-----------------+-----------------+
-| `SegNext_T `_ | 12.44 | 4.23 | 104.90 | 0.126 |
+| `SegNext_T `_ | 12.44 | 4.23 | 104.90 | 0.126 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+-----------------+-----------------+
-| `SegNext_S `_ | 30.93 | 13.90 | 85.67 | 0.134 |
+| `SegNext_S `_ | 30.93 | 13.90 | 85.67 | 0.134 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+-----------------+-----------------+
-| `SegNext_B `_ | 64.65 | 27.56 | 61.91 | 0.215 |
+| `SegNext_B `_ | 64.65 | 27.56 | 61.91 | 0.215 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+-----------------+-----------------+
-| `DinoV2 `_ | 124.01 | 24.40 | 3.52 | 0.116 |
+| `DinoV2 `_ | 124.01 | 24.40 | 3.52 | 0.116 |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------+-----------------+-----------------+-----------------+
All of these models differ in the trade-off between accuracy and inference/training speed. For example, ``SegNext_B`` is the recipe with heavy-size architecture for more accurate predictions, but it requires longer training.
diff --git a/docs/source/guide/get_started/installation.rst b/docs/source/guide/get_started/installation.rst
index 628b476e4f..4720deed0a 100644
--- a/docs/source/guide/get_started/installation.rst
+++ b/docs/source/guide/get_started/installation.rst
@@ -16,9 +16,9 @@ The current version of OpenVINO™ Training Extensions was tested in the followi
To enable efficient execution of multiple models, we increase the ONEDNN_PRIMITIVE_CACHE_CAPACITY environment variable from its default value to 10000.
For more information, refer to the `Primitive cache `_.
-***************
+******************
Installing ``uv``
-***************
+******************
To use OpenVINO™ Training Extensions with ``uv``, you first need to install the ``uv`` tool.
diff --git a/docs/source/guide/get_started/introduction.rst b/docs/source/guide/get_started/introduction.rst
index 8d232f2bbb..cfc94de148 100644
--- a/docs/source/guide/get_started/introduction.rst
+++ b/docs/source/guide/get_started/introduction.rst
@@ -109,7 +109,7 @@ Documentation content
Learn how to train a semantic segmentation model
.. grid-item-card:: Anomaly Task
- :link: ../tutorials/base/how_to_train/anomaly_detection
+ :link: ../tutorials/base/how_to_train/anomaly
:link-type: doc
:text-align: center
diff --git a/docs/source/guide/index.rst b/docs/source/guide/index.rst
deleted file mode 100644
index a84541a2ee..0000000000
--- a/docs/source/guide/index.rst
+++ /dev/null
@@ -1,43 +0,0 @@
-Guide
-=====
-
-
-.. toctree::
- :hidden:
- :maxdepth: 3
- :caption: Get Started
-
- get_started/introduction
- get_started/installation
- get_started/cli_commands
- get_started/api_tutorial
-
-
-.. toctree::
- :hidden:
- :caption: Tutorials
-
- tutorials/base/index.rst
- tutorials/advanced/index.rst
-
-
-.. toctree::
- :hidden:
- :caption: Explanation
-
- explanation/algorithms/index
- explanation/additional_features/index
- explanation/product_design
-
-
-.. toctree::
- :hidden:
- :caption: Reference
-
- reference/index
-
-
-.. toctree::
- :caption: Release Notes
-
- release_notes/index
diff --git a/docs/source/guide/tutorials/advanced/index.rst b/docs/source/guide/tutorials/advanced/index.rst
index 48828feca7..338ad54b24 100644
--- a/docs/source/guide/tutorials/advanced/index.rst
+++ b/docs/source/guide/tutorials/advanced/index.rst
@@ -5,7 +5,6 @@ Advanced Tutorials
:maxdepth: 1
configuration
- huggingface_model
multi_gpu
low_rank_adaptation
torch_compile
diff --git a/docs/source/guide/tutorials/base/how_to_train/index.rst b/docs/source/guide/tutorials/base/how_to_train/index.rst
index 758975866b..a9453ad172 100644
--- a/docs/source/guide/tutorials/base/how_to_train/index.rst
+++ b/docs/source/guide/tutorials/base/how_to_train/index.rst
@@ -34,7 +34,7 @@ Training to deployment tutorials
Learn how to train a semantic segmentation model
.. grid-item-card:: Anomaly Task
- :link: anomaly_detection
+ :link: anomaly
:link-type: doc
:text-align: center
@@ -48,4 +48,4 @@ Training to deployment tutorials
detection
instance_segmentation
semantic_segmentation
- anomaly_detection
+ anomaly
diff --git a/docs/source/index.rst b/docs/source/index.rst
index a14536bc2d..11a7c2488f 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -1,10 +1,193 @@
-Welcome to Intel OpenVINO Training Extensions's develop documentation!
-======================================================================
+.. raw:: html
+
+
+

+
+
+Introduction
+============
+
+**OpenVINO™ Training Extensions** is a low-code transfer learning framework for Computer Vision.
+
+The framework's CLI commands and API allow users to easily train, infer, optimize and export models, even with limited deep learning expertise. OpenVINO™ Training Extensions offers diverse combinations of model architectures, learning methods, and task types based on `PyTorch `_ , `Lightning `_ and `OpenVINO™ toolkit `_.
+
+OpenVINO™ Training Extensions provide `recipe `_ for every supported task type, which consolidates necessary information to build a model. Model configs are validated on various datasets and serve one-stop shop for obtaining the best models in general.
+
+The framework will identify the most suitable recipe based on your dataset, and choose the best hyperparameter configuration. The development team is continuously extending functionalities to make training as simple as possible so that single CLI command can obtain accurate, efficient and robust models ready to be integrated into your project.
+
+|
+
+.. figure:: ../utils/images/diagram_otx.png
+ :align: center
+ :width: 100%
+
+|
+
+************
+Key Features
+************
+
+OpenVINO™ Training Extensions supports the following computer vision tasks:
+
+- **Classification**, including multi-class, multi-label and hierarchical image classification tasks.
+- **Object detection** including rotated bounding box and tiling support
+- **Semantic segmentation** including tiling algorithm support
+- **Instance segmentation** including tiling algorithm support
+- **Anomaly recognition** tasks including anomaly classification, detection and segmentation
+
+OpenVINO™ Training Extensions provide the :doc:`following features `:
+
+- Native **Intel GPUs (XPU) support**. OpenVINO™ Training Extensions can be installed with XPU support to utilize Intel GPUs for training and testing.
+- **Distributed training** to accelerate the training process when you have multiple GPUs
+- **Half-precision training** to save GPUs memory and use larger batch sizes
+- **Class incremental learning** to add new classes to the existing model
+- OpenVINO™ Training Extensions uses `Datumaro `_ as the backend to handle datasets. On account of that, OpenVINO™ Training Extensions supports the most common academic field dataset formats for each task. In the future there will be more supported formats available to give more freedom of datasets format choice.
+- Improved :doc:`auto-configuration functionality `. OpenVINO™ Training Extensions analyzes provided dataset and selects the proper task and model recipe to provide the best accuracy/speed trade-off. It will also make a random auto-split of your dataset if there is no validation set provided.
+
+*********************
+Documentation content
+*********************
+
+1. :octicon:`light-bulb` **Quick start guide**:
+
+.. grid::
+ :gutter: 1
+
+ .. grid-item-card:: :octicon:`package` Installation Guide
+ :link: guide/get_started/installation
+ :link-type: doc
+ :text-align: center
+
+ Learn more about how to install OpenVINO™ Training Extensions
+
+ .. grid-item-card:: :octicon:`code-square` API Quick-Guide
+ :link: guide/get_started/api_tutorial
+ :link-type: doc
+ :text-align: center
+
+ Learn more about how to use OpenVINO™ Training Extensions Python API.
+
+ .. grid-item-card:: :octicon:`terminal` CLI Guide
+ :link: guide/get_started/cli_commands
+ :link-type: doc
+ :text-align: center
+
+ Learn more about how to use OpenVINO™ Training Extensions CLI commands
+
+2. :octicon:`book` **Tutorials**:
+
+.. grid:: 1 2 2 3
+ :margin: 1 1 0 0
+ :gutter: 1
+
+ .. grid-item-card:: Classification
+ :link: guide/tutorials/base/how_to_train/classification
+ :link-type: doc
+ :text-align: center
+
+ Learn how to train a classification model
+
+ .. grid-item-card:: Detection
+ :link: guide/tutorials/base/how_to_train/detection
+ :link-type: doc
+ :text-align: center
+
+ Learn how to train a detection model.
+
+ .. grid-item-card:: Instance Segmentation
+ :link: guide/tutorials/base/how_to_train/instance_segmentation
+ :link-type: doc
+ :text-align: center
+
+ Learn how to train an instance segmentation model
+
+ .. grid-item-card:: Semantic Segmentation
+ :link: guide/tutorials/base/how_to_train/semantic_segmentation
+ :link-type: doc
+ :text-align: center
+
+ Learn how to train a semantic segmentation model
+
+ .. grid-item-card:: Anomaly Task
+ :link: guide/tutorials/base/how_to_train/anomaly
+ :link-type: doc
+ :text-align: center
+
+ Learn how to train an anomaly detection model
+
+ .. grid-item-card:: Advanced
+ :link: guide/tutorials/advanced/index
+ :link-type: doc
+ :text-align: center
+
+ Learn how to use advanced features of OpenVINO™ Training Extensions
+
+3. **Explanation section**:
+
+This section consists of an algorithms explanation and describes additional features that are supported by OpenVINO™ Training Extensions.
+:ref:`Algorithms ` section includes a description of all supported algorithms:
+
+ 1. Explanation of the task and main supervised training pipeline.
+ 2. Description of the supported datasets formats for each task.
+ 3. Available recipes and models.
+
+:ref:`Additional Features ` section consists of:
+
+ 1. Overview of model optimization algorithms.
+ 2. Auto-configuration algorithm to select the most appropriate training pipeline for a given dataset.
+ 3. Tiling algorithm to detect small objects in large images.
+ 4. explainable AI algorithms to visualize the model's decision-making process.
+ 5. Additional useful features like configurable input size, class incremental learning, and adaptive training.
+
+4. **Reference**:
+
+This section gives an overview of the OpenVINO™ Training Extensions code base, where source code for Entities, classes and functions can be found.
+
+5. **Release Notes**:
+
+This section contains descriptions of current and previous releases.
+
+
+.. toctree::
+ :hidden:
+ :maxdepth: 3
+ :caption: Get Started
+
+ guide/get_started/introduction
+ guide/get_started/installation
+ guide/get_started/cli_commands
+ guide/get_started/api_tutorial
+
+
+.. toctree::
+ :hidden:
+ :caption: Tutorials
+
+ guide/tutorials/base/index.rst
+ guide/tutorials/advanced/index.rst
+
+
+.. toctree::
+ :hidden:
+ :caption: Explanation
+
+ guide/explanation/algorithms/index
+ guide/explanation/additional_features/index
+ guide/explanation/product_design
+
+
+.. toctree::
+ :hidden:
+ :caption: Reference
+
+ guide/reference/index
+
.. toctree::
- :hidden:
+ :hidden:
+ :caption: Release Notes
- guide/index
+ guide/release_notes/index
******************
Indices and tables
diff --git a/docs/utils/auto_sphinx_build.py b/docs/utils/auto_sphinx_build.py
deleted file mode 100644
index c39d5dd7c2..0000000000
--- a/docs/utils/auto_sphinx_build.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (C) 2024 Intel Corporation
-# SPDX-License-Identifier: Apache-2.0
-
-"""This script enable automatic detect the change of docs/source contents.
-
-It brings the convinient to check the output of the docs.
-
-When you used the VSCode + watchdog, you can easily check the docs output.
-
-1. Open the builded index.rst file with live server (Visual Studio Code extension)
-2. Execute this script `auto_sphix_build_for_vscode.py`
-3. Then, the watchdog + sphinx builder automatically builds the source when there are changes
-
-"""
-
-import os
-import sys
-import time
-from pathlib import Path
-from typing import Any
-
-from watchdog.events import FileSystemEventHandler
-from watchdog.observers import Observer
-
-
-class SphinxBuilder(FileSystemEventHandler):
- """Build sphinx docs."""
-
- def on_modified(self, event: Any) -> None: # noqa:ANN401
- """When the file is modified."""
- print(f"Changes detected: {event.src_path}")
- os.system("sphinx-build -b html ../source ../build") # noqa:S605, S607
-
-
-def main(path: str) -> None:
- """Main function."""
- event_handler: FileSystemEventHandler = SphinxBuilder()
- observer = Observer()
- observer.schedule(event_handler, path, recursive=True)
- observer.start()
- try:
- while True:
- time.sleep(1)
- except KeyboardInterrupt:
- observer.stop()
- observer.join()
-
-
-if __name__ == "__main__":
- print("Auto sphinx builder is ON. It automatically builds the source when the change is detected.")
- script_location = Path(__file__).resolve().parent
- parent_dir = script_location.parent
- source_folder = parent_dir / "source"
- print(f"The location of source folder: {source_folder}")
- print("Initial build...")
- time.sleep(10)
- os.system("sphinx-build -b html ../source ../build") # noqa:S605, S607
- path: str = sys.argv[1] if len(sys.argv) > 1 else str(source_folder)
- main(path)
diff --git a/pyproject.toml b/pyproject.toml
index 71716927bd..da62c430f0 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -77,7 +77,6 @@ docs = [
"furo",
"myst-parser",
"sphinx==7.2.6",
- "pydata-sphinx-theme==0.12.0",
"sphinx-tabs",
"sphinx-panels",
"sphinx-design",
@@ -87,6 +86,7 @@ docs = [
"nbsphinx",
"myst-parser>=2.0.0",
"linkify-it-py",
+ "sphinx_book_theme",
]
ci_tox = [
@@ -108,10 +108,6 @@ ci_benchmark = [
[project.scripts]
otx = "otx.cli:main"
-[project.urls]
-Documentation = "https://open-edge-platform.github.io/training_extensions/"
-Repository = "https://github.com/open-edge-platform/training_extensions/"
-
[tool.uv.sources]
torch = [
{ index = "torch-xpu", extra = "xpu"},
@@ -325,7 +321,7 @@ line-length = 120
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
# minimum target version
-target-version = "py38"
+target-version = "py311"
# Enumerate all fixed violations.
show-fixes = true
@@ -388,6 +384,12 @@ notice-rgx = """
[tool.ruff.pydocstyle]
convention = "google"
+[tool.ruff.flake8-copyright]
+notice-rgx = """
+# Copyright \\(C\\) (\\d{4}(-\\d{4})?) Intel Corporation
+# SPDX-License-Identifier: Apache-2\\.0
+"""
+
[tool.pytest.ini_options]
markers = [
"gpu", # mark tests which require NVIDIA GPU
diff --git a/src/otx/backend/native/callbacks/adaptive_train_scheduling.py b/src/otx/backend/native/callbacks/adaptive_train_scheduling.py
index 2b1200756e..d0b5296eba 100644
--- a/src/otx/backend/native/callbacks/adaptive_train_scheduling.py
+++ b/src/otx/backend/native/callbacks/adaptive_train_scheduling.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Callback to reschedule the validation interval adaptively."""
@@ -91,7 +91,7 @@ def on_train_end(self, trainer: Trainer, pl_module: LightningModule) -> None:
self._saved_log_every_n_steps = None
if len(self._revert_lr_frequency) > 0 and len(self._revert_lr_patience) > 0:
- for revert_f, revert_p in zip(self._revert_lr_frequency, self._revert_lr_patience):
+ for revert_f, revert_p in zip(self._revert_lr_frequency, self._revert_lr_patience, strict=True):
revert_f()
revert_p()
diff --git a/src/otx/backend/native/engine.py b/src/otx/backend/native/engine.py
index 523307de92..af4290536e 100644
--- a/src/otx/backend/native/engine.py
+++ b/src/otx/backend/native/engine.py
@@ -14,7 +14,7 @@
from contextlib import contextmanager
from multiprocessing import Value
from pathlib import Path
-from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterable, Iterator, Literal
+from typing import TYPE_CHECKING, Any, ClassVar, Literal
from warnings import warn
import torch
@@ -44,6 +44,8 @@
from otx.utils.utils import measure_flops
if TYPE_CHECKING:
+ from collections.abc import Callable, Iterable, Iterator
+
from lightning import Callback
from lightning.pytorch.loggers import Logger
from lightning.pytorch.utilities.types import EVAL_DATALOADERS
@@ -108,11 +110,11 @@ def __init__(
self.work_dir = work_dir
self.device = device # type: ignore[assignment]
self.num_devices = num_devices
- if not isinstance(data, (OTXDataModule, str, os.PathLike)):
+ if not isinstance(data, OTXDataModule | str | os.PathLike):
msg = f"data should be OTXDataModule or PathLike, but got {type(data)}"
raise TypeError(msg)
self._auto_configurator = AutoConfigurator(
- data_root=data if isinstance(data, (str, os.PathLike)) else None,
+ data_root=data if isinstance(data, str | os.PathLike) else None,
task=data.task if isinstance(data, OTXDataModule) else None,
model_config_path=None if isinstance(model, OTXModel) else model,
)
@@ -139,7 +141,7 @@ def __init__(
self.checkpoint = checkpoint
if self.checkpoint:
- if not isinstance(self.checkpoint, (Path, str)) and not Path(self.checkpoint).exists():
+ if not isinstance(self.checkpoint, Path | str) and not Path(self.checkpoint).exists():
msg = f"Checkpoint {self.checkpoint} does not exist."
raise FileNotFoundError(msg)
self._model.load_state_dict_incrementally(torch.load(self.checkpoint))
@@ -284,7 +286,7 @@ def train(
)
self.checkpoint = self.trainer.checkpoint_callback.best_model_path
- if not isinstance(self.checkpoint, (Path, str)):
+ if not isinstance(self.checkpoint, Path | str):
msg = "self.checkpoint should be Path or str at this time."
raise TypeError(msg)
diff --git a/src/otx/backend/native/exporter/exportable_code/demo/demo_package/streamer/streamer.py b/src/otx/backend/native/exporter/exportable_code/demo/demo_package/streamer/streamer.py
index 1a734b75e8..20c3a135f6 100644
--- a/src/otx/backend/native/exporter/exportable_code/demo/demo_package/streamer/streamer.py
+++ b/src/otx/backend/native/exporter/exportable_code/demo/demo_package/streamer/streamer.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Streamer for reading input."""
@@ -13,9 +13,11 @@
import sys
from enum import Enum
from pathlib import Path
-from typing import TYPE_CHECKING, Iterator
+from typing import TYPE_CHECKING
if TYPE_CHECKING:
+ from collections.abc import Iterator
+
import numpy as np
import cv2
@@ -332,7 +334,7 @@ def get_streamer(
try:
streamer = reader(input_stream, loop) # type: ignore [abstract]
return ThreadedStreamer(streamer) if threaded else streamer
- except RuntimeError as error: # noqa: PERF203
+ except RuntimeError as error:
errors.append(error)
try:
streamer = CameraStreamer(input_stream)
diff --git a/src/otx/backend/native/exporter/exportable_code/demo/demo_package/visualizers/vis_utils.py b/src/otx/backend/native/exporter/exportable_code/demo/demo_package/visualizers/vis_utils.py
index 55e7344df1..e0749b95d7 100644
--- a/src/otx/backend/native/exporter/exportable_code/demo/demo_package/visualizers/vis_utils.py
+++ b/src/otx/backend/native/exporter/exportable_code/demo/demo_package/visualizers/vis_utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""This module implements activation map."""
@@ -75,7 +75,7 @@ def dump_frames(saved_frames: list, output: str, input_path: str | int, capture:
else:
if len(filenames) != len(saved_frames):
filenames = [f"output_{i}.jpeg" for i, _ in enumerate(saved_frames)]
- for filename, frame in zip(filenames, saved_frames):
+ for filename, frame in zip(filenames, saved_frames, strict=True):
image_path = str(output_path / filename)
cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
cv2.imwrite(image_path, frame)
diff --git a/src/otx/backend/native/exporter/exportable_code/demo/demo_package/visualizers/visualizer.py b/src/otx/backend/native/exporter/exportable_code/demo/demo_package/visualizers/visualizer.py
index 1a77250b87..4eabfb40e6 100644
--- a/src/otx/backend/native/exporter/exportable_code/demo/demo_package/visualizers/visualizer.py
+++ b/src/otx/backend/native/exporter/exportable_code/demo/demo_package/visualizers/visualizer.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Visualizer for results of prediction."""
@@ -369,7 +369,7 @@ def _overlay_masks(self, image: np.ndarray, masks: np.ndarray) -> np.ndarray:
return image
def _overlay_boxes(self, image: np.ndarray, boxes: list[np.ndarray], classes: list[int]) -> np.ndarray:
- for box, class_id in zip(boxes, classes):
+ for box, class_id in zip(boxes, classes, strict=True):
color = self.palette[class_id]
top_left, bottom_right = box[:2], box[2:]
image = cv2.rectangle(image, top_left, bottom_right, color, 2)
@@ -384,7 +384,7 @@ def _overlay_labels(
) -> np.ndarray:
template = "{}: {:.2f}" if self.show_scores else "{}"
- for box, score, label in zip(boxes, scores, classes):
+ for box, score, label in zip(boxes, scores, classes, strict=True):
text = template.format(label, score)
textsize = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)[0]
cv2.putText(
diff --git a/src/otx/backend/native/models/anomaly/base.py b/src/otx/backend/native/models/anomaly/base.py
index 94f801aaa6..3407586db7 100644
--- a/src/otx/backend/native/models/anomaly/base.py
+++ b/src/otx/backend/native/models/anomaly/base.py
@@ -1,11 +1,11 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Anomaly Lightning OTX model."""
from __future__ import annotations
-from typing import TYPE_CHECKING, Any, Sequence
+from typing import TYPE_CHECKING, Any
import torch
from anomalib import TaskType as AnomalibTaskType
@@ -28,6 +28,7 @@
if TYPE_CHECKING:
import types
+ from collections.abc import Sequence
from pathlib import Path
from anomalib.metrics import AnomalibMetricCollection
diff --git a/src/otx/backend/native/models/anomaly/openvino_model.py b/src/otx/backend/native/models/anomaly/openvino_model.py
index 59c856c72c..f442884fe0 100644
--- a/src/otx/backend/native/models/anomaly/openvino_model.py
+++ b/src/otx/backend/native/models/anomaly/openvino_model.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""OTX Anomaly OpenVINO model.
@@ -11,7 +11,7 @@
from __future__ import annotations
-from typing import TYPE_CHECKING, Any, Literal, Sequence
+from typing import TYPE_CHECKING, Any, Literal
import numpy as np
import openvino
@@ -28,6 +28,7 @@
from otx.types.task import OTXTaskType
if TYPE_CHECKING:
+ from collections.abc import Sequence
from pathlib import Path
from anomalib.metrics import AnomalibMetricCollection
diff --git a/src/otx/backend/native/models/anomaly/stfpm.py b/src/otx/backend/native/models/anomaly/stfpm.py
index 1e79796fb4..9fee168304 100644
--- a/src/otx/backend/native/models/anomaly/stfpm.py
+++ b/src/otx/backend/native/models/anomaly/stfpm.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""OTX STFPM model."""
@@ -8,7 +8,7 @@
from __future__ import annotations
-from typing import TYPE_CHECKING, Literal, Sequence
+from typing import TYPE_CHECKING, Literal
from anomalib.models.image.stfpm import Stfpm as AnomalibStfpm
@@ -18,6 +18,8 @@
from otx.types.task import OTXTaskType
if TYPE_CHECKING:
+ from collections.abc import Sequence
+
from otx.types.label import LabelInfoTypes
diff --git a/src/otx/backend/native/models/base.py b/src/otx/backend/native/models/base.py
index f6923879ca..4bc444ca88 100644
--- a/src/otx/backend/native/models/base.py
+++ b/src/otx/backend/native/models/base.py
@@ -11,8 +11,9 @@
import logging
import warnings
from abc import abstractmethod
+from collections.abc import Callable, Sequence
from dataclasses import dataclass
-from typing import TYPE_CHECKING, Any, Callable, Literal, Sequence
+from typing import TYPE_CHECKING, Any, Literal
import torch
from datumaro import LabelCategories
@@ -352,7 +353,7 @@ def configure_metric(self) -> None:
metric = self.metric_callable(self.label_info)
- if not isinstance(metric, (Metric, MetricCollection)):
+ if not isinstance(metric, Metric | MetricCollection):
msg = "Metric should be the instance of `torchmetrics.Metric` or `torchmetrics.MetricCollection`."
raise TypeError(msg, metric)
diff --git a/src/otx/backend/native/models/classification/backbones/efficientnet.py b/src/otx/backend/native/models/classification/backbones/efficientnet.py
index e7f9d7e538..55f1c46ec9 100644
--- a/src/otx/backend/native/models/classification/backbones/efficientnet.py
+++ b/src/otx/backend/native/models/classification/backbones/efficientnet.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023-2024 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""EfficientNet Module."""
@@ -7,7 +7,7 @@
import math
from pathlib import Path
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
from pytorchcv.models.model_store import download_model
@@ -23,6 +23,9 @@
"efficientnet_b0": PRETRAINED_ROOT + "efficientnet_b0-0752-0e386130.pth.zip",
}
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
def conv1x1_block(
in_channels: int,
@@ -632,22 +635,22 @@ def __new__(
channels: list = reduce(
lambda x, y: [*x, [y[0]] * y[1]] if y[2] != 0 else x[:-1] + [x[-1] + [y[0]] * y[1]],
- zip(channels_per_layers, effnet_layers, cls.downsample),
+ zip(channels_per_layers, effnet_layers, cls.downsample, strict=True),
[],
)
kernel_sizes: list = reduce(
lambda x, y: [*x, [y[0]] * y[1]] if y[2] != 0 else x[:-1] + [x[-1] + [y[0]] * y[1]],
- zip(cls.kernel_sizes_per_layers, effnet_layers, cls.downsample),
+ zip(cls.kernel_sizes_per_layers, effnet_layers, cls.downsample, strict=True),
[],
)
expansion_factors: list = reduce(
lambda x, y: [*x, [y[0]] * y[1]] if y[2] != 0 else x[:-1] + [x[-1] + [y[0]] * y[1]],
- zip(cls.expansion_factors_per_layers, effnet_layers, cls.downsample),
+ zip(cls.expansion_factors_per_layers, effnet_layers, cls.downsample, strict=True),
[],
)
strides_per_stage: list = reduce(
lambda x, y: [*x, [y[0]] * y[1]] if y[2] != 0 else x[:-1] + [x[-1] + [y[0]] * y[1]],
- zip(cls.strides_per_stage, effnet_layers, cls.downsample),
+ zip(cls.strides_per_stage, effnet_layers, cls.downsample, strict=True),
[],
)
strides_per_stage = [si[0] for si in strides_per_stage]
diff --git a/src/otx/backend/native/models/classification/backbones/timm.py b/src/otx/backend/native/models/classification/backbones/timm.py
index c59fc73349..6882e95a70 100644
--- a/src/otx/backend/native/models/classification/backbones/timm.py
+++ b/src/otx/backend/native/models/classification/backbones/timm.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Timm Backbone Class for OTX classification.
@@ -58,7 +58,7 @@ def get_config_optim(self, lrs: list[float] | float) -> list[dict[str, float]]:
{"params": self.model.named_parameters()},
]
if isinstance(lrs, list):
- for lr, param_dict in zip(lrs, parameters):
+ for lr, param_dict in zip(lrs, parameters, strict=True):
param_dict["lr"] = lr
else:
for param_dict in parameters:
diff --git a/src/otx/backend/native/models/classification/backbones/vision_transformer.py b/src/otx/backend/native/models/classification/backbones/vision_transformer.py
index 0b96a08cfe..efd16d7f95 100644
--- a/src/otx/backend/native/models/classification/backbones/vision_transformer.py
+++ b/src/otx/backend/native/models/classification/backbones/vision_transformer.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -8,7 +8,7 @@
import math
from functools import partial
-from typing import TYPE_CHECKING, Any, Callable, ClassVar, Literal
+from typing import TYPE_CHECKING, Any, ClassVar, Literal
import torch
from timm.layers import (
@@ -34,6 +34,7 @@
from otx.backend.native.models.modules.base_module import BaseModule
if TYPE_CHECKING:
+ from collections.abc import Callable
from pathlib import Path
import numpy as np
@@ -538,7 +539,7 @@ def get_intermediate_layers(
for out in outputs
]
if return_class_token:
- return tuple(zip(outputs, class_tokens))
+ return tuple(zip(outputs, class_tokens, strict=True))
return tuple(outputs)
def forward(
diff --git a/src/otx/backend/native/models/classification/heads/hlabel_cls_head.py b/src/otx/backend/native/models/classification/heads/hlabel_cls_head.py
index e621bd22c5..9ad61cf091 100644
--- a/src/otx/backend/native/models/classification/heads/hlabel_cls_head.py
+++ b/src/otx/backend/native/models/classification/heads/hlabel_cls_head.py
@@ -1,11 +1,11 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Module for defining h-label linear classification head."""
from __future__ import annotations
-from typing import Callable, Sequence
+from collections.abc import Callable, Sequence
import torch
from torch import nn
diff --git a/src/otx/backend/native/models/classification/heads/multilabel_cls_head.py b/src/otx/backend/native/models/classification/heads/multilabel_cls_head.py
index e1ad0f3013..2d2fd9f416 100644
--- a/src/otx/backend/native/models/classification/heads/multilabel_cls_head.py
+++ b/src/otx/backend/native/models/classification/heads/multilabel_cls_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -12,7 +12,7 @@
from __future__ import annotations
-from typing import Callable, Sequence
+from collections.abc import Callable, Sequence
import torch
from torch import nn
diff --git a/src/otx/backend/native/models/classification/multiclass_models/vit.py b/src/otx/backend/native/models/classification/multiclass_models/vit.py
index d95b911cce..75ee252773 100644
--- a/src/otx/backend/native/models/classification/multiclass_models/vit.py
+++ b/src/otx/backend/native/models/classification/multiclass_models/vit.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""ViT model implementation."""
@@ -7,7 +7,7 @@
import types
from pathlib import Path
-from typing import TYPE_CHECKING, Any, Callable, Literal
+from typing import TYPE_CHECKING, Any, Literal
from urllib.parse import urlparse
import numpy as np
@@ -32,6 +32,8 @@
from otx.types.label import LabelInfoTypes
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from lightning.pytorch.cli import LRSchedulerCallable, OptimizerCallable
from otx.metrics import MetricCallable
diff --git a/src/otx/backend/native/models/classification/necks/gap.py b/src/otx/backend/native/models/classification/necks/gap.py
index 21e3cdf0e0..7adc97eb67 100644
--- a/src/otx/backend/native/models/classification/necks/gap.py
+++ b/src/otx/backend/native/models/classification/necks/gap.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -58,7 +58,7 @@ def forward(self, inputs: tuple | torch.Tensor) -> tuple | torch.Tensor:
"""
if isinstance(inputs, tuple):
outs = tuple([self.gap(x) for x in inputs])
- outs = tuple([out.view(x.size(0), -1) for out, x in zip(outs, inputs)])
+ outs = tuple([out.view(x.size(0), -1) for out, x in zip(outs, inputs, strict=True)])
elif isinstance(inputs, torch.Tensor):
_outs = self.gap(inputs)
outs = _outs.view(inputs.size(0), -1)
diff --git a/src/otx/backend/native/models/classification/utils/swiglu_ffn.py b/src/otx/backend/native/models/classification/utils/swiglu_ffn.py
index 9139419e6b..da4ae33b0f 100644
--- a/src/otx/backend/native/models/classification/utils/swiglu_ffn.py
+++ b/src/otx/backend/native/models/classification/utils/swiglu_ffn.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -7,7 +7,7 @@
from __future__ import annotations
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
from torch import nn
@@ -15,6 +15,9 @@
from otx.backend.native.models.modules.drop import build_dropout
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class SwiGLUFFN(nn.Module):
"""SwiGLU FFN layer.
diff --git a/src/otx/backend/native/models/common/backbones/pytorchcv_backbones.py b/src/otx/backend/native/models/common/backbones/pytorchcv_backbones.py
index 345f75d0f7..69567f7d7c 100644
--- a/src/otx/backend/native/models/common/backbones/pytorchcv_backbones.py
+++ b/src/otx/backend/native/models/common/backbones/pytorchcv_backbones.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023-2024 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Backbone of pytorchcv for mmdetection backbones."""
@@ -6,7 +6,7 @@
from __future__ import annotations
from pathlib import Path
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
from pytorchcv.model_provider import _models
@@ -17,6 +17,9 @@
from otx.backend.native.models.modules.norm import build_norm_layer
from otx.backend.native.models.utils.utils import get_dist_info
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
# ruff: noqa: SLF001
diff --git a/src/otx/backend/native/models/common/backbones/resnet.py b/src/otx/backend/native/models/common/backbones/resnet.py
index d56408b40a..c345304e70 100644
--- a/src/otx/backend/native/models/common/backbones/resnet.py
+++ b/src/otx/backend/native/models/common/backbones/resnet.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""MMDet ResNet."""
@@ -7,7 +7,7 @@
import warnings
from functools import partial
-from typing import Callable, ClassVar
+from typing import TYPE_CHECKING, ClassVar
import torch
import torch.utils.checkpoint as cp
@@ -18,6 +18,9 @@
from otx.backend.native.models.modules.base_module import BaseModule
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class Bottleneck(BaseModule):
"""Bottleneck block for ResNet.
@@ -178,11 +181,7 @@ def __init__(
out_indices: tuple[int, int, int, int] = (0, 1, 2, 3),
avg_down: bool = False,
frozen_stages: int = -1,
- normalization: Callable[..., nn.Module] = partial(
- build_norm_layer,
- nn.BatchNorm2d,
- requires_grad=True,
- ),
+ normalization: Callable[..., nn.Module] | None = None,
norm_eval: bool = True,
with_cp: bool = False,
zero_init_residual: bool = True,
@@ -235,6 +234,20 @@ def __init__(
raise ValueError(msg)
self.avg_down = avg_down
self.frozen_stages = frozen_stages
+
+ if normalization is None:
+ normalization = partial(
+ build_norm_layer,
+ nn.BatchNorm2d,
+ requires_grad=True,
+ )
+ elif not callable(normalization):
+ msg = (
+ "normalization must be None, a normalization layer class, or a callable, "
+ f"but got {type(normalization)}."
+ )
+ raise TypeError(msg)
+
self.normalization = normalization
self.with_cp = with_cp
self.norm_eval = norm_eval
diff --git a/src/otx/backend/native/models/common/layers/res_layer.py b/src/otx/backend/native/models/common/layers/res_layer.py
index 17070bbd64..fb68b6cab8 100644
--- a/src/otx/backend/native/models/common/layers/res_layer.py
+++ b/src/otx/backend/native/models/common/layers/res_layer.py
@@ -1,17 +1,20 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""MMDet ResLayer."""
from __future__ import annotations
-from typing import Callable
+from typing import TYPE_CHECKING
from torch import nn
from otx.backend.native.models.modules.base_module import BaseModule, Sequential
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class ResLayer(Sequential):
"""ResLayer to build ResNet style backbone.
diff --git a/src/otx/backend/native/models/common/layers/spp_layer.py b/src/otx/backend/native/models/common/layers/spp_layer.py
index 78eab17d68..925be7664c 100644
--- a/src/otx/backend/native/models/common/layers/spp_layer.py
+++ b/src/otx/backend/native/models/common/layers/spp_layer.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -11,7 +11,7 @@
from __future__ import annotations
from functools import partial
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
from torch import Tensor, nn
@@ -21,6 +21,9 @@
from otx.backend.native.models.modules.conv_module import Conv2dModule
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class SPPBottleneck(BaseModule):
"""Spatial pyramid pooling layer used in YOLOv3-SPP.
@@ -32,7 +35,7 @@ class SPPBottleneck(BaseModule):
layers. Default: (5, 9, 13).
normalization (Callable[..., nn.Module]): Normalization layer module.
Defaults to ``partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)``.
- activation (Callable[..., nn.Module] | None): Activation layer module.
+ activation (Callable[..., nn.Module]): Activation layer module.
Defaults to ``Swish``.
init_cfg (dict, list[dict], optional): Initialization config dict.
Default: None.
@@ -43,12 +46,16 @@ def __init__(
in_channels: int,
out_channels: int,
kernel_sizes: tuple[int, ...] = (5, 9, 13),
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001),
- activation: Callable[..., nn.Module] | None = Swish,
+ normalization: Callable[..., nn.Module] | None = None,
+ activation: Callable[..., nn.Module] = Swish,
init_cfg: dict | list[dict] | None = None,
):
super().__init__(init_cfg=init_cfg)
mid_channels = in_channels // 2
+
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)
+
self.conv1 = Conv2dModule(
in_channels,
mid_channels,
diff --git a/src/otx/backend/native/models/common/layers/transformer_layers.py b/src/otx/backend/native/models/common/layers/transformer_layers.py
index 72332c2af3..dfde3767ae 100644
--- a/src/otx/backend/native/models/common/layers/transformer_layers.py
+++ b/src/otx/backend/native/models/common/layers/transformer_layers.py
@@ -7,7 +7,7 @@
import copy
import math
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
import torch.nn.functional as f
@@ -17,6 +17,9 @@
from otx.backend.native.models.common.utils.utils import get_clones
from otx.backend.native.models.modules.transformer import deformable_attention_core_func
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class TransformerEncoderLayer(nn.Module):
"""TransformerEncoderLayer."""
@@ -150,7 +153,7 @@ def __init__(
super().__init__()
self.num_layers = num_layers
h = [hidden_dim] * (num_layers - 1)
- self.layers = nn.ModuleList(nn.Linear(n, k) for n, k in zip([input_dim, *h], [*h, output_dim]))
+ self.layers = nn.ModuleList(nn.Linear(n, k) for n, k in zip([input_dim, *h], [*h, output_dim], strict=True))
self.act = activation() if activation else nn.Identity()
def forward(self, x: torch.Tensor) -> torch.Tensor:
diff --git a/src/otx/backend/native/models/common/losses/utils.py b/src/otx/backend/native/models/common/losses/utils.py
index 8f26727d7a..b26837f0fe 100644
--- a/src/otx/backend/native/models/common/losses/utils.py
+++ b/src/otx/backend/native/models/common/losses/utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -11,12 +11,15 @@
from __future__ import annotations
import functools
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
from torch import Tensor
from torch.nn import functional
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
def reduce_loss(loss: Tensor, reduction: str) -> Tensor:
"""Reduce loss as specified.
diff --git a/src/otx/backend/native/models/common/utils/assigners/dynamic_soft_label_assigner.py b/src/otx/backend/native/models/common/utils/assigners/dynamic_soft_label_assigner.py
index 71dba94a28..30cb21d9e1 100644
--- a/src/otx/backend/native/models/common/utils/assigners/dynamic_soft_label_assigner.py
+++ b/src/otx/backend/native/models/common/utils/assigners/dynamic_soft_label_assigner.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -12,7 +12,7 @@
from __future__ import annotations
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
import numpy as np
import torch
@@ -29,6 +29,8 @@
GPU_MEM_LIMIT = 1024**3 # 1 GB memory limit
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from otx.backend.native.models.utils.utils import InstanceData
diff --git a/src/otx/backend/native/models/common/utils/assigners/max_iou_assigner.py b/src/otx/backend/native/models/common/utils/assigners/max_iou_assigner.py
index d9ed97e799..2d3273fafe 100644
--- a/src/otx/backend/native/models/common/utils/assigners/max_iou_assigner.py
+++ b/src/otx/backend/native/models/common/utils/assigners/max_iou_assigner.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -11,7 +11,7 @@
from __future__ import annotations
import copy
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
import torch
from torch import Tensor
@@ -20,6 +20,8 @@
from otx.backend.native.models.common.utils.structures import AssignResult
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from otx.backend.native.models.utils.utils import InstanceData
diff --git a/src/otx/backend/native/models/common/utils/nms.py b/src/otx/backend/native/models/common/utils/nms.py
index 6500c7461d..e3f7a7cd9d 100644
--- a/src/otx/backend/native/models/common/utils/nms.py
+++ b/src/otx/backend/native/models/common/utils/nms.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -13,7 +13,7 @@
from __future__ import annotations
import warnings
-from typing import Any, Callable
+from typing import TYPE_CHECKING, Any
import numpy as np
import torch
@@ -23,6 +23,9 @@
from otx.backend.native.models.common.utils.utils import dynamic_topk
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class NMSop(torch.autograd.Function):
"""NMS operation."""
diff --git a/src/otx/backend/native/models/common/utils/prior_generators/anchor_generator.py b/src/otx/backend/native/models/common/utils/prior_generators/anchor_generator.py
index de1d2ae0bf..29b1f12576 100644
--- a/src/otx/backend/native/models/common/utils/prior_generators/anchor_generator.py
+++ b/src/otx/backend/native/models/common/utils/prior_generators/anchor_generator.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023-2024 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -487,7 +487,7 @@ def __init__(
def gen_base_anchors(self) -> None: # type: ignore[override]
"""Generate base anchor for SSD."""
multi_level_base_anchors = []
- for widths, heights, centers in zip(self.widths, self.heights, self.centers):
+ for widths, heights, centers in zip(self.widths, self.heights, self.centers, strict=True):
base_anchors = self.gen_single_level_base_anchors(
widths=Tensor(widths),
heights=Tensor(heights),
diff --git a/src/otx/backend/native/models/common/utils/prior_generators/base_prior_generator.py b/src/otx/backend/native/models/common/utils/prior_generators/base_prior_generator.py
index b954281c77..c51eed3202 100644
--- a/src/otx/backend/native/models/common/utils/prior_generators/base_prior_generator.py
+++ b/src/otx/backend/native/models/common/utils/prior_generators/base_prior_generator.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Base prior generator."""
@@ -6,9 +6,11 @@
from __future__ import annotations
from abc import ABCMeta, abstractmethod
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from torch import Tensor
diff --git a/src/otx/backend/native/models/common/utils/prior_generators/point_generator.py b/src/otx/backend/native/models/common/utils/prior_generators/point_generator.py
index 3d8df0ffc6..405afc6527 100644
--- a/src/otx/backend/native/models/common/utils/prior_generators/point_generator.py
+++ b/src/otx/backend/native/models/common/utils/prior_generators/point_generator.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -10,8 +10,6 @@
from __future__ import annotations
-from typing import Union
-
import numpy as np
import torch
from torch import Tensor
@@ -19,8 +17,6 @@
from .base_prior_generator import BasePriorGenerator
-DeviceType = Union[str, torch.device]
-
class MlvlPointGenerator(BasePriorGenerator):
"""Standard points generator for multi-level (Mlvl) feature maps in 2D points-based detectors.
@@ -60,7 +56,7 @@ def grid_priors(
self,
featmap_sizes: list[tuple[int, int]],
dtype: torch.dtype = torch.float32,
- device: DeviceType = "cuda",
+ device: str | torch.device = "cuda",
with_stride: bool = False,
) -> list[Tensor]:
"""Generate grid points of multiple feature levels.
@@ -103,7 +99,7 @@ def single_level_grid_priors(
featmap_size: tuple[int, int],
level_idx: int,
dtype: torch.dtype = torch.float32,
- device: DeviceType = "cuda",
+ device: str | torch.device = "cuda",
with_stride: bool = False,
) -> Tensor:
"""Generate grid Points of a single level.
@@ -156,7 +152,7 @@ def valid_flags(
self,
featmap_sizes: list[tuple[int, int]],
pad_shape: tuple[int, ...],
- device: DeviceType = "cuda",
+ device: str | torch.device = "cuda",
) -> list[Tensor]:
"""Generate valid flags of points of multiple feature levels.
@@ -188,7 +184,7 @@ def single_level_valid_flags(
self,
featmap_size: tuple[int, int],
valid_size: tuple[int, int],
- device: DeviceType = "cuda",
+ device: str | torch.device = "cuda",
) -> Tensor:
"""Generate the valid flags of points of a single feature map.
@@ -221,7 +217,7 @@ def sparse_priors(
featmap_size: tuple[int, int],
level_idx: int,
dtype: torch.dtype = torch.float32,
- device: DeviceType = "cuda",
+ device: str | torch.device = "cuda",
) -> Tensor:
"""Generate sparse points according to the ``prior_idxs``.
diff --git a/src/otx/backend/native/models/common/utils/utils.py b/src/otx/backend/native/models/common/utils/utils.py
index 04f71f8720..9ea110c532 100644
--- a/src/otx/backend/native/models/common/utils/utils.py
+++ b/src/otx/backend/native/models/common/utils/utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -19,12 +19,15 @@
import copy
from functools import partial
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
import torch.distributed as dist
from torch import Tensor, nn
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
def reduce_mean(tensor: Tensor) -> Tensor:
"""Obtain the mean of tensor on different GPUs."""
@@ -54,7 +57,7 @@ def multi_apply(func: Callable, *args, **kwargs) -> tuple:
"""
pfunc = partial(func, **kwargs) if kwargs else func
map_results = map(pfunc, *args) # type: ignore[call-overload]
- return tuple(map(list, zip(*map_results)))
+ return tuple(map(list, zip(*map_results, strict=True)))
def filter_scores_and_topk(
diff --git a/src/otx/backend/native/models/detection/backbones/csp_darknet.py b/src/otx/backend/native/models/detection/backbones/csp_darknet.py
index f726a105f8..7614f37316 100644
--- a/src/otx/backend/native/models/detection/backbones/csp_darknet.py
+++ b/src/otx/backend/native/models/detection/backbones/csp_darknet.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -12,7 +12,7 @@
import math
from functools import partial
-from typing import Any, Callable, ClassVar, Sequence
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
from torch import Tensor, nn
@@ -25,6 +25,9 @@
from otx.backend.native.models.modules.conv_module import Conv2dModule, DepthwiseSeparableConvModule
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable, Sequence
+
class Focus(nn.Module):
"""Focus width and height information into channel space.
@@ -35,8 +38,8 @@ class Focus(nn.Module):
kernel_size (int): The kernel size of the convolution. Default: 1
stride (int): The stride of the convolution. Default: 1
normalization (Callable[..., nn.Module] | None): Normalization layer module.
- Defaults to ``partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)``.
- activation (Callable[..., nn.Module] | None): Activation layer module.
+ Defaults to ``None``.
+ activation (Callable[..., nn.Module]): Activation layer module.
Defaults to ``Swish``.
"""
@@ -46,10 +49,14 @@ def __init__(
out_channels: int,
kernel_size: int = 1,
stride: int = 1,
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001),
- activation: Callable[..., nn.Module] | None = Swish,
+ normalization: Callable[..., nn.Module] | None = None,
+ activation: Callable[..., nn.Module] = Swish,
):
super().__init__()
+
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)
+
self.conv = Conv2dModule(
in_channels * 4,
out_channels,
@@ -112,8 +119,8 @@ class CSPDarknetModule(BaseModule):
spp_kernal_sizes: (tuple[int]): Sequential of kernel sizes of SPP
layers. Default: (5, 9, 13).
normalization (Callable[..., nn.Module] | None): Normalization layer module.
- Defaults to ``partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)``.
- activation (Callable[..., nn.Module] | None): Activation layer module.
+ Defaults to ``None``.
+ activation (Callable[..., nn.Module]): Activation layer module.
Defaults to ``Swish``.
norm_eval (bool): Whether to set norm layers to eval mode, namely,
freeze running stats (mean and var). Note: Effect on Batch Norm
@@ -150,7 +157,7 @@ def __init__(
use_depthwise: bool = False,
arch_ovewrite: list | None = None,
spp_kernal_sizes: tuple[int, ...] = (5, 9, 13),
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001),
+ normalization: Callable[..., nn.Module] | None = None,
activation: Callable[..., nn.Module] = Swish,
norm_eval: bool = False,
init_cfg: dict | list[dict] | None = None,
@@ -179,6 +186,9 @@ def __init__(
self.norm_eval = norm_eval
conv = DepthwiseSeparableConvModule if use_depthwise else Conv2dModule
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)
+
self.stem = Focus(
3,
int(arch_setting[0][0] * widen_factor),
diff --git a/src/otx/backend/native/models/detection/backbones/cspnext.py b/src/otx/backend/native/models/detection/backbones/cspnext.py
index 94ab4544de..cfe61de2b1 100644
--- a/src/otx/backend/native/models/detection/backbones/cspnext.py
+++ b/src/otx/backend/native/models/detection/backbones/cspnext.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -12,7 +12,7 @@
import math
from functools import partial
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
from torch import Tensor, nn
from torch.nn.modules.batchnorm import _BatchNorm
@@ -24,6 +24,9 @@
from otx.backend.native.models.modules.conv_module import Conv2dModule, DepthwiseSeparableConvModule
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class CSPNeXtModule(BaseModule):
"""CSPNeXt backbone used in RTMDet.
@@ -50,8 +53,8 @@ class CSPNeXtModule(BaseModule):
channel_attention (bool): Whether to add channel attention in each
stage. Defaults to True.
normalization (Callable[..., nn.Module]): Normalization layer module.
- Defaults to ``partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)``.
- activation (Callable[..., nn.Module] | None): Activation layer module.
+ Defaults to ``None``.
+ activation (Callable[..., nn.Module]): Activation layer module.
Defaults to ``nn.SiLU``.
norm_eval (bool): Whether to set norm layers to eval mode, namely,
freeze running stats (mean and var). Note: Effect on Batch Norm
@@ -89,7 +92,7 @@ def __init__(
arch_ovewrite: dict | None = None,
spp_kernel_sizes: tuple[int, int, int] = (5, 9, 13),
channel_attention: bool = True,
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001),
+ normalization: Callable[..., nn.Module] | None = None,
activation: Callable[..., nn.Module] = nn.SiLU,
norm_eval: bool = False,
init_cfg: dict | None = None,
@@ -121,6 +124,10 @@ def __init__(
self.use_depthwise = use_depthwise
self.norm_eval = norm_eval
conv = DepthwiseSeparableConvModule if use_depthwise else Conv2dModule
+
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)
+
self.stem = nn.Sequential(
Conv2dModule(
3,
diff --git a/src/otx/backend/native/models/detection/backbones/presnet.py b/src/otx/backend/native/models/detection/backbones/presnet.py
index 6207355a18..6e1d756fb9 100644
--- a/src/otx/backend/native/models/detection/backbones/presnet.py
+++ b/src/otx/backend/native/models/detection/backbones/presnet.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Presnet backbones, modified from https://github.com/lyuwenyu/RT-DETR."""
@@ -7,7 +7,7 @@
from collections import OrderedDict
from functools import partial
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
from torch import nn
@@ -17,6 +17,9 @@
from otx.backend.native.models.modules.conv_module import Conv2dModule
from otx.backend.native.models.modules.norm import FrozenBatchNorm2d, build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
__all__ = ["PResNet"]
@@ -251,10 +254,10 @@ class PResNetModule(BaseModule):
variant (str): The variant of the PResNet backbone. Defaults to "d".
num_stages (int): The number of stages in the PResNet backbone. Defaults to 4.
return_idx (list[int]): The indices of the stages to return as output. Defaults to [0, 1, 2, 3].
- activation (Callable[..., nn.Module] | None): Activation layer module.
+ activation (Callable[..., nn.Module]): Activation layer module.
Defaults to None.
normalization (Callable[..., nn.Module] | None): Normalization layer module.
- Defaults to ``nn.BatchNorm2d``.
+ Defaults to ``None``.
freeze_at (int): The stage at which to freeze the parameters. Defaults to -1.
pretrained (bool): Whether to load pretrained weights. Defaults to False.
"""
@@ -279,14 +282,17 @@ def __init__(
variant: str = "d",
num_stages: int = 4,
return_idx: list[int] = [0, 1, 2, 3], # noqa: B006
- activation: Callable[..., nn.Module] | None = nn.ReLU,
- normalization: Callable[..., nn.Module] = partial(build_norm_layer, nn.BatchNorm2d, layer_name="norm"),
+ activation: Callable[..., nn.Module] = nn.ReLU,
+ normalization: Callable[..., nn.Module] | None = None,
freeze_at: int = -1,
pretrained: bool = False,
) -> None:
"""Initialize the PResNet backbone."""
super().__init__()
+ if normalization is None:
+ normalization = partial(build_norm_layer, nn.BatchNorm2d, layer_name="norm")
+
block_nums = self.num_resnet_blocks[depth]
ch_in = 64
if variant in ["c", "d"]:
diff --git a/src/otx/backend/native/models/detection/base.py b/src/otx/backend/native/models/detection/base.py
index e003ff7a26..e6a3e2e33c 100644
--- a/src/otx/backend/native/models/detection/base.py
+++ b/src/otx/backend/native/models/detection/base.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023-2024 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Class definition for detection model entity used in OTX."""
@@ -10,7 +10,7 @@
import logging as log
import types
from contextlib import contextmanager
-from typing import TYPE_CHECKING, Any, Callable, Iterator, Literal
+from typing import TYPE_CHECKING, Any, Literal
import torch
from torchmetrics import Metric, MetricCollection
@@ -33,6 +33,8 @@
from otx.types.task import OTXTaskType
if TYPE_CHECKING:
+ from collections.abc import Callable, Iterator
+
from lightning.pytorch.cli import LRSchedulerCallable, OptimizerCallable
from otx.backend.native.models.detection.detectors import SingleStageDetector
@@ -120,7 +122,7 @@ def _filter_outputs_by_threshold(self, outputs: OTXPredBatch) -> OTXPredBatch:
bboxes = []
labels = []
if outputs.scores is not None and outputs.bboxes is not None and outputs.labels is not None:
- for score, bbox, label in zip(outputs.scores, outputs.bboxes, outputs.labels):
+ for score, bbox, label in zip(outputs.scores, outputs.bboxes, outputs.labels, strict=True):
filtered_idx = torch.where(score > self.best_confidence_threshold)
scores.append(score[filtered_idx])
bboxes.append(tv_tensors.wrap(bbox[filtered_idx], like=bbox))
@@ -175,7 +177,7 @@ def _customize_outputs(
bboxes = []
labels = []
predictions = outputs["predictions"] if isinstance(outputs, dict) else outputs
- for img_info, prediction in zip(inputs.imgs_info, predictions): # type: ignore[union-attr,arg-type]
+ for img_info, prediction in zip(inputs.imgs_info, predictions, strict=True): # type: ignore[union-attr,arg-type]
if not isinstance(prediction, InstanceData):
raise TypeError(prediction)
@@ -300,14 +302,14 @@ def _convert_pred_entity_to_compute_metric(
"scores": scores.type(torch.float32),
"labels": labels,
}
- for bboxes, scores, labels in zip(preds.bboxes, preds.scores, preds.labels) # type: ignore[arg-type]
+ for bboxes, scores, labels in zip(preds.bboxes, preds.scores, preds.labels, strict=True) # type: ignore[arg-type]
],
"target": [
{
"boxes": bboxes.data,
"labels": labels,
}
- for bboxes, labels in zip(inputs.bboxes, inputs.labels) # type: ignore[arg-type]
+ for bboxes, labels in zip(inputs.bboxes, inputs.labels, strict=True) # type: ignore[arg-type]
],
}
diff --git a/src/otx/backend/native/models/detection/detectors/detection_transformer.py b/src/otx/backend/native/models/detection/detectors/detection_transformer.py
index 1ffec9e9dd..f03f69e87b 100644
--- a/src/otx/backend/native/models/detection/detectors/detection_transformer.py
+++ b/src/otx/backend/native/models/detection/detectors/detection_transformer.py
@@ -137,7 +137,8 @@ def split_and_reshape_logits(
# Reshape each split in a list comprehension
return tuple(
- logits.reshape(f.shape[0], -1, f.shape[-2], f.shape[-1]) for logits, f in zip(raw_logits, backbone_feats)
+ logits.reshape(f.shape[0], -1, f.shape[-2], f.shape[-1])
+ for logits, f in zip(raw_logits, backbone_feats, strict=True)
)
def postprocess(
@@ -176,7 +177,7 @@ def postprocess(
scores_list, boxes_list, labels_list = [], [], []
- for sc, bb, ll, original_size in zip(scores, boxes, labels, original_sizes):
+ for sc, bb, ll, original_size in zip(scores, boxes, labels, original_sizes, strict=True):
scores_list.append(sc)
boxes_list.append(
BoundingBoxes(bb, format="xyxy", canvas_size=original_size),
diff --git a/src/otx/backend/native/models/detection/heads/atss_head.py b/src/otx/backend/native/models/detection/heads/atss_head.py
index 3f587a6c01..0e87036793 100644
--- a/src/otx/backend/native/models/detection/heads/atss_head.py
+++ b/src/otx/backend/native/models/detection/heads/atss_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -11,7 +11,7 @@
from __future__ import annotations
from functools import partial
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
from torch import Tensor, nn
@@ -31,6 +31,9 @@
from otx.backend.native.models.utils.utils import InstanceData
from otx.data.entity.torch import OTXDataBatch
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
EPS = 1e-12
@@ -47,7 +50,7 @@ class ATSSHeadModule(ClassIncrementalMixin, AnchorHead):
pred_kernel_size (int): Kernel size of ``nn.Conv2d``. Defaults to 3.
stacked_convs (int): Number of stacking convs of the head. Defaults to 4.
normalization (Callable[..., nn.Module] | None): Normalization layer module.
- Defaults to ``partial(build_norm_layer, nn.GroupNorm, num_groups=32, requires_grad=True)``.
+ Defaults to ``None``.
reg_decoded_bbox (bool): If true, the regression loss would be
applied directly on decoded bounding boxes, converting both
the predicted boxes and regression targets to absolute
@@ -64,17 +67,19 @@ def __init__(
in_channels: int,
pred_kernel_size: int = 3,
stacked_convs: int = 4,
- normalization: Callable[..., nn.Module] = partial(
- build_norm_layer,
- nn.GroupNorm,
- num_groups=32,
- requires_grad=True,
- ),
+ normalization: Callable[..., nn.Module] | None = None,
reg_decoded_bbox: bool = True,
init_cfg: dict | None = None,
use_sigmoid_cls: bool = True,
**kwargs,
) -> None:
+ if normalization is None:
+ normalization = partial(
+ build_norm_layer,
+ nn.GroupNorm,
+ num_groups=32,
+ requires_grad=True,
+ )
self.pred_kernel_size = pred_kernel_size
self.stacked_convs = stacked_convs
self.normalization = normalization
diff --git a/src/otx/backend/native/models/detection/heads/base_head.py b/src/otx/backend/native/models/detection/heads/base_head.py
index 46562ca65a..910c9cea70 100644
--- a/src/otx/backend/native/models/detection/heads/base_head.py
+++ b/src/otx/backend/native/models/detection/heads/base_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -269,6 +269,7 @@ def _predict_by_feat_single(
bbox_pred_list,
score_factor_list,
mlvl_priors,
+ strict=True,
):
dim = self.bbox_coder.encode_size
bbox_pred = bbox_pred.permute(1, 2, 0).reshape(-1, dim) # noqa: PLW2901
@@ -491,6 +492,7 @@ def export_by_feat(
mlvl_bbox_preds,
mlvl_score_factor,
mlvl_priors,
+ strict=True,
):
scores = cls_score.permute(0, 2, 3, 1).reshape(batch_size, -1, self.cls_out_channels)
scores = scores.sigmoid() if self.use_sigmoid_cls else scores.softmax(-1)[:, :, :-1]
diff --git a/src/otx/backend/native/models/detection/heads/dfine_decoder.py b/src/otx/backend/native/models/detection/heads/dfine_decoder.py
index 253190dedf..e51da60eb5 100644
--- a/src/otx/backend/native/models/detection/heads/dfine_decoder.py
+++ b/src/otx/backend/native/models/detection/heads/dfine_decoder.py
@@ -8,7 +8,7 @@
import copy
from collections import OrderedDict
from functools import partial
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
import torch.nn.functional as f
@@ -21,6 +21,9 @@
from otx.backend.native.models.detection.utils.utils import dfine_distance2bbox, dfine_weighting_function
from otx.backend.native.models.utils.weight_init import bias_init_with_prob
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class TransformerDecoderLayer(nn.Module):
"""Transformer Decoder Layer with MSDeformableAttentionV2.
@@ -41,12 +44,15 @@ def __init__(
n_head: int = 8,
dim_feedforward: int = 1024,
dropout: float = 0.0,
- activation: Callable[..., nn.Module] = partial(nn.ReLU, inplace=True),
+ activation: Callable[..., nn.Module] | None = None,
n_levels: int = 4,
num_points_list: list[int] = [3, 6, 3], # noqa: B006
):
super().__init__()
+ if activation is None:
+ activation = partial(nn.ReLU, inplace=True)
+
# self attention
self.self_attn = nn.MultiheadAttention(
d_model,
@@ -565,7 +571,7 @@ def _reset_parameters(self, feat_channels: list[int]) -> None:
init.constant_(self.pre_bbox_head.layers[-1].weight, 0)
init.constant_(self.pre_bbox_head.layers[-1].bias, 0)
- for cls_, reg_ in zip(self.dec_score_head, self.dec_bbox_head):
+ for cls_, reg_ in zip(self.dec_score_head, self.dec_bbox_head, strict=True):
init.constant_(cls_.bias, bias)
if hasattr(reg_, "layers"):
init.constant_(reg_.layers[-1].weight, 0)
@@ -574,7 +580,7 @@ def _reset_parameters(self, feat_channels: list[int]) -> None:
init.xavier_uniform_(self.enc_output[0].weight)
init.xavier_uniform_(self.query_pos_head.layers[0].weight)
init.xavier_uniform_(self.query_pos_head.layers[1].weight)
- for m, in_channels in zip(self.input_proj, feat_channels):
+ for m, in_channels in zip(self.input_proj, feat_channels, strict=True):
if in_channels != self.hidden_dim:
init.xavier_uniform_(m[0].weight)
@@ -892,7 +898,7 @@ def _set_aux_loss(self, outputs_class: Tensor, outputs_coord: Tensor) -> list[di
# this is a workaround to make torchscript happy, as torchscript
# doesn't support dictionary with non-homogeneous values, such
# as a dict having both a Tensor and a list.
- return [{"pred_logits": a, "pred_boxes": b} for a, b in zip(outputs_class, outputs_coord)]
+ return [{"pred_logits": a, "pred_boxes": b} for a, b in zip(outputs_class, outputs_coord, strict=True)]
@torch.jit.unused
def _set_aux_loss2(
@@ -916,7 +922,7 @@ def _set_aux_loss2(
"teacher_corners": teacher_corners,
"teacher_logits": teacher_logits,
}
- for a, b, c, d in zip(outputs_class, outputs_coord, outputs_corners, outputs_ref)
+ for a, b, c, d in zip(outputs_class, outputs_coord, outputs_corners, outputs_ref, strict=True)
]
diff --git a/src/otx/backend/native/models/detection/heads/rtdetr_decoder.py b/src/otx/backend/native/models/detection/heads/rtdetr_decoder.py
index d6e308a7aa..407dfac919 100644
--- a/src/otx/backend/native/models/detection/heads/rtdetr_decoder.py
+++ b/src/otx/backend/native/models/detection/heads/rtdetr_decoder.py
@@ -8,7 +8,7 @@
import copy
import math
from collections import OrderedDict
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
import torchvision
@@ -19,6 +19,9 @@
from otx.backend.native.models.common.utils.utils import inverse_sigmoid
from otx.backend.native.models.modules.base_module import BaseModule
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
__all__ = ["RTDETRTransformer"]
@@ -423,7 +426,7 @@ def init_weights(self) -> None:
init.constant_(self.enc_bbox_head.layers[-1].weight, 0)
init.constant_(self.enc_bbox_head.layers[-1].bias, 0)
- for cls_, reg_ in zip(self.dec_score_head, self.dec_bbox_head):
+ for cls_, reg_ in zip(self.dec_score_head, self.dec_bbox_head, strict=True):
init.constant_(cls_.bias, bias)
init.constant_(reg_.layers[-1].weight, 0)
init.constant_(reg_.layers[-1].bias, 0)
@@ -654,7 +657,7 @@ def _set_aux_loss(self, outputs_class: torch.Tensor, outputs_coord: torch.Tensor
# this is a workaround to make torchscript happy, as torchscript
# doesn't support dictionary with non-homogeneous values, such
# as a dict having both a Tensor and a list.
- return [{"pred_logits": a, "pred_boxes": b} for a, b in zip(outputs_class, outputs_coord)]
+ return [{"pred_logits": a, "pred_boxes": b} for a, b in zip(outputs_class, outputs_coord, strict=True)]
class RTDETRTransformer:
diff --git a/src/otx/backend/native/models/detection/heads/rtmdet_head.py b/src/otx/backend/native/models/detection/heads/rtmdet_head.py
index 211d33fa12..e319859a43 100644
--- a/src/otx/backend/native/models/detection/heads/rtmdet_head.py
+++ b/src/otx/backend/native/models/detection/heads/rtmdet_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -11,7 +11,7 @@
from __future__ import annotations
from functools import partial
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
from torch import Tensor, nn
@@ -35,6 +35,9 @@
from otx.backend.native.models.utils.weight_init import bias_init_with_prob, constant_init, normal_init
from otx.data.entity.torch import OTXDataBatch
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class RTMDetHead(ATSSHeadModule):
"""Detection Head of RTMDet.
@@ -139,7 +142,7 @@ def forward(self, feats: tuple[Tensor, ...]) -> tuple:
"""
cls_scores = []
bbox_preds = []
- for x, scale, stride in zip(feats, self.scales, self.prior_generator.strides):
+ for x, scale, stride in zip(feats, self.scales, self.prior_generator.strides, strict=True):
cls_feat = x
reg_feat = x
@@ -196,7 +199,7 @@ def prepare_loss_inputs(
1,
)
decoded_bboxes = []
- for anchor, bbox_pred in zip(anchor_list[0], bbox_preds):
+ for anchor, bbox_pred in zip(anchor_list[0], bbox_preds, strict=True):
anchor = anchor.reshape(-1, 4) # noqa: PLW2901
bbox_pred = bbox_pred.permute(0, 2, 3, 1).reshape(num_imgs, -1, 4) # noqa: PLW2901
bbox_pred = distance2bbox(anchor, bbox_pred) # noqa: PLW2901
@@ -564,8 +567,8 @@ class RTMDetSepBNHeadModule(RTMDetHead):
Defaults to True.
use_depthwise (bool): Whether to use depthwise separable convolution in head.
Defaults to False.
- normalization (Callable[..., nn.Module]): Normalization layer module.
- Defaults to ``partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)``.
+ normalization (Callable[..., nn.Module] | None): Normalization layer module.
+ Defaults to ``None``.
activation (Callable[..., nn.Module]): Activation layer module.
Defaults to ``nn.SiLU``.
pred_kernel_size (int): Kernel size of prediction layer. Defaults to 1.
@@ -580,13 +583,16 @@ def __init__(
in_channels: int,
share_conv: bool = True,
use_depthwise: bool = False,
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001),
+ normalization: Callable[..., nn.Module] | None = None,
activation: Callable[..., nn.Module] = nn.SiLU,
pred_kernel_size: int = 1,
exp_on_reg: bool = False,
use_sigmoid_cls: bool = True,
**kwargs,
) -> None:
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)
+
self.share_conv = share_conv
self.exp_on_reg = exp_on_reg
self.use_depthwise = use_depthwise
@@ -675,7 +681,7 @@ def init_weights(self) -> None:
if is_norm(m):
constant_init(m, 1)
bias_cls = bias_init_with_prob(0.01)
- for rtm_cls, rtm_reg in zip(self.rtm_cls, self.rtm_reg):
+ for rtm_cls, rtm_reg in zip(self.rtm_cls, self.rtm_reg, strict=True):
normal_init(rtm_cls, std=0.01, bias=bias_cls)
normal_init(rtm_reg, std=0.01)
if self.with_objectness:
@@ -700,7 +706,7 @@ def forward(self, feats: tuple[Tensor, ...]) -> tuple:
"""
cls_scores = []
bbox_preds = []
- for idx, (x, stride) in enumerate(zip(feats, self.prior_generator.strides)):
+ for idx, (x, stride) in enumerate(zip(feats, self.prior_generator.strides, strict=True)):
cls_feat = x
reg_feat = x
diff --git a/src/otx/backend/native/models/detection/heads/ssd_head.py b/src/otx/backend/native/models/detection/heads/ssd_head.py
index 3d5b37a7a0..5f63b2b316 100644
--- a/src/otx/backend/native/models/detection/heads/ssd_head.py
+++ b/src/otx/backend/native/models/detection/heads/ssd_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -107,7 +107,7 @@ def forward(self, x: tuple[Tensor]) -> tuple[list[Tensor], list[Tensor]]:
"""
cls_scores = []
bbox_preds = []
- for feat, reg_conv, cls_conv in zip(x, self.reg_convs, self.cls_convs):
+ for feat, reg_conv, cls_conv in zip(x, self.reg_convs, self.cls_convs, strict=True):
cls_scores.append(cls_conv(feat))
bbox_preds.append(reg_conv(feat))
return cls_scores, bbox_preds
@@ -180,7 +180,7 @@ def _init_layers(self) -> None:
if isinstance(self.num_base_priors, int):
self.num_base_priors = [self.num_base_priors]
- for in_channel, num_base_priors in zip(self.in_channels, self.num_base_priors):
+ for in_channel, num_base_priors in zip(self.in_channels, self.num_base_priors, strict=True):
if self.use_depthwise:
activation_layer = nn.ReLU(inplace=True)
diff --git a/src/otx/backend/native/models/detection/heads/yolox_head.py b/src/otx/backend/native/models/detection/heads/yolox_head.py
index 90948666bf..fe7d6bc9a5 100644
--- a/src/otx/backend/native/models/detection/heads/yolox_head.py
+++ b/src/otx/backend/native/models/detection/heads/yolox_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -13,7 +13,7 @@
import logging
import math
from functools import partial
-from typing import Any, Callable, ClassVar, Sequence
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
import torch.nn.functional as F # noqa: N812
@@ -31,6 +31,9 @@
from otx.backend.native.models.utils.utils import InstanceData
from otx.data.entity.torch import OTXDataBatch
+if TYPE_CHECKING:
+ from collections.abc import Callable, Sequence
+
logger = logging.getLogger()
@@ -77,13 +80,16 @@ def __init__(
use_depthwise: bool = False,
dcn_on_last_conv: bool = False,
conv_bias: bool | str = "auto",
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001),
+ normalization: Callable[..., nn.Module] | None = None,
activation: Callable[..., nn.Module] = Swish,
train_cfg: dict | None = None,
test_cfg: dict | None = None,
init_cfg: dict | list[dict] | None = None,
use_sigmoid_cls: bool = True,
) -> None:
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)
+
if init_cfg is None:
init_cfg = {
"type": "Kaiming",
diff --git a/src/otx/backend/native/models/detection/layers/csp_layer.py b/src/otx/backend/native/models/detection/layers/csp_layer.py
index 0f869b6efc..5f69c91982 100644
--- a/src/otx/backend/native/models/detection/layers/csp_layer.py
+++ b/src/otx/backend/native/models/detection/layers/csp_layer.py
@@ -8,7 +8,7 @@
from __future__ import annotations
from functools import partial
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
from torch import Tensor, nn
@@ -19,6 +19,9 @@
from otx.backend.native.models.modules.conv_module import Conv2dModule, DepthwiseSeparableConvModule
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class DarknetBottleneck(BaseModule):
"""The basic bottleneck block used in Darknet.
@@ -50,12 +53,15 @@ def __init__(
expansion: float = 0.5,
add_identity: bool = True,
use_depthwise: bool = False,
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001),
+ normalization: Callable[..., nn.Module] | None = None,
activation: Callable[..., nn.Module] = Swish,
init_cfg: dict | list[dict] | None = None,
) -> None:
super().__init__(init_cfg=init_cfg)
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)
+
hidden_channels = int(out_channels * expansion)
conv = DepthwiseSeparableConvModule if use_depthwise else Conv2dModule
self.conv1 = Conv2dModule(
@@ -101,7 +107,7 @@ class CSPNeXtBlock(BaseModule):
kernel_size (int): The kernel size of the second convolution layer.
Defaults to 5.
normalization (Callable[..., nn.Module] | None): Normalization layer module.
- Defaults to ``partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)``.
+ Defaults to ``None``.
activation (Callable[..., nn.Module]): Activation layer module.
Defaults to ``nn.SiLU``.
init_cfg (dict or list[dict], optional): Initialization config dict.
@@ -116,12 +122,15 @@ def __init__(
add_identity: bool = True,
use_depthwise: bool = False,
kernel_size: int = 5,
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001),
+ normalization: Callable[..., nn.Module] | None = None,
activation: Callable[..., nn.Module] = nn.SiLU,
init_cfg: dict | list[dict] | None = None,
) -> None:
super().__init__(init_cfg=init_cfg)
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)
+
hidden_channels = int(out_channels * expansion)
conv = DepthwiseSeparableConvModule if use_depthwise else Conv2dModule
self.conv1 = conv(
@@ -269,12 +278,15 @@ def __init__(
use_depthwise: bool = False,
use_cspnext_block: bool = False,
channel_attention: bool = False,
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001),
+ normalization: Callable[..., nn.Module] | None = None,
activation: Callable[..., nn.Module] | None = Swish,
init_cfg: dict | list[dict] | None = None,
) -> None:
super().__init__(init_cfg=init_cfg)
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)
+
block = CSPNeXtBlock if use_cspnext_block else DarknetBottleneck
mid_channels = int(out_channels * expand_ratio)
self.channel_attention = channel_attention
diff --git a/src/otx/backend/native/models/detection/layers/elan_layer.py b/src/otx/backend/native/models/detection/layers/elan_layer.py
index cef1e13ac5..f2836b4a35 100644
--- a/src/otx/backend/native/models/detection/layers/elan_layer.py
+++ b/src/otx/backend/native/models/detection/layers/elan_layer.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""ELAN layers implementation for YOLOv7 and v9.
@@ -9,7 +9,7 @@
from __future__ import annotations
import logging
-from typing import Any, Callable
+from typing import TYPE_CHECKING, Any
import torch
from torch import Tensor, nn
@@ -17,6 +17,9 @@
from otx.backend.native.models.detection.utils.utils import auto_pad
from otx.backend.native.models.modules import Conv2dModule, build_activation_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
logger = logging.getLogger(__name__)
diff --git a/src/otx/backend/native/models/detection/losses/deim_loss.py b/src/otx/backend/native/models/detection/losses/deim_loss.py
index 531b7e0e1c..fb4842a9ce 100644
--- a/src/otx/backend/native/models/detection/losses/deim_loss.py
+++ b/src/otx/backend/native/models/detection/losses/deim_loss.py
@@ -5,7 +5,7 @@
from __future__ import annotations
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
import torch.nn.functional as f
@@ -16,6 +16,9 @@
from .dfine_loss import DFINECriterion
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class DEIMCriterion(DFINECriterion):
"""DEIM criterion for DEIM-DFine model."""
@@ -41,7 +44,7 @@ def loss_labels_mal(
idx = self._get_src_permutation_idx(indices)
src_boxes = outputs["pred_boxes"][idx]
- target_boxes = torch.cat([t["boxes"][i] for t, (_, i) in zip(targets, indices)], dim=0)
+ target_boxes = torch.cat([t["boxes"][i] for t, (_, i) in zip(targets, indices, strict=True)], dim=0)
ious = bbox_overlaps(
box_convert(src_boxes, in_fmt="cxcywh", out_fmt="xyxy"),
box_convert(target_boxes, in_fmt="cxcywh", out_fmt="xyxy"),
@@ -49,7 +52,7 @@ def loss_labels_mal(
ious = torch.diag(ious).detach()
src_logits = outputs["pred_logits"]
- target_classes_o = torch.cat([t["labels"][J] for t, (_, J) in zip(targets, indices)])
+ target_classes_o = torch.cat([t["labels"][J] for t, (_, J) in zip(targets, indices, strict=True)])
target_classes = torch.full(src_logits.shape[:2], self.num_classes, dtype=torch.int64, device=src_logits.device)
target_classes[idx] = target_classes_o
target = f.one_hot(target_classes, num_classes=self.num_classes + 1)[..., :-1]
diff --git a/src/otx/backend/native/models/detection/losses/dfine_loss.py b/src/otx/backend/native/models/detection/losses/dfine_loss.py
index 6d5f0bfbf4..6e8c9b777b 100644
--- a/src/otx/backend/native/models/detection/losses/dfine_loss.py
+++ b/src/otx/backend/native/models/detection/losses/dfine_loss.py
@@ -6,7 +6,7 @@
from __future__ import annotations
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
import torch.nn.functional as f
@@ -17,6 +17,9 @@
from otx.backend.native.models.common.utils.bbox_overlaps import bbox_overlaps
from otx.backend.native.models.detection.utils.utils import dfine_bbox2distance
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class DFINECriterion(nn.Module):
"""D-Fine criterion with FGL and DDF losses.
@@ -78,7 +81,7 @@ def loss_labels_vfl(
"""
idx = self._get_src_permutation_idx(indices)
src_boxes = outputs["pred_boxes"][idx]
- target_boxes = torch.cat([t["boxes"][i] for t, (_, i) in zip(targets, indices)], dim=0)
+ target_boxes = torch.cat([t["boxes"][i] for t, (_, i) in zip(targets, indices, strict=True)], dim=0)
ious = bbox_overlaps(
box_convert(src_boxes, in_fmt="cxcywh", out_fmt="xyxy"),
box_convert(target_boxes, in_fmt="cxcywh", out_fmt="xyxy"),
@@ -86,7 +89,7 @@ def loss_labels_vfl(
ious = torch.diag(ious).detach()
src_logits = outputs["pred_logits"]
- target_classes_o = torch.cat([t["labels"][J] for t, (_, J) in zip(targets, indices)])
+ target_classes_o = torch.cat([t["labels"][J] for t, (_, J) in zip(targets, indices, strict=True)])
target_classes = torch.full(src_logits.shape[:2], self.num_classes, dtype=torch.int64, device=src_logits.device)
target_classes[idx] = target_classes_o
target = f.one_hot(target_classes, num_classes=self.num_classes + 1)[..., :-1]
@@ -125,7 +128,7 @@ def loss_boxes(
"""
idx = self._get_src_permutation_idx(indices)
src_boxes = outputs["pred_boxes"][idx]
- target_boxes = torch.cat([t["boxes"][i] for t, (_, i) in zip(targets, indices)], dim=0)
+ target_boxes = torch.cat([t["boxes"][i] for t, (_, i) in zip(targets, indices, strict=True)], dim=0)
losses = {}
loss_bbox = f.l1_loss(src_boxes, target_boxes, reduction="none")
losses["loss_bbox"] = loss_bbox.sum() / num_boxes
@@ -165,7 +168,7 @@ def loss_local(
if "pred_corners" in outputs:
idx = self._get_src_permutation_idx(indices)
target_boxes = torch.cat(
- [t["boxes"][i] for t, (_, i) in zip(targets, indices)],
+ [t["boxes"][i] for t, (_, i) in zip(targets, indices, strict=True)],
dim=0,
)
@@ -263,7 +266,7 @@ def _get_go_indices(
for indices_aux in indices_aux_list:
indices = [
(torch.cat([idx1[0], idx2[0]]), torch.cat([idx1[1], idx2[1]]))
- for idx1, idx2 in zip(indices.copy(), indices_aux.copy())
+ for idx1, idx2 in zip(indices.copy(), indices_aux.copy(), strict=True)
]
for ind in [torch.cat([idx[0][:, None], idx[1][:, None]], 1) for idx in indices]:
diff --git a/src/otx/backend/native/models/detection/losses/rtdetr_loss.py b/src/otx/backend/native/models/detection/losses/rtdetr_loss.py
index ca313316be..105fdac859 100644
--- a/src/otx/backend/native/models/detection/losses/rtdetr_loss.py
+++ b/src/otx/backend/native/models/detection/losses/rtdetr_loss.py
@@ -1,11 +1,11 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""RT-Detr loss, modified from https://github.com/lyuwenyu/RT-DETR."""
from __future__ import annotations
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
from torch import nn
@@ -15,6 +15,9 @@
from otx.backend.native.models.common.utils.assigners.hungarian_matcher import HungarianMatcher
from otx.backend.native.models.common.utils.bbox_overlaps import bbox_overlaps
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class DetrCriterion(nn.Module):
"""This class computes the loss for DETR.
@@ -67,7 +70,7 @@ def loss_labels_vfl(
idx = self._get_src_permutation_idx(indices)
src_boxes = outputs["pred_boxes"][idx]
- target_boxes = torch.cat([t["boxes"][i] for t, (_, i) in zip(targets, indices)], dim=0)
+ target_boxes = torch.cat([t["boxes"][i] for t, (_, i) in zip(targets, indices, strict=True)], dim=0)
ious = bbox_overlaps(
box_convert(src_boxes, in_fmt="cxcywh", out_fmt="xyxy"),
box_convert(target_boxes, in_fmt="cxcywh", out_fmt="xyxy"),
@@ -75,7 +78,7 @@ def loss_labels_vfl(
ious = torch.diag(ious).detach()
src_logits = outputs["pred_logits"]
- target_classes_o = torch.cat([t["labels"][J] for t, (_, J) in zip(targets, indices)])
+ target_classes_o = torch.cat([t["labels"][J] for t, (_, J) in zip(targets, indices, strict=True)])
target_classes = torch.full(src_logits.shape[:2], self.num_classes, dtype=torch.int64, device=src_logits.device)
target_classes[idx] = target_classes_o.long()
target = nn.functional.one_hot(target_classes, num_classes=self.num_classes + 1)[..., :-1]
@@ -114,7 +117,7 @@ def loss_boxes(
"""
idx = self._get_src_permutation_idx(indices)
src_boxes = outputs["pred_boxes"][idx]
- target_boxes = torch.cat([t["boxes"][i] for t, (_, i) in zip(targets, indices)], dim=0)
+ target_boxes = torch.cat([t["boxes"][i] for t, (_, i) in zip(targets, indices, strict=True)], dim=0)
losses = {}
diff --git a/src/otx/backend/native/models/detection/necks/cspnext_pafpn.py b/src/otx/backend/native/models/detection/necks/cspnext_pafpn.py
index e7edc8388f..1a80ebbd31 100644
--- a/src/otx/backend/native/models/detection/necks/cspnext_pafpn.py
+++ b/src/otx/backend/native/models/detection/necks/cspnext_pafpn.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -14,7 +14,7 @@
import math
from functools import partial
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
from torch import Tensor, nn
@@ -25,6 +25,9 @@
from otx.backend.native.models.modules.conv_module import Conv2dModule, DepthwiseSeparableConvModule
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class CSPNeXtPAFPNModule(BaseModule):
"""Path Aggregation Network with CSPNeXt blocks.
@@ -37,7 +40,7 @@ class CSPNeXtPAFPNModule(BaseModule):
expand_ratio (float): Ratio to adjust the number of channels of the hidden layer. Default: 0.5
upsample_cfg (dict): Config dict for interpolate layer. Default: `dict(scale_factor=2, mode='nearest')`
normalization (Callable[..., nn.Module] | None): Normalization layer module.
- Defaults to ``partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)``.
+ Defaults to ``None``.
activation (Callable[..., nn.Module]): Activation layer module.
Defaults to ``Swish``.
init_cfg (dict or list[dict], optional): Initialization config dict. Default: None.
@@ -51,10 +54,13 @@ def __init__(
use_depthwise: bool = False,
expand_ratio: float = 0.5,
upsample_cfg: dict | None = None,
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001),
+ normalization: Callable[..., nn.Module] | None = None,
activation: Callable[..., nn.Module] = Swish,
init_cfg: dict | None = None,
) -> None:
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)
+
upsample_cfg = upsample_cfg or {"scale_factor": 2, "mode": "nearest"}
init_cfg = init_cfg or {
"type": "Kaiming",
diff --git a/src/otx/backend/native/models/detection/necks/dfine_hybrid_encoder.py b/src/otx/backend/native/models/detection/necks/dfine_hybrid_encoder.py
index 3a552c3267..2898e3d2d1 100644
--- a/src/otx/backend/native/models/detection/necks/dfine_hybrid_encoder.py
+++ b/src/otx/backend/native/models/detection/necks/dfine_hybrid_encoder.py
@@ -8,7 +8,7 @@
import copy
from collections import OrderedDict
from functools import partial
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
import torch.nn.functional as f
@@ -21,6 +21,9 @@
from otx.backend.native.models.modules.conv_module import Conv2dModule
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class SCDown(nn.Module):
"""SCDown downsampling module.
@@ -187,7 +190,7 @@ class HybridEncoderModule(nn.Module):
enc_activation (Callable[..., nn.Module]): Activation layer module.
Defaults to ``nn.GELU``.
normalization (Callable[..., nn.Module]): Normalization layer module.
- Defaults to ``partial(build_norm_layer, nn.BatchNorm2d, layer_name="norm")``.
+ Defaults to ``None``.
use_encoder_idx (list[int], optional): List of indices of the encoder to use.
Defaults to [2].
num_encoder_layers (int, optional): Number of layers in the transformer encoder.
@@ -213,7 +216,7 @@ def __init__(
dim_feedforward: int = 1024,
dropout: float = 0.0,
enc_activation: Callable[..., nn.Module] = nn.GELU,
- normalization: Callable[..., nn.Module] = partial(build_norm_layer, nn.BatchNorm2d, layer_name="norm"),
+ normalization: Callable[..., nn.Module] | None = None,
use_encoder_idx: list[int] = [2], # noqa: B006
num_encoder_layers: int = 1,
pe_temperature: int = 10000,
@@ -260,6 +263,9 @@ def __init__(
[TransformerEncoder(copy.deepcopy(encoder_layer), num_encoder_layers) for _ in range(len(use_encoder_idx))],
)
+ if normalization is None:
+ normalization = partial(build_norm_layer, nn.BatchNorm2d, layer_name="norm")
+
# top-down fpn
self.lateral_convs = nn.ModuleList()
self.fpn_blocks = nn.ModuleList()
diff --git a/src/otx/backend/native/models/detection/necks/fpn.py b/src/otx/backend/native/models/detection/necks/fpn.py
index bfe67a6c3b..e2fe9c8c9a 100644
--- a/src/otx/backend/native/models/detection/necks/fpn.py
+++ b/src/otx/backend/native/models/detection/necks/fpn.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -12,7 +12,7 @@
from __future__ import annotations
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
from torch import Tensor, nn
@@ -21,6 +21,9 @@
from otx.backend.native.models.modules.conv_module import Conv2dModule
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class FPNModule(BaseModule):
r"""Feature Pyramid Network.
diff --git a/src/otx/backend/native/models/detection/necks/hybrid_encoder.py b/src/otx/backend/native/models/detection/necks/hybrid_encoder.py
index c4862bc818..2a76a41039 100644
--- a/src/otx/backend/native/models/detection/necks/hybrid_encoder.py
+++ b/src/otx/backend/native/models/detection/necks/hybrid_encoder.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Hybrid Encoder module for detection task, modified from https://github.com/lyuwenyu/RT-DETR."""
@@ -7,7 +7,7 @@
import copy
from functools import partial
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
from torch import nn
@@ -18,6 +18,9 @@
from otx.backend.native.models.modules.base_module import BaseModule
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
__all__ = ["HybridEncoder"]
@@ -38,7 +41,7 @@ class HybridEncoderModule(BaseModule):
enc_activation (Callable[..., nn.Module]): Activation layer module.
Defaults to ``nn.GELU``.
normalization (Callable[..., nn.Module]): Normalization layer module.
- Defaults to ``partial(build_norm_layer, nn.BatchNorm2d, layer_name="norm")``.
+ Defaults to ``None``.
use_encoder_idx (list[int], optional): List of indices of the encoder to use.
Defaults to [2].
num_encoder_layers (int, optional): Number of layers in the transformer encoder.
@@ -64,7 +67,7 @@ def __init__(
dim_feedforward: int = 1024,
dropout: float = 0.0,
enc_activation: Callable[..., nn.Module] = nn.GELU,
- normalization: Callable[..., nn.Module] = partial(build_norm_layer, nn.BatchNorm2d, layer_name="norm"),
+ normalization: Callable[..., nn.Module] | None = None,
use_encoder_idx: list[int] = [2], # noqa: B006
num_encoder_layers: int = 1,
pe_temperature: float = 10000,
@@ -95,6 +98,9 @@ def __init__(
),
)
+ if normalization is None:
+ normalization = partial(build_norm_layer, nn.BatchNorm2d, layer_name="norm")
+
# encoder transformer
encoder_layer = TransformerEncoderLayer(
hidden_dim,
diff --git a/src/otx/backend/native/models/detection/necks/yolox_pafpn.py b/src/otx/backend/native/models/detection/necks/yolox_pafpn.py
index 226b3775ee..6946a31911 100644
--- a/src/otx/backend/native/models/detection/necks/yolox_pafpn.py
+++ b/src/otx/backend/native/models/detection/necks/yolox_pafpn.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -12,7 +12,7 @@
import math
from functools import partial
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
from torch import Tensor, nn
@@ -23,6 +23,9 @@
from otx.backend.native.models.modules.conv_module import Conv2dModule, DepthwiseSeparableConvModule
from otx.backend.native.models.modules.norm import build_norm_layer
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class YOLOXPAFPNModule(BaseModule):
"""Path Aggregation Network used in YOLOX.
@@ -50,10 +53,13 @@ def __init__(
num_csp_blocks: int = 3,
use_depthwise: bool = False,
upsample_cfg: dict | None = None,
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001),
+ normalization: Callable[..., nn.Module] | None = None,
activation: Callable[..., nn.Module] = Swish,
init_cfg: dict | list[dict] | None = None,
):
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, momentum=0.03, eps=0.001)
+
upsample_cfg = upsample_cfg or {"scale_factor": 2, "mode": "nearest"}
init_cfg = init_cfg or {
"type": "Kaiming",
diff --git a/src/otx/backend/native/models/detection/rtdetr.py b/src/otx/backend/native/models/detection/rtdetr.py
index a5ac56b83e..a3c24d00f3 100644
--- a/src/otx/backend/native/models/detection/rtdetr.py
+++ b/src/otx/backend/native/models/detection/rtdetr.py
@@ -132,7 +132,7 @@ def _customize_inputs(
targets: list[dict[str, Any]] = []
# prepare bboxes for the model
if entity.bboxes is not None and entity.labels is not None:
- for bb, ll in zip(entity.bboxes, entity.labels):
+ for bb, ll in zip(entity.bboxes, entity.labels, strict=True):
# convert to cxcywh if needed
if len(scaled_bboxes := bb):
converted_bboxes = (
diff --git a/src/otx/backend/native/models/detection/utils/assigners/atss_assigner.py b/src/otx/backend/native/models/detection/utils/assigners/atss_assigner.py
index c2e1450740..b3bad77c43 100644
--- a/src/otx/backend/native/models/detection/utils/assigners/atss_assigner.py
+++ b/src/otx/backend/native/models/detection/utils/assigners/atss_assigner.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -11,7 +11,7 @@
from __future__ import annotations
import warnings
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
import torch
from torch import Tensor
@@ -20,6 +20,8 @@
from otx.backend.native.models.common.utils.structures import AssignResult
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from otx.backend.native.models.utils.utils import InstanceData
diff --git a/src/otx/backend/native/models/detection/utils/assigners/sim_ota_assigner.py b/src/otx/backend/native/models/detection/utils/assigners/sim_ota_assigner.py
index 90e492295c..5a0265bc4b 100644
--- a/src/otx/backend/native/models/detection/utils/assigners/sim_ota_assigner.py
+++ b/src/otx/backend/native/models/detection/utils/assigners/sim_ota_assigner.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -10,7 +10,7 @@
from __future__ import annotations
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
import torch
import torch.nn.functional as F # noqa: N812
@@ -20,6 +20,8 @@
from otx.backend.native.models.common.utils.structures import AssignResult
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from otx.backend.native.models.utils.utils import InstanceData
INF = 100000.0
diff --git a/src/otx/backend/native/models/detection/utils/prior_generators/anchor_generator.py b/src/otx/backend/native/models/detection/utils/prior_generators/anchor_generator.py
index 4999617148..ef4bdf5549 100644
--- a/src/otx/backend/native/models/detection/utils/prior_generators/anchor_generator.py
+++ b/src/otx/backend/native/models/detection/utils/prior_generators/anchor_generator.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023-2024 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -44,7 +44,7 @@ def __init__(
def gen_base_anchors(self) -> None: # type: ignore[override]
"""Generate base anchor for SSD."""
multi_level_base_anchors = []
- for widths, heights, centers in zip(self.widths, self.heights, self.centers):
+ for widths, heights, centers in zip(self.widths, self.heights, self.centers, strict=True):
base_anchors = self.gen_single_level_base_anchors(
widths=Tensor(widths),
heights=Tensor(heights),
diff --git a/src/otx/backend/native/models/instance_segmentation/backbones/swin.py b/src/otx/backend/native/models/instance_segmentation/backbones/swin.py
index 8f340a112b..8350862aa4 100644
--- a/src/otx/backend/native/models/instance_segmentation/backbones/swin.py
+++ b/src/otx/backend/native/models/instance_segmentation/backbones/swin.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -14,7 +14,7 @@
from collections import OrderedDict
from copy import deepcopy
from pathlib import Path
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
import torch.nn.functional
@@ -28,6 +28,9 @@
from otx.backend.native.models.utils.utils import load_from_http
from otx.backend.native.models.utils.weight_init import constant_init, trunc_normal_, trunc_normal_init
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
# ruff: noqa: PLR0913
diff --git a/src/otx/backend/native/models/instance_segmentation/base.py b/src/otx/backend/native/models/instance_segmentation/base.py
index 905f25fe62..f8a2636607 100644
--- a/src/otx/backend/native/models/instance_segmentation/base.py
+++ b/src/otx/backend/native/models/instance_segmentation/base.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023-2024 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Class definition for instance segmentation model entity used in OTX."""
@@ -10,7 +10,7 @@
import copy
import types
from contextlib import contextmanager
-from typing import TYPE_CHECKING, Any, Callable, Iterator, Literal
+from typing import TYPE_CHECKING, Any, Literal
import torch
from torch import Tensor
@@ -39,6 +39,8 @@
from otx.types.task import OTXTaskType
if TYPE_CHECKING:
+ from collections.abc import Callable, Iterator
+
from lightning.pytorch.cli import LRSchedulerCallable, OptimizerCallable
from torch import nn
@@ -136,7 +138,7 @@ def _customize_outputs(
masks: list[tv_tensors.Mask] = []
predictions = outputs["predictions"] if isinstance(outputs, dict) else outputs
- for img_info, prediction in zip(inputs.imgs_info, predictions): # type: ignore[arg-type]
+ for img_info, prediction in zip(inputs.imgs_info, predictions, strict=True): # type: ignore[arg-type]
scores.append(prediction.scores)
bboxes.append(
tv_tensors.BoundingBoxes(
@@ -406,7 +408,7 @@ def _forward_explain_inst_seg(
# Export case, consists of tensors
# For OV task saliency map are generated on MAPI side
saliency_map = torch.empty(1, dtype=torch.uint8)
- elif isinstance(predictions, list) and isinstance(predictions[0], (InstanceData, dict)):
+ elif isinstance(predictions, list) and isinstance(predictions[0], (InstanceData | dict)):
# Predict case, consists of InstanceData or dict
saliency_map = self.explain_fn(predictions)
else:
diff --git a/src/otx/backend/native/models/instance_segmentation/heads/bbox_head.py b/src/otx/backend/native/models/instance_segmentation/heads/bbox_head.py
index b8cd0c7d1d..17ea4bfb25 100644
--- a/src/otx/backend/native/models/instance_segmentation/heads/bbox_head.py
+++ b/src/otx/backend/native/models/instance_segmentation/heads/bbox_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -11,7 +11,7 @@
from __future__ import annotations
import warnings
-from typing import TYPE_CHECKING, Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
import torch.nn.functional
@@ -31,6 +31,8 @@
from otx.backend.native.models.utils.utils import InstanceData
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from otx.backend.native.models.common.utils.coders import DeltaXYWHBBoxCoder
diff --git a/src/otx/backend/native/models/instance_segmentation/heads/fcn_mask_head.py b/src/otx/backend/native/models/instance_segmentation/heads/fcn_mask_head.py
index cde6a9830c..ca16501404 100644
--- a/src/otx/backend/native/models/instance_segmentation/heads/fcn_mask_head.py
+++ b/src/otx/backend/native/models/instance_segmentation/heads/fcn_mask_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -11,7 +11,7 @@
from __future__ import annotations
import warnings
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
import numpy as np
import torch
@@ -32,6 +32,8 @@
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from otx.backend.native.models.utils.utils import InstanceData
diff --git a/src/otx/backend/native/models/instance_segmentation/heads/roi_head_tv.py b/src/otx/backend/native/models/instance_segmentation/heads/roi_head_tv.py
index f6da5ac719..6267a7da83 100644
--- a/src/otx/backend/native/models/instance_segmentation/heads/roi_head_tv.py
+++ b/src/otx/backend/native/models/instance_segmentation/heads/roi_head_tv.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Customised torchvision RoIHeads class with support for polygons as ground truth masks."""
@@ -37,7 +37,7 @@ def maskrcnn_loss(
image_shapes (list[tuple[int, int]]): the image shapes.
"""
meta_infos = [{"img_shape": img_shape} for img_shape in image_shapes]
- labels = [gt_label[idxs] for gt_label, idxs in zip(gt_labels, mask_matched_idxs)]
+ labels = [gt_label[idxs] for gt_label, idxs in zip(gt_labels, mask_matched_idxs, strict=True)]
mask_targets = mask_target(
proposals,
@@ -157,7 +157,7 @@ def forward(
else:
labels = [r["labels"] for r in result]
masks_probs = maskrcnn_inference(mask_logits, labels)
- for mask_prob, r in zip(masks_probs, result):
+ for mask_prob, r in zip(masks_probs, result, strict=True):
r["masks"] = mask_prob
losses.update(loss_mask)
diff --git a/src/otx/backend/native/models/instance_segmentation/heads/rpn_head.py b/src/otx/backend/native/models/instance_segmentation/heads/rpn_head.py
index c11860e648..97a3d1e3de 100644
--- a/src/otx/backend/native/models/instance_segmentation/heads/rpn_head.py
+++ b/src/otx/backend/native/models/instance_segmentation/heads/rpn_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023-2024 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -293,7 +293,9 @@ def _predict_by_feat_single( # type: ignore[override]
mlvl_valid_priors = []
mlvl_scores = []
level_ids = []
- for level_idx, (cls_score, bbox_pred, priors) in enumerate(zip(cls_score_list, bbox_pred_list, mlvl_priors)):
+ for level_idx, (cls_score, bbox_pred, priors) in enumerate(
+ zip(cls_score_list, bbox_pred_list, mlvl_priors, strict=True),
+ ):
if cls_score.size()[-2:] != bbox_pred.size()[-2:]:
msg = "cls_score and bbox_pred should have the same size"
raise RuntimeError(msg)
@@ -439,6 +441,7 @@ def export_by_feat(
mlvl_cls_scores,
mlvl_bbox_preds,
mlvl_anchors,
+ strict=True,
):
if cls_score.size()[-2:] != bbox_pred.size()[-2:]:
msg = "cls_score and bbox_pred should have the same size"
diff --git a/src/otx/backend/native/models/instance_segmentation/heads/rtmdet_inst_head.py b/src/otx/backend/native/models/instance_segmentation/heads/rtmdet_inst_head.py
index a12a55b7f2..97f262cdb8 100644
--- a/src/otx/backend/native/models/instance_segmentation/heads/rtmdet_inst_head.py
+++ b/src/otx/backend/native/models/instance_segmentation/heads/rtmdet_inst_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -13,7 +13,7 @@
import copy
import math
from functools import partial
-from typing import Callable
+from typing import TYPE_CHECKING
import numpy as np
import torch
@@ -44,6 +44,9 @@
from .utils import sigmoid_geometric_mean
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
# mypy: disable-error-code="call-overload, index, override, attr-defined, misc"
@@ -156,7 +159,7 @@ def forward(self, feats: tuple[Tensor, ...]) -> tuple:
cls_scores = []
bbox_preds = []
kernel_preds = []
- for x, scale, stride in zip(feats, self.scales, self.prior_generator.strides):
+ for x, scale, stride in zip(feats, self.scales, self.prior_generator.strides, strict=True):
cls_feat = x
reg_feat = x
kernel_feat = x
@@ -263,6 +266,7 @@ def _predict_by_feat_single(
bbox_pred_list,
kernel_pred_list,
mlvl_priors,
+ strict=True,
):
if cls_score.size()[-2:] != bbox_pred.size()[-2:]:
msg = "The spatial sizes of cls_score and bbox_pred should be the same."
@@ -527,7 +531,7 @@ def _mask_predict_by_feat_single(self, mask_feat: Tensor, kernels: Tensor, prior
n_layers = len(weights)
x = mask_feat.reshape(1, -1, h, w)
- for i, (weight, bias) in enumerate(zip(weights, biases)):
+ for i, (weight, bias) in enumerate(zip(weights, biases, strict=True)):
x = torch.nn.functional.conv2d(x, weight, bias=bias, stride=1, padding=0, groups=num_inst)
if i < n_layers - 1:
x = torch.nn.functional.relu(x)
@@ -563,6 +567,7 @@ def prepare_mask_loss_inputs(
flatten_kernels,
sampling_results_list,
batch_gt_instances,
+ strict=True,
):
pos_priors = sampling_results.pos_priors
pos_inds = sampling_results.pos_inds
@@ -645,7 +650,7 @@ def prepare_loss_inputs(self, x: tuple[Tensor], entity: OTXDataBatch) -> dict:
# Convert polygon masks to bitmap masks
if isinstance(batch_gt_instances[0].masks[0], Polygon):
- for gt_instances, img_meta in zip(batch_gt_instances, batch_img_metas):
+ for gt_instances, img_meta in zip(batch_gt_instances, batch_img_metas, strict=True):
ndarray_masks = polygon_to_bitmap(gt_instances.masks, *img_meta["img_shape"])
if len(ndarray_masks) == 0:
ndarray_masks = np.empty((0, *img_meta["img_shape"]), dtype=np.uint8)
@@ -667,7 +672,7 @@ def prepare_loss_inputs(self, x: tuple[Tensor], entity: OTXDataBatch) -> dict:
1,
)
decoded_bboxes = []
- for anchor, bbox_pred in zip(anchor_list[0], bbox_preds):
+ for anchor, bbox_pred in zip(anchor_list[0], bbox_preds, strict=True):
anchor = anchor.reshape(-1, 4) # noqa: PLW2901
bbox_pred = bbox_pred.permute(0, 2, 3, 1).reshape(num_imgs, -1, 4) # noqa: PLW2901
bbox_pred = distance2bbox(anchor, bbox_pred) # noqa: PLW2901
@@ -728,9 +733,9 @@ class MaskFeatModule(BaseModule):
kernel.
stacked_convs (int): Number of convs in mask feature branch.
activation (Callable[..., nn.Module]): Activation layer module.
- Defaults to ``partial(nn.ReLU, inplace=True)``.
+ Defaults to ``None``.
normalization (Callable[..., nn.Module] | None): Normalization layer module.
- Defaults to ``nn.BatchNorm2d``.
+ Defaults to ``None``.
"""
def __init__(
@@ -740,11 +745,17 @@ def __init__(
stacked_convs: int = 4,
num_levels: int = 3,
num_prototypes: int = 8,
- activation: Callable[..., nn.Module] = partial(nn.ReLU, inplace=True),
- normalization: Callable[..., nn.Module] = nn.BatchNorm2d,
+ activation: Callable[..., nn.Module] | None = None,
+ normalization: Callable[..., nn.Module] | None = None,
) -> None:
super().__init__(init_cfg=None)
+ if activation is None:
+ activation = partial(nn.ReLU, inplace=True)
+
+ if normalization is None:
+ normalization = nn.BatchNorm2d
+
self.num_levels = num_levels
self.fusion_conv = nn.Conv2d(num_levels * in_channels, in_channels, 1)
convs = []
@@ -788,9 +799,9 @@ class RTMDetInstSepBNHead(RTMDetInstHead):
share_conv (bool): Whether to share conv layers between stages.
Defaults to True.
normalization (Callable[..., nn.Module]): Normalization layer module.
- Defaults to ``partial(nn.BatchNorm2d, requires_grad=True)``.
+ Defaults to ``None``.
activation (Callable[..., nn.Module]): Activation layer module.
- Defaults to ``partial(nn.SiLU, inplace=True)``.
+ Defaults to ``None``.
pred_kernel_size (int): Kernel size of prediction layer. Defaults to 1.
use_sigmoid_cls (bool): Whether to use a sigmoid activation function
for classification prediction. Defaults to True.
@@ -802,12 +813,18 @@ def __init__(
in_channels: int,
share_conv: bool = True,
with_objectness: bool = False,
- normalization: Callable[..., nn.Module] = partial(nn.BatchNorm2d, requires_grad=True),
- activation: Callable[..., nn.Module] = partial(nn.SiLU, inplace=True),
+ normalization: Callable[..., nn.Module] | None = None,
+ activation: Callable[..., nn.Module] | None = None,
pred_kernel_size: int = 1,
use_sigmoid_cls: bool = True,
**kwargs,
) -> None:
+ if normalization is None:
+ normalization = partial(nn.BatchNorm2d, requires_grad=True)
+
+ if activation is None:
+ activation = partial(nn.SiLU, inplace=True)
+
self.share_conv = share_conv
super().__init__(
num_classes,
@@ -939,7 +956,7 @@ def init_weights(self) -> None:
if is_norm(m):
constant_init(m, 1)
bias_cls = bias_init_with_prob(0.01)
- for rtm_cls, rtm_reg in zip(self.rtm_cls, self.rtm_reg):
+ for rtm_cls, rtm_reg in zip(self.rtm_cls, self.rtm_reg, strict=True):
normal_init(rtm_cls, std=0.01, bias=bias_cls)
normal_init(rtm_reg, std=0.01, bias=1)
if self.with_objectness:
@@ -972,7 +989,7 @@ def forward(self, feats: tuple[Tensor, ...]) -> tuple:
cls_scores = []
bbox_preds = []
kernel_preds = []
- for idx, (x, stride) in enumerate(zip(feats, self.prior_generator.strides)):
+ for idx, (x, stride) in enumerate(zip(feats, self.prior_generator.strides, strict=True)):
cls_feat = x
reg_feat = x
kernel_feat = x
@@ -1160,7 +1177,7 @@ def export_mask_predict_by_feat_single(
n_layers = len(weights)
x = mask_feat.flatten(0, 1).flatten(2)
- for i, (weight, bias) in enumerate(zip(weights, biases)):
+ for i, (weight, bias) in enumerate(zip(weights, biases, strict=True)):
# replace dynamic conv with bmm
weight = weight.flatten(0, 1) # noqa: PLW2901
bias = bias.flatten(0, 1).unsqueeze(2) # noqa: PLW2901
diff --git a/src/otx/backend/native/models/instance_segmentation/losses/accuracy.py b/src/otx/backend/native/models/instance_segmentation/losses/accuracy.py
index 07fdd053a1..ebe22fd638 100644
--- a/src/otx/backend/native/models/instance_segmentation/losses/accuracy.py
+++ b/src/otx/backend/native/models/instance_segmentation/losses/accuracy.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -40,7 +40,7 @@ def accuracy(
function will return a tuple containing accuracies of
each ``topk`` number.
"""
- if not isinstance(topk, (int, tuple)):
+ if not isinstance(topk, (int | tuple)):
msg = f"topk must be int or tuple of int, got {type(topk)}"
raise TypeError(msg)
if isinstance(topk, int):
diff --git a/src/otx/backend/native/models/instance_segmentation/maskrcnn.py b/src/otx/backend/native/models/instance_segmentation/maskrcnn.py
index 9de70fbdd3..4af73e887d 100644
--- a/src/otx/backend/native/models/instance_segmentation/maskrcnn.py
+++ b/src/otx/backend/native/models/instance_segmentation/maskrcnn.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""MaskRCNN model implementations."""
@@ -416,6 +416,7 @@ def predict_step(self, *args: torch.Any, **kwargs: torch.Any) -> OTXPredBatch:
for field_name, field in zip(
["imgs_info", "bboxes", "scores", "labels", "masks"],
[preds.imgs_info, preds.bboxes, preds.scores, preds.labels, preds.masks],
+ strict=True,
):
if field is None:
msg = f"Field '{field_name}' is None, which is not allowed."
@@ -427,6 +428,7 @@ def predict_step(self, *args: torch.Any, **kwargs: torch.Any) -> OTXPredBatch:
preds.scores, # type: ignore[arg-type]
preds.labels, # type: ignore[arg-type]
preds.masks, # type: ignore[arg-type]
+ strict=True,
):
boxes = []
scores = []
@@ -434,7 +436,7 @@ def predict_step(self, *args: torch.Any, **kwargs: torch.Any) -> OTXPredBatch:
masks = []
polygons = []
- for bbox, score, label, mask in zip(pred_bboxes, pred_scores, pred_labels, pred_masks):
+ for bbox, score, label, mask in zip(pred_bboxes, pred_scores, pred_labels, pred_masks, strict=True):
if mask.sum() == 0:
continue
np_mask = mask.detach().cpu().numpy().astype(int)
@@ -442,7 +444,7 @@ def predict_step(self, *args: torch.Any, **kwargs: torch.Any) -> OTXPredBatch:
if hierarchies is None:
continue
rbox_polygons = []
- for contour, hierarchy in zip(contours, hierarchies[0]):
+ for contour, hierarchy in zip(contours, hierarchies[0], strict=True):
# skip inner contours
if hierarchy[3] != -1 or len(contour) <= 2:
continue
diff --git a/src/otx/backend/native/models/instance_segmentation/maskrcnn_tv.py b/src/otx/backend/native/models/instance_segmentation/maskrcnn_tv.py
index d8765b7593..e2701dfc59 100644
--- a/src/otx/backend/native/models/instance_segmentation/maskrcnn_tv.py
+++ b/src/otx/backend/native/models/instance_segmentation/maskrcnn_tv.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""TV MaskRCNN model implementations."""
@@ -180,7 +180,7 @@ def _customize_outputs(
# XAI wraps prediction under dictionary with key "predictions"
predictions = outputs["predictions"] if isinstance(outputs, dict) else outputs
- for img_info, prediction in zip(inputs.imgs_info, predictions): # type: ignore[arg-type]
+ for img_info, prediction in zip(inputs.imgs_info, predictions, strict=True): # type: ignore[arg-type]
scores.append(prediction["scores"])
bboxes.append(
tv_tensors.BoundingBoxes(
diff --git a/src/otx/backend/native/models/instance_segmentation/segmentors/maskrcnn_tv.py b/src/otx/backend/native/models/instance_segmentation/segmentors/maskrcnn_tv.py
index feda0ce63d..bfabeae66e 100644
--- a/src/otx/backend/native/models/instance_segmentation/segmentors/maskrcnn_tv.py
+++ b/src/otx/backend/native/models/instance_segmentation/segmentors/maskrcnn_tv.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Torchvision MaskRCNN model with forward method accepting TorchDataBatch."""
@@ -88,7 +88,7 @@ def postprocess(
mask_thr_binary: float = 0.5,
) -> list[dict[str, Tensor]]:
"""Postprocess the output of the model."""
- for i, (pred, scale_factor, ori_shape) in enumerate(zip(result, scale_factors, ori_shapes)):
+ for i, (pred, scale_factor, ori_shape) in enumerate(zip(result, scale_factors, ori_shapes, strict=True)):
boxes = pred["boxes"]
labels = pred["labels"]
scores = pred["scores"]
diff --git a/src/otx/backend/native/models/instance_segmentation/utils/utils.py b/src/otx/backend/native/models/instance_segmentation/utils/utils.py
index 3487e5662a..767861b165 100644
--- a/src/otx/backend/native/models/instance_segmentation/utils/utils.py
+++ b/src/otx/backend/native/models/instance_segmentation/utils/utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Instance Segmentation Utilities."""
@@ -6,7 +6,7 @@
from __future__ import annotations
from dataclasses import dataclass
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
from torch import Tensor
@@ -15,6 +15,9 @@
from otx.backend.native.models.utils.utils import InstanceData
from otx.data.entity.torch import OTXDataBatch
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
def unpack_inst_seg_entity(entity: OTXDataBatch) -> tuple:
"""Unpack gt_instances, gt_instances_ignore and img_metas based on batch_data_samples.
diff --git a/src/otx/backend/native/models/keypoint_detection/base.py b/src/otx/backend/native/models/keypoint_detection/base.py
index da5216984a..0bcb440f9f 100644
--- a/src/otx/backend/native/models/keypoint_detection/base.py
+++ b/src/otx/backend/native/models/keypoint_detection/base.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Class definition for keypoint detection model entity used in OTX."""
@@ -153,7 +153,7 @@ def _convert_pred_entity_to_compute_metric( # type: ignore[override]
"keypoints": kpt[:, :2],
"scores": score,
}
- for kpt, score in zip(preds.keypoints, preds.scores)
+ for kpt, score in zip(preds.keypoints, preds.scores, strict=True)
],
"target": [
{
diff --git a/src/otx/backend/native/models/keypoint_detection/heads/rtmcc_head.py b/src/otx/backend/native/models/keypoint_detection/heads/rtmcc_head.py
index 4239be85ec..5c2bc4777a 100644
--- a/src/otx/backend/native/models/keypoint_detection/heads/rtmcc_head.py
+++ b/src/otx/backend/native/models/keypoint_detection/heads/rtmcc_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -73,7 +73,7 @@ def __init__(
self.loss_module = loss
self.codec = SimCCLabel(**decoder_cfg)
- if isinstance(in_channels, (tuple, list)):
+ if isinstance(in_channels, (tuple | list)):
msg = f"{self.__class__.__name__} does not support selecting multiple input features."
raise TypeError(msg)
@@ -146,7 +146,7 @@ def predict(
)
preds = []
- for keypoints, scores in zip(batch_keypoints, batch_scores):
+ for keypoints, scores in zip(batch_keypoints, batch_scores, strict=True):
preds.append((keypoints, scores))
return preds
diff --git a/src/otx/backend/native/models/keypoint_detection/losses/kl_discret_loss.py b/src/otx/backend/native/models/keypoint_detection/losses/kl_discret_loss.py
index a9f42b864b..c17334d767 100644
--- a/src/otx/backend/native/models/keypoint_detection/losses/kl_discret_loss.py
+++ b/src/otx/backend/native/models/keypoint_detection/losses/kl_discret_loss.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -79,7 +79,7 @@ def forward(
loss = 0
weight = target_weight.reshape(-1) if self.use_target_weight else 1.0
- for pred, target in zip(pred_simcc, gt_simcc):
+ for pred, target in zip(pred_simcc, gt_simcc, strict=True):
_pred = pred.reshape(-1, pred.size(-1))
_target = target.reshape(-1, target.size(-1))
diff --git a/src/otx/backend/native/models/keypoint_detection/utils/simcc_label.py b/src/otx/backend/native/models/keypoint_detection/utils/simcc_label.py
index e752cbc3ab..29ba9a24b8 100644
--- a/src/otx/backend/native/models/keypoint_detection/utils/simcc_label.py
+++ b/src/otx/backend/native/models/keypoint_detection/utils/simcc_label.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -81,7 +81,7 @@ def __init__(
self.decode_scores = decode_scores
self.decode_beta = decode_beta
- if isinstance(sigma, (float, int)):
+ if isinstance(sigma, (float | int)):
self.sigma = np.array([sigma, sigma])
else:
self.sigma = np.array(sigma)
diff --git a/src/otx/backend/native/models/modules/activation.py b/src/otx/backend/native/models/modules/activation.py
index eff125fcaa..bc7cf59d78 100644
--- a/src/otx/backend/native/models/modules/activation.py
+++ b/src/otx/backend/native/models/modules/activation.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -8,11 +8,14 @@
from __future__ import annotations
from functools import partial
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
from torch import Tensor, nn
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class Swish(nn.Module):
"""Swish Module.
diff --git a/src/otx/backend/native/models/modules/base_module.py b/src/otx/backend/native/models/modules/base_module.py
index 87f8c7e568..d574ac7292 100644
--- a/src/otx/backend/native/models/modules/base_module.py
+++ b/src/otx/backend/native/models/modules/base_module.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -12,12 +12,15 @@
from abc import ABCMeta
from collections import defaultdict
from logging import FileHandler
-from typing import Iterable
+from typing import TYPE_CHECKING
from torch import nn
from otx.backend.native.models.utils.weight_init import PretrainedInit, initialize, update_init_info
+if TYPE_CHECKING:
+ from collections.abc import Iterable
+
logger = logging.getLogger()
diff --git a/src/otx/backend/native/models/modules/conv_module.py b/src/otx/backend/native/models/modules/conv_module.py
index d7d0bdb4f1..925af44ba9 100644
--- a/src/otx/backend/native/models/modules/conv_module.py
+++ b/src/otx/backend/native/models/modules/conv_module.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -12,7 +12,7 @@
import operator
import warnings
from copy import deepcopy
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
from torch import Tensor, nn
from torch.nn.modules.batchnorm import _BatchNorm as BatchNorm
@@ -25,6 +25,8 @@
from .padding import build_padding_layer
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from torch.nn.modules.conv import _ConvNd as ConvNd
@@ -145,7 +147,7 @@ def __init__(
self.norm_name = infer_abbr(norm.__class__)
self.add_module(self.norm_name, norm)
- if self.with_bias and isinstance(norm, (BatchNorm, InstanceNorm)):
+ if self.with_bias and isinstance(norm, (BatchNorm | InstanceNorm)):
warnings.warn("Unnecessary conv bias before batch/instance norm", stacklevel=1)
# build activation layer
@@ -366,7 +368,7 @@ def hook(grad_x: Tensor) -> Tensor:
# If the stride is equal to 1 for a dimension of size 1 (condition which triggers the bug),
# set the stride based on the expected one that we calculated above to workaround the problem.
- new_stride = [cst if sz == 1 and st == 1 else st for cst, st, sz in zip(calc_stride, stride, size)]
+ new_stride = [cst if sz == 1 and st == 1 else st for cst, st, sz in zip(calc_stride, stride, size, strict=True)]
return grad_x.as_strided(size, new_stride)
if x.requires_grad:
diff --git a/src/otx/backend/native/models/modules/norm.py b/src/otx/backend/native/models/modules/norm.py
index 54e922d868..f97831f59c 100644
--- a/src/otx/backend/native/models/modules/norm.py
+++ b/src/otx/backend/native/models/modules/norm.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -9,7 +9,7 @@
import inspect
from functools import partial
-from typing import Any, Callable
+from typing import TYPE_CHECKING, Any
import torch
from torch import nn
@@ -17,6 +17,9 @@
from torch.nn.modules.batchnorm import _BatchNorm
from torch.nn.modules.instancenorm import _InstanceNorm
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class FrozenBatchNorm2d(nn.Module):
"""Copy and modified from https://github.com/facebookresearch/detr/blob/master/models/backbone.py.
diff --git a/src/otx/backend/native/models/modules/transformer.py b/src/otx/backend/native/models/modules/transformer.py
index 5436dc3cde..bf06114549 100644
--- a/src/otx/backend/native/models/modules/transformer.py
+++ b/src/otx/backend/native/models/modules/transformer.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -8,8 +8,8 @@
from __future__ import annotations
import math
+from collections.abc import Callable, Sequence
from functools import partial
-from typing import Callable, Sequence
import torch
from timm.layers import to_2tuple
@@ -254,7 +254,7 @@ class FFN(BaseModule):
num_fcs (int, optional): The number of fully-connected layers in
FFNs. Default: 2.
activation (Callable[..., nn.Module]): Activation layer module.
- Defaults to ``partial(nn.ReLU, inplace=True)``.
+ Defaults to ``None``.
ffn_drop (float, optional): Probability of an element to be
zeroed in FFN. Default 0.0.
add_identity (bool, optional): Whether to add the
@@ -270,13 +270,16 @@ def __init__(
embed_dims: int = 256,
feedforward_channels: int = 1024,
num_fcs: int = 2,
- activation: Callable[..., nn.Module] = partial(nn.ReLU, inplace=True),
+ activation: Callable[..., nn.Module] | None = None,
ffn_drop: float = 0.0,
dropout_layer: dict | None = None,
add_identity: bool = True,
init_cfg: dict | None = None,
):
super().__init__(init_cfg)
+ if activation is None:
+ activation = partial(nn.ReLU, inplace=True)
+
if num_fcs < 2:
msg = "The number of fully-connected layers in FFNs should be at least 2."
raise ValueError(msg)
diff --git a/src/otx/backend/native/models/segmentation/backbones/litehrnet.py b/src/otx/backend/native/models/segmentation/backbones/litehrnet.py
index 9986ed12c8..9b8ee387e7 100644
--- a/src/otx/backend/native/models/segmentation/backbones/litehrnet.py
+++ b/src/otx/backend/native/models/segmentation/backbones/litehrnet.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023-2024 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""HRNet network modules for base backbone.
@@ -11,7 +11,7 @@
from functools import partial
from pathlib import Path
-from typing import Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
import torch.utils.checkpoint as cp
@@ -24,6 +24,9 @@
)
from otx.backend.native.models.utils.utils import load_checkpoint_to_model, load_from_http
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class NeighbourSupport(nn.Module):
"""Neighbour support module.
@@ -179,7 +182,7 @@ def forward(self, x: torch.Tensor) -> list[torch.Tensor]:
out = self.conv2(out)
out = torch.split(out, self.channels, dim=1)
- return [s * functional.interpolate(a, size=s.size()[-2:], mode="nearest") for s, a in zip(x, out)]
+ return [s * functional.interpolate(a, size=s.size()[-2:], mode="nearest") for s, a in zip(x, out, strict=True)]
class SpatialWeighting(nn.Module):
@@ -478,17 +481,17 @@ def _inner_forward(self, x: torch.Tensor) -> list[torch.Tensor]:
x2 = [s[1] for s in x]
x2 = self.cross_resolution_weighting(x2)
- x2 = [dw(s) for s, dw in zip(x2, self.depthwise_convs)]
+ x2 = [dw(s) for s, dw in zip(x2, self.depthwise_convs, strict=True)]
if self.neighbour_weighting is not None:
- x2 = [nw(s) for s, nw in zip(x2, self.neighbour_weighting)]
+ x2 = [nw(s) for s, nw in zip(x2, self.neighbour_weighting, strict=True)]
- x2 = [sw(s) for s, sw in zip(x2, self.spatial_weighting)]
+ x2 = [sw(s) for s, sw in zip(x2, self.spatial_weighting, strict=True)]
if self.dropout is not None:
- x2 = [dropout(s) for s, dropout in zip(x2, self.dropout)]
+ x2 = [dropout(s) for s, dropout in zip(x2, self.dropout, strict=True)]
- out = [torch.cat([s1, s2], dim=1) for s1, s2 in zip(x1, x2)]
+ out = [torch.cat([s1, s2], dim=1) for s1, s2 in zip(x1, x2, strict=True)]
return [channel_shuffle(s, 2) for s in out]
@@ -524,7 +527,7 @@ def __init__(
stem_channels: int = 32,
out_channels: int = 32,
expand_ratio: int = 1,
- normalization: Callable[..., nn.Module] = partial(build_norm_layer, nn.BatchNorm2d, requires_grad=True),
+ normalization: Callable[..., nn.Module] | None = None,
with_cp: bool = False,
strides: tuple[int, int] = (2, 2),
extra_stride: bool = False,
@@ -533,7 +536,10 @@ def __init__(
"""Stem initialization."""
super().__init__()
- if not isinstance(strides, (tuple, list)):
+ if normalization is None:
+ normalization = partial(build_norm_layer, nn.BatchNorm2d, requires_grad=True)
+
+ if not isinstance(strides, (tuple | list)):
msg = "strides must be tuple or list."
raise TypeError(msg)
if len(strides) != 2:
@@ -1017,8 +1023,8 @@ class LiteHRNetModule(nn.Module):
Args:
extra (dict): detailed configuration for each stage of HRNet.
in_channels (int): Number of input image channels. Default: 3.
- normalization (Callable[..., nn.Module]): Normalization layer module.
- Defaults to ``nn.BatchNorm2d``.
+ normalization (Callable[..., nn.Module] | None): Normalization layer module.
+ Defaults to ``None``.
norm_eval (bool): Whether to set norm layers to eval mode, namely,
freeze running stats (mean and var). Note: Effect on Batch Norm
and its variants only. Default: False
@@ -1034,7 +1040,7 @@ def __init__(
stem_configuration: dict[str, Any],
stages_spec: dict[str, Any],
in_channels: int = 3,
- normalization: Callable[..., nn.Module] = partial(build_norm_layer, nn.BatchNorm2d, requires_grad=True),
+ normalization: Callable[..., nn.Module] | None = None,
norm_eval: bool = False,
with_cp: bool = False,
zero_init_residual: bool = False,
@@ -1044,6 +1050,9 @@ def __init__(
"""Init."""
super().__init__()
+ if normalization is None:
+ normalization = partial(build_norm_layer, nn.BatchNorm2d, requires_grad=True)
+
self.normalization = normalization
self.norm_eval = norm_eval
self.with_cp = with_cp
diff --git a/src/otx/backend/native/models/segmentation/backbones/mscan.py b/src/otx/backend/native/models/segmentation/backbones/mscan.py
index 53b5ed069f..7721dfc6ce 100644
--- a/src/otx/backend/native/models/segmentation/backbones/mscan.py
+++ b/src/otx/backend/native/models/segmentation/backbones/mscan.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023-2024 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""MSCAN backbone for SegNext model."""
@@ -7,7 +7,7 @@
from functools import partial
from pathlib import Path
-from typing import TYPE_CHECKING, Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
from torch import nn
@@ -18,6 +18,8 @@
from otx.backend.native.models.utils.utils import load_checkpoint_to_model, load_from_http
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from torch import Tensor
@@ -109,7 +111,7 @@ class StemConv(BaseModule):
activation (Callable[..., nn.Module]): Activation layer module.
Defaults to ``nn.GELU``.
normalization (Callable[..., nn.Module]): Normalization layer module.
- Defaults to ``partial(build_norm_layer, SyncBatchNorm, requires_grad=True)``.
+ Defaults to ``None``.
"""
def __init__(
@@ -117,8 +119,11 @@ def __init__(
in_channels: int,
out_channels: int,
activation: Callable[..., nn.Module] = nn.GELU,
- normalization: Callable[..., nn.Module] = partial(build_norm_layer, SyncBatchNorm, requires_grad=True),
+ normalization: Callable[..., nn.Module] | None = None,
) -> None:
+ if normalization is None:
+ normalization = partial(build_norm_layer, SyncBatchNorm, requires_grad=True)
+
super().__init__()
self.proj = nn.Sequential(
nn.Conv2d(in_channels, out_channels // 2, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1)),
@@ -157,11 +162,11 @@ def __init__(
"""
super().__init__()
self.conv0 = nn.Conv2d(channels, channels, kernel_size=kernel_sizes[0], padding=paddings[0], groups=channels)
- for i, (kernel_size, padding) in enumerate(zip(kernel_sizes[1:], paddings[1:])):
+ for i, (kernel_size, padding) in enumerate(zip(kernel_sizes[1:], paddings[1:], strict=True)):
kernel_size_ = [kernel_size, kernel_size[::-1]]
padding_ = [padding, padding[::-1]]
conv_name = [f"conv{i}_1", f"conv{i}_2"]
- for i_kernel, i_pad, i_conv in zip(kernel_size_, padding_, conv_name):
+ for i_kernel, i_pad, i_conv in zip(kernel_size_, padding_, conv_name, strict=True):
self.add_module(i_conv, nn.Conv2d(channels, channels, tuple(i_kernel), padding=i_pad, groups=channels))
self.conv3 = nn.Conv2d(channels, channels, 1)
@@ -255,9 +260,12 @@ def __init__(
drop: float = 0.0,
drop_path: float = 0.0,
activation: Callable[..., nn.Module] = nn.GELU,
- normalization: Callable[..., nn.Module] = partial(build_norm_layer, SyncBatchNorm, requires_grad=True),
+ normalization: Callable[..., nn.Module] | None = None,
) -> None:
"""Initialize a MSCABlock."""
+ if normalization is None:
+ normalization = partial(build_norm_layer, SyncBatchNorm, requires_grad=True)
+
super().__init__()
self.norm1 = build_norm_layer(normalization, num_features=channels)[1] # type: nn.Module
self.attn = MSCASpatialAttention(
@@ -306,9 +314,12 @@ def __init__(
stride: int = 4,
in_channels: int = 3,
embed_dim: int = 768,
- normalization: Callable[..., nn.Module] = partial(build_norm_layer, SyncBatchNorm, requires_grad=True),
+ normalization: Callable[..., nn.Module] | None = None,
):
"""Initializes the OverlapPatchEmbed module."""
+ if normalization is None:
+ normalization = partial(build_norm_layer, SyncBatchNorm, requires_grad=True)
+
super().__init__()
self.proj = nn.Conv2d(in_channels, embed_dim, kernel_size=patch_size, stride=stride, padding=patch_size // 2)
self.norm = build_norm_layer(normalization, num_features=embed_dim)[1]
@@ -347,7 +358,7 @@ class MSCANModule(nn.Module):
activation (Callable[..., nn.Module]): Activation layer module.
Defaults to ``nn.GELU``.
normalization (Callable[..., nn.Module]): Normalization layer module.
- Defaults to ``partial(build_norm_layer, SyncBatchNorm, requires_grad=True)``.
+ Defaults to ``None``.
init_cfg (Optional[Union[Dict[str, str], List[Dict[str, str]]]]): Initialization config dict.
Defaults to None.
"""
@@ -364,11 +375,14 @@ def __init__(
attention_kernel_sizes: list[int | list[int]] = [5, [1, 7], [1, 11], [1, 21]], # noqa: B006
attention_kernel_paddings: list[int | list[int]] = [2, [0, 3], [0, 5], [0, 10]], # noqa: B006
activation: Callable[..., nn.Module] = nn.GELU,
- normalization: Callable[..., nn.Module] = partial(build_norm_layer, nn.BatchNorm2d, requires_grad=True),
+ normalization: Callable[..., nn.Module] | None = None,
pretrained_weights: str | None = None,
) -> None:
"""Initialize a MSCAN backbone."""
super().__init__()
+ if normalization is None:
+ normalization = partial(build_norm_layer, nn.BatchNorm2d, requires_grad=True)
+
self.depths = depths
self.num_stages = num_stages
diff --git a/src/otx/backend/native/models/segmentation/base.py b/src/otx/backend/native/models/segmentation/base.py
index ec809dddc1..6fddd8d55c 100644
--- a/src/otx/backend/native/models/segmentation/base.py
+++ b/src/otx/backend/native/models/segmentation/base.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023-2024 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Class definition for detection model entity used in OTX."""
@@ -182,7 +182,7 @@ def _convert_pred_entity_to_compute_metric(
"preds": pred_mask,
"target": target_mask,
}
- for pred_mask, target_mask in zip(preds.masks, inputs.masks)
+ for pred_mask, target_mask in zip(preds.masks, inputs.masks, strict=True)
]
@staticmethod
diff --git a/src/otx/backend/native/models/segmentation/heads/base_segm_head.py b/src/otx/backend/native/models/segmentation/heads/base_segm_head.py
index 259707cbcf..144da4dd13 100644
--- a/src/otx/backend/native/models/segmentation/heads/base_segm_head.py
+++ b/src/otx/backend/native/models/segmentation/heads/base_segm_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Base head for OTX segmentation models."""
@@ -7,7 +7,7 @@
from abc import abstractmethod
from pathlib import Path
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
from torch import nn
@@ -15,6 +15,9 @@
from otx.backend.native.models.segmentation.modules import resize
from otx.backend.native.models.utils.utils import load_checkpoint_to_model, load_from_http
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class BaseSegmentationHead(nn.Module):
"""Base class for segmentation heads.
diff --git a/src/otx/backend/native/models/segmentation/heads/fcn_head.py b/src/otx/backend/native/models/segmentation/heads/fcn_head.py
index 6093ef0048..1db710c105 100644
--- a/src/otx/backend/native/models/segmentation/heads/fcn_head.py
+++ b/src/otx/backend/native/models/segmentation/heads/fcn_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Custom FCNHead modules for OTX segmentation model."""
@@ -6,7 +6,7 @@
from __future__ import annotations
from functools import partial
-from typing import TYPE_CHECKING, Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
from torch import Tensor, nn
@@ -18,6 +18,7 @@
from .base_segm_head import BaseSegmentationHead
if TYPE_CHECKING:
+ from collections.abc import Callable
from pathlib import Path
@@ -28,7 +29,7 @@ class FCNHeadModule(BaseSegmentationHead):
Args:
normalization (Callable[..., nn.Module] | None): Normalization layer module.
- Defaults to None.
+ Defaults to ``None``.
num_convs (int): Number of convs in the head. Default: 2.
kernel_size (int): The kernel size for convs in the head. Default: 3.
concat_input (bool): Whether concat the input and output of convs
@@ -41,7 +42,7 @@ def __init__(
in_channels: list[int] | int,
in_index: list[int] | int,
channels: int,
- normalization: Callable[..., nn.Module] = partial(build_norm_layer, nn.BatchNorm2d, requires_grad=True),
+ normalization: Callable[..., nn.Module] | None = None,
input_transform: str | None = None,
num_classes: int = 80,
num_convs: int = 1,
@@ -58,6 +59,9 @@ def __init__(
pretrained_weights: Path | str | None = None,
) -> None:
"""Initialize a Fully Convolution Networks head."""
+ if normalization is None:
+ normalization = partial(build_norm_layer, nn.BatchNorm2d, requires_grad=True)
+
if not isinstance(dilation, int):
msg = f"dilation should be int, but got {type(dilation)}"
raise TypeError(msg)
diff --git a/src/otx/backend/native/models/segmentation/heads/ham_head.py b/src/otx/backend/native/models/segmentation/heads/ham_head.py
index e522290fc3..7bbe4fb1db 100644
--- a/src/otx/backend/native/models/segmentation/heads/ham_head.py
+++ b/src/otx/backend/native/models/segmentation/heads/ham_head.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Implementation of HamburgerNet head."""
@@ -6,7 +6,7 @@
from __future__ import annotations
from functools import partial
-from typing import TYPE_CHECKING, Any, Callable, ClassVar
+from typing import TYPE_CHECKING, Any, ClassVar
import torch
import torch.nn.functional as f
@@ -19,6 +19,7 @@
from .base_segm_head import BaseSegmentationHead
if TYPE_CHECKING:
+ from collections.abc import Callable
from pathlib import Path
@@ -75,12 +76,7 @@ def __init__(
channels: int,
num_classes: int,
dropout_ratio: float = 0.1,
- normalization: Callable[..., nn.Module] | None = partial(
- build_norm_layer,
- nn.GroupNorm,
- num_groups=32,
- requires_grad=True,
- ),
+ normalization: Callable[..., nn.Module] | None = None,
activation: Callable[..., nn.Module] | None = nn.ReLU,
in_index: int | list[int] = [1, 2, 3], # noqa: B006
input_transform: str | None = "multiple_select",
@@ -109,6 +105,14 @@ def __init__(
Returns:
None
"""
+ if normalization is None:
+ normalization = partial(
+ build_norm_layer,
+ nn.GroupNorm,
+ num_groups=32,
+ requires_grad=True,
+ )
+
super().__init__(
input_transform=input_transform,
in_channels=in_channels,
diff --git a/src/otx/backend/native/models/segmentation/modules/aggregators.py b/src/otx/backend/native/models/segmentation/modules/aggregators.py
index 3e5f0b42e5..951374492a 100644
--- a/src/otx/backend/native/models/segmentation/modules/aggregators.py
+++ b/src/otx/backend/native/models/segmentation/modules/aggregators.py
@@ -1,11 +1,11 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Aggregators for semantic segmentation."""
from __future__ import annotations
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
from torch import nn
@@ -16,6 +16,9 @@
from .utils import normalize
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class IterativeAggregator(nn.Module):
"""IterativeAggregator.
diff --git a/src/otx/backend/native/models/segmentation/modules/blocks.py b/src/otx/backend/native/models/segmentation/modules/blocks.py
index e3aafb030c..be455ca943 100644
--- a/src/otx/backend/native/models/segmentation/modules/blocks.py
+++ b/src/otx/backend/native/models/segmentation/modules/blocks.py
@@ -1,14 +1,17 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Blocks/modules for semantic segmentation."""
from __future__ import annotations
-from typing import Callable
+from typing import TYPE_CHECKING
import torch
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
class OnnxLpNormalization(torch.autograd.Function):
"""OnnxLpNormalization."""
diff --git a/src/otx/backend/native/models/utils/utils.py b/src/otx/backend/native/models/utils/utils.py
index 4e6169a926..cdb897f0bf 100644
--- a/src/otx/backend/native/models/utils/utils.py
+++ b/src/otx/backend/native/models/utils/utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Utility functions for OTX algo."""
@@ -10,7 +10,7 @@
import re
from collections import OrderedDict, abc, namedtuple
from pathlib import Path
-from typing import Any, Callable, Iterator, Sequence, Union
+from typing import TYPE_CHECKING, Any
from warnings import warn
import numpy as np
@@ -19,9 +19,8 @@
from torch import nn
from torch.utils.model_zoo import load_url
-BoolTypeTensor = Union[torch.BoolTensor, torch.cuda.BoolTensor]
-LongTypeTensor = Union[torch.LongTensor, torch.cuda.LongTensor]
-IndexType = Union[str, slice, int, list, LongTypeTensor, BoolTypeTensor, np.ndarray]
+if TYPE_CHECKING:
+ from collections.abc import Callable, Iterator, Sequence
def _torch_hub_model_reduce(self) -> tuple[Callable, tuple]: # noqa: ANN001
@@ -436,7 +435,18 @@ def __setattr__(self, name: str, value: Any): # noqa: ANN401
__setitem__ = __setattr__
- def __getitem__(self, item: IndexType) -> InstanceData:
+ def __getitem__(
+ self,
+ item: str
+ | slice
+ | int
+ | list
+ | torch.LongTensor
+ | torch.cuda.LongTensor
+ | torch.BoolTensor
+ | torch.cuda.BoolTensor
+ | np.ndarray,
+ ) -> InstanceData:
"""Get item mehod.
Args:
@@ -473,9 +483,9 @@ def __getitem__(self, item: IndexType) -> InstanceData:
new_data[k] = v[item]
elif isinstance(v, np.ndarray):
new_data[k] = v[item.cpu().numpy()]
- elif isinstance(v, (str, list, tuple)) or (hasattr(v, "__getitem__") and hasattr(v, "cat")):
+ elif isinstance(v, (str | list | tuple)) or (hasattr(v, "__getitem__") and hasattr(v, "cat")):
# convert to indexes from BoolTensor
- if isinstance(item, BoolTypeTensor.__args__): # type: ignore[attr-defined]
+ if isinstance(item, torch.BoolTensor | torch.cuda.BoolTensor.__args__): # type: ignore[attr-defined]
indexes = torch.nonzero(item).view(-1).cpu().numpy().tolist()
else:
indexes = item.cpu().numpy().tolist()
@@ -486,7 +496,7 @@ def __getitem__(self, item: IndexType) -> InstanceData:
else:
slice_list.append(slice(None, 0, None))
r_list = [v[s] for s in slice_list]
- if isinstance(v, (str, list, tuple)):
+ if isinstance(v, (str | list | tuple)):
new_value = r_list[0]
for r in r_list[1:]:
new_value = new_value + r
@@ -592,7 +602,7 @@ def cpu(self) -> InstanceData:
"""Convert all tensors to CPU in data."""
new_data = self.new()
for k, v in self.items():
- if isinstance(v, (torch.Tensor, InstanceData)):
+ if isinstance(v, (torch.Tensor | InstanceData)):
v = v.cpu() # noqa: PLW2901
data = {k: v}
new_data.set_data(data)
@@ -603,7 +613,7 @@ def cuda(self) -> InstanceData:
"""Convert all tensors to GPU in data."""
new_data = self.new()
for k, v in self.items():
- if isinstance(v, (torch.Tensor, InstanceData)):
+ if isinstance(v, (torch.Tensor | InstanceData)):
v = v.cuda() # noqa: PLW2901
data = {k: v}
new_data.set_data(data)
@@ -614,7 +624,7 @@ def detach(self) -> InstanceData:
"""Detach all tensors in data."""
new_data = self.new()
for k, v in self.items():
- if isinstance(v, (torch.Tensor, InstanceData)):
+ if isinstance(v, (torch.Tensor | InstanceData)):
v = v.detach() # noqa: PLW2901
data = {k: v}
new_data.set_data(data)
@@ -625,7 +635,7 @@ def numpy(self) -> InstanceData:
"""Convert all tensors to np.ndarray in data."""
new_data = self.new()
for k, v in self.items():
- if isinstance(v, (torch.Tensor, InstanceData)):
+ if isinstance(v, (torch.Tensor | InstanceData)):
v = v.detach().cpu().numpy() # noqa: PLW2901
data = {k: v}
new_data.set_data(data)
diff --git a/src/otx/backend/native/models/utils/weight_init.py b/src/otx/backend/native/models/utils/weight_init.py
index b2551cb693..b80388e60a 100644
--- a/src/otx/backend/native/models/utils/weight_init.py
+++ b/src/otx/backend/native/models/utils/weight_init.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -194,7 +194,7 @@ class BaseInit:
def __init__(self, *, bias: int | float = 0, bias_prob: float | None = None, layer: str | list | None = None):
self.wholemodule = False
- if not isinstance(bias, (int, float)):
+ if not isinstance(bias, (int | float)):
msg = f"bias must be a number, but got a {type(bias)}"
raise TypeError(msg)
@@ -204,7 +204,7 @@ def __init__(self, *, bias: int | float = 0, bias_prob: float | None = None, lay
raise TypeError(msg)
if layer is not None:
- if not isinstance(layer, (str, list)):
+ if not isinstance(layer, (str | list)):
msg = f"layer must be a str or a list of str, \
but got a {type(layer)}"
raise TypeError(msg)
@@ -603,7 +603,7 @@ def _initialize(module: nn.Module, cfg: dict, wholemodule: bool = False) -> None
def _initialize_override(module: nn.Module, override: dict | list[dict], cfg: dict) -> None:
- if not isinstance(override, (dict, list)):
+ if not isinstance(override, (dict | list)):
msg = f"override must be a dict or a list of dict, \
but got {type(override)}"
raise TypeError(msg)
@@ -677,7 +677,7 @@ def initialize(module: nn.Module, init_cfg: dict | list[dict]) -> None:
>>> init_cfg = dict(type='Pretrained',
checkpoint=url, prefix='backbone.')
"""
- if not isinstance(init_cfg, (dict, list)):
+ if not isinstance(init_cfg, (dict | list)):
msg = f"init_cfg must be a dict or a list of dict, \
but got {type(init_cfg)}"
raise TypeError(msg)
diff --git a/src/otx/backend/native/models/utils/xai_utils.py b/src/otx/backend/native/models/utils/xai_utils.py
index a3e31240ec..dfdf739729 100644
--- a/src/otx/backend/native/models/utils/xai_utils.py
+++ b/src/otx/backend/native/models/utils/xai_utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Utils used for XAI."""
@@ -62,7 +62,7 @@ def _process(
conf_thr = explain_config.predicted_maps_conf_thr
pred_labels = []
- for labels, scores in zip(predict_result_per_batch.labels, predict_result_per_batch.scores): # type: ignore[union-attr, arg-type]
+ for labels, scores in zip(predict_result_per_batch.labels, predict_result_per_batch.scores, strict=True): # type: ignore[union-attr, arg-type]
if isinstance(label_info, HLabelInfo):
pred_labels.append(_convert_labels_from_hcls_format(labels, scores, label_info, conf_thr))
elif labels.shape == scores.shape: # type: ignore[union-attr, attr-defined]
diff --git a/src/otx/backend/native/schedulers/__init__.py b/src/otx/backend/native/schedulers/__init__.py
index d7aaa67e7f..f8c4d1f645 100644
--- a/src/otx/backend/native/schedulers/__init__.py
+++ b/src/otx/backend/native/schedulers/__init__.py
@@ -1,11 +1,11 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Custom schedulers for the OTX2.0."""
from __future__ import annotations
-from typing import Callable
+from collections.abc import Callable
from lightning.pytorch.cli import ReduceLROnPlateau
from torch.optim.lr_scheduler import LRScheduler
diff --git a/src/otx/backend/native/tools/adaptive_bs/algorithm.py b/src/otx/backend/native/tools/adaptive_bs/algorithm.py
index cb58d9c04d..5ad72371e3 100644
--- a/src/otx/backend/native/tools/adaptive_bs/algorithm.py
+++ b/src/otx/backend/native/tools/adaptive_bs/algorithm.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Algorithm to find a proper batch size which is fit to current device."""
@@ -8,12 +8,15 @@
import logging
import multiprocessing as mp
import queue
-from typing import Any, Callable
+from typing import TYPE_CHECKING, Any
import torch
from otx.utils.device import is_xpu_available
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
logger = logging.getLogger(__name__)
diff --git a/src/otx/backend/native/tools/explain/explain_algo.py b/src/otx/backend/native/tools/explain/explain_algo.py
index c06654d7e2..6c8ae16788 100644
--- a/src/otx/backend/native/tools/explain/explain_algo.py
+++ b/src/otx/backend/native/tools/explain/explain_algo.py
@@ -1,11 +1,12 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Algorithms for calculcalating XAI branch for Explainable AI."""
from __future__ import annotations
-from typing import TYPE_CHECKING, Callable
+from collections.abc import Callable
+from typing import TYPE_CHECKING
import torch
@@ -23,7 +24,7 @@
def feature_vector_fn(feature_map: FeatureMapType) -> torch.Tensor:
"""Generate the feature vector by average pooling feature maps."""
- if isinstance(feature_map, (list, tuple, dict)):
+ if isinstance(feature_map, (list | tuple | dict)):
if isinstance(feature_map, dict):
feature_map = list(feature_map.values())
@@ -87,7 +88,7 @@ class ActivationMap(BaseExplainAlgo):
def func(self, feature_map: FeatureMapType, fpn_idx: int = -1) -> torch.Tensor:
"""Generate the saliency map by average feature maps then normalizing to (0, 255)."""
- if isinstance(feature_map, (list, tuple)):
+ if isinstance(feature_map, (list | tuple)):
feature_map = feature_map[fpn_idx]
batch_size, _, h, w = feature_map.size()
@@ -129,7 +130,7 @@ def func(self, feature_map: FeatureMapType, fpn_idx: int = -1) -> torch.Tensor:
Returns:
torch.Tensor: Class-wise Saliency Maps. One saliency map per each class - [batch, class_id, H, W]
"""
- if isinstance(feature_map, (list, tuple)):
+ if isinstance(feature_map, (list | tuple)):
feature_map = feature_map[fpn_idx]
batch_size, channel, h, w = feature_map.size()
@@ -370,7 +371,7 @@ def average_and_normalize(
saliency_map = torch.zeros((num_classes, height, width), dtype=torch.float32, device=labels.device)
class_objects = [0 for _ in range(num_classes)]
- for confidence, class_ind, raw_mask in zip(scores, labels, masks):
+ for confidence, class_ind, raw_mask in zip(scores, labels, masks, strict=True):
weighted_mask = raw_mask * confidence
saliency_map[class_ind] += weighted_mask
class_objects[class_ind] += 1
diff --git a/src/otx/backend/native/tools/tile_merge.py b/src/otx/backend/native/tools/tile_merge.py
index 1ee91356dc..d7b91b7438 100644
--- a/src/otx/backend/native/tools/tile_merge.py
+++ b/src/otx/backend/native/tools/tile_merge.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""OTX tile merge module."""
@@ -7,7 +7,7 @@
from abc import abstractmethod
from collections import defaultdict
-from typing import Callable
+from typing import TYPE_CHECKING
import cv2
import numpy as np
@@ -20,6 +20,9 @@
from otx.config.data import TileConfig
from otx.data.entity import ImageInfo, OTXPredBatch, OTXPredItem
+if TYPE_CHECKING:
+ from collections.abc import Callable
+
# Maximum number of elements 2**31 -1
MAX_ELEMENTS: int = np.iinfo(np.int32).max
@@ -523,7 +526,7 @@ def merge(
img_ids = []
explain_mode = self.explain_mode
- for tile_preds, tile_attrs in zip(batch_tile_preds, batch_tile_attrs):
+ for tile_preds, tile_attrs in zip(batch_tile_preds, batch_tile_attrs, strict=True):
batch_size = tile_preds.batch_size
saliency_maps = tile_preds.saliency_map if explain_mode else [[] for _ in range(batch_size)]
feature_vectors = tile_preds.feature_vector if explain_mode else [[] for _ in range(batch_size)]
@@ -543,6 +546,7 @@ def merge(
tile_preds.masks,
saliency_maps,
feature_vectors,
+ strict=True,
):
if tile_img_info is None:
msg = f"Image information is not provided : {tile_preds.imgs_info}."
@@ -566,7 +570,7 @@ def merge(
return [
self._merge_entities(image_info, entities_to_merge[img_id], explain_mode)
- for img_id, image_info in zip(img_ids, self.img_infos)
+ for img_id, image_info in zip(img_ids, self.img_infos, strict=True)
]
def _merge_entities(
diff --git a/src/otx/backend/native/utils/utils.py b/src/otx/backend/native/utils/utils.py
index bb22678ade..c1c587909f 100644
--- a/src/otx/backend/native/utils/utils.py
+++ b/src/otx/backend/native/utils/utils.py
@@ -8,7 +8,7 @@
import importlib
from collections import defaultdict
from multiprocessing import cpu_count
-from typing import TYPE_CHECKING, Any
+from typing import TYPE_CHECKING, Any, TypeVar
import torch
from datumaro.components.annotation import AnnotationType, LabelCategories
@@ -16,10 +16,10 @@
from otx.utils.device import is_xpu_available
if TYPE_CHECKING:
- from datumaro import Dataset as DmDataset
+ from collections.abc import Callable
+ from datumaro import Dataset as DmDataset
-from typing import Callable, TypeVar
_T = TypeVar("_T")
_V = TypeVar("_V")
diff --git a/src/otx/backend/openvino/engine.py b/src/otx/backend/openvino/engine.py
index 110cd0e2b5..eb78a6e706 100644
--- a/src/otx/backend/openvino/engine.py
+++ b/src/otx/backend/openvino/engine.py
@@ -52,13 +52,13 @@ def __init__(
work_dir (PathLike, optional): Working directory for the engine. Defaults to "./otx-workspace".
"""
self._work_dir = work_dir
- if isinstance(model, (str, os.PathLike)) and Path(model).suffix in [".xml"]:
+ if isinstance(model, (str | os.PathLike)) and Path(model).suffix in [".xml"]:
task: OTXTaskType | None = self._derive_task_from_ir(model)
elif isinstance(model, OVModel):
task = model.task # type: ignore[assignment]
self._auto_configurator = AutoConfigurator(
- data_root=data if isinstance(data, (str, os.PathLike)) else None,
+ data_root=data if isinstance(data, (str | os.PathLike)) else None,
task=task,
)
@@ -171,7 +171,7 @@ def test(
RuntimeError: If required data or metric is not provided.
ValueError: If label information between model and datamodule does not match.
"""
- if isinstance(data, (str, os.PathLike)):
+ if isinstance(data, (str | os.PathLike)):
datamodule = self._auto_configurator.get_datamodule(data_root=data)
elif isinstance(data, OTXDataModule):
datamodule = data
@@ -276,7 +276,7 @@ def predict(
)
model = self._update_checkpoint(checkpoint)
- if isinstance(data, (str, os.PathLike)):
+ if isinstance(data, (str | os.PathLike)):
data = self._auto_configurator.get_datamodule(data_root=data)
datamodule = data or self.datamodule
@@ -377,12 +377,12 @@ def is_supported(model: MODEL, data: DATA) -> bool:
check_data = False
if isinstance(model, OVModel):
check_model = True
- elif isinstance(model, (str, os.PathLike)):
+ elif isinstance(model, (str | os.PathLike)):
model_path = Path(model)
check_model = model_path.suffix in [".xml"]
if isinstance(data, OTXDataModule):
check_data = True
- elif isinstance(data, (str, os.PathLike)):
+ elif isinstance(data, (str | os.PathLike)):
data_path = Path(data)
check_data = data_path.is_dir()
diff --git a/src/otx/backend/openvino/models/detection.py b/src/otx/backend/openvino/models/detection.py
index b83232189a..28d3039be4 100644
--- a/src/otx/backend/openvino/models/detection.py
+++ b/src/otx/backend/openvino/models/detection.py
@@ -232,14 +232,14 @@ def prepare_metric_inputs(
"scores": scores,
"labels": labels,
}
- for bboxes, scores, labels in zip(preds.bboxes, preds.scores, preds.labels) # type: ignore[arg-type]
+ for bboxes, scores, labels in zip(preds.bboxes, preds.scores, preds.labels, strict=True) # type: ignore[arg-type]
],
"target": [
{
"boxes": bboxes.data,
"labels": labels,
}
- for bboxes, labels in zip(inputs.bboxes, inputs.labels) # type: ignore[arg-type]
+ for bboxes, labels in zip(inputs.bboxes, inputs.labels, strict=True) # type: ignore[arg-type]
],
}
diff --git a/src/otx/backend/openvino/models/keypoint_detection.py b/src/otx/backend/openvino/models/keypoint_detection.py
index 78f34ffd02..ab5a23af5e 100644
--- a/src/otx/backend/openvino/models/keypoint_detection.py
+++ b/src/otx/backend/openvino/models/keypoint_detection.py
@@ -147,7 +147,7 @@ def prepare_metric_inputs( # type: ignore[override]
"keypoints": kpt[:, :2],
"scores": score,
}
- for kpt, score in zip(preds.keypoints, preds.scores)
+ for kpt, score in zip(preds.keypoints, preds.scores, strict=True)
],
"target": [
{
diff --git a/src/otx/backend/openvino/models/segmentation.py b/src/otx/backend/openvino/models/segmentation.py
index 6764bf2df8..7655ee6c5b 100644
--- a/src/otx/backend/openvino/models/segmentation.py
+++ b/src/otx/backend/openvino/models/segmentation.py
@@ -142,7 +142,7 @@ def prepare_metric_inputs(
"preds": pred_mask,
"target": target_mask,
}
- for pred_mask, target_mask in zip(preds.masks, inputs.masks)
+ for pred_mask, target_mask in zip(preds.masks, inputs.masks, strict=True)
]
def _create_label_info_from_ov_ir(self) -> SegLabelInfo:
diff --git a/src/otx/cli/cli.py b/src/otx/cli/cli.py
index b824a75d1a..26fb1a5ccf 100644
--- a/src/otx/cli/cli.py
+++ b/src/otx/cli/cli.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""CLI entrypoints."""
@@ -8,7 +8,7 @@
import sys
from copy import deepcopy
from pathlib import Path
-from typing import TYPE_CHECKING, Any, Optional
+from typing import TYPE_CHECKING, Any
from warnings import warn
from jsonargparse import ActionConfigFile, ArgumentParser, Namespace, namespace_to_dict
@@ -280,14 +280,14 @@ def _set_extension_subcommands_parser(self, parser_subcommands: _ActionSubComman
find_parser.add_argument(
"--task",
help="Value for filtering by task. Default is None, which shows all recipes.",
- type=Optional[OTXTaskType],
+ type=OTXTaskType | None,
)
find_parser.add_argument(
"--pattern",
help="This allows you to filter the model name of the recipe. \
For example, if you want to find all models that contain the word 'efficient', \
you can use '--pattern efficient'",
- type=Optional[str],
+ type=str | None,
)
parser_subcommands.add_subcommand("find", find_parser, help="This shows the model provided by OTX.")
diff --git a/src/otx/cli/utils/help_formatter.py b/src/otx/cli/utils/help_formatter.py
index b58019160a..3f90179183 100644
--- a/src/otx/cli/utils/help_formatter.py
+++ b/src/otx/cli/utils/help_formatter.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Custom Help Formatters for OTX CLI."""
@@ -7,7 +7,7 @@
import re
import sys
-from typing import TYPE_CHECKING, Iterable
+from typing import TYPE_CHECKING
from jsonargparse import DefaultHelpFormatter
from rich.markdown import Markdown
@@ -17,6 +17,7 @@
if TYPE_CHECKING:
import argparse
+ from collections.abc import Iterable
from rich.console import Console, RenderableType
diff --git a/src/otx/cli/utils/jsonargparse.py b/src/otx/cli/utils/jsonargparse.py
index 0574424d66..e6d8481293 100644
--- a/src/otx/cli/utils/jsonargparse.py
+++ b/src/otx/cli/utils/jsonargparse.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023-2024 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Functions related to jsonargparse."""
@@ -9,13 +9,16 @@
import logging
from contextlib import contextmanager
from pathlib import Path
-from typing import Any, Iterator, TypeVar, Union
+from typing import TYPE_CHECKING, Any, TypeVar
import docstring_parser
from jsonargparse import ActionConfigFile, ArgumentParser, Namespace, dict_to_namespace, namespace_to_dict
from otx.types import PathLike
+if TYPE_CHECKING:
+ from collections.abc import Iterator
+
logger = logging.getLogger()
@@ -77,7 +80,7 @@ def update(
# Dict -> Nested Namespace for overriding
is_value_dict = True
value = dict_to_namespace(value)
- if not isinstance(value, (Namespace, dict)):
+ if not isinstance(value, (Namespace | dict)):
if not key:
msg = "Key is required if value not a Namespace."
raise KeyError(msg)
@@ -382,7 +385,7 @@ def add_list_type_arguments(
added_args: list[str] = []
if skip is not None:
skip = {f"{nested_key}.init_args." + s for s in skip}
- param = ParamData(name=nested_key, annotation=Union[baseclass], component=baseclass)
+ param = ParamData(name=nested_key, annotation=baseclass, component=baseclass)
str_baseclass = iter_to_set_str(get_import_path(x) for x in baseclass)
kwargs = {
"metavar": "CONFIG | CLASS_PATH_OR_NAME | .INIT_ARG_NAME VALUE",
diff --git a/src/otx/cli/utils/workspace.py b/src/otx/cli/utils/workspace.py
index 85b963c153..fd4e81b4ef 100644
--- a/src/otx/cli/utils/workspace.py
+++ b/src/otx/cli/utils/workspace.py
@@ -1,11 +1,11 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Class modules that manage Workspace."""
from __future__ import annotations
-from datetime import datetime, timezone
+from datetime import UTC, datetime
from pathlib import Path
@@ -26,6 +26,6 @@ def __init__(self, work_dir: Path | str = Path.cwd(), use_sub_dir: bool = True):
else work_dir
)
if use_sub_dir:
- timestamp = datetime.now(tz=timezone.utc).strftime("%Y%m%d_%H%M%S")
+ timestamp = datetime.now(tz=UTC).strftime("%Y%m%d_%H%M%S")
self.work_dir = self.work_dir / f"{timestamp}"
Path(self.work_dir).mkdir(parents=True, exist_ok=True)
diff --git a/src/otx/config/__init__.py b/src/otx/config/__init__.py
index 53cff1b514..a7654ab923 100644
--- a/src/otx/config/__init__.py
+++ b/src/otx/config/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Config data type objects."""
@@ -120,7 +120,7 @@ def ignore_aliases(self: yaml.representer.SafeRepresenter, data: Any) -> bool:
return True
if isinstance(data, tuple) and data == ():
return True
- if isinstance(data, (str, bytes, bool, int, float, dtype)):
+ if isinstance(data, (str | bytes | bool | int | float | dtype)):
return True
return None
diff --git a/src/otx/data/dataset/anomaly.py b/src/otx/data/dataset/anomaly.py
index a4728fccc4..c47c79c03e 100644
--- a/src/otx/data/dataset/anomaly.py
+++ b/src/otx/data/dataset/anomaly.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Anomaly Classification Dataset."""
@@ -101,7 +101,7 @@ def _get_mask(self, datumaro_item: DatasetItem, label: torch.Tensor, img_shape:
if label == AnomalyLabel.ANOMALOUS.value:
for annotation in datumaro_item.annotations:
# There is only one mask
- if isinstance(annotation, (Ellipse, Polygon)):
+ if isinstance(annotation, (Ellipse | Polygon)):
polygons = np.asarray(annotation.as_polygon(), dtype=np.int32).reshape((-1, 1, 2))
mask = np.zeros(img_shape, dtype=np.uint8)
mask = cv2.drawContours(
diff --git a/src/otx/data/dataset/base.py b/src/otx/data/dataset/base.py
index 501114f4fc..7e3e1bc269 100644
--- a/src/otx/data/dataset/base.py
+++ b/src/otx/data/dataset/base.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Base class for OTXDataset."""
@@ -6,9 +6,9 @@
from __future__ import annotations
from abc import abstractmethod
-from collections.abc import Iterable
+from collections.abc import Callable, Iterable
from contextlib import contextmanager
-from typing import TYPE_CHECKING, Any, Callable, Iterator, List, Union
+from typing import TYPE_CHECKING, Any, TypeAlias
import cv2
import numpy as np
@@ -23,10 +23,12 @@
from otx.types.label import LabelInfo, NullLabelInfo
if TYPE_CHECKING:
+ from collections.abc import Iterator
+
from datumaro import DatasetSubset, Image
-Transforms = Union[Compose, Callable, List[Callable], dict[str, Compose | Callable | List[Callable]]]
+Transforms: TypeAlias = Compose | Callable | list[Callable] | dict[str, Compose | Callable | list[Callable]]
@contextmanager
diff --git a/src/otx/data/dataset/classification.py b/src/otx/data/dataset/classification.py
index 4280e26413..7261db9e8a 100644
--- a/src/otx/data/dataset/classification.py
+++ b/src/otx/data/dataset/classification.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Module for OTXClassificationDatasets."""
@@ -134,7 +134,7 @@ def __init__(self, **kwargs) -> None:
else:
self.label_info = HLabelInfo.from_dm_label_groups(self.dm_categories)
- self.id_to_name_mapping = dict(zip(self.label_info.label_ids, self.label_info.label_names))
+ self.id_to_name_mapping = dict(zip(self.label_info.label_ids, self.label_info.label_names, strict=False))
self.id_to_name_mapping[""] = ""
if self.label_info.num_multiclass_heads == 0:
diff --git a/src/otx/data/dataset/keypoint_detection.py b/src/otx/data/dataset/keypoint_detection.py
index c97d00ac17..1bdf8706f0 100644
--- a/src/otx/data/dataset/keypoint_detection.py
+++ b/src/otx/data/dataset/keypoint_detection.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Module for OTXKeypointDetectionDataset."""
@@ -6,7 +6,8 @@
from __future__ import annotations
from collections import defaultdict
-from typing import Callable, List, Union
+from collections.abc import Callable
+from typing import TypeAlias
import numpy as np
import torch
@@ -22,7 +23,7 @@
from .base import OTXDataset
-Transforms = Union[Compose, Callable, List[Callable], dict[str, Compose | Callable | List[Callable]]]
+Transforms: TypeAlias = Compose | Callable | list[Callable] | dict[str, Compose | Callable | list[Callable]]
class OTXKeypointDetectionDataset(OTXDataset):
@@ -65,7 +66,7 @@ def _get_single_bbox_dataset(self, dm_subset: DatasetSubset) -> Dataset:
for item in dm_subset:
new_items = defaultdict(list)
for ann in item.annotations:
- if isinstance(ann, (Bbox, Points)):
+ if isinstance(ann, (Bbox | Points)):
new_items[ann.id].append(ann)
for ann_id, anns in new_items.items():
available_types = []
diff --git a/src/otx/data/dataset/segmentation.py b/src/otx/data/dataset/segmentation.py
index 34835b542d..3aff465a1a 100644
--- a/src/otx/data/dataset/segmentation.py
+++ b/src/otx/data/dataset/segmentation.py
@@ -99,11 +99,11 @@ def _extract_class_mask(item: DatasetItem, img_shape: tuple[int, int], ignore_in
raise ValueError(msg, ignore_index)
# fill mask with background label if we have Polygon/Ellipse/Bbox annotations
- fill_value = 0 if isinstance(item.annotations[0], (Ellipse, Polygon, Bbox, RotatedBbox)) else ignore_index
+ fill_value = 0 if isinstance(item.annotations[0], (Ellipse | Polygon | Bbox | RotatedBbox)) else ignore_index
class_mask = np.full(shape=img_shape[:2], fill_value=fill_value, dtype=np.uint8)
for mask in sorted(
- [ann for ann in item.annotations if isinstance(ann, (Mask, Ellipse, Polygon, Bbox, RotatedBbox))],
+ [ann for ann in item.annotations if isinstance(ann, (Mask | Ellipse | Polygon | Bbox | RotatedBbox))],
key=lambda ann: ann.z_order,
):
index = mask.label
@@ -112,7 +112,7 @@ def _extract_class_mask(item: DatasetItem, img_shape: tuple[int, int], ignore_in
msg = "Mask's label index should not be None."
raise ValueError(msg)
- if isinstance(mask, (Ellipse, Polygon, Bbox, RotatedBbox)):
+ if isinstance(mask, (Ellipse | Polygon | Bbox | RotatedBbox)):
polygons = np.asarray(mask.as_polygon(), dtype=np.int32).reshape((-1, 1, 2))
class_index = index + 1 # NOTE: disregard the background index. Objects start from index=1
this_class_mask = cv2.drawContours(
diff --git a/src/otx/data/dataset/tile.py b/src/otx/data/dataset/tile.py
index 778b7de6b3..d66d260448 100644
--- a/src/otx/data/dataset/tile.py
+++ b/src/otx/data/dataset/tile.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""OTX tile dataset."""
@@ -11,7 +11,7 @@
from collections import defaultdict
from copy import deepcopy
from itertools import product
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
import numpy as np
import shapely.geometry as sg
@@ -46,6 +46,8 @@
from .base import OTXDataset
if TYPE_CHECKING:
+ from collections.abc import Callable
+
from datumaro.components.media import BboxIntCoords
from otx.config.data import TileConfig
@@ -115,7 +117,7 @@ def _tile_polygon(
# NOTE: intersection may return a GeometryCollection or MultiPolygon
inter = polygon.intersection(roi_box)
- if isinstance(inter, (sg.GeometryCollection, sg.MultiPolygon)):
+ if isinstance(inter, (sg.GeometryCollection | sg.MultiPolygon)):
shapes = [(geom, geom.area) for geom in list(inter.geoms) if geom.is_valid]
if not shapes:
return None
@@ -177,7 +179,7 @@ def _tile_ellipse(
# NOTE: intersection may return a GeometryCollection or MultiPolygon
inter = polygon.intersection(roi_box)
- if isinstance(inter, (sg.GeometryCollection, sg.MultiPolygon)):
+ if isinstance(inter, (sg.GeometryCollection | sg.MultiPolygon)):
shapes = [(geom, geom.area) for geom in list(inter.geoms) if geom.is_valid]
if not shapes:
return None
diff --git a/src/otx/data/entity/base.py b/src/otx/data/entity/base.py
index b9c1d2f03f..ec40acab22 100644
--- a/src/otx/data/entity/base.py
+++ b/src/otx/data/entity/base.py
@@ -5,7 +5,7 @@
from __future__ import annotations
-from typing import TYPE_CHECKING, Any, Dict
+from typing import TYPE_CHECKING, Any
import torch
import torchvision.transforms.v2.functional as F # noqa: N812
@@ -170,7 +170,7 @@ def _wrap_output(
image_color_channel=image_info.image_color_channel,
ignored_labels=image_info.ignored_labels,
)
- elif isinstance(output, (tuple, list)):
+ elif isinstance(output, (tuple | list)):
image_infos = [x for x in flat_params if isinstance(x, ImageInfo)]
output = type(output)(
ImageInfo._wrap(
@@ -186,7 +186,7 @@ def _wrap_output(
image_color_channel=image_info.image_color_channel,
ignored_labels=image_info.ignored_labels,
)
- for dummy_tensor, image_info in zip(output, image_infos)
+ for dummy_tensor, image_info in zip(output, image_infos, strict=True)
)
return output
@@ -340,7 +340,7 @@ def _wrap_output(
if isinstance(output, Tensor) and not isinstance(output, Points):
output = Points._wrap(output, canvas_size=canvas_size)
- elif isinstance(output, (tuple, list)):
+ elif isinstance(output, (tuple | list)):
output = type(output)(Points._wrap(part, canvas_size=canvas_size) for part in output)
return output
@@ -464,5 +464,5 @@ def clamp_points(inpt: Tensor, canvas_size: tuple[int, int] | None = None) -> Te
)
-class OTXBatchLossEntity(Dict[str, Tensor]):
+class OTXBatchLossEntity(dict[str, Tensor]):
"""Data entity to represent model output losses."""
diff --git a/src/otx/data/entity/tile.py b/src/otx/data/entity/tile.py
index cb8ce3f9dc..033a65ab3f 100644
--- a/src/otx/data/entity/tile.py
+++ b/src/otx/data/entity/tile.py
@@ -6,7 +6,7 @@
from __future__ import annotations
from dataclasses import dataclass
-from typing import TYPE_CHECKING, Sequence
+from typing import TYPE_CHECKING
import torch
from torchvision import tv_tensors
@@ -18,6 +18,8 @@
from .base import ImageInfo
if TYPE_CHECKING:
+ from collections.abc import Sequence
+
from datumaro import Polygon
from torch import LongTensor
@@ -289,7 +291,7 @@ def unbind(self) -> list[tuple[list[dict[str, int | str]], OTXDataBatch]]:
)
for i in range(0, len(tiles), self.batch_size)
]
- return list(zip(batch_tile_attr_list, batch_data_entities))
+ return list(zip(batch_tile_attr_list, batch_data_entities, strict=True))
@classmethod
def collate_fn(cls, batch_entities: list[TileSegDataEntity]) -> TileBatchSegDataEntity:
diff --git a/src/otx/data/entity/torch/torch.py b/src/otx/data/entity/torch/torch.py
index ff85c15c51..cd5e08a69d 100644
--- a/src/otx/data/entity/torch/torch.py
+++ b/src/otx/data/entity/torch/torch.py
@@ -5,9 +5,9 @@
from __future__ import annotations
-from collections.abc import Iterator, Mapping
+from collections.abc import Iterator, Mapping, Sequence
from dataclasses import asdict, dataclass, fields
-from typing import TYPE_CHECKING, Any, Sequence
+from typing import TYPE_CHECKING, Any
import torch
import torchvision.transforms.v2.functional as F # noqa: N812
diff --git a/src/otx/data/entity/torch/validations.py b/src/otx/data/entity/torch/validations.py
index d797ceb4fb..5ad605cb85 100644
--- a/src/otx/data/entity/torch/validations.py
+++ b/src/otx/data/entity/torch/validations.py
@@ -42,7 +42,7 @@ def __post_init__(self) -> None:
@staticmethod
def _image_validator(image: torch.Tensor | np.ndarray) -> torch.Tensor | np.ndarray:
"""Validate the image."""
- if not isinstance(image, (torch.Tensor, np.ndarray)):
+ if not isinstance(image, (torch.Tensor | np.ndarray)):
msg = f"Image must be a torch tensor or numpy array. Got {type(image)}"
raise TypeError(msg)
if image.ndim != 3:
@@ -88,7 +88,7 @@ def _feature_vector_validator(feature_vector: torch.Tensor | np.ndarray) -> torc
Numpy is mixed for this round as it is used in OV Classification.
"""
- if not isinstance(feature_vector, (torch.Tensor, np.ndarray)):
+ if not isinstance(feature_vector, (torch.Tensor | np.ndarray)):
msg = "Feature vector must be a torch tensor or numpy array"
raise TypeError(msg)
if isinstance(feature_vector, torch.Tensor) and feature_vector.dtype != torch.float32:
@@ -280,7 +280,7 @@ def _feature_vectors_validator(
"""
if not isinstance(feature_vector_batch, list) or not isinstance(
feature_vector_batch[0],
- (torch.Tensor, np.ndarray),
+ (torch.Tensor | np.ndarray),
):
msg = (
"Feature vector batch must be a list of torch tensors or numpy arrays."
@@ -313,7 +313,7 @@ def _saliency_maps_validator(
# TODO(ashwinvaidya17): use only one dtype. Kept for OV Classification compatibility
if not isinstance(saliency_map_batch, list) or not isinstance(
saliency_map_batch[0],
- (torch.Tensor, np.ndarray),
+ (torch.Tensor | np.ndarray),
):
msg = f"Saliency map batch must be a list of torch tensors. Got {type(saliency_map_batch)}"
raise TypeError(msg)
diff --git a/src/otx/data/entity/utils.py b/src/otx/data/entity/utils.py
index 626f215ed0..fcf6aa6fa4 100644
--- a/src/otx/data/entity/utils.py
+++ b/src/otx/data/entity/utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Utility functions for OTX data entities."""
@@ -29,7 +29,7 @@ class MulticlassClsDataEntity(OTXDataEntity):
...
"""
flatten_fn = lambda obj: (list(obj.values()), list(obj.keys()))
- unflatten_fn = lambda values, context: cls(**dict(zip(context, values)))
+ unflatten_fn = lambda values, context: cls(**dict(zip(context, values, strict=True)))
pytree.register_pytree_node(
cls,
flatten_fn=flatten_fn,
@@ -81,7 +81,7 @@ def stack_batch(
pad[:, 1::2] = padded_sizes[:, range(dim - 1, -1, -1)]
batch_tensor = []
batch_info = []
- for idx, (tensor, info) in enumerate(zip(tensor_list, img_info_list)):
+ for idx, (tensor, info) in enumerate(zip(tensor_list, img_info_list, strict=True)):
padded_img = torch.nn.functional.pad(tensor, tuple(pad[idx].tolist()), value=pad_value)
# update img_info.img_shape
info.img_shape = padded_img.shape[1:]
diff --git a/src/otx/data/module.py b/src/otx/data/module.py
index d3db20020f..4c4051a087 100644
--- a/src/otx/data/module.py
+++ b/src/otx/data/module.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2023 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""LightningDataModule extension for OTX."""
@@ -115,7 +115,7 @@ def __init__(
self.task,
input_size_multiplier,
)
- elif not isinstance(input_size, (tuple, list)):
+ elif not isinstance(input_size, (tuple | list)):
msg = f"input_size should be tuple/list of ints or 'auto', but got {input_size}"
raise ValueError(msg)
diff --git a/src/otx/data/transform_libs/torchvision.py b/src/otx/data/transform_libs/torchvision.py
index 67df8d0d1f..352c9e61d7 100644
--- a/src/otx/data/transform_libs/torchvision.py
+++ b/src/otx/data/transform_libs/torchvision.py
@@ -11,8 +11,9 @@
import math
import operator
import typing
+from collections.abc import Iterable, Sequence
from inspect import isclass
-from typing import TYPE_CHECKING, Any, ClassVar, Iterable, Sequence
+from typing import TYPE_CHECKING, Any, ClassVar
import cv2
import numpy as np
@@ -574,7 +575,7 @@ def _crop_img(
list[ndarray] | ndarray: The cropped image patches.
"""
chn = 1 if img.ndim == 2 else img.shape[2]
- if pad_fill is not None and isinstance(pad_fill, (int, float)):
+ if pad_fill is not None and isinstance(pad_fill, (int | float)):
pad_fill = [pad_fill for _ in range(chn)]
_bboxes = bboxes[None, ...] if bboxes.ndim == 1 else bboxes
@@ -1236,7 +1237,7 @@ def __init__(
) -> None:
super().__init__()
- assert isinstance(img_scale, (tuple, list)) # noqa: S101
+ assert isinstance(img_scale, (tuple | list)) # noqa: S101
assert 0 <= prob <= 1.0, f"The probability should be in range [0,1]. got {prob}." # noqa: S101
self.img_scale = img_scale # (H, W)
@@ -1402,7 +1403,7 @@ def forward(self, *_inputs: OTXDataItem) -> OTXDataItem | None:
inputs.masks = np.concatenate(mosaic_masks, axis=0)[inside_inds]
if len(mosaic_polygons) > 0:
inputs.polygons = [
- polygon for ind, polygon in zip(inside_inds, itertools.chain(*mosaic_polygons)) if ind
+ polygon for ind, polygon in zip(inside_inds, itertools.chain(*mosaic_polygons), strict=True) if ind
] # type: ignore[union-attr]
return self.convert(inputs)
@@ -1544,7 +1545,7 @@ def __init__(
) -> None:
super().__init__()
- assert isinstance(img_scale, (tuple, list)) # noqa: S101
+ assert isinstance(img_scale, (tuple | list)) # noqa: S101
assert max_cached_images >= 2, f"The length of cache must >= 2, but got {max_cached_images}." # noqa: S101
assert 0 <= prob <= 1.0, f"The probability should be in range [0,1]. got {prob}." # noqa: S101
self.dynamic_scale = img_scale # (H, W)
@@ -2625,7 +2626,7 @@ def generate(cls, config: SubsetConfig) -> Compose:
input_size = getattr(config, "input_size", None)
transforms = []
for cfg_transform in config.transforms:
- if isinstance(cfg_transform, (dict, DictConfig)):
+ if isinstance(cfg_transform, (dict | DictConfig)):
if not cfg_transform.get("enable", True): # Optional "enable: false" flag would remove the transform
continue
cls._configure_input_size(cfg_transform, input_size)
@@ -2733,7 +2734,7 @@ def _eval(node: Any) -> Any: # noqa: ANN401
@classmethod
def _dispatch_transform(cls, cfg_transform: DictConfig | dict | tvt_v2.Transform) -> tvt_v2.Transform:
- if isinstance(cfg_transform, (DictConfig, dict)):
+ if isinstance(cfg_transform, (DictConfig | dict)):
transform = instantiate_class(args=(), init=cfg_transform)
elif isinstance(cfg_transform, tvt_v2.Transform):
diff --git a/src/otx/data/transform_libs/utils.py b/src/otx/data/transform_libs/utils.py
index 464b5b24ef..be56402417 100644
--- a/src/otx/data/transform_libs/utils.py
+++ b/src/otx/data/transform_libs/utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) OpenMMLab. All rights reserved.
@@ -12,7 +12,7 @@
import inspect
import itertools
import weakref
-from typing import TYPE_CHECKING, Sequence
+from typing import TYPE_CHECKING
import cv2
import numpy as np
@@ -21,6 +21,8 @@
from torch import BoolTensor, Tensor
if TYPE_CHECKING:
+ from collections.abc import Sequence
+
from datumaro import Polygon
@@ -111,7 +113,7 @@ def __get__(self, obj, cls): # noqa: ANN001
def get_image_shape(img: np.ndarray | Tensor | list) -> tuple[int, int]:
"""Get image(s) shape with (height, width)."""
- if not isinstance(img, (np.ndarray, Tensor, list)):
+ if not isinstance(img, (np.ndarray | Tensor | list)):
msg = f"{type(img)} is not supported."
raise TypeError(msg)
@@ -636,7 +638,7 @@ def scale_size(
Returns:
tuple[int]: scaled size with (height, width).
"""
- if isinstance(scale, (float, int)):
+ if isinstance(scale, (float | int)):
scale = (scale, scale)
h, w = size
return int(h * float(scale[0]) + 0.5), int(w * float(scale[1]) + 0.5)
@@ -663,7 +665,7 @@ def rescale_size(
"""
h, w = old_size
msg = ""
- if isinstance(scale, (float, int)):
+ if isinstance(scale, (float | int)):
if scale <= 0:
msg = f"Invalid scale {scale}, must be positive."
raise ValueError(msg)
diff --git a/src/otx/metrics/accuracy.py b/src/otx/metrics/accuracy.py
index 8255796bdd..2558eb5c96 100644
--- a/src/otx/metrics/accuracy.py
+++ b/src/otx/metrics/accuracy.py
@@ -1,11 +1,11 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Module for OTX accuracy metric used for classification tasks."""
from __future__ import annotations
-from typing import TYPE_CHECKING, Any, Callable, Literal, Sequence
+from typing import TYPE_CHECKING, Any, Literal
import torch
from torch import nn
@@ -21,6 +21,8 @@
from .mlc_map import MultilabelmAP
if TYPE_CHECKING:
+ from collections.abc import Callable, Sequence
+
from torch import Tensor
from otx.types.label import HLabelInfo, LabelInfo
diff --git a/src/otx/metrics/fmeasure.py b/src/otx/metrics/fmeasure.py
index 603c7fdf57..4ba88d25b5 100644
--- a/src/otx/metrics/fmeasure.py
+++ b/src/otx/metrics/fmeasure.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Module for OTX custom f1 metrices."""
@@ -541,9 +541,9 @@ def __filter_nms(
list[list[tuple]]: list of list of filtered boxes in each image
"""
new_boxes_per_image = []
- for boxes, boxes_nms in zip(boxes_per_image, critical_nms):
+ for boxes, boxes_nms in zip(boxes_per_image, critical_nms, strict=True):
new_boxes = []
- for box, nms in zip(boxes, boxes_nms):
+ for box, nms in zip(boxes, boxes_nms, strict=True):
if nms < nms_threshold:
new_boxes.append(box)
new_boxes_per_image.append(new_boxes)
@@ -610,6 +610,7 @@ def get_counters(self, iou_threshold: float) -> _ResultCounters:
for ground_truth_boxes, predicted_boxes in zip(
self.ground_truth_boxes_per_image,
self.prediction_boxes_per_image,
+ strict=True,
):
n_true += len(ground_truth_boxes)
n_predicted += len(predicted_boxes)
@@ -677,7 +678,7 @@ def reset(self) -> None:
def update(self, preds: list[dict[str, Tensor]], target: list[dict[str, Tensor]]) -> None:
"""Update total predictions and targets from given batch predicitons and targets."""
- for pred, tget in zip(preds, target):
+ for pred, tget in zip(preds, target, strict=True):
self.preds.append(
[
(*box, self.classes[label], score)
@@ -685,13 +686,14 @@ def update(self, preds: list[dict[str, Tensor]], target: list[dict[str, Tensor]]
pred["boxes"].tolist(),
pred["labels"].tolist(),
pred["scores"].tolist(),
+ strict=True,
)
],
)
self.targets.append(
[
(*box, self.classes[label], 0.0)
- for box, label in zip(tget["boxes"].tolist(), tget["labels"].tolist())
+ for box, label in zip(tget["boxes"].tolist(), tget["labels"].tolist(), strict=True)
],
)
diff --git a/src/otx/metrics/pck.py b/src/otx/metrics/pck.py
index bcc03e21f6..c7d528e3c8 100644
--- a/src/otx/metrics/pck.py
+++ b/src/otx/metrics/pck.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Module for OTX accuracy metric used for classification tasks."""
@@ -163,7 +163,7 @@ def reset(self) -> None:
def update(self, preds: list[dict[str, Tensor]], target: list[dict[str, Tensor]]) -> None:
"""Update total predictions and targets from given batch predicitons and targets."""
- for pred, tget in zip(preds, target):
+ for pred, tget in zip(preds, target, strict=True):
self.preds.extend(
[
(pred["keypoints"], pred["scores"]),
diff --git a/src/otx/metrics/types.py b/src/otx/metrics/types.py
index e51a61637b..9cfb641f8c 100644
--- a/src/otx/metrics/types.py
+++ b/src/otx/metrics/types.py
@@ -1,10 +1,11 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Type definitions for OTX metrics."""
import logging
-from typing import Any, Callable
+from collections.abc import Callable
+from typing import Any
from torch import zeros
from torchmetrics import Metric, MetricCollection
diff --git a/src/otx/tools/auto_configurator.py b/src/otx/tools/auto_configurator.py
index 1615706293..20ee7fff84 100644
--- a/src/otx/tools/auto_configurator.py
+++ b/src/otx/tools/auto_configurator.py
@@ -165,7 +165,7 @@ def get_datamodule(self, data_root: PathLike | None = None) -> OTXDataModule:
if data_root is None and self.data_root is None:
msg = "No data root provided."
raise ValueError(msg)
- if data_root is not None and not isinstance(data_root, (str, os.PathLike)):
+ if data_root is not None and not isinstance(data_root, (str | os.PathLike)):
msg = f"data_root should be of type PathLike, but got {type(data_root)}"
raise TypeError(msg)
diff --git a/src/otx/types/__init__.py b/src/otx/types/__init__.py
index 355a06d2b3..072b0c07b9 100644
--- a/src/otx/types/__init__.py
+++ b/src/otx/types/__init__.py
@@ -1,13 +1,11 @@
-# Copyright (C) 2023 Intel Corporation
+# Copyright (C) 2023-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Module reserved for definitions used in OTX."""
import os
from pathlib import Path
-from typing import Union
-
-from typing_extensions import TypeAlias
+from typing import TypeAlias
from otx.types.label import HLabelInfo, LabelInfo, NullLabelInfo, SegLabelInfo
from otx.types.task import OTXTaskType
@@ -22,4 +20,4 @@
"OTXTaskType",
]
-PathLike: TypeAlias = Union[str, Path, os.PathLike]
+PathLike: TypeAlias = str | Path | os.PathLike
diff --git a/src/otx/types/explain.py b/src/otx/types/explain.py
index 40ef53d842..497d4d910b 100644
--- a/src/otx/types/explain.py
+++ b/src/otx/types/explain.py
@@ -1,12 +1,12 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""OTX explain type definition."""
from __future__ import annotations
+from collections.abc import Sequence
from enum import Enum
-from typing import Sequence
import torch
diff --git a/src/otx/utils/signal.py b/src/otx/utils/signal.py
index 1ca3311be8..89dfc4babd 100644
--- a/src/otx/utils/signal.py
+++ b/src/otx/utils/signal.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""Functions to append a signal handler."""
@@ -8,9 +8,10 @@
import os
import signal
from dataclasses import dataclass
-from typing import TYPE_CHECKING, Callable
+from typing import TYPE_CHECKING
if TYPE_CHECKING:
+ from collections.abc import Callable
from types import FrameType
diff --git a/src/otx/utils/utils.py b/src/otx/utils/utils.py
index 835e88910e..32cf8e3709 100644
--- a/src/otx/utils/utils.py
+++ b/src/otx/utils/utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""OTX utility functions."""
@@ -11,11 +11,12 @@
from decimal import Decimal
from functools import partial
from types import LambdaType
-from typing import TYPE_CHECKING, Any, Callable
+from typing import TYPE_CHECKING, Any
from otx.backend.native.models.base import OTXModel
if TYPE_CHECKING:
+ from collections.abc import Callable
from pathlib import Path
import torch
@@ -213,7 +214,7 @@ def _need_skip(obj: Any) -> bool: # noqa: ANN401
return isinstance(obj, memoryview) # it makes core dumped
def _make_iter(obj: Any) -> list[tuple[str, Any]]: # noqa: ANN401
- if isinstance(obj, (list, tuple)):
+ if isinstance(obj, (list | tuple)):
return [(f"[{i}]", obj[i]) for i in range(len(obj))]
if isinstance(obj, dict):
return [(f'["{key}"]', obj[key]) for key in obj]
@@ -226,7 +227,7 @@ def _make_iter(obj: Any) -> list[tuple[str, Any]]: # noqa: ANN401
attr_obj = getattr(obj, attr)
except Exception: # noqa: S112
continue
- if callable(attr_obj) and not isinstance(attr_obj, (LambdaType, partial)):
+ if callable(attr_obj) and not isinstance(attr_obj, (LambdaType | partial)):
continue
res.append((f".{attr}", attr_obj))
return res
diff --git a/tests/integration/api/test_augmentation.py b/tests/integration/api/test_augmentation.py
index 9b25bc8d9a..a99727bda7 100644
--- a/tests/integration/api/test_augmentation.py
+++ b/tests/integration/api/test_augmentation.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
@@ -42,7 +42,7 @@ def _test_augmentation(
img_shape = None
for switches in itertools.product([True, False], repeat=len(configurable_augs)):
# Configure on/off
- for aug_name, switch in zip(configurable_augs, switches):
+ for aug_name, switch in zip(configurable_augs, switches, strict=True):
aug_found = False
for aug_config in train_config["transforms"]:
if aug_name in aug_config["class_path"]:
diff --git a/tests/perf_v2/run.py b/tests/perf_v2/run.py
index fe9d44fbe5..d4ec56742e 100644
--- a/tests/perf_v2/run.py
+++ b/tests/perf_v2/run.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
"""OTX Benchmark Entry Point."""
@@ -39,7 +39,7 @@ def run_job(cmd: list[str], retries: int = MAX_RETRIES) -> dict | None:
logger.info(f"Running (attempt {attempt}): {' '.join(cmd)}")
subprocess.run(cmd, check=True) # noqa: S603
return None # Success # noqa: TRY300
- except subprocess.CalledProcessError as e: # noqa: PERF203
+ except subprocess.CalledProcessError as e:
stderr_output = ""
try:
subprocess.run(
diff --git a/tests/perf_v2/utils.py b/tests/perf_v2/utils.py
index 8ca970e670..069cd846e4 100644
--- a/tests/perf_v2/utils.py
+++ b/tests/perf_v2/utils.py
@@ -11,7 +11,7 @@
import subprocess
import tempfile
from dataclasses import dataclass
-from datetime import datetime, timezone
+from datetime import UTC, datetime
from enum import Enum
from pathlib import Path
@@ -122,7 +122,7 @@ def current_date_str() -> str:
Returns:
str: Current date string.
"""
- return datetime.now(timezone.utc).strftime("%Y%m%d-%H%M%S")
+ return datetime.now(UTC).strftime("%Y%m%d-%H%M%S")
def setup_output_root(config: Namespace, task: OTXTaskType) -> Path:
diff --git a/tests/unit/backend/native/callbacks/test_aug_scheduler.py b/tests/unit/backend/native/callbacks/test_aug_scheduler.py
index cc7717349d..108260c0ef 100644
--- a/tests/unit/backend/native/callbacks/test_aug_scheduler.py
+++ b/tests/unit/backend/native/callbacks/test_aug_scheduler.py
@@ -367,7 +367,7 @@ def test_full_training_simulation(self, integration_setup):
"light_aug",
]
- for epoch, expected_policy_type in zip(test_epochs, expected_policies):
+ for epoch, expected_policy_type in zip(test_epochs, expected_policies, strict=True):
# Simulate trainer epoch update
mock_trainer = MagicMock(spec=Trainer)
mock_trainer.current_epoch = epoch
diff --git a/tests/unit/backend/native/exporter/exportable_code/demo/demo_package/streamer/test_streamer.py b/tests/unit/backend/native/exporter/exportable_code/demo/demo_package/streamer/test_streamer.py
index a384d8d4ad..6ebdba6f8c 100644
--- a/tests/unit/backend/native/exporter/exportable_code/demo/demo_package/streamer/test_streamer.py
+++ b/tests/unit/backend/native/exporter/exportable_code/demo/demo_package/streamer/test_streamer.py
@@ -1,10 +1,11 @@
-# Copyright (C) 2024 Intel Corporation
+# Copyright (C) 2024-2025 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
+
"""Test of AsyncExecutor in demo_package."""
import tempfile
+from collections.abc import Iterator
from pathlib import Path
-from typing import Iterator
import cv2
import numpy as np
diff --git a/tests/unit/backend/native/exporter/test_base.py b/tests/unit/backend/native/exporter/test_base.py
index eb169612be..51fd234920 100644
--- a/tests/unit/backend/native/exporter/test_base.py
+++ b/tests/unit/backend/native/exporter/test_base.py
@@ -85,7 +85,7 @@ def test_postprocess_openvino_model(self, mock_model, exporter):
processed_model = exporter._postprocess_openvino_model(mock_model)
# Verify the processed model is returned and the names are set correctly
assert processed_model is mock_model
- for output, name in zip(processed_model.outputs, exporter.output_names):
+ for output, name in zip(processed_model.outputs, exporter.output_names, strict=True):
output.tensor.set_names.assert_called_once_with({name})
def test_embed_metadata_true_precision_fp16(self, exporter):
diff --git a/tests/unit/backend/native/models/common/utils/assigners/test_hungarian_matcher.py b/tests/unit/backend/native/models/common/utils/assigners/test_hungarian_matcher.py
index b728b059db..2634daeaa5 100644
--- a/tests/unit/backend/native/models/common/utils/assigners/test_hungarian_matcher.py
+++ b/tests/unit/backend/native/models/common/utils/assigners/test_hungarian_matcher.py
@@ -49,4 +49,4 @@ def test_hungarian_matcher(self, targets, outputs):
# Assert the output matches the expected shape
assert len(matches) == 1
assert all(len(match[0]) == len(match[1]) for match in matches)
- assert all(len(match[0]) == len(target["labels"]) for match, target in zip(matches, targets))
+ assert all(len(match[0]) == len(target["labels"]) for match, target in zip(matches, targets, strict=True))
diff --git a/tests/unit/backend/native/models/detection/backbones/test_csp_darknet.py b/tests/unit/backend/native/models/detection/backbones/test_csp_darknet.py
index 373f0b1de1..02553d1a17 100644
--- a/tests/unit/backend/native/models/detection/backbones/test_csp_darknet.py
+++ b/tests/unit/backend/native/models/detection/backbones/test_csp_darknet.py
@@ -28,7 +28,7 @@ def is_norm(modules):
Reference : https://github.com/open-mmlab/mmdetection/blob/v3.2.0/tests/test_models/test_backbones/utils.py#L19-L23
"""
- if isinstance(modules, (GroupNorm, _BatchNorm)):
+ if isinstance(modules, (GroupNorm | _BatchNorm)):
return True
return False
diff --git a/tests/unit/backend/native/models/detection/heads/test_rtmdet_head.py b/tests/unit/backend/native/models/detection/heads/test_rtmdet_head.py
index 568f32d491..9a91b5af29 100644
--- a/tests/unit/backend/native/models/detection/heads/test_rtmdet_head.py
+++ b/tests/unit/backend/native/models/detection/heads/test_rtmdet_head.py
@@ -64,7 +64,7 @@ def test_forward(self, rtmdet_head, input_features) -> None:
cls_scores, bbox_preds = rtmdet_head(input_features)
assert len(cls_scores) == len(input_features)
assert len(bbox_preds) == len(input_features)
- for cls_score, bbox_pred in zip(cls_scores, bbox_preds):
+ for cls_score, bbox_pred in zip(cls_scores, bbox_preds, strict=True):
assert cls_score.shape[1] == rtmdet_head.num_base_priors * rtmdet_head.cls_out_channels
assert bbox_pred.shape[1] == rtmdet_head.num_base_priors * 4
@@ -101,10 +101,10 @@ def test_get_anchors(self, rtmdet_head) -> None:
assert len(anchor_list) == len(batch_img_metas)
assert len(valid_flag_list) == len(batch_img_metas)
- for anchors, valid_flags in zip(anchor_list, valid_flag_list):
+ for anchors, valid_flags in zip(anchor_list, valid_flag_list, strict=True):
assert len(anchors) == len(featmap_sizes)
assert len(valid_flags) == len(featmap_sizes)
- for anchor, valid_flag in zip(anchors, valid_flags):
+ for anchor, valid_flag in zip(anchors, valid_flags, strict=True):
assert anchor.shape[1] == 4
assert valid_flag.dtype == torch.bool
@@ -151,7 +151,7 @@ def test_rtmdet_sep_bn_head_forward(self, rtmdet_sep_bn_head, input_features) ->
cls_scores, bbox_preds = rtmdet_sep_bn_head(input_features)
assert len(cls_scores) == len(input_features)
assert len(bbox_preds) == len(input_features)
- for cls_score, bbox_pred in zip(cls_scores, bbox_preds):
+ for cls_score, bbox_pred in zip(cls_scores, bbox_preds, strict=True):
# The number of channels in cls_scores should be num_base_priors * num_classes
assert cls_score.size(1) == rtmdet_sep_bn_head.num_base_priors * rtmdet_sep_bn_head.cls_out_channels
# The number of channels in bbox_preds should be num_base_priors * 4
diff --git a/tests/unit/backend/native/models/detection/test_rtdetr.py b/tests/unit/backend/native/models/detection/test_rtdetr.py
index 04a642ab88..b54715a7dc 100644
--- a/tests/unit/backend/native/models/detection/test_rtdetr.py
+++ b/tests/unit/backend/native/models/detection/test_rtdetr.py
@@ -89,7 +89,7 @@ def test_get_optim_params(self):
cfg = [{"params": "^fc", "lr": 0.01, "weight_decay": 0.0}]
params = RTDETR._get_optim_params(cfg, model)
assert len(params) == 2
- for p1, (name, p2) in zip(params[0]["params"], model.named_parameters()):
+ for p1, (name, p2) in zip(params[0]["params"], model.named_parameters(), strict=True):
if "fc" in name:
assert not torch.is_nonzero((p1.data - p2.data).sum())
@@ -98,7 +98,7 @@ def test_get_optim_params(self):
cfg = None
params = RTDETR._get_optim_params(cfg, model)
- for p1, p2 in zip(params, model.parameters()):
+ for p1, p2 in zip(params, model.parameters(), strict=True):
assert not torch.is_nonzero((p1.data - p2.data).sum())
cfg = [
@@ -107,9 +107,17 @@ def test_get_optim_params(self):
]
params = RTDETR._get_optim_params(cfg, model)
assert len(params) == 2
- for p1, p2 in zip(params[0]["params"], [p.data for name, p in model.named_parameters() if "conv" in name]):
+ for p1, p2 in zip(
+ params[0]["params"],
+ [p.data for name, p in model.named_parameters() if "conv" in name],
+ strict=True,
+ ):
assert not torch.is_nonzero((p1.data - p2.data).sum())
- for p1, p2 in zip(params[1]["params"], [p.data for name, p in model.named_parameters() if "fc" in name]):
+ for p1, p2 in zip(
+ params[1]["params"],
+ [p.data for name, p in model.named_parameters() if "fc" in name],
+ strict=True,
+ ):
assert not torch.is_nonzero((p1.data - p2.data).sum())
assert params[0]["lr"] == 0.01 # conv
assert params[1]["lr"] == 0.001 # fc
diff --git a/tests/unit/backend/native/models/utils/test_support_otx_v1.py b/tests/unit/backend/native/models/utils/test_support_otx_v1.py
index a776d9595a..af57305423 100644
--- a/tests/unit/backend/native/models/utils/test_support_otx_v1.py
+++ b/tests/unit/backend/native/models/utils/test_support_otx_v1.py
@@ -16,7 +16,11 @@ def fxt_random_tensor(self) -> torch.Tensor:
return torch.randn(3, 10)
def _check_ckpt_pairs(self, src_state_dict: dict, dst_state_dict: dict) -> None:
- for (src_key, src_value), (dst_key, dst_value) in zip(src_state_dict.items(), dst_state_dict.items()):
+ for (src_key, src_value), (dst_key, dst_value) in zip(
+ src_state_dict.items(),
+ dst_state_dict.items(),
+ strict=True,
+ ):
assert src_key == dst_key
assert src_value.shape == dst_value.shape
diff --git a/tests/unit/data/dataset/test_detection_aug_switch.py b/tests/unit/data/dataset/test_detection_aug_switch.py
index 1c2cfaf0dd..d345f6f969 100644
--- a/tests/unit/data/dataset/test_detection_aug_switch.py
+++ b/tests/unit/data/dataset/test_detection_aug_switch.py
@@ -175,7 +175,7 @@ def test_transforms_updated_correctly(self, detection_dataset, data_aug_switch):
test_epochs = [2, 15, 35]
expected_policies = ["no_aug", "strong_aug", "light_aug"]
- for epoch, expected_policy_type in zip(test_epochs, expected_policies):
+ for epoch, expected_policy_type in zip(test_epochs, expected_policies, strict=True):
data_aug_switch.epoch = epoch
# Apply augmentation switch
diff --git a/tests/unit/data/transform_libs/test_torchvision.py b/tests/unit/data/transform_libs/test_torchvision.py
index e5dd3eeadf..f6b67f2b15 100644
--- a/tests/unit/data/transform_libs/test_torchvision.py
+++ b/tests/unit/data/transform_libs/test_torchvision.py
@@ -153,7 +153,7 @@ def test_forward_bboxes_masks_polygons(
np.array(rp.points).reshape(-1, 2)
== np.array(fp.points).reshape(-1, 2) * np.array([results.img_info.scale_factor[::-1]]),
)
- for rp, fp in zip(results.polygons, fxt_inst_seg_data_entity[0].polygons)
+ for rp, fp in zip(results.polygons, fxt_inst_seg_data_entity[0].polygons, strict=True)
],
)