Skip to content

Fix crash in GreedyTokenSampler when top-K probability sum is zero#487

Open
tsushanth wants to merge 1 commit into
argmaxinc:mainfrom
tsushanth:fix/issue-478-sampler-zero-probsum
Open

Fix crash in GreedyTokenSampler when top-K probability sum is zero#487
tsushanth wants to merge 1 commit into
argmaxinc:mainfrom
tsushanth:fix/issue-478-sampler-zero-probsum

Conversation

@tsushanth

Copy link
Copy Markdown

Summary

  • Guard Float.random(in: 0..<probSum) in GreedyTokenSampler.sampleFromProbs against degenerate softmax output.
  • Fall back to argmax when top-K probabilities sum to zero or NaN.
  • Add a regression test that reproduces the original crash.

Problem

When softmax output becomes numerically degenerate — all logits at -inf, NaN propagation, or extreme underflow — the top-K probabilities sum to zero. Float.random(in: 0..<probSum) then traps with:

Fatal error: Can't get random value with an empty range

I confirmed this locally with the new test: temporarily reverting the guard reproduces the exact crash from Swift's FloatingPointRandom.swift:52.

Fix

Inline guard in Sources/TTSKit/Utilities/Sampling.swift. When probSum is zero or non-finite, return the highest-probability token from the top-K window (argmax fallback). Lock-free, no new dependencies, no API changes.

Test plan

  • New regression test testGreedySamplerZeroProbSumFallsBackToArgmax constructs [1, 1, vocabSize] logits at -Float.infinity, calls sampleCodec0 with topK=4, asserts no crash and a valid token index.
  • Verified the test reproduces the original crash without the guard.
  • All 5 existing GreedyTokenSampler tests pass.
  • swift build succeeds.

Fixes #478

When softmax output is numerically degenerate (all logits at -inf, NaN,
or extreme underflow), the top-K probabilities sum to zero or NaN.
`Float.random(in: 0..<probSum)` then traps with
"Fatal error: Can't get random value with an empty range".

Guard against `probSum <= 0` and non-finite sums by falling back to
argmax over the top-K probabilities. Adds a regression test that
reproduces the original crash without the guard.

Fixes argmaxinc#478

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a runtime trap in GreedyTokenSampler when numerically degenerate softmax output causes the top‑K probability sum to be zero (or non-finite), by adding a guard and an argmax-style fallback. It also adds a regression test intended to reproduce the original crash scenario.

Changes:

  • Add a probSum finiteness/positivity guard in GreedyTokenSampler.sampleFromProbs to avoid Float.random(in: 0..<probSum) trapping on an empty/invalid range.
  • Fall back to selecting a top‑K token when probSum is zero or non-finite.
  • Add a new unit test covering degenerate softmax behavior that previously caused a crash.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
Sources/TTSKit/Utilities/Sampling.swift Adds guard + fallback path to prevent Float.random(in:) from trapping when top‑K probability sum is zero/non-finite.
Tests/TTSKitTests/TTSKitUnitTests.swift Adds a regression test intended to reproduce the degenerate-softmax crash scenario.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +241 to +244
guard probSum.isFinite, probSum > 0 else {
let maxIdx = probsArray.enumerated().max(by: { $0.element < $1.element })?.offset ?? 0
return Int32(idxArray[maxIdx])
}
Comment on lines +304 to +307
// Every logit at -inf → softmax → all zeros (or NaN). Tag index 9 with a
// slightly less-negative value so argmax has a clear winner to fall back to.
for i in 0..<vocabSize { ptr[i] = FloatType(-Float.infinity) }
ptr[9] = FloatType(-1e30)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fatal crash in GreedyTokenSampler.sampleFromProbs when top-K probability sum is zero

2 participants