| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| r"""Implements the OKVQA dataset for TFDS. |
| |
| Download the required files from https://okvqa.allenai.org/download.html: |
| |
| mkdir -p /tmp/tfds |
| cd /tmp/tfds/ |
| wget http://images.cocodataset.org/zips/train2014.zip |
| wget http://images.cocodataset.org/zips/val2014.zip |
| wget https://okvqa.allenai.org/static/data/mscoco_train2014_annotations.json.zip |
| wget https://okvqa.allenai.org/static/data/mscoco_val2014_annotations.json.zip |
| wget https://okvqa.allenai.org/static/data/OpenEnded_mscoco_train2014_questions.json.zip |
| wget https://okvqa.allenai.org/static/data/OpenEnded_mscoco_val2014_questions.json.zip |
| unzip val2014.zip |
| unzip train2014.zip |
| unzip OpenEnded_mscoco_train2014_questions.json.zip |
| unzip OpenEnded_mscoco_val2014_questions.json.zip |
| unzip mscoco_train2014_annotations.json.zip |
| unzip mscoco_val2014_annotations.json.zip |
| |
| 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=okvqa |
| |
| Example to load: |
| |
| import tensorflow_datasets as tfds |
| dataset = tfds.load('okvqa', split='val', data_dir='/tmp/tfds') |
| """ |
|
|
| import json |
| import os |
| from typing import Any |
| import numpy as np |
| import tensorflow_datasets as tfds |
|
|
| _DESCRIPTION = """ |
| OKVQA addresses the task of VQA with outside knowledge. |
| This version of the dataset contains: |
| - Questions + Answers from OKVQA. |
| - Images from COCO. |
| """ |
|
|
| _CITATION = """ |
| @InProceedings{okvqa, |
| author = {Kenneth Marino and Mohammad Rastegari and Ali Farhadi and Roozbeh Mottaghi}, |
| title = {OK-VQA: A Visual Question Answering Benchmark Requiring External Knowledge}, |
| booktitle = {Conference on Computer Vision and Pattern Recognition (CVPR)}, |
| year = {2019}, |
| } |
| """ |
|
|
| ANNOTATION_FILE = { |
| 'train': 'mscoco_train2014_annotations.json', |
| 'val': 'mscoco_val2014_annotations.json', |
| } |
| QUESTIONS_FILE = { |
| 'train': 'OpenEnded_mscoco_train2014_questions.json', |
| 'val': 'OpenEnded_mscoco_val2014_questions.json', |
| } |
| QUESTION_TYPES = { |
| 'one': 'Vehicles and Transportation', |
| 'two': 'Brands, Companies and Products', |
| 'three': 'Objects, Material and Clothing', |
| 'four': 'Sports and Recreation', |
| 'five': 'Cooking and Food', |
| 'six': 'Geography, History, Language and Culture', |
| 'seven': 'People and Everyday life', |
| 'eight': 'Plants and Animals', |
| 'nine': 'Science and Technology', |
| 'ten': 'Weather and Climate', |
| 'other': 'Other', |
| } |
|
|
|
|
| |
| _OKVQA_PATH = '/media/scratch/okvqa' |
|
|
|
|
| class OkVqa(tfds.core.GeneratorBasedBuilder): |
| """Import COCO dataset for OKVQA with KAT features.""" |
|
|
| VERSION = tfds.core.Version('1.0.0') |
| RELEASE_NOTES = {'1.0.0': 'Changed to array record format.'} |
| MANUAL_DOWNLOAD_INSTRUCTIONS = """ |
| In manual_dir/ you should have a directory okvqa which contains the |
| following files and directories: |
| From the OKVQA dataset: |
| - mscoco_train2014_annotations.json |
| - mscoco_val2014_annotations.json |
| - OpenEnded_mscoco_train2014_questions.json |
| - OpenEnded_mscoco_val2014_questions.json |
| - train2014.zip |
| - val2014.zip |
| """ |
|
|
| 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), |
| 'answer_type': tfds.features.Text(), |
| 'answers': tfds.features.Sequence(tfds.features.Text()), |
| 'answers_confidence': tfds.features.Tensor(shape=[10], dtype=np.bool_), |
| 'answers_raw': tfds.features.Sequence(tfds.features.Text()), |
| 'question_id': tfds.features.Scalar(dtype=np.int64), |
| 'question_type': tfds.features.Text(), |
| 'question_type_readable': tfds.features.Text(), |
| 'question': 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 = _OKVQA_PATH |
| return { |
| 'train': self._generate_examples(data_dir, 'train'), |
| 'val': self._generate_examples(data_dir, 'val'), |
| } |
|
|
| def _generate_examples(self, data_dir: str, split: str) -> ...: |
| annotations = get_okvqa_annotations(data_dir, split) |
|
|
| for question_id, annotation in annotations.items(): |
| image_id = annotation['image_id'] |
|
|
| |
| if len(annotation['answers']) != 10: |
| num_answers = len(annotation['answers']) |
| raise ValueError( |
| f'The number of answers for {image_id} is not 10 but {num_answers}') |
|
|
| feature_dict = { |
| 'image': self.get_image_path(data_dir, split, image_id), |
| 'image_id': image_id, |
| 'answer_type': annotation['answer_type'], |
| 'answers': [a['answer'] for a in annotation['answers']], |
| 'answers_confidence': _get_answer_confidence(annotation['answers']), |
| 'answers_raw': [a['raw_answer'] for a in annotation['answers']], |
| 'question_id': annotation['question_id'], |
| 'question_type': annotation['question_type'], |
| 'question_type_readable': QUESTION_TYPES[annotation['question_type']], |
| 'question': annotation['question'], |
| } |
| yield f'{question_id}', feature_dict |
|
|
| def get_image_path(self, data_dir: str, split: str, image_id: int) -> str: |
| subdir = {'train': 'train2014', 'val': 'val2014'}[split] |
| return f'{data_dir}/{subdir}/COCO_{subdir}_{image_id:012d}.jpg' |
|
|
|
|
| def _get_answer_confidence(answers: list[dict[str, str]]) -> np.ndarray: |
| """Get OKVQA answer confidences as bool.""" |
| confidences = [] |
| for a in answers: |
| confidence = a['answer_confidence'] |
| if confidence == 'yes': |
| confidences.append(True) |
| elif confidence == 'no': |
| confidences.append(False) |
| else: |
| raise ValueError(f'Unknown confidence: {confidence}') |
| return np.array(confidences, dtype=bool) |
|
|
|
|
| def _read_json( |
| data_dir: str, file: str, key: str |
| ) -> dict[int, dict[str, Any]]: |
| with open(os.path.join(data_dir, file)) as f: |
| data = json.load(f) |
| questions = {d['question_id']: d for d in data[key]} |
| return questions |
|
|
|
|
| def get_okvqa_annotations( |
| data_dir: str, split: str |
| ) -> dict[int, dict[str, Any]]: |
| """Return okvqa annotations (quesions and answers) as dictionary.""" |
| questions = _read_json(data_dir, QUESTIONS_FILE[split], 'questions') |
| annotations = _read_json(data_dir, ANNOTATION_FILE[split], 'annotations') |
|
|
| assert len(annotations) == len(questions) |
| for question_id, question in questions.items(): |
| assert question['image_id'] == annotations[question_id]['image_id'] |
| assert question['question_id'] == annotations[question_id]['question_id'] |
| annotations[question_id]['question'] = question['question'] |
|
|
| return annotations |
|
|