|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r"""Implements the OKVQA dataset for TFDS.
|
|
|
|
Download the required files from https://aokvqa.allenai.org/download.html:
|
|
|
|
mkdir -p /tmp/tfds
|
|
cd /tmp/tfds/
|
|
wget http://images.cocodataset.org/zips/train2017.zip
|
|
wget http://images.cocodataset.org/zips/val2017.zip
|
|
wget http://images.cocodataset.org/zips/test2017.zip
|
|
wget https://prior-datasets.s3.us-east-2.amazonaws.com/aokvqa/aokvqa_v1p0.tar.gz
|
|
unzip val2017.zip
|
|
unzip train2017.zip
|
|
unzip test2017.zip
|
|
tar xzf aokvqa_v1p0.tar.gz
|
|
|
|
Then, run conversion locally (make sure to install tensorflow-datasets for the `tfds` util):
|
|
|
|
cd big_vision/datasets
|
|
env TFDS_DATA_DIR=/tmp/tfds tfds build --datasets=aokvqa
|
|
|
|
Example to load:
|
|
|
|
import tensorflow_datasets as tfds
|
|
dataset = tfds.load('aokvqa', split='val', data_dir='/tmp/tfds')
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
from typing import Any
|
|
import numpy as np
|
|
import tensorflow_datasets as tfds
|
|
|
|
_DESCRIPTION = """
|
|
A-OKVQA addresses the task of VQA with outside knowledge.
|
|
It is a follow-up dataset of OKVQA.
|
|
|
|
This version of the dataset contains:
|
|
- Questions + Answers + Multiple Choice Answers + Rationales from A-OKVQA.
|
|
- Images from COCO.
|
|
"""
|
|
|
|
_CITATION = """
|
|
@article{AOKVQA,
|
|
title={A-OKVQA: A Benchmark for Visual Question Answering using World Knowledge},
|
|
author={Dustin Schwenk and Apoorv Khandelwal and Christopher Clark and Kenneth Marino and Roozbeh Mottaghi},
|
|
journal={arXiv},
|
|
year={2022},
|
|
}
|
|
"""
|
|
|
|
ANNOTATION_FILES = {
|
|
'train': 'aokvqa_v1p0_train.json',
|
|
'val': 'aokvqa_v1p0_val.json',
|
|
'test': 'aokvqa_v1p0_test.json',
|
|
}
|
|
|
|
|
|
|
|
_AOKVQA_PATH = '/tmp/tfds'
|
|
|
|
|
|
class AOkVqa(tfds.core.GeneratorBasedBuilder):
|
|
"""AOKVQA dataset for TFDS."""
|
|
|
|
VERSION = tfds.core.Version('1.0.0')
|
|
RELEASE_NOTES = {'1.0.0': 'ArrayRecord version.'}
|
|
MANUAL_DOWNLOAD_INSTRUCTIONS = """
|
|
In manual_dir/ you should have a directory a_ok_vqa which contains the
|
|
following files and directories:
|
|
From the A-OKVQA dataset:
|
|
- aokvqa_v1p0_train.json
|
|
- aokvqa_v1p0_val.json
|
|
- aokvqa_v1p0_test.json
|
|
It also requires the COCO data files.
|
|
"""
|
|
|
|
def _info(self) -> tfds.core.DatasetInfo:
|
|
"""Returns the dataset metadata."""
|
|
features = tfds.features.FeaturesDict({
|
|
'image': tfds.features.Image(shape=(None, None, 3)),
|
|
'image_id': tfds.features.Scalar(dtype=np.int64),
|
|
'direct_answers': tfds.features.Sequence(tfds.features.Text()),
|
|
'direct_answer_is_difficult': tfds.features.Scalar(dtype=np.bool_),
|
|
'multiple_choice_possible_answers':
|
|
tfds.features.Sequence(tfds.features.Text()),
|
|
'multiple_choice_correct_idx':
|
|
tfds.features.Scalar(dtype=np.int32),
|
|
'answer_rationales': tfds.features.Sequence(tfds.features.Text()),
|
|
'question': tfds.features.Text(),
|
|
'question_id': tfds.features.Text(),
|
|
})
|
|
|
|
return tfds.core.DatasetInfo(
|
|
builder=self,
|
|
features=features,
|
|
description=_DESCRIPTION,
|
|
supervised_keys=None,
|
|
homepage='https://okvqa.allenai.org/',
|
|
citation=_CITATION,
|
|
)
|
|
|
|
def _split_generators(self, dl_manager: tfds.download.DownloadManager) -> ...:
|
|
"""Call the function which defines the splits."""
|
|
|
|
data_dir = _AOKVQA_PATH
|
|
return {
|
|
'train': self._generate_examples(data_dir, 'train'),
|
|
'val': self._generate_examples(data_dir, 'val'),
|
|
'test': self._generate_examples(data_dir, 'test'),
|
|
}
|
|
|
|
def _generate_examples(self, data_dir: str, split: str) -> ...:
|
|
annotations = get_annotations(data_dir, split)
|
|
|
|
for question_id, feature_dict in annotations.items():
|
|
image_id = feature_dict['image_id']
|
|
|
|
|
|
feature_dict['image'] = self.get_image_path(data_dir, split, image_id)
|
|
|
|
|
|
if split not in ['train', 'val']:
|
|
assert split == 'test', f'Unknown split: {split}'
|
|
feature_dict['multiple_choice_correct_idx'] = -1
|
|
feature_dict['direct_answers'] = []
|
|
feature_dict['answer_rationales'] = []
|
|
yield f'{question_id}', feature_dict
|
|
|
|
def get_image_path(self, data_dir: str, split: str, image_id: int) -> str:
|
|
return f'{data_dir}/{split}2017/{image_id:012d}.jpg'
|
|
|
|
|
|
def get_annotations(
|
|
data_dir: str, split: str) -> dict[int, dict[str, Any]]:
|
|
"""Return okvqa annotations (quesions and answers) as dictionary."""
|
|
path = os.path.join(data_dir, ANNOTATION_FILES[split])
|
|
with open(path) as f:
|
|
annotations = json.load(f)
|
|
|
|
aokvqa_annotations = {}
|
|
for annotation in annotations:
|
|
|
|
assert len(annotation['choices']) == 4
|
|
|
|
question_id = annotation['question_id']
|
|
|
|
aokvqa_annotations[question_id] = {
|
|
'image_id': annotation['image_id'],
|
|
'direct_answer_is_difficult': annotation['difficult_direct_answer'],
|
|
'multiple_choice_possible_answers': annotation['choices'],
|
|
'question': annotation['question'],
|
|
'question_id': annotation['question_id'],
|
|
}
|
|
|
|
|
|
if split in ['train', 'val']:
|
|
assert len(annotation['direct_answers']) == 10
|
|
assert len(annotation['rationales']) == 3
|
|
|
|
aokvqa_annotations[question_id]['direct_answers'] = annotation[
|
|
'direct_answers']
|
|
aokvqa_annotations[question_id]['answer_rationales'] = annotation[
|
|
'rationales']
|
|
aokvqa_annotations[question_id]['multiple_choice_correct_idx'] = (
|
|
annotation['correct_choice_idx'])
|
|
|
|
return aokvqa_annotations
|
|
|