Expand description
The DRY repetition sampler (“Don’t Repeat Yourself”), ported from
llama.cpp’s llama_sampler_dry (src/llama-sampler.cpp:3078-3400),
which is itself a port of Koboldcpp PR 982 by pi6am.
§What it does that the repetition penalty cannot
penalties looks at SINGLE tokens: a token that occurred in the
window is made less likely, once. DRY looks at SEQUENCES. It asks,
for every token the model could emit next, “how long a repetition of
earlier context would emitting this token continue?”, and penalises
by multiplier * base ^ (that length - allowed_length). A model
looping on a four-token phrase is not emitting one over-represented
token, so the repetition penalty barely moves it while DRY’s
exponential grows every time round the loop.
§The three parts, and where each one comes from
DryBreakersisget_overlapping_token_sequences(src/llama-sampler.cpp:3095): the sequence breakers a caller gives as STRINGS, tokenised against the loaded vocabulary. A breaker is a point the repetition detector refuses to look past, so"\n"stops one paragraph’s phrasing from penalising the next. It has to be done against the model’s own vocabulary because a breaker string is usually not a whole token:":"may only ever appear as the tail of"foo:", so the entry is keyed on the token that CONTAINS it and carries whatever tokens must follow.DryParams::penaltiesisllama_sampler_dry_apply(src/llama-sampler.cpp:3151), including the reverse Z-algorithm that finds, in one linear pass, how long a suffix ending at each position also occurs elsewhere in the window.- [
crate::sampler_chain::Candidates::dry] subtracts the result.
§Why the parameters are a struct with private fields
Because enabling DRY without tokenising its breakers is a silent
wrong answer, not an error: the sampler runs, penalises across
newlines it was told to stop at, and nothing says so. So there is no
way to build an ENABLED DryParams without handing it a
DryBreakers, and the only way to build a non-empty
DryBreakers is DryBreakers::from_vocab, which needs a
vocabulary. A caller that genuinely wants none writes
DryBreakers::none and that is visible in the diff.
Structs§
- DryBreakers
- Sequence breakers, tokenised against one model’s vocabulary.
- DryParams
- One request’s DRY configuration.
- DryRequest
- DRY as a caller SPELLS it: four numbers and a list of strings, with the breakers not yet tokenised.
- DryVocab
Missing - DRY was asked for and there is no vocabulary to tokenise its sequence breakers against.
Constants§
- DEFAULT_
SEQUENCE_ BREAKERS - llama.cpp’s default sequence breakers
(
common/common.h:259,dry_sequence_breakers = {"\n", ":", "\"", "*"}).
Traits§
- DryVocab
- What DRY needs from a loaded model’s vocabulary, and nothing else.