Skip to content

Store intensity config in IR metadata#6059

Merged
kprokofi merged 15 commits intodevelopfrom
kprokofi/introduce-ir-meta-data
Apr 13, 2026
Merged

Store intensity config in IR metadata#6059
kprokofi merged 15 commits intodevelopfrom
kprokofi/introduce-ir-meta-data

Conversation

@kprokofi
Copy link
Copy Markdown
Contributor

@kprokofi kprokofi commented Apr 9, 2026

Summary

Resolves #5952

How to test

Checklist

  • The PR title and description are clear and descriptive
  • I have manually tested the changes
  • All changes are covered by automated tests
  • All related issues are linked to this PR (if applicable)
  • Documentation has been updated (if applicable)

@github-actions github-actions bot added the TEST Any changes in tests label Apr 9, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 9, 2026

🐳 Docker image sizes

Device Size
cpu 3592.9 MB (3.51 GB)
xpu 10561.5 MB (10.31 GB)
cuda 11713.8 MB (11.44 GB)

@kprokofi kprokofi marked this pull request as ready for review April 9, 2026 06:28
@kprokofi kprokofi requested a review from a team as a code owner April 9, 2026 06:28
Copilot AI review requested due to automatic review settings April 9, 2026 06:28
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements exporting of IntensityConfig (high-bit-depth / domain-specific intensity preprocessing) into exported model metadata (rt_info / ONNX metadata), by propagating intensity configuration from the data pipeline through CLI/Engine into DataInputParams, and finally embedding it during export. This addresses the need from issue #5952 to make exported models self-describing for inference-time preprocessing reconstruction.

Changes:

  • Extend DataInputParams to optionally carry IntensityConfig and serialize it via as_dict().
  • Plumb intensity config from OTXDataModule → CLI/Engine model instantiation → exporter metadata embedding.
  • Add unit tests covering metadata embedding for multiple IntensityConfig modes and DataInputParams.as_dict() behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
library/src/otx/backend/native/exporter/base.py Embed intensity-related keys (dtype, mode, parameters) into export metadata.
library/src/otx/backend/native/models/base.py Add intensity_config to DataInputParams; parse intensity config dicts in preprocessing params.
library/src/otx/data/module.py Expose training subset intensity config on the datamodule for downstream plumbing.
library/src/otx/cli/cli.py Forward datamodule intensity config into data_input_params during CLI instantiation.
library/src/otx/backend/native/engine.py Forward datamodule intensity config into model construction args.
library/tests/unit/backend/native/exporter/test_base.py Add tests for intensity metadata embedding and DataInputParams.as_dict().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread library/src/otx/data/module.py Outdated
Comment on lines +133 to +137
# Forward the training subset's intensity config so that Engine / CLI
# can pass it to OTXModel.data_input_params → exporter rt_info.
# None means no subset or no intensity attr (old configs / no data pipeline).
self.input_intensity_config = getattr(self.train_subset, "intensity", None)

Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OTXDataModule.from_otx_datasets() does not set input_intensity_config, but Engine/CLI now read datamodule.input_intensity_config. If a datamodule is created via from_otx_datasets (e.g. quantization/AutoConfigurator path), this can raise AttributeError. Consider initializing input_intensity_config in from_otx_datasets as well (e.g. from train_subset.intensity) or ensuring callers use getattr(..., None).

Copilot uses AI. Check for mistakes.
Comment on lines +151 to +152
if self._datamodule.input_intensity_config is not None:
params["intensity_config"] = self._datamodule.input_intensity_config
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly accessing self._datamodule.input_intensity_config can raise AttributeError for datamodules created via OTXDataModule.from_otx_datasets(), which currently doesn’t define that attribute. Either ensure the datamodule factory sets input_intensity_config or use getattr(self._datamodule, "input_intensity_config", None) here.

Suggested change
if self._datamodule.input_intensity_config is not None:
params["intensity_config"] = self._datamodule.input_intensity_config
input_intensity_config = getattr(self._datamodule, "input_intensity_config", None)
if input_intensity_config is not None:
params["intensity_config"] = input_intensity_config

