Skip to content

Fix ModelPruning iterative reuse RuntimeError on non-leaf tensors#21717

Open
Priyanshu-byte-coder wants to merge 4 commits into
Lightning-AI:masterfrom
Priyanshu-byte-coder:fix/model-pruning-iterative-deepcopy-error
Open

Fix ModelPruning iterative reuse RuntimeError on non-leaf tensors#21717
Priyanshu-byte-coder wants to merge 4 commits into
Lightning-AI:masterfrom
Priyanshu-byte-coder:fix/model-pruning-iterative-deepcopy-error

Conversation

@Priyanshu-byte-coder

@Priyanshu-byte-coder Priyanshu-byte-coder commented May 17, 2026

Copy link
Copy Markdown

What does this PR fix?

Fixes #8542.

When ModelPruning(use_lottery_ticket_hypothesis=True) is reused across multiple trainer.fit() calls (iterative pruning), the second and subsequent calls to setup() raise:

RuntimeError: Only Tensors created explicitly by the user (graph leaves) support the deepcopy protocol at the moment

Root cause: After the first training pass, apply_lottery_ticket_hypothesis() calls _copy_param() which does dst.data = src.data.to(dst.device). This in-place data assignment makes the model parameters non-leaf tensors. When setup() is called again on the next trainer.fit(), deepcopy(module) fails.

Changes

src/lightning/pytorch/callbacks/pruning.py

  • Added _deepcopy_for_pruning(module) static helper: temporarily replaces non-leaf parameters with detach().clone() copies, deepcopies, then restores originals
  • Updated setup() to use _deepcopy_for_pruning instead of bare deepcopy(module)
  • In setup(), set self._original_layers = None before re-populating to release previous-run tensor references

tests/tests_pytorch/callbacks/test_pruning.py

  • Added test_iterative_pruning_no_runtime_error: runs 3 consecutive trainer.fit() calls with the same pruning callback and verifies no RuntimeError is raised

Reproduction

model = BoringModel()
pruning_callback = ModelPruning("l1_unstructured", use_lottery_ticket_hypothesis=True, amount=0.2)
for _ in range(2):
    trainer = Trainer(max_epochs=1, accelerator="cpu", callbacks=[pruning_callback])
    trainer.fit(model)  # RuntimeError on second iteration (before fix)

📚 Documentation preview 📚: https://pytorch-lightning--21717.org.readthedocs.build/en/21717/

When ModelPruning with use_lottery_ticket_hypothesis=True is reused
across multiple trainer.fit() calls, setup() is called again each run.
After the first pass, _copy_param sets dst.data = src.data, making the
parameters non-leaf tensors. The subsequent deepcopy(module) then raises:

  RuntimeError: Only Tensors created explicitly by the user (graph
  leaves) support the deepcopy protocol at the moment

Fix by adding _deepcopy_for_pruning(), a helper that temporarily
replaces non-leaf parameters with detached clones before deepcopy and
restores the originals afterward. Also explicitly set _original_layers
to None before re-populating in setup() so the previous run's tensor
references are released before new copies are allocated.

Fixes Lightning-AI#8542
@github-actions github-actions Bot added the pl Generic label for PyTorch Lightning package label May 17, 2026
The actual non-leaf tensor after pruning is module.weight stored in
module.__dict__ by the forward pre-hook (weight_orig * weight_mask),
not in module._parameters. Patching _parameters had two problems:

1. Did not fix the RuntimeError (wrong dict being patched)
2. Caused mypy errors: assigning Tensor to Parameter | None

Switch to iterating module.__dict__ instead, which correctly captures
the hook-written non-leaf weight attribute.
@Priyanshu-byte-coder Priyanshu-byte-coder force-pushed the fix/model-pruning-iterative-deepcopy-error branch from 3de4112 to 03ed64a Compare May 17, 2026 11:02
@Priyanshu-byte-coder

Copy link
Copy Markdown
Author

Pinging for review — all CI checks are green (triage, pre-commit, GitGuardian, ReadTheDocs all pass).

@justusschock @tchaton could one of you take a look when you get a chance? The fix is in _deepcopy_for_pruning in pruning.py — patches module.__dict__ instead of module._parameters to handle the non-leaf tensor that PyTorch's pruning forward pre-hook stores there.

@Priyanshu-byte-coder

Priyanshu-byte-coder commented Jul 5, 2026

Copy link
Copy Markdown
Author

Follow-up ping @justusschock @tchaton — CI is green and the fix is small: ModelPruning no longer raises RuntimeError on non-leaf tensors during iterative reuse (pruning.py + regression test). Happy to rebase onto current master if that helps get it reviewed.

@codecov-commenter

codecov-commenter commented Jul 6, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 79%. Comparing base (4819088) to head (b528ac5).
✅ All tests successful. No failed tests found.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

❗ There is a different number of reports uploaded between BASE (4819088) and HEAD (b528ac5). Click for more details.

HEAD has 1666 uploads less than BASE
Flag BASE (4819088) HEAD (b528ac5)
python3.10 30 3
cpu 417 42
lightning 149 15
pytest 209 0
python 30 3
lightning_fabric 134 0
python3.12 120 12
python3.12.7 88 9
python3.11 60 6
python3.13 89 9
pytorch2.8 30 6
pytorch_lightning 134 27
pytest-full 208 42
pytorch2.7 15 3
pytorch2.9 30 6
pytorch2.10 30 6
pytorch2.6 14 3
pytorch2.4.1 14 3
pytorch2.2.2 15 3
pytorch2.1 30 6
pytorch2.3 15 3
pytorch2.5.1 15 3
Additional details and impacted files
@@            Coverage Diff            @@
##           master   #21717     +/-   ##
=========================================
- Coverage      87%      79%     -8%     
=========================================
  Files         270      267      -3     
  Lines       24010    23963     -47     
=========================================
- Hits        20790    18842   -1948     
- Misses       3220     5121   +1901     

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pl Generic label for PyTorch Lightning package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pruning callback causes GPU memory leak when used iteratively

3 participants