"""English report of measured reward-guided search, never estimated timings.""" from collections import defaultdict import json import statistics as st import numpy as np import settings from reports import CSS, esc, table, card ROOT=settings.HERE/'search' def name(row): if row['kind']=='single':return 'Single sample' if row['kind']=='best_of_n':return 'Full-utterance Best-of-8' return f"{'Winner-of-8' if row['beam_width']==1 else 'Top-2 / budget 8'} · {row['chunk_frames']*80} ms" def quality_table(rows,emotion): grouped=defaultdict(list) for row in rows:grouped[name(row)].append(row) output=[] for label,group in sorted(grouped.items()): mean=lambda key:st.mean(x['final'][key] for x in group) ranks=[emotion[x['id']]['rank_percentile'] for x in group if x['id'] in emotion] output.append([label,str(len(group)),f"{mean('prefix_wer')*100:.2f}", f"{mean('clap'):.3f}",f"{mean('genuineness'):.3f}",f"{mean('blend'):.3f}", f"{mean('reward'):.3f}",f'{st.mean(ranks):.3f}' if ranks else 'pending']) return table(['Method','Takes','Raw WER % ↓','Style CLAP ↑','Genuine /6 ↑','Blend /10 ↑','Selection reward ↑','Held-out EIV rank percentile ↑'],output) def paired(rows): groups=defaultdict(dict) for row in rows:groups[name(row)][(row['case'],row['seed'])]=row baseline=groups.get('Full-utterance Best-of-8',{}) output=[] rng=np.random.default_rng(1827) for method,group in sorted(groups.items()): if method=='Full-utterance Best-of-8':continue for field in ['prefix_wer','clap','genuineness','reward']: blocks=defaultdict(list) for key,row in group.items(): if key in baseline:blocks[key[0]].append(row['final'][field]-baseline[key]['final'][field]) if not blocks:continue values=np.array([st.mean(x) for x in blocks.values()]) draws=rng.choice(values,size=(5000,len(values)),replace=True).mean(1) low,high=np.quantile(draws,[.025,.975]) output.append([method,field,f'{values.mean():+.4f}',f'[{low:+.4f}, {high:+.4f}]']) return table(['Method − Best-of-8','Metric','Mean paired delta','Descriptive 95% text-cluster interval'],output) def main(): rows=[] for phase in ['smoke','measure','quality','audit']: rows.extend(json.loads(p.read_text()) for p in sorted(ROOT.glob(phase+'-*.json'))) valid=[r for r in rows if not r.get('error')] measures=[r for r in valid if r['phase']=='measure'] quality=[r for r in valid if r['phase']=='quality'] emotion_file=ROOT/'emotion-check.json' eiv=json.loads(emotion_file.read_text()) if emotion_file.is_file() else {} emotion={x['id']:x for x in eiv.get('results',[])} validation=json.loads((ROOT/'validation.json').read_text()) if (ROOT/'validation.json').is_file() else {} (ROOT/'results.json').write_text(json.dumps(rows,indent=2,ensure_ascii=False)) body='' body+='

Training-free inference-time search · measured implementation

Listen, rank, fork, continue.

Reward-guided chunk search for Humaneness Voice Small: can we steer emotional speech while emitting irreversible audio, on one RTX 3090?

' body+='
'+card(str(len(valid)),'Actual output takes, including first-use checks')+card('4 / 8 / 12 / 16','Fixed parallel candidate budgets')+card('800 / 1600 ms','10 / 20 acoustic frames per search decision')+card('1 / 2','Retained prefixes; not token-level probability beams')+'
' body+='
Systems answer: yes, within the measured envelope. On one RTX 3090, warm eight-strand search measured about RTF 0.73 at 800 ms and 0.51 at 1600 ms, including ASR and quality selection. Sixteen strands measured about 1.13 at 800 ms (slower than real time), but 0.78 at 1600 ms. This is output-duration RTF, not aggregate candidate RTF or an end-to-end browser guarantee. First-use compilation can take tens of seconds.
' body+='
Quality answer: a trade-off, not a universal win. In the three speech-only texts × two seeds pilot, top-2/1600 ms and Best-of-8 both had zero mean measured WER. Top-2/1600 ms had a slightly higher combined selection reward but lower style CLAP. Other search variants introduced word errors, including substantial errors in a German take. Learned reward gains are not evidence of improved human naturalness.
' body+='

