[Minor] fix type annotations and invalid method calls in constrained … (#20132)
This commit is contained in:
@@ -15,9 +15,8 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import Future, ThreadPoolExecutor
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from threading import Event
|
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
@@ -120,43 +119,36 @@ class BaseGrammarObject:
|
|||||||
INVALID_GRAMMAR_OBJ = BaseGrammarObject()
|
INVALID_GRAMMAR_OBJ = BaseGrammarObject()
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CacheEntry:
|
|
||||||
value: BaseGrammarObject
|
|
||||||
event: Event
|
|
||||||
|
|
||||||
|
|
||||||
class BaseGrammarBackend:
|
class BaseGrammarBackend:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.executor = ThreadPoolExecutor()
|
self.executor = ThreadPoolExecutor()
|
||||||
self.cache: Dict[Tuple[str, str], CacheEntry] = {}
|
self.cache: Dict[Tuple[str, str], BaseGrammarObject] = {}
|
||||||
|
|
||||||
def _not_supported(self, key_type: str, key_string: str) -> None:
|
def _not_supported(self, key_type: str, key_string: str) -> BaseGrammarObject:
|
||||||
logger.warning(f"Skip unsupported {key_type=}, {key_string=}")
|
logger.warning(f"Skip unsupported {key_type=}, {key_string=}")
|
||||||
|
return INVALID_GRAMMAR_OBJ
|
||||||
|
|
||||||
def dispatch_fallback(
|
def dispatch_fallback(self, key_type: str, key_string: str) -> BaseGrammarObject:
|
||||||
self, key_type: str, key_string: str
|
|
||||||
) -> Optional[BaseGrammarObject]:
|
|
||||||
"""
|
"""
|
||||||
This function should not be reached in any case.
|
This function should not be reached in any case.
|
||||||
"""
|
"""
|
||||||
raise ValueError(f"Invalid key_type: {key_type}={key_string}")
|
raise ValueError(f"Invalid key_type: {key_type}={key_string}")
|
||||||
|
|
||||||
def dispatch_json(self, key_string: str) -> Optional[BaseGrammarObject]:
|
def dispatch_json(self, key_string: str) -> BaseGrammarObject:
|
||||||
return self._not_supported("json", key_string)
|
return self._not_supported("json", key_string)
|
||||||
|
|
||||||
def dispatch_regex(self, key_string: str) -> Optional[BaseGrammarObject]:
|
def dispatch_regex(self, key_string: str) -> BaseGrammarObject:
|
||||||
return self._not_supported("regex", key_string)
|
return self._not_supported("regex", key_string)
|
||||||
|
|
||||||
def dispatch_ebnf(self, key_string: str) -> Optional[BaseGrammarObject]:
|
def dispatch_ebnf(self, key_string: str) -> BaseGrammarObject:
|
||||||
return self._not_supported("ebnf", key_string)
|
return self._not_supported("ebnf", key_string)
|
||||||
|
|
||||||
def dispatch_structural_tag(self, key_string: str) -> Optional[BaseGrammarObject]:
|
def dispatch_structural_tag(self, key_string: str) -> BaseGrammarObject:
|
||||||
return self._not_supported("structural_tag", key_string)
|
return self._not_supported("structural_tag", key_string)
|
||||||
|
|
||||||
def _init_value_dispatch(
|
def _init_value_dispatch(
|
||||||
self, key: Tuple[str, str], require_reasoning: bool
|
self, key: Tuple[str, str], require_reasoning: bool
|
||||||
) -> Optional[BaseGrammarObject]:
|
) -> BaseGrammarObject:
|
||||||
s = time.perf_counter()
|
s = time.perf_counter()
|
||||||
key_type, key_string = key
|
key_type, key_string = key
|
||||||
if key_type == "json":
|
if key_type == "json":
|
||||||
@@ -167,10 +159,6 @@ class BaseGrammarBackend:
|
|||||||
grammar = self.dispatch_ebnf(key_string)
|
grammar = self.dispatch_ebnf(key_string)
|
||||||
elif key_type == "structural_tag":
|
elif key_type == "structural_tag":
|
||||||
grammar = self.dispatch_structural_tag(key_string)
|
grammar = self.dispatch_structural_tag(key_string)
|
||||||
elif key_type == "structural_pattern":
|
|
||||||
grammar = self.dispatch_structural_pattern(key_string)
|
|
||||||
elif key_type == "structural_pattern_v2":
|
|
||||||
grammar = self.dispatch_structural_pattern_v2(key_string)
|
|
||||||
else:
|
else:
|
||||||
grammar = self.dispatch_fallback(key_type, key_string)
|
grammar = self.dispatch_fallback(key_type, key_string)
|
||||||
|
|
||||||
@@ -180,7 +168,7 @@ class BaseGrammarBackend:
|
|||||||
|
|
||||||
def get_cached_or_future_value(
|
def get_cached_or_future_value(
|
||||||
self, key: Tuple[str, str], require_reasoning: bool
|
self, key: Tuple[str, str], require_reasoning: bool
|
||||||
) -> Optional[BaseGrammarObject]:
|
) -> Tuple[BaseGrammarObject | Future[BaseGrammarObject], bool]:
|
||||||
value = self.cache.get(key)
|
value = self.cache.get(key)
|
||||||
if value:
|
if value:
|
||||||
copied_value = value.copy()
|
copied_value = value.copy()
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class GrammarManager:
|
|||||||
for req in self.grammar_queue:
|
for req in self.grammar_queue:
|
||||||
if recv_req.abort_all or req.rid.startswith(recv_req.rid):
|
if recv_req.abort_all or req.rid.startswith(recv_req.rid):
|
||||||
logger.debug(f"Abort grammar queue request. {req.rid=}")
|
logger.debug(f"Abort grammar queue request. {req.rid=}")
|
||||||
if req.grammar:
|
if isinstance(req.grammar, futures.Future) and req.grammar:
|
||||||
req.grammar.cancel()
|
req.grammar.cancel()
|
||||||
req.set_finish_with_abort("Aborted by AbortReq.")
|
req.set_finish_with_abort("Aborted by AbortReq.")
|
||||||
|
|
||||||
@@ -115,6 +115,7 @@ class GrammarManager:
|
|||||||
ready_reqs = intersect(ready_reqs_all)
|
ready_reqs = intersect(ready_reqs_all)
|
||||||
failed_reqs = union(failed_reqs_all)
|
failed_reqs = union(failed_reqs_all)
|
||||||
"""
|
"""
|
||||||
|
assert self.grammar_backend
|
||||||
ready_req_idxs: set[int] = set()
|
ready_req_idxs: set[int] = set()
|
||||||
failed_req_idxs: set[int] = set()
|
failed_req_idxs: set[int] = set()
|
||||||
|
|
||||||
@@ -170,6 +171,7 @@ class GrammarManager:
|
|||||||
if req.finished() or req.grammar is None: # It is aborted by AbortReq
|
if req.finished() or req.grammar is None: # It is aborted by AbortReq
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
assert isinstance(req.grammar, futures.Future) and req.grammar_key
|
||||||
req.grammar = req.grammar.result()
|
req.grammar = req.grammar.result()
|
||||||
self.grammar_backend.set_cache(req.grammar_key, req.grammar.copy())
|
self.grammar_backend.set_cache(req.grammar_key, req.grammar.copy())
|
||||||
if req.grammar is INVALID_GRAMMAR_OBJ:
|
if req.grammar is INVALID_GRAMMAR_OBJ:
|
||||||
@@ -181,6 +183,7 @@ class GrammarManager:
|
|||||||
req = self.grammar_queue[i]
|
req = self.grammar_queue[i]
|
||||||
return_reqs.append(req)
|
return_reqs.append(req)
|
||||||
|
|
||||||
|
assert isinstance(req.grammar, futures.Future) and req.grammar_key
|
||||||
req.grammar.cancel()
|
req.grammar.cancel()
|
||||||
self.grammar_backend.set_cache(req.grammar_key, INVALID_GRAMMAR_OBJ)
|
self.grammar_backend.set_cache(req.grammar_key, INVALID_GRAMMAR_OBJ)
|
||||||
error_msg = f"Grammar preprocessing timed out: {req.grammar_key=}"
|
error_msg = f"Grammar preprocessing timed out: {req.grammar_key=}"
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class GuidanceBackend(BaseGrammarBackend):
|
|||||||
self.whitespace_pattern = whitespace_pattern
|
self.whitespace_pattern = whitespace_pattern
|
||||||
self.llguidance_tokenizer = from_tokenizer(self.tokenizer, n_vocab)
|
self.llguidance_tokenizer = from_tokenizer(self.tokenizer, n_vocab)
|
||||||
|
|
||||||
def _from_serialized(self, serialized_grammar) -> Optional[GuidanceGrammar]:
|
def _from_serialized(self, serialized_grammar) -> BaseGrammarObject:
|
||||||
try:
|
try:
|
||||||
return GuidanceGrammar(
|
return GuidanceGrammar(
|
||||||
llguidance_tokenizer=self.llguidance_tokenizer,
|
llguidance_tokenizer=self.llguidance_tokenizer,
|
||||||
@@ -132,7 +132,7 @@ class GuidanceBackend(BaseGrammarBackend):
|
|||||||
logger.error(f"Hit invalid grammar: {serialized_grammar=}, {e=}")
|
logger.error(f"Hit invalid grammar: {serialized_grammar=}, {e=}")
|
||||||
return INVALID_GRAMMAR_OBJ
|
return INVALID_GRAMMAR_OBJ
|
||||||
|
|
||||||
def dispatch_json(self, key_string: str) -> Optional[GuidanceGrammar]:
|
def dispatch_json(self, key_string: str) -> BaseGrammarObject:
|
||||||
try:
|
try:
|
||||||
serialized_grammar = LLMatcher.grammar_from_json_schema(
|
serialized_grammar = LLMatcher.grammar_from_json_schema(
|
||||||
key_string,
|
key_string,
|
||||||
@@ -146,11 +146,11 @@ class GuidanceBackend(BaseGrammarBackend):
|
|||||||
return INVALID_GRAMMAR_OBJ
|
return INVALID_GRAMMAR_OBJ
|
||||||
return self._from_serialized(serialized_grammar)
|
return self._from_serialized(serialized_grammar)
|
||||||
|
|
||||||
def dispatch_regex(self, key_string: str) -> Optional[GuidanceGrammar]:
|
def dispatch_regex(self, key_string: str) -> BaseGrammarObject:
|
||||||
serialized_grammar = grammar_from("regex", key_string)
|
serialized_grammar = grammar_from("regex", key_string)
|
||||||
return self._from_serialized(serialized_grammar)
|
return self._from_serialized(serialized_grammar)
|
||||||
|
|
||||||
def dispatch_ebnf(self, key_string: str) -> Optional[GuidanceGrammar]:
|
def dispatch_ebnf(self, key_string: str) -> BaseGrammarObject:
|
||||||
try:
|
try:
|
||||||
serialized_grammar = grammar_from("ebnf", key_string)
|
serialized_grammar = grammar_from("ebnf", key_string)
|
||||||
return self._from_serialized(serialized_grammar)
|
return self._from_serialized(serialized_grammar)
|
||||||
@@ -158,7 +158,7 @@ class GuidanceBackend(BaseGrammarBackend):
|
|||||||
logger.error(f"Hit invalid ebnf: {key_string=}, {e=}")
|
logger.error(f"Hit invalid ebnf: {key_string=}, {e=}")
|
||||||
return INVALID_GRAMMAR_OBJ
|
return INVALID_GRAMMAR_OBJ
|
||||||
|
|
||||||
def dispatch_structural_tag(self, key_string: str) -> Optional[GuidanceGrammar]:
|
def dispatch_structural_tag(self, key_string: str) -> BaseGrammarObject:
|
||||||
try:
|
try:
|
||||||
structural_tag = json.loads(key_string)
|
structural_tag = json.loads(key_string)
|
||||||
assert is_legacy_structural_tag(structural_tag)
|
assert is_legacy_structural_tag(structural_tag)
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ class OutlinesGrammarBackend(BaseGrammarBackend):
|
|||||||
)
|
)
|
||||||
self.whitespace_pattern = whitespace_pattern
|
self.whitespace_pattern = whitespace_pattern
|
||||||
|
|
||||||
def _compile_regex(self, regex: str) -> Optional[OutlinesGrammar]:
|
def _compile_regex(self, regex: str) -> BaseGrammarObject:
|
||||||
try:
|
try:
|
||||||
if hasattr(RegexGuide, "from_regex"):
|
if hasattr(RegexGuide, "from_regex"):
|
||||||
# outlines >= 0.1.1
|
# outlines >= 0.1.1
|
||||||
|
|||||||
@@ -113,8 +113,6 @@ class XGrammarGrammar(BaseGrammarObject):
|
|||||||
apply_token_bitmask_inplace_cuda(logits, vocab_mask)
|
apply_token_bitmask_inplace_cuda(logits, vocab_mask)
|
||||||
else:
|
else:
|
||||||
apply_token_bitmask_inplace_triton(logits, vocab_mask)
|
apply_token_bitmask_inplace_triton(logits, vocab_mask)
|
||||||
elif logits.device.type == "cpu" and self.apply_vocab_mask_cpu:
|
|
||||||
self.apply_vocab_mask_cpu(logits, vocab_mask)
|
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(f"Unsupported device: {logits.device.type}")
|
raise RuntimeError(f"Unsupported device: {logits.device.type}")
|
||||||
|
|
||||||
@@ -124,15 +122,17 @@ class XGrammarGrammar(BaseGrammarObject):
|
|||||||
max_rollback_tokens=MAX_ROLLBACK_TOKENS,
|
max_rollback_tokens=MAX_ROLLBACK_TOKENS,
|
||||||
override_stop_tokens=self.override_stop_tokens,
|
override_stop_tokens=self.override_stop_tokens,
|
||||||
)
|
)
|
||||||
|
if grammar_stats := self.grammar_stats:
|
||||||
|
grammar_stats = dataclasses.replace(
|
||||||
|
grammar_stats, is_cache_hit=True, tree_traversal_time=[]
|
||||||
|
)
|
||||||
return XGrammarGrammar(
|
return XGrammarGrammar(
|
||||||
matcher,
|
matcher,
|
||||||
self.vocab_size,
|
self.vocab_size,
|
||||||
self.ctx,
|
self.ctx,
|
||||||
self.override_stop_tokens,
|
self.override_stop_tokens,
|
||||||
self.key_string,
|
self.key_string,
|
||||||
dataclasses.replace(
|
grammar_stats,
|
||||||
self.grammar_stats, is_cache_hit=True, tree_traversal_time=[]
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def try_jump_forward(self, tokenizer) -> Optional[Tuple[List[int], str]]:
|
def try_jump_forward(self, tokenizer) -> Optional[Tuple[List[int], str]]:
|
||||||
@@ -254,7 +254,7 @@ class XGrammarGrammarBackend(BaseGrammarBackend):
|
|||||||
grammar_stats,
|
grammar_stats,
|
||||||
)
|
)
|
||||||
|
|
||||||
def dispatch_json(self, key_string: str) -> Optional[XGrammarGrammar]:
|
def dispatch_json(self, key_string: str) -> BaseGrammarObject:
|
||||||
try:
|
try:
|
||||||
if key_string == "$$ANY$$":
|
if key_string == "$$ANY$$":
|
||||||
# Note: This builtin JSON grammar includes *all* valid JSON (including, for example, arrays at the root)
|
# Note: This builtin JSON grammar includes *all* valid JSON (including, for example, arrays at the root)
|
||||||
@@ -269,7 +269,7 @@ class XGrammarGrammarBackend(BaseGrammarBackend):
|
|||||||
return INVALID_GRAMMAR_OBJ
|
return INVALID_GRAMMAR_OBJ
|
||||||
return self._from_context(ctx, key_string, GrammarStats(dispatch_type="json"))
|
return self._from_context(ctx, key_string, GrammarStats(dispatch_type="json"))
|
||||||
|
|
||||||
def dispatch_ebnf(self, key_string: str) -> Optional[XGrammarGrammar]:
|
def dispatch_ebnf(self, key_string: str) -> BaseGrammarObject:
|
||||||
try:
|
try:
|
||||||
ctx = self.grammar_compiler.compile_grammar(key_string)
|
ctx = self.grammar_compiler.compile_grammar(key_string)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
@@ -277,7 +277,7 @@ class XGrammarGrammarBackend(BaseGrammarBackend):
|
|||||||
return INVALID_GRAMMAR_OBJ
|
return INVALID_GRAMMAR_OBJ
|
||||||
return self._from_context(ctx, key_string, GrammarStats(dispatch_type="ebnf"))
|
return self._from_context(ctx, key_string, GrammarStats(dispatch_type="ebnf"))
|
||||||
|
|
||||||
def dispatch_regex(self, key_string: str) -> Optional[XGrammarGrammar]:
|
def dispatch_regex(self, key_string: str) -> BaseGrammarObject:
|
||||||
try:
|
try:
|
||||||
ctx = self.grammar_compiler.compile_regex(key_string)
|
ctx = self.grammar_compiler.compile_regex(key_string)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
@@ -285,7 +285,7 @@ class XGrammarGrammarBackend(BaseGrammarBackend):
|
|||||||
return INVALID_GRAMMAR_OBJ
|
return INVALID_GRAMMAR_OBJ
|
||||||
return self._from_context(ctx, key_string, GrammarStats(dispatch_type="regex"))
|
return self._from_context(ctx, key_string, GrammarStats(dispatch_type="regex"))
|
||||||
|
|
||||||
def dispatch_structural_tag(self, key_string: str) -> Optional[XGrammarGrammar]:
|
def dispatch_structural_tag(self, key_string: str) -> BaseGrammarObject:
|
||||||
try:
|
try:
|
||||||
# TODO(dark): it's REALLY stupid to construct object from string and decode it again
|
# TODO(dark): it's REALLY stupid to construct object from string and decode it again
|
||||||
structural_tag = json.loads(key_string)
|
structural_tag = json.loads(key_string)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import copy
|
|||||||
import dataclasses
|
import dataclasses
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
from concurrent.futures import Future
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
@@ -725,8 +726,10 @@ class Req(ReqDllmMixin):
|
|||||||
self.embedding = None
|
self.embedding = None
|
||||||
|
|
||||||
# Constrained decoding
|
# Constrained decoding
|
||||||
self.grammar_key: Optional[str] = None
|
self.grammar_key: Optional[Tuple[str, str]] = None
|
||||||
self.grammar: Optional[BaseGrammarObject] = None
|
self.grammar: Optional[Union[BaseGrammarObject, Future[BaseGrammarObject]]] = (
|
||||||
|
None
|
||||||
|
)
|
||||||
self.grammar_wait_ct = 0
|
self.grammar_wait_ct = 0
|
||||||
|
|
||||||
# The number of cached tokens that were already cached in the KV cache
|
# The number of cached tokens that were already cached in the KV cache
|
||||||
|
|||||||
Reference in New Issue
Block a user