Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- LaViDa/eval/lmms_eval/tasks/ai2d/ai2d.yaml +55 -0
- LaViDa/eval/lmms_eval/tasks/ai2d/ai2d_lite.yaml +56 -0
- LaViDa/eval/lmms_eval/tasks/air_bench/_default_template_yaml +7 -0
- LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat.yaml +6 -0
- LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_mixed.yaml +25 -0
- LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_music.yaml +25 -0
- LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_sound.yaml +25 -0
- LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_chat_speech.yaml +25 -0
- LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation.yaml +5 -0
- LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation_music.yaml +26 -0
- LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation_sound.yaml +26 -0
- LaViDa/eval/lmms_eval/tasks/air_bench/air_bench_foundation_speech.yaml +26 -0
- LaViDa/eval/lmms_eval/tasks/air_bench/utils.py +281 -0
- LaViDa/eval/lmms_eval/tasks/arc/README.md +58 -0
- LaViDa/eval/lmms_eval/tasks/arc/arc_challenge.yaml +3 -0
- LaViDa/eval/lmms_eval/tasks/arc/arc_easy.yaml +23 -0
- LaViDa/eval/lmms_eval/tasks/av_odyssey/av_odyssey.yaml +24 -0
- LaViDa/eval/lmms_eval/tasks/av_odyssey/utils.py +264 -0
- LaViDa/eval/lmms_eval/tasks/chartqa/chartqa.yaml +34 -0
- LaViDa/eval/lmms_eval/tasks/chartqa/chartqa_lite.yaml +35 -0
- LaViDa/eval/lmms_eval/tasks/chartqa/upload_chartqa.py +129 -0
- LaViDa/eval/lmms_eval/tasks/chartqa/utils.py +62 -0
- LaViDa/eval/lmms_eval/tasks/clotho_aqa/_default_template_yaml +10 -0
- LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_aqa.yaml +4 -0
- LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_aqa_test.yaml +19 -0
- LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_aqa_val.yaml +19 -0
- LaViDa/eval/lmms_eval/tasks/clotho_aqa/clotho_asqa_test_v2.yaml +19 -0
- LaViDa/eval/lmms_eval/tasks/clotho_aqa/utils.py +142 -0
- LaViDa/eval/lmms_eval/tasks/coco_cap/coco2014_cap.yaml +4 -0
- LaViDa/eval/lmms_eval/tasks/coco_cap/coco2014_cap_test.yaml +24 -0
- LaViDa/eval/lmms_eval/tasks/coco_cap/coco2014_cap_val.yaml +45 -0
- LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap.yaml +4 -0
- LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap_test.yaml +24 -0
- LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap_val.yaml +45 -0
- LaViDa/eval/lmms_eval/tasks/coco_cap/coco2017_cap_val_lite.yaml +45 -0
- LaViDa/eval/lmms_eval/tasks/coco_cap/coco_cap.yaml +6 -0
- LaViDa/eval/lmms_eval/tasks/coco_cap/utils.py +155 -0
- LaViDa/eval/lmms_eval/tasks/common_voice_15/_default_template_yaml +21 -0
- LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15.yaml +5 -0
- LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15_en.yaml +10 -0
- LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15_fr.yaml +10 -0
- LaViDa/eval/lmms_eval/tasks/common_voice_15/common_voice_15_zh-CN.yaml +10 -0
- LaViDa/eval/lmms_eval/tasks/common_voice_15/utils.py +182 -0
- LaViDa/eval/lmms_eval/tasks/conbench/conbench.yaml +24 -0
- LaViDa/eval/lmms_eval/tasks/conbench/utils.py +96 -0
- LaViDa/eval/lmms_eval/tasks/covost2/_default_template_en_zh_yaml +28 -0
- LaViDa/eval/lmms_eval/tasks/covost2/_default_template_zh_en_yaml +28 -0
- LaViDa/eval/lmms_eval/tasks/covost2/covost2.yaml +4 -0
- LaViDa/eval/lmms_eval/tasks/covost2/covost2_en_zh.yaml +4 -0
- 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: ""
|