Add ndd.compile.invariant#6429
Conversation
Signed-off-by: Rostan Tabet <rtabet@nvidia.com>
Signed-off-by: Rostan Tabet <rtabet@nvidia.com>
Signed-off-by: Rostan Tabet <rtabet@nvidia.com>
Signed-off-by: Rostan Tabet <rtabet@nvidia.com>
|
| Filename | Overview |
|---|---|
| dali/python/nvidia/dali/experimental/dynamic/compile/_invariant.py | New core invariant proxy type: lazy per-type proxy factory, correct dunder forwarding, thread-safe lazy cache, and recursive container unwrapping. Well-structured and carefully handles edge cases. |
| dali/python/nvidia/dali/experimental/dynamic/compile/init.py | New package init that re-exports invariant as the public API surface for ndd.compile.invariant. |
| dali/python/nvidia/dali/experimental/dynamic/_compile.py | Refactored record() matching to use per-value _value_matches helper; _matches now unwraps invariant before CompileRef checks; _wire_compile_graph unwraps invariants when building the DALI pipeline. Logic is correct. |
| dali/python/nvidia/dali/experimental/dynamic/_source_analysis.py | Key change: classify() no longer short-circuits on missing module_info, allowing invariant-tagged args to be captured even from exec()'d code; _is_explicit_invariant_expr added to walk CST for explicit invariant expressions; _is_name_invariant restructured to check runtime invariant marker first. Minor docstring inaccuracy. |
| dali/python/nvidia/dali/experimental/dynamic/_op_builder.py | _scalar_decay now starts with unwrap_invariants; reader init args, batch_size, rng, and convert_args loops all gain unwrap_invariant calls; the init_args/call_args split loop was refactored to thread the unwrapping correctly. |
| dali/test/python/experimental_mode/test_invariant.py | New unit tests for the invariant proxy: proxy behaviour, magic methods, recursive unwrapping, and API-level smoke tests. Tests validate correctness with assert_array_equal comparisons. |
| dali/test/python/experimental_mode/test_compile_invariants.py | New compile-path tests for invariant: module-level markers, parameter passing, list args, source-unavailable paths, and the removal-of-marker error. assert_compiled_matches_eager verifies pixel-level correctness. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
User["User code\n(angle = ndd.compile.invariant(x))"] --> Wrapper["_compile_intercept wrapper\nunwrap_invariant(batch_size)"]
Wrapper --> Classify["classify(frame, inputs, raw_kwargs)\n_Classifier(module_info, frame)"]
Classify --> CaptureArg["_capture_arg(node, value)"]
CaptureArg -->|"isinstance(value, CompiledBatch)"| CompileRef["CompileRef stored"]
CaptureArg -->|"is_invariant(value)"| StoreInvariant["Invariant proxy stored as-is"]
CaptureArg -->|"is_invariant(node) [static]"| StoreValue["Plain value stored"]
CaptureArg -->|"else"| Unresolved["_Unresolved → eager execution"]
StoreInvariant --> Record["record() in CompileContext\n_value_matches(actual, expected)"]
StoreValue --> Record
CompileRef --> Record
Record -->|"is_invariant(expected) & is_invariant(actual)"| TrustInvariant["Return True (unchecked promise)"]
Record -->|"is_invariant(expected) & not is_invariant(actual)"| RaiseError["RuntimeError: must remain marked"]
Record -->|"plain comparison"| EqualityCheck["actual == expected"]
TrustInvariant --> BuildPipeline["_wire_compile_graph\nunwrap_invariants on all inputs/kwargs"]
EqualityCheck --> BuildPipeline
BuildPipeline --> DALIPipe["DALI Pipeline\n(compiled)"]
Reviews (2): Last reviewed commit: "Test ndd.compile.invariant in transparen..." | Re-trigger Greptile
Category:
New feature (non-breaking change which adds functionality)
Description:
For an operator to be captured in transparent pipelining, we require all of its arguments to be either outputs of another captured operator or constants. We statically detect invariant function parameters, local variables and closure cells. However, it is not tractable to extend this static analysis to e.g. module globals or attributes.
This PR introduces
ndd.compile.invariant, which allows marking any variable as invariant in order for it to be blindly trusted during capture in transparent pipelining. This function returns a proxy object that tries to be as close as possible to the original object and is undistinguishable from it in most cases:Objects marked with
ndd.compile.invariantalso propagate their invariant property to their attributes, allowing for such cases:Additional information:
Affected modules and functionalities:
Dynamic mode, transparent pipelining
Key points relevant for the review:
Two things to review:
ndd.compile.invariantitselfTests:
Checklist
Documentation
DALI team only
Requirements
REQ IDs: N/A
JIRA TASK: DALI-4818