Skip to content

Commit 470e517

Browse files
[Benchmark] Add support for SIS-Bench benchmark (#1603)
* feat(dataset): add SIS-Bench evaluation * docs: drop SIS-Bench news entry --------- Co-authored-by: TianhaoLiang2000 <2662248501@qq.com>
1 parent aaea844 commit 470e517

3 files changed

Lines changed: 169 additions & 2 deletions

File tree

‎vlmeval/dataset/__init__.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
from .SGI_Bench_1_0.idea_generation import SGI_Bench_Idea_Generation
130130
from .SGI_Bench_1_0.wet_experiment import SGI_Bench_Wet_Experiment
131131
from .simplevqa import SimpleVQA
132+
from .sis_bench import SISBench
132133
from .sitebench import SiteBenchImage, SiteBenchVideo
133134
from .siuo import SIUODataset
134135
from .siuo_gen import SIUOGenDataset
@@ -340,7 +341,7 @@ def evaluate(self, eval_file, **judge_kwargs):
340341
Video_MMLU_CAP, Video_MMLU_QA,
341342
Video_Holmes, VCRBench, CGAVCounting,
342343
EgoExoBench_MCQ, DREAM, VideoTT, VideoMMMU, MVUEval, OMTGBench, V2PBench, AVSpeakerBench,
343-
VideoMMEv2, ReVSI
344+
VideoMMEv2, ReVSI, SISBench
344345
]
345346

346347
# add by EASI team

‎vlmeval/dataset/sis_bench.py‎

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import os.path as osp
2+
from collections import OrderedDict
3+
4+
import pandas as pd
5+
from huggingface_hub import snapshot_download
6+
7+
from vlmeval.smp import dump, get_cache_path, get_file_extension, get_intermediate_file_path, load
8+
from .utils.multiple_choice import extract_characters_regex
9+
from .video_base import VideoBaseDataset
10+
11+
12+
class SISBench(VideoBaseDataset):
13+
14+
TYPE = 'Video-MCQ'
15+
REPO_ID = 'choucsan/SIS-Bench'
16+
CHOICES = ('A', 'B', 'C', 'D')
17+
18+
SPATIAL_COGNITION_TASKS = (
19+
'object_existence',
20+
'object_attribute',
21+
'relative_direction',
22+
'landmark_appearance_order',
23+
'landmark_recall',
24+
'positional_relationship',
25+
'spatial_consistency',
26+
'spatio-temporal_consistency',
27+
)
28+
SELF_AWARENESS_TASKS = (
29+
'action_recognition',
30+
'action_sequence',
31+
'action_recall',
32+
'action_prediction',
33+
'path_planning',
34+
)
35+
TASKS = SPATIAL_COGNITION_TASKS + SELF_AWARENESS_TASKS
36+
37+
@classmethod
38+
def supported_datasets(cls):
39+
return ['SIS-Bench', 'SIS-Bench_8frame', 'SIS-Bench_32frame', 'SIS-Bench_1fps']
40+
41+
@classmethod
42+
def _generate_tsv(cls, dataset_path, dataset_name):
43+
data_file = osp.join(dataset_path, f'{dataset_name}.tsv')
44+
source_file = osp.join(dataset_path, 'SIS-Bench.jsonl')
45+
data = pd.read_json(source_file, lines=True)
46+
required = {
47+
'question_id', 'video_name', 'concat_num', 'task_type', 'question', 'options', 'answer'
48+
}
49+
missing = required.difference(data.columns)
50+
if missing:
51+
raise ValueError(f'SIS-Bench annotations are missing fields: {sorted(missing)}')
52+
53+
unknown_tasks = set(data['task_type']).difference(cls.TASKS)
54+
if unknown_tasks:
55+
raise ValueError(f'SIS-Bench contains unknown task types: {sorted(unknown_tasks)}')
56+
57+
data = data.assign(index=range(len(data)))
58+
data['video'] = data['video_name'].map(lambda value: osp.splitext(value)[0])
59+
data['video_path'] = data['video_name'].map(lambda value: osp.join('video', value))
60+
for choice in cls.CHOICES:
61+
data[choice] = data['options'].map(lambda options: options[choice])
62+
63+
columns = [
64+
'index', 'question_id', 'video', 'video_path', 'concat_num', 'task_type', 'question',
65+
*cls.CHOICES, 'answer'
66+
]
67+
data[columns].to_csv(data_file, sep='\t', index=False)
68+
return data_file
69+
70+
@classmethod
71+
def _check_integrity(cls, dataset_path, dataset_name):
72+
data_file = osp.join(dataset_path, f'{dataset_name}.tsv')
73+
if not osp.isfile(data_file):
74+
return False
75+
76+
data = load(data_file)
77+
required = {'question', 'video', 'video_path', 'task_type', 'answer', *cls.CHOICES}
78+
if not required.issubset(data.columns):
79+
return False
80+
return all(
81+
osp.isfile(osp.join(dataset_path, path)) for path in data['video_path'].unique())
82+
83+
def prepare_dataset(self, dataset_name='SIS-Bench', repo_id=REPO_ID):
84+
dataset_path = get_cache_path(repo_id)
85+
if dataset_path is None or not self._check_integrity(dataset_path, dataset_name):
86+
dataset_path = snapshot_download(repo_id=repo_id, repo_type='dataset')
87+
self._generate_tsv(dataset_path, dataset_name)
88+
89+
data_file = osp.join(dataset_path, f'{dataset_name}.tsv')
90+
return dict(root=osp.join(dataset_path, 'video'), data_file=data_file)
91+
92+
def build_prompt(self, line, video_llm):
93+
if isinstance(line, int):
94+
if line >= len(self):
95+
raise IndexError(f'SIS-Bench index out of range: {line}')
96+
line = self.data.iloc[line]
97+
98+
options = '\n'.join(f'({choice}) {line[choice]}' for choice in self.CHOICES)
99+
prompt = (f"{line['question']}\nOptions:\n{options}\n"
100+
'Answer with only the letter of the correct option.')
101+
102+
if video_llm:
103+
video_path = osp.join(self.data_root, line['video'] + '.mp4')
104+
return [dict(type='video', value=video_path), dict(type='text', value=prompt)]
105+
106+
frame_paths = self.save_video_frames(line['video'])
107+
message = [dict(type='image', value=path) for path in frame_paths]
108+
message.append(dict(type='text', value=prompt))
109+
return message
110+
111+
@staticmethod
112+
def _accuracy(data):
113+
return float(data['score'].mean() * 100) if len(data) else 0.0
114+
115+
@classmethod
116+
def evaluate(cls, eval_file, **judge_kwargs):
117+
del judge_kwargs
118+
if get_file_extension(eval_file) not in ['xlsx', 'json', 'tsv']:
119+
raise ValueError('SIS-Bench predictions must be an xlsx, json, or tsv file')
120+
121+
data = load(eval_file)
122+
required = {'prediction', 'answer', 'task_type'}
123+
missing = required.difference(data.columns)
124+
if missing:
125+
raise ValueError(f'SIS-Bench prediction file is missing fields: {sorted(missing)}')
126+
127+
unknown_tasks = set(data['task_type']).difference(cls.TASKS)
128+
if unknown_tasks:
129+
raise ValueError(
130+
f'SIS-Bench prediction file contains unknown task types: {sorted(unknown_tasks)}')
131+
132+
def extract_prediction(value):
133+
if pd.isna(value):
134+
return ''
135+
return extract_characters_regex(str(value), choices=['(A)', '(B)', '(C)', '(D)'])
136+
137+
data['predicted_answer'] = data['prediction'].map(extract_prediction)
138+
data['score'] = (data['predicted_answer'].str.upper() == data['answer'].astype(
139+
str).str.strip().str.upper()).astype(int)
140+
141+
metrics = OrderedDict()
142+
metrics['Overall'] = cls._accuracy(data)
143+
metrics['Spatial Avg'] = cls._accuracy(data[data['task_type'].isin(
144+
cls.SPATIAL_COGNITION_TASKS)])
145+
metrics['Self Avg'] = cls._accuracy(data[data['task_type'].isin(cls.SELF_AWARENESS_TASKS)])
146+
for task_type in cls.TASKS:
147+
metrics[task_type] = cls._accuracy(data[data['task_type'] == task_type])
148+
149+
score_file = get_intermediate_file_path(eval_file, '_score')
150+
rating_file = get_intermediate_file_path(eval_file, '_rating', 'json')
151+
dump(data, score_file)
152+
dump(dict(metrics), rating_file)
153+
return dict(metrics)
154+
155+
@classmethod
156+
def report_primary_metric(cls, metrics):
157+
if isinstance(metrics, dict) and 'Overall' in metrics:
158+
return {'Overall': metrics['Overall']}
159+
return super().report_primary_metric(metrics)

