Files changed (4) hide show
  1. app.py +17 -3
  2. datasets.py +1 -1
  3. utils.py +16 -1
  4. utils_v3.py +35 -20
app.py CHANGED
@@ -129,8 +129,9 @@ with gr.Blocks() as block:
129
 
130
  # table 2, text scores
131
  with gr.TabItem("πŸ“ Text [𝓝𝓔𝒲]", elem_id="tab-text", id=2):
 
132
  data_component_t = gr.components.Dataframe(
133
- value=v3.rank_models(df2[v3.COLUMN_NAMES_T], 'Text-Overall'),
134
  headers=v3.COLUMN_NAMES_T,
135
  type="pandas",
136
  datatype=v3.DATA_TITLE_TYPE_T,
@@ -138,6 +139,9 @@ with gr.Blocks() as block:
138
  visible=True,
139
  max_height=2400,
140
  )
 
 
 
141
 
142
  def get_special_processed_df2():
143
  """Temporary special processing to merge v1 scores with v2 image scores.
@@ -189,8 +193,9 @@ with gr.Blocks() as block:
189
  # table 5, audio scores
190
  with gr.TabItem("🎡 Audio [𝓝𝓔𝒲]", elem_id="tab-audio", id=5):
191
  gr.Markdown(v3.TABLE_INTRODUCTION_A)
 
192
  data_component_a = gr.components.Dataframe(
193
- value=v3.rank_models(df2[v3.COLUMN_NAMES_A], 'Audio-Overall'),
194
  headers=v3.COLUMN_NAMES_A,
195
  type="pandas",
196
  datatype=v3.DATA_TITLE_TYPE_A,
@@ -198,6 +203,10 @@ with gr.Blocks() as block:
198
  visible=True,
199
  max_height=2400,
200
  )
 
 
 
 
201
 
202
  # table 6, visual document scores only
203
  with gr.TabItem("πŸ“‘ Visual Doc", elem_id="tab-visdoc", id=6):
@@ -224,8 +233,9 @@ with gr.Blocks() as block:
224
  # table 7, agent scores
225
  with gr.TabItem("πŸ€– Agents [𝓝𝓔𝒲]", elem_id="tab-agents", id=7):
226
  gr.Markdown(v3.TABLE_INTRODUCTION_AG)
 
227
  data_component_ag = gr.components.Dataframe(
228
- value=v3.rank_models(df2[v3.COLUMN_NAMES_AG], 'Agent-Overall'),
229
  headers=v3.COLUMN_NAMES_AG,
230
  type="pandas",
231
  datatype=v3.DATA_TITLE_TYPE_AG,
@@ -233,9 +243,13 @@ with gr.Blocks() as block:
233
  visible=True,
234
  max_height=2400,
235
  )
 
 
 
236
 
237
  # table 8
238
  with gr.TabItem("πŸ“° About", elem_id="tab-about", id=8):
 
239
  gr.Image("overview.png", width=900, label="Dataset Overview")
240
  gr.Markdown(LEADERBOARD_INFO, elem_classes="markdown-text")
241
 
 
129
 
130
  # table 2, text scores
131
  with gr.TabItem("πŸ“ Text [𝓝𝓔𝒲]", elem_id="tab-text", id=2):
132
+ df3_t = v3.rank_models(df2[v3.COLUMN_NAMES_T], 'Text-Overall')
133
  data_component_t = gr.components.Dataframe(
134
+ value=df3_t,
135
  headers=v3.COLUMN_NAMES_T,
136
  type="pandas",
137
  datatype=v3.DATA_TITLE_TYPE_T,
 
139
  visible=True,
140
  max_height=2400,
141
  )
142
+ v3.save_ranking_summary(df3_t, 'text_ranking')
143
+ gr.DownloadButton("Download Text Ranking (CSV)", value=v3.download_ranking(df3_t, 'text_ranking'))
144
+ gr.DownloadButton("Download Text Ranking (JSON)", value=v3.download_ranking(df3_t, 'text_ranking', format='json'))
145
 
146
  def get_special_processed_df2():
147
  """Temporary special processing to merge v1 scores with v2 image scores.
 
193
  # table 5, audio scores
194
  with gr.TabItem("🎡 Audio [𝓝𝓔𝒲]", elem_id="tab-audio", id=5):
