Repository navigation
Accept containers of tensors as Nx.block arguments - #1895
Merged
polvalente merged 5 commits intoOct 26, 2026
Merged
Conversation
polvalente
requested changes
Oct 24, 2026
polvalente
left a comment
Member
There was a problem hiding this comment.
I believe this makes for a confusing interface. Does block accept a container as one of the arguments? If not, then that's the proper fix, I believe
A block's default implementation receives the struct and then one argument per input, so a block with hundreds of inputs ran into the 255-argument limit on Erlang functions. An argument may now be a tuple, map or other container of tensors, which lets such a block take all of its inputs as one argument. The block node stores the arguments as written. The tracer creates one body parameter per tensor inside a container in traversal order and gives the function containers of parameters, tracking vectorized axes per tensor. Tree.apply_args, the Evaluator, Graph and inspect traverse containers and leave keyword options alone. EXLA flattens the arguments into the compiled function's parameters in the same order. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
blasphemetheus
force-pushed
the
feat/block-list-callback
branch
from
October 25, 2026 18:29
f1d4285 to
68367b6
Compare
Adds an Nx.block example with a tuple argument, checks a boolean output alongside the vectorized container case, and trims a tracer comment that repeated the docs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
blasphemetheus
marked this pull request as ready for review
October 25, 2026 18:39
This was referenced Oct 25, 2026
Closed
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
EXLA.Backend.block split the arguments on tensor structs, so a container argument fell into the trailing options and reached the tracer as a closure. Split on keyword lists instead, pick the client from the tensors inside the containers, and clear the donatable flag inside them as well. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
polvalente
approved these changes
Oct 26, 2026
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.
Nx.block/4now accepts a container of tensors, such as a tuple or a map, as an argument.A block's default implementation receives the struct and then one argument per input, and an Erlang function cannot take more than 255 arguments. A block with hundreds of inputs, such as a checkpointed group of layers whose weights all arrive as block arguments, could not be written. With containers, those inputs are passed as a single tuple or map, and the callback keeps its one-argument-per-input shape:
This is part of the gradient checkpointing work in #1865. It replaces the list-form callback this PR first proposed, following the review suggestion to accept a container instead.
How it works
The block node keeps its arguments as the user wrote them, containers included. Everything that walks the arguments walks into the containers:
Nx.Defn.Tree.apply_args/4, the Evaluator,Nx.Defn.Graphand inspect traverse containers and leave keyword options alone.EXLA.CustomCallsee the arguments as written.Nx.block/4and the Evaluator pick the backend from the tensors inside the containers.Backends that run the default implementation with
apply(fun, [struct | args])need no change, since the containers pass straight through to the function. The gradient re-traces the body from the stored arguments, so it needs no change either.Tests
Nx: a map argument alongside a tensor, a tuple with a vectorized entry, a gradient through a tuple argument, a tuple of 300 tensors forward and gradient, and a graph split whose boundary runs through a container argument. EXLA: a tuple with a vectorized entry forward and gradient, and a tuple of 300 tensors. Full Nx suite and EXLA block tests on host pass.
🤖 Generated with Claude Code