English summary of the proposed idea

A pretrained semantic decoder emits one conditioning vector per 80-ms acoustic frame. A local autoregressive Talker then generates the frame’s twelve acoustic tokens. Instead of finishing N independent utterances, generate N continuations for a short chunk, decode them, and score the spoken prefix and delivery. Keep either the single best prefix or the best two, clone their semantic and codec states, and generate fresh children. With a total budget of eight and width two, each retained prefix gets four children at the next step, and the best two are selected globally from the eight continuations.

' body+='
Winner-of-8: shared prefix → 8 chunk continuations → score → keep 1 → fork 8\nTop-2:       shared prefix → 8 chunk continuations → score → keep 2\n             each retained prefix → 4 children → 8 total → global top 2
' body+='

Width one is greedy, reward-guided chunk rollout / sequential best-of-N. Width two is a sampled, reward-guided beam-like search over audio prefixes. It is not conventional token-level beam search ranked by accumulated model log probability. The full prefix reward is recomputed, not summed across overlapping windows; summing would count the same words repeatedly. Future utterance-level reward is unknown, so neither mode is globally optimal.

' body+='

Architecture caveat: the question describes a roughly 600M semantic backbone plus a 525M local Talker. The checkpoint actually available in this demo has approximately 715.5M total parameters and a 112.8M Talker/bridge, as documented in its model card. These timings therefore do not establish real-time performance for a different 525M-Talker model. The search mechanism applies conceptually to that architecture, but it needs a new benchmark.

' body+='

What was implemented

' body+='

Reward, normalization and partial WER

style = clip((centered_cosine + 1) / 2, 0, 1)\ngenuine = clip(genuineness / 6, 0, 1)\nblend = clip(burst_blend / 10, 0, 1)\nquality = 0.50 * style + 0.25 * genuine + 0.25 * blend\nreward = quality * max(0, 1 - prefix_WER)
' body+='

Thus Genuineness plus Burst Blend jointly carry the same nominal weight as style similarity. Fixed scales keep parent/time comparisons meaningful; candidate-set min–max normalization would change the meaning of a score when one bad candidate appears or disappears. Equal nominal weights do not imply equal empirical influence: CLAP has a narrower observed range, and all three quality terms share an encoder. The bounded “inverse WER” factor is 1−WER, not 1/WER, which would be singular at perfect speech.

' body+='

The style query comes only from delivery instructions and parenthesized acting cues. Known literal transcript text and quoted material are removed; spoken content is never a fallback style query. This is style matching, not a speaker-identity verification score. Voice identity is conditioned by the reference, not independently checked with a speaker recognizer.

' body+='

At intermediate boundaries, ASR runs on the cumulative audible prefix, retaining words with end timestamps at least 120 ms before the right edge. Word Levenshtein alignment chooses the target-prefix endpoint with minimum edit count; the not-yet-spoken suffix is free, internal deletions/substitutions are not. Empty recognized speech gets a zero intelligibility gate. At EOS or the frame cap, the complete target and complete hypothesis are used. Prefix WER is a surrogate, not a valid final-utterance WER or a confidence estimate. Timestamp filtering helps but cannot guarantee a stable boundary word.

' body+='
Intentional pauses and bursts need a better gate. A chunk containing only an intended groan, laugh or silence can have empty ASR and hence zero reward in this implementation. It then falls back to stable row-order tie breaking. The exploratory groan case tests this limitation; no burst-presence detector is included in the search reward. A high Blend score does not demonstrate that a requested burst exists or occurred at the right time.
' body+='

Irreversible streaming versus a real beam

