[Perf] Reduce fallback decode CPU by 69% at 32K (#60497)

Signed-off-by: spa5k <79936503+spa5k@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Kamran
2026-10-08 21:42:56 +00:00
committed by GitHub
co-authored by Codex
parent 240785b82c
commit 8d10c38b73
2 changed files with 61 additions and 7 deletions
+47 -1
View File
@@ -8,7 +8,11 @@ import pytest
from transformers import AutoTokenizer, PythonBackend, TokenizersBackend
from vllm.sampling_params import SamplingParams
from vllm.tokenizers.detokenizer_utils import convert_ids_list_to_tokens
from vllm.tokenizers.detokenizer_utils import (
convert_ids_list_to_tokens,
convert_prompt_ids_to_tokens,
detokenize_incrementally,
)
from vllm.tokenizers.mistral import MistralTokenizer
from vllm.tokenizers.protocol import TokenizerLike
from vllm.v1.engine import EngineCoreRequest
@@ -98,6 +102,48 @@ def tokenizer(tokenizer_name):
)
@pytest.mark.parametrize(
"tokenizer_name", ["openai-community/gpt2", "mistralai/Pixtral-12B-2409"]
)
def test_slow_decode_long_history_preserves_text_and_token_ids(tokenizer):
truth = "A map. 我很感谢你的热情 🙂🌶️\n" * 32
ids = tokenizer.encode(truth, add_special_tokens=False)
text, output_ids = _run_incremental_decode(
tokenizer, ids, skip_special_tokens=True, starting_index=0, fast=False
)
assert text == tokenizer.decode(ids, skip_special_tokens=True)
assert output_ids == ids
@pytest.mark.parametrize(
"tokenizer_name", ["openai-community/gpt2", "mistralai/Pixtral-12B-2409"]
)
def test_first_incremental_decode_returns_the_prompt_window(tokenizer):
ids = tokenizer.encode("A map in a library. " * 8, add_special_tokens=False)
prompt_tokens, _, _ = convert_prompt_ids_to_tokens(
tokenizer, ids[:-1], skip_special_tokens=True
)
new_token = tokenizer.convert_ids_to_tokens([ids[-1]], skip_special_tokens=True)
tokens, _, _, _ = detokenize_incrementally(
tokenizer, ids, None, 0, 0, skip_special_tokens=True
)
assert tokens == prompt_tokens + new_token
@pytest.mark.parametrize(
"tokenizer_name", ["openai-community/gpt2", "mistralai/Pixtral-12B-2409"]
)
def test_incremental_decode_past_the_window_emits_no_text(tokenizer):
ids = tokenizer.encode("A map in a library.", add_special_tokens=False)
tokens = tokenizer.convert_ids_to_tokens(ids[:-1], skip_special_tokens=True)
offset = len(tokens) + 1
_, text, prefix_offset, read_offset = detokenize_incrementally(
tokenizer, ids, tokens, offset, offset, skip_special_tokens=True
)
assert text == ""
assert (prefix_offset, read_offset) == (offset, offset)
@pytest.mark.parametrize("tokenizer_name", ["mistralai/Pixtral-12B-2409"])
@pytest.mark.parametrize(
"truth",
+14 -6
View File
@@ -230,7 +230,13 @@ def detokenize_incrementally(
_replace_none_with_empty(new_tokens) # type: ignore[arg-type]
else:
new_tokens = [""]
output_tokens = prev_tokens + new_tokens
output_token_count = len(prev_tokens) + len(new_tokens)
window_start = (
0 if is_first_iter else min(prefix_offset, read_offset, len(prev_tokens))
)
output_tokens = (
prev_tokens[window_start:] if window_start else prev_tokens
) + new_tokens
# If this is the first iteration, return all tokens.
if is_first_iter:
@@ -241,19 +247,21 @@ def detokenize_incrementally(
# surrounding ids.
if tokenizer.is_fast or not tokenizer.get_added_vocab():
prefix_text = tokenizer.convert_tokens_to_string(
output_tokens[prefix_offset:read_offset]
output_tokens[prefix_offset - window_start : read_offset - window_start]
)
new_text = tokenizer.convert_tokens_to_string(
output_tokens[prefix_offset - window_start :]
)
new_text = tokenizer.convert_tokens_to_string(output_tokens[prefix_offset:])
else:
prefix_text = _convert_tokens_to_string_with_added_encoders(
tokenizer,
output_tokens[prefix_offset:read_offset],
output_tokens[prefix_offset - window_start : read_offset - window_start],
skip_special_tokens=skip_special_tokens,
spaces_between_special_tokens=spaces_between_special_tokens,
)
new_text = _convert_tokens_to_string_with_added_encoders(
tokenizer,
output_tokens[prefix_offset:],
output_tokens[prefix_offset - window_start :],
skip_special_tokens=skip_special_tokens,
spaces_between_special_tokens=spaces_between_special_tokens,
)
@@ -266,4 +274,4 @@ def detokenize_incrementally(
return new_tokens, "", prefix_offset, read_offset
new_text = new_text[len(prefix_text) :]
return new_tokens, new_text, read_offset, len(output_tokens)
return new_tokens, new_text, read_offset, output_token_count