python/sglang/srt/multimodal/evs/README.md
Implementation of Efficient Video Sampling: Pruning Temporally Redundant Tokens for Faster VLM Inference.
NOTE: The current implementation in sglang is cannot work with VLMs that use positional embeddings [Such as Qwen2.5VL]. Further work is warranted.
Video frames often contain redundant information, as consecutive frames may be nearly identical. EVS exploits this in the latent space [=embedding space] by computing similarity between adjacent frame token embeddings and pruning tokens that are highly similar to the previous frames. This reduces the token count while preserving informative content.
Key properties:
video_pruning_rate in model config.json (0 = disabled, 0.7 = ~70% reduction; ~30% retained.)NOTE: Actual retained accuracy post-EVS may depend on how dynamic the input videos are, how high the pruning rate is, whether or not the model was trained with EVS on or not, etc. To learn more, read the paper above. It is incumbent on the user to evaluate as per their use case and benchmarks.
A cursory example of a performance boost due to EVS:
export SGLANG_VLM_CACHE_SIZE_MB=0
sglang serve --model-path nvidia/Nemotron-Nano-12B-v2-VL-BF16 --trust-remote-code --mem-fraction-static 0.8 --max-mamba-cache-size 128 --chunked-prefill-size 8192
Example Request:
{ "model": "nvidia/Nemotron-Nano-12B-v2-VL-BF16", "stream": true, "temperature": 0.0, "max_completion_tokens": 3, "messages": [{ "role": "user", "content": [{ "type": "video_url", "video_url": { "url": "file:///tmp/01.mp4" } }]}]}
1XH100 95GiBBS=1https://huggingface.co/datasets/lmms-lab/Video-MME/blob/main/videos_chunked_01.zip--json-model-override-args '{"video_pruning_rate": 0.7}' [i.e., 30% of tokens are preserved] VS. --json-model-override-args '{"video_pruning_rate": 0.0}' [EVS off]| Scenario\ Metric | Online TTFT (Seconds) stderr: ±0.38 | VideoMME Accuracy |
|---|---|---|
| EVS Off [q=0.0] | 11.96 [100%] | Between 0.665 and 0.668 |
| EVS Off [q=0.4] | 09.97 [ 83%] | |
| EVS On [q=0.7] (default value) | 08.79 [ 73%] | |
| EVS Off [q=0.9] | 08.39 [ 70%] | 0.644 |
get_video_feature() for full embeddingsNemotronH_Nano_VL_V2]Make your model inherit from EVS and implement create_evs_config:
from sglang.srt.multimodal.evs import EVSConfig, EVS
class MyEVSVideoModel(EVS):
@staticmethod
def create_evs_config(config):
return EVSConfig(
video_pruning_rate=config.video_pruning_rate
)
def __init__(self, config, ...):
super().__init__(config) # EVS wraps get_video_feature
...
def get_video_feature(self, items):
# Your existing implementation
# Returns: (total_frames, tokens_per_frame, hidden_dim)
...
NanoNemotronVLImageProcessor]Create an EVSProcessor as a member of your VLImageProcessor:
from sglang.srt.multimodal.evs import EVSProcessor
class MyProcessor:
models = [MyEVSVideoModel, MyNonEVSModel] # You may mix evs and non evs models in a processor
def __init__(hf_config):
self.evs = EVSProcessor(hf_config, config_to_evs_model={MyEVSVideoModelConfig: MyEVSVideoModel})
def process_video(self, ...):
for video in videos:
tokens_per_frame = self.tokens_per_frame()
mm_items = create_data_items(
image=image_feature,
image_offsets=img_offsets,
video=video_feature,
video_offsets=video_offsets,
)
NemotronH_Nano_VL_V2_Config]Add video_pruning_rate to your model config:
class MyModelConfig(PretrainedConfig):
def __init__(self, ..., video_pruning_rate=0.0, ...):
self.video_pruning_rate = video_pruning_rate
evs_core.py: Core algorithms (retention mask computation, token redistribution)evs_module.py: EVS, configs)evs_processor.py: EVSProcessor