Spaces:
Running on Zero
Running on Zero
| """Prompt encoding with a content-addressed cache. | |
| The T5 encoder (umt5-xxl) runs on CPU here to keep the GPU free, which costs | |
| ~40 s per prompt -- worth caching. The original cache key in run_streaming.py was | |
| `abs(hash(prompt)) % 10**8`; Python salts `hash()` for str per process | |
| (PYTHONHASHSEED), so the key changed on every invocation and the cache never hit. | |
| That is why diag/ accumulated 19 ctx_*.pt files for ~3 distinct prompts. sha1 of | |
| the text is stable across processes. | |
| """ | |
| import gc | |
| import hashlib | |
| import os | |
| import torch | |
| def prompt_key(prompt): | |
| return hashlib.sha1(prompt.encode('utf-8')).hexdigest()[:16] | |
| def encode_prompt(prompt, neg_prompt, ckpt_dir, cfg, cache_dir, text_len=512): | |
| """Return (pos, neg) embeddings [1, text_len, dim], cached on disk.""" | |
| os.makedirs(cache_dir, exist_ok=True) | |
| path = os.path.join(cache_dir, f'ctx_{prompt_key(prompt)}.pt') | |
| if os.path.exists(path): | |
| return torch.load(path, map_location='cpu') | |
| from wan.modules.t5 import T5EncoderModel | |
| print(f'Loading T5 (CPU) to encode prompt -> {os.path.basename(path)} ...') | |
| t5 = T5EncoderModel(text_len=text_len, dtype=cfg.t5_dtype, | |
| device=torch.device('cpu'), | |
| checkpoint_path=f'{ckpt_dir}/{cfg.t5_checkpoint}', | |
| tokenizer_path=f'{ckpt_dir}/google/umt5-xxl') | |
| def enc(p): | |
| x = t5([p], torch.device('cpu'))[0].float() | |
| if x.shape[0] < text_len: | |
| x = torch.cat([x, torch.zeros(text_len - x.shape[0], x.shape[1])], 0) | |
| return x[:text_len].unsqueeze(0) | |
| blob = {'pos': enc(prompt), 'neg': enc(neg_prompt), 'prompt': prompt} | |
| del t5 | |
| gc.collect() | |
| torch.save(blob, path) | |
| return blob | |