Add ndd.compile.invariant - #6429
Conversation
Signed-off-by: Rostan Tabet <rtabet@nvidia.com>
|
| Filename | Overview |
|---|---|
| dali/python/nvidia/dali/experimental/dynamic/compile/_invariant.py | New module implementing the invariant proxy. Proxy type caching, dunder forwarding, descriptor handling, and recursive container unwrapping are all correct. Minor variable-shadowing style issue in _DunderForwarder.call for the setitem branch. |
| dali/python/nvidia/dali/experimental/dynamic/_source_analysis.py | _Classifier now accepts None module_info, falling back to node=None for all positional/keyword args so that CompiledBatch and explicitly-invariant values are still captured even from exec'd or unavailable source. Logic is correct and covered by test_invariant_marker_without_source. |
| dali/python/nvidia/dali/experimental/dynamic/_compile.py | _value_matches correctly handles invariant vs plain, invariant vs invariant (trusted), and plain vs plain. record() matching replaces the old single-expression equality with per-element _value_matches calls. _wire_compile_graph unwraps invariants before CompileRef check and None-filters correctly. |
| dali/python/nvidia/dali/experimental/dynamic/_batch.py | unwrap_invariant_args added at all relevant entry points (Batch.init, Batch.broadcast, batch(), as_batch()); unwrap_invariants applied before np.array() calls on sample data. |
| dali/python/nvidia/dali/experimental/dynamic/_op_builder.py | unwrap_invariant applied at batch_size, device resolution, rng, and tensor-arg conversion points. The init_args/call_args loop refactor correctly preserves None-filtering semantics. |
| dali/test/python/experimental_mode/test_invariant.py | New unit tests cover None/int/str/list/type values, attribute propagation, method re-binding, dunder forwarding, recursive unwrapping, and ndd API integration. |
| dali/test/python/experimental_mode/test_compile_invariants.py | New compile-integration tests cover invariant in expressions, as a parameter, in a list, from exec'd code, mixed with globals (expect_captured=False), and removal-of-marker RuntimeError. |
Sequence Diagram
sequenceDiagram
participant User
participant invariant as ndd.compile.invariant
participant Proxy as _InvariantProxy
participant Classifier as _Classifier
participant CompileCtx as CompileContext
User->>invariant: invariant(value)
invariant->>Proxy: _make_proxy_type(type(value))
Proxy-->>User: proxy wrapping value
Note over User,CompileCtx: Tracing phase (first iteration)
User->>CompileCtx: "ndd.rotate(images, angle=proxy)"
CompileCtx->>Classifier: classify(inputs, kwargs)
Classifier->>Classifier: _capture_arg(node, proxy)
Classifier->>Classifier: _is_explicit_invariant(proxy) → True
Classifier-->>CompileCtx: "kwargs[angle] = proxy (invariant)"
CompileCtx->>CompileCtx: record() → store node with invariant kwargs
Note over User,CompileCtx: Replay phase (subsequent iterations)
User->>CompileCtx: "ndd.rotate(images, angle=proxy2)"
CompileCtx->>CompileCtx: get_compiled_result()
CompileCtx->>CompileCtx: _matches(proxy2, proxy_expected)
CompileCtx->>CompileCtx: _value_matches → both invariant → True
CompileCtx-->>User: cached compiled result
Note over User,CompileCtx: Error case: marker removed
User->>CompileCtx: "ndd.rotate(images, angle=plain_value)"
CompileCtx->>CompileCtx: _value_matches(plain, invariant) → RuntimeError
Reviews (3): Last reviewed commit: "Test ndd.compile.invariant in transparen..." | Re-trigger Greptile
| raise RuntimeError( | ||
| "An argument marked with ndd.compile.invariant when captured must remain marked." | ||
| ) | ||
| return True |
There was a problem hiding this comment.
Do we care if actual == expected?
There was a problem hiding this comment.
Marking a variable with ndd.compile.invariant asserts that the value won't change. This allows us to avoid to check for equality, which can be quite expensive for some types.
|
!build |
|
CI MESSAGE: [59986947]: BUILD STARTED |
|
CI MESSAGE: [59986947]: BUILD PASSED |
Signed-off-by: Rostan Tabet <rtabet@nvidia.com>
Signed-off-by: Rostan Tabet <rtabet@nvidia.com>
Signed-off-by: Rostan Tabet <rtabet@nvidia.com>
|
!build |
81eb017 to
5d8f694
Compare
|
CI MESSAGE: [60098020]: BUILD STARTED |
|
CI MESSAGE: [60098020]: BUILD PASSED |
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