67 lines
2.6 KiB
Python
67 lines
2.6 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
"""Unit tests for LogprobsProcessor.
|
|
|
|
These tests exercise the truncation invariant that the MRV2 sampler relies
|
|
on: when the sampler returns a row wider than a request's own
|
|
`num_logprobs + 1` (because another request in the batch needed a wider
|
|
row), the trailing positions are populated with sentinel values
|
|
(`token_id=0`, `logprob=-inf`). LogprobsProcessor must read only the first
|
|
`num_logprobs + 1` entries so those sentinels never reach the user.
|
|
"""
|
|
|
|
import numpy as np
|
|
|
|
from vllm.logprobs import create_sample_logprobs
|
|
from vllm.v1.engine.logprobs import LogprobsProcessor
|
|
from vllm.v1.outputs import LogprobsLists
|
|
|
|
|
|
def _make_processor(num_logprobs: int) -> LogprobsProcessor:
|
|
return LogprobsProcessor(
|
|
tokenizer=None,
|
|
logprobs=create_sample_logprobs(flat_logprobs=False),
|
|
prompt_logprobs=None,
|
|
cumulative_logprob=0.0,
|
|
num_logprobs=num_logprobs,
|
|
num_prompt_logprobs=None,
|
|
)
|
|
|
|
|
|
def test_drops_trailing_sentinel_columns():
|
|
"""A request that asked for 3 custom token logprobs but ended up in a
|
|
batch padded to width 5 must not surface the trailing -inf entries."""
|
|
processor = _make_processor(num_logprobs=3)
|
|
|
|
sampled = 42
|
|
# Layout: [sampled, custom_1, custom_2, custom_3, SENTINEL, SENTINEL]
|
|
# Use float32-exact values so cumulative_logprob compares cleanly.
|
|
token_ids = np.array([[sampled, 100, 200, 300, 0, 0]], dtype=np.int32)
|
|
logprobs = np.array([[-0.5, -1.0, -2.0, -3.0, -np.inf, -np.inf]], dtype=np.float32)
|
|
ranks = np.array([1], dtype=np.int32)
|
|
|
|
processor._update_sample_logprobs(LogprobsLists(token_ids, logprobs, ranks))
|
|
|
|
assert len(processor.logprobs) == 1
|
|
pos = processor.logprobs[0]
|
|
# Exactly sampled + 3 requested tokens; trailing sentinels dropped.
|
|
assert set(pos.keys()) == {sampled, 100, 200, 300}
|
|
assert 0 not in pos
|
|
assert all(np.isfinite(lp.logprob) for lp in pos.values())
|
|
# cumulative_logprob comes from the sampled token's logprob only.
|
|
assert processor.cumulative_logprob == -0.5
|
|
|
|
|
|
def test_accepts_exactly_sized_row():
|
|
"""When the row is exactly num_logprobs+1, no truncation needed."""
|
|
processor = _make_processor(num_logprobs=2)
|
|
|
|
token_ids = np.array([[7, 11, 13]], dtype=np.int32)
|
|
logprobs = np.array([[-0.5, -1.5, -2.5]], dtype=np.float32)
|
|
ranks = np.array([1], dtype=np.int32)
|
|
|
|
processor._update_sample_logprobs(LogprobsLists(token_ids, logprobs, ranks))
|
|
|
|
pos = processor.logprobs[0]
|
|
assert set(pos.keys()) == {7, 11, 13}
|