11import json
22import os
3+ import re
34import string
4- import pandas as pd
5- import numpy as np
65
6+ import numpy as np
7+ import pandas as pd
78from datasets import Dataset , DatasetDict
89
10+ from ais_bench .benchmark .datasets import build_choices , can_infer , dump_image , split_MMMU
11+ from ais_bench .benchmark .datasets .utils .datasets import get_data_path , toliststr
912from ais_bench .benchmark .openicl import BaseEvaluator
1013from ais_bench .benchmark .registry import LOAD_DATASET
11- from ais_bench .benchmark .datasets .utils .datasets import get_data_path , toliststr
1214from ais_bench .benchmark .utils .logging import AISLogger
13- from ais_bench .benchmark .datasets import dump_image , split_MMMU , build_choices , can_infer
14- from ais_bench .benchmark .utils .prompt import AIS_CONTENT_TAG , AIS_TEXT_START , AIS_IMAGE_START
15+ from ais_bench .benchmark .utils .prompt import AIS_CONTENT_TAG , AIS_IMAGE_START , AIS_TEXT_START
1516
1617from .base import BaseDataset
1718
1819IMAGE_MAP_LEN = 64
1920logger = AISLogger ()
2021
22+
23+ def extract_options_from_question (question_text ):
24+ options = {}
25+
26+ # 查找"Options:"部分
27+ if "Options:" in question_text :
28+ # 获取Options部分
29+ options_part = question_text .split ("Options:" )[1 ].strip ()
30+
31+ # 使用正则表达式匹配所有A-Z的选项
32+ pattern = r"([A-Z]):\s*([^,]+(?:,\s*[^,]+)*?)(?=(?:,\s*[A-Z]:|$))"
33+
34+ matches = re .findall (pattern , options_part )
35+ for letter , content in matches :
36+ # 清理内容:移除末尾的句点(如果存在)
37+ content = content .strip ()
38+ if content .endswith ("." ):
39+ content = content [:- 1 ]
40+ options [letter ] = content
41+
42+ return options
43+
44+
2145@LOAD_DATASET .register_module ()
2246class MMStarDataset (BaseDataset ):
23-
2447 @staticmethod
2548 def load (path ):
2649 path = get_data_path (path )
2750 image_root_path = os .path .join (os .path .dirname (path ), "MMStar_images" )
2851 logger .info (f"Convert base64 to image and save it in { image_root_path } " )
2952 skip_noimg = True
30-
31- data = pd .read_csv (path , sep = ' \t ' )
32- if skip_noimg and ' image' in data :
33- data = data [~ pd .isna (data [' image' ])]
53+
54+ data = pd .read_csv (path , sep = " \t " )
55+ if skip_noimg and " image" in data :
56+ data = data [~ pd .isna (data [" image" ])]
3457 # The image field can store the base64 encoded image or another question index (for saving space)
35- if ' image' in data :
36- data [' image' ] = [str (x ) for x in data [' image' ]]
37- image_map = {x : y for x , y in zip (data [' index' ], data [' image' ])}
58+ if " image" in data :
59+ data [" image" ] = [str (x ) for x in data [" image" ]]
60+ image_map = {x : y for x , y in zip (data [" index" ], data [" image" ])}
3861 for k in image_map :
3962 if len (image_map [k ]) <= IMAGE_MAP_LEN :
4063 idx = image_map [k ]
4164 image_map [k ] = image_map [idx ]
4265
43- images = [toliststr (image_map [k ]) for k in data [' index' ]]
44- data [' image' ] = [x [0 ] if len (x ) == 1 else x for x in images ]
45- if ' image_path' in data :
46- paths = [toliststr (x ) for x in data [' image_path' ]]
47- data [' image_path' ] = [x [0 ] if len (x ) == 1 else x for x in paths ]
66+ images = [toliststr (image_map [k ]) for k in data [" index" ]]
67+ data [" image" ] = [x [0 ] if len (x ) == 1 else x for x in images ]
68+ if " image_path" in data :
69+ paths = [toliststr (x ) for x in data [" image_path" ]]
70+ data [" image_path" ] = [x [0 ] if len (x ) == 1 else x for x in paths ]
4871
49- if np .all ([isinstance (x , int ) for x in data [' index' ]]):
50- data [' index' ] = [int (x ) for x in data [' index' ]]
72+ if np .all ([isinstance (x , int ) for x in data [" index" ]]):
73+ data [" index" ] = [int (x ) for x in data [" index" ]]
5174
5275 sheet_indices = list (range (0 , len (data ), 1 ))
5376 data = data .iloc [sheet_indices ]
@@ -61,59 +84,67 @@ def load(path):
6184 for cand in string .ascii_uppercase
6285 if cand in line and not pd .isna (line [cand ])
6386 }
64- options_prompt = ' Options:\n '
87+ options_prompt = " Options:\n "
6588 for key , item in options .items ():
66- options_prompt += f' { key } . { item } \n '
67-
68- hint = line [' hint' ] if (' hint' in line and not pd .isna (line [' hint' ])) else None
69- # get text prompt
70- prompt = ''
89+ options_prompt += f" { key } . { item } \n "
90+
91+ hint = line [" hint" ] if (" hint" in line and not pd .isna (line [" hint" ])) else None
92+ # get text prompt
93+ prompt = ""
7194 if hint is not None :
72- prompt += f' Hint: { hint } \n '
95+ prompt += f" Hint: { hint } \n "
7396 prompt += line ["question" ]
7497 if len (options ):
7598 prompt += options_prompt
76- prompt += ' Please select the correct answer from the options above. \n '
99+ prompt += " Please select the correct answer from the options above. \n "
77100 # add image info
78101 if isinstance (tgt_path , list ):
79102 tgt_path = tgt_path [0 ]
80-
81- content = AIS_IMAGE_START + tgt_path + AIS_CONTENT_TAG \
82- + AIS_TEXT_START + prompt + AIS_CONTENT_TAG
83- choices = build_choices (line )
84- dataset .append ({"content" : content ,
85- "answer" : {'choices' : json .dumps (choices ),
86- 'answer' : line ['answer' ],
87- 'split' : line .get ('split' ),
88- 'l2-category' : line .get ('l2-category' ),
89- 'category' : line .get ('category' )}})
103+
104+ content = (
105+ AIS_IMAGE_START
106+ + tgt_path
107+ + AIS_CONTENT_TAG
108+ + AIS_TEXT_START
109+ + prompt
110+ + AIS_CONTENT_TAG
111+ )
112+ choices = build_choices (extract_options_from_question (line ['question' ]))
113+ dataset .append (
114+ {
115+ "content" : content ,
116+ "answer" : {
117+ "choices" : json .dumps (choices ),
118+ "answer" : line ["answer" ],
119+ "split" : line .get ("split" ),
120+ "l2-category" : line .get ("l2-category" ),
121+ "category" : line .get ("category" ),
122+ },
123+ }
124+ )
90125 return Dataset .from_list (dataset )
91126
92- class MMStarEvaluator (BaseEvaluator ):
93127
128+ class MMStarEvaluator (BaseEvaluator ):
94129 def score (self , predictions , references ):
95130 result = {}
96131 if len (predictions ) != len (references ):
97- return {
98- 'error' : 'predictions and references have different '
99- 'length'
100- }
132+ return {"error" : "predictions and references have different length" }
101133 details = []
102- overall_key = ' Overall'
134+ overall_key = " Overall"
103135 for pred , refer in zip (predictions , references ):
104- detail = {' pred' : pred , ' answer' : refer , ' correct' : False }
105- choices = json .loads (refer [' choices' ])
136+ detail = {" pred" : pred , " answer" : refer , " correct" : False }
137+ choices = json .loads (refer [" choices" ])
106138 infer_res = can_infer (pred , choices )
107-
108- key_category = refer [' category' ]
109- score = 1 if infer_res == refer [' answer' ] else 0
139+
140+ key_category = refer [" category" ]
141+ score = 1 if infer_res == refer [" answer" ] else 0
110142 if score == 1 :
111- detail [' correct' ] = True
143+ detail [" correct" ] = True
112144 details .append (detail )
113145 result .setdefault (overall_key , []).append (score )
114146 result .setdefault (key_category , []).append (score )
115147 for key in result :
116148 result [key ] = 100 * sum (result [key ]) / len (result [key ])
117- result [' details' ] = details
149+ result [" details" ] = details
118150 return result
119-
0 commit comments