File size: 1,731 Bytes
36cdb93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
"""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