Download code/beam_search.py from laion/humaneness-voice-small-studies: direct link, hf CLI and curl.
- Browser
- Download file 10.5 kB
-
https://huggingface.co/spaces/laion/humaneness-voice-small-studies/resolve/main/code/beam_search.py
- Command line
-
hf download hf://spaces/laion/humaneness-voice-small-studies/code/beam_search.py
-
curl -L -o beam_search.py https://huggingface.co/spaces/laion/humaneness-voice-small-studies/resolve/main/code/beam_search.py
10.5 kB
| """Causal reward-guided chunk search with persistent global/codec KV caches. | |
| Winner-of-N: keep one prefix and fork it N ways at each chunk. | |
| Top-2: retain up to two global winners, split N children (extra to the best). | |
| Only common acoustic | |
| token prefixes are irreversible streaming output; unrelated beams are not spliced. | |
| """ | |
| import math | |
| import time | |
| import numpy as np | |
| import torch | |
| from performance_core import combine_branches, StreamingCodec | |
| def expansion_indices(winners, n): | |
| if not winners or n < len(winners): | |
| raise ValueError('Candidate budget must cover retained beam count') | |
| quotient, remainder = divmod(n, len(winners)) | |
| return [index for position,index in enumerate(winners) | |
| for _ in range(quotient + (position < remainder))] | |
| def common_prefix(codes, rows): | |
| if len(rows) == 1: | |
| return int(codes[rows[0], :, 0].ne(-1).sum()) | |
| same = codes[rows].eq(codes[rows[0]].unsqueeze(0)).all(-1).all(0) | |
| same &= codes[rows[0], :, 0].ne(-1) | |
| differing = (~same).nonzero() | |
| return int(differing[0]) if len(differing) else codes.shape[1] | |
| def reorder_codec(codec, indexes, n): | |
| """Pinned codec state has per-row tensors, all with batch axis zero. | |
| Copy via index_select, including duplicates; never share mutable child KV. | |
| Fail closed if a new codec revision adds an unsupported state shape. | |
| """ | |
| for module in codec.modules(): | |
| state = getattr(module, '_streaming_state', None) | |
| if state is None: | |
| continue | |
| for name, value in vars(state).items(): | |
| if torch.is_tensor(value): | |
| if value.ndim == 0 or value.shape[0] != n: | |
| raise ValueError(f'Unsupported codec state tensor {name}: {tuple(value.shape)}') | |
| setattr(state, name, value.index_select(0, indexes)) | |
| class ChunkSearch: | |
| def __init__(self, engine, scorer): | |
| self.engine, self.scorer = engine, scorer | |
| def generate(self, spec, n=8, beam_width=1, chunk_frames=10, max_seconds=6.6, | |
| guidance=1.5, temperature=1., seed=777, reference_path=None, on_commit=None): | |
| if not 1 <= n <= 16 or beam_width not in [1,2]: | |
| raise ValueError('Search supports batch sizes 1 through 16 and beam width 1/2') | |
| requested_beam_width = beam_width | |
| beam_width = min(n, beam_width) | |
| if chunk_frames not in [10,20]: | |
| raise ValueError('Search chunk must be 800 or 1600 ms') | |
| engine, mdl = self.engine, self.engine.model | |
| cfg = mdl.config | |
| budget = min(750, math.ceil(max_seconds/.08)) | |
| p = {'max_new_tokens':budget, 'audio_temperature':temperature, 'audio_top_p':.95, | |
| 'audio_top_k':50, 'audio_repetition_penalty':1., 'text_temperature':0. if temperature==0 else 1., | |
| 'text_top_p':1., 'text_top_k':50} | |
| timeline, committed, first_commit = [], 0, None | |
| started = time.perf_counter() | |
| with engine.lock, torch.cuda.device(engine.device), torch.autocast('cuda',dtype=torch.bfloat16): | |
| reference = engine.reference(reference_path) if reference_path else None | |
| branches = [engine.pack(spec['prompt'],spec,reference,n)] | |
| if guidance != 1 and spec['prompt'] != spec['unconditional']: | |
| branches.append(engine.pack(spec['unconditional'],spec,reference,n)) | |
| ids, initial = combine_branches(branches,cfg.pad_token_id,cfg.audio_pad_token_id) | |
| nb, length = len(branches), ids.shape[1] | |
| masks = torch.zeros(n*nb,length+budget,dtype=torch.bool,device=engine.device) | |
| masks[:,:length] = initial | |
| past, model_input, steps = None, ids, 0 | |
| codes = torch.empty(n,0,12,dtype=torch.long,device=engine.device) | |
| finished = torch.zeros(n,dtype=torch.bool,device=engine.device) | |
| pcm = [np.empty(0,dtype=np.float32) for _ in range(n)] | |
| torch.manual_seed(seed) | |
| torch.cuda.manual_seed_all(seed) | |
| capture_start = engine.fast.capture_seconds | |
| decoder = engine.proc.audio_tokenizer | |
| with StreamingCodec(decoder,n,cfg.audio_pad_token_id) as streaming: | |
| while steps < budget: | |
| phase_start = time.perf_counter() | |
| event_start,event_end = [torch.cuda.Event(enable_timing=True) for _ in range(2)] | |
| event_start.record() | |
| new = [] | |
| for _ in range(min(chunk_frames,budget-steps)): | |
| out = mdl.transformer(inputs_embeds=mdl._build_inputs_embeds(model_input),input_ids=None, | |
| attention_mask=masks[:,:length+steps],past_key_values=past,use_cache=True, | |
| position_ids=None,output_attentions=False,output_hidden_states=False, | |
| return_dict=True,cu_seqlens=None,num_sequences=None) | |
| past = out.past_key_values | |
| local = mdl._global_hidden_to_local(out.last_hidden_state[:,-1]).to(mdl.local_transformer.ln_f.weight.dtype) | |
| stop,sampled = engine.fast.frame(local,n,nb,guidance,p,graph=True) | |
| continues = stop.eq(cfg.audio_assistant_slot_token_id) & ~finished | |
| finished |= stop.eq(cfg.audio_end_token_id) | |
| if not bool(continues.any()): | |
| break | |
| frame = sampled.masked_fill(~continues.unsqueeze(-1),cfg.audio_pad_token_id) | |
| new.append(frame) | |
| row = mdl._build_generation_row(n,ids.device,frame) | |
| row[:,0,0] = torch.where(continues,row[:,0,0],cfg.pad_token_id) | |
| model_input = row.repeat(nb,1,1) | |
| masks[:,length+steps] = continues.repeat(nb) | |
| steps += 1 | |
| if new: | |
| chunk = torch.stack(new,dim=1) | |
| codes = torch.cat((codes,chunk),dim=1) | |
| wave,lengths = streaming.decode(chunk) | |
| for i in range(n): | |
| pcm[i] = np.concatenate((pcm[i],wave[i,:int(lengths[i])].float().cpu().numpy())) | |
| event_end.record() | |
| event_end.synchronize() | |
| generation_seconds = time.perf_counter()-phase_start | |
| endpoint = steps>=budget or bool(finished.all()) or not new | |
| # Scoring exits cuda:0 autocast so cuda:1's FP32 quality | |
| # tower/head precision remains unchanged. | |
| with torch.autocast('cuda', enabled=False): | |
| scores = self.scorer.score(pcm,spec['text'],[endpoint or bool(x) for x in finished.cpu()]) | |
| order = sorted(range(n),key=lambda i:(-scores[i]['reward'],scores[i]['prefix_wer'],i)) | |
| winners = order[:beam_width] if not endpoint else order[:1] | |
| safe = common_prefix(codes,winners) | |
| if safe < committed: | |
| raise RuntimeError('Search attempted to revise committed acoustic prefix') | |
| committed_seconds = max(0,safe-committed)*.08 | |
| entry = {'step':len(timeline)+1,'frame':steps,'retained_rows':winners, | |
| 'committed_audio_seconds':committed_seconds,'committed_until_seconds':safe*.08, | |
| 'generation_wall_seconds':generation_seconds,'tts_codec_device_seconds':event_start.elapsed_time(event_end)/1000, | |
| 'scores':scores, **self.scorer.last_timing} | |
| if safe > committed: | |
| if first_commit is None: | |
| first_commit = time.perf_counter()-started | |
| segment = pcm[winners[0]][committed*3840:safe*3840].copy() | |
| if on_commit: | |
| on_commit(segment,entry) | |
| committed = safe | |
| timeline.append(entry) | |
| if endpoint: | |
| winner = winners[0] | |
| break | |
| indexes = torch.tensor(expansion_indices(winners,n),device=engine.device) | |
| branch_indexes = torch.cat([indexes+branch*n for branch in range(nb)]) | |
| past = tuple(tuple(value.index_select(0,branch_indexes) for value in layer) for layer in past) | |
| masks = masks.index_select(0,branch_indexes) | |
| model_input = model_input.index_select(0,branch_indexes) | |
| codes = codes.index_select(0,indexes) | |
| finished = finished.index_select(0,indexes) | |
| pcm = [pcm[i].copy() for i in indexes.cpu().tolist()] | |
| reorder_codec(decoder,indexes,n) | |
| else: | |
| winner = 0 | |
| output = pcm[winner] | |
| engine.last_codes = [codes[winner][codes[winner,:,0].ne(cfg.audio_pad_token_id)].cpu()] | |
| capture_seconds = engine.fast.capture_seconds-capture_start | |
| total = time.perf_counter()-started | |
| seconds = len(output)/48000 | |
| if not seconds: | |
| raise RuntimeError('Search generated no audio; try another seed/reference') | |
| performance = {'n':n,'beam_width':beam_width,'requested_beam_width':requested_beam_width, | |
| 'chunk_ms':chunk_frames*80,'max_seconds':max_seconds, | |
| 'actual_seconds':seconds,'search_wall_seconds':total,'search_rtf':total/seconds, | |
| 'first_commit_seconds':first_commit,'tts_codec_seconds':sum(x['tts_codec_device_seconds'] for x in timeline), | |
| 'scoring_seconds':sum(x['total_seconds'] for x in timeline),'graph_capture_seconds':capture_seconds, | |
| 'streaming_rule':'Winner commits immediately; top-2 emits only common acoustic-token prefixes', | |
| 'includes':'reference encoding, packing, global/local TTS, codec, GPU transfers, batched ASR/timestamps, shared VoiceCLAP, heads, CPU selection and KV cloning', | |
| 'excludes':'model loading, one-time style text-query embedding, Luna, MP3 encoding, final optional alignment/evaluation, network/playback', | |
| 'device':str(engine.device),'scorer_device':str(self.scorer.device), | |
| 'timeline':timeline,'final_search_score':scores[winner], | |
| 'hit_frame_limit':steps>=budget and not bool(finished[winner])} | |
| return output,performance | |