Skip to content

Commit e36a6ec

Browse files
committed
feature: storing prompt on cpu
1 parent 6143569 commit e36a6ec

1 file changed

Lines changed: 23 additions & 29 deletions

File tree

workers/common/prompt_caching.py

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from collections import OrderedDict
22
from functools import wraps
3+
from typing import Any
34

45
import torch
56
from diffusers import DiffusionPipeline
@@ -12,35 +13,28 @@
1213
MAX_PROMPT_CACHE_SIZE = 64
1314

1415

16+
def _move_to_device(obj: Any, device):
17+
"""Recursively move tensors in a nested structure to a device."""
18+
if isinstance(obj, torch.Tensor):
19+
# NOTE important we must detach and clone tensors before caching them
20+
return obj.detach().clone().to(device)
21+
if isinstance(obj, (list, tuple)):
22+
return type(obj)(_move_to_device(x, device) for x in obj)
23+
24+
# Dict support removed as encode_prompt does not return dicts
25+
return obj
26+
27+
1528
def clear_global_prompt_cache():
1629
"""Clear the global prompt embeddings cache."""
1730
GLOBAL_PROMPT_CACHE.clear()
1831
logger.debug("Global prompt cache cleared")
1932

2033

21-
def get_prompt_cache_total_mb() -> float:
22-
"""
23-
Calculate the total memory usage of the prompt cache in Megabytes (MB).
24-
Each element in GLOBAL_PROMPT_CACHE can be a Tensor or a tuple/list of Tensors.
25-
"""
26-
total_bytes = 0
27-
28-
def get_size(obj):
29-
if isinstance(obj, torch.Tensor):
30-
return obj.element_size() * obj.nelement()
31-
if isinstance(obj, (list, tuple)):
32-
return sum(get_size(i) for i in obj)
33-
return 0
34-
35-
for value in GLOBAL_PROMPT_CACHE.values():
36-
total_bytes += get_size(value)
37-
38-
return total_bytes / (1024 * 1024)
39-
40-
4134
def get_prompt_cache_if_exists(cache_key):
4235
"""
4336
Retrieve cached result if it exists and move to Most Recently Used.
37+
Note: The caller is responsible for moving the result to the correct device.
4438
"""
4539
if cache_key in GLOBAL_PROMPT_CACHE:
4640
GLOBAL_PROMPT_CACHE.move_to_end(cache_key)
@@ -52,14 +46,17 @@ def get_prompt_cache_if_exists(cache_key):
5246
def add_prompt_cache(cache_key, result):
5347
"""
5448
Add a result to the global cache and manage its size.
49+
Automatically moves the result to CPU to save VRAM.
5550
"""
56-
GLOBAL_PROMPT_CACHE[cache_key] = result
51+
# Move to CPU for storage
52+
cpu_result = _move_to_device(result, "cpu")
53+
54+
GLOBAL_PROMPT_CACHE[cache_key] = cpu_result
5755
if len(GLOBAL_PROMPT_CACHE) > MAX_PROMPT_CACHE_SIZE:
5856
GLOBAL_PROMPT_CACHE.popitem(last=False) # Remove Least Recently Used
5957

60-
mb = get_prompt_cache_total_mb()
6158
logger.info(
62-
f"Prompt cached for {cache_key[0]}. Current cache size: {mb:.2f} MB ({len(GLOBAL_PROMPT_CACHE)}/{MAX_PROMPT_CACHE_SIZE})"
59+
f"Prompt cached for {cache_key[0]}. Current cache size: ({len(GLOBAL_PROMPT_CACHE)}/{MAX_PROMPT_CACHE_SIZE})"
6360
)
6461

6562

@@ -90,22 +87,19 @@ def enable_prompt_caching(pipeline: DiffusionPipeline) -> DiffusionPipeline:
9087
@wraps(original_encode_prompt)
9188
def wrapped_encode_prompt(*args, **kwargs):
9289
try:
93-
# Create a cache key from identity and hashable representation of all arguments
94-
# Identity ensures we don't use Flux embeddings for a Wan model, etc.
9590
cache_key = (pipeline_identity, make_hashable(args), make_hashable(kwargs))
9691
except (TypeError, ValueError):
9792
logger.warning("Failed to create hashable cache key; skipping prompt caching")
98-
# Fallback: if something isn't hashable, just compute normally
9993
return original_encode_prompt(*args, **kwargs)
10094

10195
cached_result = get_prompt_cache_if_exists(cache_key)
10296
if cached_result is not None:
103-
return cached_result
97+
# Move back to the target device (e.g. CUDA)
98+
target_device = kwargs.get("device") or getattr(pipeline, "device", torch.device("cuda"))
99+
return _move_to_device(cached_result, target_device)
104100

105-
# Compute new results (e.g., prompt_embeds, negative_prompt_embeds)
106101
result = original_encode_prompt(*args, **kwargs)
107102

108-
# Store in global cache
109103
add_prompt_cache(cache_key, result)
110104

111105
return result

0 commit comments

Comments
 (0)