Skip to content

functionalization bugfix: using owning type when unwrapping tensors#76125

Closed
bdhirsh wants to merge 8 commits intogh/bdhirsh/213/basefrom
gh/bdhirsh/213/head
Closed

functionalization bugfix: using owning type when unwrapping tensors#76125
bdhirsh wants to merge 8 commits intogh/bdhirsh/213/basefrom
gh/bdhirsh/213/head

Conversation

@bdhirsh
Copy link
Collaborator

@bdhirsh bdhirsh commented Apr 20, 2022

Addresses the comment here: #73441 (comment)

This PR should also fix a bug with at::cat.out in functionalization, so I added a test for it.

When the functionalization pass unwraps tensor arguments, we need to make sure the thing that we unwrap into has an owning type - we can't blindly base the type off whatever types come from the operator's schema.

This is basically just a problem for at::TensorList (non-owning) - we need to use an owning std::vector<Tensor> instead.

@ezyang I wasn't sure how general of a fix to make. translate() already knows a bit about "expensive conversions" from non-owning to owning types. I couldn't think of a way to re-use that code without making some larger changes (like teaching CType's about whether they're owning types), so I added a simple fix inside the functionalization codegen. Feedback totally welcome.

Here's part of the old cat kernel:

    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      at::TensorList tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ....
    }

And here's the new one (the temporary it creates is a vector)

    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      ::std::vector<at::Tensor> tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ...
    }

Stack from ghstack:

@facebook-github-bot
Copy link
Contributor

facebook-github-bot commented Apr 20, 2022

🔗 Helpful links

💊 CI failures summary and remediations

As of commit ebb412f (more details on the Dr. CI page):

Expand to see more

💚 💚 Looks good so far! There are no failures yet. 💚 💚


This comment was automatically generated by Dr. CI (expand for details).

Please report bugs/suggestions to the (internal) Dr. CI Users group.

Click here to manually regenerate this comment.

for (const auto i : c10::irange(functional_tensor.size())) {
commit_update(functional_tensor[i]);
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

These aren't strictly necessary for this PR, but I need them later (accidentally bundled them in this commit)

Copy link
Contributor

@ezyang ezyang left a comment

Choose a reason for hiding this comment

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

the one off seems fine. keep an eye on it in the future

…g tensors"

Addresses the comment here: #73441 (comment)

When the functionalization pass unwraps tensor arguments, we need to make sure the thing that we unwrap into has an owning type - we can't blindly base the type off whatever types come from the operator's schema.

This is basically just a problem for `at::TensorList` (non-owning) - we need to use an owning `std::vector<Tensor>` instead.

@ezyang I wasn't sure how general of a fix to make. `translate()` already knows a bit about "expensive conversions" from non-owning to owning types. I couldn't think of a way to re-use that code without making some larger changes (like teaching `CType`'s about whether they're owning types), so I added a simple fix inside the functionalization codegen. Feedback totally welcome.

Here's part of the old `cat` kernel:
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      at::TensorList tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ....
    }
```

And here's the new one (the temporary it creates is a vector)
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      ::std::vector<at::Tensor> tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ...
    }
```




[ghstack-poisoned]
bdhirsh added 4 commits April 21, 2022 16:36
…g tensors"

Addresses the comment here: #73441 (comment)

When the functionalization pass unwraps tensor arguments, we need to make sure the thing that we unwrap into has an owning type - we can't blindly base the type off whatever types come from the operator's schema.

This is basically just a problem for `at::TensorList` (non-owning) - we need to use an owning `std::vector<Tensor>` instead.

@ezyang I wasn't sure how general of a fix to make. `translate()` already knows a bit about "expensive conversions" from non-owning to owning types. I couldn't think of a way to re-use that code without making some larger changes (like teaching `CType`'s about whether they're owning types), so I added a simple fix inside the functionalization codegen. Feedback totally welcome.

Here's part of the old `cat` kernel:
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      at::TensorList tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ....
    }
```

And here's the new one (the temporary it creates is a vector)
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      ::std::vector<at::Tensor> tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ...
    }
```




[ghstack-poisoned]
…g tensors"

