diff --git a/invokeai/app/invocations/compel.py b/invokeai/app/invocations/compel.py index 36c9d7b6522..3ad05bcc9b9 100644 --- a/invokeai/app/invocations/compel.py +++ b/invokeai/app/invocations/compel.py @@ -114,6 +114,13 @@ def _lora_loader() -> Iterator[Tuple[ModelPatchRaw, float]]: c, _options = compel.build_conditioning_tensor_for_conjunction(conjunction) + del compel + del patched_tokenizer + del tokenizer + del ti_manager + del text_encoder + del text_encoder_info + c = c.detach().to("cpu") conditioning_data = ConditioningFieldData(conditionings=[BasicConditioningInfo(embeds=c)]) @@ -222,7 +229,10 @@ def _lora_loader() -> Iterator[Tuple[ModelPatchRaw, float]]: else: c_pooled = None + del compel + del patched_tokenizer del tokenizer + del ti_manager del text_encoder del text_encoder_info diff --git a/invokeai/app/services/session_processor/session_processor_default.py b/invokeai/app/services/session_processor/session_processor_default.py index 07b1bacfc48..6c320eabda5 100644 --- a/invokeai/app/services/session_processor/session_processor_default.py +++ b/invokeai/app/services/session_processor/session_processor_default.py @@ -1,3 +1,4 @@ +import gc import traceback from contextlib import suppress from threading import BoundedSemaphore, Thread @@ -439,6 +440,12 @@ def _process( poll_now_event.wait(self._polling_interval) continue + # GC-ing here can reduce peak memory usage of the invoke process by freeing allocated memory blocks. + # Most queue items take seconds to execute, so the relative cost of a GC is very small. + # Python will never cede allocated memory back to the OS, so anything we can do to reduce the peak + # allocation is well worth it. + gc.collect() + self._invoker.services.logger.info( f"Executing queue item {self._queue_item.item_id}, session {self._queue_item.session_id}" ) diff --git a/invokeai/backend/model_patcher.py b/invokeai/backend/model_patcher.py index 3d614077c1f..a1d8bbed0a5 100644 --- a/invokeai/backend/model_patcher.py +++ b/invokeai/backend/model_patcher.py @@ -46,6 +46,10 @@ def apply_ti( text_encoder: Union[CLIPTextModel, CLIPTextModelWithProjection], ti_list: List[Tuple[str, TextualInversionModelRaw]], ) -> Iterator[Tuple[CLIPTokenizer, TextualInversionManager]]: + if len(ti_list) == 0: + yield tokenizer, TextualInversionManager(tokenizer) + return + init_tokens_count = None new_tokens_added = None