TTSKit : guard sampleFromProbs against zero-sum top-k probabilities (#450)#459
Open
achyutbenz19 wants to merge 1 commit intoargmaxinc:mainfrom
Open
TTSKit : guard sampleFromProbs against zero-sum top-k probabilities (#450)#459achyutbenz19 wants to merge 1 commit intoargmaxinc:mainfrom
achyutbenz19 wants to merge 1 commit intoargmaxinc:mainfrom
Conversation
GreedyTokenSampler.sampleFromProbs crashes with 'Fatal error: Can't get random value with an empty range' when every top-k probability rounds to zero. Reported during long-form generation (audiobook chapters) at low temperature (0.10) and small top-k (15), where numerical underflow accumulates across hundreds of chunks. Add a guard that falls back to greedy selection (the highest- probability token, which MLTensor.topK returns first) when probSum is zero. Apply the same guard to the non-topK branch for completeness, since softmax underflow can in principle zero that array too. Fixes argmaxinc#450
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #450.
GreedyTokenSampler.sampleFromProbscrashes withFatal error: Can't get random value with an empty rangewhen every top-k probability rounds to zero. The call isFloat.random(in: 0..<probSum, using: &rng); whenprobSum == 0the range is empty and Swift traps.The reporter triggers this during long-form TTS generation (audiobook chapters) at low temperature (0.10) and small top-k (15). Numerical underflow accumulates across hundreds of chunks until a chunk's softmax output lands entirely below single-precision range for those 15 slots.
Scope of the change
Sources/TTSKit/Utilities/Sampling.swift, +12/-0 on one method.probSum > 0before callingFloat.random(in: 0..<probSum). On underflow, fall back to greedy selection by returning the highest-probability token.MLTensor.topKreturns entries in descending probability order, soidxArray.firstis the argmax.probsArray.reduce(0, +)for completeness. Softmax normally sums to 1, but the same numerical path can underflow in principle.The guard changes behavior only when
probSum == 0, which is the crash case. All paths where the old code returned a valid token continue to do the same random draw bit-for-bit.Match to reporter's proposal
The reporter suggested:
That is exactly what this patch does. Greedy fallback (rather than, say, uniform-random over top-k) matches the intent of a temperature that has already collapsed the distribution.
Build
Builds clean on
Xcode 26.1.1/Swift 6.2.1against theTTSKitproduct target.What this does not do
probSum > 0is byte-identical, including RNG advancement order.sampleFromProbsstill returnsInt32.Tools used
git,swift build, andaudiokitfor the rest of the audio PRs in this session. Skipped running an audiokit differential matrix on this specific change because the patch only adds guards along the crash-only path (probSum == 0); every branch whereprobSum > 0is byte-for-byte identical to the pre-patch code, including RNG draw order. No audio-output differential is possible against a path that crashes pre-patch.Disclosure
I am an AI assistant (Anthropic's Claude) helping a user contribute this fix. I reproduced the crash path by inspection of the code and verified the patch compiles against current
main.