Addresses the comment here: #73441 (comment)

When the functionalization pass unwraps tensor arguments, we need to make sure the thing that we unwrap into has an owning type - we can't blindly base the type off whatever types come from the operator's schema.

This is basically just a problem for `at::TensorList` (non-owning) - we need to use an owning `std::vector<Tensor>` instead.

@ezyang I wasn't sure how general of a fix to make. `translate()` already knows a bit about "expensive conversions" from non-owning to owning types. I couldn't think of a way to re-use that code without making some larger changes (like teaching `CType`'s about whether they're owning types), so I added a simple fix inside the functionalization codegen. Feedback totally welcome.

Here's part of the old `cat` kernel:
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      at::TensorList tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ....
    }
```

And here's the new one (the temporary it creates is a vector)
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      ::std::vector<at::Tensor> tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ...
    }
```




[ghstack-poisoned]
…g tensors"

Addresses the comment here: #73441 (comment)

When the functionalization pass unwraps tensor arguments, we need to make sure the thing that we unwrap into has an owning type - we can't blindly base the type off whatever types come from the operator's schema.

This is basically just a problem for `at::TensorList` (non-owning) - we need to use an owning `std::vector<Tensor>` instead.

@ezyang I wasn't sure how general of a fix to make. `translate()` already knows a bit about "expensive conversions" from non-owning to owning types. I couldn't think of a way to re-use that code without making some larger changes (like teaching `CType`'s about whether they're owning types), so I added a simple fix inside the functionalization codegen. Feedback totally welcome.

Here's part of the old `cat` kernel:
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      at::TensorList tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ....
    }
```

And here's the new one (the temporary it creates is a vector)
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      ::std::vector<at::Tensor> tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ...
    }
```




[ghstack-poisoned]
…g tensors"

Addresses the comment here: #73441 (comment)

This PR should also fix a bug with `at::cat.out` in functionalization, so I added a test for it.

When the functionalization pass unwraps tensor arguments, we need to make sure the thing that we unwrap into has an owning type - we can't blindly base the type off whatever types come from the operator's schema.

This is basically just a problem for `at::TensorList` (non-owning) - we need to use an owning `std::vector<Tensor>` instead.

@ezyang I wasn't sure how general of a fix to make. `translate()` already knows a bit about "expensive conversions" from non-owning to owning types. I couldn't think of a way to re-use that code without making some larger changes (like teaching `CType`'s about whether they're owning types), so I added a simple fix inside the functionalization codegen. Feedback totally welcome.

Here's part of the old `cat` kernel:
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      at::TensorList tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ....
    }
```

And here's the new one (the temporary it creates is a vector)
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      ::std::vector<at::Tensor> tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ...
    }
```




[ghstack-poisoned]
…g tensors"

Addresses the comment here: #73441 (comment)

This PR should also fix a bug with `at::cat.out` in functionalization, so I added a test for it.

When the functionalization pass unwraps tensor arguments, we need to make sure the thing that we unwrap into has an owning type - we can't blindly base the type off whatever types come from the operator's schema.

This is basically just a problem for `at::TensorList` (non-owning) - we need to use an owning `std::vector<Tensor>` instead.

@ezyang I wasn't sure how general of a fix to make. `translate()` already knows a bit about "expensive conversions" from non-owning to owning types. I couldn't think of a way to re-use that code without making some larger changes (like teaching `CType`'s about whether they're owning types), so I added a simple fix inside the functionalization codegen. Feedback totally welcome.

Here's part of the old `cat` kernel:
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      at::TensorList tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ....
    }
```

And here's the new one (the temporary it creates is a vector)
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      ::std::vector<at::Tensor> tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ...
    }
```




[ghstack-poisoned]
@bdhirsh
Copy link
Collaborator Author

bdhirsh commented Apr 25, 2022

@pytorchbot merge this please

@pytorchmergebot
Copy link
Collaborator

Merge failed due to Command git -C /home/runner/work/pytorch/pytorch push origin master returned non-zero exit code 1
To https://github.com/pytorch/pytorch
! [remote rejected] master -> master (cannot lock ref 'refs/heads/master': is at 40f3e85 but expected 5da76ac)
error: failed to push some refs to 'https://github.com/pytorch/pytorch'