‎vlmeval/dataset/video_dataset_config.py‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@
5252
'Video-MME_0.5fps_subs': partial(VideoMME, dataset='Video-MME', fps=0.5, use_subtitle=True),
5353
}
5454

55+
sis_bench_dataset = {
56+
'SIS-Bench_8frame': partial(SISBench, dataset='SIS-Bench', nframe=8),
57+
'SIS-Bench_32frame': partial(SISBench, dataset='SIS-Bench', nframe=32),
58+
'SIS-Bench_1fps': partial(SISBench, dataset='SIS-Bench', fps=1.0),
59+
}
60+
5561
videommev2_dataset = {
5662
# ── No subtitle ──
5763
'Video-MME-v2_64frame': partial(VideoMMEv2, dataset='Video-MME-v2', nframe=64),
@@ -384,7 +390,8 @@ def _build_video_variants(subsets, cls, variants=VSI_FRAME_VARIANTS):
384390
supported_video_datasets = {}
385391

386392
dataset_groups = [
387-
mmbench_video_dataset, mvbench_dataset, videomme_dataset, videommev2_dataset, videommmu_dataset,
393+
mmbench_video_dataset, mvbench_dataset, videomme_dataset, sis_bench_dataset,
394+
videommev2_dataset, videommmu_dataset,
388395
longvideobench_dataset, mlvu_dataset, tempcompass_dataset, cgbench_dataset, worldsense_dataset, tamperbench_dataset,
389396
megabench_dataset, qbench_video_dataset, moviechat1k_dataset, vdc_dataset, video_holmes_dataset, vcrbench_dataset,
390397
cg_av_counting_dataset, video_mmlu_dataset, egoexobench_dataset, dream_1k_dataset, video_tt_dataset,

0 commit comments

Comments
 (0)