Repository navigation
Conversation
Every concrete schedule tree node type now has a factory that builds a tree containing it, mostly by converting a small SDFG, and the tree is converted back into a validated SDFG. Node types whose conversion is not yet supported are strict xfails, so they must be removed from the list once supported. Also adds a roundtrip helper that compares the outputs of the original and the converted SDFG. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…schedule trees to SDFGs Exit gotos and state-if scopes raised NotImplementedError in StreeToSDFG. Returns inside nested SDFGs were also flattened into exit gotos, which exit the whole program instead of only the nested SDFG. SDFG to schedule tree: * A flattened nested SDFG that exits early now ends with a unique label, and its exits become gotos to that label. * Break and continue blocks become break and continue nodes. * The negated condition of exit state-ifs is now a well-formed code block. * StateLabel may hold a label name instead of a state. Schedule tree to SDFG: * Forward gotos are first removed by moving the statements after a conditional into the branches that do not jump. * Remaining gotos to the end of the SDFG being built become return blocks. * Otherwise, the statements up to the label are converted into a nested SDFG (outside of maps as well), in which the gotos become return blocks. * State-if scopes are converted like if scopes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
General blocks raised NotImplementedError in StreeToSDFG, and the trees produced for them could not be converted back: only the start state of a region was labeled, so gotos to other blocks had no target, and the start block was not necessarily first. SDFG to schedule tree: * Every block of a general block is preceded by its label, starting with the start block. * Conditional transitions are emitted before unconditional ones. * Labels in general blocks are kept even if no goto jumps to them. * Duplicate labels of all control flow blocks (not just states) are renamed. Schedule tree to SDFG: * A general block becomes an unstructured control flow region with one state per labeled segment. Gotos to its labels become inter-state edges, and statements after conditional gotos run in a state reached by the negation of their conditions. Falling off the end of a segment exits the region, and unreachable segments are removed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Consume scopes raised NotImplementedError in StreeToSDFG. SDFG to schedule tree: * The consumed stream is emitted as a dynamic scope input (IN_stream) before the consume scope. Schedule tree to SDFG: * Map and consume scopes share the same conversion. Reads of the consumed stream inside the scope use the entry's OUT_stream connector. Without a stream input, the stream is inferred from the code nodes in the scope. * Code generation supports only one read of the consumed element, and the element cannot be passed into a nested SDFG under the stream's name. In those cases, the element is first copied into a new scalar, which the rest of the scope reads. * Copies into streams are described on the stream, as code generation expects for pushes. * Nested SDFGs can now also be created for part of a dataflow scope. Also fixes two issues found along the way: * The state boundary analysis treated a node that reads and writes the same data as racing with itself. Maps like A[i] = A[i] + 1 were therefore converted into nested SDFGs. Reads are now only considered racy if they are not performed by an ancestor of the writing node. * is_array_stream_view raised IndexError for a stream that is filled from an array and consumed by code through the same access node. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… nested SDFG views from schedule trees * Empty map scopes raised IndexError. Their entry is now connected directly to their exit. * References set by the output of a tasklet or library node raised NotImplementedError. The output is now connected to the reference's set connector instead of being written as regular data. * Symbol assignments at the end of an if/elif/else or loop body were performed after the conditional or loop (or raised NotImplementedError). They are now performed at the end of the body. * Nested SDFG views (NView to NViewEnd) were only applied within the nested SDFGs created for map scopes, so accesses outside of maps used the un-viewed container. Their regions are now converted into nested SDFGs. With this, every schedule tree node type is converted in the coverage test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Converting an SDFG to a schedule tree and back lost SDFG-level metadata and named regions. * Schedule tree roots now store global, init, and exit code blocks, which are merged per code generation target from all nested SDFGs, and are written back to the SDFG. * The callback mapping (merged from nested SDFGs) and argument names are now filled in and written back. * Named regions become NamedRegionScope nodes, which are converted back into named regions. Function call regions remain flattened. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Control flow raising lifts irreducible control flow into an UnstructuredControlFlow region, which InlineControlFlowRegions then inlined again, so SDFG.simplify() never converged on such SDFGs. Add a no_inline_unstructured option (enabled by default), like the existing options for loops and conditional blocks. The sibling loops test is simplified as well. Its loop body continued unconditionally next to the conditional jump into the second loop, which is ambiguous: dead state elimination removed the jump. The body now continues only if the jump is not taken. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… test All schedule tree node types are converted to SDFGs now, so the list of expected failures is empty. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
StreeToSDFG raised NotImplementedError for StateBoundaryBehavior.EMPTY_MEMLET. With that behavior, state boundaries that neither precede control flow nor perform symbol assignments are now kept within the state. Nodes after such a boundary are ordered after the nodes before it: every top-level sink before the boundary gets an empty memlet edge to every top-level source after it (scopes are represented by their exit and entry nodes). Writes after a boundary use new access nodes, so that the edges cannot form cycles. Dataflow scopes with boundaries still become nested SDFGs, and the boundary before such a nested SDFG remains a state transition. The behavior can be selected in ScheduleTreeRoot.as_sdfg. Also fixes the state boundary analysis, which did not register the reads and writes of the node right after an inserted boundary. A subsequent conflicting write therefore got no boundary, e.g., for three consecutive writes to the same element (as produced by nested SDFGs with multiple states). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Resolve the conflict in the state boundary analysis in favor of main (#2611), which fixes the same missing registration of the node after an inserted boundary and also checks that previous writes are ordered before the node through the dataflow. Update the scalar connector dealiasing tests from main (#2608) to the trailing StateLabel that nested SDFG exits now jump to on this branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…flow New package dace/frontend/ml/torch/dynamo registers a 'dace' torch.compile backend. ATen graphs from AOTAutograd (with an Inductor-style decomposition table) are lowered into a DaCe schedule tree and converted to an SDFG: - Dynamo shape/stride symbols become DaCe symbols (one SDFG per guard set, no recompilation across shapes or strides) - pointwise ops with broadcasting, casts, fills, arange; reductions via the Reduce library node; mm/bmm/addmm via BLAS MatMul; views via ViewNode - torch.cond / while_loop / scan / map lowered to IfScope / WhileScope / ForScope (native ConditionalBlock / LoopRegion in the SDFG) - runtime wrapper allocates outputs as torch tensors and calls the SDFG Exposed as dace.ml.compile(); tests in tests/torch_dynamo. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ransformer block - Allocate every container with the FakeTensor's (symbolic) strides: FX view metadata is relative to torch's layout (clone/pointwise preserve stride order), so contiguous allocation broke permute->clone->permute chains. Returned tensors now also match torch's expected strides. - keepdim reductions write through a view of the final container. - Native lowerings for split/split_with_sizes/unbind/narrow and a real as_strided lowering that honors storage_offset (split decomposed to it). - Skip identity views (full-range slices); prims.var/sum/amax, any/all, prims pointwise aliases, sym_float/sym_int, float-valued shape exprs. - Rename ops/symbolic.py to ops/symint.py to avoid confusion with dace/symbolic.py (which is untouched; torch stays optional). - M2 tests: views/slices, softmax+layer_norm, bmm, SDPA, encoder block. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- convolution (N-d, stride/padding/dilation/groups) as a zero-padded copy
plus nested maps accumulating with a WCR sum; bias folded into the init
- max_pool{1,2,3}d_with_indices / avg_pool as one map per output element
with the static window unrolled into memlets (-inf/0 padded input)
- index.Tensor (embedding, index_select, advanced indexing with one index
tensor) and gather via indirect memlets; argmax/argmin as Reduce + WCR-min
map (no loops inside tasklets)
- translate torch's own sympy Max/Min in shape expressions
- M4 tests: conv1d/2d (groups, dilation), pooling, embedding/gather/argmax,
LeNet compiled once across batch sizes
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds doc/frontend/torch_dynamo.rst (usage, lowering overview, limitations)
to the user guide and frontend.torch_dynamo.{simplify,onnx_fallback}
configuration defaults consumed by DaceBackend when not given explicitly.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ort graphs) Dynamo decomposes linear before the backend sees it, but torch.export's IR keeps aten.linear unless the decomposition table contains it. Verified that exported programs now import through GraphImporter with parameters as inputs and Dim sizes as symbols. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ExtUnparser special-cases numbers.Number for NumPy 2 scalars, but numpy.bool_ is not a Number, so a constant-propagated bool (e.g. from torch.zeros_like on a bool scalar) was unparsed as 'np.False_' and broke generated C++. Also normalize numpy scalars in the Dynamo frontend's tasklet literals. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ed dimensions, torch.export Dim) Dynamo alone decides which sizes are symbolic (duck shaping, 0/1 specialization) and names them s0, s1, ... dace.ml.compile(model, dynamic_shapes=...) gives that control to the user with torch.export's vocabulary: 'all' makes every dimension of every argument its own symbol (weights stay static) and a per-argument specification names dimensions (strings or Dim objects with bounds). The names become the DaCe symbol names. Requires torch >= 2.13 (pinned in the ml extra). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… ATen semantics - amax/amin (and max/min, argmax/argmin, softmax via amax) passed identity=None to Reduce, which then folds into the uninitialized output: results depended on leftover memory. Use the dtype's -inf/inf (or integer/bool extremes). - Tensor constants of the graph (get_attr, e.g. torch.tensor([...]) in the program) crashed under fake mode and were never passed at runtime. They are now transient containers that are also compile-time constants of the SDFG (ScheduleTreeRoot.constants -> SDFG.constants_prop); the unused constant-input path of the runtime is removed. Constant arrays now emit bool and non-finite elements as valid C++ literals. - round rounds half to even (rint); integer floor division floors (py_floor); maximum/minimum/clamp/relu propagate NaN, fmax/fmin ignore it. - sym_storage_offset returns the tensor's storage offset instead of 0. - Remove unused imports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ependent capture tests - torch 2.14 wraps fake-tensor errors raised during speculation in FakeTensorObservedException, a subclass of the ObservedException passthrough, so a failed capture was re-raised instead of falling back. Such errors now take the fallback path: the jump is blacklisted and the frame's analysis restarts (re-raising made Dynamo skip the whole frame), so the stock handler graph-breaks there on the next pass. - The capture tests no longer depend on CPython code generation (supported versions are 3.10-3.14; e.g. 3.10/3.12/3.14 copy small exit blocks into break sites). Each test asserts with dis the instruction pattern it exercises (jump out of the loop, early return, back-edges), and new tests cover break and continue separately. - Remove unused imports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Python 3.12/3.13 end a rotated while loop with `POP_JUMP_IF_FALSE exit; JUMP_BACKWARD body`, so the loop test at the bottom of the body has no successor equal to the loop entry and was not recognized as the back-edge (3.10/3.11 jump back conditionally, 3.14 re-evaluates the single loop test). Jump successors are now compared after following unconditional jumps and no-ops, which makes the three layouts equivalent. The capture tests pass on 3.10 through 3.14. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
capture(module_or_fn, *args) returns the functional ATen graph that Dynamo and AOTAutograd produce (fullgraph, inference) without compiling or executing it: the capturing backend stops after AOTAutograd's forward graph. The result records the source of every graph input (argument, parameter, buffer, module attribute, global, or tensor size/stride, with names matching named_parameters()), Dynamo's guards, and the shape assumptions and symbol ranges. CapturedProgram builds the SDFG, binds inputs from their sources (parameters by reference), and can compile itself. The torch.compile backend describes its graphs the same way, so SDFG arguments are now named after their sources (x, fc1_weight, ...) instead of FX placeholders. Symbol naming moves from shapes.py to the new sources.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A module found in a program's closure is wrapped in an SDFG-convertible adapter and captured with TorchDynamo for the data descriptors of the call site: symbolic sizes keep their DaCe names, integer arguments become symbols, and the outputs are returned as __return arrays. Parameters and buffers are closure arrays passed by reference. Dynamo's guards on the module (attribute values such as training, submodule types) and on global state become part of the program's cache key through a new SDFGConvertible.__sdfg_guards__ hook, which DaceProgram collects after parsing and evaluates on every call, so a change re-parses the program. Also make create_datadescriptor recognize torch.Tensor subclasses such as nn.Parameter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…G-convertible objects - Lists, tuples, and dicts passed to an SDFG-convertible object now reach __sdfg__ as structures of data descriptors (string-literal dict keys become strings) instead of container names, and their elements bind to separate arguments of the returned SDFG (xs[0] -> xs_0, d['w'] -> d_w; see structured_argument_name). - Closure arrays that a convertible only reports in __sdfg_closure__ after conversion (i.e., not through closure_resolver during preprocessing) were added to the SDFG but never passed at call time. They now join the program's closure with an evaluator that queries the convertible on every call, and their descriptors are part of the cache key. The new tests use plain-Python convertibles; the guard test also covers the __sdfg_guards__ hook of the previous commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tes in modules used by @dace.program Modules called from a @dace.program can now take lists, tuples, and dicts of arrays (captured with nested example values and named as the Python frontend binds the elements), and may read global tensors or plain tensor attributes: those become closure arrays reported after conversion and are re-evaluated on every call. Shape guards are simplified with the shape environment's replacements before translation, which removes spurious warnings about sizes that Dynamo unified. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_is_slice accepted any View whose strides all appear among the Array's strides, including permutations such as a transpose (strides (1, n) of an array with strides (n, 1)). RedundantReadSlice and RedundantWriteSlice then rewrote the memlets without permuting their subsets, so a copy through a transposed view copied the untransposed data. A slice must keep the order of the Array's dimensions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
….compile) AOTAutograd's backward graphs were run eagerly; they are now lowered and compiled like the forward graphs (each with the symbol names of its forward graph, bound at forward time since AOTAutograd may compile the backward lazily). - New lowerings for backward operators: convolution_backward (input, weight, and bias gradients as maps with write-conflict resolution), max-pool backward (scatter through the saved indices), and index_put with one index tensor (accumulating, e.g., embedding gradients). - Attention is traced with the math SDPA kernel, so its backward consists of operators the frontend lowers instead of the fused CPU flash-attention backward. - CompiledGraph takes AOTAutograd's boxed calling convention (as an instance attribute, which survives AOTAutograd's functools.wraps wrappers) and still accepts positional inputs. Tests compare outputs and gradients with eager PyTorch for MLPs, layer norm with softmax, a CNN (padding, stride, groups, max-pool), a transformer block, and an embedding with repeated tokens, compiling forward and backward once across sizes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ion connectors, and cast stripping - Conditional tasklets: the condition of `out = a if cond else b` (also wrapped in a cast) or `if cond: out = a` may now be any expression of the tasklet's inputs, not only a boolean input connector. The code is parsed with ast instead of regular expressions, the backward tasklet reads every connector the condition uses, the branches may read different inputs, and only tasklets that read a boolean array take the conditional-array-assignment path. - Data forwarding no longer asserts when a tasklet reads the same array through two connectors (e.g., `x * x`); the path into the backward map is shared. - ReverseReduce swapped the required and given gradient connector names. This was invisible with unnamed connectors (as the NumPy frontend creates them) and failed for Reduce nodes with named `_in`/`_out` connectors. - Casts were stripped with a non-greedy regular expression that ended at the first closing parenthesis, so `dace.float64((a - b) * (a - b))` was differentiated as `a - b*(a - b)`. They are now removed with an AST transformation, which also covers floating-point casts spelled with C type names (`double(...)`, `float(...)`). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The expansions communicate a count of elements from a pointer. Simplification may hand a collective a strided view (e.g., a transpose) in place of the contiguous copy a frontend wrote, and a packed permutation is contiguous memory but not in row-major order. pack_noncontiguous_buffers routes such buffers through contiguous transients, with one transient for in-place buffers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI runs the MPI tests on two ranks. The subgroup of every rank but the last has one member there, and send/recv runs over the world in reverse order, so communicator ranks still differ from world ranks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ibrary nodes Dynamo rewrites torch.distributed calls into _c10d_functional operators. They now lower to dace.libraries.comm nodes: - all_reduce(_coalesced), all_gather_into_tensor(_coalesced), reduce_scatter_tensor(_coalesced), broadcast and all_to_all_single (even splits as Alltoall, uneven as Alltoallv), including the autograd-aware variants of backward graphs; collectives are blocking, so wait_tensor of their results is the identity. - isend, irecv and batch_p2p_ops (TORCHDYNAMO_ENABLE_P2P_COMPILATION=1) as Isend/Irecv; wait_tensor emits the Wait, which orders the readers of a received tensor after it. Programs communicate over the communicators of torch's process groups, taken as arguments (dace_comm_<group>_<backend>) and supplied by the runtime from a per-process cache (dynamo/distributed.py): NCCL for GPU tensors, bootstrapped over the process group itself (no MPI, works under torchrun); MPI for CPU tensors, over the MPI ranks of the group. Tests (tests/torch_dynamo/test_distributed.py, under mpirun with a gloo process group) cover in-place all_reduce (sum/avg/max), gather/scatter/broadcast of a strided view, even and uneven all-to-all, a subgroup, a ring exchange and training through the autograd collectives. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The c_char array field stopped at the first zero byte of the binary ID. Tested on a GPU: collectives and a self-exchange over an NCCL communicator created in Python, with no MPI in the program. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AOTAutograd desugars DTensors into local tensors and functional collectives, and passes the DeviceMesh of each DTensor in and out of the graph as an opaque object so that it can rewrap the results. The importer binds such inputs as constants and returns them as the arguments themselves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rank 0 broadcasts its compilation error instead of a build folder, and the final barrier becomes an exchange of load outcomes, so a failure no longer leaves the other ranks waiting. A rank that holds an SDFG checks that it is the one rank 0 compiled. Only Get_rank, bcast and allgather are used, so non-mpi4py communicators work too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
aten.constant_pad_nd lowers to a fill and a copy of the kept part of the input; negative amounts narrow it. Symbols get the sign Dynamo's value ranges give them: a symbolic Python integer (e.g., a padding amount) may be negative, and assuming otherwise simplified Max(-pad, 0) to 0 and wrote out of bounds. Strides torch writes as Max(1, n) become n, so contiguous layouts are recognized (the all-gather of an unevenly sharded DTensor). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DaceBackendOptions.distributed_compilation (and the capture/export options) compiles on rank 0 and loads the build on the other ranks through dace.sdfg.utils.distributed_compile, over the default process group (so torchrun programs work without MPI). A failure on any rank, or a program that differs from rank 0's, raises on every rank. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Allreduce, Allgather, ReduceScatter, Bcast, Alltoall and Alltoallv derive from NonblockingCommNode, whose nonblocking property starts the operation and writes a request that a Wait completes. MPI calls the MPI_I* variant (Alltoallv keeps its count arrays alive until completion); NCCL launches the operation right away and tracks its stream for the Wait, with a token request. Nonblocking nodes need contiguous buffers (a packed copy would not outlive the operation), and MPI cannot average without blocking. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dace.libraries.comm.schedule.overlap_communication moves nonblocking starts as early, and their waits as late, as data, symbol and view dependencies allow within each scope; a wait inherits the buffers of the starts whose requests it completes. Starts keep their order relative to other starts and blocking operations (collectives start in the same order on every process), and waits keep theirs. Every communication node then gets a state of its own, which state fusion keeps (communication has side effects), so code generation runs start, independent work and wait in this order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A start moves ahead of the work before it together with the nodes it depends on, so that independent work that precedes its producers also runs while the communication is in flight; a wait likewise moves behind the work that does not depend on it. Relative orders within each group are kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collectives lower to nonblocking comm nodes whose wait_tensor emits the Wait (MPI averages reduce the sum, and the wait divides), like point-to-point operations; every Wait reads all buffers of its operation, so transients live until it. The importer runs dace.libraries.comm.schedule .overlap_communication on the schedule tree of graphs that communicate, so that independent work runs between start and wait. DaceBackendOptions.overlap_communication=False keeps blocking collectives. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A collective runs asynchronously on the stream of its node already, so a nonblocking one is launched right away like any other and needs no request, stream tracking or Wait: code generation orders its readers on the device and runs independent work on other streams. A Wait (and Waitall) connected to GPU memory makes its stream wait for the pending point-to-point streams through events, instead of synchronizing them on the host, which also keeps code generation from forcing it onto the default stream. Isend accepts ordering output connectors, so that a send can be ordered before its wait through the sent buffer: a request or token in host memory makes the host wait for the stream. The overlap pass leaves NCCL nodes in the states of their neighbors, whose end would make the host wait for them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collectives on GPU tensors lower without a request or Wait: they run on the stream of their node, whose readers code generation orders on the device. Point-to-point operations have no requests either (a token in host memory made the host wait for the stream): a send writes its buffer through an ordering connector, which its Wait reads. MPI keeps nonblocking operations with requests and waits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Packing copies into and out of contiguous buffers are ordered on the GPU stream of the node, so stream-ordered (NCCL or RCCL) expansions pack the strided buffers of a nonblocking node like those of any other; only MPI, whose Wait completes the operation later, still requires contiguous buffers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The requirement that a nonblocking node have contiguous buffers holds for MPI only, so it moves out of pack_noncontiguous_buffers (and its stream_ordered escape hatch) into NonblockingCommNode.validate_nonblocking, which the MPI expansions call before packing, together with the request check. NCCL/RCCL expansions pack as for any node. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main replaced all_states() with a recursive states() (#2652). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…states() A one-rank gloo group bootstraps NCCL in a single process, so the GPU test needs no MPI. Main replaced all_states() with a recursive states() (#2652). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ept sliced operands
dace.libraries.ml.Convolution gets an ``activation`` property ('none'/'relu'). The pure expansion applies it while
writing the result; cuDNN uses cudnnConvolutionBiasActivationForward (with a zero bias from the plan when the layer
has none) and MIOpen a compiled fusion plan, both falling back to the separate calls when the library does not support
the configuration. FuseConvolutionActivation folds a ReLU map that is the only reader of a convolution's result into
the node, also when the map writes a slice of a concatenation; the convolution nodes therefore size their operands by
the memlet subset instead of the whole container. The TorchDynamo frontend applies the fusion when
``fuse_activations=True`` is passed to dace.ml.compile or dace.ml.to_sdfg (off by default until the fused vendor
kernels are measured broadly); the ATen Convolution wrapper carries the property.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requires #2590