195
  gr.Markdown(v3.TABLE_INTRODUCTION_A)
196
+ df3_a = v3.rank_models(df2[v3.COLUMN_NAMES_A], 'Audio-Overall')
197
  data_component_a = gr.components.Dataframe(
198
+ value=df3_a,
199
  headers=v3.COLUMN_NAMES_A,
200
  type="pandas",
201
  datatype=v3.DATA_TITLE_TYPE_A,
 
203
  visible=True,
204
  max_height=2400,
205
  )
206
+ v3.save_ranking_summary(df3_a, 'audio_ranking')
207
+ gr.DownloadButton("Download Audio Ranking (CSV)", value=v3.download_ranking(df3_a, 'audio_ranking'))
208
+ gr.DownloadButton("Download Audio Ranking (JSON)", value=v3.download_ranking(df3_a, 'audio_ranking', format='json'))
209
+
210
 
211
  # table 6, visual document scores only
212
  with gr.TabItem("πŸ“‘ Visual Doc", elem_id="tab-visdoc", id=6):
 
233
  # table 7, agent scores
234
  with gr.TabItem("πŸ€– Agents [𝓝𝓔𝒲]", elem_id="tab-agents", id=7):
235
  gr.Markdown(v3.TABLE_INTRODUCTION_AG)
236
+ df3_ag = v3.rank_models(df2[v3.COLUMN_NAMES_AG], 'Agent-Overall')
237
  data_component_ag = gr.components.Dataframe(
238
+ value=df3_ag,
239
  headers=v3.COLUMN_NAMES_AG,
240
  type="pandas",
241
  datatype=v3.DATA_TITLE_TYPE_AG,
 
243
  visible=True,
244
  max_height=2400,
245
  )
246
+ v3.save_ranking_summary(df3_ag, 'agent_ranking')
247
+ gr.DownloadButton("Download Agent Ranking (CSV)", value=v3.download_ranking(df3_ag, 'agent_ranking'))
248
+ gr.DownloadButton("Download Agent Ranking (JSON)", value=v3.download_ranking(df3_ag, 'agent_ranking', format='json'))
249
 
250
  # table 8
251
  with gr.TabItem("πŸ“° About", elem_id="tab-about", id=8):
252
+ gr.Markdown(SCORING_INFO, elem_classes="markdown-text")
253
  gr.Image("overview.png", width=900, label="Dataset Overview")
254
  gr.Markdown(LEADERBOARD_INFO, elem_classes="markdown-text")
255
 
