"""Periodic Python and accelerator garbage collection callback."""
import gc
from typing import Any
from hyper_parallel.trainer.runtime.device import empty_cache, get_device_type
from .base import Callback, TrainerState
class GarbageCollectionCallback(Callback):
"""Run Python GC and device cache cleanup on independent step cadences."""
def __init__(self, trainer: Any) -> None:
"""Read cleanup intervals from the Trainer configuration.
Args:
trainer: Trainer that owns the callback lifecycle.
"""
super().__init__(trainer)
training_config = trainer.config.training
self.gc_steps = training_config.gc_steps
self.empty_cache_steps = training_config.empty_cache_steps
def on_step_end(self, state: TrainerState, **kwargs: Any) -> None:
"""Run configured cleanup operations after an optimizer step."""
del kwargs
if self.gc_steps > 0 and state.global_step % self.gc_steps == 0:
gc.collect()
if (
self.empty_cache_steps > 0
and state.global_step % self.empty_cache_steps == 0
and get_device_type() != "cpu"
):
empty_cache()