[misc] Trim restating comments and docstrings in srt/managers (#35622)
This commit is contained in:
@@ -15,15 +15,47 @@ Applies to `#` and `//` comments, Python docstrings, and C/C++ Doxygen blocks
|
|||||||
like code, with the burden of proof reversed: the author justifies a comment's
|
like code, with the burden of proof reversed: the author justifies a comment's
|
||||||
existence, not the reviewer its removal.
|
existence, not the reviewer its removal.
|
||||||
|
|
||||||
**The test.** Delete the comment. If someone familiar with the repo can recover
|
## Two modes
|
||||||
the fact from the surrounding code plus a grep, it stays deleted.
|
|
||||||
|
|
||||||
The next three sections are that test applied. A comment either carries a fact
|
Writing a comment and editing someone else's are different decisions.
|
||||||
you cannot see from here (**keep**), carries nothing the code does not already
|
|
||||||
carry (**delete**), or carries a real fact whose home is somewhere else
|
|
||||||
(**move**).
|
|
||||||
|
|
||||||
## Keep: facts you cannot see from here
|
**Writing.** You still have the context that made the comment necessary, so the
|
||||||
|
judgment is reliable. Everything below `## Cleanup` is written for this case.
|
||||||
|
|
||||||
|
**Editing.** The judgment is unreliable and the error is one-way. A one-line
|
||||||
|
comment carries too little text to tell a restatement apart from the last anchor
|
||||||
|
for a cross-file fact -- deciding takes the whole function and its callers, more
|
||||||
|
context than the line costs. And the payoff is asymmetric: keeping a useless
|
||||||
|
one-liner costs a line of scroll, while deleting a load-bearing one deletes a
|
||||||
|
fact silently, inside a diff of two hundred deletions where no reviewer will
|
||||||
|
catch it. So: a bright line, not a judgment call.
|
||||||
|
|
||||||
|
> **A comment-only diff does not touch one-line comments.** It removes or
|
||||||
|
> condenses multi-line prose blocks. A one-liner is rewritten only for a reason
|
||||||
|
> of its own -- it is wrong, it is stale, or it is commented-out code -- never
|
||||||
|
> because the line below it says the same thing.
|
||||||
|
|
||||||
|
## Cleanup: what a comment-only diff may remove
|
||||||
|
|
||||||
|
- **Multi-line prose restating the code** -- the function name, the next line,
|
||||||
|
the branch condition, or the loop body, written out as a paragraph.
|
||||||
|
- **Python `Args:` / `Returns:` blocks** on anything that is not a documented API
|
||||||
|
surface -- see `## Documentation blocks` for the list of surfaces that keep
|
||||||
|
them.
|
||||||
|
- **Multi-line history and rationale** -- what the code used to do, why the
|
||||||
|
change was made, which approach was abandoned. Each of these has a home
|
||||||
|
elsewhere (see `## Where other explanations live`).
|
||||||
|
- **Commented-out code**, at any length.
|
||||||
|
|
||||||
|
Condense rather than delete when a block carries one fact that is not
|
||||||
|
recoverable: keep that sentence, drop the enumeration around it.
|
||||||
|
|
||||||
|
## What a comment is for
|
||||||
|
|
||||||
|
State the fact a reader cannot see from here. Delete the comment and ask what it
|
||||||
|
costs to recover: a fact that lives in another file costs everything, a grouping
|
||||||
|
the names only half-encode costs a tedious reconstruction, a restated line costs
|
||||||
|
nothing.
|
||||||
|
|
||||||
- **Cross-boundary constraints.** Layout, field order, or call order shared with
|
- **Cross-boundary constraints.** Layout, field order, or call order shared with
|
||||||
a CUDA kernel, the Rust router, an IPC schema, or another process. Nothing in
|
a CUDA kernel, the Rust router, an IPC schema, or another process. Nothing in
|
||||||
@@ -70,29 +102,51 @@ carry (**delete**), or carries a real fact whose home is somewhere else
|
|||||||
# None means the request is excluded from the radix cache, not that lookup failed.
|
# None means the request is excluded from the radix cache, not that lookup failed.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Delete: nothing the code does not already carry
|
- **Structure the names only partly encode** -- a group boundary in a long flat
|
||||||
|
block, a section split in a long body. `# ===== Helpers =====` above two
|
||||||
|
functions costs nothing to see past; the same banner splitting a genuinely long
|
||||||
|
flat module (see `python/sglang/srt/environ.py`) is the only statement of where
|
||||||
|
one group ends.
|
||||||
|
|
||||||
- **Restating the code.** The function name, the next line, the branch
|
Not worth writing, at any length: prose that restates the line below it,
|
||||||
condition, or the loop body in prose.
|
`# Step 1:` / `# Step 2:` numbering over straight-line code (extract named
|
||||||
- **Step-by-step play-by-play.** `# Step 1: ...` / `# Step 2: ...` over
|
helpers if the flow needs numbers), the names of the callers (that is what grep
|
||||||
straight-line code. If the flow needs numbering, extract named helpers.
|
is for), and hedging -- "this should probably be revisited" is either a fact to
|
||||||
- **Naming the callers.** That is what grep is for.
|
establish and state, or a `TODO(<owner>)`.
|
||||||
- **Section banners on short bodies.** `# ===== Helpers =====` above two
|
|
||||||
functions. Banners are for genuinely long modules only
|
|
||||||
(see `python/sglang/srt/environ.py`).
|
|
||||||
- **Hedging.** "This should probably be revisited." Either establish the fact
|
|
||||||
and state it, or file it as `TODO(<owner>)`.
|
|
||||||
|
|
||||||
## Move: real facts that live somewhere else
|
## Form and tags
|
||||||
|
|
||||||
|
- **One or two lines.** A genuinely intricate invariant may run longer; that is a
|
||||||
|
rare exception, not a licence. Documentation blocks are the separate case
|
||||||
|
below.
|
||||||
|
- **ASCII and English only.** No Unicode arrows, math symbols, or CJK.
|
||||||
|
- **Break at a clause boundary.** If a comment needs a second line, wrap after a
|
||||||
|
semicolon or a comma -- never mid-phrase. A sentence that will not split
|
||||||
|
cleanly is a sentence that should be shortened instead.
|
||||||
|
- **Attach the comment to the line it constrains**, not to the top of the
|
||||||
|
function. Comments collected into a preamble are the ones that go stale.
|
||||||
|
- **You change the line, you own its comment.** Update it or delete it -- never
|
||||||
|
leave it orphaned. A stale comment is worse than no comment.
|
||||||
|
|
||||||
|
Two tag spellings only. New code does not use `FIXME`, `XXX`, or `HACK`; existing
|
||||||
|
occurrences are grandfathered and get folded into these when the line is touched.
|
||||||
|
|
||||||
|
- `# NOTE:` -- a constraint or trap. Most of the time the prefix adds nothing;
|
||||||
|
drop it and just state the fact.
|
||||||
|
- `# TODO(<gh-handle>):` -- planned work, **always** with an owner or an issue
|
||||||
|
link. A bare `# TODO: fix this` is rejected in review; an unowned TODO is
|
||||||
|
never retired. `TODO(perf)` and similar topic tags are acceptable when the work
|
||||||
|
is a standing category rather than one person's task.
|
||||||
|
|
||||||
|
## Where other explanations live
|
||||||
|
|
||||||
Every explanation has exactly one home. A second copy in a comment drifts from
|
Every explanation has exactly one home. A second copy in a comment drifts from
|
||||||
the first.
|
the first.
|
||||||
|
|
||||||
- **What the code used to do -> `git log`.** Comments describe the current
|
- **What the code used to do -> `git log`.** Comments describe the current
|
||||||
state: not what was tried first, not which approach was abandoned.
|
state: not what was tried first, not which approach was abandoned. The
|
||||||
|
exception is a past failure that is still a live constraint -- write it as the
|
||||||
The exception is a past failure that is still a live constraint. That is not
|
constraint, not as the story.
|
||||||
history -- but write it as the constraint, not as the story.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Bad: We used to call this before init_new but it broke CUDA graph capture.
|
# Bad: We used to call this before init_new but it broke CUDA graph capture.
|
||||||
@@ -104,44 +158,16 @@ the first.
|
|||||||
diff, and is written for a reviewer who is long gone.
|
diff, and is written for a reviewer who is long gone.
|
||||||
- **Design rationale -> `docs/` or a module docstring. CLI semantics -> the
|
- **Design rationale -> `docs/` or a module docstring. CLI semantics -> the
|
||||||
`ServerArgs` help text. Test intent -> the test.**
|
`ServerArgs` help text. Test intent -> the test.**
|
||||||
- **Superseded code -> `git show`.** Never leave commented-out code behind.
|
- **Superseded code -> `git show`.**
|
||||||
|
|
||||||
Also out: review attribution ("as suggested in review") and our own PR numbers
|
Also out: review attribution ("as suggested in review") and our own PR numbers
|
||||||
used as a changelog. An upstream issue URL is different -- it is not a changelog
|
used as a changelog. An upstream issue URL is different -- it is not a changelog
|
||||||
entry but a workaround's retirement condition, and the Keep section requires it.
|
entry but a workaround's retirement condition, and the section above requires it.
|
||||||
|
|
||||||
What stays next to the line is why *this line* exists, written for a reader who
|
What stays next to the line is why *this line* exists, written for a reader who
|
||||||
has neither the PR nor the discussion.
|
has neither the PR nor the discussion.
|
||||||
|
|
||||||
## Form
|
## Documentation blocks
|
||||||
|
|
||||||
Governs `#` / `//` comments; the length and placement of documentation blocks
|
|
||||||
follow the section below. ASCII-and-English applies to both.
|
|
||||||
|
|
||||||
- **One or two lines.** A genuinely intricate invariant may run longer; that is
|
|
||||||
a rare exception, not a licence.
|
|
||||||
- **ASCII and English only.** No Unicode arrows, math symbols, or CJK.
|
|
||||||
- **Break at a clause boundary.** If a comment needs a second line, wrap after a
|
|
||||||
semicolon or a comma -- never mid-phrase. A sentence that will not split
|
|
||||||
cleanly is a sentence that should be shortened instead.
|
|
||||||
- **Attach the comment to the line it constrains**, not to the top of the
|
|
||||||
function. Comments collected into a preamble are the ones that go stale.
|
|
||||||
- **You change the line, you own its comment.** Update it or delete it -- never
|
|
||||||
leave it orphaned. A stale comment is worse than no comment.
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
Two spellings only. New code does not use `FIXME`, `XXX`, or `HACK`; existing
|
|
||||||
occurrences are grandfathered and get folded into these when the line is touched.
|
|
||||||
|
|
||||||
- `# NOTE:` -- a constraint or trap. Most of the time the prefix adds nothing;
|
|
||||||
drop it and just state the fact.
|
|
||||||
- `# TODO(<gh-handle>):` -- planned work, **always** with an owner or an issue
|
|
||||||
link. A bare `# TODO: fix this` is rejected in review; an unowned TODO is
|
|
||||||
never retired. `TODO(perf)` and similar topic tags are acceptable when the work
|
|
||||||
is a standing category rather than one person's task.
|
|
||||||
|
|
||||||
## API documentation blocks
|
|
||||||
|
|
||||||
Python docstrings and Doxygen blocks are part of the product on the surfaces
|
Python docstrings and Doxygen blocks are part of the product on the surfaces
|
||||||
users, integrators, and tooling read, and noise everywhere else. Where warranted
|
users, integrators, and tooling read, and noise everywhere else. Where warranted
|
||||||
@@ -162,3 +188,11 @@ they may run past two lines; every other rule in this file still applies.
|
|||||||
- **No:** internal helpers, overrides, private methods. Never hand-write or
|
- **No:** internal helpers, overrides, private methods. Never hand-write or
|
||||||
generate Python `Args:` / `Returns:` blocks -- the signature and its type
|
generate Python `Args:` / `Returns:` blocks -- the signature and its type
|
||||||
hints already carry the names and types.
|
hints already carry the names and types.
|
||||||
|
|
||||||
|
The one exception is the orchestration step. In the frozen classes
|
||||||
|
(`Scheduler`, `TokenizerManager`, `ModelRunner` -- see
|
||||||
|
`.claude/skills/large-class-style`), each `init_*` / `handle_*` / event-loop
|
||||||
|
method is an override point a subclass picks from a list; its one-line
|
||||||
|
docstring is the catalog entry that says what the step does, so it stays even
|
||||||
|
when it reads close to the method name. A genuine private helper
|
||||||
|
(`_validate_*`, `_normalize_*`) that no subclass overrides still gets nothing.
|
||||||
|
|||||||
@@ -372,9 +372,6 @@ class MultimodalDataItem:
|
|||||||
return len([item for item in flatten_nested_list(l) if item is not None]) == 0
|
return len([item for item in flatten_nested_list(l) if item is not None]) == 0
|
||||||
|
|
||||||
def set_pad_value(self):
|
def set_pad_value(self):
|
||||||
"""
|
|
||||||
Set the pad value after first hashing the data
|
|
||||||
"""
|
|
||||||
if self.pad_value is not None:
|
if self.pad_value is not None:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -722,9 +719,6 @@ class MultimodalInputs:
|
|||||||
return image_tokens, audio_tokens, video_tokens
|
return image_tokens, audio_tokens, video_tokens
|
||||||
|
|
||||||
def merge(self, other: MultimodalInputs):
|
def merge(self, other: MultimodalInputs):
|
||||||
"""
|
|
||||||
merge image inputs when requests are being merged
|
|
||||||
"""
|
|
||||||
|
|
||||||
# args needed to be merged
|
# args needed to be merged
|
||||||
optional_args = [
|
optional_args = [
|
||||||
@@ -1233,11 +1227,7 @@ class Req(ReqDllmMixin):
|
|||||||
return self.kv_committed_len
|
return self.kv_committed_len
|
||||||
|
|
||||||
def update_spec_correct_drafts_histogram(self, num_correct_drafts: int):
|
def update_spec_correct_drafts_histogram(self, num_correct_drafts: int):
|
||||||
"""Update the speculative decoding acceptance histogram.
|
"""Record one step accepted draft count (excludes bonus token) into the histogram."""
|
||||||
|
|
||||||
Args:
|
|
||||||
num_correct_drafts: Number of correct draft tokens (no bonus) in this step.
|
|
||||||
"""
|
|
||||||
if len(self.spec_correct_drafts_histogram) <= num_correct_drafts:
|
if len(self.spec_correct_drafts_histogram) <= num_correct_drafts:
|
||||||
self.spec_correct_drafts_histogram.extend(
|
self.spec_correct_drafts_histogram.extend(
|
||||||
[0] * (num_correct_drafts - len(self.spec_correct_drafts_histogram) + 1)
|
[0] * (num_correct_drafts - len(self.spec_correct_drafts_histogram) + 1)
|
||||||
@@ -1459,9 +1449,6 @@ class Req(ReqDllmMixin):
|
|||||||
return self.tokenizer.decode(self.output_ids[-tail_len:])
|
return self.tokenizer.decode(self.output_ids[-tail_len:])
|
||||||
|
|
||||||
def check_match_stop_str_prefix(self) -> bool:
|
def check_match_stop_str_prefix(self) -> bool:
|
||||||
"""
|
|
||||||
Check if the suffix of tail_str overlaps with any stop_str prefix
|
|
||||||
"""
|
|
||||||
if not self.sampling_params.stop_strs:
|
if not self.sampling_params.stop_strs:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
@@ -833,13 +833,6 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
|
|||||||
def _detect_input_format(
|
def _detect_input_format(
|
||||||
self, texts: Union[str, List[str]], is_cross_encoder: bool
|
self, texts: Union[str, List[str]], is_cross_encoder: bool
|
||||||
) -> InputFormat:
|
) -> InputFormat:
|
||||||
"""Detect the format of input texts for proper tokenization handling.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
- InputFormat.SINGLE_STRING: Regular single text like "Hello world"
|
|
||||||
- InputFormat.BATCH_STRINGS: Regular batch like ["Hello", "World"]
|
|
||||||
- InputFormat.CROSS_ENCODER_PAIRS: Cross-encoder pairs like [["query", "document"]]
|
|
||||||
"""
|
|
||||||
if isinstance(texts, str):
|
if isinstance(texts, str):
|
||||||
return InputFormat.SINGLE_STRING
|
return InputFormat.SINGLE_STRING
|
||||||
|
|
||||||
@@ -894,38 +887,6 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
|
|||||||
Tuple[List[int], Optional[List[int]]],
|
Tuple[List[int], Optional[List[int]]],
|
||||||
Tuple[List[List[int]], Optional[List[List[int]]]],
|
Tuple[List[List[int]], Optional[List[List[int]]]],
|
||||||
]:
|
]:
|
||||||
"""
|
|
||||||
Tokenize text(s) using the appropriate tokenizer strategy.
|
|
||||||
|
|
||||||
This method handles multiple input formats and chooses between async dynamic
|
|
||||||
batch tokenizer (for single texts only) and regular tokenizer.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
texts: Text input in various formats:
|
|
||||||
|
|
||||||
Regular cases:
|
|
||||||
- Single string: "How are you?"
|
|
||||||
- Batch of strings: ["Hello", "World", "How are you?"]
|
|
||||||
|
|
||||||
Cross-encoder cases (sentence pairs for similarity/ranking):
|
|
||||||
- Single pair: [["query text", "document text"]]
|
|
||||||
- Multiple pairs: [["q1", "d1"], ["q2", "d2"], ["q3", "d3"]]
|
|
||||||
|
|
||||||
is_cross_encoder: Whether to return token_type_ids for cross-encoder models.
|
|
||||||
Enables proper handling of sentence pairs with segment IDs.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Single input cases:
|
|
||||||
Tuple[List[int], Optional[List[int]]]: (input_ids, token_type_ids)
|
|
||||||
Example: ([101, 2129, 102], [0, 0, 0]) for single text
|
|
||||||
Example: ([101, 2129, 102, 4068, 102], [0, 0, 0, 1, 1]) for cross-encoder pair
|
|
||||||
|
|
||||||
Batch input cases:
|
|
||||||
Tuple[List[List[int]], Optional[List[List[int]]]]: (batch_input_ids, batch_token_type_ids)
|
|
||||||
Example: ([[101, 2129, 102], [101, 4068, 102]], None) for regular batch
|
|
||||||
|
|
||||||
Note: token_type_ids is None unless is_cross_encoder=True.
|
|
||||||
"""
|
|
||||||
if not texts or self.tokenizer is None:
|
if not texts or self.tokenizer is None:
|
||||||
raise ValueError("texts cannot be empty and tokenizer must be initialized")
|
raise ValueError("texts cannot be empty and tokenizer must be initialized")
|
||||||
|
|
||||||
@@ -1490,11 +1451,6 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
|
|||||||
token_id: int,
|
token_id: int,
|
||||||
embeds: List[torch.Tensor],
|
embeds: List[torch.Tensor],
|
||||||
) -> PositionalEmbeds:
|
) -> PositionalEmbeds:
|
||||||
"""Resolve placeholder positions in input_ids and create PositionalEmbeds.
|
|
||||||
|
|
||||||
Scans input_ids for occurrences of token_id and pairs them with the
|
|
||||||
provided embedding tensors.
|
|
||||||
"""
|
|
||||||
positions = [idx for idx, tok in enumerate(input_ids) if tok == token_id]
|
positions = [idx for idx, tok in enumerate(input_ids) if tok == token_id]
|
||||||
if len(positions) != len(embeds):
|
if len(positions) != len(embeds):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@@ -1692,11 +1648,8 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
|
|||||||
state: ReqState,
|
state: ReqState,
|
||||||
is_stream: bool,
|
is_stream: bool,
|
||||||
) -> Optional[dict]:
|
) -> Optional[dict]:
|
||||||
"""Handle abort/error finish reasons from the scheduler.
|
"""Returns the output dict to yield (stream abort), None for normal flow;
|
||||||
|
raises ValueError/HTTPException for non-stream aborts."""
|
||||||
Returns the output dict if it should be yielded (stream abort), or None
|
|
||||||
for normal flow. Raises ValueError or HTTPException for non-stream aborts.
|
|
||||||
"""
|
|
||||||
finish_reason = out["meta_info"]["finish_reason"]
|
finish_reason = out["meta_info"]["finish_reason"]
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -3433,17 +3386,6 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
|
|||||||
def _should_dispatch_to_encoder(
|
def _should_dispatch_to_encoder(
|
||||||
self, obj: Union[GenerateReqInput, EmbeddingReqInput]
|
self, obj: Union[GenerateReqInput, EmbeddingReqInput]
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Check if the request should be dispatched to encoder for processing.
|
|
||||||
|
|
||||||
Returns True if the request should be dispatched to encoder (multiple multimodal items),
|
|
||||||
False if it should be processed locally (single multimodal item or no multimodal items).
|
|
||||||
|
|
||||||
Args:
|
|
||||||
obj: The request input object
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: True if should dispatch to encoder, False otherwise
|
|
||||||
"""
|
|
||||||
if obj.batch_size > 1:
|
if obj.batch_size > 1:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Batch request (batch_size=%d) is not supported in EPD disaggregation mode; skipping encoder dispatch.",
|
"Batch request (batch_size=%d) is not supported in EPD disaggregation mode; skipping encoder dispatch.",
|
||||||
|
|||||||
@@ -38,18 +38,6 @@ class TokenizerManagerScoreMixin:
|
|||||||
|
|
||||||
This is a thin wrapper over `score_request` that treats `prompts` as
|
This is a thin wrapper over `score_request` that treats `prompts` as
|
||||||
already-composed inputs (i.e., no query/item concatenation needed).
|
already-composed inputs (i.e., no query/item concatenation needed).
|
||||||
|
|
||||||
Args:
|
|
||||||
prompts: A single prompt string, a list of prompt strings, or a list of
|
|
||||||
pre-tokenized prompt token ID sequences.
|
|
||||||
label_token_ids: Token IDs to compute probabilities for.
|
|
||||||
apply_softmax: Whether to normalize probabilities using softmax.
|
|
||||||
request: Optional FastAPI request object.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
ScoreResult with:
|
|
||||||
scores: List of score lists, one for each prompt, each in the order of label_token_ids.
|
|
||||||
prompt_tokens: The number of prompt tokens processed.
|
|
||||||
"""
|
"""
|
||||||
# Text prompts
|
# Text prompts
|
||||||
if isinstance(prompts, str) or (
|
if isinstance(prompts, str) or (
|
||||||
@@ -83,14 +71,6 @@ class TokenizerManagerScoreMixin:
|
|||||||
"""
|
"""
|
||||||
Build a single token sequence for multi-item scoring.
|
Build a single token sequence for multi-item scoring.
|
||||||
Format: query<delimiter>item1<delimiter>item2<delimiter>item3<delimiter>
|
Format: query<delimiter>item1<delimiter>item2<delimiter>item3<delimiter>
|
||||||
|
|
||||||
Args:
|
|
||||||
query: Query token IDs
|
|
||||||
items: List of item token ID sequences
|
|
||||||
delimiter_token_id: Token ID to use as delimiter
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Tuple of (combined token sequence, delimiter indices)
|
|
||||||
"""
|
"""
|
||||||
combined_sequence = query[:] # Start with query
|
combined_sequence = query[:] # Start with query
|
||||||
delimiter_indices = []
|
delimiter_indices = []
|
||||||
@@ -111,16 +91,6 @@ class TokenizerManagerScoreMixin:
|
|||||||
query: Optional[Union[str, List[int]]],
|
query: Optional[Union[str, List[int]]],
|
||||||
items: Optional[Union[str, List[str], List[List[int]]]],
|
items: Optional[Union[str, List[str], List[List[int]]]],
|
||||||
) -> Tuple[List[int], List[List[int]]]:
|
) -> Tuple[List[int], List[List[int]]]:
|
||||||
"""
|
|
||||||
Tokenize query and items into token IDs.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
query: The query text (str) or pre-tokenized token IDs (List[int]).
|
|
||||||
items: Item texts or pre-tokenized token IDs.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(query_ids, items_ids): query token IDs and list of per-item token IDs.
|
|
||||||
"""
|
|
||||||
if isinstance(query, str):
|
if isinstance(query, str):
|
||||||
query_ids = self.tokenizer.encode(query)
|
query_ids = self.tokenizer.encode(query)
|
||||||
else:
|
else:
|
||||||
@@ -153,20 +123,6 @@ class TokenizerManagerScoreMixin:
|
|||||||
populated (input_token_ids_logprobs for generation models,
|
populated (input_token_ids_logprobs for generation models,
|
||||||
embedding for classification models), then uniformly validates,
|
embedding for classification models), then uniformly validates,
|
||||||
skips the query-boundary delimiter, and normalizes.
|
skips the query-boundary delimiter, and normalizes.
|
||||||
|
|
||||||
Args:
|
|
||||||
results: Results from generate_request
|
|
||||||
items: List of items being scored
|
|
||||||
label_token_ids: Token IDs to extract scores for
|
|
||||||
apply_softmax: Whether to apply softmax normalization
|
|
||||||
batch_request: The original batch request containing input sequence
|
|
||||||
return_pooled_hidden_states: Whether to extract pooled hidden states
|
|
||||||
from the result and include them in the ScoreResult.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
ScoreResult with per-item scores, prompt token count, and optional
|
|
||||||
pooled_hidden_states (when return_pooled_hidden_states=True and the
|
|
||||||
model populated the field).
|
|
||||||
"""
|
"""
|
||||||
single_result = results[0] if isinstance(results, list) else results
|
single_result = results[0] if isinstance(results, list) else results
|
||||||
meta_info = single_result.get("meta_info", {})
|
meta_info = single_result.get("meta_info", {})
|
||||||
@@ -246,15 +202,6 @@ class TokenizerManagerScoreMixin:
|
|||||||
For generation (CausalLM) models: reads output_token_ids_logprobs.
|
For generation (CausalLM) models: reads output_token_ids_logprobs.
|
||||||
For non-generation (SequenceClassification) models: reads the embedding field
|
For non-generation (SequenceClassification) models: reads the embedding field
|
||||||
which contains pooled class logits from the classification head.
|
which contains pooled class logits from the classification head.
|
||||||
|
|
||||||
Args:
|
|
||||||
results: Results from generate_request
|
|
||||||
label_token_ids: Token IDs to extract scores for (generation models only)
|
|
||||||
apply_softmax: Whether to apply softmax normalization
|
|
||||||
return_pooled_hidden_states: Whether to extract pooled hidden states
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
ScoreResult with per-item scores, prompt token count, and optional pooled_hidden_states.
|
|
||||||
"""
|
"""
|
||||||
scores = []
|
scores = []
|
||||||
phs_list = []
|
phs_list = []
|
||||||
@@ -329,17 +276,7 @@ class TokenizerManagerScoreMixin:
|
|||||||
label: str = "input",
|
label: str = "input",
|
||||||
) -> Tuple[List[torch.Tensor], List[int]]:
|
) -> Tuple[List[torch.Tensor], List[int]]:
|
||||||
"""Scan token_ids for placeholder occurrences and pair with embeddings.
|
"""Scan token_ids for placeholder occurrences and pair with embeddings.
|
||||||
|
Returns empty lists when embeds is None."""
|
||||||
Args:
|
|
||||||
token_ids: The token sequence to scan.
|
|
||||||
embeds: Embedding tensors to place at placeholder positions (None = skip).
|
|
||||||
embed_override_token_id: The placeholder token ID.
|
|
||||||
position_offset: Added to each found position (for absolute coordinates).
|
|
||||||
label: Label for error messages (e.g. "query", "items[2]").
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
(embeds, positions) lists. Empty lists if embeds is None.
|
|
||||||
"""
|
|
||||||
if embeds is None:
|
if embeds is None:
|
||||||
return [], []
|
return [], []
|
||||||
positions = [
|
positions = [
|
||||||
@@ -365,10 +302,7 @@ class TokenizerManagerScoreMixin:
|
|||||||
item_position_offset: int,
|
item_position_offset: int,
|
||||||
item_label: str,
|
item_label: str,
|
||||||
) -> Optional[PositionalEmbeds]:
|
) -> Optional[PositionalEmbeds]:
|
||||||
"""Resolve embed overrides for a single query+item pair.
|
"""Resolve embed overrides for a query+item pair; None when no overrides exist."""
|
||||||
|
|
||||||
Returns PositionalEmbeds if any overrides exist, None otherwise.
|
|
||||||
"""
|
|
||||||
q_embeds, q_positions = self._resolve_overrides_for_sequence(
|
q_embeds, q_positions = self._resolve_overrides_for_sequence(
|
||||||
query,
|
query,
|
||||||
query_embed_overrides,
|
query_embed_overrides,
|
||||||
@@ -405,11 +339,8 @@ class TokenizerManagerScoreMixin:
|
|||||||
) -> Tuple[None, List[List[int]], Optional[list], Optional[List[int]]]:
|
) -> Tuple[None, List[List[int]], Optional[list], Optional[List[int]]]:
|
||||||
"""Build input_ids and resolve embed overrides for token-ID inputs.
|
"""Build input_ids and resolve embed overrides for token-ID inputs.
|
||||||
|
|
||||||
Works identically for multi-item-scoring and single-item modes — the only difference is
|
Multi-item-scoring and single-item modes differ only in how input_ids
|
||||||
how input_ids are assembled and what position offset each item gets.
|
are assembled and what position offset each item gets.
|
||||||
|
|
||||||
Returns:
|
|
||||||
(text_prompts, input_ids, positional_embed_overrides, delimiter_indices)
|
|
||||||
"""
|
"""
|
||||||
# Both query and items are token IDs
|
# Both query and items are token IDs
|
||||||
has_embeds = (
|
has_embeds = (
|
||||||
@@ -540,28 +471,8 @@ class TokenizerManagerScoreMixin:
|
|||||||
- Generation (CausalLM): Requires label_token_ids; returns logprob-based scores.
|
- Generation (CausalLM): Requires label_token_ids; returns logprob-based scores.
|
||||||
- SequenceClassification: label_token_ids is optional; returns pooled class logits.
|
- SequenceClassification: label_token_ids is optional; returns pooled class logits.
|
||||||
|
|
||||||
Args:
|
return_pooled_hidden_states is only supported for non-generation models
|
||||||
query: The query text or pre-tokenized query token IDs
|
(SequenceClassification, RewardModel); raises ValueError for CausalLM.
|
||||||
items: The item text(s) or pre-tokenized item token IDs
|
|
||||||
label_token_ids: List of token IDs to compute probabilities for
|
|
||||||
apply_softmax: Whether to normalize probabilities using softmax
|
|
||||||
item_first: If True, prepend items to query. Ignored for multi-item scoring.
|
|
||||||
embed_override_token_id: Placeholder token ID for embedding override positions.
|
|
||||||
query_embed_overrides: Embedding vectors replacing placeholder tokens in query.
|
|
||||||
item_embed_overrides: Per-item embedding vectors replacing placeholder tokens in items.
|
|
||||||
request: Optional FastAPI request object
|
|
||||||
return_pooled_hidden_states: Whether to include the raw pooled transformer
|
|
||||||
hidden states (before the task-specific head) in the result. Only
|
|
||||||
supported for non-generation models (SequenceClassification,
|
|
||||||
RewardModel). Raises ValueError for CausalLM models.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
ScoreResult with:
|
|
||||||
scores: List of score lists, one per item.
|
|
||||||
prompt_tokens: The number of prompt tokens processed.
|
|
||||||
pooled_hidden_states: Per-item CPU tensors when
|
|
||||||
return_pooled_hidden_states=True and the model supports it;
|
|
||||||
None otherwise.
|
|
||||||
"""
|
"""
|
||||||
is_generation = self.is_generation
|
is_generation = self.is_generation
|
||||||
|
|
||||||
@@ -734,17 +645,6 @@ class TokenizerManagerScoreMixin:
|
|||||||
label_token_ids: List[int],
|
label_token_ids: List[int],
|
||||||
apply_softmax: bool,
|
apply_softmax: bool,
|
||||||
) -> List[float]:
|
) -> List[float]:
|
||||||
"""
|
|
||||||
Convert logprobs dictionary to ordered score list.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
logprobs: Dictionary mapping token_id to logprob
|
|
||||||
label_token_ids: Token IDs in desired order
|
|
||||||
apply_softmax: Whether to apply softmax normalization
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
List of scores in the same order as label_token_ids
|
|
||||||
"""
|
|
||||||
score_list = [
|
score_list = [
|
||||||
logprobs.get(token_id, float("-inf")) for token_id in label_token_ids
|
logprobs.get(token_id, float("-inf")) for token_id in label_token_ids
|
||||||
]
|
]
|
||||||
@@ -762,16 +662,7 @@ class TokenizerManagerScoreMixin:
|
|||||||
def _extract_logprobs_for_tokens(
|
def _extract_logprobs_for_tokens(
|
||||||
self, logprobs_data: List, label_token_ids: List[int]
|
self, logprobs_data: List, label_token_ids: List[int]
|
||||||
) -> Dict[int, float]:
|
) -> Dict[int, float]:
|
||||||
"""
|
"""Extract logprobs for label_token_ids from (logprob, token_id, text) tuples."""
|
||||||
Extract logprobs for specified token IDs from logprobs data.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
logprobs_data: List of (logprob, token_id, text) tuples
|
|
||||||
label_token_ids: Token IDs to extract logprobs for
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Dictionary mapping token_id to logprob
|
|
||||||
"""
|
|
||||||
logprobs = {}
|
logprobs = {}
|
||||||
if logprobs_data:
|
if logprobs_data:
|
||||||
for logprob, token_id, _ in logprobs_data:
|
for logprob, token_id, _ in logprobs_data:
|
||||||
|
|||||||
Reference in New Issue
Block a user