Skip to content

[Bugfix][MiniCPM-o] Apply the Talker's 16-frame codec penalty on MRv2 - #8576

Merged
linyueqian merged 1 commit into
vllm-project:mainfrom
linyueqian:fix/minicpmo-mrv2-talker-penalty
Oct 8, 2026
Merged

linyueqian merged 1 commit into
vllm-project:mainfrom
linyueqian:fix/minicpmo-mrv2-talker-penalty

Conversation

@linyueqian

Copy link
Copy Markdown
Collaborator

Purpose

On the MRv2 runner, the MiniCPM-o 4.5 Talker is meant to apply a repetition penalty only over the codec codes of the last 16 frames, as the V1 path does in _apply_batched_repetition_penalty. Since the vLLM 0.31 rebase (#8459) that penalty never runs.

In vLLM 0.31 the MRv2 Sampler builds self.logits_processors = [LogitBiasState, self.penalties_state, BadWordsState, *custom] in __init__, registers every request with each entry, and applies them through processor.apply(logits, ctx). _install_mrv2_talker_sampler only reassigned sampler.penalties_state, so the list kept the stock PenaltiesState: the stock 1.05 penalty ran over the whole prompt and output (including the dummy prompt id 0), and the Talker's window penalty was never called. The wrapper also still used the 0.30 interface.

This change, scoped to the MiniCPM-o Talker:

  • _CodecWindowPenaltiesState implements vLLM 0.31's LogitsProcessor: add_request returns whether processing is needed, and apply(logits, ctx) applies the 16-frame window repetition penalty over output codes, then delegates frequency/presence to the stock state with its repetition factor neutralized.
  • _install_mrv2_talker_sampler replaces the stock penalty entry in that sampler instance's logits_processors by identity (and fails loudly if it is missing), and keeps penalties_state pointing at the wrapper so the runner still reads output_bin_counts. Nothing is patched globally; other MRv2 samplers are unchanged.

custom_logits_processors cannot disable the stock penalty, which is why the entry is replaced rather than appended.

Test Plan

vLLM Version: 0.31.0

vLLM-Omni Commit: this branch on d5a338010

  • New CUDA test test_mrv2_sampler_applies_codec_window_penalty_instead_of_stock_penalty drives the real 0.31 Sampler/RequestState and compares logits with V1's _apply_batched_repetition_penalty.
  • pytest tests/model_executor/models/minicpmo_4_5 tests/worker_v2 on H200.
  • E2E on H200: turn_mrv2 profile, 128 Seed-TTS EN prompts at C=8, main vs this branch, plus the default V1 profile; Whisper large-v3. Both MRv2 arms carry [Core][Model] Unified Full-Duplex MRv2 Support and MiniCPM-o 4.5 Adaptation #8536's one-line omni_ar_model_runner.py fix locally (not part of this PR) so the separate duplicated-hidden-state bug does not mask this change.

Test Result

The new test fails on main (3 of 32 logits differ: prompt id 0, an out-of-window code, and an in-window code penalized once instead of 1.05^3) and passes with this change. The GPU suites pass: 1161 passed, 5 skipped.

Processor list on the Talker sampler: main ['LogitBiasState', 'PenaltiesState', 'BadWordsState'], this PR ['LogitBiasState', '_CodecWindowPenaltiesState', 'BadWordsState']. While serving, the logits changed per row equal the distinct codes in the last 16 frames, id 0 is never touched, and factors are 1/1.05 and 1/1.05^2 by frequency, as on V1.

Arm Failed WER mean WER > 0.3 Loops Median clip
main, turn_mrv2 0 1.95% 0 0 4.06 s
this PR, turn_mrv2 0 1.94% 1 0 3.96 s
V1 default 0 1.75% 1 0 3.96 s

The two items above 0.3 are one-word ASR slips. Throughput is unchanged within noise. Seed-TTS EN clips are about 4 s, so this run cannot show the long-answer drift the window penalty targets; no long-form A/B was run.

Since the vLLM 0.31 rebase the MRv2 sampler runs its penalty stage from
`sampler.logits_processors` (`Sampler.add_request` registers requests
with every list entry and `apply_sampling_params` calls each entry's
`apply(logits, ctx)`). `_install_mrv2_talker_sampler` only rebound
`sampler.penalties_state`, so the list kept the stock `PenaltiesState`:
the Talker's codec window penalty never ran, and the stock presence
penalty (repetition_penalty 1.05 over the whole prompt and output,
including the placeholder prompt id 0) was applied instead.

Make `_CodecWindowPenaltiesState` a vLLM 0.31 `LogitsProcessor`
(`add_request` returns whether it applies, `apply(logits, ctx)`), put it
in the stock penalty state's slot of the sampler's own pipeline, and keep
`penalties_state` pointing at it for the runner's output bin counts.

Add a CUDA test that drives the real MRv2 `Sampler` and checks the
processed logits match the V1 `_apply_batched_repetition_penalty`.

Signed-off-by: Yueqian Lin <linyueqian@outlook.com>
@linyueqian linyueqian added the ready label to trigger buildkite CI label Oct 7, 2026
@vllm-omni-review-bot

Copy link
Copy Markdown

This PR appears to belong to: docs/design/module/model_integration.md, docs/design/module/ar_runtime.md.

Module owners: @tzhouam @fake0fan @Gaohan123

Routing: @tzhouam via module of the changed files, CODEOWNERS; @fake0fan via module of the changed files; @Gaohan123 via module of the changed files

@linyueqian, please review your own changes and leave a short self-review comment describing what you checked. PRs without author self-review may not be assigned a reviewer.

Please take a look when you have a chance. If you would like an automated review, mention @vllm-omni-review-bot in a comment.

@vllm-omni-review-bot

Copy link
Copy Markdown
Omni ReviewBot routing record

Assigned Strict on cursor (cursor-grok-4.6-high) under experiment fleet-strict-cursor-grok46-zcode-glm53flash-5050-c5-z10-20261002.

@hsliuustc0106 hsliuustc0106 added the high priority high priority issue, needs to be done asap label Oct 7, 2026 — with ChatGPT Codex Connector
@hsliuustc0106 hsliuustc0106 added the bug Something isn't working label Oct 8, 2026

@Sy0307 Sy0307 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The replacement reaches the real vLLM 0.31 sampler and restores the 16-frame codec repetition penalty while preserving frequency and presence penalties. H200 validation passed 1,139 tests (5 skipped); the new regression fails with the base implementation, and independent real-sampler checks matched the oracle through mixed penalties, row reordering, and slot reuse. No blocking issue found; this validation did not include full-model generation or long-form audio quality.

BeatSeat added a commit to BeatSeat/vllm-omni that referenced this pull request Oct 8, 2026
Reuse the existing Talker prompt-window recipe for native MRv2 updates, retain the codec penalty window across conditions, and flush confirmed sampled EOS without ending a live session early. Integrates the sampler pipeline registration fix from vllm-project#8576. Add V1/MRv2 live-client CI coverage and remove independent H200 precision tuning from this PR.

Signed-off-by: BeatSeat <wendavid552@gmail.com>
@linyueqian
linyueqian merged commit 508ceaa into vllm-project:main Oct 8, 2026
8 of 9 checks passed
khairulkabir1661 pushed a commit to khairulkabir1661/vllm-omni that referenced this pull request Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working high priority high priority issue, needs to be done asap ready label to trigger buildkite CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants