[Bugfix] Handle empty FlatLogprobs slices and delta output (#53704)
Signed-off-by: tony <864832769@qq.com>
This commit is contained in:
@@ -208,3 +208,10 @@ def test_flat_logprobs_access() -> None:
|
||||
assert logprobs_last2.logprobs == [0.4, 0.5, 0.6, 0.1]
|
||||
assert logprobs_last2.ranks == [40, 50, 60, 10]
|
||||
assert logprobs_last2.decoded_tokens == ["40", "50", "60", "10"]
|
||||
|
||||
for empty_slice in (slice(0, 0), slice(3, 3), slice(10, 10)):
|
||||
empty = logprobs[empty_slice]
|
||||
assert isinstance(empty, FlatLogprobs)
|
||||
assert len(empty) == 0
|
||||
assert empty.start_indices == []
|
||||
assert empty.end_indices == []
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import math
|
||||
import time
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -14,7 +15,7 @@ from tests.v1.engine.utils import (
|
||||
MockEngineCore,
|
||||
)
|
||||
from vllm import PoolingParams
|
||||
from vllm.logprobs import PromptLogprobs, SampleLogprobs
|
||||
from vllm.logprobs import FlatLogprobs, Logprob, PromptLogprobs, SampleLogprobs
|
||||
from vllm.lora.request import LoRARequest
|
||||
from vllm.outputs import CompletionOutput, RequestOutput
|
||||
from vllm.sampling_params import RequestOutputKind, SamplingParams
|
||||
@@ -26,10 +27,39 @@ from vllm.v1.engine import (
|
||||
EngineCoreRequest,
|
||||
FinishReason,
|
||||
)
|
||||
from vllm.v1.engine.output_processor import OutputProcessor, RequestOutputCollector
|
||||
from vllm.v1.engine.output_processor import (
|
||||
OutputProcessor,
|
||||
RequestOutputCollector,
|
||||
RequestState,
|
||||
)
|
||||
from vllm.v1.metrics.stats import IterationStats, SchedulerStats
|
||||
|
||||
|
||||
@pytest.mark.parametrize("flat_logprobs", [False, True])
|
||||
def test_delta_output_without_new_tokens_returns_empty_logprobs(
|
||||
flat_logprobs: bool,
|
||||
) -> None:
|
||||
accumulated = FlatLogprobs() if flat_logprobs else []
|
||||
accumulated.append({1: Logprob(logprob=-0.5, rank=1)})
|
||||
|
||||
state = RequestState.__new__(RequestState)
|
||||
state.detokenizer = MagicMock()
|
||||
state.detokenizer.get_next_output_text.return_value = ""
|
||||
state.logprobs_processor = MagicMock()
|
||||
state.logprobs_processor.logprobs = accumulated
|
||||
state.logprobs_processor.cumulative_logprob = -0.5
|
||||
state.output_kind = RequestOutputKind.DELTA
|
||||
state.request_index = 0
|
||||
state.sampling_mask_chunks = []
|
||||
state.routed_experts_chunks = []
|
||||
state.spec_decode_metrics = None
|
||||
|
||||
output = state._new_completion_output([], None, None)
|
||||
|
||||
assert isinstance(output.logprobs, FlatLogprobs if flat_logprobs else list)
|
||||
assert len(output.logprobs) == 0
|
||||
|
||||
|
||||
def _ref_convert_id_to_token(
|
||||
tokenizer: TokenizerLike,
|
||||
token_id: int,
|
||||
|
||||
+9
-4
@@ -119,13 +119,18 @@ class FlatLogprobs(MutableSequence[LogprobsOnePosition | None]):
|
||||
for i in range(self.start_indices[index], self.end_indices[index])
|
||||
}
|
||||
elif isinstance(index, slice):
|
||||
min_index = self.start_indices[index][0]
|
||||
max_index = self.end_indices[index][-1]
|
||||
selected_starts = self.start_indices[index]
|
||||
selected_ends = self.end_indices[index]
|
||||
# Empty slices have no source offset to normalize.
|
||||
if not selected_starts:
|
||||
return FlatLogprobs()
|
||||
min_index = selected_starts[0]
|
||||
max_index = selected_ends[-1]
|
||||
return FlatLogprobs(
|
||||
# Shift updated start_indices and end_indices to
|
||||
# be 0-indexed
|
||||
start_indices=[i - min_index for i in self.start_indices[index]],
|
||||
end_indices=[i - min_index for i in self.end_indices[index]],
|
||||
start_indices=[i - min_index for i in selected_starts],
|
||||
end_indices=[i - min_index for i in selected_ends],
|
||||
token_ids=self.token_ids[min_index:max_index],
|
||||
logprobs=self.logprobs[min_index:max_index],
|
||||
ranks=self.ranks[min_index:max_index],
|
||||
|
||||
@@ -411,7 +411,11 @@ class RequestState:
|
||||
# Prepare logprobs, based on delta mode
|
||||
logprobs = self.logprobs_processor.logprobs
|
||||
if delta and logprobs:
|
||||
logprobs = logprobs[-len(token_ids) :]
|
||||
num_new_tokens = len(token_ids)
|
||||
# Avoid [-0:], which returns the full accumulated history when a
|
||||
# delta contains no new token IDs. [:0] preserves the concrete
|
||||
# list or FlatLogprobs representation while returning no entries.
|
||||
logprobs = logprobs[-num_new_tokens:] if num_new_tokens else logprobs[:0]
|
||||
|
||||
sampling_mask = None
|
||||
if finished and self.sampling_mask_chunks:
|
||||
|
||||
Reference in New Issue
Block a user