Winner-of-N commits each chosen chunk immediately: discarded histories are gone forever. For top-2, only an identical acoustic-token prefix of both retained beams can be emitted. If the surviving children later share one ancestor, that shared prefix becomes streamable. Otherwise output must wait until the final winner is known. The code never plays the current leader and subsequently swaps it for another voice trajectory.

A bounded-latency variant would retain both beams for one look-ahead chunk and then commit to one ancestor, discarding incompatible histories. That is useful but changes the search into a commitment-constrained beam. It is proposed below, not silently substituted for the exact common-prefix top-2 mode tested here. Complete-utterance Best-of-N could likewise stream only a shared prefix; independent sampled acoustic sequences generally offer none.

' body+='

One-GPU versus two-GPU performance

One-GPU rows place every active TTS, codec, ASR and quality model on cuda:0, a single RTX 3090 with 24 GiB VRAM. The second card is unused for active computation. Two-GPU rows place TTS/codec on card 0 and scorers on card 1. Scoring precedes the next expansion, so a second card does not remove the sequential decision dependency. No competing GPU jobs ran during measurements; clocks were not locked.

Warm table below uses the second seed (2027) after each shape’s preceding trial. All first trials remain in the complete data, including compilation/capture costs. Each row is a measured observation, not a population average. The generation hint and hard cap were 6.6 s, quantized upward to 83 frames / 6.64 s; natural EOS was enabled and no minimum length was forced. Many outputs reached the cap, and generated trailing silence/noise remains in the RTF denominator.

' for layout,title in [('one_gpu','Single RTX 3090'),('two_gpu','Two RTX 3090s, separate scorer card')]: output=[] for n in [4,8,12,16]: for chunk in [10,20]: for width in [1,2]: candidates=[r for r in measures if (r['layout'],r['n'],r['chunk_frames'],r['beam_width'],r['seed'])==(layout,n,chunk,width,2027)] if not candidates:continue r=candidates[0];p=r['performance'] output.append([str(n),str(width),str(chunk*80),f"{p['search_rtf']:.3f}", f"{p['first_commit_seconds']:.3f}",f"{p['tts_codec_seconds']:.3f}", f"{p['scoring_seconds']:.3f}",f"{r['peak_vram_gib'][0]:.2f}", 'Yes' if p['search_rtf']<1 else 'No']) body+=f'

{title}

'+table(['N','Beam width','Chunk ms','Search RTF ↓','First committed PCM, s','TTS/codec GPU s','Scoring wall s','Peak card-0 GiB','RTF <1'],output) body+='

Search RTF = search critical-path wall seconds / final delivered raw PCM seconds. It includes prompt packing/reference coding, TTS/codec, GPU transfers, cumulative-prefix ASR, timestamp processing, quality heads, CPU ranking and cache cloning. It excludes model loading, one-time style text-query embedding, Luna, MP3 encoding, optional final alignment/evaluation, HTTP and browser playback. This differs deliberately from the earlier TTS-only GPU event RTF. An N-way aggregate audio throughput divided by N is not used to claim real-time playback.

' cold=sorted(measures,key=lambda r:-r['performance']['search_wall_seconds'])[:5] body+='

First-use costs are real

'+table(['Actual run','Search seconds','RTF','Graph capture s'],[[r['id'],f"{r['performance']['search_wall_seconds']:.2f}",f"{r['performance']['search_rtf']:.2f}",f"{r['performance']['graph_capture_seconds']:.2f}"] for r in cold]) audits=[r for r in valid if r['phase']=='audit'] if audits: body+='

Fresh-seed speech/language stress checks

After profiling one anger text, winner search was checked on the fear and German-affection texts with a fresh seed 12345, again on one card. These are additional systems checks, not many independent speakers.

'+table(['Text','N','Chunk ms','RTF','First commit s','Raw WER %'],[[r['case'],str(r['n']),str(r['chunk_frames']*80),f"{r['performance']['search_rtf']:.3f}",f"{r['performance']['first_commit_seconds']:.3f}",f"{r['final']['prefix_wer']*100:.1f}"] for r in audits]) speech=[r for r in quality if r['case']!='burst_en'] burst=[r for r in quality if r['case']=='burst_en'] body+='

