feat(tdt): add opt-in N-best beam decoding - #56
Conversation
Implement NeMo-compatible default TDT beam search, expose ranked hypotheses through Model, C API, and CLI surfaces, and add CPU/CUDA plus closed-loop NeMo parity coverage. Assisted-by: Codex:gpt-5 [Codex]
|
Fork CI completed successfully: build, server E2E, and strict closed-loop NeMo TDT N-best parity. Marking this ready for design/API feedback; the open questions in the description are intentionally unresolved. |
Validate requests before inference, reject malformed duration tables and non-progressing zero-duration expansions, and broaden real-model API coverage. [skip ci] Assisted-by: Codex:gpt-5 [Codex]
localai-org-maint-bot
left a comment
There was a problem hiding this comment.
There is one correctness edge case in the advertised beam_size >= 1 surface. When beam_size == 1 and duration 0 is the highest-probability duration, best_durations contains only duration 0. The blank fallback then chooses min_nonzero_duration_idx, which is the smallest duration value, not the highest-probability non-zero duration. That can select a lower-scoring/incorrect blank transition whenever another positive duration has higher probability. The beam-4 NeMo parity fixture does not exercise this.
Please select the best-scoring positive duration for this fallback (or rank blank-positive-duration candidates independently, matching NeMo) and add a model-independent regression where duration 0 ranks first but a non-minimal positive duration is the best legal blank duration.
The implementation and parity coverage otherwise look thoughtfully structured. After this is fixed, @mudler should also decide the two intentional product/API questions in the PR description before merge.
Select the highest-scoring positive duration when zero is the only top-k blank duration, and cover the beam-1 fallback independently of a model. Assisted-by: Codex:gpt-5 [Codex]
Keep the TDT beam test portable across compilers instead of relying on a transitive standard-library include. Assisted-by: Codex:gpt-5 [Codex]
|
Addressed the requested
The current head passed the full hosted workflow: Linux build/model-independent tests, server E2E, strict NeMo N-best parity, and the greedy transcript assertion: https://github.com/inlanger/parakeet.cpp/actions/runs/30248394029 |
localai-org-maint-bot
left a comment
There was a problem hiding this comment.
Re-reviewed at 2f37c2c. The beam-size-1 blank fallback now selects the highest-scoring legal positive duration, and the model-independent regression covers the exact zero-duration-ranked-first case. The implementation retains explicit malformed-duration guards, and the fresh hosted build, server E2E, and strict NeMo parity checks are green. Good to merge from my review. @mudler
Summary
Add an opt-in offline TDT N-best decoder without changing the existing greedy
path.
pk::Model, additive flat C API symbols, and CLI JSONThis is ready for design and API feedback before treating the new surface as
final.
Reference behavior
The implementation independently follows NVIDIA NeMo 2.7.3's
BeamTDTInfer.default_beam_search:log_softmax(token sequence, last frame)paths merge withlogaddexpscore / len(y_sequence)by default, including NeMo's leading SOS/blank sentinelOne edge case intentionally differs from NeMo: when the duration beam contains only duration 0, blank uses the highest-scoring positive duration rather than the smallest positive duration. This preserves score ordering for the advertised
beam_size=1surface and is covered by a model-independent regression.The C++ implementation additionally rejects malformed duration tables,
non-finite log probabilities, and a zero-duration expansion that does not
strictly reduce accumulated score. These checks fail explicitly; they do not
truncate valid hypotheses or apply NeMo's unsupported
max_symbols_per_stepparameter to default beam.
NeMo labels this default TDT beam strategy experimental and recommends
malsd_batch.This PR deliberately starts with the smaller directly comparable reference
algorithm; it does not claim that default beam is the final high-performance
decoder design.
Surface
Additive C API symbols:
The existing ABI version and all greedy entry points are unchanged. Details and
the JSON shape are in
docs/tdt-nbest.md.Validation
9f6c147test_tdt_beampassed on CPU and CUDA withtdt-0.6b-v3-q8_0.ggufb9abbbcis byte-identical to9f6c147, including all hypotheses, scores, and token metadata25b8a3afixes the beam-size-1 legal blank fallback and adds a model-independent regression25b8a3a; the regression also passed 100 consecutive runsA full manually dispatched hosted workflow passed against
2f37c2c: Linux build and 18 model-independent tests, server E2E, strict NeMo N-best parity, and the existing greedy transcript assertion.CUDA cold-process sanity check on an RTX PRO 2000 Blackwell, 7.4 s fixture,
with existing unrelated GPU services left running:
Those numbers include container startup, model load, mel, and encoder; they are
not presented as a decoder-only benchmark.
Open questions
malsd_batchbefore merge?AI assistance disclosure
This change was implemented with Codex assistance. The commits use the
repository's required
Assisted-by:trailer and intentionally have no AISigned-off-byorCo-Authored-Bytrailer. Human review and ownership arerequired before merge.