CoolFace
Modelpublic

OzzyGT/YuE2-Modular

sourceHugging Faceapache-2.0updated 17h agoView on Hugging Face
2likes6downloads
sampling.py201 linesDownload Raw Back to root
1# Adapted for diffusers from multimodal-art-projection/YuE at commit ef1936f2ee39fe8de486a0f47a481c95f8d4da87.2# Licensed under Apache-2.0; see LICENSE.3from __future__ import annotations4 5import time6 7import torch8 9from .protocol import ABC_END, CODEC_OFFSET, CODEC_SIZE, CONTEXT, EOD, MUSIC_END10 11 12class YuE2StaticKVCache:13    """Preallocated token cache for eager decoding; returns views of the filled prefix without copying history."""14 15    def __init__(self, num_layers, batch_size, num_kv_heads, max_seq_len, head_dim, dtype, device):16        self.num_layers = num_layers17        self.max_seq_len = max_seq_len18        self.seen_tokens = 019        shape = (batch_size, num_kv_heads, max_seq_len, head_dim)20        self.keys = [torch.zeros(shape, dtype=dtype, device=device) for _ in range(num_layers)]21        self.values = [torch.zeros(shape, dtype=dtype, device=device) for _ in range(num_layers)]22 23    def get_seq_length(self):24        return self.seen_tokens25 26    def update(self, key, value, layer_idx):27        start, end = self.seen_tokens, self.seen_tokens + key.shape[1]28        if end > self.max_seq_len:29            raise ValueError(f"KV cache capacity {self.max_seq_len} exceeded by {end}; generation was not shortened")30        self.keys[layer_idx][:, :, start:end] = key.transpose(1, 2)31        self.values[layer_idx][:, :, start:end] = value.transpose(1, 2)32        if layer_idx == self.num_layers - 1:33            self.seen_tokens = end34        return self.keys[layer_idx][:, :, :end].transpose(1, 2), self.values[layer_idx][:, :, :end].transpose(1, 2)35 36 37def synchronize(device):38    if device.type == "cuda":39        torch.cuda.synchronize(device)40    elif device.type == "mps":41        torch.mps.synchronize()42 43 44def window_penalty(logits, recent_ids, penalty):45    if penalty == 1.0 or len(recent_ids) == 0:46        return logits47    recent = torch.as_tensor(recent_ids, dtype=torch.long, device=logits.device).reshape(1, -1)48    freq = torch.zeros_like(logits)49    freq.scatter_add_(-1, recent, torch.ones_like(recent, dtype=logits.dtype))50    alpha = penalty**freq51    return torch.where(logits < 0, logits * alpha, logits / alpha)52 53 54def distribution(logits, sampling, history, step, phase, legacy_off=False):55    # Planning-off requests keep the release's BF16 logits and top-3 floor; other modes sample from FP32 logits.56    scores = logits.clone() if legacy_off else logits.float().clone()57    end = ABC_END if phase == "abc" else MUSIC_END58    allowed = torch.full_like(scores, float("-inf"))59    if phase == "abc":60        allowed[..., :EOD] = 061    else:62        allowed[..., CODEC_OFFSET : CODEC_OFFSET + CODEC_SIZE] = 063    allowed[..., end] = 064    scores = scores + allowed65    if step < sampling.min_tokens:66        scores[..., end] = -torch.inf67    scores = window_penalty(scores, history[-sampling.penalty_window :], sampling.repetition_penalty)68    if sampling.temperature == 0:69        return scores70    if sampling.temperature != 1:71        scores = scores / sampling.temperature72    threshold = scores.topk(min(sampling.top_k, scores.shape[-1])).values[..., -1, None]73    scores = scores.masked_fill(scores < threshold, -torch.inf)74    if sampling.top_p < 1:75        values, indices = scores.sort(descending=True)76        probabilities = values.softmax(-1)77        removed = probabilities.cumsum(-1) - probabilities > sampling.top_p78        removed[..., : 3 if legacy_off else 1] = False79        values = values.masked_fill(removed, -torch.inf)80        scores = values.scatter(-1, indices, values)81    return scores82 83 84@torch.inference_mode()85def generate_tokens(86    transformer,87    prefix,88    sampling,89    seed,90    phase,91    device,92    negative=None,93    combine_logits=None,94    legacy_off=False,95    cancelled=None,96    on_token=None,97    graph_decoder=None,98):99    """Sample one stage's tokens.100 101    With `negative`, `combine_logits(conditional, unconditional)` applies guidance. `graph_decoder` (the `GraphAR`102    class) decodes with CUDA graphs on CUDA devices; elsewhere decoding stays eager.103    """104    if len(prefix) + sampling.max_tokens > CONTEXT:105        raise ValueError("Prefix + requested generation budget exceeds 24576; no implicit truncation")106    if negative is not None and (combine_logits is None or len(negative) + sampling.max_tokens > CONTEXT):107        raise ValueError("Guidance needs `combine_logits` and a negative prefix that fits the context")108    if cancelled is not None and cancelled():109        raise InterruptedError("Cancelled before prefill")110    # Both stages reset the request seed, as the release does.111    rng_device = device if device.type in {"cpu", "cuda"} else torch.device("cpu")112    generator = torch.Generator(device=rng_device).manual_seed(seed)113    config = transformer.config114 115    def prefill(ids):116        cache = YuE2StaticKVCache(117            num_layers=config.num_layers,118            batch_size=1,119            num_kv_heads=config.num_key_value_heads,120            max_seq_len=len(ids) + sampling.max_tokens,121            head_dim=config.attention_head_dim,122            dtype=transformer.dtype,123            device=device,124        )125        logits = transformer(torch.tensor([ids], device=device), kv_cache=cache, logits_to_keep=1).logits126        return logits[:, -1, :], cache127 128    graph = None129    positive_cache = negative_cache = None130    synchronize(device)131    start = time.perf_counter()132    try:133        if graph_decoder is not None and device.type == "cuda":134            graph = graph_decoder(135                transformer, [prefix] if negative is None else [prefix, negative], sampling.max_tokens, device136            )137            logits = graph.prefill()138            conditional = logits[:1]139            unconditional = logits[1:] if negative is not None else None140        else:141            conditional, positive_cache = prefill(prefix)142            unconditional = None143            if negative is not None:144                unconditional, negative_cache = prefill(negative)145        synchronize(device)146        prefill_seconds = time.perf_counter() - start147        history, first, eos = [], None, False148        end = ABC_END if phase == "abc" else MUSIC_END149        for step in range(sampling.max_tokens):150            if cancelled is not None and cancelled():151                raise InterruptedError(f"Cancelled during {phase}")152            logits = conditional if negative is None else combine_logits(conditional, unconditional)153            scores = distribution(logits, sampling, history, step, phase, legacy_off)154            if sampling.temperature == 0:155                next_id = scores.argmax(-1, keepdim=True)156            else:157                probabilities = scores.softmax(-1)158                if device.type == "mps":159                    next_id = torch.multinomial(probabilities.cpu(), 1, generator=generator).to(device)160                else:161                    next_id = torch.multinomial(probabilities, 1, generator=generator)162            token = int(next_id.item())163            if first is None:164                first = time.perf_counter() - start165            if on_token is not None:166                on_token(phase, token)167            if token == end:168                eos = True169                break170            history.append(token)171            if step + 1 < sampling.max_tokens:172                if graph is not None:173                    branch_logits = graph.step(next_id)174                    conditional = branch_logits[:1]175                    unconditional = branch_logits[1:] if negative is not None else None176                else:177                    conditional = transformer(next_id, kv_cache=positive_cache, logits_to_keep=1).logits[:, -1, :]178                    if negative_cache is not None:179                        unconditional = transformer(next_id, kv_cache=negative_cache, logits_to_keep=1).logits[180                            :, -1, :181                        ]182        synchronize(device)183        seconds = time.perf_counter() - start184        count = len(history) + int(eos)185        timing = {186            "seconds": seconds,187            "prefill_seconds": prefill_seconds,188            "ttft_seconds": first,189            "output_tokens": count,190            "content_tokens": len(history),191            "output_tps": count / seconds,192            "prefix_tokens": len(prefix),193            "cfg_branches": 1 if negative is None else 2,194            "execution": "cuda_graph" if graph is not None else "eager",195        }196        return history, timing, not eos197    finally:198        if graph is not None:199            graph.close()200        positive_cache = negative_cache = None201