Skip to content

Add opt-in periodic device cache clearing during training - #402

Merged
vince62s merged 2 commits into
eole-nlp:mainfrom
dameikle:mps-empty-cache-steps
Jul 28, 2026
Merged

Add opt-in periodic device cache clearing during training#402
vince62s merged 2 commits into
eole-nlp:mainfrom
dameikle:mps-empty-cache-steps

Conversation

@dameikle

Copy link
Copy Markdown
Contributor

Summary

Adds an opt-in training.empty_cache_steps setting to periodically clear PyTorch device caches during training.

This is primarily useful for MPS training runs where cached allocator memory can grow over time with variable-shape workloads, with open issues in PyTorch for this.

On supported PyTorch versions, MPS graph cache clearing is also invoked via a guarded torch.mps.clear_graph_cache() call.

Default behavior is unchanged: empty_cache_steps: 0 disables periodic clearing.

Changes

  • Add training.empty_cache_steps, defaulting to 0.
  • Reuse clear_gpu_cache() from the trainer loop when the configured interval matches.
  • Extend clear_gpu_cache() to clear the MPS graph cache when available.
  • Add mocked tests for disabled, interval mismatch, CUDA, MPS with graph cache, and MPS without graph cache.

Notes

This should not affect training quality. It only clears cached device allocations and, when available, cached MPS graph objects. Model weights, gradients, optimizer state, batches, and loss computation are unchanged.

The main tradeoff is performance: lower intervals may reduce MPS memory pressure but can add cache-clearing/recompilation overhead.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds an opt-in training setting to periodically clear PyTorch device caches (with additional MPS graph-cache clearing when supported) to mitigate allocator/cache growth during long-running variable-shape workloads, especially on MPS.

Changes:

  • Introduces training.empty_cache_steps (default 0) and wires it into TrainerConfig.
  • Calls a new Trainer._maybe_clear_device_cache() hook during the training loop to invoke clear_gpu_cache() at the configured interval.
  • Extends clear_gpu_cache() to also call torch.mps.clear_graph_cache() when available, and adds unit tests for the new behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
eole/utils/misc.py Extends cache clearing to include optional MPS graph-cache clearing.
eole/trainer.py Adds empty_cache_steps plumbing and periodic cache clearing during training.
eole/tests/test_trainer_cache.py Adds tests for cache-clearing behavior across disabled/mismatch/CUDA/MPS scenarios.
eole/config/training.py Adds the empty_cache_steps config field to the training schema with documentation.
Comments suppressed due to low confidence (4)

eole/tests/test_trainer_cache.py:40

  • This test patches torch.mps.empty_cache just to assert it’s not called, which can fail on non-MPS builds. Since torch.backends.mps.is_available() is forced False, it’s sufficient to only patch/assert the CUDA path.
        with patch("torch.cuda.is_available", return_value=True), patch(
            "torch.backends.mps.is_available", return_value=False
        ), patch("torch.cuda.empty_cache") as cuda_empty_cache, patch("torch.mps.empty_cache") as mps_empty_cache:
            trainer._maybe_clear_device_cache(step=10)

        cuda_empty_cache.assert_called_once_with()
        mps_empty_cache.assert_not_called()

eole/tests/test_trainer_cache.py:54

  • Patching torch.mps.empty_cache by dotted string requires torch.mps to exist, which may not be true on non-Apple builds. Patch torch.mps itself (with create=True) to a small namespace containing the methods you need to assert.
        with patch("torch.cuda.is_available", return_value=False), patch(
            "torch.backends.mps.is_available", return_value=True
        ), patch("torch.mps.empty_cache") as mps_empty_cache, patch(
            "torch.mps.clear_graph_cache", create=True
        ) as clear_graph_cache:
            trainer._maybe_clear_device_cache(step=10)

        mps_empty_cache.assert_called_once_with()
        clear_graph_cache.assert_called_once_with()

eole/tests/test_trainer_cache.py:63

  • patch("torch.mps", mps) will fail if torch has no mps attribute. Use patch.object(torch, "mps", ..., create=True) to make this test portable across non-MPS PyTorch builds.
        with patch("torch.cuda.is_available", return_value=False), patch(
            "torch.backends.mps.is_available", return_value=True
        ), patch("torch.mps", mps):
            trainer._maybe_clear_device_cache(step=10)

eole/tests/test_trainer_cache.py:28

  • Same issue as the disabled test: patching torch.mps.empty_cache is unnecessary here and can fail if torch.mps doesn’t exist. Patch/assert eole.trainer.clear_gpu_cache instead to test the interval-mismatch behavior without depending on optional PyTorch backends.
    def test_empty_cache_steps_interval_mismatch_does_not_clear_cache(self):
        trainer = object.__new__(Trainer)
        trainer.config = TrainerConfig(empty_cache_steps=10)

        with patch("torch.cuda.empty_cache") as cuda_empty_cache, patch("torch.mps.empty_cache") as mps_empty_cache:
            trainer._maybe_clear_device_cache(step=9)

        cuda_empty_cache.assert_not_called()
        mps_empty_cache.assert_not_called()


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread eole/trainer.py
Comment thread eole/tests/test_trainer_cache.py
Comment thread eole/tests/test_trainer_cache.py Outdated
@vince62s
vince62s merged commit 98d65b3 into eole-nlp:main Jul 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants