Skip to content

Commit 752a4a0

Browse files
authored
Optimize RF-DETR object detection pre/post-processing (#2667)
* Enhance RF-DETR preprocessing capabilities by introducing a threaded preprocessor implementation. This update includes a new `resolve_rfdetr_preprocessor` function for selecting preprocessing strategies, and integrates preprocessor configuration into the `pre_process_network_input` function. Additionally, the `RFDetrForObjectDetectionTRT` class now supports customizable preprocessor settings, improving flexibility for users. Updated error handling for unsupported input types and added logging for selected preprocessors. * Change logging level from info to warning in RF-DETR preprocessor logging to better reflect the significance of selected implementations. * Add Triton universal preprocessor implementation for RF-DETR This commit introduces a new preprocessor implementation, `RFDETR_PREPROCESSOR_TRITON_UNIVERSAL_V1`, enhancing the RF-DETR model's preprocessing capabilities. The implementation supports various input types and optimizes CUDA processing. Additionally, it integrates with the `RFDetrForObjectDetectionTRT` class, allowing for streamlined preprocessing during inference. A new runtime class, `UniversalFastPreprocessRuntime`, is added to handle the preprocessing logic, and corresponding unit tests are included to ensure functionality and compatibility. * Add RF-DETR postprocessing capabilities with Triton integration This commit introduces a new postprocessing module for RF-DETR, including the `FusedObjectDetectionPostprocessor` that optimizes object detection results using Triton. The implementation allows for explicit selection of postprocessor strategies, enhancing flexibility during inference. Additionally, the `RFDetrForObjectDetectionTRT` class is updated to support the new postprocessor, and corresponding unit tests are added to validate functionality and performance. This update aims to improve efficiency and streamline the postprocessing workflow for RF-DETR models. * Enhance RF-DETR preprocessing and postprocessing with environment variable support This commit introduces support for environment variables in the RF-DETR preprocessing and postprocessing modules. New environment variables, `INFERENCE_MODELS_RFDETR_PREPROCESSOR` and `INFERENCE_MODELS_RFDETR_POSTPROCESSOR`, allow users to specify preprocessing and postprocessing strategies without modifying code. The `resolve_rfdetr_preprocessor` and `resolve_rfdetr_postprocessor` functions are updated to utilize these environment variables, enhancing flexibility. Additionally, new unit tests validate the correct behavior of these features, ensuring robust functionality across different configurations. * Implement RF-DETR execution plan for flexible inference paths This commit introduces a new `RFDetrExecutionPlan` class that allows users to define a composed execution plan for RF-DETR inference, enabling independent selection of preprocessing, postprocessing, buffer strategy, scheduler, and engine plugin stages. The implementation ensures that explicit plans cannot be combined with legacy arguments, enhancing clarity and usability. Additionally, the `RFDetrForObjectDetectionTRT` class is updated to support this new execution plan, improving the flexibility of inference configurations. Corresponding updates are made to the preprocessing and postprocessing modules to integrate with the new execution plan structure. * Add Inference-Path Optimization Architecture documentation and Mermaid integration This commit introduces a new documentation file detailing the Inference-Path Optimization Architecture, explaining the selection and execution of inference-path implementations. It includes a flowchart visualized with Mermaid to illustrate the architecture's components and their interactions. Additionally, the mkdocs configuration is updated to include the new documentation and enable Mermaid support for enhanced visual representation. References to this architecture are added in relevant sections of the environment variables and RF-DETR object detection documentation, improving clarity and accessibility for users. * Refactor RF-DETR optimization architecture with reusable components This commit introduces a comprehensive refactor of the RF-DETR optimization architecture, creating reusable components for inference-path implementations. New modules for contracts, execution plans, and a context-aware registry are added to enhance flexibility and maintainability. The `RFDetrExecutionPlan` class is updated to support independent selection of preprocessing, postprocessing, and other stages, while ensuring compatibility with environment variables. Documentation is also improved to clarify the architecture and its components, facilitating better user understanding and integration. * Change logging level from warning to info for RF-DETR preprocessor and postprocessor implementation selections to better reflect their significance in the inference process. * Enhance RF-DETR preprocessing architecture with compatibility checks and fallback mechanisms This commit introduces a new `CompatibilityResult` class to encapsulate the results of compatibility checks for preprocessing implementations. It adds methods for checking model and request compatibility across various preprocessors, ensuring that incompatible configurations are handled gracefully with declared fallbacks. The `resolve_preprocessor_for_model` and `resolve_preprocessor_for_request` functions are updated to utilize these compatibility checks, logging fallback reasons when applicable. Additionally, the documentation is updated to reflect these changes, improving clarity on how preprocessing selections are made and their implications for inference execution. * Enhance RF-DETR execution plan with compatibility fallback support This commit introduces the `allow_compatibility_fallback` parameter to the `RFDetrExecutionPlan`, enabling users to specify whether to allow fallback to a base implementation when an explicitly requested implementation is incompatible. The documentation is updated to clarify the implications of this setting, and the relevant selection functions are modified to respect this new parameter. Additionally, unit tests are added to validate the behavior of the fallback mechanism across preprocessing and postprocessing stages, ensuring robust handling of compatibility checks during inference execution. * Add independent stage execution option for RF-DETR model Enhance the RFDetrForObjectDetectionTRT class to support an independent stage execution mode. This allows public preprocessing to return a ready tensor without relying on the model's readiness state during the forward pass. Update documentation to reflect this new feature and provide usage examples. Add integration tests to ensure the new functionality works as expected, matching outputs with composed inference. The default behavior remains asynchronous to preserve existing optimizations. * Update RF-DETR execution plan defaults and enhance Triton compatibility checks - Change default preprocessor to `triton-universal-v1` and postprocessor to `triton-fused-v1` in the RF-DETR execution plan. - Update documentation to clarify the behavior when no explicit plan or environment overrides are provided. - Add compatibility checks in postprocessing and preprocessing classes to report Triton availability issues. - Enhance unit tests to validate the new default behavior and Triton dependency checks. * Enhance RF-DETR TensorRT execution with composable plans and independent stage execution - Updated RF-DETR TensorRT to default to `triton-universal-v1` preprocessing and `triton-fused-v1` postprocessing. - Introduced breaking changes for independent stage execution, requiring `independent_stage_execution=True` for callers using `pre_process()` and `forward()` separately. - Added documentation for new execution plan features, including environment variable controls and usage examples for independent stage execution. - Improved compatibility checks and metadata reporting for preprocessing and postprocessing implementations. * Implement thread-safe fallback warning de-duplication and enhance compatibility checks - Introduced `FallbackWarningTracker` to ensure each distinct fallback warning is logged only once per model instance, improving logging efficiency. - Updated RF-DETR model to utilize the new tracker for preprocessing and postprocessing fallback warnings. - Enhanced documentation to clarify the behavior of active preprocessing overrides and their impact on compatibility checks. - Added unit tests to validate the functionality of the fallback warning system and its thread safety. * Update version to 0.32.0 and revise changelog for new features - Bump project version in `pyproject.toml` to 0.32.0. - Update `uv.lock` revision to 3. - Document changes in `changelog.md`, including updates to RF-DETR TensorRT object detection and other enhancements. * Update inference-models version to 0.32.0 across all requirements files - Bumped the version of `inference-models` to 0.32.0 in `requirements.cpu.txt`, `requirements.gpu.txt`, `requirements.jetson.txt`, and `requirements.vino.txt` to ensure consistency across environments. * Use a release candidate for inference models * Update inference-models version to 0.32.0rc2 across all requirements files for consistency * Refine RF-DETR TensorRT execution and documentation for independent stage handling - Update changelog to clarify the backward compatibility of direct RF-DETR TensorRT stage calls, ensuring public `pre_process()` synchronizes by default. - Revise documentation to reflect the new default behavior of public preprocessing and its interaction with composed inference calls. - Enhance the `RFDetrForObjectDetectionTRT` class to streamline the handling of independent stage execution, removing the need for the `independent_stage_execution` parameter in the constructor. - Improve integration tests to validate the new behavior and ensure consistency across public stage calls. * Update inference-models version to 0.32.0rc3 in project files - Bump version in `pyproject.toml` and `uv.lock` to 0.32.0rc3 for consistency across the project. * Update inference-models version to 0.32.0rc3 across all requirements files for consistency * Update inference-models version to 0.32.0 in project files - Bump version in `pyproject.toml` and `uv.lock` to 0.32.0 for consistency across the project.
1 parent 4290a6e commit 752a4a0

46 files changed

Lines changed: 5736 additions & 85 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

inference_models/docs/changelog.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,25 @@ Add user-facing changes below using `### Added`, `### Changed`, `### Fixed`, or
66
`### Removed` subsections as appropriate.
77

88
---
9+
10+
## `0.32.0`
11+
12+
### Changed
13+
14+
- RF-DETR TensorRT object detection now selects `triton-universal-v1`
15+
preprocessing and `triton-fused-v1` postprocessing by default. Incompatible requests
16+
use the declared `base` implementation unless strict selection is requested through
17+
an explicit execution plan. The selected implementations can be controlled with an
18+
`RFDetrExecutionPlan` or the `INFERENCE_MODELS_RFDETR_PREPROCESSOR` and
19+
`INFERENCE_MODELS_RFDETR_POSTPROCESSOR` environment variables. No-op preprocessing
20+
override containers used by the inference server remain on the optimized path;
21+
active overrides use the declared fallback. Repeated occurrences of the same
22+
request-level fallback warning are logged only once per model instance.
23+
- Direct RF-DETR TensorRT stage calls remain backward compatible: public
24+
`pre_process()` synchronizes before returning by default, so its output is ready for
25+
an independent `forward()` call. Composed `model(...)` and `infer()` calls explicitly
26+
use the asynchronous exact-tensor readiness handoff to avoid a host synchronization.
27+
928
### Fixed
1029

1130
- SAM3 concept-segmentation postprocessing no longer scales its memory working set with
@@ -17,10 +36,15 @@ Add user-facing changes below using `### Added`, `### Changed`, `### Fixed`, or
1736

1837
### Added
1938

39+
- Composable RF-DETR TensorRT execution plans, implementation contracts and registries,
40+
compatibility-aware implementation selection, and runtime metadata reporting the
41+
requested and effective preprocessing and postprocessing implementations.
2042
- `segment_with_text_prompts` accepts `max_detections` (top-k by score, applied before mask
2143
interpolation; default `-1` = uncapped) and `mask_format` (`"dense"` default, or `"rle"`
2244
for COCO RLE at original resolution).
2345

46+
---
47+
2448
## `0.31.0`
2549

2650
### Fixed
Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
# Inference-Path Optimization Architecture
2+
3+
This guide explains how independently selectable inference-path implementations are
4+
described, selected, and executed. It first describes the reusable architecture and
5+
then maps it to the current RF-DETR TensorRT object-detection implementation.
6+
7+
The design keeps two concerns separate:
8+
9+
- **selection** decides which implementation is valid for a runtime;
10+
- **execution** runs the selected implementation without changing the model's semantic
11+
forward pass.
12+
13+
## Component overview
14+
15+
```mermaid
16+
flowchart TD
17+
selection["Selection inputs<br/>explicit plan / environment"]
18+
plan["ExecutionPlan<br/>stage IDs only"]
19+
catalog["Catalog<br/>metadata + constructors"]
20+
registry["ImplementationRegistry<br/>registered instances"]
21+
context["ExecutionContext<br/>device + scenario + resolved axes + stream"]
22+
contracts["Contracts<br/>metadata + compatibility + requests + results + protocols"]
23+
implementations["Implementations<br/>base and optimized choices in separate modules"]
24+
model["Model<br/>preprocess → protected forward → postprocess"]
25+
observable["Runtime observability<br/>selected IDs + resolved plan + metadata"]
26+
27+
selection --> plan
28+
plan -->|requested stage IDs| registry
29+
implementations -->|available classes| catalog
30+
catalog -->|constructs and registers| registry
31+
context -->|runtime constraints| registry
32+
registry -->|selected stage objects| model
33+
model --> observable
34+
35+
contracts -.->|defines plan shape| plan
36+
contracts -.->|defines resolution inputs| registry
37+
contracts -.->|defines stage interfaces| implementations
38+
```
39+
40+
### Contracts
41+
42+
Shared contracts define the stable language used by every optimized inference path.
43+
They include:
44+
45+
- `OptimizationMetadata`, including the stable implementation ID, stage, version,
46+
target, input constraints, dependencies, numerical behavior, stream behavior,
47+
output contract, fallback ID, and validation history;
48+
- `ExecutionContext`, which describes the actual device, scenario, resolved input
49+
axes, compute capability, and current stream;
50+
- the common `InferenceStage` compatibility protocol.
51+
52+
Stage-specific requests, results, and protocols stay in the model namespace because
53+
their signatures depend on that model's inputs and outputs.
54+
55+
Metadata is immutable and can be serialized with `to_dict()`. An implementation can
56+
therefore be inspected without executing it, and the resolved runtime configuration
57+
can be attached to profiling results.
58+
59+
### Catalog
60+
61+
The catalog is the inventory of available choices. It exposes read-only metadata maps
62+
for introspection and constructs a registry containing the corresponding runtime
63+
objects. It does not decide which choice should run.
64+
65+
Keeping construction in the catalog avoids importing one concrete implementation from
66+
another and gives the model a single place to assemble all available stages.
67+
68+
### Execution plan
69+
70+
An execution plan is an immutable collection of implementation IDs, one per selectable
71+
stage:
72+
73+
```python
74+
RFDetrExecutionPlan(
75+
preprocessor_id="triton-universal-v1",
76+
buffer_strategy_id="base",
77+
scheduler_id="base",
78+
postprocessor_id="triton-fused-v1",
79+
engine_plugin_id="base",
80+
allow_compatibility_fallback=True,
81+
)
82+
```
83+
84+
The plan contains choices, not implementation objects or mutable runtime state. This
85+
makes it suitable for configuration, logging, and comparison between profiling runs.
86+
87+
### Implementation registry
88+
89+
The registry owns the constructed stage objects and resolves a requested ID against an
90+
`ExecutionContext`. Resolution follows these rules:
91+
92+
1. `base` selects the preserved reference implementation.
93+
2. An explicit implementation ID selects that implementation when compatible. A
94+
declared compatibility miss may follow its observable `fallback_id`.
95+
3. `auto` selects a compatible implementation only when it has a matching validated
96+
environment; otherwise it selects `base`.
97+
4. Unknown IDs and failures during implementation execution never fall back.
98+
99+
Compatibility fallback is decided before execution and records the requested ID,
100+
effective ID, and reason. It does not catch compilation, CUDA, allocation, or other
101+
unexpected runtime failures.
102+
103+
The same policy applies to every selectable stage. Set
104+
`allow_compatibility_fallback=False` when an explicitly requested implementation must
105+
either run or raise. The default is `True`, which preserves the base inference path for
106+
contracts that an optimized implementation declares unsupported.
107+
108+
The catalog answers **what exists**. The registry answers **what may run here**.
109+
110+
### Implementations
111+
112+
Each implementation lives in its own module and depends on the shared contracts. Base
113+
implementations preserve the original behavior, while optimized implementations make
114+
their own compatibility checks before performing work.
115+
116+
Implementation-local state may include streams, events, reusable buffers, or bounded
117+
caches. That state belongs to the implementation object rather than the plan or
118+
metadata.
119+
120+
### Runtime observability
121+
122+
The resolved plan is the model-level plan that actually runs. Models expose both
123+
selected IDs and JSON-compatible selection metadata. The metadata records model-level
124+
and latest per-request requested/effective IDs plus any fallback reason, so profiling
125+
and validation output does not need to infer selection from environment variables or
126+
log messages.
127+
128+
## Current RF-DETR integration
129+
130+
The current implementation applies this architecture to RF-DETR TensorRT object
131+
detection. The TensorRT semantic forward pass remains protected and is not a selectable
132+
implementation.
133+
134+
### Model initialization and selection
135+
136+
```mermaid
137+
flowchart TD
138+
load["AutoModel.from_pretrained(...)"] --> init["RFDetrForObjectDetectionTRT.__init__"]
139+
init --> explicit{"Explicit RFDetrExecutionPlan?"}
140+
explicit -->|yes| use_plan["Use plan<br/>do not read selection environment"]
141+
explicit -->|no| precedence["Resolve each stage<br/>environment → optimized default"]
142+
use_plan --> requested["Requested RFDetrExecutionPlan"]
143+
precedence --> requested
144+
145+
requested --> build["build_rfdetr_implementation_registry<br/>(device, max_workers)"]
146+
147+
subgraph preprocessors["Preprocessor implementations"]
148+
pre_base["base"]
149+
pre_threaded["threaded-exact-v1"]
150+
pre_triton["triton-universal-v1"]
151+
end
152+
153+
subgraph postprocessors["Postprocessor implementations"]
154+
post_base["base"]
155+
post_triton["triton-fused-v1"]
156+
end
157+
158+
pre_base --> build
159+
pre_threaded --> build
160+
pre_triton --> build
161+
post_base --> build
162+
post_triton --> build
163+
164+
build --> resolve["Resolve preprocessor and postprocessor<br/>with ExecutionContext"]
165+
resolve --> store["Store resolved plan"]
166+
store --> metadata["Expose optimization_runtime_metadata"]
167+
```
168+
169+
Environment management remains available for clients that cannot pass new model
170+
arguments:
171+
172+
| Variable | Stage | Example value |
173+
|---|---|---|
174+
| `INFERENCE_MODELS_RFDETR_PREPROCESSOR` | preprocessing | `triton-universal-v1` |
175+
| `INFERENCE_MODELS_RFDETR_PREPROCESSOR_MAX_WORKERS` | threaded preprocessing | `4` |
176+
| `INFERENCE_MODELS_RFDETR_POSTPROCESSOR` | postprocessing | `triton-fused-v1` |
177+
178+
An explicit plan has the clearest provenance and takes precedence over environment
179+
variables. Environment values are read only when no plan is supplied. When neither an
180+
explicit plan nor environment overrides are present, RF-DETR selects
181+
`triton-universal-v1` preprocessing and `triton-fused-v1` postprocessing. A declared
182+
contract mismatch or unavailable Triton dependency follows the implementation's
183+
`base` fallback before execution.
184+
185+
### Per-request execution
186+
187+
```mermaid
188+
flowchart TD
189+
inputs["Image inputs<br/>NumPy or torch.Tensor<br/>CPU or CUDA"]
190+
invocation{"Invocation"}
191+
pre_request["PreprocessRequest + ExecutionContext"]
192+
pre_selected{"Selected Preprocessor<br/>compatible with request?"}
193+
pre_base["base / threaded exact<br/>synchronize before return"]
194+
pre_triton["Triton universal<br/>record CUDA ready event"]
195+
boundary{"independent_stage_execution?<br/>default: true"}
196+
independent["Synchronize producer<br/>do not register readiness"]
197+
readiness["PreprocessReadinessTracker<br/>associate readiness with exact tensor"]
198+
wait["TensorRT inference stream<br/>wait on ready event when present"]
199+
forward["Protected TensorRT forward"]
200+
outputs["Boxes + logits on CUDA"]
201+
post_request["PostprocessRequest + ExecutionContext"]
202+
post_selected{"Selected Postprocessor"}
203+
post_base["Base PyTorch path"]
204+
post_triton["Fused Triton path"]
205+
detections["list[Detections]"]
206+
207+
inputs --> invocation --> pre_request --> pre_selected
208+
pre_selected -->|base or declared fallback| pre_base
209+
pre_selected -->|compatible triton-universal-v1| pre_triton
210+
pre_base --> boundary
211+
pre_triton --> boundary
212+
invocation -.->|public pre_process: true| boundary
213+
invocation -.->|composed infer: false| boundary
214+
boundary -->|true| independent --> forward
215+
boundary -->|false| readiness
216+
readiness --> wait --> forward --> outputs --> post_request --> post_selected
217+
post_selected -->|base| post_base
218+
post_selected -->|triton-fused-v1| post_triton
219+
post_base --> detections
220+
post_triton --> detections
221+
```
222+
223+
`PreprocessReadinessTracker` is deliberately separate from tensors. It uses the exact
224+
tensor identity and a weak reference to transfer an optional CUDA event from
225+
preprocessing to the TensorRT consumer without adding dynamic attributes to framework
226+
tensors.
227+
228+
Public `pre_process()` calls default to `independent_stage_execution=True`: they
229+
synchronize their producer before returning and do not add a tracker entry. Composed
230+
`model(...)` and `infer()` calls explicitly pass `False`, allowing preprocessing to
231+
return asynchronously after associating its CUDA event with the exact output tensor.
232+
`forward()` always checks for such an entry and waits on its event when present; an
233+
independently prepared ready tensor has no entry and proceeds normally.
234+
235+
```python
236+
model = AutoModel.from_pretrained(
237+
"rfdetr-small",
238+
backend="trt",
239+
)
240+
preprocessed, metadata = model.pre_process(image)
241+
raw_predictions = model.forward(preprocessed)
242+
detections = model.post_process(raw_predictions, metadata)
243+
```
244+
245+
This is an invocation-boundary policy rather than an implementation choice, so it is
246+
not part of `InferenceExecutionPlan`. Safe standalone behavior is the public default;
247+
the composed inference path opts into the optimized asynchronous handoff internally.
248+
249+
The preprocessing, inference, and postprocessing streams are reused. Events express
250+
the GPU dependency at the consumer boundary; the protected TensorRT forward does not
251+
need to know which preprocessor produced its input.
252+
253+
### RF-DETR files and responsibilities
254+
255+
| Path | Responsibility |
256+
|---|---|
257+
| `models/optimization/contracts.py` | Reusable metadata, compatibility, runtime context, and base stage protocol |
258+
| `models/optimization/execution_plan.py` | Reusable immutable execution-plan representation |
259+
| `models/optimization/fallback_warnings.py` | Thread-safe per-model de-duplication of request fallback warnings |
260+
| `models/optimization/ids.py` | Conventional `base` and `auto` implementation IDs |
261+
| `models/optimization/registry.py` | Strict explicit and conservative automatic resolution |
262+
| `models/optimization/torch_readiness.py` | Generic one-shot state handoff tied to exact tensor identity |
263+
| `models/rfdetr/optimization/contracts.py` | RF-DETR requests, results, and stage-specific protocols |
264+
| `models/rfdetr/optimization/ids.py` | Stable implementation IDs and environment-variable names |
265+
| `models/rfdetr/optimization/execution_plan.py` | RF-DETR environment resolution and supported-stage validation |
266+
| `models/rfdetr/optimization/catalog.py` | Read-only metadata catalogs and registry construction |
267+
| `models/rfdetr/optimization/readiness.py` | RF-DETR readiness payload and shared-tracker adapter |
268+
| `models/rfdetr/optimization/preprocessors/` | One module per preprocessing choice |
269+
| `models/rfdetr/optimization/postprocessors/` | One module per postprocessing choice |
270+
| `models/rfdetr/rfdetr_object_detection_trt.py` | Plan integration and request-stage orchestration |
271+
272+
### Current boundaries
273+
274+
- Preprocessing and postprocessing have selectable implementations.
275+
- Buffer strategy, scheduler, and engine-plugin slots exist in the plan but currently
276+
accept only `base`. Selecting an unimplemented value raises an error.
277+
- `auto` remains on `base` until machine-readable validation records are added for a
278+
matching runtime environment.
279+
- Static model incompatibilities resolve the stored plan through the implementation's
280+
declared fallback. Request-only incompatibilities use the fallback for that request.
281+
- Fallback decisions are logged and carried with preprocessing readiness metadata;
282+
execution failures still propagate.
283+
- Target-device profiling and output-snapshot parity checks remain required before an
284+
optimized choice is promoted for automatic selection.
285+
286+
## Adding another implementation
287+
288+
1. Give the implementation a stable ID in `ids.py`.
289+
2. Add a separate implementation module that satisfies the stage protocol.
290+
3. Declare immutable compatibility and behavioral metadata.
291+
4. Reject unsupported explicit inputs with an actionable error.
292+
5. Register the implementation in `catalog.py`.
293+
6. Add contract, compatibility, numerical-parity, and selection tests.
294+
7. Profile and compare snapshots on the target device.
295+
8. Add validated environment records only after the target results justify automatic
296+
selection.
297+
298+
This sequence keeps a new optimization independently selectable, attributable in
299+
profiling, and removable without changing the semantic model forward pass.

0 commit comments

Comments
 (0)