[style] Extract init-static values in tokenizer + multimodal path (#30709)

This commit is contained in:
Liangsheng Yin
2026-07-09 19:36:34 -07:00
committed by GitHub
parent dda61b476e
commit ccd2028def
5 changed files with 49 additions and 40 deletions
+18 -20
View File
@@ -262,6 +262,11 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
# Parse args # Parse args
self.server_args = server_args self.server_args = server_args
self.enable_metrics = server_args.enable_metrics self.enable_metrics = server_args.enable_metrics
self.incremental_streaming_output = server_args.incremental_streaming_output
self.enable_lora = server_args.enable_lora
self.enable_trace = server_args.enable_trace
self.allow_auto_truncate = server_args.allow_auto_truncate
self.skip_tokenizer_init = server_args.skip_tokenizer_init
self.preferred_sampling_params = server_args.preferred_sampling_params self.preferred_sampling_params = server_args.preferred_sampling_params
self.crash_dump_folder = server_args.crash_dump_folder self.crash_dump_folder = server_args.crash_dump_folder
set_global_server_args_for_tokenizer(server_args) set_global_server_args_for_tokenizer(server_args)
@@ -956,7 +961,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
# Validate input length # Validate input length
if input_token_num >= self.context_len: if input_token_num >= self.context_len:
if self.server_args.allow_auto_truncate: if self.allow_auto_truncate:
logger.warning( logger.warning(
f"The input ({input_token_num} tokens) is longer than the " f"The input ({input_token_num} tokens) is longer than the "
f"model's context length ({self.context_len} tokens). " f"model's context length ({self.context_len} tokens). "
@@ -977,7 +982,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
and max_new_tokens is not None and max_new_tokens is not None
and (max_new_tokens + input_token_num) > _max_req_len and (max_new_tokens + input_token_num) > _max_req_len
): ):
if self.server_args.allow_auto_truncate: if self.allow_auto_truncate:
logger.warning( logger.warning(
f"Requested token count ({input_token_num} input + {max_new_tokens} new) " f"Requested token count ({input_token_num} input + {max_new_tokens} new) "
f"exceeds the model's context length ({self.context_len} tokens). " f"exceeds the model's context length ({self.context_len} tokens). "
@@ -1432,7 +1437,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
del self.rid_to_state[state.obj.rid] del self.rid_to_state[state.obj.rid]
# Mark ongoing LoRA request as finished. # Mark ongoing LoRA request as finished.
if self.server_args.enable_lora and state.obj.lora_path: if self.enable_lora and state.obj.lora_path:
await self.lora_registry.release(state.obj.lora_id) await self.lora_registry.release(state.obj.lora_id)
if not is_stream: if not is_stream:
raise fastapi.HTTPException( raise fastapi.HTTPException(
@@ -1479,9 +1484,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
# With incremental streaming, each chunk is a delta — coalesce # With incremental streaming, each chunk is a delta — coalesce
# multiple queued chunks to avoid dropping token ids. # multiple queued chunks to avoid dropping token ids.
incremental_stream = ( incremental_stream = is_stream and self.incremental_streaming_output
is_stream and self.server_args.incremental_streaming_output
)
if incremental_stream and len(out_list) > 1: if incremental_stream and len(out_list) > 1:
out = self._coalesce_streaming_chunks( out = self._coalesce_streaming_chunks(
out_list, out_list,
@@ -1906,8 +1909,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
state, state,
state.obj.top_logprobs_num, state.obj.top_logprobs_num,
state.obj.token_ids_logprob, state.obj.token_ids_logprob,
state.obj.return_text_in_logprobs state.obj.return_text_in_logprobs and not self.skip_tokenizer_init,
and not self.server_args.skip_tokenizer_init,
recv_obj, recv_obj,
i, i,
) )
@@ -1972,9 +1974,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
if isinstance(recv_obj, BatchStrOutput): if isinstance(recv_obj, BatchStrOutput):
# Not all request types have `stream` (e.g., EmbeddingReqInput). Default to non-streaming. # Not all request types have `stream` (e.g., EmbeddingReqInput). Default to non-streaming.
is_stream = getattr(state.obj, "stream", False) is_stream = getattr(state.obj, "stream", False)
incremental = ( incremental = is_stream and self.incremental_streaming_output
self.server_args.incremental_streaming_output and is_stream
)
delta_text = recv_obj.output_strs[i] delta_text = recv_obj.output_strs[i]
delta_output_ids = list(recv_obj.output_ids[i]) delta_output_ids = list(recv_obj.output_ids[i])
output_offset = state.last_output_offset output_offset = state.last_output_offset
@@ -2022,9 +2022,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
out_dict["prompt_token_ids"] = state.prompt_token_ids out_dict["prompt_token_ids"] = state.prompt_token_ids
elif isinstance(recv_obj, BatchTokenIDOutput): elif isinstance(recv_obj, BatchTokenIDOutput):
is_stream = getattr(state.obj, "stream", False) is_stream = getattr(state.obj, "stream", False)
incremental = ( incremental = is_stream and self.incremental_streaming_output
self.server_args.incremental_streaming_output and is_stream
)
delta_output_ids = list(recv_obj.output_ids[i]) delta_output_ids = list(recv_obj.output_ids[i])
output_offset = state.last_output_offset output_offset = state.last_output_offset
state.output_ids.extend(delta_output_ids) state.output_ids.extend(delta_output_ids)
@@ -2113,7 +2111,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
del self.rid_to_state[rid] del self.rid_to_state[rid]
# Mark ongoing LoRA request as finished. # Mark ongoing LoRA request as finished.
if self.server_args.enable_lora and state.obj.lora_path: if self.enable_lora and state.obj.lora_path:
asyncio.create_task(self.lora_registry.release(state.obj.lora_id)) asyncio.create_task(self.lora_registry.release(state.obj.lora_id))
if out_dict is not None: if out_dict is not None:
@@ -2779,7 +2777,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
if not obj.lora_path: if not obj.lora_path:
return return
if not self.server_args.enable_lora: if not self.enable_lora:
first_adapter = ( first_adapter = (
obj.lora_path obj.lora_path
if isinstance(obj.lora_path, str) if isinstance(obj.lora_path, str)
@@ -2856,7 +2854,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
created_time = obj.received_time created_time = obj.received_time
external_trace_header = None external_trace_header = None
if self.server_args.enable_trace: if self.enable_trace:
if obj.external_trace_header: if obj.external_trace_header:
# When the request comes from the rust grpc server or Engine there isn't a # When the request comes from the rust grpc server or Engine there isn't a
# real request object but we still need to propagate the trace context from # real request object but we still need to propagate the trace context from
@@ -2889,7 +2887,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
time_stats = APIServerReqTimeStats(disagg_mode=self.disaggregation_mode) time_stats = APIServerReqTimeStats(disagg_mode=self.disaggregation_mode)
state = ReqState([], False, asyncio.Event(), sub_obj, time_stats) state = ReqState([], False, asyncio.Event(), sub_obj, time_stats)
self.rid_to_state[rid] = state self.rid_to_state[rid] = state
if self.server_args.enable_trace: if self.enable_trace:
time_stats.init_trace_ctx(rid, bootstrap_room, external_trace_header) time_stats.init_trace_ctx(rid, bootstrap_room, external_trace_header)
time_stats.set_created_time(created_time) time_stats.set_created_time(created_time)
@@ -2962,7 +2960,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
"mooncake", "mooncake",
]: ]:
time_stats_json = None time_stats_json = None
if self.server_args.enable_trace: if self.enable_trace:
state = self.rid_to_state.get(obj.rid) state = self.rid_to_state.get(obj.rid)
if state is not None: if state is not None:
time_stats_json = state.time_stats.encode_json() time_stats_json = state.time_stats.encode_json()
@@ -2986,7 +2984,7 @@ class TokenizerManager(TokenizerControlMixin, TokenizerManagerScoreMixin):
"""Convert attributes to span attributes.""" """Convert attributes to span attributes."""
span_attrs = {} span_attrs = {}
if not self.server_args.enable_trace: if not self.enable_trace:
return span_attrs return span_attrs
# Token usage attributes # Token usage attributes
@@ -188,6 +188,9 @@ class BaseMultimodalProcessor(ABC):
self._processor = _processor self._processor = _processor
self.server_args = server_args self.server_args = server_args
self.transport_mode = transport_mode self.transport_mode = transport_mode
self.keep_mm_feature_on_device = server_args.keep_mm_feature_on_device
self.disable_fast_image_processor = server_args.disable_fast_image_processor
self.skip_tokenizer_init = server_args.skip_tokenizer_init
mm_process_config = self.server_args.mm_process_config mm_process_config = self.server_args.mm_process_config
self.image_config = mm_process_config.get("image", {}) self.image_config = mm_process_config.get("image", {})
@@ -436,7 +439,7 @@ class BaseMultimodalProcessor(ABC):
if ( if (
hasattr(processor, "image_processor") hasattr(processor, "image_processor")
and isinstance(processor.image_processor, BaseImageProcessor) and isinstance(processor.image_processor, BaseImageProcessor)
and not self.server_args.disable_fast_image_processor and not self.disable_fast_image_processor
): ):
if _is_cpu or get_server_args().rl_on_policy_target is not None: if _is_cpu or get_server_args().rl_on_policy_target is not None:
kwargs["device"] = "cpu" kwargs["device"] = "cpu"
@@ -470,7 +473,7 @@ class BaseMultimodalProcessor(ABC):
return_tensors="pt", return_tensors="pt",
**kwargs, **kwargs,
) )
if not self.server_args.keep_mm_feature_on_device: if not self.keep_mm_feature_on_device:
# move feature tensors to cpu # move feature tensors to cpu
for feature_name in self.FEATURE_NAMES: for feature_name in self.FEATURE_NAMES:
if SGL_USE_CUDA_IPC: if SGL_USE_CUDA_IPC:
@@ -832,7 +835,7 @@ class BaseMultimodalProcessor(ABC):
# For MiniCPMO and MiniCPMV or multimodal_tokens not totally align, legacy show path # For MiniCPMO and MiniCPMV or multimodal_tokens not totally align, legacy show path
if ( if (
self.server_args.skip_tokenizer_init self.skip_tokenizer_init
or cnt[Modality.IMAGE] != n_image or cnt[Modality.IMAGE] != n_image
or cnt[Modality.VIDEO] != n_video or cnt[Modality.VIDEO] != n_video
or cnt[Modality.AUDIO] != n_audio or cnt[Modality.AUDIO] != n_audio
@@ -1234,7 +1237,7 @@ class BaseMultimodalProcessor(ABC):
pool_byte_offset=byte_offset, pool_byte_offset=byte_offset,
pool_device_index=self.cudaipc_mmfeature_pool._pool_device_index, pool_device_index=self.cudaipc_mmfeature_pool._pool_device_index,
) )
if self.server_args.keep_mm_feature_on_device: if self.keep_mm_feature_on_device:
return tensor return tensor
return tensor.cpu() return tensor.cpu()
@@ -303,7 +303,7 @@ class Ernie4_5_VLImageProcessor(SGLangBaseProcessor):
if ( if (
hasattr(processor, "image_processor") hasattr(processor, "image_processor")
and isinstance(processor.image_processor, BaseImageProcessor) and isinstance(processor.image_processor, BaseImageProcessor)
and not self.server_args.disable_fast_image_processor and not self.disable_fast_image_processor
): ):
if not _is_npu: if not _is_npu:
kwargs["device"] = "cuda" kwargs["device"] = "cuda"
@@ -349,7 +349,7 @@ class Ernie4_5_VLImageProcessor(SGLangBaseProcessor):
if result["pixel_values_videos"].numel() == 0: if result["pixel_values_videos"].numel() == 0:
del result["pixel_values_videos"] del result["pixel_values_videos"]
if not self.server_args.keep_mm_feature_on_device: if not self.keep_mm_feature_on_device:
# move feature tensors to cpu # move feature tensors to cpu
for feature_name in self.FEATURE_NAMES: for feature_name in self.FEATURE_NAMES:
if SGL_USE_CUDA_IPC: if SGL_USE_CUDA_IPC:
@@ -289,6 +289,11 @@ class QwenVLImageProcessor(SGLangBaseProcessor):
self.audio_start_token_id = getattr(hf_config, "audio_start_token_id", None) self.audio_start_token_id = getattr(hf_config, "audio_start_token_id", None)
self.audio_token_id = getattr(hf_config, "audio_token_id", None) self.audio_token_id = getattr(hf_config, "audio_token_id", None)
self._spatial_merge_size = self.hf_config.vision_config.spatial_merge_size
self._tokens_per_second = getattr(
self.hf_config.vision_config, "tokens_per_second", None
)
self.mm_tokens = MultimodalSpecialTokens( self.mm_tokens = MultimodalSpecialTokens(
image_token="<|vision_start|><|image_pad|><|vision_end|>", image_token="<|vision_start|><|image_pad|><|vision_end|>",
image_token_id=hf_config.image_token_id, image_token_id=hf_config.image_token_id,
@@ -300,6 +305,10 @@ class QwenVLImageProcessor(SGLangBaseProcessor):
audio_token_id=self.audio_token_id, audio_token_id=self.audio_token_id,
).build(_processor) ).build(_processor)
@property
def spatial_merge_size(self):
return self._spatial_merge_size
def build_input_ids_with_timestamps( def build_input_ids_with_timestamps(
self, prompt, embeddings, img_grid_thw, video_grid_thw, video_timestamps self, prompt, embeddings, img_grid_thw, video_grid_thw, video_timestamps
): ):
@@ -311,7 +320,7 @@ class QwenVLImageProcessor(SGLangBaseProcessor):
img_token_id = getattr(self, "IM_TOKEN_ID", None) img_token_id = getattr(self, "IM_TOKEN_ID", None)
video_token_id = getattr(self, "VIDEO_TOKEN_ID", None) video_token_id = getattr(self, "VIDEO_TOKEN_ID", None)
spatial_merge_size = getattr(self, "spatial_merge_size", 1) spatial_merge_size = self.spatial_merge_size
vision_start_token_id = getattr(self, "vision_start_token_id", None) vision_start_token_id = getattr(self, "vision_start_token_id", None)
vision_end_token_id = getattr(self, "vision_end_token_id", None) vision_end_token_id = getattr(self, "vision_end_token_id", None)
@@ -401,14 +410,12 @@ class QwenVLImageProcessor(SGLangBaseProcessor):
input_ids_tensor = torch.tensor(input_ids, dtype=torch.long).unsqueeze(0) input_ids_tensor = torch.tensor(input_ids, dtype=torch.long).unsqueeze(0)
mrope_positions, mrope_position_delta = MRotaryEmbedding.get_rope_index( mrope_positions, mrope_position_delta = MRotaryEmbedding.get_rope_index(
spatial_merge_size=self.hf_config.vision_config.spatial_merge_size, spatial_merge_size=self._spatial_merge_size,
image_token_id=self.mm_tokens.image_token_id, image_token_id=self.mm_tokens.image_token_id,
video_token_id=self.mm_tokens.video_token_id, video_token_id=self.mm_tokens.video_token_id,
vision_start_token_id=self.vision_start_token_id, vision_start_token_id=self.vision_start_token_id,
model_type=self.model_type, model_type=self.model_type,
tokens_per_second=getattr( tokens_per_second=self._tokens_per_second,
self.hf_config.vision_config, "tokens_per_second", None
),
input_ids=input_ids_tensor, input_ids=input_ids_tensor,
image_grid_thw=image_grid_thw, image_grid_thw=image_grid_thw,
video_grid_thw=video_grid_thw, video_grid_thw=video_grid_thw,
@@ -474,7 +481,7 @@ class QwenVLImageProcessor(SGLangBaseProcessor):
if not image_items or len(image_items) != len(mm_items): if not image_items or len(image_items) != len(mm_items):
return None return None
spatial_merge_size = self.hf_config.vision_config.spatial_merge_size spatial_merge_size = self._spatial_merge_size
sorted_items = sorted(image_items, key=lambda item: item.offsets[0][0]) sorted_items = sorted(image_items, key=lambda item: item.offsets[0][0])
position_segments = [] position_segments = []
st = 0 st = 0
@@ -615,7 +622,7 @@ class QwenVLImageProcessor(SGLangBaseProcessor):
assert all(isinstance(modality, Modality) for modality in modality_list) assert all(isinstance(modality, Modality) for modality in modality_list)
mrope_positions, mrope_position_delta = MRotaryEmbedding.get_rope_index( mrope_positions, mrope_position_delta = MRotaryEmbedding.get_rope_index(
spatial_merge_size=self.hf_config.vision_config.spatial_merge_size, spatial_merge_size=self._spatial_merge_size,
image_token_id=self.mm_tokens.image_token_id, image_token_id=self.mm_tokens.image_token_id,
video_token_id=self.mm_tokens.video_token_id, video_token_id=self.mm_tokens.video_token_id,
vision_start_token_id=self.vision_start_token_id, vision_start_token_id=self.vision_start_token_id,
@@ -633,9 +640,7 @@ class QwenVLImageProcessor(SGLangBaseProcessor):
position_id_per_seconds=getattr( position_id_per_seconds=getattr(
self.hf_config, "position_id_per_seconds", None self.hf_config, "position_id_per_seconds", None
), ),
tokens_per_second=getattr( tokens_per_second=self._tokens_per_second,
self.hf_config.vision_config, "tokens_per_second", None
),
) )
mrope_positions = mrope_positions.squeeze(1) mrope_positions = mrope_positions.squeeze(1)
@@ -783,14 +788,12 @@ class QwenVLImageProcessor(SGLangBaseProcessor):
) )
if mrope_result is None: if mrope_result is None:
mrope_result = MRotaryEmbedding.get_rope_index( mrope_result = MRotaryEmbedding.get_rope_index(
spatial_merge_size=self.hf_config.vision_config.spatial_merge_size, spatial_merge_size=self._spatial_merge_size,
image_token_id=self.mm_tokens.image_token_id, image_token_id=self.mm_tokens.image_token_id,
video_token_id=self.mm_tokens.video_token_id, video_token_id=self.mm_tokens.video_token_id,
vision_start_token_id=self.vision_start_token_id, vision_start_token_id=self.vision_start_token_id,
model_type=self.model_type, model_type=self.model_type,
tokens_per_second=getattr( tokens_per_second=self._tokens_per_second,
self.hf_config.vision_config, "tokens_per_second", None
),
# use the expanded token ids # use the expanded token ids
input_ids=input_ids.unsqueeze(0), input_ids=input_ids.unsqueeze(0),
image_grid_thw=image_grid_thw, image_grid_thw=image_grid_thw,
@@ -110,6 +110,11 @@ def _make_tokenizer_manager() -> TokenizerManager:
tm.disaggregation_mode = "none" tm.disaggregation_mode = "none"
tm.rid_to_state = {} tm.rid_to_state = {}
tm.enable_metrics = False tm.enable_metrics = False
tm.enable_trace = False
tm.enable_lora = False
tm.incremental_streaming_output = False
tm.allow_auto_truncate = False
tm.skip_tokenizer_init = False
tm.dump_requests_folder = "" tm.dump_requests_folder = ""
tm.crash_dump_folder = "" tm.crash_dump_folder = ""
tm.send_to_scheduler = MagicMock() tm.send_to_scheduler = MagicMock()