Raised by https://github.com/pytorch/pytorch/actions/runs/2223007110

@bdhirsh
Copy link
Collaborator Author

bdhirsh commented Apr 25, 2022

@pytorchbot merge this please

@pytorchmergebot
Copy link
Collaborator

Merge failed due to Command git -C /home/runner/work/pytorch/pytorch cherry-pick -x 5a8f6814c4e9354929062574d6fd2e3f3ead5105 returned non-zero exit code 1
Auto-merging aten/src/ATen/native/native_functions.yaml
Auto-merging tools/autograd/gen_python_functions.py
CONFLICT (content): Merge conflict in tools/autograd/gen_python_functions.py
error: could not apply 5a8f681... functionalization: add a copy() native function
hint: After resolving the conflicts, mark them with
hint: "git add/rm ", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".

Raised by https://github.com/pytorch/pytorch/actions/runs/2223067256

…g tensors"

Addresses the comment here: #73441 (comment)

This PR should also fix a bug with `at::cat.out` in functionalization, so I added a test for it.

When the functionalization pass unwraps tensor arguments, we need to make sure the thing that we unwrap into has an owning type - we can't blindly base the type off whatever types come from the operator's schema.

This is basically just a problem for `at::TensorList` (non-owning) - we need to use an owning `std::vector<Tensor>` instead.

@ezyang I wasn't sure how general of a fix to make. `translate()` already knows a bit about "expensive conversions" from non-owning to owning types. I couldn't think of a way to re-use that code without making some larger changes (like teaching `CType`'s about whether they're owning types), so I added a simple fix inside the functionalization codegen. Feedback totally welcome.

Here's part of the old `cat` kernel:
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      at::TensorList tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ....
    }
```

And here's the new one (the temporary it creates is a vector)
```
    at::Tensor & cat_out_out(c10::DispatchKeySet dispatchKeySet, at::TensorList tensors, int64_t dim, at::Tensor & out) {
      ::std::vector<at::Tensor> tensors_;
      if (at::functionalization::impl::isFunctionalTensor(tensors)) {
        at::functionalization::impl::sync(tensors);
        tensors_ = at::functionalization::impl::from_functional_tensor(tensors);
      } else {
        tensors_ = tensors;
      }
      ...
    }
```




[ghstack-poisoned]
@bdhirsh
Copy link
Collaborator Author

bdhirsh commented Apr 25, 2022

@pytorchbot merge this please

@pytorchmergebot
Copy link
Collaborator

Merge failed due to Refusing to merge as mandatory check Lint failed for rule superuser
Raised by https://github.com/pytorch/pytorch/actions/runs/2223089719

@bdhirsh
Copy link
Collaborator Author

bdhirsh commented Apr 25, 2022

@pytorchbot merge this please

@github-actions
Copy link
Contributor

Hey @bdhirsh.
You've committed this PR, but it does not have both a 'release notes: ...' and 'topics: ...' label. Please add one of each to the PR. The 'release notes: ...' label should represent the part of PyTorch that this PR changes (fx, autograd, distributed, etc) and the 'topics: ...' label should represent the kind of PR it is (not user facing, new feature, bug fix, perf improvement, etc). The list of valid labels can be found here for the 'release notes: ...' and here for the 'topics: ...'.
For changes that are 'topic: not user facing' there is no need for a release notes label.

facebook-github-bot pushed a commit that referenced this pull request Apr 26, 2022
…76125)

Summary:
Pull Request resolved: #76125

Approved by: https://github.com/ezyang

Test Plan: contbuild & OSS CI, see https://hud.pytorch.org/commit/pytorch/pytorch/640ce6bc9bbd25603c80651fd2be3f0045ea0d75

Reviewed By: osalpekar

Differential Revision: D35938196

Pulled By: bdhirsh

fbshipit-source-id: 1640a07e70f4036e42f12d657628e37848e26c35
@facebook-github-bot facebook-github-bot deleted the gh/bdhirsh/213/head branch April 29, 2022 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants