11import json
22import os
3+ import hashlib
34
45from PIL import Image
56
67from loguru import logger
78
9+ from lmms_eval .api .metrics import levenshtein_distance
10+
811from lmms_eval .tasks ._task_utils .file_utils import generate_submission_file
912
1013IMAGES_PATH = "/data-net/storage/users/evivoli/CoMix/data/datasets/Manga109/images"
1114
15+ def create_deterministic_id (doc ):
16+ book = doc ["title" ]
17+ image_num = doc ["image_number" ]
18+
19+ question = doc ['question' ]
20+
21+ question_hash = hashlib .sha256 (question .encode ('utf-8' )).hexdigest ()[:8 ]
22+
23+ doc_id = f"{ book } _{ image_num :03d} _{ question_hash } "
24+
25+ return doc_id
26+
1227def mangavqa_doc_to_visual (doc ):
1328 book = doc ["title" ]
1429 image_num = doc ["image_number" ]
@@ -25,22 +40,82 @@ def mangavqa_doc_to_text(doc, lmms_eval_specific_kwargs):
2540
2641def mangavqa_test_process_results (doc , results ):
2742 pred = results [0 ]
28- questionId = doc ["questionId" ]
2943
44+ questionId = create_deterministic_id (doc )
45+
46+ # Process prediction
47+ pred = pred .strip ()
48+
49+ # Get ground truths
50+ ground_truths = [doc ["answer" ]] if isinstance (doc ["answer" ], str ) else doc ["answer" ]
51+
52+ # Calculate ANLS
53+ anls_values = []
54+ for answer in ground_truths :
55+ gt_answer = " " .join (answer .strip ().lower ().split ())
56+ det_answer = " " .join (pred .strip ().lower ().split ())
57+
58+ dist = levenshtein_distance (gt_answer , det_answer )
59+ length = max (len (answer .upper ()), len (pred .upper ()))
60+ anls_values .append (0.0 if length == 0 else float (dist ) / float (length ))
61+
62+ anls_score = 1 - min (anls_values ) if anls_values else 0
63+ if anls_score < 0.5 :
64+ anls_score = 0
65+
66+ # Calculate F1
67+ import string
68+ def normalize_answer (s ):
69+ def white_space_fix (text ):
70+ return " " .join (text .split ())
71+
72+ def remove_punc (text ):
73+ return "" .join (ch for ch in text if ch not in set (string .punctuation ))
74+
75+ def lower (text ):
76+ return text .lower ()
77+
78+ return white_space_fix (remove_punc (lower (s )))
79+
80+ f1_scores = []
81+ for answer in ground_truths :
82+ pred_tokens = normalize_answer (pred ).split ()
83+ gt_tokens = normalize_answer (answer ).split ()
84+
85+ common = set (pred_tokens ) & set (gt_tokens )
86+ num_same = len (common )
87+
88+ if len (pred_tokens ) == 0 or len (gt_tokens ) == 0 :
89+ f1_scores .append (int (pred_tokens == gt_tokens ))
90+ continue
91+
92+ precision = 1.0 * num_same / len (pred_tokens )
93+ recall = 1.0 * num_same / len (gt_tokens )
94+ f1 = (2 * precision * recall ) / (precision + recall ) if (precision + recall ) != 0 else 0
95+ f1_scores .append (f1 )
96+
97+ f1_score = max (f1_scores ) if f1_scores else 0
98+
99+ # Calculate Exact Match
100+ em_scores = []
101+ for answer in ground_truths :
102+ em_scores .append (1.0 if normalize_answer (pred ) == normalize_answer (answer ) else 0.0 )
103+ exact_match_score = max (em_scores ) if em_scores else 0
104+
30105 results_dict = {
31- "anls" : { "questionId" : int ( questionId ), "answer" : pred } ,
32- "f1" : { "questionId" : int ( questionId ), "answer" : pred } ,
33- "exact_match" : { "questionId" : int ( questionId ), "answer" : pred } ,
34- "submission" : {"questionId" : int ( questionId ) , "answer" : pred },
106+ "anls" : anls_score ,
107+ "f1" : f1_score ,
108+ "exact_match" : exact_match_score ,
109+ "submission" : {"questionId" : questionId , "answer" : pred },
35110 }
36111
37112 return results_dict
38113
39114def mangavqa_test_aggregate_results (results , args ):
40115 # save results as json
41- path = generate_submission_file ("docvqa_test_for_submission .json" , args )
42- with open (path , "w" ) as f :
43- json .dump (results , f )
116+ path = generate_submission_file ("manga_vqa_test_submission .json" , args )
117+ with open (path , "w" , encoding = "utf-8" ) as f :
118+ json .dump (results , f , ensure_ascii = False , indent = 4 )
44119 logger .info (f"Results saved to { path } " )
45120
46121
0 commit comments