Skip to content

Add XTC and token ban sampling steps - #256

Merged
turboderp merged 3 commits into
turboderp-org:devfrom
ethanj801:samplers-xtc-token-ban
Jul 29, 2026
Merged

Add XTC and token ban sampling steps#256
turboderp merged 3 commits into
turboderp-org:devfrom
ethanj801:samplers-xtc-token-ban

Conversation

@ethanj801

Copy link
Copy Markdown
Contributor

Summary

This PR introduces sampler steps that enable XTC sampling and the banning of tokens. Previous versions such as EXL2 had these sampling features, and they are present (but not hooked up) downstream in TabbyAPI (for the EXL3 backend, they work for the EXL2 backend).

This PR also includes a bugfix for an issue I encountered during testing.

Design Notes

  • SS_BanTokens: Very straightforward class. We cache the mask to avoid needing to recompute each token.
  • SS_XTC:
    • We implement this in the same way that EXL2 does, avoiding explicit randomness and instead creating the distribution mixture directly. This leads to the same sampling results as the probabilistic approach, except in cases where argmax sampling is used. This is reasonable since greedy sampling would seem to defeat the purpose of using XTC in the first place.
    • We use the same token exclusions as EXL2: all new line containing tokens and all special tokens.

Bugfix

During testing, SS_Argmax appeared to fail on unsorted states. It appears that this is due to the following.

The sorted branches indexed state.indices with the argmax positions alone, which selects
rows of the index tensor instead of one token per row:

case SS.PROBS_S | SS.PROBS_N_S:
    temp = torch.argmax(state.probs, dim = -1)
    state.sample = state.indices[temp]      # PR NOTE: issue is on this line

This appears to have been unreachable before due to the fusion meaning this code was basically never reached. I corrected it by applying the pattern from the SS.LOGITS_S state.

state.sample = state.indices[buffered_arange(state.bsz, state.in_logits.device), temp]

Testing

I added some tests to tests/test_sampler.py following the existing pattern. The tests check a few various edge cases and also show that our implementation has the same distributional result as the random version of XTC.

137 passed in 53.80s                          # fused sampler enabled
136 passed, 1 skipped in 119.60s              # EXL3_FUSED_SAMPLER=0

Reverting only custom.py to the first commit reproduces the SS_Argmax failure (RuntimeError: shape '[2]' is invalid for input of size 8), and restoring it passes.

Limitations

I did not implement either token banning or XTC into ComboSampler. My understanding is ComboSampler is designed to provide an easy interface for sampling, and so it would be ideal to add these samplers there. However, both of these steps require a tokenizer, which ComboSampler currently does not take. If desired we could add a tokenizer parameter to ComboSampler and add xtc parameter, token bans and an eos token ban option.

SS_BanTokens masks a fixed set of token IDs. It is recognized alongside the
penalty steps when collapsing a stack, so a ban keeps the fused tail.

SS_XTC excludes all but the least likely token above its threshold, leaving
protected IDs in place. It reweights the distribution rather than drawing the
outcome per token, which is the same distribution and needs no RNG. Only the
tokens above the threshold are scaled, bounding the work by 1/threshold.
The sorted branches indexed state.indices with the argmax positions alone,
selecting rows instead of one token per row. SS_XTC reaches them through its
prep steps, as does any stack with an explicit sort and any top-k greedy stack
under EXL3_FUSED_SAMPLER=0.
@turboderp
turboderp changed the base branch from master to dev July 29, 2026 23:41
@turboderp
turboderp merged commit ae22078 into turboderp-org:dev Jul 29, 2026
@turboderp

Copy link
Copy Markdown
Member

Thanks. 👍

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.

2 participants