Skip to content

Add repetition penalty to the llm-runner - #176

Open
stikves wants to merge 4 commits into
apple:mainfrom
stikves:sukru/repetition-penalty
Open

Add repetition penalty to the llm-runner#176
stikves wants to merge 4 commits into
apple:mainfrom
stikves:sukru/repetition-penalty

Conversation

@stikves

@stikves stikves commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Adds repetition penalty to existing sampler pipelines.

For sequential ones, provides immediate logits penalty
For pipelined engine, it lags by the pipeline depth - 1 (currently: 2)

Closes: #43

A follow up should provide a better interface for logits buffer manipulation (currently only contained sampling and repetition penalty, so duplication is acceptable)

Penalizes tokens that appear in recent generation history, discouraging
repetitive output. Applied as a separate logit modification step before
the existing sampling pipeline (temperature/topK/topP/minP).

- Add repetitionPenalty and repetitionPenaltyWindow to SamplingConfiguration
- Add RepetitionPenaltyProcessor (deduplicates, sign-aware divide/multiply)
- Integrate into Sequential, StaticShape, VLM, and Constrained engines
- Only penalize generated tokens (not prompt) via generationStartOffset
- Pipelined engine: hard fail with clear error (GPU path in follow-up)
- CLI: --repetition-penalty and --repetition-penalty-window flags
@stikves
stikves force-pushed the sukru/repetition-penalty branch 3 times, most recently from 1b9a3fc to 5225f38 Compare August 15, 2026 19:02
Extend MPSGraphCompositeSampler with an optional penalty stage (penaltyEnabled
flag at init). When active, the compiled graph applies sign-aware penalty
(divide positive logits, multiply negative) before topK.

Refactor the monolithic graph-building init into composable static stage
helpers (applyPenaltyStage, topKStage, temperatureStage, softmaxStage,
minPStage, topPStage, maskAndNormalizeStage, multinomialStage, gatherTokenStage)
that can be unit-tested independently.

RepetitionPenaltyGPUState manages per-pipeline-depth rotating penalty buffers
with dirty-tracking: recordToken() updates only CPU-side ring state, and
buffer(forStep:) applies pending writes at encode time when the gate guarantees
no in-flight GPU read on that slot.

Inherent 2-token staleness from pipelineDepth=3 is acceptable for practical
window sizes. Greedy + penalty on pipelined is rejected at entry (use sequential).
@stikves
stikves force-pushed the sukru/repetition-penalty branch from 5225f38 to 0442649 Compare August 15, 2026 19:04
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.

Implement missing Sampler combinations

1 participant