GuoruiSong commited on
Commit
40e31b6
·
verified ·
1 Parent(s): c3275b3

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. LaViDa/eval/lmms_eval/tasks/ai2d/ai2d.yaml +55 -0
  2. LaViDa/eval/lmms_eval/tasks/ai2d/ai2d_lite.yaml +56 -0
  3. LaViDa/eval/lmms_eval/tasks/air_bench/_default_template_yaml +7 -0
  4. LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat.yaml +6 -0
  5. LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_mixed.yaml +25 -0
  6. LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_music.yaml +25 -0
  7. LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_sound.yaml +25 -0
  8. LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_speech.yaml +25 -0
  9. LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation.yaml +5 -0
  10. LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation_music.yaml +26 -0
  11. LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation_sound.yaml +26 -0
  12. LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation_speech.yaml +26 -0
  13. LaViDa/eval/lmms_eval/tasks/air_bench/utils.py +281 -0
  14. LaViDa/eval/lmms_eval/tasks/arc/README.md +58 -0
  15. LaViDa/eval/lmms_eval/tasks/arc/arc_challenge.yaml +3 -0
  16. LaViDa/eval/lmms_eval/tasks/arc/arc_easy.yaml +23 -0
  17. LaViDa/eval/lmms_eval/tasks/av_odyssey/av_odyssey.yaml +24 -0
  18. LaViDa/eval/lmms_eval/tasks/av_odyssey/utils.py +264 -0
  19. LaViDa/eval/lmms_eval/tasks/chartqa/chartqa.yaml +34 -0
  20. LaViDa/eval/lmms_eval/tasks/chartqa/chartqa_lite.yaml +35 -0
  21. LaViDa/eval/lmms_eval/tasks/chartqa/upload_chartqa.py +129 -0
  22. LaViDa/eval/lmms_eval/tasks/chartqa/utils.py +62 -0
  23. LaViDa/eval/lmms_eval/tasks/clotho_aqa/_default_template_yaml +10 -0
  24. LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_aqa.yaml +4 -0
  25. LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_aqa_test.yaml +19 -0
  26. LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_aqa_val.yaml +19 -0
  27. LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_asqa_test_v2.yaml +19 -0
  28. LaViDa/eval/lmms_eval/tasks/clotho_aqa/utils.py +142 -0
  29. LaViDa/eval/lmms_eval/tasks/coco_cap/coco2014_cap.yaml +4 -0
  30. LaViDa/eval/lmms_eval/tasks/coco_cap/coco2014_cap_test.yaml +24 -0
  31. LaViDa/eval/lmms_eval/tasks/coco_cap/coco2014_cap_val.yaml +45 -0
  32. LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap.yaml +4 -0
  33. LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap_test.yaml +24 -0
  34. LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap_val.yaml +45 -0
  35. LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap_val_lite.yaml +45 -0
  36. LaViDa/eval/lmms_eval/tasks/coco_cap/coco_cap.yaml +6 -0
  37. LaViDa/eval/lmms_eval/tasks/coco_cap/utils.py +155 -0
  38. LaViDa/eval/lmms_eval/tasks/common_voice_15/_default_template_yaml +21 -0
  39. LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15.yaml +5 -0
  40. LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15_en.yaml +10 -0
  41. LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15_fr.yaml +10 -0
  42. LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15_zh-CN.yaml +10 -0
  43. LaViDa/eval/lmms_eval/tasks/common_voice_15/utils.py +182 -0
  44. LaViDa/eval/lmms_eval/tasks/conbench/conbench.yaml +24 -0
  45. LaViDa/eval/lmms_eval/tasks/conbench/utils.py +96 -0
  46. LaViDa/eval/lmms_eval/tasks/covost2/_default_template_en_zh_yaml +28 -0
  47. LaViDa/eval/lmms_eval/tasks/covost2/_default_template_zh_en_yaml +28 -0
  48. LaViDa/eval/lmms_eval/tasks/covost2/covost2.yaml +4 -0
  49. LaViDa/eval/lmms_eval/tasks/covost2/covost2_en_zh.yaml +4 -0
  50. LaViDa/eval/lmms_eval/tasks/covost2/covost2_en_zh_dev.yaml +12 -0