datasets.py CHANGED
@@ -20,7 +20,7 @@ DATASETS = {
20
  "image": {
21
  "I-CLS": ['VOC2007', 'N24News', 'SUN397', 'ObjectNet', 'Country211', 'Place365', 'ImageNet-1K', 'HatefulMemes', 'ImageNet-A', 'ImageNet-R'],
22
  "I-QA": ['OK-VQA', 'A-OKVQA', 'DocVQA', 'InfographicsVQA', 'ChartQA', 'Visual7W', 'ScienceQA', 'GQA', 'TextVQA', 'VizWiz'],
23
- "I-RET": ['VisDial', 'CIRR', 'VisualNews_t2i', 'VisualNews_i2t', 'MSCOCO_t2i', 'MSCOCO_i2t', 'NIGHTS', 'WebQA', 'FashionIQ', 'Wiki-SS-NQ', 'OVEN', 'EDIS'],
24
  "I-VG": ['MSCOCO', 'RefCOCO', 'RefCOCO-Matching', 'Visual7W-Pointing']
25
  },
26
  "visdoc": {
 
20
  "image": {
21
  "I-CLS": ['VOC2007', 'N24News', 'SUN397', 'ObjectNet', 'Country211', 'Place365', 'ImageNet-1K', 'HatefulMemes', 'ImageNet-A', 'ImageNet-R'],
22
  "I-QA": ['OK-VQA', 'A-OKVQA', 'DocVQA', 'InfographicsVQA', 'ChartQA', 'Visual7W', 'ScienceQA', 'GQA', 'TextVQA', 'VizWiz'],
23
+ "I-RET": ['VisDial', 'CIRR', 'VisualNews_t2i', 'VisualNews_i2t', 'MSCOCO_t2i', 'MSCOCO_i2t', 'NIGHTS', 'WebQA', 'FashionIQ', 'Wiki-SS-NQ', 'OVEN', 'EDIS', 'MCMR'],
24
  "I-VG": ['MSCOCO', 'RefCOCO', 'RefCOCO-Matching', 'Visual7W-Pointing']
25
  },
26
  "visdoc": {
utils.py CHANGED
@@ -69,8 +69,23 @@ ANNOUNCEMENT = """
69
  <li>[2025-06] VLM2Vec/MMEB-V2 released!</li>
70
  </ul>"""
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  LEADERBOARD_INFO = f"""
73
- ## Dataset Overview
74
  This is the dictionary of all datasets used in our code. Please make sure all datasets' scores are included in your submission. \n
75
  ```python
76
  {pp.pformat(DATASETS)}
 
69
  <li>[2025-06] VLM2Vec/MMEB-V2 released!</li>
70
  </ul>"""
71
 
72
+ SCORING_INFO = """
73
+ # MMEB-V3 Datasets Overview and Introductions
74
+
75
+ ## Scoring
76
+ Scores are computed as the unweighted average of all the datasets.\n
77
+ Ex.:\n
78
+ **Overall** is the average score of all the datasets included in MMEB-V3.\n
79
+ **Image-Overall is the average score of all the image datasets.**\n
80
+ **I-RET is the average of all the image retrieval datasets' scores.**\n
81
+
82
+ Rankings in CSV/JSON is available at [rankings folder](https://huggingface.co/spaces/TIGER-Lab/MMEB-Leaderboard/tree/main/rankings). You may also scroll down to the bottom of each leaderboard and click the buttons to download.
83
+
84
+ ## Appendix 1: Dataset Overview Visualization
85
+ """
86
+
87
  LEADERBOARD_INFO = f"""
88
+ ## Appendix 2: Dataset Overview in Text
89
  This is the dictionary of all datasets used in our code. Please make sure all datasets' scores are included in your submission. \n
90
  ```python
91
  {pp.pformat(DATASETS)}
utils_v3.py CHANGED
@@ -1,5 +1,6 @@
1
  import json
2
  import os
 
3
  import pandas as pd
4
  from datetime import datetime
5
  from utils import create_hyperlinked_names, process_model_size, MODEL_SIZE_COL_NAME
@@ -8,12 +9,12 @@ from datasets import *
8
  BASE_COLS = ['Rank', 'Models', MODEL_SIZE_COL_NAME, 'Date']
9
  BASE_DATA_TITLE_TYPE = ['str', 'markdown', 'str', 'str']
10
 
11
- OVERALL_COLS_V2 = ["Overall-V2", 'Image-Overall', 'Video-Overall', 'Visdoc-Overall']
12
  COLUMN_NAMES_V2 = BASE_COLS + OVERALL_COLS_V2
13
  DATA_TITLE_TYPE_V2 = BASE_DATA_TITLE_TYPE + \
14
  ['number'] * len(OVERALL_COLS_V2)
15
 
16
- OVERALL_COLS_V3 = ["Overall", "Overall-V3πŸ†•", "Text-Overall", "Audio-Overall", "Agent-Overall"]
17
  COLUMN_NAMES_V3 = BASE_COLS + OVERALL_COLS_V3
18
  DATA_TITLE_TYPE_V3 = BASE_DATA_TITLE_TYPE + \
19
  ['number'] * len(OVERALL_COLS_V3)
@@ -25,7 +26,7 @@ DATA_TITLE_TYPE_T = BASE_DATA_TITLE_TYPE + \
25
  ['number'] * len(TASKS_T)
26
 
27
  SUB_TASKS_I = ["I-CLS", "I-QA", "I-RET", "I-VG"]
28
- TASKS_I = ['Image-Overall'] + SUB_TASKS_I + ALL_DATASETS_SPLITS['image']
29
  COLUMN_NAMES_I = BASE_COLS + TASKS_I
30
  DATA_TITLE_TYPE_I = BASE_DATA_TITLE_TYPE + \
31
  ['number'] * len(TASKS_I)
@@ -55,12 +56,10 @@ DATA_TITLE_TYPE_AG = BASE_DATA_TITLE_TYPE + \
55
  ['number'] * len(TASKS_AG)
56
 
57
  TABLE_INTRODUCTION = """**MMEB**: Massive MultiModal Embedding Benchmark \n
58
- Models are ranked based on **Overall**(V3-ALL). **Overall-V3πŸ†•**: Newly added datasets in V3."""
59
  TABLE_INTRODUCTION_I = """**I-CLS**: Image Classification, **I-QA**: (Image) Visual Question Answering, **I-RET**: Image Retrieval, **I-VG**: (Image) Visual Grounding \n
60
- Models are ranked based on **Image-Overall**\n
61
- **Models from the old V1 leaderboard are missing detailed scores of each dataset.
62
- We hope the authors of the models on V1 leaderboard could rerun your models using our updated V2 pipeline,
63
- and provide us the scores sheet with the new format, so that we can make them consistent with the other models' formats.**"""
64
  TABLE_INTRODUCTION_V = """**V-CLS**: Video Classification, **V-QA**: (Video) Visual Question Answering, **V-RET**: Video Retrieval, **V-MRET**: Video Moment Retrieval \n
65
  Models are ranked based on **Video-Overall**"""
66
  TABLE_INTRODUCTION_A = """**A-CLS**: Audio Classification, **A-RET**: Audio Retrieval \n
@@ -110,10 +109,9 @@ def load_data(base_dir=SCORE_BASE_DIR):
110
 
111
  def load_scores(raw_scores={}):
112
  """This function loads the raw scores from the user provided scores summary and flattens them into a single dictionary."""
113
- # temp fix, will figure out later ===========
114
  if any(_ in raw_scores for _ in ['tool', 'gui', 'memory']):
115
  raw_scores['agent'] = raw_scores.pop('tool', {}) | raw_scores.pop('gui', {}) | raw_scores.pop('memory', {})
116
- # ===========================================
117
  all_scores = {}
118
  for modality, datasets_list in DATASETS.items(): # Ex.: ('image', {'I-CLS': [...], 'I-QA': [...]})
119
  for sub_task, datasets in datasets_list.items(): # Ex.: ('I-CLS', ['VOC2007', 'N24News', ...])
@@ -128,14 +126,14 @@ def load_scores(raw_scores={}):
128
  all_scores[dataset] = round(score * 100.0, 2)
129
  return all_scores
130
 
 
 
 
 
 
131
  def calculate_score(raw_scores=None):
132
  """This function calculates the overall average scores for all datasets as well as avg scores for each modality and sub-task based on the raw scores.
133
  """
134
- def get_avg(sum_score, leng):
135
- avg = sum_score / leng if leng > 0 else 0.0
136
- avg = round(avg, 2) # Round to 2 decimal places
137
- return avg
138
-
139
  all_scores = load_scores(raw_scores)
140
  avg_scores = {}
141
 
@@ -143,7 +141,7 @@ def calculate_score(raw_scores=None):
143
  avg_scores['Overall'] = get_avg(sum(all_scores.values()), len(ALL_DATASETS))
144
  v2_scores = {k:v for k,v in all_scores.items() if k in ALL_DATASETS_SPLITS['image'] or k in ALL_DATASETS_SPLITS['video'] or k in ALL_DATASETS_SPLITS['visdoc']}
145
  avg_scores['Overall-V2'] = get_avg(sum(v2_scores.values()), len(v2_scores))
146
- v3_newonly_scores = {k:v for k,v in all_scores.items() if k in ALL_DATASETS_SPLITS['text'] or k in ALL_DATASETS_SPLITS['audio'] or k in ALL_DATASETS_SPLITS['agent']}
147
  avg_scores['Overall-V3πŸ†•'] = get_avg(sum(v3_newonly_scores.values()), len(v3_newonly_scores))
148
 
149
  # Calculate scores for each modality
@@ -153,6 +151,10 @@ def calculate_score(raw_scores=None):
153
  sum(all_scores.get(dataset, 0.0) for dataset in datasets_for_each_modality),
154
  len(datasets_for_each_modality)
155
  )
 
 
 
 
156
 
157
  # Calculate scores for each sub-task
158
  for modality, datasets_list in DATASETS.items():
@@ -205,11 +207,11 @@ def get_df(rank_column='Overall'):
205
  df = rank_models(df, column=rank_column)
206
  return df
207
 
208
- def refresh_data():
209
  df = get_df()
210
- return df[COLUMN_NAMES]
211
 
212
- def search_and_filter_models(df, query, min_size, max_size):
213
  filtered_df = df.copy()
214
 
215
  if query:
@@ -221,9 +223,22 @@ def search_and_filter_models(df, query, min_size, max_size):
221
 
222
  filtered_df = filtered_df[size_mask]
223
 
224
- return filtered_df[COLUMN_NAMES]
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
  def save_ranking_summary(df, name, save_now=True, dir='rankings'):
 
227
  csv_path, json_path = os.path.join(dir, f'{name}.csv'), os.path.join(dir, f'{name}.jsonl')
228
  if save_now:
229
  df.to_csv(csv_path, index=False)
 
1
  import json
2
  import os
3
+ import re
4
  import pandas as pd
5
  from datetime import datetime
6
  from utils import create_hyperlinked_names, process_model_size, MODEL_SIZE_COL_NAME
 
9
  BASE_COLS = ['Rank', 'Models', MODEL_SIZE_COL_NAME, 'Date']
10
  BASE_DATA_TITLE_TYPE = ['str', 'markdown', 'str', 'str']
11
 
12
+ OVERALL_COLS_V2 = ["Overall-V2", 'Image-Overall(V2)', 'Video-Overall', 'Visdoc-Overall']
13
  COLUMN_NAMES_V2 = BASE_COLS + OVERALL_COLS_V2
14
  DATA_TITLE_TYPE_V2 = BASE_DATA_TITLE_TYPE + \
15
  ['number'] * len(OVERALL_COLS_V2)
16
 
17
+ OVERALL_COLS_V3 = ["Overall", "Overall-V3πŸ†•", "Text-Overall", "Audio-Overall", "Agent-Overall", 'Image-Overall', 'Video-Overall', 'Visdoc-Overall']
18
  COLUMN_NAMES_V3 = BASE_COLS + OVERALL_COLS_V3
19
  DATA_TITLE_TYPE_V3 = BASE_DATA_TITLE_TYPE + \
20
  ['number'] * len(OVERALL_COLS_V3)
 
26
  ['number'] * len(TASKS_T)
27
 
28
  SUB_TASKS_I = ["I-CLS", "I-QA", "I-RET", "I-VG"]
29
+ TASKS_I = ['Image-Overall', 'Image-Overall(V2)'] + SUB_TASKS_I + ALL_DATASETS_SPLITS['image']
30
  COLUMN_NAMES_I = BASE_COLS + TASKS_I
31
  DATA_TITLE_TYPE_I = BASE_DATA_TITLE_TYPE + \
32
  ['number'] * len(TASKS_I)
 
56
  ['number'] * len(TASKS_AG)
57
 
58
  TABLE_INTRODUCTION = """**MMEB**: Massive MultiModal Embedding Benchmark \n
59
+ Models are ranked based on **Overall**(V3-ALL). **Overall-V3πŸ†•**: Newly added datasets in V3 (e.g., agent, audio, text and MCMR)"""
60
  TABLE_INTRODUCTION_I = """**I-CLS**: Image Classification, **I-QA**: (Image) Visual Question Answering, **I-RET**: Image Retrieval, **I-VG**: (Image) Visual Grounding \n
61
+ Models are ranked based on **Image-Overall**, the V3 version which includes the newly added I-RET dataset MCMR.\n
62
+ **Image-Overall(V2)** is the original V2 version that excludes MCMR.\n"""
 
 
63
  TABLE_INTRODUCTION_V = """**V-CLS**: Video Classification, **V-QA**: (Video) Visual Question Answering, **V-RET**: Video Retrieval, **V-MRET**: Video Moment Retrieval \n
64
  Models are ranked based on **Video-Overall**"""
65
  TABLE_INTRODUCTION_A = """**A-CLS**: Audio Classification, **A-RET**: Audio Retrieval \n
 
109
 
110
  def load_scores(raw_scores={}):
111
  """This function loads the raw scores from the user provided scores summary and flattens them into a single dictionary."""
112
+ # merge the three agent tasks into one
113
  if any(_ in raw_scores for _ in ['tool', 'gui', 'memory']):
114
  raw_scores['agent'] = raw_scores.pop('tool', {}) | raw_scores.pop('gui', {}) | raw_scores.pop('memory', {})
 
115
  all_scores = {}
116
  for modality, datasets_list in DATASETS.items(): # Ex.: ('image', {'I-CLS': [...], 'I-QA': [...]})
117
  for sub_task, datasets in datasets_list.items(): # Ex.: ('I-CLS', ['VOC2007', 'N24News', ...])
 
126
  all_scores[dataset] = round(score * 100.0, 2)
127
  return all_scores
128
 
129
+ def get_avg(sum_score, leng):
130
+ avg = sum_score / leng if leng > 0 else 0.0
131
+ avg = round(avg, 2) # Round to 2 decimal places
132
+ return avg
133
+
134
  def calculate_score(raw_scores=None):
135
  """This function calculates the overall average scores for all datasets as well as avg scores for each modality and sub-task based on the raw scores.
136
  """
 
 
 
 
 
137
  all_scores = load_scores(raw_scores)
138
  avg_scores = {}
139
 
 
141
  avg_scores['Overall'] = get_avg(sum(all_scores.values()), len(ALL_DATASETS))
142
  v2_scores = {k:v for k,v in all_scores.items() if k in ALL_DATASETS_SPLITS['image'] or k in ALL_DATASETS_SPLITS['video'] or k in ALL_DATASETS_SPLITS['visdoc']}
143
  avg_scores['Overall-V2'] = get_avg(sum(v2_scores.values()), len(v2_scores))
144
+ v3_newonly_scores = {k:v for k,v in all_scores.items() if k in ALL_DATASETS_SPLITS['text'] or k in ALL_DATASETS_SPLITS['audio'] or k in ALL_DATASETS_SPLITS['agent'] or k == "MCMR"}
145
  avg_scores['Overall-V3πŸ†•'] = get_avg(sum(v3_newonly_scores.values()), len(v3_newonly_scores))
146
 
147
  # Calculate scores for each modality
 
151
  sum(all_scores.get(dataset, 0.0) for dataset in datasets_for_each_modality),
152
  len(datasets_for_each_modality)
153
  )
154
+ # special process for image overall v2, excluding MCMR
155
+ img_datasets_without_mcmr = [_ for _ in ALL_DATASETS_SPLITS["image"] if _ != "MCMR"] # exclude MCMR
156
+ assert len(img_datasets_without_mcmr) == len(ALL_DATASETS_SPLITS["image"])-1 and "MCMR" not in img_datasets_without_mcmr, f"MCMR not removed properly"
157
+ avg_scores["Image-Overall(V2)"] = get_avg(sum(all_scores.get(dataset, 0.0) for dataset in img_datasets_without_mcmr), len(img_datasets_without_mcmr))
158
 
159
  # Calculate scores for each sub-task
160
  for modality, datasets_list in DATASETS.items():
 
207
  df = rank_models(df, column=rank_column)
208
  return df
209
 
210
+ def refresh_data(columns = COLUMN_NAMES_V3):
211
  df = get_df()
212
+ return df[columns]
213
 
214
+ def search_and_filter_models(df, query, min_size, max_size, columns = COLUMN_NAMES_V3):
215
  filtered_df = df.copy()
216
 
217
  if query:
 
223
 
224
  filtered_df = filtered_df[size_mask]
225
 
226
+ return filtered_df[columns]
227
+
228
+ def extract_link_data(text):
229
+ # Regex to capture content inside href="..." and inside <a>...</a>
230
+ pattern = r'href="([^"]+)".*?>(.*?)</a>'
231
+ match = re.search(pattern, text)
232
+
233
+ if match:
234
+ # Found HTML: return (URL, Name)
235
+ return match.group(1), match.group(2)
236
+
237
+ # No HTML found: return (None, Original String)
238
+ return None, text
239
 
240
  def save_ranking_summary(df, name, save_now=True, dir='rankings'):
241
+ # df[['url', 'name']] = df['Models'].apply(lambda x: pd.Series(extract_link_data(x)))
242
  csv_path, json_path = os.path.join(dir, f'{name}.csv'), os.path.join(dir, f'{name}.jsonl')
243
  if save_now:
244
  df.to_csv(csv_path, index=False)