Skip to content

Conversation

digantdesai
Copy link
Contributor

Rationale:

* We want to support stateful custom ops inserted after to_edge in a non delegated cases like op-lib-backends i.e. cortex-m::cmsis_nn::linear

Details:

* Allows a pass to add a mutable buffer.
* Essentially redoes what export, to_edge does for a buffer registered in an nn.module.
* Also plays nice with to_executorch passes like conversion to in-place, and write-back for mutated buffers.
* Verifies above with tests, adds a HelperPass for someone looking to leverage this util as an example too.

To Test:

$ python -m unittest backends.transforms.test.test_create_mutable_buffer

Copy link

pytorch-bot bot commented Aug 29, 2025

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/13813

Note: Links to docs will display an error until the docs builds have been completed.

✅ No Failures

As of commit c6bb918 with merge base 6c12956 (image):
💚 Looks good so far! There are no failures yet. 💚

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 29, 2025
Copy link

This PR needs a release notes: label

If your change should be included in the release notes (i.e. would users of this library care about this change?), please use a label starting with release notes:. This helps us keep track and include your important work in the next release notes.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "release notes: none"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

@digantdesai digantdesai force-pushed the mutable_buffers branch 2 times, most recently from dbbd892 to 311eba6 Compare September 2, 2025 21:25
Copy link
Contributor

@mergennachin mergennachin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


if not user_input_indices_or_consts:
# If no user inputs or constants exist, insert at the end of all existing inputs
node_index = len(exp_program.graph_signature.input_specs)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused in this if block

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is used outside the block

)
return executorch_program_manager

def _test_eager(self, model, example_inputs, num_lifted_args=1):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont follow what this is doing for eager?

Copy link
Contributor Author

@digantdesai digantdesai Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eager might be a bad name, but the idea is to compare the ExecuTorch graph from two different origins for a mutable buffer (1) written in torch.nn.Module by the end user as in eager mode, and (2) inserted via this util + pass, and both ET graphs should be indistinguishable in every way.


self.compare(et_1, et_2, example_inputs)

def test_basic_with_param(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are you testing when you dont have any inputs in the graph? there is a path for that in your pass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I follow. x is the normal input, and I am adding a param (beyond the test_basic module) to test if the signature update is correct.

Copy link
Contributor

@kimishpatel kimishpatel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks pretty good. left some comments

)

# Find indices of user inputs and constant tensors
user_input_indices_or_consts = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like a loop would be a cleaner way of writing this through line 324.

Since you have validated the Spec.kind and the nodes earlier you could just loop over the input_specs and index into graph.nodes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refactored but still not as clean as I like.

@JacobSzwejbka
Copy link
Contributor

JacobSzwejbka commented Sep 3, 2025

@angelayi @avikchaudhuri @tugsbayasgalan

I think in general it would be a good value add from compiler if these sorts of primitive graph operations lived in core.

Things like node.is_mutable_buffer(), ep.add_buffer() ep.add_mutable_buffer() etc

Copy link
Contributor

@JacobSzwejbka JacobSzwejbka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.

@digantdesai digantdesai force-pushed the mutable_buffers branch 2 times, most recently from 332edae to 918b70b Compare September 5, 2025 10:30
@mergennachin
Copy link
Contributor

@digantdesai see my previous comment #13813 (review)

@digantdesai
Copy link
Contributor Author

@digantdesai see my previous comment #13813 (review)

separate PR?

if modified:
graph_module = super().call(graph_module).graph_module
graph_module.graph.lint()
graph_module.graph.eliminate_dead_code()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this fn is technically unsafe to call if the graph is not functional.


example_node = nodes[0]
if isinstance(
example_node.meta["val"], (tuple, torch.fx.immutable_collections.immutable_list)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like a bit of a strange check. Is this robust?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm just refactored in this PR.. but what else it can be when number of tensors > 1?

Copy link
Contributor Author

@digantdesai digantdesai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


example_node = nodes[0]
if isinstance(
example_node.meta["val"], (tuple, torch.fx.immutable_collections.immutable_list)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm just refactored in this PR.. but what else it can be when number of tensors > 1?

Rationale:
    * We want to support stateful custom ops inserted after to_edge in a
      non delegated cases like op-lib-backends i.e. cortex-m::cmsis_nn::linear

Details:
    * Allows a pass to add a mutable buffer.
    * Essentially redoes what export, to_edge does for a buffer
      registered in an nn.module.
    * Also plays nice with to_executorch passes like conversion to
      in-place, and write-back for mutated buffers.
    * Verifies above with tests, adds a HelperPass for someone looking
      to leverage this util as an example too.

To Test:
    $ python -m unittest backends.transforms.test.test_create_mutable_buffer
@digantdesai digantdesai merged commit 9ce07da into main Sep 8, 2025
116 checks passed
@digantdesai digantdesai deleted the mutable_buffers branch September 8, 2025 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants