This repository contains the baseline model used in LLaVA-Scissor.
This model is an enhanced version of
LLaVA-OneVision model with
SIGLIP vision encoder and
Qwen2.5-0.5B-Instruct large language model and is finetuned with
Oryx data.
Here we provide a script for LLaVA-Scissor full token inference (without token compression).
1from operator import attrgetter
2from llava.model.builder import load_pretrained_model
3from llava.mm_utils import get_model_name_from_path, process_images, tokenizer_image_token
4from llava.constants import IMAGE_TOKEN_INDEX, DEFAULT_IMAGE_TOKEN, DEFAULT_IM_START_TOKEN, DEFAULT_IM_END_TOKEN, IGNORE_INDEX
5from llava.conversation import conv_templates, SeparatorStyle
6
7import torch
8import cv2
9import numpy as np
10from PIL import Image
11import requests
12import copy
13import warnings
14from decord import VideoReader, cpu
15
16warnings.filterwarnings("ignore")
17# Load the OneVision model
18pretrained = "model_zoo/BBBBCHAN/LLaVA-Scissor-baseline-0.5B"
19model_name = "llava_qwen"
20device = "cuda"
21device_map = "auto"
22tokenizer, model, image_processor, max_length = load_pretrained_model(pretrained, None, model_name, device_map=device_map, attn_implementation="sdpa")
23
24model.eval()
25
26
27# Function to extract frames from video
28def load_video(video_path, max_frames_num):
29 if type(video_path) == str:
30 vr = VideoReader(video_path, ctx=cpu(0))
31 else:
32 vr = VideoReader(video_path[0], ctx=cpu(0))
33 total_frame_num = len(vr)
34 uniform_sampled_frames = np.linspace(0, total_frame_num - 1, max_frames_num, dtype=int)
35 frame_idx = uniform_sampled_frames.tolist()
36 spare_frames = vr.get_batch(frame_idx).asnumpy()
37 return spare_frames # (frames, height, width, channels)
38
39
40# Load and process video
41video_path = "Your/path/to/the/video"
42video_frames = load_video(video_path, 16)
43print(video_frames.shape)
44image_tensors = []
45frames = image_processor.preprocess(video_frames, return_tensors="pt")["pixel_values"].half().cuda()
46image_tensors.append(frames)
47
48# Prepare conversation input
49conv_template = "qwen_2"
50question = f"{DEFAULT_IMAGE_TOKEN}
51Describe this video."
52conv = copy.deepcopy(conv_templates[conv_template])
53conv.append_message(conv.roles[0], question)
54conv.append_message(conv.roles[1], None)
55prompt_question = conv.get_prompt()
56
57input_ids = tokenizer_image_token(prompt_question, tokenizer, IMAGE_TOKEN_INDEX, return_tensors="pt").unsqueeze(0).to(device)
58image_sizes = [frame.size for frame in video_frames]
59
60# Generate response
61cont = model.generate(
62 input_ids,
63 images=image_tensors,
64 image_sizes=image_sizes,
65 do_sample=False,
66 temperature=0,
67 max_new_tokens=4096,
68 modalities=["video"],
69)
70text_outputs = tokenizer.batch_decode(cont, skip_special_tokens=True)
71print(text_outputs[0])
1@article{sun2025llava,
2 title={LLaVA-Scissor: Token Compression with Semantic Connected Components for Video LLMs},
3 author={Sun, Boyuan and Zhao, Jiaxing and Wei, Xihan and Hou, Qibin},
4 journal={arXiv preprint arXiv:2506.21862},
5 year={2025}
6}