Skip to content

Commit aa30a98

Browse files
[perf]: rebuild the deferred-release schedule when a stage is added late
The schedule maps each deferred component to the last stage that holds it, derived once after create_pipeline_stages. Every pipeline in the tree builds its stages there, but nothing enforced it. A stage appended afterwards could hold a component an earlier stage had already been told to free, and would then be handed a released component mid-run with no error. add_stage now rebuilds the schedule and says so, turning an invariant nothing checked into a visible self-correction. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent e4c71ca commit aa30a98

2 files changed

Lines changed: 37 additions & 0 deletions

File tree

fastvideo/pipelines/composed_pipeline_base.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ class ComposedPipelineBase(ABC):
4848
trainable_transformer_names: list[str] = ["transformer"]
4949
trainable_transformer_modules: dict[str, torch.nn.Module] = {}
5050
post_init_called: bool = False
51+
# Set once the deferred-release schedule has been derived from the stage
52+
# list, so a stage added afterwards can rebuild it instead of running
53+
# against a plan that predates it.
54+
_lazy_release_hooks_installed: bool = False
5155
# Components eligible for deferred loading under ``lazy_module_load``.
5256
# These are the weight-bearing ones; tokenizers, processors, and
5357
# schedulers are cheap and stay resident so the pipeline can inspect them
@@ -600,11 +604,13 @@ def _install_lazy_release_hooks(self) -> None:
600604
"lazy_module_load is on but no deferred module is held by a stage, so nothing will be "
601605
"freed mid-run. Pipeline %s may load its modules eagerly or hold them outside its stages.",
602606
type(self).__name__)
607+
self._lazy_release_hooks_installed = True
603608
return
604609

605610
for index, names in sorted(schedule.items()):
606611
logger.info("Deferred modules to free after stage %d (%s): %s", index,
607612
getattr(self._stages[index], "_pipeline_stage_name", "?"), names)
613+
self._lazy_release_hooks_installed = True
608614

609615
def add_stage(self, stage_name: str, stage: PipelineStage):
610616
assert self.modules is not None, "No modules are registered"
@@ -616,6 +622,15 @@ def add_stage(self, stage_name: str, stage: PipelineStage):
616622
self._stage_name_mapping[stage_name] = stage
617623
setattr(self, stage_name, stage)
618624

625+
if self._lazy_release_hooks_installed:
626+
# The schedule maps each deferred module to its last holder. A
627+
# stage appended afterwards may hold a module an earlier stage has
628+
# already been told to free, which would hand it a released
629+
# component mid-run. Rebuild rather than trust the stale plan.
630+
logger.warning("Stage %s was added after the deferred-release schedule was built; rebuilding the schedule",
631+
stage_name)
632+
self._install_lazy_release_hooks()
633+
619634
# TODO(will): don't hardcode no_grad
620635
@torch.no_grad()
621636
def forward(

fastvideo/tests/stages/test_lazy_module_load.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,25 @@ def test_a_stage_that_rebinds_through_to_can_still_be_released():
383383
stage(object(), SimpleNamespace(enable_stage_verification=False))
384384

385385
assert not vae.is_materialized
386+
387+
388+
def test_a_stage_added_after_the_schedule_rebuilds_it(caplog):
389+
# The schedule is derived from the stage list. A stage appended afterwards
390+
# could hold a module an earlier stage was already told to free, which
391+
# would hand it a released component mid-run.
392+
vae = _lazy("vae")
393+
first = _EchoStage(vae=vae)
394+
pipeline = _FakePipeline({"vae": vae}, [])
395+
pipeline._stage_name_mapping = {}
396+
pipeline.add_stage("first", first)
397+
pipeline._install_lazy_release_hooks()
398+
399+
assert first._lazy_modules_to_release == (vae, )
400+
401+
later = _EchoStage(vae=vae)
402+
with caplog.at_level("WARNING"):
403+
pipeline.add_stage("later", later)
404+
405+
assert "rebuilding the schedule" in caplog.text
406+
assert first._lazy_modules_to_release == ()
407+
assert later._lazy_modules_to_release == (vae, )

0 commit comments

Comments
 (0)