Quality: single sample versus whole-utterance BoN versus search

The primary comparison is three fixed texts (anger English, fear English, affection German) × two seeds × six methods = 36 selected outputs. Every method uses the same text, reference, CFG, temperature and 83-frame cap. Best-of-8 is ranked by the same fixed-scale reward, not the legacy UI’s candidate-min–max normalization. Equal N does not mean identical random samples or equal total compute: search evaluates many prefix sets, while BoN evaluates the finished set once. No human listening study, independent ASR or speaker-identity evaluation was performed.

' body+=quality_table(speech,emotion) body+='

The direction is mixed even under automatic evaluation: compared with Best-of-8, top-2/1600 ms lowered style CLAP (0.151 vs 0.201) and had slightly lower independently measured emotion rank percentile (0.829 vs 0.842), despite a higher combined search reward (0.574 vs 0.563). Top-2/800 ms had higher emotion rank percentile (0.882) but mean WER 14.55%. Winner-of-8/800 ms had mean WER 6.06% versus 7.73% for one sample, with an error concentrated in one take. These few observations do not establish a generally better decoder.

' body+='

Paired effects versus Best-of-8

Seeds are paired within text; bootstrap resamples the three text clusters after averaging each seed pair. With only three clusters, intervals are descriptive and very weak evidence. Negative WER deltas are better; positive quality deltas are better. This analysis is not corrected for multiple comparisons.

'+paired(speech) if burst: body+='

Exploratory real burst / shout recipe

After the speech-only comparison, a separate structured prompt requested a 0.3-second frustrated groan followed by angry shouted speech. No settings were re-tuned. Two seeds per method are only a diagnostic. This recipe is not comparable to the caption-only cases as an isolated causal emotion effect.

'+quality_table(burst,emotion) body+='

Independent emotion-model check

The post-search check uses the Empathic-Insight-Voice-Small heads with the documented mkrausio/EmoWhisper-AnS-Small-v0.1 encoder and ReLU activation, on raw output. This encoder/head set was not used for selection. Actual loaded head count: '+esc(eiv.get('head_count','pending'))+'. Rank percentile is normalized by this actual count, not interpreted as a probability or an intensity guarantee. It provides a differently modeled diagnostic, still not a human rating. ASR, Genuineness, Blend and CLAP endpoint scores reuse the ranking models and are vulnerable to selection/reward hacking.

' body+='

Correctness and practical UI behavior

'+esc(json.dumps(validation,indent=2))+'

The validation checks one four-row / twenty-frame trajectory. With a constant selector, chunk-search continuation produced exactly the same acoustic tokens and PCM as the optimized normal stream’s first row. Concatenated emitted chunks exactly equaled the final raw PCM. Independently loaded packaged head towers matched the shared VoiceCLAP embedding numerically. These checks do not prove all future cache revisions or human perceptual quality; unknown codec state shapes fail closed.

' browser_check=settings.HERE/'test-results/search-browser.json' if browser_check.is_file(): checked=json.loads(browser_check.read_text()) if len(checked)==5 and {r['n'] for r in checked}=={1,3,4,8,16}: body+='

Actual HTTPS Chromium integration checks passed at BS 1, 3, 4, 8 and 16 across both chunk sizes. The checks verified all 1–16 UI options, effective single-path behavior at BS 1, audio arriving before the completed result, decoded MP3 segment durations matching raw PCM duration without encoder-padding gaps, mono 96-kbps encoding, session-private audio access and mobile layout. These developer smoke tests used the live two-card deployment and are separate from the isolated one-card throughput/quality measurements; they do not establish performance for every intermediate BS.

' body+='

