Views
No views yet


| Model | visual | audio | details | average | Link |
|---|---|---|---|---|---|
| Gemini-2.5-pro | 75.8 | 70.8 | 74.8 | 73.78 | N/A |
| Gemini-2.5-flash | 78.8 | 74.2 | 77.2 | 76.73 | N/A |
| Qwen2.5-Omni-3B | 55.6 | 48.2 | 52.6 | 52.18 | N/A |
| UGC-VideoCaptioner-3B-zero(1k RL) | 57.8 | 53.0 | 55.4 | 55.40(+3.22) | google-drive |
| Qwen2.5-Omni-3B 1k sft | 58.4 | 61.4 | 57.0 | 58.96(+6.78) | google-drive |
| Qwen2.5-Omni-3B 10k sft | 58.4 | 63.2 | 58.0 | 59.87(+7.69) | google-drive |
| Qwen2.5-Omni-3B 20k sft | 59.2 | 64 | 58.4 | 60.50(+8.32) | google-drive |
| UGC-VideoCaptioner-3B (1k SFT + 1k RL) | 59.4 | 62.4 | 58.2 | 60.01(+7.83) | google-drive |
transformers library. Below is a quick example demonstrating how to perform inference.
Please note that for full video processing capabilities, you might need to install decord and refer to the official GitHub repository for detailed video handling steps, especially if AutoProcessor doesn't directly handle video file paths for complex scenarios.pip install transformers torch decord soundfile qwen_omni_utils1import soundfile as sf
2
3from transformers import Qwen2_5OmniForConditionalGeneration, Qwen2_5OmniProcessor
4from qwen_omni_utils import process_mm_info
5
6model = Qwen2_5OmniForConditionalGeneration.from_pretrained("openinterx/UGC-VideoCaptioner", torch_dtype="auto", device_map="auto")
7
8# We recommend enabling flash_attention_2 for better acceleration and memory saving.
9# model = Qwen2_5OmniForConditionalGeneration.from_pretrained(
10# "Qwen/Qwen2.5-Omni-3B",
11# torch_dtype="auto",
12# device_map="auto",
13# attn_implementation="flash_attention_2",
14# )
15
16processor = Qwen2_5OmniProcessor.from_pretrained("openinterx/UGC-VideoCaptioner")
17
18# Example video path (replace with your actual video file path)
19video_path = "path/to/your/video.mp4"
20
21# Define the detailed captioning prompt
22prompt_text = (
23 "You are given a short video with both audio and visual content. Write a detailed and coherent paragraph "
24 "that naturally integrates all modalities. Your description should include: (1) the primary scene and "
25 "background setting; (2) key characters or objects and their actions or interactions; (3) significant "
26 "audio cues such as voices, background music, sound effects, and their emotional tone; (4) any on-screen "
27 "text (OCR) and its role in the video context; and (5) the overall theme or purpose of the video. "
28 "Ensure the output is a fluent and objective paragraph, not a bullet-point list, and captures the video's "
29 "content in a human-like, narrative style."
30)
31
32# Prepare messages in the chat template format
33messages = [
34 {
35 "role": "user",
36 "content": [
37 {"type": "video", "video": video_path}, # Pass video path
38 {"type": "text", "text": prompt_text},
39 ],
40 }
41]
42
43
44# set use audio in video
45USE_AUDIO_IN_VIDEO = True
46
47# Preparation for inference
48text = processor.apply_chat_template(conversation, add_generation_prompt=True, tokenize=False)
49audios, images, videos = process_mm_info(conversation, use_audio_in_video=USE_AUDIO_IN_VIDEO)
50inputs = processor(text=text, audio=audios, images=images, videos=videos, return_tensors="pt", padding=True, use_audio_in_video=USE_AUDIO_IN_VIDEO)
51inputs = inputs.to(model.device).to(model.dtype)
52
53# Inference: Generation of the output text and audio
54text_ids, audio = model.generate(**inputs, use_audio_in_video=USE_AUDIO_IN_VIDEO)
55
56text = processor.batch_decode(text_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)
57print(text)
58sf.write(
59 "output.wav",
60 audio.reshape(-1).detach().cpu().numpy(),
61 samplerate=24000,
62)1# pip install vllm
2# pip install transformers==4.52.3
3
4
5import os
6import json
7import re
8from tqdm import tqdm
9from vllm import LLM, SamplingParams
10from vllm.assets.video import VideoAsset
11from vllm.utils import FlexibleArgumentParser
12
13VIDEO_DIR = "/workspace/benchmark/video"
14OUTPUT_JSONL = "/workspace/benchmark/omni_vllm_sft_result_same_parameter.jsonl"
15USE_AUDIO_IN_VIDEO = True
16MAX_RETRY = 3
17
18# Ensure output file exists
19def ensure_output_file(path: str):
20 if not os.path.exists(path):
21 open(path, "w", encoding="utf-8").close()
22
23# Load processed video IDs to skip
24
25def load_processed_ids(jsonl_path: str) -> set[str]:
26 processed = set()
27 with open(jsonl_path, "r", encoding="utf-8") as fin:
28 for line in fin:
29 try:
30 data = json.loads(line)
31 vid = data.get("video_id")
32 if vid:
33 processed.add(vid)
34 except json.JSONDecodeError:
35 continue
36 return processed
37
38# Regex to verify level tag at end of caption
39# 没有level
40LEVEL_PATTERN = re.compile(r"<level>[A-F]</level>\s*$")
41
42PROMPT_TEMPLATE = (
43 f"<|im_start|>system\n" +
44 "You are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generating text and speech. Please make sure that the content within the answer is long and detailed enough." +
45 "<|im_end|>\n"
46 "<|im_start|>user\n<|vision_bos|><|VIDEO|><|vision_eos|>"
47 "You are given a short video with both audio and visual content. Write a detailed and coherent paragraph that naturally integrates all modalities. "
48 "Your description should include: (1) the primary scene and background setting; (2) key characters or objects and their actions or interactions; "
49 "(3) significant audio cues such as voices, background music, sound effects, and their emotional tone; "
50 "(4) any on-screen text (OCR) and its role in the video context; and (5) the overall theme or purpose of the video. "
51 "Ensure the output is a fluent and objective paragraph, not a bullet-point list, and captures the video's content in a human-like, narrative style. <|im_end|>\n"
52 "<|im_start|>assistant\n"
53)
54
55
56def process_video_folder(model_name: str, seed: int = None):
57 ensure_output_file(OUTPUT_JSONL)
58 video_files = sorted(f for f in os.listdir(VIDEO_DIR) if f.lower().endswith(".mp4"))
59 processed_ids = load_processed_ids(OUTPUT_JSONL)
60
61 llm = LLM(
62 model=model_name,
63 max_model_len=20000,
64 max_num_seqs=5,
65 limit_mm_per_prompt={"video": 1, "audio": 1},
66 seed=seed,
67 )
68 sampling_params = SamplingParams(temperature=0.2, max_tokens=1024)
69
70 with open(OUTPUT_JSONL, "a", encoding="utf-8") as fout:
71 for fname in tqdm(video_files, desc="Processing videos"):
72 video_id = os.path.splitext(fname)[0]
73 if video_id in processed_ids:
74 print(f"[Skip] {fname} already processed, skipping.")
75 continue
76
77 fpath = os.path.join(VIDEO_DIR, fname)
78 valid_caption = None
79 try:
80 video_asset = VideoAsset(path=fpath, num_frames=32)
81 audio = video_asset.get_audio(sampling_rate=16000)
82
83 inputs = {
84 "prompt": PROMPT_TEMPLATE,
85 "multi_modal_data": {"video": video_asset.np_ndarrays, "audio": audio},
86 "mm_processor_kwargs": {"use_audio_in_video": USE_AUDIO_IN_VIDEO},
87 }
88
89 for attempt in range(MAX_RETRY):
90 outputs = llm.generate(inputs, sampling_params=sampling_params)
91 text = outputs[0].outputs[0].text.strip()
92 if text and LEVEL_PATTERN.search(text):
93 valid_caption = text
94 break
95 else:
96 print(f"[Retry] Attempt {attempt+1} for {fname} did not end with level tag, retrying...")
97
98 if not valid_caption:
99 print(f"[Warning] {fname} failed to get valid level tag after {MAX_RETRY} attempts, skipping.")
100 continue
101
102 fout.write(json.dumps({"video_id": video_id, "caption": valid_caption}, ensure_ascii=False) + "\n")
103 fout.flush()
104 processed_ids.add(video_id)
105
106 except Exception as e:
107 print(f"[Error] Failed to process {fname}: {e}")
108 continue
109
110 print(f"✅ Done! Processed videos with skipping and level validation. Output written to {OUTPUT_JSONL}")
111
112
113def parse_args():
114 parser = FlexibleArgumentParser(description="Batch inference for a folder of videos using Qwen2.5-Omni + vLLM.")
115 parser.add_argument("--model-name", type=str, default="/workspace/output_model/tiktok_caption/omni_sft_20k_level/v1-20250701-150049/checkpoint-2404-merged", help="Model path or name.")
116 parser.add_argument("--seed", type=int, default=42, help="Random seed for reproducibility.")
117 return parser.parse_args()
118
119
120if __name__ == "__main__":
121 args = parse_args()
122 process_video_folder(args.model_name, args.seed)
1231prompt = "You are given a short video with both audio and visual content. Write a detailed and coherent paragraph that naturally integrates all modalities. "
2"Your description should include: (1) the primary scene and background setting; (2) key characters or objects and their actions or interactions; "
3"(3) significant audio cues such as voices, background music, sound effects, and their emotional tone; "
4"(4) any on-screen text (OCR) and its role in the video context; and (5) the overall theme or purpose of the video. "
5"Ensure the output is a fluent and objective paragraph, not a bullet-point list, and captures the video's content in a human-like, narrative style.python eval_caption.py1@article{wu2025ugc,
2 title={UGC-VideoCaptioner: An Omni UGC Video Detail Caption Model and New Benchmarks},
3 author={Wu, Peiran and Liu, Yunze and Zhu, Zhengdong and Zhou, Enmin and Shen, Shawn},
4 journal={arXiv preprint arXiv:2507.11336},
5 year={2025}
6}