feat: Add limit-mm-data-per-request argument to server arguments (#15418)
Signed-off-by: Xinyuan Tong <xinyuantong.cs@gmail.com>
This commit is contained in:
@@ -93,6 +93,7 @@ Please consult the documentation below and [server_args.py](https://github.com/s
|
|||||||
| `--context-length` | The model's maximum context length. Defaults to None (will use the value from the model's config.json instead). | `None` | Type: int |
|
| `--context-length` | The model's maximum context length. Defaults to None (will use the value from the model's config.json instead). | `None` | Type: int |
|
||||||
| `--is-embedding` | Whether to use a CausalLM as an embedding model. | `False` | bool flag (set to enable) |
|
| `--is-embedding` | Whether to use a CausalLM as an embedding model. | `False` | bool flag (set to enable) |
|
||||||
| `--enable-multimodal` | Enable the multimodal functionality for the served model. If the model being served is not multimodal, nothing will happen | `None` | bool flag (set to enable) |
|
| `--enable-multimodal` | Enable the multimodal functionality for the served model. If the model being served is not multimodal, nothing will happen | `None` | bool flag (set to enable) |
|
||||||
|
| `--limit-mm-data-per-request` | Limit the number of multimodal inputs per request. e.g. '{"image": 1, "video": 1, "audio": 1}' | `None` | Type: JSON / Dict |
|
||||||
| `--revision` | The specific model version to use. It can be a branch name, a tag name, or a commit id. If unspecified, will use the default version. | `None` | Type: str |
|
| `--revision` | The specific model version to use. It can be a branch name, a tag name, or a commit id. If unspecified, will use the default version. | `None` | Type: str |
|
||||||
| `--model-impl` | Which implementation of the model to use. * "auto" will try to use the SGLang implementation if it exists and fall back to the Transformers implementation if no SGLang implementation is available. * "sglang" will use the SGLang model implementation. * "transformers" will use the Transformers model implementation. | `auto` | Type: str |
|
| `--model-impl` | Which implementation of the model to use. * "auto" will try to use the SGLang implementation if it exists and fall back to the Transformers implementation if no SGLang implementation is available. * "sglang" will use the SGLang model implementation. * "transformers" will use the Transformers model implementation. | `auto` | Type: str |
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ from http import HTTPStatus
|
|||||||
from typing import Any, Awaitable, Dict, List, Optional, Tuple, Union
|
from typing import Any, Awaitable, Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
import fastapi
|
import fastapi
|
||||||
import orjson
|
|
||||||
import uvloop
|
import uvloop
|
||||||
import zmq
|
import zmq
|
||||||
import zmq.asyncio
|
import zmq.asyncio
|
||||||
@@ -184,11 +183,7 @@ class TokenizerManager(TokenizerCommunicatorMixin, TokenizerManagerMultiItemMixi
|
|||||||
self.enable_metrics = server_args.enable_metrics
|
self.enable_metrics = server_args.enable_metrics
|
||||||
self.log_requests = server_args.log_requests
|
self.log_requests = server_args.log_requests
|
||||||
self.log_requests_level = server_args.log_requests_level
|
self.log_requests_level = server_args.log_requests_level
|
||||||
self.preferred_sampling_params = (
|
self.preferred_sampling_params = server_args.preferred_sampling_params
|
||||||
orjson.loads(server_args.preferred_sampling_params)
|
|
||||||
if server_args.preferred_sampling_params
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
self.crash_dump_folder = server_args.crash_dump_folder
|
self.crash_dump_folder = server_args.crash_dump_folder
|
||||||
self.enable_trace = server_args.enable_trace
|
self.enable_trace = server_args.enable_trace
|
||||||
|
|
||||||
@@ -628,6 +623,7 @@ class TokenizerManager(TokenizerCommunicatorMixin, TokenizerManagerMultiItemMixi
|
|||||||
obj.image_data = [obj.image_data]
|
obj.image_data = [obj.image_data]
|
||||||
if obj.audio_data is not None and not isinstance(obj.audio_data, list):
|
if obj.audio_data is not None and not isinstance(obj.audio_data, list):
|
||||||
obj.audio_data = [obj.audio_data]
|
obj.audio_data = [obj.audio_data]
|
||||||
|
self._validate_mm_limits(obj)
|
||||||
|
|
||||||
mm_inputs = None
|
mm_inputs = None
|
||||||
|
|
||||||
@@ -748,6 +744,21 @@ class TokenizerManager(TokenizerCommunicatorMixin, TokenizerManagerMultiItemMixi
|
|||||||
"Please set `--enable-custom-logit-processor` to enable this feature."
|
"Please set `--enable-custom-logit-processor` to enable this feature."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _validate_mm_limits(
|
||||||
|
self, obj: Union[GenerateReqInput, EmbeddingReqInput]
|
||||||
|
) -> None:
|
||||||
|
if not self.server_args.limit_mm_data_per_request:
|
||||||
|
return
|
||||||
|
|
||||||
|
for modality, limit in self.server_args.limit_mm_data_per_request.items():
|
||||||
|
data = getattr(obj, f"{modality}_data", None)
|
||||||
|
if data:
|
||||||
|
count = len(data) if isinstance(data, list) else 1
|
||||||
|
if count > limit:
|
||||||
|
raise ValueError(
|
||||||
|
f"{modality.capitalize()} count {count} exceeds limit {limit} per request."
|
||||||
|
)
|
||||||
|
|
||||||
def _validate_for_matryoshka_dim(self, obj: EmbeddingReqInput) -> None:
|
def _validate_for_matryoshka_dim(self, obj: EmbeddingReqInput) -> None:
|
||||||
"""Validate the request for Matryoshka dim if it has the field set."""
|
"""Validate the request for Matryoshka dim if it has the field set."""
|
||||||
if obj.dimensions is None:
|
if obj.dimensions is None:
|
||||||
|
|||||||
@@ -264,6 +264,7 @@ class ServerArgs:
|
|||||||
context_length: Optional[int] = None
|
context_length: Optional[int] = None
|
||||||
is_embedding: bool = False
|
is_embedding: bool = False
|
||||||
enable_multimodal: Optional[bool] = None
|
enable_multimodal: Optional[bool] = None
|
||||||
|
limit_mm_data_per_request: Optional[Union[str, Dict[str, int]]] = None
|
||||||
revision: Optional[str] = None
|
revision: Optional[str] = None
|
||||||
model_impl: str = "auto"
|
model_impl: str = "auto"
|
||||||
|
|
||||||
@@ -2367,6 +2368,29 @@ class ServerArgs:
|
|||||||
self.disable_cuda_graph = True
|
self.disable_cuda_graph = True
|
||||||
self.skip_server_warmup = True
|
self.skip_server_warmup = True
|
||||||
|
|
||||||
|
# Validate limit_mm_per_prompt modalities
|
||||||
|
if self.limit_mm_data_per_request:
|
||||||
|
if isinstance(self.limit_mm_data_per_request, str):
|
||||||
|
self.limit_mm_data_per_request = json.loads(
|
||||||
|
self.limit_mm_data_per_request
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(self.limit_mm_data_per_request, dict):
|
||||||
|
allowed_modalities = {"image", "video", "audio"}
|
||||||
|
for modality in self.limit_mm_data_per_request.keys():
|
||||||
|
if modality not in allowed_modalities:
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid modality '{modality}' in --limit-mm-data-per-request."
|
||||||
|
f"Allowed modalities are: {list(allowed_modalities)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Validate preferred_sampling_params
|
||||||
|
if self.preferred_sampling_params:
|
||||||
|
if isinstance(self.preferred_sampling_params, str):
|
||||||
|
self.preferred_sampling_params = json.loads(
|
||||||
|
self.preferred_sampling_params
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_cli_args(parser: argparse.ArgumentParser):
|
def add_cli_args(parser: argparse.ArgumentParser):
|
||||||
|
|
||||||
@@ -2455,6 +2479,13 @@ class ServerArgs:
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
help="Enable the multimodal functionality for the served model. If the model being served is not multimodal, nothing will happen",
|
help="Enable the multimodal functionality for the served model. If the model being served is not multimodal, nothing will happen",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--limit-mm-data-per-request",
|
||||||
|
type=json.loads,
|
||||||
|
default=ServerArgs.limit_mm_data_per_request,
|
||||||
|
help="Limit the number of multimodal inputs per request. "
|
||||||
|
'e.g. \'{"image": 1, "video": 1, "audio": 1}\'',
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--revision",
|
"--revision",
|
||||||
type=str,
|
type=str,
|
||||||
@@ -3135,7 +3166,7 @@ class ServerArgs:
|
|||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--preferred-sampling-params",
|
"--preferred-sampling-params",
|
||||||
type=str,
|
type=json.loads,
|
||||||
help="json-formatted sampling settings that will be returned in /get_model_info",
|
help="json-formatted sampling settings that will be returned in /get_model_info",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user