Copilot uses AI. Check for mistakes.
Comment thread library/src/otx/cli/cli.py Outdated
Comment on lines +325 to +326
if self.datamodule.input_intensity_config is not None:
_dip["intensity_config"] = self.datamodule.input_intensity_config
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.datamodule.input_intensity_config may not exist for datamodules created via OTXDataModule.from_otx_datasets() (it currently doesn’t define that attribute). This can raise AttributeError during CLI instantiation; consider using getattr(self.datamodule, "input_intensity_config", None) or making from_otx_datasets initialize it.

Suggested change
if self.datamodule.input_intensity_config is not None:
_dip["intensity_config"] = self.datamodule.input_intensity_config
input_intensity_config = getattr(self.datamodule, "input_intensity_config", None)
if input_intensity_config is not None:
_dip["intensity_config"] = input_intensity_config

Copilot uses AI. Check for mistakes.
Comment on lines +191 to +193
# Map storage_dtype to the ModelAPI input_dtype convention
_dtype_map = {"uint8": "u8", "uint16": "u16", "float32": "f32"}
input_dtype = _dtype_map.get(intensity_cfg.storage_dtype, intensity_cfg.storage_dtype)
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IntensityConfig.storage_dtype supports values beyond {uint8,uint16,float32} (e.g. "int16" per otx/config/data.py). The dtype mapping here will fall back to the raw string, which may not match the intended ModelAPI input_dtype convention. Consider extending _dtype_map (and/or validating storage_dtype) to cover all supported dtypes consistently.

Suggested change
# Map storage_dtype to the ModelAPI input_dtype convention
_dtype_map = {"uint8": "u8", "uint16": "u16", "float32": "f32"}
input_dtype = _dtype_map.get(intensity_cfg.storage_dtype, intensity_cfg.storage_dtype)
# Map storage_dtype to the ModelAPI input_dtype convention.
# Keep the original value for unknown dtypes to preserve current behavior,
# but warn because ModelAPI expects the shorthand form (for example, "i16").
_dtype_map = {
"int8": "i8",
"int16": "i16",
"int32": "i32",
"uint8": "u8",
"uint16": "u16",
"uint32": "u32",
"float16": "f16",
"float32": "f32",
"float64": "f64",
}
storage_dtype = intensity_cfg.storage_dtype
normalized_storage_dtype = storage_dtype.lower()
input_dtype = _dtype_map.get(normalized_storage_dtype, storage_dtype)
if input_dtype == storage_dtype and normalized_storage_dtype not in _dtype_map:
log.warning(
"Unsupported intensity storage_dtype '%s' for ModelAPI input_dtype mapping; "
"using raw value in exported metadata.",
storage_dtype,
)

Copilot uses AI. Check for mistakes.
Comment on lines +195 to +199
extra_data[("model_info", "intensity_mode")] = intensity_cfg.mode

if intensity_cfg.max_value is not None:
extra_data[("model_info", "intensity_max_value")] = str(intensity_cfg.max_value)
if intensity_cfg.window_center is not None:
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IntensityConfig.max_value has an 'auto' meaning when None (see otx/config/data.py and build_intensity_transform auto-detection). For mode="scale_to_unit", the exporter currently omits intensity_max_value when max_value is None, so the exported rt_info can’t fully represent the effective preprocessing parameters unless the consumer duplicates the same auto-logic. Consider resolving and exporting the effective max_value (at least for non-uint8 dtypes) to make exports self-contained.

Copilot uses AI. Check for mistakes.
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 9, 2026

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 95.00000% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
library/src/otx/backend/native/models/base.py 77.77% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

leoll2
leoll2 previously approved these changes Apr 10, 2026
@leoll2 leoll2 changed the title Store Intencity Config in IR meta data Store intensity config in IR metadata Apr 11, 2026
Comment thread library/src/otx/backend/native/exporter/base.py Outdated
@kprokofi kprokofi requested a review from leoll2 April 13, 2026 13:14
@kprokofi kprokofi enabled auto-merge April 13, 2026 13:56
@kprokofi kprokofi added this pull request to the merge queue Apr 13, 2026
Merged via the queue into develop with commit 0590444 Apr 13, 2026
49 checks passed
@kprokofi kprokofi deleted the kprokofi/introduce-ir-meta-data branch April 13, 2026 15:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

TEST Any changes in tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Embed intensity metadata in exported model rt_info

4 participants