The live demo adds two generation modes, every batch size from 1 through 16, 800/1600-ms search chunks and a configurable duration cap. Top-2 divides N children between the retained prefixes; for odd N the higher-ranked prefix receives the extra child (e.g. 4+3 for BS 7). BS 1 uses one path in either mode. The isolated throughput measurements above cover N=4/8/12/16, not every intermediate size; a newly used shape may require first-use compilation. The demo sends mono 96-kbps MP3 segments as soon as PCM is committed, schedules decoded segments using Web Audio, and keeps the final complete take downloadable. Live audio is raw; forced-alignment fades apply only to the finished take and cannot retroactively alter audio already heard. Private reference uploads and generated chunks keep the existing session isolation and one-hour cleanup. The browser stream may underrun despite model RTF <1 if compilation, HTTP/MP3 decoding or a delayed beam commitment exhausts its buffer.

' body+='

Assessment and improvements worth pursuing

  1. Use winner-of-8 at 800 ms for a low-delay starting point; use 1600 ms for more throughput headroom. Sixteen strands need 1600 ms in these measurements. Keep search optional: it is not proven to beat BoN for overall voice quality.
  2. Protect semantic progress. Prefix-WER can prefer slowing down or an easy partial phrase. Add monotonic alignment/progress constraints, expected speech/non-speech masks and calibrated uncertainty for short ASR spans; use complete-target WER at completion.
  3. Control burst timing and identity separately. Add a localized burst-presence term or hard eligibility check for actual requested events, and a consented reference-speaker embedding constraint. Blend and style CLAP alone cannot verify either.
  4. Bound beam latency explicitly. Offer a one-chunk look-ahead commitment-constrained beam as a distinct mode, or keep an exact top-2 mode and show when output must wait. Do not splice unrelated beam PCM or crossfade to hide incompatible histories.
  5. Preserve diversity. Two near-identical children of one parent can eliminate the other promising beam immediately. Consider per-parent diversity quotas, distinct acoustic-prefix deduplication or soft/particle resampling, with a clearly changed selection rule.
  6. Calibrate and audit the reward. Learn fixed percentile scales on an external calibration set, validate held-out emotions/texts/voices and use blind human pairwise listening. More search can exploit a proxy rather than improve speech; a CLAP/Genuine/Blend shared backbone is not three independent judges.
  7. Reduce repeated scoring work. The biggest implemented saving is one batch embedding instead of three encodes per candidate. Prefix rescoring still re-encodes cumulative audio; a truly cached streaming ASR/quality encoder, bounded rolling windows plus transcript progress, and shortlist-first scoring could help. They require new accuracy/cost checks, not merely smaller windows.
  8. Keep model likelihood as a safety signal. Track per-frame probability/entropy and apply a calibrated plausibility constraint or KL-style regularizer, rather than selecting arbitrarily off-model prefixes solely by a noisy short-window proxy. This is a future extension, not a measured result here.
' body+='

All measured output takes

Each row is a selected final output, not every discarded branch. Complete per-chunk candidate scores and retained row indices are in the JSON; discarded branch audio was not archived. Filter by phase, method, case, N, beam or chunk. Playback files are raw generated mono MP3s, not source references.

' compact=[{'id':r['id'],'audio':r['audio'],'wer':r['final']['prefix_wer'],'reward':r['final']['reward'], 'hyp':r['final']['hyp'],'rtf':r['performance']['search_rtf'],'first':r['performance']['first_commit_seconds']} for r in valid] body+='''' body+='

Reproducibility and sources

Design/environment · All measured results and chunk traces · Cache/embedding validation · Unselected emotion-model evaluation · Implementation and reproduction notes

NVIDIA Parakeet v3 model card documents multilingual support and timestamp capabilities. Official Transformers Parakeet implementation/docs describe duration/timestamp handling. Inference-Time Reward Hacking in Large Language Models motivates a proxy-hacking caution by analogy, not direct evidence for this TTS model.

' body+='' html='Humaneness Voice Small — reward-guided chunk search
'+body+'
' (ROOT/'index.html').write_text(html) print(json.dumps({'takes':len(valid),'measure':len(measures),'quality':len(quality),'audit':len(audits), 'emotion_checks':len(emotion),'errors':len(rows)-len(valid)}),flush=True) if __name__=='__main__':main()