LaViDa/eval/lmms_eval/tasks/ai2d/ai2d.yaml ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/ai2d
2
+ task: "ai2d"
3
+ dataset_kwargs:
4
+ token: True
5
+ test_split: test
6
+ output_type: generate_until
7
+ doc_to_visual: !function utils.ai2d_doc_to_visual
8
+ doc_to_text: !function utils.ai2d_doc_to_text
9
+ doc_to_target: !function utils.ai2d_doc_to_target
10
+
11
+ lmms_eval_specific_kwargs:
12
+ default:
13
+ prompt_format: mcq
14
+ pre_prompt: ""
15
+ post_prompt: "\nAnswer with the option's letter from the given choices directly."
16
+ gpt4v:
17
+ prompt_format: mcq
18
+ pre_prompt: ""
19
+ post_prompt: "\nAbove choices are given in {option}. {content} format.\nPlease answer with the option letter from the given choices directly."
20
+ qwen_vl:
21
+ prompt_format: qa
22
+ pre_prompt: ""
23
+ post_prompt: " Answer:"
24
+ xcomposer2_4khd:
25
+ prompt_format: mcq_xcomposer
26
+ pre_prompt: "[UNUSED_TOKEN_146]user\nQuestion: "
27
+ post_prompt: "[UNUSED_TOKEN_145]\n[UNUSED_TOKEN_146]assistant\nThe answer is"
28
+
29
+ model_specific_target_kwargs:
30
+ default: "mcq"
31
+ qwen_vl: "qa"
32
+
33
+ generation_kwargs:
34
+ max_new_tokens: 16
35
+ temperature: 0
36
+ do_sample: False
37
+
38
+ filter_list:
39
+ - name: "flexible-extract"
40
+ filter:
41
+ - function: !function utils.MultiChoiceRegexFilter
42
+ group_select: 0
43
+ ignore_case: true
44
+ ignore_punctuation: true
45
+ regex_pattern: "([A-Z])\\."
46
+
47
+ metric_list:
48
+ - metric: exact_match
49
+ aggregation: mean
50
+ higher_is_better: true
51
+ ignore_case: true
52
+ ignore_punctuation: true
53
+
54
+ metadata:
55
+ - version: 0.0
LaViDa/eval/lmms_eval/tasks/ai2d/ai2d_lite.yaml ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/LMMs-Eval-Lite
2
+ task: "ai2d_lite"
3
+ dataset_kwargs:
4
+ token: True
5
+ dataset_name: ai2d
6
+ test_split: lite
7
+ output_type: generate_until
8
+ doc_to_visual: !function utils.ai2d_doc_to_visual
9
+ doc_to_text: !function utils.ai2d_doc_to_text
10
+ doc_to_target: !function utils.ai2d_doc_to_target
11
+
12
+ lmms_eval_specific_kwargs:
13
+ default:
14
+ prompt_format: mcq
15
+ pre_prompt: ""
16
+ post_prompt: "\nAnswer with the option's letter from the given choices directly."
17
+ gpt4v:
18
+ prompt_format: mcq
19
+ pre_prompt: ""
20
+ post_prompt: "\nAbove choices are given in {option}. {content} format.\nPlease answer with the option letter from the given choices directly."
21
+ qwen_vl:
22
+ prompt_format: qa
23
+ pre_prompt: ""
24
+ post_prompt: " Answer:"
25
+ xcomposer2_4khd:
26
+ prompt_format: mcq_xcomposer
27
+ pre_prompt: "[UNUSED_TOKEN_146]user\nQuestion: "
28
+ post_prompt: "[UNUSED_TOKEN_145]\n[UNUSED_TOKEN_146]assistant\nThe answer is"
29
+
30
+ model_specific_target_kwargs:
31
+ default: "mcq"
32
+ qwen_vl: "qa"
33
+
34
+ generation_kwargs:
35
+ max_new_tokens: 16
36
+ temperature: 0
37
+ do_sample: False
38
+
39
+ filter_list:
40
+ - name: "flexible-extract"
41
+ filter:
42
+ - function: !function utils.MultiChoiceRegexFilter
43
+ group_select: 0
44
+ ignore_case: true
45
+ ignore_punctuation: true
46
+ regex_pattern: "([A-Z])\\."
47
+
48
+ metric_list:
49
+ - metric: exact_match
50
+ aggregation: mean
51
+ higher_is_better: true
52
+ ignore_case: true
53
+ ignore_punctuation: true
54
+
55
+ metadata:
56
+ - version: 0.0
LaViDa/eval/lmms_eval/tasks/air_bench/_default_template_yaml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/AIR_Bench
2
+ dataset_kwargs:
3
+ token: True
4
+
5
+ metadata:
6
+ gpt_eval_model_name: gpt-4o
7
+ version: 0.0
LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat.yaml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ group: air_bench_chat
2
+ task:
3
+ - air_bench_chat_sound
4
+ - air_bench_chat_music
5
+ - air_bench_chat_speech
6
+ - air_bench_chat_mixed
LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_mixed.yaml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: "air_bench_chat_mixed"
2
+ dataset_name: "Chat"
3
+ test_split: mixed
4
+ doc_to_target: "answer_gt"
5
+ doc_to_visual: !function utils.air_bench_doc_to_audio
6
+ doc_to_text: !function utils.air_bench_doc_to_text_chat
7
+
8
+ generation_kwargs:
9
+ max_new_tokens: 1024
10
+ temperature: 0.2
11
+ top_p: 1.0
12
+ num_beams: 1
13
+
14
+ lmms_eval_specific_kwargs:
15
+ default:
16
+ pre_prompt: ""
17
+ post_prompt: "Give a detail answer to the question in English."
18
+ metric_list:
19
+ - metric: gpt_eval
20
+ aggregation: !function utils.air_bench_aggregate_results_chat
21
+ higher_is_better: true
22
+
23
+ process_results: !function utils.air_bench_process_results_chat
24
+
25
+ include: _default_template_yaml
LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_music.yaml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: "air_bench_chat_music"
2
+ dataset_name: "Chat"
3
+ test_split: music
4
+ doc_to_target: "answer_gt"
5
+ doc_to_visual: !function utils.air_bench_doc_to_audio
6
+ doc_to_text: !function utils.air_bench_doc_to_text_chat
7
+
8
+ generation_kwargs:
9
+ max_new_tokens: 1024
10
+ temperature: 0.2
11
+ top_p: 1.0
12
+ num_beams: 1
13
+
14
+ lmms_eval_specific_kwargs:
15
+ default:
16
+ pre_prompt: ""
17
+ post_prompt: "Give a detail answer to the question in English."
18
+ metric_list:
19
+ - metric: gpt_eval
20
+ aggregation: !function utils.air_bench_aggregate_results_chat
21
+ higher_is_better: true
22
+
23
+ process_results: !function utils.air_bench_process_results_chat
24
+
25
+ include: _default_template_yaml
LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_sound.yaml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: "air_bench_chat_sound"
2
+ dataset_name: "Chat"
3
+ test_split: sound
4
+ doc_to_target: "answer_gt"
5
+ doc_to_visual: !function utils.air_bench_doc_to_audio
6
+ doc_to_text: !function utils.air_bench_doc_to_text_chat
7
+
8
+ generation_kwargs:
9
+ max_new_tokens: 1024
10
+ temperature: 0.2
11
+ top_p: 1.0
12
+ num_beams: 1
13
+
14
+ lmms_eval_specific_kwargs:
15
+ default:
16
+ pre_prompt: ""
17
+ post_prompt: "Give a detail answer to the question in English."
18
+ metric_list:
19
+ - metric: gpt_eval
20
+ aggregation: !function utils.air_bench_aggregate_results_chat
21
+ higher_is_better: true
22
+
23
+ process_results: !function utils.air_bench_process_results_chat
24
+
25
+ include: _default_template_yaml
LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_speech.yaml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: "air_bench_chat_speech"
2
+ dataset_name: "Chat"
3
+ test_split: speech
4
+ doc_to_target: "answer_gt"
5
+ doc_to_visual: !function utils.air_bench_doc_to_audio
6
+ doc_to_text: !function utils.air_bench_doc_to_text_chat
7
+
8
+ generation_kwargs:
9
+ max_new_tokens: 1024
10
+ temperature: 0.2
11
+ top_p: 1.0
12
+ num_beams: 1
13
+
14
+ lmms_eval_specific_kwargs:
15
+ default:
16
+ pre_prompt: ""
17
+ post_prompt: "Give a detail answer to the question in English."
18
+ metric_list:
19
+ - metric: gpt_eval
20
+ aggregation: !function utils.air_bench_aggregate_results_chat
21
+ higher_is_better: true
22
+
23
+ process_results: !function utils.air_bench_process_results_chat
24
+
25
+ include: _default_template_yaml
LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation.yaml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ group: air_bench_foundation
2
+ task:
3
+ - air_bench_foundation_sound
4
+ - air_bench_foundation_music
5
+ - air_bench_foundation_speech
LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation_music.yaml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: "air_bench_foundation_music"
2
+ dataset_name: "Foundation"
3
+ test_split: music
4
+ doc_to_target: !function utils.air_bench_doc_to_target_foundation
5
+ doc_to_visual: !function utils.air_bench_doc_to_audio
6
+ doc_to_text: !function utils.air_bench_doc_to_text_foundation
7
+ doc_to_choice: !function utils.air_bench_doc_to_choice_foundation
8
+ generation_kwargs:
9
+ max_new_tokens: 256
10
+ temperature: 0
11
+ do_sample: False
12
+ lmms_eval_specific_kwargs:
13
+ default:
14
+ pre_prompt: ""
15
+ post_prompt: "\nAnswer with the option's letter from the given choices directly."
16
+ metric_list:
17
+ - metric: accuracy
18
+ aggregation: !function utils.air_bench_aggregate_results_foundation
19
+ higher_is_better: true
20
+ - metric: submission
21
+ aggregation: !function utils.air_bench_aggregate_results_for_submission
22
+ higher_is_better: true
23
+
24
+ process_results: !function utils.air_bench_process_results_foundation
25
+
26
+ include: _default_template_yaml
LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation_sound.yaml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: "air_bench_foundation_sound"
2
+ dataset_name: "Foundation"
3
+ test_split: sound
4
+ doc_to_target: !function utils.air_bench_doc_to_target_foundation
5
+ doc_to_visual: !function utils.air_bench_doc_to_audio
6
+ doc_to_text: !function utils.air_bench_doc_to_text_foundation
7
+ doc_to_choice: !function utils.air_bench_doc_to_choice_foundation
8
+ generation_kwargs:
9
+ max_new_tokens: 256
10
+ temperature: 0
11
+ do_sample: False
12
+ lmms_eval_specific_kwargs:
13
+ default:
14
+ pre_prompt: ""
15
+ post_prompt: "\nAnswer with the option's letter from the given choices directly."
16
+ metric_list:
17
+ - metric: accuracy
18
+ aggregation: !function utils.air_bench_aggregate_results_foundation
19
+ higher_is_better: true
20
+ - metric: submission
21
+ aggregation: !function utils.air_bench_aggregate_results_for_submission
22
+ higher_is_better: true
23
+
24
+ process_results: !function utils.air_bench_process_results_foundation
25
+
26
+ include: _default_template_yaml
LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation_speech.yaml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: "air_bench_foundation_speech"
2
+ dataset_name: "Foundation"
3
+ test_split: speech
4
+ doc_to_target: !function utils.air_bench_doc_to_target_foundation
5
+ doc_to_visual: !function utils.air_bench_doc_to_audio
6
+ doc_to_text: !function utils.air_bench_doc_to_text_foundation
7
+ doc_to_choice: !function utils.air_bench_doc_to_choice_foundation
8
+ generation_kwargs:
9
+ max_new_tokens: 256
10
+ temperature: 0
11
+ do_sample: False
12
+ lmms_eval_specific_kwargs:
13
+ default:
14
+ pre_prompt: ""
15
+ post_prompt: "\nAnswer with the option's letter from the given choices directly."
16
+ metric_list:
17
+ - metric: accuracy
18
+ aggregation: !function utils.air_bench_aggregate_results_foundation
19
+ higher_is_better: true
20
+ - metric: submission
21
+ aggregation: !function utils.air_bench_aggregate_results_for_submission
22
+ higher_is_better: true
23
+
24
+ process_results: !function utils.air_bench_process_results_foundation
25
+
26
+ include: _default_template_yaml
LaViDa/eval/lmms_eval/tasks/air_bench/utils.py ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datetime
2
+ import json
3
+ import os
4
+ import random
5
+ import re
6
+ import sys
7
+ import time
8
+ from pathlib import Path
9
+
10
+ import numpy as np
11
+ import requests
12
+ import yaml
13
+ from loguru import logger as eval_logger
14
+
15
+ from lmms_eval.tasks._task_utils.file_utils import generate_submission_file
16
+
17
+
18
+ def air_bench_doc_to_audio(doc):
19
+ return [doc["audio"]]
20
+
21
+
22
+ def air_bench_doc_to_text_chat(doc, lmms_eval_specific_kwargs):
23
+ question = doc["question"]
24
+ pre_prompt = lmms_eval_specific_kwargs["pre_prompt"]
25
+ post_prompt = lmms_eval_specific_kwargs["post_prompt"]
26
+ return f"{pre_prompt}{question}{post_prompt}"
27
+
28
+
29
+ with open(Path(__file__).parent / "_default_template_yaml", "r") as f:
30
+ raw_data = f.readlines()
31
+ safe_data = []
32
+ for i, line in enumerate(raw_data):
33
+ # remove function definition since yaml load cannot handle it
34
+ if "!function" not in line:
35
+ safe_data.append(line)
36
+
37
+ config = yaml.safe_load("".join(safe_data))
38
+
39
+ # specify api type and key in .env
40
+ GPT_EVAL_MODEL_NAME = config["metadata"]["gpt_eval_model_name"]
41
+ API_TYPE = os.getenv("API_TYPE", "azure")
42
+
43
+ if API_TYPE == "openai":
44
+ API_URL = os.getenv("OPENAI_API_URL", "https://api.openai.com/v1/chat/completions")
45
+ API_KEY = os.getenv("OPENAI_API_KEY", "YOUR_API_KEY")
46
+ headers = {
47
+ "Authorization": f"Bearer {API_KEY}",
48
+ "Content-Type": "application/json",
49
+ }
50
+ elif API_TYPE == "azure":
51
+ API_URL = os.getenv("AZURE_ENDPOINT", "https://api.cognitive.microsoft.com/sts/v1.0/issueToken")
52
+ API_KEY = os.getenv("AZURE_API_KEY", "YOUR_API_KEY")
53
+ headers = {
54
+ "api-key": API_KEY,
55
+ "Content-Type": "application/json",
56
+ }
57
+
58
+ # prompt taken from the AIR-Bench repo
59
+ eval_prompt = (
60
+ "You are a helpful and precise assistant for checking the quality of the answer.\n"
61
+ "[Detailed Audio Description]\nXAudioX\n[Question]\nXQuestionX\n"
62
+ "[The Start of Assistant 1s Answer]\nXAssistant1X\n[The End of Assistant 1s Answer]\n"
63
+ "[The Start of Assistant 2s Answer]\nXAssistant2X\n[The End of Assistant 2s Answer]\n[System]\n"
64
+ "We would like to request your feedback on the performance of two AI assistants in response to the user question "
65
+ "and audio description displayed above. AI assistants are provided with detailed audio descriptions and questions.\n"
66
+ "Please rate the helpfulness, relevance, accuracy, and comprehensiveness of their responses. "
67
+ "Each assistant receives an overall score on a scale of 1 to 10, where a higher score indicates better overall performance. "
68
+ "Please output a single line containing only two values indicating the scores for Assistant 1 and 2, respectively. "
69
+ "The two scores are separated by a space. Please only output the 2 required number and no text."
70
+ )
71
+
72
+ retries = 3
73
+ NUM_SECONDS_TO_SLEEP = 5
74
+
75
+
76
+ def get_eval(max_tokens: int, content: str, retries: int = retries):
77
+ global headers
78
+
79
+ messages = [
80
+ {"role": "user", "content": content},
81
+ ]
82
+
83
+ payload = {
84
+ "model": GPT_EVAL_MODEL_NAME,
85
+ "messages": messages,
86
+ "temperature": 0,
87
+ "max_tokens": max_tokens,
88
+ }
89
+
90
+ for attempt in range(retries):
91
+ try:
92
+ response = requests.post(API_URL, headers=headers, json=payload, timeout=60)
93
+ response.raise_for_status()
94
+ response_data = response.json()
95
+
96
+ content = response_data["choices"][0]["message"]["content"].strip()
97
+ if content != "":
98
+ return content, response_data["model"]
99
+ break # If successful, break out of the loop
100
+
101
+ except Exception as e:
102
+ eval_logger.info(f"Attempt {attempt + 1} failed with error: {e}")
103
+ if attempt < retries: # If we have retries left, sleep and then continue to next attempt
104
+ time.sleep(NUM_SECONDS_TO_SLEEP)
105
+ else: # If this was the last attempt, log and return empty
106
+ eval_logger.error(f"All {retries} attempts failed. Last error message: {e}")
107
+ return "", ""
108
+ return "", ""
109
+
110
+
111
+ def air_bench_process_results_chat(doc, result):
112
+ path = doc["path"]
113
+ question = doc["question"]
114
+ answer_gt = doc["answer_gt"]
115
+ task_name = doc["task_name"]
116
+ dataset_name = doc["dataset_name"]
117
+ response = result[0]
118
+
119
+ if response == None:
120
+ exit(1)
121
+
122
+ if doc["meta_info"] == None:
123
+ print("lack meta info")
124
+ exit(1)
125
+ else:
126
+ meta_info = doc["meta_info"]
127
+
128
+ # Get the evaluation score 2 times: one with ourmodel as assistant 1 and the other with our model as assistant 2 to prevent position bias
129
+ content = eval_prompt.replace("XAudioX", meta_info).replace("XQuestionX", question).replace("XAssistant1X", answer_gt).replace("XAssistant2X", response)
130
+ eval_answer, model_name = get_eval(max_tokens=1024, content=content)
131
+ content = eval_prompt.replace("XAudioX", meta_info).replace("XQuestionX", question).replace("XAssistant1X", response).replace("XAssistant2X", answer_gt)
132
+ eval_answer2, model_name2 = get_eval(max_tokens=1024, content=content)
133
+
134
+ return {
135
+ "gpt_eval": {
136
+ "eval_answer": [eval_answer, eval_answer2],
137
+ "model_name": model_name,
138
+ },
139
+ }
140
+
141
+
142
+ def air_bench_aggregate_results_chat(results):
143
+ score = 0
144
+ for result in results:
145
+ eval_answer = result["eval_answer"]
146
+ eval_answer = [eval_answer[i].strip().replace(".", "") for i in range(len(eval_answer))]
147
+ pattern = r"\b(?:[1-9]|10)\b"
148
+
149
+ # Find all matches
150
+ try:
151
+ matches1 = re.findall(pattern, eval_answer[0])
152
+ matches2 = re.findall(pattern, eval_answer[1])
153
+ # Get the first two occurrences
154
+ eval_score = float(matches1[1]) + float(matches2[0])
155
+ score += eval_score
156
+ except Exception as e:
157
+ eval_logger.error(f"Error parsing eval_score: {e}")
158
+ continue
159
+
160
+ return score / (2 * len(results))
161
+
162
+
163
+ # Functions for Foundation tasks
164
+
165
+
166
+ def air_bench_doc_to_text_foundation(doc, lmms_eval_specific_kwargs):
167
+ question = doc["question"]
168
+ answers = [doc["choice_a"], doc["choice_b"], doc.get("choice_c", None), doc.get("choice_d", None)]
169
+ question = f"{question}\nA. {answers[0]}\nB. {answers[1]}\nC. {answers[2]}\nD. {answers[3]}\n"
170
+ pre_prompt = lmms_eval_specific_kwargs["pre_prompt"]
171
+ post_prompt = lmms_eval_specific_kwargs["post_prompt"]
172
+ return f"{pre_prompt}{question}{post_prompt}"
173
+
174
+
175
+ def air_bench_doc_to_target_foundation(doc):
176
+ return get_gt(doc)
177
+
178
+
179
+ def air_bench_doc_to_choice_foundation(doc):
180
+ choices = []
181
+ for option in ["choice_a", "choice_b", "choice_c", "choice_d"]:
182
+ if doc.get(option) and doc[option].strip():
183
+ choices.append(option[-1].upper())
184
+ return choices
185
+
186
+
187
+ def air_bench_process_results_foundation(doc, result):
188
+ response = result[0].strip()
189
+ all_choices = [choice[-1].upper() for choice in ["choice_a", "choice_b", "choice_c", "choice_d"] if doc.get(choice)]
190
+ pred = parse_multi_choice_response(response, all_choices) # AdaptfromMMMU
191
+ gt_ans = get_gt(doc)
192
+ score = 1.0 if pred == gt_ans else 0.0
193
+ submission_dict = {}
194
+ submission_dict = {doc.get("uniq_id", "unknown"): pred}
195
+ return {
196
+ "accuracy": {"score": score, "task": doc["task_name"]},
197
+ "submission": submission_dict,
198
+ }
199
+
200
+
201
+ def air_bench_aggregate_results_for_submission(results, args):
202
+ path = generate_submission_file("air_bench_test_submission.json", args)
203
+ with open(path, "w") as f:
204
+ json.dump(results, f)
205
+ eval_logger.info(f"Results saved to {path}.")
206
+
207
+
208
+ def air_bench_aggregate_results_foundation(results):
209
+ score = 0
210
+ categorical_correct = {}
211
+ categorical_total = {}
212
+ for result in results:
213
+ score += result["score"]
214
+ if result["task"] not in categorical_correct.keys():
215
+ categorical_correct[result["task"]] = 0
216
+ categorical_total[result["task"]] = 0
217
+ categorical_correct[result["task"]] += result["score"]
218
+ categorical_total[result["task"]] += 1
219
+
220
+ overall_accuracy = round(score / len(results), 5)
221
+ categorical_accuracy = {task: round(categorical_correct[task] / categorical_total[task], 5) for task in categorical_correct.keys()}
222
+
223
+ eval_logger.info("=" * 50)
224
+ eval_logger.info(f"Overall accuracy: {overall_accuracy}")
225
+ for task, acc in categorical_accuracy.items():
226
+ eval_logger.info(f"{task} accuracy: {acc}")
227
+ eval_logger.info("=" * 50)
228
+ return overall_accuracy
229
+
230
+
231
+ def parse_multi_choice_response(response, all_choices):
232
+ """
233
+ Parse the prediction from the generated response.
234
+ Return the predicted choice letter e.g., A, B, C, D.
235
+ """
236
+ # Clean response of unwanted characters
237
+ for char in [",", ".", "!", "?", ";", ":", "'"]:
238
+ response = response.strip(char)
239
+ response = " " + response + " " # Add space to avoid partial match
240
+
241
+ candidates = []
242
+ # Look for choices with parentheses, e.g., (A)
243
+ for choice in all_choices:
244
+ if f"({choice})" in response:
245
+ candidates.append(choice)
246
+
247
+ # Look for simple choices, e.g., A, B, C
248
+ if len(candidates) == 0:
249
+ for choice in all_choices:
250
+ if f" {choice} " in response:
251
+ candidates.append(choice)
252
+
253
+ # Look for choices with periods, e.g., A., B., C.
254
+ if len(candidates) == 0:
255
+ for choice in all_choices:
256
+ if f"{choice}." in response:
257
+ candidates.append(choice)
258
+
259
+ # If no candidates, randomly choose one
260
+ if len(candidates) == 0:
261
+ pred_index = random.choice(all_choices)
262
+ elif len(candidates) > 1:
263
+ # If more than one candidate, choose the last one found
264
+ start_indexes = [response.rfind(f" {can} ") for can in candidates]
265
+ pred_index = candidates[np.argmax(start_indexes)]
266
+ else:
267
+ # If only one candidate, use it
268
+ pred_index = candidates[0]
269
+
270
+ return pred_index
271
+
272
+
273
+ def get_gt(doc):
274
+ if doc["answer_gt"] == doc["choice_a"]:
275
+ return "A"
276
+ elif doc["answer_gt"] == doc["choice_b"]:
277
+ return "B"
278
+ elif doc["answer_gt"] == doc.get("choice_c", None):
279
+ return "C"
280
+ elif doc["answer_gt"] == doc.get("choice_d", None):
281
+ return "D"
LaViDa/eval/lmms_eval/tasks/arc/README.md ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ARC
2
+
3
+ ### Paper
4
+
5
+ Title: Think you have Solved Question Answering? Try ARC, the AI2 Reasoning Challenge
6
+
7
+ Abstract: https://arxiv.org/abs/1803.05457
8
+
9
+ The ARC dataset consists of 7,787 science exam questions drawn from a variety
10
+ of sources, including science questions provided under license by a research
11
+ partner affiliated with AI2. These are text-only, English language exam questions
12
+ that span several grade levels as indicated in the files. Each question has a
13
+ multiple choice structure (typically 4 answer options). The questions are sorted
14
+ into a Challenge Set of 2,590 “hard” questions (those that both a retrieval and
15
+ a co-occurrence method fail to answer correctly) and an Easy Set of 5,197 questions.
16
+
17
+ Homepage: https://allenai.org/data/arc
18
+
19
+
20
+ ### Citation
21
+
22
+ ```
23
+ @article{Clark2018ThinkYH,
24
+ title={Think you have Solved Question Answering? Try ARC, the AI2 Reasoning Challenge},
25
+ author={Peter Clark and Isaac Cowhey and Oren Etzioni and Tushar Khot and Ashish Sabharwal and Carissa Schoenick and Oyvind Tafjord},
26
+ journal={ArXiv},
27
+ year={2018},
28
+ volume={abs/1803.05457}
29
+ }
30
+ ```
31
+
32
+ ### Groups, Tags, and Tasks
33
+
34
+ #### Groups
35
+
36
+ None.
37
+
38
+ #### Tags
39
+
40
+ * `ai2_arc`: Evaluates `arc_easy` and `arc_challenge`
41
+
42
+ #### Tasks
43
+
44
+ * `arc_easy`
45
+ * `arc_challenge`
46
+
47
+ ### Checklist
48
+
49
+ For adding novel benchmarks/datasets to the library:
50
+ * [ ] Is the task an existing benchmark in the literature?
51
+ * [ ] Have you referenced the original paper that introduced the task?
52
+ * [ ] If yes, does the original paper provide a reference implementation? If so, have you checked against the reference implementation and documented how to run such a test?
53
+
54
+
55
+ If other tasks on this dataset are already supported:
56
+ * [ ] Is the "Main" variant of this task clearly denoted?
57
+ * [ ] Have you provided a short sentence in a README on what each new variant adds / evaluates?
58
+ * [ ] Have you noted which, if any, published evaluation setups are matched by this variant?
LaViDa/eval/lmms_eval/tasks/arc/arc_challenge.yaml ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ include: arc_easy.yaml
2
+ task: arc_challenge
3
+ dataset_name: ARC-Challenge
LaViDa/eval/lmms_eval/tasks/arc/arc_easy.yaml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ tag:
2
+ - ai2_arc
3
+ task: arc_easy
4
+ dataset_path: allenai/ai2_arc
5
+ dataset_name: ARC-Easy
6
+ output_type: multiple_choice
7
+ training_split: train
8
+ validation_split: validation
9
+ test_split: test
10
+ doc_to_text: "Question: {{question}}\nAnswer:"
11
+ doc_to_target: "{{choices.label.index(answerKey)}}"
12
+ doc_to_choice: "{{choices.text}}"
13
+ should_decontaminate: true
14
+ doc_to_decontamination_query: "Question: {{question}}\nAnswer:"
15
+ metric_list:
16
+ - metric: acc
17
+ aggregation: mean
18
+ higher_is_better: true
19
+ - metric: acc_norm
20
+ aggregation: mean
21
+ higher_is_better: true
22
+ metadata:
23
+ version: 1.0
LaViDa/eval/lmms_eval/tasks/av_odyssey/av_odyssey.yaml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: AV-Odyssey/AV_Odyssey_Bench_LMMs_Eval
2
+ dataset_kwargs:
3
+ token: True
4
+ cache_dir: AV_Odyssey
5
+ video: True
6
+ task: "av_odyssey"
7
+ test_split: test
8
+ output_type: generate_until
9
+ doc_to_visual: !function utils.av_odyssey_doc_to_visual
10
+ doc_to_text: !function utils.av_odyssey_doc_to_text
11
+ doc_to_target: "answer"
12
+ generation_kwargs:
13
+ max_new_tokens: 1024
14
+ temperature: 0
15
+ top_p: 1.0
16
+ num_beams: 1
17
+ do_sample: false
18
+ # The return value of process_results will be used by metrics
19
+ process_results: !function utils.av_odyssey_process_results
20
+ # Note that the metric name can be either a registed metric function (such as the case for GQA) or a key name returned by process_results
21
+ metric_list:
22
+ - metric: av_odyssey_score
23
+ aggregation: !function utils.av_odyssey_aggregate_results
24
+ higher_is_better: true
LaViDa/eval/lmms_eval/tasks/av_odyssey/utils.py ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datetime
2
+ import os
3
+ import random
4
+ import re
5
+ from collections import defaultdict
6
+ from pathlib import Path
7
+
8
+ import numpy as np
9
+ import yaml
10
+ from loguru import logger as eval_logger
11
+ from PIL import Image
12
+
13
+ from lmms_eval.tasks._task_utils.file_utils import generate_submission_file
14
+
15
+ dir_name = os.path.dirname(os.path.abspath(__file__))
16
+
17
+ eval_type_dict = {
18
+ "Subfield": [
19
+ "Timbre",
20
+ "Tone",
21
+ "Melody",
22
+ "Space",
23
+ "Time",
24
+ "Hallucination",
25
+ "Intricacy",
26
+ ],
27
+ }
28
+
29
+ with open(Path(__file__).parent / "av_odyssey.yaml", "r") as f:
30
+ raw_data = f.readlines()
31
+ safe_data = []
32
+ for i, line in enumerate(raw_data):
33
+ # remove function definition since yaml load cannot handle it
34
+ if "!function" not in line:
35
+ safe_data.append(line)
36
+
37
+ config = yaml.safe_load("".join(safe_data))
38
+
39
+ hf_home = os.getenv("HF_HOME", "~/.cache/huggingface/")
40
+ cache_dir = os.path.join(hf_home, config["dataset_kwargs"]["cache_dir"])
41
+
42
+ question_prompt = "Answer with the option's letter from the given choices directly."
43
+
44
+
45
+ def split_media_tags(content):
46
+ pattern = r"\[(audio|video|img)(\d+)\]"
47
+
48
+ matches = list(re.finditer(pattern, content))
49
+ if not matches:
50
+ return [content]
51
+
52
+ result = []
53
+ last_end = 0
54
+
55
+ for match in matches:
56
+ if match.start() > last_end:
57
+ result.append(content[last_end : match.start()])
58
+
59
+ media_type = match.group(1)
60
+ media_num = int(match.group(2))
61
+ result.append((media_type, media_num))
62
+
63
+ last_end = match.end()
64
+
65
+ if last_end < len(content):
66
+ result.append(content[last_end:])
67
+
68
+ return result
69
+
70
+
71
+ def av_odyssey_doc_to_visual(doc):
72
+ audio_data = []
73
+ image_data = []
74
+ video_data = []
75
+ result = []
76
+
77
+ # 处理 image 类型数据
78
+ if "image" in doc["data_type"]:
79
+ for relative_path in doc["image_path"]:
80
+ abs_path = os.path.join(cache_dir, relative_path)
81
+ if os.path.exists(abs_path):
82
+ image_data.append(abs_path) # 保留路径以供后续处理
83
+ else:
84
+ print(f"Image path does not exist: {abs_path}")
85
+
86
+ # 处理 video 类型数据
87
+ elif "video" in doc["data_type"]:
88
+ for relative_path in doc["video_path"]:
89
+ abs_path = os.path.join(cache_dir, relative_path)
90
+ if os.path.exists(abs_path):
91
+ video_data.append(abs_path) # 保留路径以供后续处理
92
+ else:
93
+ print(f"Video path does not exist: {abs_path}")
94
+
95
+ # 处理 audio 类型数据
96
+ for relative_path in doc["audio_path"]:
97
+ abs_path = os.path.join(cache_dir, relative_path)
98
+ if os.path.exists(abs_path):
99
+ audio_data.append(abs_path) # 保留路径以供后续处理
100
+ else:
101
+ print(f"Audio path does not exist: {abs_path}")
102
+
103
+ question = get_text(doc)
104
+ for q in question:
105
+ if isinstance(q, str):
106
+ continue
107
+ else:
108
+ media_type, media_num = q
109
+ media_num = media_num - 1
110
+ if media_type == "audio":
111
+ result.append(audio_data[media_num])
112
+ elif media_type == "video":
113
+ result.append(video_data[media_num])
114
+ elif media_type == "img":
115
+ result.append(image_data[media_num])
116
+
117
+ return result
118
+
119
+
120
+ def get_text(doc):
121
+ question = doc["question"]
122
+ options = doc["options"]
123
+ option_text = options[0] + "\n" + options[1] + "\n" + options[2] + "\n" + options[3] + "\n"
124
+ text = question + "\n" + option_text + question_prompt
125
+ return split_media_tags(text)
126
+
127
+
128
+ def av_odyssey_doc_to_text(doc, lmms_eval_specific_kwargs=None):
129
+ text = get_text(doc)
130
+ id = 0
131
+ result = []
132
+ for t in text:
133
+ if isinstance(t, str):
134
+ result.append(t)
135
+ else:
136
+ result.append(f"<media_{id}>")
137
+ id += 1
138
+ return "".join(result)
139
+
140
+
141
+ def parse_multi_choice_response(response, all_choices, index2ans):
142
+ """
143
+ Parse the prediction from the generated response.
144
+ Return the predicted index e.g., A, B, C, D.
145
+ """
146
+ for char in [",", ".", "!", "?", ";", ":", "'"]:
147
+ response = response.strip(char)
148
+ response = " " + response + " " # add space to avoid partial match
149
+
150
+ index_ans = True
151
+ ans_with_brack = False
152
+ candidates = []
153
+ for choice in all_choices: # e.g., (A) (B) (C) (D)
154
+ if f"{choice}" in response:
155
+ candidates.append(choice)
156
+ ans_with_brack = True
157
+
158
+ if len(candidates) == 0:
159
+ for choice in all_choices: # e.g., A B C D
160
+ if f" {choice} " in response:
161
+ candidates.append(choice)
162
+
163
+ # if all above doesn't get candidates, check if the content is larger than 5 tokens and try to parse the example
164
+ if len(candidates) == 0 and len(response.split()) > 5:
165
+ for index, ans in index2ans.items():
166
+ if ans.lower() in response.lower():
167
+ candidates.append(index)
168
+ index_ans = False # it's content ans.
169
+
170
+ if len(candidates) == 0: # still not get answer, randomly choose one.
171
+ # pred_index = random.choice(all_choices)
172
+ pred_index = "A"
173
+ elif len(candidates) > 1:
174
+ start_indexes = []
175
+ if index_ans:
176
+ if ans_with_brack:
177
+ for can in candidates:
178
+ index = response.rfind(f"({can})")
179
+ start_indexes.append(index) # -1 will be ignored anyway
180
+ # start_indexes = [generated_response.index(f'({can})') for can in candidates]
181
+ else:
182
+ for can in candidates:
183
+ index = response.rfind(f" {can} ")
184
+ start_indexes.append(index)
185
+ else:
186
+ for can in candidates:
187
+ index = response.lower().rfind(index2ans[can].lower())
188
+ start_indexes.append(index)
189
+ # get the last one
190
+ pred_index = candidates[np.argmax(start_indexes)]
191
+ else: # if only one candidate, use it.
192
+ pred_index = candidates[0]
193
+
194
+ return pred_index
195
+
196
+
197
+ def av_odyssey_process_results(doc, results):
198
+ """
199
+ Args:
200
+ doc: a instance of the eval dataset
201
+ results: [pred]
202
+ Returns:
203
+ a dictionary with key: metric name (in this case av_odyssey score), value: metric value
204
+ """
205
+ pred = results[0]
206
+ options = doc["options"]
207
+ option_list = {"A": options[0][3:], "B": options[1][3:], "C": options[2][3:], "D": options[3][3:]}
208
+ answer = parse_multi_choice_response(pred, ["A", "B", "C", "D"], option_list)
209
+ gt_answer = doc["answer"]
210
+ assert answer in ["A", "B", "C", "D"]
211
+ assert gt_answer in ["A", "B", "C", "D"]
212
+ score = 1.0 if answer == gt_answer else 0.0
213
+ category = doc["subfield"]
214
+ key_name = "av_odyssey_score"
215
+ # Note: the key name here is very important. It decides which aggregation function will receive the results
216
+ # We note down the question id/category to help us aggregate the results later
217
+ return {key_name: {"question_id": doc["question_id"], "category": category, "score": score}}
218
+
219
+
220
+ def av_odyssey_aggregate_results(results):
221
+ """
222
+ Args:
223
+ results: a list of values returned by process_results
224
+ Returns:
225
+ A score
226
+ """
227
+ category2score = defaultdict(dict)
228
+ for result in results:
229
+ question_id = result["question_id"]
230
+ score = result["score"]
231
+ category = result["category"]
232
+ if question_id not in category2score[category]:
233
+ category2score[category][question_id] = []
234
+ category2score[category][question_id].append(score)
235
+
236
+ # 计算每个 category 的平均分
237
+ category_avg_scores = {}
238
+ total_score = 0
239
+ total_questions = 0
240
+
241
+ # 遍历所有 category 来计算每个 category 的平均分
242
+ for category, questions in category2score.items():
243
+ # import pdb
244
+ # pdb.set_trace()
245
+ category_total = 0 # 计算所有问题的总分
246
+ for question_id, score in questions.items():
247
+ category_total += score[0] # 累加所有问题的平均分
248
+ category_avg_scores[category] = category_total / len(questions) * 100.0 # 当前类别的平均分
249
+
250
+ total_score += category_total # 累加所有类别的问题总分
251
+ total_questions += len(questions) # 累加所有问题的数量
252
+
253
+ # 计算所有问题的平均分(按问题的总数来平均)
254
+ overall_avg_score = total_score / total_questions * 100.0
255
+
256
+ # 输出每个 category 的平均分
257
+ print("Average scores per category:")
258
+ for category, avg_score in category_avg_scores.items():
259
+ print(f"{category}: {avg_score:.2f}")
260
+
261
+ # 输出所有问题的平均分
262
+ print(f"Overall average score (across all questions): {overall_avg_score:.2f}")
263
+
264
+ return overall_avg_score
LaViDa/eval/lmms_eval/tasks/chartqa/chartqa.yaml ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/ChartQA
2
+ dataset_kwargs:
3
+ token: True
4
+ task: "chartqa"
5
+ test_split: test
6
+ output_type: generate_until
7
+ doc_to_visual: !function utils.chartqa_doc_to_visual
8
+ doc_to_text: !function utils.chartqa_doc_to_text
9
+ doc_to_target: "answer"
10
+ generation_kwargs:
11
+ max_new_tokens: 16
12
+ temperature: 0
13
+ do_sample: False
14
+ process_results: !function utils.chartqa_process_results
15
+ metric_list:
16
+ - metric: relaxed_overall
17
+ aggregation: mean
18
+ higher_is_better: true
19
+ - metric: relaxed_human_split
20
+ aggregation: mean
21
+ higher_is_better: true
22
+ - metric: relaxed_augmented_split
23
+ aggregation: mean
24
+ higher_is_better: true
25
+ metadata:
26
+ - version: 0.0
27
+ lmms_eval_specific_kwargs:
28
+ default:
29
+ pre_prompt: ""
30
+ post_prompt: "\nAnswer the question with a single word."
31
+ qwen_vl:
32
+ pre_prompt: ""
33
+ post_prompt: " Answer:"
34
+
LaViDa/eval/lmms_eval/tasks/chartqa/chartqa_lite.yaml ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/LMMs-Eval-Lite
2
+ dataset_kwargs:
3
+ token: True
4
+ task: "chartqa_lite"
5
+ dataset_name: chartqa
6
+ test_split: lite
7
+ output_type: generate_until
8
+ doc_to_visual: !function utils.chartqa_doc_to_visual
9
+ doc_to_text: !function utils.chartqa_doc_to_text
10
+ doc_to_target: "answer"
11
+ generation_kwargs:
12
+ max_new_tokens: 16
13
+ temperature: 0
14
+ do_sample: False
15
+ process_results: !function utils.chartqa_process_results
16
+ metric_list:
17
+ - metric: relaxed_overall
18
+ aggregation: mean
19
+ higher_is_better: true
20
+ - metric: relaxed_human_split
21
+ aggregation: mean
22
+ higher_is_better: true
23
+ - metric: relaxed_augmented_split
24
+ aggregation: mean
25
+ higher_is_better: true
26
+ metadata:
27
+ - version: 0.0
28
+ lmms_eval_specific_kwargs:
29
+ default:
30
+ pre_prompt: ""
31
+ post_prompt: "\nAnswer the question with a single word."
32
+ qwen_vl:
33
+ pre_prompt: ""
34
+ post_prompt: " Answer:"
35
+
LaViDa/eval/lmms_eval/tasks/chartqa/upload_chartqa.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2020 The HuggingFace Datasets Authors and the current dataset script contributor.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ import json
17
+ import os
18
+
19
+ import datasets
20
+ from PIL import Image
21
+
22
+ # Find for instance the citation on arxiv or on the dataset repo/website
23
+ _CITATION = """\
24
+ @inproceedings{masry-etal-2022-chartqa,
25
+ title = "{C}hart{QA}: A Benchmark for Question Answering about Charts with Visual and Logical Reasoning",
26
+ author = "Masry, Ahmed and
27
+ Long, Do and
28
+ Tan, Jia Qing and
29
+ Joty, Shafiq and
30
+ Hoque, Enamul",
31
+ booktitle = "Findings of the Association for Computational Linguistics: ACL 2022",
32
+ month = may,
33
+ year = "2022",
34
+ address = "Dublin, Ireland",
35
+ publisher = "Association for Computational Linguistics",
36
+ url = "https://aclanthology.org/2022.findings-acl.177",
37
+ doi = "10.18653/v1/2022.findings-acl.177",
38
+ pages = "2263--2279",
39
+ }
40
+ """
41
+ _DESCRIPTION = "A largescale benchmark covering 9.6K human-written questions as well as 23.1K questions generated from human-written chart summaries."
42
+
43
+
44
+ def get_builder_config(VERSION):
45
+ builder_config = [
46
+ datasets.BuilderConfig(
47
+ name=f"ChartQA",
48
+ version=VERSION,
49
+ description=f"ChartQA",
50
+ )
51
+ ]
52
+ return builder_config
53
+
54
+
55
+ dataset_features = {
56
+ "type": datasets.Value("string"),
57
+ "question": datasets.Value("string"),
58
+ "answer": datasets.Value("string"),
59
+ "image": datasets.Image(),
60
+ }
61
+
62
+
63
+ class ChartQA(datasets.GeneratorBasedBuilder):
64
+ VERSION = datasets.Version("1.0.0")
65
+
66
+ BUILDER_CONFIGS = get_builder_config(VERSION)
67
+
68
+ def _info(self):
69
+ features = datasets.Features(dataset_features)
70
+ return datasets.DatasetInfo(
71
+ # This is the description that will appear on the datasets page.
72
+ description=_DESCRIPTION,
73
+ # This defines the different columns of the dataset and their types
74
+ features=features, # Here we define them above because they are different between the two configurations
75
+ # If there's a common (input, target) tuple from the features, uncomment supervised_keys line below and
76
+ # specify them. They'll be used if as_supervised=True in builder.as_dataset.
77
+ # supervised_keys=("sentence", "label"),
78
+ # Homepage of the dataset for documentation
79
+ # Citation for the dataset
80
+ citation=_CITATION,
81
+ )
82
+
83
+ def _split_generators(self, dl_manager):
84
+ # If several configurations are possible (listed in BUILDER_CONFIGS), the configuration selected by the user is in self.config.name
85
+
86
+ # dl_manager is a datasets.download.DownloadManager that can be used to download and extract URLS
87
+ # It can accept any type or nested list/dict and will give back the same structure with the url replaced with path to local files.
88
+ # By default the archives will be extracted and a path to a cached folder where they are extracted is returned instead of the archive
89
+ image_path = "/home/yhzhang/ChartQA/ChartQA Dataset/test/png/"
90
+ human_annotation_path = "/home/yhzhang/ChartQA/ChartQA Dataset/test/test_human.json"
91
+ augmented_annotation_path = "/home/yhzhang/ChartQA/ChartQA Dataset/test/test_augmented.json"
92
+ return [
93
+ datasets.SplitGenerator(
94
+ name=datasets.Split.TEST,
95
+ gen_kwargs={
96
+ "human_annotation": human_annotation_path,
97
+ "augmented_annotation": augmented_annotation_path,
98
+ "images": image_path,
99
+ },
100
+ ),
101
+ ]
102
+
103
+ # method parameters are unpacked from `gen_kwargs` as given in `_split_generators`
104
+ def _generate_examples(self, human_annotation, augmented_annotation, images):
105
+ # The `key` is for legacy reasons (tfds) and is not important in itself, but must be unique for each example.
106
+ with open(human_annotation, encoding="utf-8") as f:
107
+ human_data = json.load(f)
108
+ with open(augmented_annotation, encoding="utf-8") as f:
109
+ augmented_data = json.load(f)
110
+ index = -1
111
+ for data in [human_data, augmented_data]:
112
+ for row in data["data"]:
113
+ index += 1
114
+ image_path = os.path.join(images, row["imgname"])
115
+ now_data = {}
116
+ now_data["type"] = "human_test" if data == human_data else "augmented_test"
117
+ now_data["image"] = Image.open(image_path)
118
+ now_data["question"] = row["query"]
119
+ now_data["answer"] = row["label"]
120
+ yield index, now_data
121
+
122
+
123
+ if __name__ == "__main__":
124
+ from datasets import load_dataset
125
+
126
+ data = load_dataset(
127
+ "/home/yhzhang/lmms-eval/lmms_eval/tasks/chartqa/upload_chartqa.py",
128
+ )
129
+ data.push_to_hub("lmms-lab/chartqa", private=True)
LaViDa/eval/lmms_eval/tasks/chartqa/utils.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ def chartqa_doc_to_visual(doc):
2
+ return [doc["image"].convert("RGB")]
3
+
4
+
5
+ def chartqa_doc_to_text(doc, lmms_eval_specific_kwargs):
6
+ question = doc["question"]
7
+ pre_prompt = lmms_eval_specific_kwargs["pre_prompt"]
8
+ post_prompt = lmms_eval_specific_kwargs["post_prompt"]
9
+ return f"{pre_prompt}{question}{post_prompt}"
10
+
11
+
12
+ def chartqa_process_results(doc, results):
13
+ pred = results[0]
14
+ type = doc["type"]
15
+ score = relaxed_correctness(pred, doc["answer"])
16
+ score = 1.0 if score else 0.0
17
+ return_dict = {"relaxed_overall": score}
18
+ if type == "human_test":
19
+ return_dict["relaxed_human_split"] = score
20
+ else:
21
+ return_dict["relaxed_augmented_split"] = score
22
+ return return_dict
23
+
24
+
25
+ def relaxed_correctness(prediction, target, max_relative_change: float = 0.05) -> bool:
26
+ """Calculates relaxed correctness.
27
+
28
+ The correctness tolerates certain error ratio defined by max_relative_change.
29
+ See https://arxiv.org/pdf/2203.10244.pdf, end of section 5.1:
30
+ “Following Methani et al. (2020), we use a relaxed accuracy measure for the
31
+ numeric answers to allow a minor inaccuracy that may result from the automatic
32
+ data extraction process. We consider an answer to be correct if it is within
33
+ 5% of the gold answer. For non-numeric answers, we still need an exact match
34
+ to consider an answer to be correct.”
35
+
36
+ This funcion is taken from https://github.com/QwenLM/Qwen-VL/blob/34b4c0ee7b07726371b960911f249fe61b362ca3/eval_mm/evaluate_vqa.py#L113
37
+ Args:
38
+ target: List of target string.
39
+ prediction: List of predicted string.
40
+ max_relative_change: Maximum relative change.
41
+
42
+ Returns:
43
+ Whether the prediction was correct given the specified tolerance.
44
+ """
45
+
46
+ def _to_float(text: str):
47
+ try:
48
+ if text.endswith("%"):
49
+ # Convert percentages to floats.
50
+ return float(text.rstrip("%")) / 100.0
51
+ else:
52
+ return float(text)
53
+ except ValueError:
54
+ return None
55
+
56
+ prediction_float = _to_float(prediction)
57
+ target_float = _to_float(target)
58
+ if prediction_float is not None and target_float:
59
+ relative_change = abs(prediction_float - target_float) / abs(target_float)
60
+ return relative_change <= max_relative_change
61
+ else:
62
+ return prediction.lower() == target.lower()
LaViDa/eval/lmms_eval/tasks/clotho_aqa/_default_template_yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/ClothoAQA
2
+ dataset_kwargs:
3
+ token: True
4
+ doc_to_target: "answer"
5
+ doc_to_visual: !function utils.clotho_aqa_doc_to_audio
6
+ doc_to_text: !function utils.clotho_aqa_doc_to_text
7
+
8
+ metadata:
9
+ gpt_eval_model_name: gpt-4o
10
+ version: 0.0
LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_aqa.yaml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ group: clotho_aqa
2
+ task:
3
+ - clotho_aqa_val
4
+ - clotho_aqa_test
LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_aqa_test.yaml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: "clotho_aqa_test"
2
+ dataset_name: "clotho_aqa"
3
+ test_split: clotho_aqa_test_filtered
4
+ generation_kwargs:
5
+ max_new_tokens: 8
6
+ temperature: 0
7
+ do_sample: False
8
+ lmms_eval_specific_kwargs:
9
+ default:
10
+ pre_prompt: ""
11
+ post_prompt: "\nAnswer the question using a single word only. "
12
+ metric_list:
13
+ - metric: exact_match
14
+ aggregation: mean
15
+ higher_is_better: true
16
+ ignore_case: true
17
+ ignore_punctuation: true
18
+
19
+ include: _default_template_yaml
LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_aqa_val.yaml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: "clotho_aqa_val"
2
+ dataset_name: "clotho_aqa"
3
+ test_split: clotho_aqa_val_filtered
4
+ generation_kwargs:
5
+ max_new_tokens: 8
6
+ temperature: 0
7
+ do_sample: False
8
+ lmms_eval_specific_kwargs:
9
+ default:
10
+ pre_prompt: ""
11
+ post_prompt: "\nAnswer the question using a single word only. "
12
+ metric_list:
13
+ - metric: exact_match
14
+ aggregation: mean
15
+ higher_is_better: true
16
+ ignore_case: true
17
+ ignore_punctuation: true
18
+
19
+ include: _default_template_yaml
LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_asqa_test_v2.yaml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: "clotho_asqa_test_v2"
2
+ dataset_name: "clotho_asqa_test_v2"
3
+ test_split: test
4
+ generation_kwargs:
5
+ max_new_tokens: 256
6
+ temperature: 0
7
+ do_sample: False
8
+ lmms_eval_specific_kwargs:
9
+ default:
10
+ pre_prompt: ""
11
+ post_prompt: ""
12
+ metric_list:
13
+ - metric: gpt_eval
14
+ aggregation: !function utils.clotho_aqa_v2_aggregate_results
15
+ higher_is_better: true
16
+
17
+ process_results: !function utils.clotho_aqa_v2_process_results
18
+
19
+ include: _default_template_yaml
LaViDa/eval/lmms_eval/tasks/clotho_aqa/utils.py ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import datetime
2
+ import json
3
+ import os
4
+ import re
5
+ import sys
6
+ import time
7
+ from pathlib import Path
8
+
9
+ import requests
10
+ import yaml
11
+ from loguru import logger as eval_logger
12
+
13
+ import lmms_eval.tasks._task_utils.file_utils as file_utils
14
+ from lmms_eval.filters.extraction import ExtendedRegexFilter
15
+
16
+
17
+ def clotho_aqa_doc_to_audio(doc):
18
+ return [doc["audio"]]
19
+
20
+
21
+ def clotho_aqa_doc_to_text(doc, lmms_eval_specific_kwargs):
22
+ question = doc["question"]
23
+ pre_prompt = lmms_eval_specific_kwargs["pre_prompt"]
24
+ post_prompt = lmms_eval_specific_kwargs["post_prompt"]
25
+ return f"{pre_prompt}{question}{post_prompt}"
26
+
27
+
28
+ # functions for the clotho_asqa_v2 task, need to be tested later
29
+
30
+ with open(Path(__file__).parent / "_default_template_yaml", "r") as f:
31
+ raw_data = f.readlines()
32
+ safe_data = []
33
+ for i, line in enumerate(raw_data):
34
+ # remove function definition since yaml load cannot handle it
35
+ if "!function" not in line:
36
+ safe_data.append(line)
37
+
38
+ config = yaml.safe_load("".join(safe_data))
39
+
40
+
41
+ NUM_SECONDS_TO_SLEEP = 2
42
+ GPT_EVAL_MODEL_NAME = config["metadata"]["gpt_eval_model_name"]
43
+ API_TYPE = os.getenv("API_TYPE", "azure")
44
+
45
+ if API_TYPE == "openai":
46
+ API_URL = os.getenv("OPENAI_API_URL", "https://api.openai.com/v1/chat/completions")
47
+ API_KEY = os.getenv("OPENAI_API_KEY", "YOUR_API_KEY")
48
+ headers = {
49
+ "Authorization": f"Bearer {API_KEY}",
50
+ "Content-Type": "application/json",
51
+ }
52
+
53
+ elif API_TYPE == "azure":
54
+ API_URL = os.getenv("AZURE_ENDPOINT", "https://api.cognitive.microsoft.com/sts/v1.0/issueToken")
55
+ API_KEY = os.getenv("AZURE_API_KEY", "YOUR_API_KEY")
56
+ headers = {
57
+ "api-key": API_KEY,
58
+ "Content-Type": "application/json",
59
+ }
60
+
61
+ eval_prompt = """
62
+ [Question]
63
+ {question}
64
+
65
+ [Reference Answer]
66
+ {ground_truth}
67
+
68
+ [Model Answer]
69
+ {model_response}
70
+
71
+ [Task]
72
+ Rate the model's answer based on its alignment with the reference answer, focusing on accuracy and relevance to the reference provided. Please be critical on the details.
73
+ Criteria: Assess if the model's response mirrors the reference in terms of content, accuracy, and relevance.
74
+ Score0: The answer is completely misaligned, providing incorrect or irrelevant information compared to the reference.
75
+ Score1: The answer shows minimal alignment, often misunderstanding or providing irrelevant details unrelated to the reference.
76
+ Score2: The answer recognizes the topic but diverges significantly from the reference in accuracy or relevance.
77
+ Score3: The answer aligns with the reference generally but lacks detail or precise accuracy in some aspects.
78
+ Score4: The answer is mostly accurate and relevant, closely following the reference but could be clearer or more detailed.
79
+ Score5: The answer is highly accurate, detailed, and matches the reference answer perfectly, capturing its essence and detail.
80
+
81
+ Your response should be formatted as follows:
82
+ Explanation: (Provide a concise explanation of your rating, comparing the reference answer with the model's response. "The reference answer is [XXX], while the model's answer is [YYY]. I think ...")
83
+ Rating: (int)"""
84
+
85
+
86
+ retries = 3
87
+ NUM_SECONDS_TO_SLEEP = 5
88
+
89
+
90
+ def get_eval(max_tokens: int, content: str, retries: int = retries):
91
+ global headers
92
+
93
+ messages = [
94
+ {"role": "user", "content": content},
95
+ ]
96
+
97
+ payload = {"model": GPT_EVAL_MODEL_NAME, "messages": messages, "temperature": 0.7, "max_tokens": max_tokens, "top_p": 0.95, "frequency_penalty": 0, "presence_penalty": 0, "stop": None}
98
+
99
+ for attempt in range(retries):
100
+ try:
101
+ response = requests.post(API_URL, headers=headers, json=payload, timeout=60)
102
+ response.raise_for_status()
103
+ response_data = response.json()
104
+
105
+ content = response_data["choices"][0]["message"]["content"].strip()
106
+ if content != "":
107
+ return content, response_data["model"]
108
+ break # If successful, break out of the loop
109
+
110
+ except Exception as e:
111
+ eval_logger.info(f"Attempt {attempt + 1} failed with error: {e}")
112
+ if attempt < retries: # If we have retries left, sleep and then continue to next attempt
113
+ time.sleep(NUM_SECONDS_TO_SLEEP)
114
+ else: # If this was the last attempt, log and return empty
115
+ eval_logger.error(f"All {retries} attempts failed. Last error message: {e}")
116
+ return "", ""
117
+ return "", ""
118
+
119
+
120
+ def clotho_aqa_v2_process_results(doc, result):
121
+ pred = result[0]
122
+ ground_truth_str = doc["answer"]
123
+ content = eval_prompt.format(model_response=pred, ground_truth=ground_truth_str, question=doc["question"])
124
+ eval_answer, model_name = get_eval(max_tokens=1024, content=content)
125
+ return {
126
+ "gpt_eval": {"eval_answer": eval_answer, "model_name": model_name},
127
+ }
128
+
129
+
130
+ def clotho_aqa_v2_aggregate_results(results):
131
+ score = 0
132
+ for result in results:
133
+ eval_answer = result["eval_answer"]
134
+ eval_score = re.search(r"([0-5])", eval_answer).group(1)
135
+ try:
136
+ eval_score = float(eval_score)
137
+ except Exception as e:
138
+ eval_logger.error(f"Error parsing eval_score: {e}")
139
+ eval_score = 0.0
140
+ score += eval_score
141
+
142
+ return score / len(results) * 20
LaViDa/eval/lmms_eval/tasks/coco_cap/coco2014_cap.yaml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ group : coco2014_cap
2
+ task:
3
+ - coco2014_cap_val
4
+ - coco2014_cap_test
LaViDa/eval/lmms_eval/tasks/coco_cap/coco2014_cap_test.yaml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/COCO-Caption
2
+ dataset_kwargs:
3
+ token: True
4
+ task : "coco2014_cap_test"
5
+ group : "coco_caption"
6
+ test_split: test
7
+ output_type: generate_until
8
+ doc_to_visual: !function utils.coco_doc_to_visual
9
+ doc_to_text: "Provide a one-sentence caption for the provided image."
10
+ doc_to_target: "answer"
11
+ generation_kwargs:
12
+ max_new_tokens: 128
13
+ temperature: 0
14
+ top_p: 1.0
15
+ num_beams: 1
16
+ do_sample: false
17
+ process_results: !function utils.coco_test_process_result
18
+ # Note that the metric name can be either a registed metric function (such as the case for GQA) or a key name returned by process_results
19
+ metric_list:
20
+ - metric: coco_passthrough
21
+ aggregation : !function utils.coco_test_aggregation_result
22
+ higher_is_better : true
23
+ metadata:
24
+ - version: 0.0
LaViDa/eval/lmms_eval/tasks/coco_cap/coco2014_cap_val.yaml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/COCO-Caption
2
+ dataset_kwargs:
3
+ token: True
4
+ task: "coco2014_cap_val"
5
+ group : "coco_caption"
6
+ test_split: val
7
+ output_type: generate_until
8
+ doc_to_visual: !function utils.coco_doc_to_visual
9
+ doc_to_text: "Provide a one-sentence caption for the provided image."
10
+ doc_to_target: "answer"
11
+ generation_kwargs:
12
+ max_new_tokens: 32
13
+ temperature: 0
14
+ top_p: 1.0
15
+ num_beams: 1
16
+ do_sample: false
17
+ process_results: !function utils.coco_process_result
18
+ # Note that the metric name can be either a registed metric function (such as the case for GQA) or a key name returned by process_results
19
+ metric_list:
20
+ - metric: coco_Bleu_4
21
+ aggregation : !function utils.coco_bleu4
22
+ higher_is_better : true
23
+ - metric: coco_Bleu_3
24
+ aggregation : !function utils.coco_bleu3
25
+ higher_is_better : true
26
+ - metric: coco_Bleu_2
27
+ aggregation : !function utils.coco_bleu2
28
+ higher_is_better : true
29
+ - metric: coco_Bleu_1
30
+ aggregation : !function utils.coco_bleu1
31
+ higher_is_better : true
32
+ - metric: coco_METEOR
33
+ aggregation : !function utils.coco_meteor
34
+ higher_is_better : true
35
+ - metric: coco_ROUGE_L
36
+ aggregation : !function utils.coco_rougel
37
+ higher_is_better : true
38
+ - metric: coco_CIDEr
39
+ aggregation : !function utils.coco_cider
40
+ higher_is_better : true
41
+ #- metric: coco_SPICE
42
+ # aggregation : !function utils.coco_spice
43
+ # higher_is_better : true
44
+ metadata:
45
+ - version: 0.0
LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap.yaml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ group : coco2017_cap
2
+ task:
3
+ - coco2017_cap_val
4
+ - coco2017_cap_test
LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap_test.yaml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/COCO-Caption2017
2
+ dataset_kwargs:
3
+ token: True
4
+ task : "coco2017_cap_test"
5
+ group : "coco_caption2017"
6
+ test_split: test
7
+ output_type: generate_until
8
+ doc_to_visual: !function utils.coco_doc_to_visual
9
+ doc_to_text: !function utils.coco_doc_to_text
10
+ doc_to_target: "answer"
11
+ generation_kwargs:
12
+ max_new_tokens: 128
13
+ temperature: 0
14
+ top_p: 1.0
15
+ num_beams: 1
16
+ do_sample: false
17
+ process_results: !function utils.coco_test_process_result
18
+ # Note that the metric name can be either a registed metric function (such as the case for GQA) or a key name returned by process_results
19
+ metric_list:
20
+ - metric: coco_passthrough
21
+ aggregation : !function utils.coco_test_aggregation_result
22
+ higher_is_better : true
23
+ metadata:
24
+ - version: 0.0
LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap_val.yaml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/COCO-Caption2017
2
+ dataset_kwargs:
3
+ token: True
4
+ task: "coco2017_cap_val"
5
+ group : "coco_caption2017"
6
+ test_split: val
7
+ output_type: generate_until
8
+ doc_to_visual: !function utils.coco_doc_to_visual
9
+ doc_to_text: !function utils.coco_doc_to_text
10
+ doc_to_target: "answer"
11
+ generation_kwargs:
12
+ max_new_tokens: 64
13
+ temperature: 0
14
+ top_p: 1.0
15
+ num_beams: 1
16
+ do_sample: false
17
+ process_results: !function utils.coco_process_result
18
+ # Note that the metric name can be either a registed metric function (such as the case for GQA) or a key name returned by process_results
19
+ metric_list:
20
+ - metric: coco_Bleu_4
21
+ aggregation : !function utils.coco_bleu4
22
+ higher_is_better : true
23
+ - metric: coco_Bleu_3
24
+ aggregation : !function utils.coco_bleu3
25
+ higher_is_better : true
26
+ - metric: coco_Bleu_2
27
+ aggregation : !function utils.coco_bleu2
28
+ higher_is_better : true
29
+ - metric: coco_Bleu_1
30
+ aggregation : !function utils.coco_bleu1
31
+ higher_is_better : true
32
+ - metric: coco_METEOR
33
+ aggregation : !function utils.coco_meteor
34
+ higher_is_better : true
35
+ - metric: coco_ROUGE_L
36
+ aggregation : !function utils.coco_rougel
37
+ higher_is_better : true
38
+ - metric: coco_CIDEr
39
+ aggregation : !function utils.coco_cider
40
+ higher_is_better : true
41
+ #- metric: coco_SPICE
42
+ # aggregation : !function utils.coco_spice
43
+ # higher_is_better : true
44
+ metadata:
45
+ - version: 0.0
LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap_val_lite.yaml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/LMMs-Eval-Lite
2
+ dataset_kwargs:
3
+ token: True
4
+ task: "coco2017_cap_val_lite"
5
+ dataset_name: coco2017_cap_val
6
+ test_split: lite
7
+ output_type: generate_until
8
+ doc_to_visual: !function utils.coco_doc_to_visual
9
+ doc_to_text: !function utils.coco_doc_to_text
10
+ doc_to_target: "answer"
11
+ generation_kwargs:
12
+ max_new_tokens: 32
13
+ temperature: 0
14
+ top_p: 1.0
15
+ num_beams: 1
16
+ do_sample: false
17
+ process_results: !function utils.coco_process_result
18
+ # Note that the metric name can be either a registed metric function (such as the case for GQA) or a key name returned by process_results
19
+ metric_list:
20
+ - metric: coco_Bleu_4
21
+ aggregation : !function utils.coco_bleu4
22
+ higher_is_better : true
23
+ - metric: coco_Bleu_3
24
+ aggregation : !function utils.coco_bleu3
25
+ higher_is_better : true
26
+ - metric: coco_Bleu_2
27
+ aggregation : !function utils.coco_bleu2
28
+ higher_is_better : true
29
+ - metric: coco_Bleu_1
30
+ aggregation : !function utils.coco_bleu1
31
+ higher_is_better : true
32
+ - metric: coco_METEOR
33
+ aggregation : !function utils.coco_meteor
34
+ higher_is_better : true
35
+ - metric: coco_ROUGE_L
36
+ aggregation : !function utils.coco_rougel
37
+ higher_is_better : true
38
+ - metric: coco_CIDEr
39
+ aggregation : !function utils.coco_cider
40
+ higher_is_better : true
41
+ #- metric: coco_SPICE
42
+ # aggregation : !function utils.coco_spice
43
+ # higher_is_better : true
44
+ metadata:
45
+ - version: 0.0
LaViDa/eval/lmms_eval/tasks/coco_cap/coco_cap.yaml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ group : coco_cap
2
+ task:
3
+ - coco2014_cap_val
4
+ - coco2014_cap_test
5
+ - coco2017_cap_val
6
+ - coco2017_cap_test
LaViDa/eval/lmms_eval/tasks/coco_cap/utils.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+
4
+ from loguru import logger as eval_logger
5
+ from pycocoevalcap.eval import Bleu, Cider, COCOEvalCap, Meteor, Rouge, Spice
6
+ from pycocoevalcap.tokenizer.ptbtokenizer import PTBTokenizer
7
+ from pycocotools.coco import COCO
8
+
9
+ from lmms_eval.tasks._task_utils.file_utils import generate_submission_file
10
+
11
+ dir_name = os.path.dirname(os.path.abspath(__file__))
12
+
13
+ COCO_METRICS = ["Bleu_4", "Bleu_3", "Bleu_2", "Bleu_1", "METEOR", "ROUGE_L", "CIDEr"] # , "SPICE"]
14
+
15
+
16
+ def coco_doc_to_visual(doc):
17
+ return [doc["image"].convert("RGB")]
18
+
19
+
20
+ def coco_doc_to_text(doc):
21
+ return f"Provide a one-sentence caption for the provided image."
22
+
23
+
24
+ def coco_process_result(doc, result):
25
+ """
26
+ Args:
27
+ doc: a instance of the eval dataset
28
+ results: [pred]
29
+ Returns:
30
+ a dictionary with key: metric name, value: metric value
31
+ """
32
+ pred = result[0] if len(result) > 0 else ""
33
+ question_id = doc["question_id"]
34
+ # The question id in our dataset is the image file itself
35
+ image_id = int(question_id.split("_")[-1].split(".")[0])
36
+ id = doc["id"]
37
+
38
+ data_dict = {"answer": doc["answer"], "pred": pred, "image_id": image_id, "id": id}
39
+
40
+ return {f"coco_{metric}": data_dict for metric in COCO_METRICS}
41
+
42
+
43
+ def coco_aggregation_result(results, metric, args):
44
+ scorers = [(Bleu(4), "Bleu_1"), (Bleu(4), "Bleu_2"), (Bleu(4), "Bleu_3"), (Bleu(4), "Bleu_4"), (Meteor(), "METEOR"), (Rouge(), "ROUGE_L"), (Cider(), "CIDEr")] # , (Spice(), "SPICE")]
45
+ scorers_dict = {s[1]: s for s in scorers}
46
+
47
+ stored_results = []
48
+ # In order to make the coco eval tools to successfully create index
49
+ # We need at least two dict in the dataset
50
+ # 'annotation' and 'images'
51
+ # 'annotation' exactly reproduce the original annotation
52
+ # 'images' however only need the image id which is contained in the file name
53
+ dataset = {"annotations": [], "images": []}
54
+ idx = 0
55
+ for result in results:
56
+ stored_results.append({"image_id": int(result["image_id"]), "caption": result["pred"]})
57
+ for a in result["answer"]:
58
+ dataset["annotations"].append({"image_id": int(result["image_id"]), "caption": a, "id": idx})
59
+ idx += 1
60
+ dataset["images"].append({"id": result["image_id"]})
61
+
62
+ coco = COCO()
63
+ # Manually create index here
64
+ coco.dataset = dataset
65
+ coco.createIndex()
66
+
67
+ coco_result = coco.loadRes(stored_results)
68
+ coco_eval = COCOEvalCap(coco, coco_result)
69
+
70
+ imgIds = coco_eval.params["image_id"]
71
+ gts = {}
72
+ res = {}
73
+ for imgId in imgIds:
74
+ gts[imgId] = coco_eval.coco.imgToAnns[imgId]
75
+ res[imgId] = coco_eval.cocoRes.imgToAnns[imgId]
76
+
77
+ eval_logger.info("tokenization...")
78
+ tokenizer = PTBTokenizer()
79
+ gts = tokenizer.tokenize(gts)
80
+ res = tokenizer.tokenize(res)
81
+
82
+ eval_logger.info(f"Computing {metric} scores...")
83
+
84
+ score, scores = scorers_dict[metric][0].compute_score(gts, res)
85
+ # When metric is one of the Bleu, score will be a list
86
+ if type(score) == list:
87
+ n = int(metric.split("_")[-1])
88
+ score = score[n - 1]
89
+
90
+ path = generate_submission_file("coco_captions_val2014_alg_results.json", args)
91
+ if not os.path.exists(path):
92
+ eval_logger.info("Storing prediction that can be submitted to the server ...")
93
+ with open(path, "w") as f:
94
+ json.dump(stored_results, f, indent=4)
95
+
96
+ return score
97
+
98
+
99
+ def coco_bleu4(results, args):
100
+ return coco_aggregation_result(results, "Bleu_4", args)
101
+
102
+
103
+ def coco_bleu3(results, args):
104
+ return coco_aggregation_result(results, "Bleu_3", args)
105
+
106
+
107
+ def coco_bleu2(results, args):
108
+ return coco_aggregation_result(results, "Bleu_2", args)
109
+
110
+
111
+ def coco_bleu1(results, args):
112
+ return coco_aggregation_result(results, "Bleu_1", args)
113
+
114
+
115
+ def coco_meteor(results, args):
116
+ return coco_aggregation_result(results, "METEOR", args)
117
+
118
+
119
+ def coco_rougel(results, args):
120
+ return coco_aggregation_result(results, "ROUGE_L", args)
121
+
122
+
123
+ def coco_cider(results, args):
124
+ return coco_aggregation_result(results, "CIDEr", args)
125
+
126
+
127
+ def coco_spice(results, args):
128
+ return coco_aggregation_result(results, "SPICE", args)
129
+
130
+
131
+ def coco_test_process_result(doc, result):
132
+ """
133
+ Args:
134
+ doc: a instance of the eval dataset
135
+ results: [pred]
136
+ Returns:
137
+ a dictionary with key: metric name (in this case coco_passthrough), value: metric value
138
+ """
139
+ question_id = doc["question_id"]
140
+ # The question id in our dataset is the image file itself
141
+ image_id = int(question_id.split("_")[-1].split(".")[0])
142
+ return {"coco_passthrough": {"pred": result, "image_id": image_id}}
143
+
144
+
145
+ def coco_test_aggregation_result(results, args):
146
+ stored_results = []
147
+ for result in results:
148
+ stored_results.append({"image_id": int(result["image_id"]), "caption": result["pred"]})
149
+
150
+ path = generate_submission_file("coco_captions_test2014_alg_results.json", args)
151
+ eval_logger.info("Storing prediction that can be submitted to the server ...")
152
+ with open(path, "w") as f:
153
+ json.dump(stored_results, f, indent=4)
154
+
155
+ eval_logger.info(f"Your test result has been stored in to {path}. Make sure you also have the val result stored to submit to the server on https://codalab.lisn.upsaclay.fr/competitions/7404#participate.")
LaViDa/eval/lmms_eval/tasks/common_voice_15/_default_template_yaml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/common_voice_15
2
+ dataset_kwargs:
3
+ token: True
4
+ test_split: test
5
+ output_type: generate_until
6
+ doc_to_visual: !function utils.common_voice_15_doc_to_audio
7
+ doc_to_text: !function utils.common_voice_15_doc_to_text
8
+ doc_to_target: "sentence"
9
+ generation_kwargs:
10
+ max_new_tokens: 256
11
+ temperature: 0
12
+ top_p: 1.0
13
+ num_beams: 1
14
+ do_sample: false
15
+ process_results: !function utils.common_voice_15_process_result
16
+ metric_list:
17
+ - metric: wer
18
+ aggregation : !function utils.common_voice_15_wer
19
+ higher_is_better : false
20
+ metadata:
21
+ - version: 0.0
LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15.yaml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ group: common_voice_15
2
+ task:
3
+ - common_voice_15_zh-CN
4
+ - common_voice_15_en
5
+ - common_voice_15_fr
LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15_en.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ task : "common_voice_15_en"
2
+ dataset_name: en
3
+ lmms_eval_specific_kwargs:
4
+ default:
5
+ pre_prompt: ""
6
+ post_prompt: ""
7
+ qwen2_audio:
8
+ pre_prompt: ""
9
+ post_prompt: " <|en|>"
10
+ include : _default_template_yaml
LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15_fr.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ task : "common_voice_15_fr"
2
+ dataset_name: fr
3
+ lmms_eval_specific_kwargs:
4
+ default:
5
+ pre_prompt: ""
6
+ post_prompt: ""
7
+ qwen2_audio:
8
+ pre_prompt: ""
9
+ post_prompt: " <|fr|>"
10
+ include : _default_template_yaml
LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15_zh-CN.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ task : "common_voice_15_zh-CN"
2
+ dataset_name: zh-CN
3
+ lmms_eval_specific_kwargs:
4
+ default:
5
+ pre_prompt: ""
6
+ post_prompt: ""
7
+ qwen2_audio:
8
+ pre_prompt: ""
9
+ post_prompt: " <|zh|>"
10
+ include : _default_template_yaml
LaViDa/eval/lmms_eval/tasks/common_voice_15/utils.py ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import unicodedata
4
+
5
+ import editdistance as ed
6
+ import zhconv
7
+
8
+ from lmms_eval.tasks.librispeech.cn_tn import TextNorm
9
+ from lmms_eval.tasks.librispeech.whisper_normalizer.basic import BasicTextNormalizer
10
+ from lmms_eval.tasks.librispeech.whisper_normalizer.english import EnglishTextNormalizer
11
+
12
+ # ImportError: To support decoding audio files, please install 'librosa' and 'soundfile'.
13
+ english_normalizer = EnglishTextNormalizer()
14
+ chinese_normalizer = TextNorm(
15
+ to_banjiao=False,
16
+ to_upper=False,
17
+ to_lower=False,
18
+ remove_fillers=False,
19
+ remove_erhua=False,
20
+ check_chars=False,
21
+ remove_space=False,
22
+ cc_mode="",
23
+ )
24
+ basic_normalizer = BasicTextNormalizer()
25
+
26
+ dir_name = os.path.dirname(os.path.abspath(__file__))
27
+
28
+
29
+ def common_voice_15_doc_to_audio(doc):
30
+ return [doc["audio"]]
31
+
32
+
33
+ def common_voice_15_doc_to_text(doc, lmms_eval_specific_kwargs):
34
+ pre_prompt = lmms_eval_specific_kwargs["pre_prompt"]
35
+ post_prompt = lmms_eval_specific_kwargs["post_prompt"]
36
+ return f"{pre_prompt}Please recognize the speech and only output the recognized content:{post_prompt}"
37
+
38
+
39
+ def common_voice_15_process_result(doc, result):
40
+ pred = result[0] if len(result) > 0 else ""
41
+
42
+ gt = doc["sentence"]
43
+ source = doc["path"]
44
+ task = doc["locale"]
45
+
46
+ data_dict = {"gt": gt, "pred": pred, "source": source, "task": task}
47
+
48
+ return {"wer": data_dict}
49
+
50
+
51
+ PUNCS = "!,.?;:"
52
+
53
+
54
+ def remove_sp(text, language):
55
+ gt = re.sub(r"<\|.*?\|>", " ", text)
56
+ gt = re.sub(rf"\s+", r" ", gt) # Replace consecutive spaces in the text with a single space.
57
+ gt = re.sub(f" ?([{PUNCS}])", r"\1", gt)
58
+ gt = gt.lstrip(" ")
59
+ if language == "zh-CN":
60
+ gt = re.sub(rf"\s+", r"", gt)
61
+ return gt
62
+
63
+
64
+ class EvaluationTokenizer(object):
65
+ """A generic evaluation-time tokenizer, which leverages built-in tokenizers
66
+ in sacreBLEU (https://github.com/mjpost/sacrebleu). It additionally provides
67
+ lowercasing, punctuation removal and character tokenization, which are
68
+ applied after sacreBLEU tokenization.
69
+
70
+ Args:
71
+ tokenizer_type (str): the type of sacreBLEU tokenizer to apply.
72
+ lowercase (bool): lowercase the text.
73
+ punctuation_removal (bool): remove punctuation (based on unicode
74
+ category) from text.
75
+ character_tokenization (bool): tokenize the text to characters.
76
+ """
77
+
78
+ SPACE = chr(32)
79
+ SPACE_ESCAPE = chr(9601)
80
+ # ALL_TOKENIZER_TYPES = ChoiceEnum(["none", "13a", "intl", "zh", "ja-mecab"])
81
+
82
+ def __init__(
83
+ self,
84
+ tokenizer_type: str = "13a",
85
+ lowercase: bool = False,
86
+ punctuation_removal: bool = False,
87
+ character_tokenization: bool = False,
88
+ ):
89
+ from sacrebleu.tokenizers.tokenizer_13a import Tokenizer13a
90
+ from sacrebleu.tokenizers.tokenizer_char import TokenizerChar
91
+ from sacrebleu.tokenizers.tokenizer_intl import TokenizerV14International
92
+ from sacrebleu.tokenizers.tokenizer_ja_mecab import TokenizerJaMecab
93
+ from sacrebleu.tokenizers.tokenizer_none import NoneTokenizer
94
+ from sacrebleu.tokenizers.tokenizer_zh import TokenizerZh
95
+
96
+ TOKENIZERS = {
97
+ "none": NoneTokenizer,
98
+ "13a": Tokenizer13a,
99
+ "intl": TokenizerV14International,
100
+ "zh": TokenizerZh,
101
+ "ja-mecab": TokenizerJaMecab,
102
+ "char": TokenizerChar,
103
+ }
104
+
105
+ assert tokenizer_type in TOKENIZERS, f"{tokenizer_type}, {TOKENIZERS}"
106
+ self.lowercase = lowercase
107
+ self.punctuation_removal = punctuation_removal
108
+ self.character_tokenization = character_tokenization
109
+ self.tokenizer = TOKENIZERS[tokenizer_type]
110
+ # self.tokenizer = tokenizer_none
111
+
112
+ @classmethod
113
+ def remove_punctuation(cls, sent: str):
114
+ """Remove punctuation based on Unicode category."""
115
+ return cls.SPACE.join(t for t in sent.split(cls.SPACE) if not all(unicodedata.category(c)[0] == "P" for c in t))
116
+
117
+ def tokenize(self, sent: str):
118
+ tokenized = self.tokenizer()(sent)
119
+
120
+ if self.punctuation_removal:
121
+ tokenized = self.remove_punctuation(tokenized)
122
+
123
+ if self.character_tokenization:
124
+ tokenized = self.SPACE.join(list(tokenized.replace(self.SPACE, self.SPACE_ESCAPE)))
125
+
126
+ if self.lowercase:
127
+ tokenized = tokenized.lower()
128
+
129
+ return tokenized
130
+
131
+
132
+ def compute_wer(refs, hyps, language):
133
+ distance = 0
134
+ ref_length = 0
135
+ tokenizer = EvaluationTokenizer(
136
+ tokenizer_type="none",
137
+ lowercase=True,
138
+ punctuation_removal=True,
139
+ character_tokenization=False,
140
+ )
141
+ for i in range(len(refs)):
142
+ ref = refs[i]
143
+ pred = hyps[i]
144
+ if language in ["yue"]:
145
+ ref = zhconv.convert(ref, "zh-cn")
146
+ pred = zhconv.convert(pred, "zh-cn")
147
+ if language in ["en"]:
148
+ ref = english_normalizer(ref)
149
+ pred = english_normalizer(pred)
150
+ if language in ["zh-CN"]:
151
+ ref = chinese_normalizer(ref)
152
+ pred = chinese_normalizer(pred)
153
+ else:
154
+ ref = basic_normalizer(ref)
155
+ pred = basic_normalizer(pred)
156
+ ref_items = tokenizer.tokenize(ref).split()
157
+ pred_items = tokenizer.tokenize(pred).split()
158
+ if language in ["zh-CN", "yue"]:
159
+ ref_items = [x for x in "".join(ref_items)]
160
+ pred_items = [x for x in "".join(pred_items)]
161
+ if i == 0:
162
+ print(f"ref: {ref}")
163
+ print(f"pred: {pred}")
164
+ print(f"ref_items:\n{ref_items}\n{len(ref_items)}\n{ref_items[0]}")
165
+ print(f"pred_items:\n{pred_items}\n{len(ref_items)}\n{ref_items[0]}")
166
+ distance += ed.eval(ref_items, pred_items)
167
+ ref_length += len(ref_items)
168
+ return distance / ref_length
169
+
170
+
171
+ def common_voice_15_wer(results, args):
172
+ refs, hyps = [], []
173
+ for result in results:
174
+ lan = result["task"]
175
+ gt = result["gt"]
176
+ response = result["pred"]
177
+ gt = remove_sp(gt, lan)
178
+ response = remove_sp(response, lan)
179
+ refs.append(gt)
180
+ hyps.append(response)
181
+ wer = compute_wer(refs, hyps, lan)
182
+ return wer * 100
LaViDa/eval/lmms_eval/tasks/conbench/conbench.yaml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: ConBench/ConBench_D
2
+ dataset_kwargs:
3
+ token: True
4
+ task: "ConBench"
5
+ test_split: test
6
+ output_type: generate_until
7
+ doc_to_visual: !function utils.conbench_doc_to_visual
8
+ doc_to_text: !function utils.conbench_doc_to_text
9
+ doc_to_target: "answer"
10
+ generation_kwargs:
11
+ max_new_tokens: 1024
12
+ temperature: 0.2
13
+ top_p: 0
14
+ num_beams: 1
15
+ do_sample: True
16
+ # The return value of process_results will be used by metrics
17
+ process_results: !function utils.conbench_process_results
18
+ # Note that the metric name can be either a registed metric function (such as the case for GQA) or a key name returned by process_results
19
+ metric_list:
20
+ - metric: ConScore_D
21
+ aggregation: !function utils.conbench_aggregate_results
22
+ higher_is_better: true
23
+ metadata:
24
+ - version: 0.0
LaViDa/eval/lmms_eval/tasks/conbench/utils.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from collections import defaultdict
3
+
4
+ from anls import anls_score
5
+ from loguru import logger as eval_logger
6
+
7
+ dir_name = os.path.dirname(os.path.abspath(__file__))
8
+
9
+ # 19 classes
10
+ eval_type_dict = {
11
+ "Sensation": ["count", "color", "scene", "poster", "attribute_recognition", "ocr", "position"],
12
+ "Cognition": ["calculation", "code", "translation", "math", "cross_instance_reason", "attribute_reason"],
13
+ "Knowledge": ["celebrity", "chemistry", "physics", "biology", "landmark", "artwork"],
14
+ }
15
+
16
+
17
+ def conbench_doc_to_visual(doc):
18
+ return [doc["image"].convert("RGB")]
19
+
20
+
21
+ def conbench_doc_to_text(doc):
22
+ question = doc["question"].strip()
23
+ return question
24
+
25
+
26
+ def parse_pred_ans_NY(pred_ans):
27
+ pred_label = None
28
+ if pred_ans in ["yes", "no"]:
29
+ pred_label = pred_ans
30
+ else:
31
+ prefix_pred_ans = pred_ans[:4]
32
+
33
+ if "yes" in prefix_pred_ans:
34
+ pred_label = "yes"
35
+ elif "no" in prefix_pred_ans:
36
+ pred_label = "no"
37
+ else:
38
+ pred_label = "other"
39
+ return pred_label
40
+
41
+
42
+ def parse_pred_ans_choice(pred_ans):
43
+ return pred_ans.replace(" ", "")[0]
44
+
45
+
46
+ def conbench_process_results(doc, results):
47
+ """
48
+ Args:
49
+ doc: a instance of the eval dataset
50
+ results: [pred]
51
+ Returns:
52
+ a dictionary with key: metric name (in this case mme score), value: metric value
53
+ """
54
+ pred = results[0]
55
+ pred = pred.replace("\n", "").lower()
56
+ # parser
57
+ if doc["question_field"] == "N/Y":
58
+ pred_ans = parse_pred_ans_NY(pred)
59
+ elif doc["question_field"] == "Choices":
60
+ pred_ans = parse_pred_ans_choice(pred)
61
+ else:
62
+ pred_ans = pred
63
+
64
+ gt_ans = doc["answer"].lower()
65
+
66
+ # score
67
+ score = 1 if (doc["question_field"] == "Q/A" and anls_score(prediction=pred_ans, gold_labels=[gt_ans], threshold=0.95) >= 0.4) or (gt_ans == pred_ans) else 0
68
+ # Note: the key name here is very important. It decides which aggregation function will receive the results
69
+ # We note down the question id/category to help us aggregate the results later
70
+ return {"ConScore_D": {"image_id": doc["image_id"], "question_field": doc["question_field"], "score": score}}
71
+
72
+
73
+ def conbench_aggregate_results(results):
74
+ """
75
+ Args:
76
+ results: a list of values returned by process_results
77
+ Returns:
78
+ A score
79
+ """
80
+ summary = defaultdict(dict)
81
+ for result in results:
82
+ image_id = result["image_id"]
83
+ score = result["score"]
84
+ if image_id not in summary.keys():
85
+ summary[image_id] = 0
86
+ summary[image_id] += score
87
+
88
+ cnt_con = 0
89
+ for image_id, score in summary.items():
90
+ if score == 3:
91
+ cnt_con += 1
92
+
93
+ print("Consistency Cases are ", cnt_con)
94
+ cnt_con = cnt_con / (len(results) / 3)
95
+ eval_logger.info(f"ConScore_D: {cnt_con:.2f}")
96
+ return cnt_con
LaViDa/eval/lmms_eval/tasks/covost2/_default_template_en_zh_yaml ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/covost2_en-zh
2
+ dataset_name: en_zh
3
+ dataset_kwargs:
4
+ token: True
5
+ output_type: generate_until
6
+ doc_to_visual: !function utils.covost2_doc_to_audio
7
+ doc_to_text: !function utils.covost2_doc_to_text
8
+ doc_to_target: "translation"
9
+ generation_kwargs:
10
+ max_new_tokens: 256
11
+ temperature: 0
12
+ top_p: 1.0
13
+ num_beams: 1
14
+ do_sample: false
15
+ process_results: !function utils.covost2_en_zh_process_result
16
+ metric_list:
17
+ - metric: bleu
18
+ aggregation: !function utils.covost2_bleu
19
+ higher_is_better: true
20
+ metadata:
21
+ - version: 0.0
22
+ lmms_eval_specific_kwargs:
23
+ default:
24
+ pre_prompt: "Translate the speech into Chinese and only output the translation:"
25
+ post_prompt: ""
26
+ qwen2_audio:
27
+ pre_prompt: "Translate the speech into Chinese and only output the translation: <|en|>"
28
+ post_prompt: ""
LaViDa/eval/lmms_eval/tasks/covost2/_default_template_zh_en_yaml ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dataset_path: lmms-lab/covost2
2
+ dataset_name: zh_en
3
+ dataset_kwargs:
4
+ token: True
5
+ output_type: generate_until
6
+ doc_to_visual: !function utils.covost2_doc_to_audio
7
+ doc_to_text: !function utils.covost2_doc_to_text
8
+ doc_to_target: "gt"
9
+ generation_kwargs:
10
+ max_new_tokens: 256
11
+ temperature: 0
12
+ top_p: 1.0
13
+ num_beams: 1
14
+ do_sample: false
15
+ process_results: !function utils.covost2_zh_en_process_result
16
+ metric_list:
17
+ - metric: bleu
18
+ aggregation: !function utils.covost2_bleu_en
19
+ higher_is_better: true
20
+ metadata:
21
+ - version: 0.0
22
+ lmms_eval_specific_kwargs:
23
+ default:
24
+ pre_prompt: "Translate the speech into English and only output the translation:"
25
+ post_prompt: ""
26
+ qwen2_audio:
27
+ pre_prompt: "Translate the speech into English and only output the translation: <|zh|>"
28
+ post_prompt: ""
LaViDa/eval/lmms_eval/tasks/covost2/covost2.yaml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ group: covost2
2
+ task:
3
+ - covost2_en_zh
4
+ - covost2_zh_en
LaViDa/eval/lmms_eval/tasks/covost2/covost2_en_zh.yaml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ group: covost2_en_zh
2
+ task:
3
+ - covost2_en_zh_test
4
+ - covost2_en_zh_dev
LaViDa/eval/lmms_eval/tasks/covost2/covost2_en_zh_dev.yaml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ task: "covost2_en_zh_dev"
2
+ include: _default_template_en_zh_yaml
3
+ dataset_path: lmms-lab/covost2_en-zh
4
+ dataset_name: en_zh
5
+ test_split: dev
6
+ lmms_eval_specific_kwargs:
7
+ default:
8
+ pre_prompt: "Translate the speech into Chinese and only output the translation:"
9
+ post_prompt: ""
10
+ qwen2_audio:
11
+ pre_prompt: "Translate the speech into Chinese and only output the translation: <|en|>"
12
+ post_prompt: ""