1010
1111from __future__ import annotations
1212
13+ import gc
1314import io
1415from dataclasses import dataclass
1516from enum import Enum
@@ -151,6 +152,8 @@ def __init__(
151152 self ._siglip_model : Any = None
152153 self ._siglip_processor : Any = None
153154 self ._text_embeddings : Any = None
155+ self ._classifier_key : str | None = None
156+ self ._siglip_key : str | None = None
154157
155158 def is_available (self ) -> bool :
156159 """Check if required models can be loaded."""
@@ -186,6 +189,7 @@ def _load_models(self) -> None:
186189 model_path = model_id ,
187190 device = self .device ,
188191 )
192+ self ._classifier_key = f"technique_router:{ model_id } "
189193
190194 if self .use_siglip and self ._siglip_model is None :
191195 # Use centralized registry for shared model instances
@@ -195,10 +199,34 @@ def _load_models(self) -> None:
195199 model_name = self .siglip_model ,
196200 device = self .device ,
197201 )
202+ self ._siglip_key = f"siglip:{ self .siglip_model } "
198203
199204 # Pre-compute text embeddings for image analysis
200205 self ._compute_text_embeddings ()
201206
207+ def release_models (self , unload_registry : bool = True ) -> None :
208+ """Release router-held model references and optional shared cache entries."""
209+ classifier_key = self ._classifier_key
210+ siglip_key = self ._siglip_key
211+
212+ self ._text_embeddings = None
213+ self ._siglip_processor = None
214+ self ._siglip_model = None
215+ self ._tokenizer = None
216+ self ._classifier = None
217+ self ._classifier_key = None
218+ self ._siglip_key = None
219+
220+ if unload_registry :
221+ from headroom .models .ml_models import MLModelRegistry
222+
223+ keys = [key for key in (classifier_key , siglip_key ) if key ]
224+ MLModelRegistry .unload_many (keys )
225+ else :
226+ gc .collect ()
227+
228+ close = release_models
229+
202230 def _compute_text_embeddings (self ) -> None :
203231 """Pre-compute SigLIP text embeddings for image analysis."""
204232 assert self ._siglip_processor is not None
0 commit comments