Reduce backward memory to ~half#218
Open
jasam-sheja wants to merge 5 commits intomapillary:mainfrom
Open
Conversation
- reuse y_act_ and dy_act_ - use inplace calculations in `forward_cpu` and `backward_cpu`
- make sure dy_act doesn't have memory overlaping - reflect the inplace operations in the doc and comments
There was a problem hiding this comment.
Pull request overview
This PR reduces memory usage during the backward pass of InPlaceABN by reusing existing activation/gradient buffers (overwriting y_act with xhat and dy_act with dy) and adjusting code paths to support in-place behavior (including an ELU backward tweak and ensuring dy_act is contiguous).
Changes:
- Reuse
y_act/dy_actasxhat/dyin backward-reduce (CPU/CUDA) to cut temporary allocations. - Switch several CPU forward/backward intermediate computations to in-place ops to reduce transient allocations.
- Update Python/C++ binding notes and make
dy_actcontiguous to support in-place writes.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/inplace_abn_cuda.cu |
Reuses y_act/dy_act buffers for backward outputs in CUDA implementation. |
src/inplace_abn_cpu.cpp |
Reuses y_act_/dy_act_ buffers and increases in-place usage for CPU forward/backward. |
src/inplace_abn.cpp |
Updates pybind docstring to mention in-place behavior for backward_reduce. |
inplace_abn/functions.py |
Makes dy_act contiguous and notes that backward-reduce overwrites tensors in-place. |
include/inplace_abn.h |
Adjusts ELU backward ordering to support in-place overwrite safely. |
Comments suppressed due to low confidence (1)
src/inplace_abn_cuda.cu:156
y_act/dy_actare being reused asxhat/dy, but the CUDA kernel is launched withat::RestrictPtrTraitsfor both input and output accessors. Wheny_act_accessoraliasesxhat_accessor(anddy_act_accessoraliasesdy_accessor), this violates the__restrict__aliasing assumption and can lead to miscompilation/incorrect results. To support in-place reuse safely, use non-restrict pointer traits (e.g.,at::DefaultPtrTraits) for these accessors / kernel params, or keep separate output tensors (or provide a separate non-restrict kernel for the in-place path).
auto &xhat = y_act; // reuse
auto &dy = dy_act; // reuse
auto sum_dy = at::empty({chn}, acc_options);
auto sum_xhat_dy = at::empty({chn}, acc_options);
// Make accessors
auto y_act_accessor = y_act.packed_accessor<scalar_t, 3, at::RestrictPtrTraits, index_t>();
auto dy_act_accessor = dy_act.packed_accessor<scalar_t, 3, at::RestrictPtrTraits, index_t>();
auto xhat_accessor = xhat.packed_accessor<scalar_t, 3, at::RestrictPtrTraits, index_t>();
auto dy_accessor = dy.packed_accessor<scalar_t, 3, at::RestrictPtrTraits, index_t>();
auto weight_accessor = packed_accessor_or_dummy<prmscalar_t, 1, at::RestrictPtrTraits, index_t>(weight);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
Comment on lines
25
to
35
| std::tuple<at::Tensor, at::Tensor, at::Tensor, at::Tensor> backward_reduce_impl( | ||
| const at::Tensor& y_act_, | ||
| const at::Tensor& dy_act_, | ||
| const std::optional<at::Tensor>& weight_, | ||
| const std::optional<at::Tensor>& bias_, | ||
| float eps, | ||
| float activation_param) { | ||
| // Initialize output tensors | ||
| auto xhat_ = at::empty_like(y_act_); | ||
| auto dy_ = at::empty_like(y_act_); | ||
| auto &xhat_ = y_act_; // reuse | ||
| auto &dy_ = dy_act_; // reuse | ||
| auto sum_dy_ = at::zeros({y_act_.size(1)}, y_act_.options()); |
|
|
||
| # Call backward_reduce if we need to compute at least one of the gradients | ||
| if any(ctx.needs_input_grad): | ||
| # remove memory overlaping to allow for in-place operation |
|
|
||
| // Backward methods | ||
| m.def("backward_reduce", &backward_reduce, "First step of the backward pass"); | ||
| m.def("backward_reduce", &backward_reduce, "First step of the backward pass. This is an in-place operation w.r.t. y_act, dy_act,"); |
Comment on lines
117
to
125
| y_act, var, count, weight, bias = ctx.saved_tensors | ||
|
|
||
| # Call backward_reduce if we need to compute at least one of the gradients | ||
| if any(ctx.needs_input_grad): | ||
| # remove memory overlaping to allow for in-place operation | ||
| dy_act = dy_act.contiguous() | ||
| # This overwrites y_act with xhat and dy_act with dy | ||
| xhat, dy, sum_dy_local, sum_xhat_dy_local = _backend.backward_reduce( | ||
| y_act, | ||
| dy_act, |
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.
Reuse the grad and input tensors in the backward pass instead of creating new ones.
Mainly reuse
y_actforxhatanddy_actfordy.Ensure every function support in-place operation. (Elu is modified accordingly)
Ensure the tensors allow in-place operation (
dy_acthas to be contiguous)Needs more testing. However, there are no unit tests.