Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- Tipsomaly/model/big_vision/datasets/ai2d/ai2d.py +209 -0
- Tipsomaly/model/big_vision/datasets/aokvqa/aokvqa.py +182 -0
- Tipsomaly/model/big_vision/datasets/chartqa/chartqa.py +122 -0
- Tipsomaly/model/big_vision/datasets/coco35l/coco35l.py +154 -0
- Tipsomaly/model/big_vision/datasets/countbenchqa/countbenchqa.py +164 -0
- Tipsomaly/model/big_vision/datasets/docvqa/docvqa.py +110 -0
- Tipsomaly/model/big_vision/datasets/gqa/gqa.py +167 -0
- Tipsomaly/model/big_vision/datasets/imagenet/class_names.py +0 -0
- Tipsomaly/model/big_vision/datasets/infovqa/infovqa.py +141 -0
- Tipsomaly/model/big_vision/datasets/okvqa/okvqa.py +213 -0
- Tipsomaly/model/big_vision/datasets/pope/pope.py +145 -0
- Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/coco_caption.py +145 -0
- Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/rsvqa.py +173 -0
- Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/science_qa.py +122 -0
- Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/segmentation.py +270 -0
- Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/storepreds.py +77 -0
- Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/tallyqa.py +144 -0
- Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/vqa.py +163 -0
- Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/vqav2.py +197 -0
- Tipsomaly/model/big_vision/pp/__pycache__/__init__.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/__init__.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/__init__.cpython-39.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/builder.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/builder.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/builder.cpython-39.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/ops_general.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/ops_general.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/ops_general.cpython-39.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/ops_image.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/ops_image.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/ops_image.cpython-39.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/ops_text.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/ops_text.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/ops_text.cpython-39.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/registry.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/registry.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/registry.cpython-39.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/tokenizer.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/tokenizer.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/tokenizer.cpython-39.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/utils.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/utils.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/pp/__pycache__/utils.cpython-39.pyc +0 -0
- Tipsomaly/model/big_vision/pp/archive/__init__.py +0 -0
- Tipsomaly/model/big_vision/pp/archive/autoaugment.py +700 -0
- Tipsomaly/model/big_vision/pp/archive/randaug.py +46 -0
- Tipsomaly/model/big_vision/pp/proj/clippo/download_unifont.sh +21 -0
- Tipsomaly/model/big_vision/pp/proj/givt/pp_ops.py +36 -0
- Tipsomaly/model/big_vision/pp/proj/image_text/ops_naflex.py +202 -0
- Tipsomaly/model/big_vision/tools/lit_demo/README.md +26 -0
Tipsomaly/model/big_vision/datasets/ai2d/ai2d.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
# pylint: disable=line-too-long
|
| 16 |
+
r"""AI2D TFDS converter.
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
It's a small dataset, so can be built locally. Copy the data to local disk:
|
| 20 |
+
|
| 21 |
+
mkdir -p /tmp/data/ai2d && cd /tmp/data/ai2d
|
| 22 |
+
wget https://ai2-public-datasets.s3.amazonaws.com/diagrams/ai2d-all.zip
|
| 23 |
+
wget https://s3-us-east-2.amazonaws.com/prior-datasets/ai2d_test_ids.csv
|
| 24 |
+
wget https://github.com/googlefonts/dm-fonts/raw/main/Sans/fonts/ttf/DMSans-Regular.ttf
|
| 25 |
+
unzip ai2d-all.zip
|
| 26 |
+
|
| 27 |
+
Also download a font for rendering, set the location in the flag font_path.
|
| 28 |
+
|
| 29 |
+
Then, run conversion locally (make sure to install tensorflow-datasets for the `tfds` util):
|
| 30 |
+
|
| 31 |
+
cd third_party/py/big_vision/datasets
|
| 32 |
+
env TFDS_DATA_DIR=/tmp/tfds tfds build --datasets=ai2d
|
| 33 |
+
|
| 34 |
+
Example to load:
|
| 35 |
+
|
| 36 |
+
import tensorflow_datasets as tfds
|
| 37 |
+
dataset = tfds.load(ai2d', split='train', data_dir='/tmp/tfds')
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
import functools
|
| 41 |
+
import glob
|
| 42 |
+
import io
|
| 43 |
+
import json
|
| 44 |
+
import os
|
| 45 |
+
from typing import Any, Dict
|
| 46 |
+
|
| 47 |
+
from absl import flags
|
| 48 |
+
import numpy as np
|
| 49 |
+
from PIL import Image
|
| 50 |
+
from PIL import ImageDraw
|
| 51 |
+
from PIL import ImageFont
|
| 52 |
+
import tensorflow_datasets as tfds
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
_DESCRIPTION = """AI2D dataset."""
|
| 56 |
+
|
| 57 |
+
# pylint: disable=line-too-long
|
| 58 |
+
_CITATION = """
|
| 59 |
+
@inproceedings{kembhavi2016eccv,
|
| 60 |
+
author = {Aniruddha Kembhavi, Mike Salvato, Eric Kolve, Minjoon Seo, Hannaneh Hajishirzi, Ali Farhadi},
|
| 61 |
+
title = {A Diagram Is Worth A Dozen Images},
|
| 62 |
+
booktitle = {European Conference on Computer Vision (ECCV)},
|
| 63 |
+
year = {2016}
|
| 64 |
+
url={https://api.semanticscholar.org/CorpusID:2682274}
|
| 65 |
+
}
|
| 66 |
+
"""
|
| 67 |
+
# pylint: enable=line-too-long
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
_INPUT_PATH = flags.DEFINE_string(
|
| 71 |
+
'input_path', '/tmp/data/ai2d/', 'Downloaded AI2D data.'
|
| 72 |
+
)
|
| 73 |
+
_FONT_PATH = flags.DEFINE_string(
|
| 74 |
+
'font_path', '/tmp/data/ai2d/DMSans-Regular.ttf',
|
| 75 |
+
'Font for rendering annotations.'
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
class Ai2d(tfds.core.GeneratorBasedBuilder):
|
| 80 |
+
"""DatasetBuilder for AI2D dataset."""
|
| 81 |
+
|
| 82 |
+
VERSION = tfds.core.Version('1.1.0')
|
| 83 |
+
RELEASE_NOTES = {'1.1.0': 'Re-create from scratch + more fields.'}
|
| 84 |
+
|
| 85 |
+
def _info(self):
|
| 86 |
+
"""Returns the metadata."""
|
| 87 |
+
return tfds.core.DatasetInfo(
|
| 88 |
+
builder=self,
|
| 89 |
+
description=_DESCRIPTION,
|
| 90 |
+
features=tfds.features.FeaturesDict({
|
| 91 |
+
'id': tfds.features.Text(),
|
| 92 |
+
'question': tfds.features.Text(),
|
| 93 |
+
'label': tfds.features.Scalar(np.int32),
|
| 94 |
+
'answer': tfds.features.Text(),
|
| 95 |
+
'possible_answers': tfds.features.Sequence(tfds.features.Text()),
|
| 96 |
+
'abc_label': tfds.features.Scalar(np.bool_),
|
| 97 |
+
'image_name': tfds.features.Text(),
|
| 98 |
+
'image': tfds.features.Image(encoding_format='png'),
|
| 99 |
+
}),
|
| 100 |
+
homepage='https://allenai.org/data/diagrams',
|
| 101 |
+
citation=_CITATION,
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
def _split_generators(self, dl_manager: tfds.download.DownloadManager):
|
| 105 |
+
"""Returns SplitGenerators."""
|
| 106 |
+
return {split: self._generate_examples(split)
|
| 107 |
+
for split in ('test', 'train')}
|
| 108 |
+
|
| 109 |
+
def _generate_examples(self, split: str):
|
| 110 |
+
"""Yields (key, example) tuples."""
|
| 111 |
+
with open(
|
| 112 |
+
os.path.join(_INPUT_PATH.value, 'ai2d_test_ids.csv'), 'r'
|
| 113 |
+
) as f:
|
| 114 |
+
all_test_ids = f.readlines()
|
| 115 |
+
all_test_ids = [line.strip() for line in all_test_ids]
|
| 116 |
+
|
| 117 |
+
all_annotation_paths = glob.glob(
|
| 118 |
+
os.path.join(_INPUT_PATH.value, 'ai2d/questions', '*.json'))
|
| 119 |
+
for annotation_path in all_annotation_paths:
|
| 120 |
+
basename = os.path.basename(annotation_path)
|
| 121 |
+
image_id = basename.split('.')[0]
|
| 122 |
+
if image_id in all_test_ids and split == 'train':
|
| 123 |
+
continue
|
| 124 |
+
elif image_id not in all_test_ids and split == 'test':
|
| 125 |
+
continue
|
| 126 |
+
|
| 127 |
+
text_annotation_path = os.path.join(
|
| 128 |
+
_INPUT_PATH.value, 'ai2d/annotations', basename
|
| 129 |
+
)
|
| 130 |
+
with open(annotation_path, 'r') as f:
|
| 131 |
+
with open(text_annotation_path, 'r') as g:
|
| 132 |
+
question_json = json.load(f)
|
| 133 |
+
text_annotation_json = json.load(g)
|
| 134 |
+
for question in question_json['questions']:
|
| 135 |
+
label_id = int(
|
| 136 |
+
question_json['questions'][question]['correctAnswer']
|
| 137 |
+
)
|
| 138 |
+
choices = question_json['questions'][question]['answerTexts']
|
| 139 |
+
abc_label = question_json['questions'][question]['abcLabel']
|
| 140 |
+
annotation = {
|
| 141 |
+
'id': question_json['questions'][question]['questionId'],
|
| 142 |
+
'question': question,
|
| 143 |
+
'label': label_id,
|
| 144 |
+
'answer': choices[label_id],
|
| 145 |
+
'possible_answers': tuple(choices),
|
| 146 |
+
'abc_label': abc_label,
|
| 147 |
+
'image_name': question_json['imageName'],
|
| 148 |
+
}
|
| 149 |
+
annotation['image'] = _create_image(
|
| 150 |
+
annotation, text_annotation_json['text']
|
| 151 |
+
)
|
| 152 |
+
yield annotation['id'], annotation
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
@functools.cache
|
| 156 |
+
def Font( # pylint: disable=invalid-name
|
| 157 |
+
size: int,
|
| 158 |
+
) -> ImageFont.FreeTypeFont:
|
| 159 |
+
"""Loads the font from in the specified style.
|
| 160 |
+
|
| 161 |
+
Args:
|
| 162 |
+
size: The size of the returned font.
|
| 163 |
+
|
| 164 |
+
Returns:
|
| 165 |
+
The loaded font.
|
| 166 |
+
"""
|
| 167 |
+
return ImageFont.truetype(_FONT_PATH.value, size=size)
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def _create_image(
|
| 171 |
+
annotation: Dict[str, Any], text_annotation: Dict[str, Any]
|
| 172 |
+
) -> bytes:
|
| 173 |
+
"""Adds image to one annotation."""
|
| 174 |
+
img_path = os.path.join(_INPUT_PATH.value, 'ai2d/images',
|
| 175 |
+
annotation['image_name'])
|
| 176 |
+
with open(img_path, 'rb') as f:
|
| 177 |
+
if annotation['abc_label']:
|
| 178 |
+
raw_image = _draw_text(f, text_annotation)
|
| 179 |
+
else:
|
| 180 |
+
raw_image = f.read()
|
| 181 |
+
return raw_image
|
| 182 |
+
|
| 183 |
+
|
| 184 |
+
def _draw_text(image, text_annotations) -> bytes:
|
| 185 |
+
"""Replaces text in image by the correct replacement letter from AI2D."""
|
| 186 |
+
image = Image.open(image)
|
| 187 |
+
draw = ImageDraw.Draw(image)
|
| 188 |
+
for annotation in text_annotations:
|
| 189 |
+
current_annotation = text_annotations[annotation]
|
| 190 |
+
rectangle = current_annotation['rectangle']
|
| 191 |
+
box = [tuple(rectangle[0]), tuple(rectangle[1]),]
|
| 192 |
+
text = current_annotation['replacementText']
|
| 193 |
+
position = box[0]
|
| 194 |
+
draw.rectangle(box, fill='white')
|
| 195 |
+
font_size = 100
|
| 196 |
+
x_diff = box[1][0] - box[0][0]
|
| 197 |
+
y_diff = box[1][1] - box[0][1]
|
| 198 |
+
font = Font(font_size)
|
| 199 |
+
size = font.getbbox(text)
|
| 200 |
+
while (size[2] > x_diff or size[3] > y_diff) and font_size > 0:
|
| 201 |
+
font = Font(font_size)
|
| 202 |
+
size = font.getbbox(text)
|
| 203 |
+
font_size -= 1
|
| 204 |
+
delta = (x_diff - size[2]) // 2
|
| 205 |
+
position = (position[0] + delta, position[1])
|
| 206 |
+
draw.text(position, text, fill='black', font=font)
|
| 207 |
+
new_image_bytes = io.BytesIO()
|
| 208 |
+
image.save(new_image_bytes, format='PNG')
|
| 209 |
+
return new_image_bytes.getvalue()
|
Tipsomaly/model/big_vision/datasets/aokvqa/aokvqa.py
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
# pylint: disable=line-too-long
|
| 16 |
+
r"""Implements the OKVQA dataset for TFDS.
|
| 17 |
+
|
| 18 |
+
Download the required files from https://aokvqa.allenai.org/download.html:
|
| 19 |
+
|
| 20 |
+
mkdir -p /tmp/tfds
|
| 21 |
+
cd /tmp/tfds/
|
| 22 |
+
wget http://images.cocodataset.org/zips/train2017.zip
|
| 23 |
+
wget http://images.cocodataset.org/zips/val2017.zip
|
| 24 |
+
wget http://images.cocodataset.org/zips/test2017.zip
|
| 25 |
+
wget https://prior-datasets.s3.us-east-2.amazonaws.com/aokvqa/aokvqa_v1p0.tar.gz
|
| 26 |
+
unzip val2017.zip
|
| 27 |
+
unzip train2017.zip
|
| 28 |
+
unzip test2017.zip
|
| 29 |
+
tar xzf aokvqa_v1p0.tar.gz
|
| 30 |
+
|
| 31 |
+
Then, run conversion locally (make sure to install tensorflow-datasets for the `tfds` util):
|
| 32 |
+
|
| 33 |
+
cd big_vision/datasets
|
| 34 |
+
env TFDS_DATA_DIR=/tmp/tfds tfds build --datasets=aokvqa
|
| 35 |
+
|
| 36 |
+
Example to load:
|
| 37 |
+
|
| 38 |
+
import tensorflow_datasets as tfds
|
| 39 |
+
dataset = tfds.load('aokvqa', split='val', data_dir='/tmp/tfds')
|
| 40 |
+
"""
|
| 41 |
+
|
| 42 |
+
import json
|
| 43 |
+
import os
|
| 44 |
+
from typing import Any
|
| 45 |
+
import numpy as np
|
| 46 |
+
import tensorflow_datasets as tfds
|
| 47 |
+
|
| 48 |
+
_DESCRIPTION = """
|
| 49 |
+
A-OKVQA addresses the task of VQA with outside knowledge.
|
| 50 |
+
It is a follow-up dataset of OKVQA.
|
| 51 |
+
|
| 52 |
+
This version of the dataset contains:
|
| 53 |
+
- Questions + Answers + Multiple Choice Answers + Rationales from A-OKVQA.
|
| 54 |
+
- Images from COCO.
|
| 55 |
+
"""
|
| 56 |
+
|
| 57 |
+
_CITATION = """
|
| 58 |
+
@article{AOKVQA,
|
| 59 |
+
title={A-OKVQA: A Benchmark for Visual Question Answering using World Knowledge},
|
| 60 |
+
author={Dustin Schwenk and Apoorv Khandelwal and Christopher Clark and Kenneth Marino and Roozbeh Mottaghi},
|
| 61 |
+
journal={arXiv},
|
| 62 |
+
year={2022},
|
| 63 |
+
}
|
| 64 |
+
"""
|
| 65 |
+
|
| 66 |
+
ANNOTATION_FILES = {
|
| 67 |
+
'train': 'aokvqa_v1p0_train.json',
|
| 68 |
+
'val': 'aokvqa_v1p0_val.json',
|
| 69 |
+
'test': 'aokvqa_v1p0_test.json',
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
# When running locally (recommended), copy files as above an use these:
|
| 74 |
+
_AOKVQA_PATH = '/tmp/tfds'
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
class AOkVqa(tfds.core.GeneratorBasedBuilder):
|
| 78 |
+
"""AOKVQA dataset for TFDS."""
|
| 79 |
+
|
| 80 |
+
VERSION = tfds.core.Version('1.0.0')
|
| 81 |
+
RELEASE_NOTES = {'1.0.0': 'ArrayRecord version.'}
|
| 82 |
+
MANUAL_DOWNLOAD_INSTRUCTIONS = """
|
| 83 |
+
In manual_dir/ you should have a directory a_ok_vqa which contains the
|
| 84 |
+
following files and directories:
|
| 85 |
+
From the A-OKVQA dataset:
|
| 86 |
+
- aokvqa_v1p0_train.json
|
| 87 |
+
- aokvqa_v1p0_val.json
|
| 88 |
+
- aokvqa_v1p0_test.json
|
| 89 |
+
It also requires the COCO data files.
|
| 90 |
+
"""
|
| 91 |
+
|
| 92 |
+
def _info(self) -> tfds.core.DatasetInfo:
|
| 93 |
+
"""Returns the dataset metadata."""
|
| 94 |
+
features = tfds.features.FeaturesDict({
|
| 95 |
+
'image': tfds.features.Image(shape=(None, None, 3)),
|
| 96 |
+
'image_id': tfds.features.Scalar(dtype=np.int64),
|
| 97 |
+
'direct_answers': tfds.features.Sequence(tfds.features.Text()),
|
| 98 |
+
'direct_answer_is_difficult': tfds.features.Scalar(dtype=np.bool_),
|
| 99 |
+
'multiple_choice_possible_answers': # List of 4 possible answers.
|
| 100 |
+
tfds.features.Sequence(tfds.features.Text()),
|
| 101 |
+
'multiple_choice_correct_idx': # Integer from 0-3.
|
| 102 |
+
tfds.features.Scalar(dtype=np.int32),
|
| 103 |
+
'answer_rationales': tfds.features.Sequence(tfds.features.Text()),
|
| 104 |
+
'question': tfds.features.Text(),
|
| 105 |
+
'question_id': tfds.features.Text(),
|
| 106 |
+
})
|
| 107 |
+
|
| 108 |
+
return tfds.core.DatasetInfo(
|
| 109 |
+
builder=self,
|
| 110 |
+
features=features,
|
| 111 |
+
description=_DESCRIPTION,
|
| 112 |
+
supervised_keys=None,
|
| 113 |
+
homepage='https://okvqa.allenai.org/',
|
| 114 |
+
citation=_CITATION,
|
| 115 |
+
)
|
| 116 |
+
|
| 117 |
+
def _split_generators(self, dl_manager: tfds.download.DownloadManager) -> ...:
|
| 118 |
+
"""Call the function which defines the splits."""
|
| 119 |
+
# data_dir = dl_manager.manual_dir
|
| 120 |
+
data_dir = _AOKVQA_PATH
|
| 121 |
+
return {
|
| 122 |
+
'train': self._generate_examples(data_dir, 'train'),
|
| 123 |
+
'val': self._generate_examples(data_dir, 'val'),
|
| 124 |
+
'test': self._generate_examples(data_dir, 'test'),
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
def _generate_examples(self, data_dir: str, split: str) -> ...:
|
| 128 |
+
annotations = get_annotations(data_dir, split)
|
| 129 |
+
|
| 130 |
+
for question_id, feature_dict in annotations.items():
|
| 131 |
+
image_id = feature_dict['image_id']
|
| 132 |
+
|
| 133 |
+
# Add image and GT segmentatio labels from total_transfer.
|
| 134 |
+
feature_dict['image'] = self.get_image_path(data_dir, split, image_id)
|
| 135 |
+
|
| 136 |
+
# Add dummy features for several features in the test set.
|
| 137 |
+
if split not in ['train', 'val']:
|
| 138 |
+
assert split == 'test', f'Unknown split: {split}'
|
| 139 |
+
feature_dict['multiple_choice_correct_idx'] = -1
|
| 140 |
+
feature_dict['direct_answers'] = []
|
| 141 |
+
feature_dict['answer_rationales'] = []
|
| 142 |
+
yield f'{question_id}', feature_dict
|
| 143 |
+
|
| 144 |
+
def get_image_path(self, data_dir: str, split: str, image_id: int) -> str:
|
| 145 |
+
return f'{data_dir}/{split}2017/{image_id:012d}.jpg'
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
def get_annotations(
|
| 149 |
+
data_dir: str, split: str) -> dict[int, dict[str, Any]]:
|
| 150 |
+
"""Return okvqa annotations (quesions and answers) as dictionary."""
|
| 151 |
+
path = os.path.join(data_dir, ANNOTATION_FILES[split])
|
| 152 |
+
with open(path) as f:
|
| 153 |
+
annotations = json.load(f)
|
| 154 |
+
|
| 155 |
+
aokvqa_annotations = {}
|
| 156 |
+
for annotation in annotations:
|
| 157 |
+
# Sanity checks
|
| 158 |
+
assert len(annotation['choices']) == 4
|
| 159 |
+
|
| 160 |
+
question_id = annotation['question_id']
|
| 161 |
+
|
| 162 |
+
aokvqa_annotations[question_id] = {
|
| 163 |
+
'image_id': annotation['image_id'],
|
| 164 |
+
'direct_answer_is_difficult': annotation['difficult_direct_answer'],
|
| 165 |
+
'multiple_choice_possible_answers': annotation['choices'],
|
| 166 |
+
'question': annotation['question'],
|
| 167 |
+
'question_id': annotation['question_id'],
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
# Get answers and rationales for train and val only, not for test.
|
| 171 |
+
if split in ['train', 'val']:
|
| 172 |
+
assert len(annotation['direct_answers']) == 10
|
| 173 |
+
assert len(annotation['rationales']) == 3
|
| 174 |
+
|
| 175 |
+
aokvqa_annotations[question_id]['direct_answers'] = annotation[
|
| 176 |
+
'direct_answers']
|
| 177 |
+
aokvqa_annotations[question_id]['answer_rationales'] = annotation[
|
| 178 |
+
'rationales']
|
| 179 |
+
aokvqa_annotations[question_id]['multiple_choice_correct_idx'] = (
|
| 180 |
+
annotation['correct_choice_idx'])
|
| 181 |
+
|
| 182 |
+
return aokvqa_annotations
|
Tipsomaly/model/big_vision/datasets/chartqa/chartqa.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
# pylint: disable=line-too-long
|
| 16 |
+
r"""Implements CharQA in TFDS structure.
|
| 17 |
+
|
| 18 |
+
It's small data, so simple to run locally. First, copy the data to local disk:
|
| 19 |
+
|
| 20 |
+
mkdir -p /tmp/data
|
| 21 |
+
wget -O /tmp/data/chartqa.zip https://huggingface.co/datasets/ahmed-masry/ChartQA/resolve/main/ChartQA%20Dataset.zip?download=true
|
| 22 |
+
unzip /tmp/data/chartqa.zip
|
| 23 |
+
|
| 24 |
+
Then, run conversion locally (make sure to install tensorflow-datasets for the `tfds` util):
|
| 25 |
+
|
| 26 |
+
cd big_vision/datasets
|
| 27 |
+
env TFDS_DATA_DIR=/tmp/tfds tfds build --datasets=chartqa
|
| 28 |
+
|
| 29 |
+
Example to load:
|
| 30 |
+
|
| 31 |
+
import tensorflow_datasets as tfds
|
| 32 |
+
dataset_augmented = tfds.load('chartqa/augmented', split='train', data_dir='/tmp/tfds')
|
| 33 |
+
"""
|
| 34 |
+
import json
|
| 35 |
+
import os
|
| 36 |
+
|
| 37 |
+
import numpy as np
|
| 38 |
+
import tensorflow_datasets as tfds
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
_DESCRIPTION = """ChartQA dataset."""
|
| 42 |
+
|
| 43 |
+
# pylint: disable=line-too-long
|
| 44 |
+
_CITATION = """
|
| 45 |
+
@inproceedings{masry-etal-2022-chartqa,
|
| 46 |
+
title = "{C}hart{QA}: A Benchmark for Question Answering about Charts with Visual and Logical Reasoning",
|
| 47 |
+
author = "Masry, Ahmed and
|
| 48 |
+
Do, Xuan Long and
|
| 49 |
+
Tan, Jia Qing and
|
| 50 |
+
Joty, Shafiq and
|
| 51 |
+
Hoque, Enamul",
|
| 52 |
+
editor = "Muresan, Smaranda and
|
| 53 |
+
Nakov, Preslav and
|
| 54 |
+
Villavicencio, Aline",
|
| 55 |
+
booktitle = "Findings of the Association for Computational Linguistics: ACL 2022",
|
| 56 |
+
month = may,
|
| 57 |
+
year = "2022",
|
| 58 |
+
address = "Dublin, Ireland",
|
| 59 |
+
publisher = "Association for Computational Linguistics",
|
| 60 |
+
url = "https://aclanthology.org/2022.findings-acl.177",
|
| 61 |
+
doi = "10.18653/v1/2022.findings-acl.177",
|
| 62 |
+
pages = "2263--2279",
|
| 63 |
+
abstract = "Charts are very popular for analyzing data. When exploring charts, people often ask a variety of complex reasoning questions that involve several logical and arithmetic operations. They also commonly refer to visual features of a chart in their questions. However, most existing datasets do not focus on such complex reasoning questions as their questions are template-based and answers come from a fixed-vocabulary. In this work, we present a large-scale benchmark covering 9.6K human-written questions as well as 23.1K questions generated from human-written chart summaries. To address the unique challenges in our benchmark involving visual and logical reasoning over charts, we present two transformer-based models that combine visual features and the data table of the chart in a unified way to answer questions. While our models achieve the state-of-the-art results on the previous datasets as well as on our benchmark, the evaluation also reveals several challenges in answering complex reasoning questions.",
|
| 64 |
+
}
|
| 65 |
+
"""
|
| 66 |
+
# pylint: enable=line-too-long
|
| 67 |
+
|
| 68 |
+
# When running locally (recommended), copy files as above an use these:
|
| 69 |
+
_CHARTQA_PATH = '/tmp/data/ChartQA Dataset/'
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
class ChartQAConfig(tfds.core.BuilderConfig):
|
| 73 |
+
"""Configuration to build the dataset."""
|
| 74 |
+
pass
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
class ChartQA(tfds.core.GeneratorBasedBuilder):
|
| 78 |
+
"""DatasetBuilder for ChartQA dataset."""
|
| 79 |
+
|
| 80 |
+
VERSION = tfds.core.Version('1.0.0')
|
| 81 |
+
RELEASE_NOTES = {'1.0.0': 'First release.'}
|
| 82 |
+
BUILDER_CONFIGS = [
|
| 83 |
+
ChartQAConfig(name='human', description='Human set'),
|
| 84 |
+
ChartQAConfig(name='augmented', description='Augmented set'),
|
| 85 |
+
]
|
| 86 |
+
|
| 87 |
+
def _info(self):
|
| 88 |
+
"""Returns the metadata."""
|
| 89 |
+
return tfds.core.DatasetInfo(
|
| 90 |
+
builder=self,
|
| 91 |
+
description=_DESCRIPTION,
|
| 92 |
+
features=tfds.features.FeaturesDict({
|
| 93 |
+
'question_id': tfds.features.Scalar(np.int32),
|
| 94 |
+
'image/filename': tfds.features.Text(),
|
| 95 |
+
'image': tfds.features.Image(encoding_format='png'),
|
| 96 |
+
'question': tfds.features.Text(),
|
| 97 |
+
'answer': tfds.features.Text(),
|
| 98 |
+
}),
|
| 99 |
+
homepage='https://github.com/vis-nlp/ChartQA',
|
| 100 |
+
citation=_CITATION,
|
| 101 |
+
)
|
| 102 |
+
|
| 103 |
+
def _split_generators(self, dl_manager: tfds.download.DownloadManager):
|
| 104 |
+
"""Returns SplitGenerators."""
|
| 105 |
+
return {split: self._generate_examples(split, self.builder_config.name)
|
| 106 |
+
for split in ('val', 'train', 'test')}
|
| 107 |
+
|
| 108 |
+
def _generate_examples(self, split: str, source: str):
|
| 109 |
+
"""Yields (key, example) tuples from test set."""
|
| 110 |
+
annot_fname = os.path.join(_CHARTQA_PATH, split, f'{split}_{source}.json')
|
| 111 |
+
|
| 112 |
+
with open(annot_fname, 'r') as f:
|
| 113 |
+
data = json.loads(f.read())
|
| 114 |
+
|
| 115 |
+
for idx, v in enumerate(data):
|
| 116 |
+
yield idx, {
|
| 117 |
+
'question_id': idx,
|
| 118 |
+
'image/filename': v['imgname'],
|
| 119 |
+
'image': os.path.join(_CHARTQA_PATH, split, 'png', v['imgname']),
|
| 120 |
+
'question': v['query'],
|
| 121 |
+
'answer': v['label'],
|
| 122 |
+
}
|
Tipsomaly/model/big_vision/datasets/coco35l/coco35l.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
# pylint: disable=line-too-long
|
| 16 |
+
r"""Generates COCO-35L in a TFDS-ready structure.
|
| 17 |
+
|
| 18 |
+
First, download the captions from https://google.github.io/crossmodal-3600/ and the images from https://cocodataset.org/#download.
|
| 19 |
+
The coco Karpathy split is available at http://cs.stanford.edu/people/karpathy/deepimagesent/caption_datasets.zip:
|
| 20 |
+
mkdir -p /tmp/data/coco35l/images
|
| 21 |
+
wget https://storage.googleapis.com/crossmodal-3600/coco_mt_train.jsonl.bz2 -P /tmp/data/coco35l
|
| 22 |
+
wget https://storage.googleapis.com/crossmodal-3600/coco_mt_dev.jsonl.bz2 -P /tmp/data/coco35l
|
| 23 |
+
bzip2 -dk /tmp/data/coco35l/coco_mt_train.jsonl.bz2 /tmp/data/coco35l/coco_mt_dev.jsonl.bz2
|
| 24 |
+
wget http://cs.stanford.edu/people/karpathy/deepimagesent/caption_datasets.zip -P /tmp/data/coco35l
|
| 25 |
+
unzip /tmp/data/coco35l/caption_datasets.zip -d /tmp/data/coco35l/
|
| 26 |
+
wget http://images.cocodataset.org/zips/train2014.zip -P /tmp/data/coco35l/images
|
| 27 |
+
wget http://images.cocodataset.org/zips/val2014.zip -P /tmp/data/coco35l/images
|
| 28 |
+
unzip /tmp/data/coco35l/images/train2014.zip -d /tmp/data/coco35l/images/
|
| 29 |
+
unzip /tmp/data/coco35l/images/val2014.zip -d /tmp/data/coco35l/images/
|
| 30 |
+
|
| 31 |
+
Then, run conversion locally (make sure to install tensorflow-datasets for the `tfds` util):
|
| 32 |
+
|
| 33 |
+
cd big_vision/datasets
|
| 34 |
+
env TFDS_DATA_DIR=/tmp/tfds tfds build --datasets=coco35l
|
| 35 |
+
|
| 36 |
+
Example to load:
|
| 37 |
+
|
| 38 |
+
import tensorflow_datasets as tfds
|
| 39 |
+
dataset = tfds.load(
|
| 40 |
+
'coco35l', split='dev_en',
|
| 41 |
+
data_dir='/tmp/tfds')
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
import json
|
| 45 |
+
import os.path
|
| 46 |
+
|
| 47 |
+
import tensorflow_datasets as tfds
|
| 48 |
+
|
| 49 |
+
_DESCRIPTION = """
|
| 50 |
+
COCO image + captions, translated from English to 35 languages (English incl.).
|
| 51 |
+
"""
|
| 52 |
+
|
| 53 |
+
# pylint: disable=line-too-long
|
| 54 |
+
_CITATION = """
|
| 55 |
+
@inproceedings{thapliyal-etal-2022-crossmodal,
|
| 56 |
+
title = "Crossmodal-3600: A Massively Multilingual Multimodal Evaluation Dataset",
|
| 57 |
+
author = "Thapliyal, Ashish V. and
|
| 58 |
+
Pont Tuset, Jordi and
|
| 59 |
+
Chen, Xi and
|
| 60 |
+
Soricut, Radu",
|
| 61 |
+
editor = "Goldberg, Yoav and
|
| 62 |
+
Kozareva, Zornitsa and
|
| 63 |
+
Zhang, Yue",
|
| 64 |
+
booktitle = "Proceedings of the 2022 Conference on Empirical Methods in Natural Language Processing",
|
| 65 |
+
month = dec,
|
| 66 |
+
year = "2022",
|
| 67 |
+
address = "Abu Dhabi, United Arab Emirates",
|
| 68 |
+
publisher = "Association for Computational Linguistics",
|
| 69 |
+
url = "https://aclanthology.org/2022.emnlp-main.45",
|
| 70 |
+
doi = "10.18653/v1/2022.emnlp-main.45",
|
| 71 |
+
pages = "715--729",
|
| 72 |
+
}
|
| 73 |
+
"""
|
| 74 |
+
# pylint: enable=line-too-long
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
_CAPTIONS_PATH = '/tmp/data/coco35l'
|
| 78 |
+
_IMAGES_PATH = '/tmp/data/mscoco/images'
|
| 79 |
+
_COCOCAPS_PATH = '/tmp/data/mscoco/dataset_coco.json'
|
| 80 |
+
|
| 81 |
+
LANGUAGES = [
|
| 82 |
+
'ar', 'bn', 'cs', 'da', 'de', 'el', 'en', 'es', 'fa', 'fi', 'fil', 'fr',
|
| 83 |
+
'he', 'hi', 'hr', 'hu', 'id', 'it', 'ja', 'ko', 'mi', 'nl', 'no', 'pl',
|
| 84 |
+
'pt', 'ro', 'ru', 'sv', 'sw', 'te', 'th', 'tr', 'uk', 'vi', 'zh',
|
| 85 |
+
]
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
class Coco35l(tfds.core.GeneratorBasedBuilder):
|
| 89 |
+
"""DatasetBuilder for COCO-35L dataset."""
|
| 90 |
+
|
| 91 |
+
VERSION = tfds.core.Version('1.0.0')
|
| 92 |
+
RELEASE_NOTES = {'1.0.0': 'First release.'}
|
| 93 |
+
|
| 94 |
+
def _info(self):
|
| 95 |
+
"""Returns the metadata."""
|
| 96 |
+
|
| 97 |
+
return tfds.core.DatasetInfo(
|
| 98 |
+
builder=self,
|
| 99 |
+
description=_DESCRIPTION,
|
| 100 |
+
features=tfds.features.FeaturesDict({
|
| 101 |
+
'image/id': tfds.features.Text(),
|
| 102 |
+
'image': tfds.features.Image(encoding_format='jpeg'),
|
| 103 |
+
'captions': tfds.features.Sequence(tfds.features.Text()),
|
| 104 |
+
'language': tfds.features.Text(),
|
| 105 |
+
}),
|
| 106 |
+
supervised_keys=None,
|
| 107 |
+
homepage='https://google.github.io/crossmodal-3600/',
|
| 108 |
+
citation=_CITATION,
|
| 109 |
+
)
|
| 110 |
+
|
| 111 |
+
def _split_generators(self, dl_manager: tfds.download.DownloadManager):
|
| 112 |
+
"""Returns SplitGenerators."""
|
| 113 |
+
splits = []
|
| 114 |
+
for lang in LANGUAGES:
|
| 115 |
+
splits.extend([f'train_{lang}', f'dev_{lang}'])
|
| 116 |
+
return {split: self._generate_examples(split) for split in splits}
|
| 117 |
+
|
| 118 |
+
def _generate_examples(self, split: str):
|
| 119 |
+
"""Yields (key, example) tuples from dataset."""
|
| 120 |
+
split, language = split.split('_')
|
| 121 |
+
|
| 122 |
+
id_to_path = dict()
|
| 123 |
+
with open(_COCOCAPS_PATH, 'r') as f:
|
| 124 |
+
data = json.load(f)['images']
|
| 125 |
+
for d in data:
|
| 126 |
+
id_to_path[d['cocoid']] = os.path.join(
|
| 127 |
+
_IMAGES_PATH, d['filepath'], d['filename']
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
annot_fname = os.path.join(_CAPTIONS_PATH, f'coco_mt_{split}.jsonl')
|
| 131 |
+
data = {}
|
| 132 |
+
with open(annot_fname, 'r') as f:
|
| 133 |
+
for line in f:
|
| 134 |
+
j = json.loads(line)
|
| 135 |
+
image_id = f'{j["image_id"].split("_")[0]}_{language}'
|
| 136 |
+
if image_id not in data:
|
| 137 |
+
data[image_id] = []
|
| 138 |
+
if language == 'en':
|
| 139 |
+
# COCO-35L was constructed from English into 35 other languages.
|
| 140 |
+
# To add English in our TFDS, we just select a language (eg. "de") to
|
| 141 |
+
# have each unique example, and add the corresponding source caption.
|
| 142 |
+
if j['trg_lang'] == 'de':
|
| 143 |
+
data[image_id].append(j['caption_tokenized'])
|
| 144 |
+
else:
|
| 145 |
+
if j['trg_lang'] == language:
|
| 146 |
+
data[image_id].append(j['translation_tokenized'])
|
| 147 |
+
|
| 148 |
+
for image_id, captions in data.items():
|
| 149 |
+
yield image_id, {
|
| 150 |
+
'image/id': image_id,
|
| 151 |
+
'image': id_to_path[int(image_id.split('_')[0])],
|
| 152 |
+
'captions': captions,
|
| 153 |
+
'language': language,
|
| 154 |
+
}
|
Tipsomaly/model/big_vision/datasets/countbenchqa/countbenchqa.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
# pylint: disable=line-too-long
|
| 16 |
+
"""Import CountBenchQA dataset (CountBench dataset with added QA annotations).
|
| 17 |
+
|
| 18 |
+
It's small data, so simple to run locally. First, download all the data:
|
| 19 |
+
|
| 20 |
+
mkdir /tmp/data/ ; cd /tmp/data
|
| 21 |
+
wget https://huggingface.co/datasets/nielsr/countbench/resolve/main/data/train-00000-of-00001-cf54c241ba947306.parquet
|
| 22 |
+
wget https://raw.githubusercontent.com/teaching-clip-to-count/teaching-clip-to-count.github.io/main/CountBench.json
|
| 23 |
+
|
| 24 |
+
Then, update the PATHs below and run conversion locally like so:
|
| 25 |
+
|
| 26 |
+
cd big_vision/datasets
|
| 27 |
+
env TFDS_DATA_DIR=/tmp/tfds tfds build --datasets=countbenchqa
|
| 28 |
+
|
| 29 |
+
The dataset contains 540 images so the dataset creation is very quick.
|
| 30 |
+
|
| 31 |
+
There is a single split called huggingface to denote that the images come from
|
| 32 |
+
the hugginface parquet file.
|
| 33 |
+
"""
|
| 34 |
+
|
| 35 |
+
import io
|
| 36 |
+
import json
|
| 37 |
+
|
| 38 |
+
import numpy as np
|
| 39 |
+
import pandas as pd
|
| 40 |
+
import PIL
|
| 41 |
+
import tensorflow_datasets as tfds
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
# Huggingface dataset path; this is missing about 10% of the images.
|
| 45 |
+
_COUNTBENCH_PARQUET_PATH = '/tmp/data/train-00000-of-00001-cf54c241ba947306.parquet'
|
| 46 |
+
# Public path to the original CountBench JSON file.
|
| 47 |
+
_COUNTBENCH_JSON_PATH = '/tmp/data/CountBench.json'
|
| 48 |
+
# VQA annotations
|
| 49 |
+
_QA_JSON_PATH = 'countbenchqa/data/countbench_paired_questions.json'
|
| 50 |
+
|
| 51 |
+
_DESCRIPTION = """
|
| 52 |
+
CountBench: We introduce a new object counting benchmark called CountBench,
|
| 53 |
+
automatically curated (and manually verified) from the publicly available
|
| 54 |
+
LAION-400M image-text dataset. CountBench contains a total of 540 images
|
| 55 |
+
containing between two and ten instances of a particular object, where their
|
| 56 |
+
corresponding captions reflect this number.
|
| 57 |
+
|
| 58 |
+
CountBenchQA: Each image is paired with a manually generated question about the
|
| 59 |
+
number of objects in the image to turn CountBench into a VQA task.
|
| 60 |
+
"""
|
| 61 |
+
|
| 62 |
+
_CITATION = """
|
| 63 |
+
@article{beyer2024paligemma,
|
| 64 |
+
title={{PaliGemma: A versatile 3B VLM for transfer}},
|
| 65 |
+
author={Lucas Beyer and Andreas Steiner and André Susano Pinto and Alexander Kolesnikov and Xiao Wang and Daniel Salz and Maxim Neumann and Ibrahim Alabdulmohsin and Michael Tschannen and Emanuele Bugliarello and Thomas Unterthiner and Daniel Keysers and Skanda Koppula and Fangyu Liu and Adam Grycner and Alexey Gritsenko and Neil Houlsby and Manoj Kumar and Keran Rong and Julian Eisenschlos and Rishabh Kabra and Matthias Bauer and Matko Bošnjak and Xi Chen and Matthias Minderer and Paul Voigtlaender and Ioana Bica and Ivana Balazevic and Joan Puigcerver and Pinelopi Papalampidi and Olivier Henaff and Xi Xiong and Radu Soricut and Jeremiah Harmsen and Xiaohua Zhai},
|
| 66 |
+
year={2024},
|
| 67 |
+
journal={arXiv preprint arXiv:2407.07726}
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
@article{paiss2023countclip,
|
| 71 |
+
title={{Teaching CLIP to Count to Ten}},
|
| 72 |
+
author={Paiss, Roni and Ephrat, Ariel and Tov, Omer and Zada, Shiran and Mosseri, Inbar and Irani, Michal and Dekel, Tali},
|
| 73 |
+
year={2023},
|
| 74 |
+
journal={arXiv preprint arXiv:2302.12066}
|
| 75 |
+
}
|
| 76 |
+
"""
|
| 77 |
+
|
| 78 |
+
_HOMEPAGE = 'https://teaching-clip-to-count.github.io/'
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
class CountbenchQA(tfds.core.GeneratorBasedBuilder):
|
| 82 |
+
"""Create CountbenchQA dataset."""
|
| 83 |
+
|
| 84 |
+
VERSION = tfds.core.Version('1.2.0')
|
| 85 |
+
RELEASE_NOTES = {'1.1.0': 'Add `huggingface` split.',
|
| 86 |
+
'1.2.0': 'Fix image loading for `huggingface` split.'}
|
| 87 |
+
MANUAL_DOWNLOAD_INSTRUCTIONS = """
|
| 88 |
+
There are two parts which should be downloaded:
|
| 89 |
+
* Countbench from Huggingface
|
| 90 |
+
* Questions found in `data/countbench_paired_questions.json`
|
| 91 |
+
"""
|
| 92 |
+
|
| 93 |
+
def _info(self) -> tfds.core.DatasetInfo:
|
| 94 |
+
"""Returns the dataset metadata."""
|
| 95 |
+
features = tfds.features.FeaturesDict({
|
| 96 |
+
'image': tfds.features.Image(shape=(None, None, 3)),
|
| 97 |
+
'image_id': tfds.features.Scalar(dtype=np.int32),
|
| 98 |
+
'question': tfds.features.Text(),
|
| 99 |
+
'text': tfds.features.Text(),
|
| 100 |
+
'image_url': tfds.features.Text(),
|
| 101 |
+
'number': tfds.features.Scalar(dtype=np.int32),
|
| 102 |
+
})
|
| 103 |
+
|
| 104 |
+
return tfds.core.DatasetInfo(
|
| 105 |
+
builder=self,
|
| 106 |
+
features=features,
|
| 107 |
+
description=_DESCRIPTION,
|
| 108 |
+
supervised_keys=None,
|
| 109 |
+
homepage=_HOMEPAGE,
|
| 110 |
+
citation=_CITATION,
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
def _split_generators(self, dl_manager: tfds.download.DownloadManager):
|
| 114 |
+
"""Call the function which defines the splits."""
|
| 115 |
+
del dl_manager
|
| 116 |
+
return {
|
| 117 |
+
'huggingface': self._generate_examples(split='huggingface'),
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
def _generate_examples_hf(self):
|
| 121 |
+
"""Generate examples from Huggingface parquet file.
|
| 122 |
+
|
| 123 |
+
Note that the parquet file provided on Huggingface is missing about 10%
|
| 124 |
+
of the images as can be verified by running
|
| 125 |
+
```
|
| 126 |
+
import pyarrow.parquet as pq
|
| 127 |
+
with open(_COUNTBENCH_PARQUET_PATH, 'rb') as f:
|
| 128 |
+
x = pq.read_table(f)
|
| 129 |
+
sum([x['image'][i].is_valid for i in range(len(x['image']))]) # result: 491
|
| 130 |
+
```
|
| 131 |
+
|
| 132 |
+
Yields:
|
| 133 |
+
An index and a dictionary with features.
|
| 134 |
+
"""
|
| 135 |
+
with open(_COUNTBENCH_PARQUET_PATH, 'rb') as f:
|
| 136 |
+
df = pd.read_parquet(f)
|
| 137 |
+
|
| 138 |
+
with open(_QA_JSON_PATH, 'r') as fq:
|
| 139 |
+
df_question = pd.read_json(fq)
|
| 140 |
+
|
| 141 |
+
df['question'] = df_question
|
| 142 |
+
|
| 143 |
+
for idx, row in df.iterrows():
|
| 144 |
+
# Some entries have no image.
|
| 145 |
+
if row['image'] is None:
|
| 146 |
+
continue
|
| 147 |
+
image = np.array(PIL.Image.open(io.BytesIO(row['image']['bytes'])))
|
| 148 |
+
if len(image.shape) != 3:
|
| 149 |
+
continue # Filter out one bad image.
|
| 150 |
+
countbenchqa_dict = {
|
| 151 |
+
'image': image,
|
| 152 |
+
'image_id': idx,
|
| 153 |
+
'question': row['question'],
|
| 154 |
+
'text': row['text'],
|
| 155 |
+
'image_url': row['image_url'],
|
| 156 |
+
'number': row['number'],
|
| 157 |
+
}
|
| 158 |
+
yield idx, countbenchqa_dict
|
| 159 |
+
|
| 160 |
+
def _generate_examples(self, split: str):
|
| 161 |
+
if split == 'huggingface':
|
| 162 |
+
yield from self._generate_examples_hf()
|
| 163 |
+
else:
|
| 164 |
+
raise ValueError(f'Unknown split: {split}')
|
Tipsomaly/model/big_vision/datasets/docvqa/docvqa.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
# pylint: disable=line-too-long
|
| 16 |
+
r"""Implements DocVQA in TFDS structure.
|
| 17 |
+
|
| 18 |
+
It's small data, so simple to run locally. First, copy the data to local disk.
|
| 19 |
+
An account will be needed in https://rrc.cvc.uab.es/?ch=17&com=downloads and
|
| 20 |
+
from there the task annotations and images can be fetched separatedly.
|
| 21 |
+
|
| 22 |
+
mkdir -p /tmp/data/docvqa
|
| 23 |
+
<COPY AND DECOMPRESS DOWNLOADED FILES HERE>
|
| 24 |
+
|
| 25 |
+
Then, run conversion locally (make sure to install tensorflow-datasets for the `tfds` util):
|
| 26 |
+
|
| 27 |
+
cd big_vision/datasets
|
| 28 |
+
env TFDS_DATA_DIR=/tmp/tfds tfds build --datasets=docvqa
|
| 29 |
+
|
| 30 |
+
Example to load:
|
| 31 |
+
|
| 32 |
+
import tensorflow_datasets as tfds
|
| 33 |
+
dataset = tfds.load('docvqa', split='val', data_dir='/tmp/tfds')
|
| 34 |
+
"""
|
| 35 |
+
import json
|
| 36 |
+
import os
|
| 37 |
+
|
| 38 |
+
import numpy as np
|
| 39 |
+
import tensorflow_datasets as tfds
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
_DESCRIPTION = """DocVQA dataset."""
|
| 43 |
+
|
| 44 |
+
# pylint: disable=line-too-long
|
| 45 |
+
_CITATION = """
|
| 46 |
+
@article{DBLP:journals/corr/abs-2007-00398,
|
| 47 |
+
author = {Minesh Mathew and
|
| 48 |
+
Dimosthenis Karatzas and
|
| 49 |
+
R. Manmatha and
|
| 50 |
+
C. V. Jawahar},
|
| 51 |
+
title = {DocVQA: {A} Dataset for {VQA} on Document Images},
|
| 52 |
+
journal = {CoRR},
|
| 53 |
+
volume = {abs/2007.00398},
|
| 54 |
+
year = {2020},
|
| 55 |
+
url = {https://arxiv.org/abs/2007.00398},
|
| 56 |
+
eprinttype = {arXiv},
|
| 57 |
+
eprint = {2007.00398},
|
| 58 |
+
timestamp = {Mon, 06 Jul 2020 15:26:01 +0200},
|
| 59 |
+
biburl = {https://dblp.org/rec/journals/corr/abs-2007-00398.bib},
|
| 60 |
+
bibsource = {dblp computer science bibliography, https://dblp.org}
|
| 61 |
+
}
|
| 62 |
+
"""
|
| 63 |
+
# pylint: enable=line-too-long
|
| 64 |
+
|
| 65 |
+
# When running locally (recommended), copy files as above an use these:
|
| 66 |
+
_DOCVQA_PATH = '/tmp/data/docvqa/'
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
class DocVQA(tfds.core.GeneratorBasedBuilder):
|
| 70 |
+
"""DatasetBuilder for DocVQA dataset."""
|
| 71 |
+
|
| 72 |
+
VERSION = tfds.core.Version('1.0.0')
|
| 73 |
+
RELEASE_NOTES = {'1.0.0': 'First release.'}
|
| 74 |
+
|
| 75 |
+
def _info(self):
|
| 76 |
+
"""Returns the metadata."""
|
| 77 |
+
return tfds.core.DatasetInfo(
|
| 78 |
+
builder=self,
|
| 79 |
+
description=_DESCRIPTION,
|
| 80 |
+
features=tfds.features.FeaturesDict({
|
| 81 |
+
'question_id': tfds.features.Scalar(np.int32),
|
| 82 |
+
'image/filename': tfds.features.Text(),
|
| 83 |
+
'image': tfds.features.Image(encoding_format='png'),
|
| 84 |
+
'question': tfds.features.Text(),
|
| 85 |
+
'answers': tfds.features.Sequence(tfds.features.Text()),
|
| 86 |
+
}),
|
| 87 |
+
supervised_keys=None,
|
| 88 |
+
homepage='https://www.docvqa.org/',
|
| 89 |
+
citation=_CITATION,
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
def _split_generators(self, dl_manager: tfds.download.DownloadManager):
|
| 93 |
+
"""Returns SplitGenerators."""
|
| 94 |
+
return {split: self._generate_examples(split)
|
| 95 |
+
for split in ('val', 'train', 'test')}
|
| 96 |
+
|
| 97 |
+
def _generate_examples(self, split: str):
|
| 98 |
+
"""Yields (key, example) tuples from split."""
|
| 99 |
+
suffix = '' if split == 'test' else '_withQT'
|
| 100 |
+
with open(os.path.join(_DOCVQA_PATH, f'{split}_v1.0{suffix}.json')) as f:
|
| 101 |
+
data = json.load(f)
|
| 102 |
+
for v in data['data']:
|
| 103 |
+
question_id = v['questionId']
|
| 104 |
+
yield question_id, {
|
| 105 |
+
'question_id': question_id,
|
| 106 |
+
'image/filename': v['image'],
|
| 107 |
+
'image': os.path.join(_DOCVQA_PATH, split, v['image']),
|
| 108 |
+
'question': v['question'],
|
| 109 |
+
'answers': v.get('answers', []),
|
| 110 |
+
}
|
Tipsomaly/model/big_vision/datasets/gqa/gqa.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
# pylint: disable=line-too-long
|
| 16 |
+
r"""Generates GQA in a TFDS-ready structure, using Beam.
|
| 17 |
+
|
| 18 |
+
Instructions below are to generate the dataset with a *local* Beam pipeline.
|
| 19 |
+
It's advisable to run the Beam job on Google Cloud Dataflow, see
|
| 20 |
+
https://www.tensorflow.org/datasets/beam_datasets.
|
| 21 |
+
for more details, which would significantly speed up generation. This would
|
| 22 |
+
involve uploading the locally downloaded data to a GCS bucket, and then
|
| 23 |
+
adding in the Beam pipeline options and your GCP/GCS bucket details
|
| 24 |
+
to the `tfds build` command below (as detailed in the link).
|
| 25 |
+
|
| 26 |
+
First, copy the data to local disk:
|
| 27 |
+
|
| 28 |
+
mkdir -p /tmp/data/gqa
|
| 29 |
+
wget -O /tmp/data/gqa/question1.2.zip https://downloads.cs.stanford.edu/nlp/data/gqa/questions1.2.zip?download=true
|
| 30 |
+
unzip /tmp/data/gqa/question1.2.zip
|
| 31 |
+
mv /tmp/data/gqa/question1.2/* /tmp/data/gqa/
|
| 32 |
+
wget -O /tmp/data/gqa/images.zip https://downloads.cs.stanford.edu/nlp/data/gqa/images.zip?download=true
|
| 33 |
+
unzip /tmp/data/gqa/images.zip
|
| 34 |
+
|
| 35 |
+
Then, run conversion (make sure to install tensorflow-datasets for the `tfds` util):
|
| 36 |
+
|
| 37 |
+
cd big_vision/datasets
|
| 38 |
+
env TFDS_DATA_DIR=/tmp/tfds tfds build --datasets=gqa
|
| 39 |
+
|
| 40 |
+
Example to load:
|
| 41 |
+
|
| 42 |
+
import tensorflow_datasets as tfds
|
| 43 |
+
dataset = tfds.load('gqa', split='testdev_balanced', data_dir='/tmp/tfds')
|
| 44 |
+
|
| 45 |
+
Some statistics:
|
| 46 |
+
train_all: 14305356 examples
|
| 47 |
+
train_balanced: 943000 examples
|
| 48 |
+
val_all: 2011853 examples
|
| 49 |
+
val_balanced: 132062 examples
|
| 50 |
+
testdev_all: 172174 examples
|
| 51 |
+
testdev_balanced: 12578 examples
|
| 52 |
+
"""
|
| 53 |
+
import glob
|
| 54 |
+
import json
|
| 55 |
+
import os
|
| 56 |
+
|
| 57 |
+
import numpy as np
|
| 58 |
+
import tensorflow_datasets as tfds
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
_DESCRIPTION = """GQA: Visual Reasoning in the Real World."""
|
| 62 |
+
|
| 63 |
+
# pylint: disable=line-too-long
|
| 64 |
+
_CITATION = """
|
| 65 |
+
@article{DBLP:journals/corr/abs-2306-14610,
|
| 66 |
+
author = {Drew Hudson and
|
| 67 |
+
Christopher Manning},
|
| 68 |
+
title = {GQA: A New Dataset for Real-World Visual Reasoning and Compositional Question Answering},
|
| 69 |
+
journal = {CVPR},
|
| 70 |
+
volume = {abs/1902.09506},
|
| 71 |
+
year = {2019},
|
| 72 |
+
url = {https://doi.org/10.48550/arXiv.1902.09506},
|
| 73 |
+
doi = {10.48550/arXiv.1902.09506},
|
| 74 |
+
eprinttype = {arXiv},
|
| 75 |
+
eprint = {1902.09506},
|
| 76 |
+
timestamp = {Tue, 25 Jun 2019 00:00:00 +0100},
|
| 77 |
+
biburl = {https://dblp.org/rec/journals/corr/abs-1902-09506},
|
| 78 |
+
bibsource = {dblp computer science bibliography, https://dblp.org}
|
| 79 |
+
}
|
| 80 |
+
"""
|
| 81 |
+
# pylint: enable=line-too-long
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
_DATA_PATH = '/tmp/data/gqa/'
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class GQA(tfds.core.GeneratorBasedBuilder):
|
| 88 |
+
"""DatasetBuilder for GQA dataset."""
|
| 89 |
+
|
| 90 |
+
VERSION = tfds.core.Version('1.0.0')
|
| 91 |
+
RELEASE_NOTES = {'1.0.0': 'First release.'}
|
| 92 |
+
|
| 93 |
+
def _info(self):
|
| 94 |
+
"""Returns the metadata."""
|
| 95 |
+
|
| 96 |
+
return tfds.core.DatasetInfo(
|
| 97 |
+
builder=self,
|
| 98 |
+
description=_DESCRIPTION,
|
| 99 |
+
features=tfds.features.FeaturesDict({
|
| 100 |
+
'example_id': tfds.features.Scalar(np.int64),
|
| 101 |
+
'image/id': tfds.features.Text(),
|
| 102 |
+
'image': tfds.features.Image(encoding_format='jpeg'),
|
| 103 |
+
'question': tfds.features.Text(),
|
| 104 |
+
'answer': tfds.features.Text(),
|
| 105 |
+
'full_answer': tfds.features.Text(),
|
| 106 |
+
'is_balanced': tfds.features.Scalar(np.bool_),
|
| 107 |
+
}),
|
| 108 |
+
homepage='https://cs.stanford.edu/people/dorarad/gqa/',
|
| 109 |
+
citation=_CITATION,
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
def _split_generators(self, dl_manager: tfds.download.DownloadManager):
|
| 113 |
+
"""Returns SplitGenerators."""
|
| 114 |
+
splits = [
|
| 115 |
+
# 'debug',
|
| 116 |
+
'train_all',
|
| 117 |
+
'train_balanced',
|
| 118 |
+
'testdev_all',
|
| 119 |
+
'testdev_balanced',
|
| 120 |
+
'val_all',
|
| 121 |
+
'val_balanced',
|
| 122 |
+
'challenge_all',
|
| 123 |
+
'challenge_balanced',
|
| 124 |
+
]
|
| 125 |
+
return {split: self._generate_examples(split) for split in splits}
|
| 126 |
+
|
| 127 |
+
def _generate_examples(self, split: str):
|
| 128 |
+
"""Yields (key, example) tuples from dataset."""
|
| 129 |
+
if split == 'train_all':
|
| 130 |
+
train_json_dir = os.path.join(_DATA_PATH, 'train_all_questions', '*.json')
|
| 131 |
+
json_files = glob.glob(train_json_dir)
|
| 132 |
+
else:
|
| 133 |
+
json_files = [os.path.join(_DATA_PATH, f'{split}_questions.json')]
|
| 134 |
+
|
| 135 |
+
def _prepare_data(json_path):
|
| 136 |
+
with open(os.path.join(json_path)) as f:
|
| 137 |
+
annotations = json.load(f)
|
| 138 |
+
return [(k, v) for k, v in annotations.items()]
|
| 139 |
+
|
| 140 |
+
def _process_example(entry):
|
| 141 |
+
question_id, question_data = entry
|
| 142 |
+
image_id = question_data['imageId']
|
| 143 |
+
image_path = os.path.join(_DATA_PATH, 'images', f'{image_id}.jpg')
|
| 144 |
+
answer = question_data['answer'] if 'answer' in question_data else ''
|
| 145 |
+
if 'fullAnswer' in question_data:
|
| 146 |
+
full_answer = question_data['fullAnswer']
|
| 147 |
+
else:
|
| 148 |
+
full_answer = ''
|
| 149 |
+
|
| 150 |
+
example = {
|
| 151 |
+
'example_id': question_id,
|
| 152 |
+
'image/id': image_id,
|
| 153 |
+
'image': image_path,
|
| 154 |
+
'question': question_data['question'],
|
| 155 |
+
'answer': answer,
|
| 156 |
+
'full_answer': full_answer,
|
| 157 |
+
'is_balanced': question_data['isBalanced'],
|
| 158 |
+
}
|
| 159 |
+
return question_id, example
|
| 160 |
+
|
| 161 |
+
beam = tfds.core.lazy_imports.apache_beam
|
| 162 |
+
return (
|
| 163 |
+
beam.Create(json_files)
|
| 164 |
+
| beam.FlatMap(_prepare_data)
|
| 165 |
+
| beam.Reshuffle()
|
| 166 |
+
| beam.Map(_process_example)
|
| 167 |
+
)
|
Tipsomaly/model/big_vision/datasets/imagenet/class_names.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
Tipsomaly/model/big_vision/datasets/infovqa/infovqa.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
# pylint: disable=line-too-long
|
| 16 |
+
r"""Implements InfoVqa in TFDS structure.
|
| 17 |
+
|
| 18 |
+
First, download and unzip the dataset from https://rrc.cvc.uab.es/?ch=17
|
| 19 |
+
and place it in /tmp/data/infovqa.
|
| 20 |
+
|
| 21 |
+
Then, run conversion locally (make sure to install tensorflow-datasets for the `tfds` util):
|
| 22 |
+
|
| 23 |
+
cd third_party/py/big_vision/datasets
|
| 24 |
+
env TFDS_DATA_DIR=/tmp/tfds tfds build --datasets=infovqa
|
| 25 |
+
|
| 26 |
+
Example to load:
|
| 27 |
+
|
| 28 |
+
import tensorflow_datasets as tfds
|
| 29 |
+
dataset = tfds.load('infovqa', split='train', data_dir='/tmp/tfds')
|
| 30 |
+
|
| 31 |
+
Dataset splits:
|
| 32 |
+
train: 23946 examples/questions (4406 images)
|
| 33 |
+
val: 2801 examples/questions (500 images)
|
| 34 |
+
test: 3288 examples/questions (579 images) (no answers)
|
| 35 |
+
|
| 36 |
+
Recommended training splits:
|
| 37 |
+
train: train[:95%] (22749 examples/questions)
|
| 38 |
+
minitrain: train[:5%] (1197 examples/questions)
|
| 39 |
+
minival: train[95%:] (1197 examples/questions)
|
| 40 |
+
eval: val (2801 examples/questions)
|
| 41 |
+
|
| 42 |
+
Note that according to task description in
|
| 43 |
+
https://rrc.cvc.uab.es/?ch=17&com=tasks:
|
| 44 |
+
- Order of items in a multi span answer does not matter. Therefore, we include
|
| 45 |
+
all permutations of the answer in the val split.
|
| 46 |
+
- Answers are not case sensitive. We leave it to the user to lower case
|
| 47 |
+
answers if they want to.
|
| 48 |
+
"""
|
| 49 |
+
import itertools
|
| 50 |
+
import json
|
| 51 |
+
import os
|
| 52 |
+
|
| 53 |
+
import numpy as np
|
| 54 |
+
import tensorflow_datasets as tfds
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
_DESCRIPTION = """InfographicVQA dataset."""
|
| 58 |
+
|
| 59 |
+
# pylint: disable=line-too-long
|
| 60 |
+
_CITATION = """
|
| 61 |
+
@inproceedings{Mathew_2022,
|
| 62 |
+
title={InfographicVQA},
|
| 63 |
+
url={http://dx.doi.org/10.1109/WACV51458.2022.00264},
|
| 64 |
+
DOI={10.1109/wacv51458.2022.00264},
|
| 65 |
+
booktitle={2022 IEEE/CVF Winter Conference on Applications of Computer Vision (WACV)},
|
| 66 |
+
publisher={IEEE},
|
| 67 |
+
author={Mathew, Minesh and Bagal, Viraj and Tito, Ruben and Karatzas, Dimosthenis and Valveny, Ernest and Jawahar, C. V.},
|
| 68 |
+
year={2022},
|
| 69 |
+
month=jan }
|
| 70 |
+
"""
|
| 71 |
+
# pylint: enable=line-too-long
|
| 72 |
+
|
| 73 |
+
# When running locally (recommended), copy files as above an use these:
|
| 74 |
+
_INFOVQA_PATH = '/tmp/data/infovqa/'
|
| 75 |
+
_ANNOTATIONS = {
|
| 76 |
+
'train': 'infographicsVQA_train_v1.0.json',
|
| 77 |
+
'val': 'infographicsVQA_val_v1.0_withQT.json',
|
| 78 |
+
'test': 'infographicsVQA_test_v1.0.json',
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
class Infovqa(tfds.core.GeneratorBasedBuilder):
|
| 83 |
+
"""DatasetBuilder for infovqa dataset."""
|
| 84 |
+
|
| 85 |
+
VERSION = tfds.core.Version('1.1.0')
|
| 86 |
+
RELEASE_NOTES = {
|
| 87 |
+
'1.0.0': 'First release.',
|
| 88 |
+
'1.1.0': 'Add multi-span permutations to the val split answers.',
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
def _info(self):
|
| 92 |
+
"""Returns the metadata."""
|
| 93 |
+
|
| 94 |
+
return tfds.core.DatasetInfo(
|
| 95 |
+
builder=self,
|
| 96 |
+
description=_DESCRIPTION,
|
| 97 |
+
features=tfds.features.FeaturesDict({
|
| 98 |
+
'question_id': tfds.features.Scalar(np.int32),
|
| 99 |
+
'filename': tfds.features.Text(),
|
| 100 |
+
'image': tfds.features.Image(encoding_format='jpeg'),
|
| 101 |
+
'question': tfds.features.Text(),
|
| 102 |
+
'answers': tfds.features.Sequence(tfds.features.Text()),
|
| 103 |
+
}),
|
| 104 |
+
supervised_keys=None,
|
| 105 |
+
homepage='https://www.docvqa.org/datasets/infographicvqa',
|
| 106 |
+
citation=_CITATION,
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
def _split_generators(self, dl_manager: tfds.download.DownloadManager):
|
| 110 |
+
"""Returns SplitGenerators."""
|
| 111 |
+
return {split: self._generate_examples(split)
|
| 112 |
+
for split in ('train', 'val', 'test')}
|
| 113 |
+
|
| 114 |
+
def _generate_examples(self, split):
|
| 115 |
+
"""Yields (key, example) tuples from test set."""
|
| 116 |
+
annot_fname = os.path.join(_INFOVQA_PATH, _ANNOTATIONS[split])
|
| 117 |
+
with open(annot_fname, 'r') as f:
|
| 118 |
+
data = json.loads(f.read())
|
| 119 |
+
|
| 120 |
+
for x in data['data']:
|
| 121 |
+
yield x['questionId'], {
|
| 122 |
+
'question_id': x['questionId'],
|
| 123 |
+
'filename': x['image_local_name'],
|
| 124 |
+
'image': os.path.join(_INFOVQA_PATH, 'images', x['image_local_name']),
|
| 125 |
+
'question': x['question'],
|
| 126 |
+
'answers': maybe_permute(x.get('answers', []), split),
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def maybe_permute(answers, split):
|
| 131 |
+
if split != 'val':
|
| 132 |
+
return answers
|
| 133 |
+
new_answers = []
|
| 134 |
+
for x in answers:
|
| 135 |
+
if ', ' in x: # Create all permutations.
|
| 136 |
+
# The first element remains the same.
|
| 137 |
+
new_answers.extend([', '.join(y)
|
| 138 |
+
for y in itertools.permutations(x.split(', '))])
|
| 139 |
+
else:
|
| 140 |
+
new_answers.append(x)
|
| 141 |
+
return new_answers
|
Tipsomaly/model/big_vision/datasets/okvqa/okvqa.py
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
# pylint: disable=line-too-long
|
| 16 |
+
r"""Implements the OKVQA dataset for TFDS.
|
| 17 |
+
|
| 18 |
+
Download the required files from https://okvqa.allenai.org/download.html:
|
| 19 |
+
|
| 20 |
+
mkdir -p /tmp/tfds
|
| 21 |
+
cd /tmp/tfds/
|
| 22 |
+
wget http://images.cocodataset.org/zips/train2014.zip
|
| 23 |
+
wget http://images.cocodataset.org/zips/val2014.zip
|
| 24 |
+
wget https://okvqa.allenai.org/static/data/mscoco_train2014_annotations.json.zip
|
| 25 |
+
wget https://okvqa.allenai.org/static/data/mscoco_val2014_annotations.json.zip
|
| 26 |
+
wget https://okvqa.allenai.org/static/data/OpenEnded_mscoco_train2014_questions.json.zip
|
| 27 |
+
wget https://okvqa.allenai.org/static/data/OpenEnded_mscoco_val2014_questions.json.zip
|
| 28 |
+
unzip val2014.zip
|
| 29 |
+
unzip train2014.zip
|
| 30 |
+
unzip OpenEnded_mscoco_train2014_questions.json.zip
|
| 31 |
+
unzip OpenEnded_mscoco_val2014_questions.json.zip
|
| 32 |
+
unzip mscoco_train2014_annotations.json.zip
|
| 33 |
+
unzip mscoco_val2014_annotations.json.zip
|
| 34 |
+
|
| 35 |
+
Then, run conversion locally (make sure to install tensorflow-datasets for the
|
| 36 |
+
`tfds` util):
|
| 37 |
+
|
| 38 |
+
cd big_vision/datasets
|
| 39 |
+
env TFDS_DATA_DIR=/tmp/tfds tfds build --datasets=okvqa
|
| 40 |
+
|
| 41 |
+
Example to load:
|
| 42 |
+
|
| 43 |
+
import tensorflow_datasets as tfds
|
| 44 |
+
dataset = tfds.load('okvqa', split='val', data_dir='/tmp/tfds')
|
| 45 |
+
"""
|
| 46 |
+
|
| 47 |
+
import json
|
| 48 |
+
import os
|
| 49 |
+
from typing import Any
|
| 50 |
+
import numpy as np
|
| 51 |
+
import tensorflow_datasets as tfds
|
| 52 |
+
|
| 53 |
+
_DESCRIPTION = """
|
| 54 |
+
OKVQA addresses the task of VQA with outside knowledge.
|
| 55 |
+
This version of the dataset contains:
|
| 56 |
+
- Questions + Answers from OKVQA.
|
| 57 |
+
- Images from COCO.
|
| 58 |
+
"""
|
| 59 |
+
|
| 60 |
+
_CITATION = """
|
| 61 |
+
@InProceedings{okvqa,
|
| 62 |
+
author = {Kenneth Marino and Mohammad Rastegari and Ali Farhadi and Roozbeh Mottaghi},
|
| 63 |
+
title = {OK-VQA: A Visual Question Answering Benchmark Requiring External Knowledge},
|
| 64 |
+
booktitle = {Conference on Computer Vision and Pattern Recognition (CVPR)},
|
| 65 |
+
year = {2019},
|
| 66 |
+
}
|
| 67 |
+
"""
|
| 68 |
+
|
| 69 |
+
ANNOTATION_FILE = {
|
| 70 |
+
'train': 'mscoco_train2014_annotations.json',
|
| 71 |
+
'val': 'mscoco_val2014_annotations.json',
|
| 72 |
+
}
|
| 73 |
+
QUESTIONS_FILE = {
|
| 74 |
+
'train': 'OpenEnded_mscoco_train2014_questions.json',
|
| 75 |
+
'val': 'OpenEnded_mscoco_val2014_questions.json',
|
| 76 |
+
}
|
| 77 |
+
QUESTION_TYPES = {
|
| 78 |
+
'one': 'Vehicles and Transportation',
|
| 79 |
+
'two': 'Brands, Companies and Products',
|
| 80 |
+
'three': 'Objects, Material and Clothing',
|
| 81 |
+
'four': 'Sports and Recreation',
|
| 82 |
+
'five': 'Cooking and Food',
|
| 83 |
+
'six': 'Geography, History, Language and Culture',
|
| 84 |
+
'seven': 'People and Everyday life',
|
| 85 |
+
'eight': 'Plants and Animals',
|
| 86 |
+
'nine': 'Science and Technology',
|
| 87 |
+
'ten': 'Weather and Climate',
|
| 88 |
+
'other': 'Other',
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
# When running locally (recommended), copy files as above an use these:
|
| 93 |
+
_OKVQA_PATH = '/media/scratch/okvqa'
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
class OkVqa(tfds.core.GeneratorBasedBuilder):
|
| 97 |
+
"""Import COCO dataset for OKVQA with KAT features."""
|
| 98 |
+
|
| 99 |
+
VERSION = tfds.core.Version('1.0.0')
|
| 100 |
+
RELEASE_NOTES = {'1.0.0': 'Changed to array record format.'}
|
| 101 |
+
MANUAL_DOWNLOAD_INSTRUCTIONS = """
|
| 102 |
+
In manual_dir/ you should have a directory okvqa which contains the
|
| 103 |
+
following files and directories:
|
| 104 |
+
From the OKVQA dataset:
|
| 105 |
+
- mscoco_train2014_annotations.json
|
| 106 |
+
- mscoco_val2014_annotations.json
|
| 107 |
+
- OpenEnded_mscoco_train2014_questions.json
|
| 108 |
+
- OpenEnded_mscoco_val2014_questions.json
|
| 109 |
+
- train2014.zip
|
| 110 |
+
- val2014.zip
|
| 111 |
+
"""
|
| 112 |
+
|
| 113 |
+
def _info(self) -> tfds.core.DatasetInfo:
|
| 114 |
+
"""Returns the dataset metadata."""
|
| 115 |
+
features = tfds.features.FeaturesDict({
|
| 116 |
+
'image': tfds.features.Image(shape=(None, None, 3)),
|
| 117 |
+
'image_id': tfds.features.Scalar(dtype=np.int64),
|
| 118 |
+
'answer_type': tfds.features.Text(),
|
| 119 |
+
'answers': tfds.features.Sequence(tfds.features.Text()),
|
| 120 |
+
'answers_confidence': tfds.features.Tensor(shape=[10], dtype=np.bool_),
|
| 121 |
+
'answers_raw': tfds.features.Sequence(tfds.features.Text()),
|
| 122 |
+
'question_id': tfds.features.Scalar(dtype=np.int64),
|
| 123 |
+
'question_type': tfds.features.Text(),
|
| 124 |
+
'question_type_readable': tfds.features.Text(),
|
| 125 |
+
'question': tfds.features.Text(),
|
| 126 |
+
})
|
| 127 |
+
|
| 128 |
+
return tfds.core.DatasetInfo(
|
| 129 |
+
builder=self,
|
| 130 |
+
features=features,
|
| 131 |
+
description=_DESCRIPTION,
|
| 132 |
+
supervised_keys=None,
|
| 133 |
+
homepage='https://okvqa.allenai.org/',
|
| 134 |
+
citation=_CITATION,
|
| 135 |
+
)
|
| 136 |
+
|
| 137 |
+
def _split_generators(self, dl_manager: tfds.download.DownloadManager) -> ...:
|
| 138 |
+
"""Call the function which defines the splits."""
|
| 139 |
+
# data_dir = dl_manager.manual_dir
|
| 140 |
+
data_dir = _OKVQA_PATH
|
| 141 |
+
return {
|
| 142 |
+
'train': self._generate_examples(data_dir, 'train'),
|
| 143 |
+
'val': self._generate_examples(data_dir, 'val'),
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
def _generate_examples(self, data_dir: str, split: str) -> ...:
|
| 147 |
+
annotations = get_okvqa_annotations(data_dir, split)
|
| 148 |
+
|
| 149 |
+
for question_id, annotation in annotations.items():
|
| 150 |
+
image_id = annotation['image_id']
|
| 151 |
+
|
| 152 |
+
# Sanity check.
|
| 153 |
+
if len(annotation['answers']) != 10:
|
| 154 |
+
num_answers = len(annotation['answers'])
|
| 155 |
+
raise ValueError(
|
| 156 |
+
f'The number of answers for {image_id} is not 10 but {num_answers}')
|
| 157 |
+
|
| 158 |
+
feature_dict = {
|
| 159 |
+
'image': self.get_image_path(data_dir, split, image_id),
|
| 160 |
+
'image_id': image_id,
|
| 161 |
+
'answer_type': annotation['answer_type'],
|
| 162 |
+
'answers': [a['answer'] for a in annotation['answers']],
|
| 163 |
+
'answers_confidence': _get_answer_confidence(annotation['answers']),
|
| 164 |
+
'answers_raw': [a['raw_answer'] for a in annotation['answers']],
|
| 165 |
+
'question_id': annotation['question_id'],
|
| 166 |
+
'question_type': annotation['question_type'],
|
| 167 |
+
'question_type_readable': QUESTION_TYPES[annotation['question_type']],
|
| 168 |
+
'question': annotation['question'],
|
| 169 |
+
}
|
| 170 |
+
yield f'{question_id}', feature_dict
|
| 171 |
+
|
| 172 |
+
def get_image_path(self, data_dir: str, split: str, image_id: int) -> str:
|
| 173 |
+
subdir = {'train': 'train2014', 'val': 'val2014'}[split]
|
| 174 |
+
return f'{data_dir}/{subdir}/COCO_{subdir}_{image_id:012d}.jpg'
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def _get_answer_confidence(answers: list[dict[str, str]]) -> np.ndarray:
|
| 178 |
+
"""Get OKVQA answer confidences as bool."""
|
| 179 |
+
confidences = []
|
| 180 |
+
for a in answers:
|
| 181 |
+
confidence = a['answer_confidence']
|
| 182 |
+
if confidence == 'yes':
|
| 183 |
+
confidences.append(True)
|
| 184 |
+
elif confidence == 'no':
|
| 185 |
+
confidences.append(False)
|
| 186 |
+
else:
|
| 187 |
+
raise ValueError(f'Unknown confidence: {confidence}')
|
| 188 |
+
return np.array(confidences, dtype=bool)
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
def _read_json(
|
| 192 |
+
data_dir: str, file: str, key: str
|
| 193 |
+
) -> dict[int, dict[str, Any]]:
|
| 194 |
+
with open(os.path.join(data_dir, file)) as f:
|
| 195 |
+
data = json.load(f)
|
| 196 |
+
questions = {d['question_id']: d for d in data[key]}
|
| 197 |
+
return questions
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
def get_okvqa_annotations(
|
| 201 |
+
data_dir: str, split: str
|
| 202 |
+
) -> dict[int, dict[str, Any]]:
|
| 203 |
+
"""Return okvqa annotations (quesions and answers) as dictionary."""
|
| 204 |
+
questions = _read_json(data_dir, QUESTIONS_FILE[split], 'questions')
|
| 205 |
+
annotations = _read_json(data_dir, ANNOTATION_FILE[split], 'annotations')
|
| 206 |
+
|
| 207 |
+
assert len(annotations) == len(questions)
|
| 208 |
+
for question_id, question in questions.items():
|
| 209 |
+
assert question['image_id'] == annotations[question_id]['image_id']
|
| 210 |
+
assert question['question_id'] == annotations[question_id]['question_id']
|
| 211 |
+
annotations[question_id]['question'] = question['question']
|
| 212 |
+
|
| 213 |
+
return annotations
|
Tipsomaly/model/big_vision/datasets/pope/pope.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
# pylint: disable=line-too-long
|
| 16 |
+
r"""Implements POPE test-set in TFDS structure.
|
| 17 |
+
|
| 18 |
+
It's small data, so simple to run locally. First, copy the data to local disk:
|
| 19 |
+
First download json files from https://github.com/AoiDragon/POPE; then download
|
| 20 |
+
MSCOCO (val 2014) images from https://cocodataset.org/#download
|
| 21 |
+
|
| 22 |
+
mkdir -p /tmp/data/pope/
|
| 23 |
+
mkdir -p /tmp/data/pope/pope/
|
| 24 |
+
mkdir -p /tmp/data/pope/images/
|
| 25 |
+
git clone https://github.com/AoiDragon/POPE.git
|
| 26 |
+
cp POPE/output/coco/* /tmp/data/pope/pope/
|
| 27 |
+
wget http://images.cocodataset.org/zips/val2014.zip
|
| 28 |
+
unzip val2014.zip
|
| 29 |
+
cp -r val2014/ /tmp/data/pope/images/
|
| 30 |
+
|
| 31 |
+
Then, run conversion locally (make sure to install tensorflow-datasets for the `tfds` util):
|
| 32 |
+
|
| 33 |
+
cd big_vision/datasets
|
| 34 |
+
env TFDS_DATA_DIR=/tmp/tfds tfds build --datasets=pope
|
| 35 |
+
|
| 36 |
+
Example to load:
|
| 37 |
+
|
| 38 |
+
import tensorflow_datasets as tfds
|
| 39 |
+
dataset_random = tfds.load('pope/pope_random', split='test', data_dir='/tmp/tfds')
|
| 40 |
+
dataset_popular = tfds.load('pope/pope_popular', split='test', data_dir='/tmp/tfds')
|
| 41 |
+
dataset_adversarial = tfds.load('pope/pope_adversarial', split='test', data_dir='/tmp/tfds')
|
| 42 |
+
|
| 43 |
+
"""
|
| 44 |
+
import json
|
| 45 |
+
import os
|
| 46 |
+
|
| 47 |
+
import numpy as np
|
| 48 |
+
import tensorflow_datasets as tfds
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
_DESCRIPTION = """POPE dataset."""
|
| 52 |
+
|
| 53 |
+
# pylint: disable=line-too-long
|
| 54 |
+
_CITATION = """
|
| 55 |
+
@inproceedings{li-etal-2023-evaluating,
|
| 56 |
+
title = "Evaluating Object Hallucination in Large Vision-Language Models",
|
| 57 |
+
author = "Li, Yifan and
|
| 58 |
+
Du, Yifan and
|
| 59 |
+
Zhou, Kun and
|
| 60 |
+
Wang, Jinpeng and
|
| 61 |
+
Zhao, Xin and
|
| 62 |
+
Wen, Ji-Rong",
|
| 63 |
+
editor = "Bouamor, Houda and
|
| 64 |
+
Pino, Juan and
|
| 65 |
+
Bali, Kalika",
|
| 66 |
+
booktitle = "Proceedings of the 2023 Conference on Empirical Methods in Natural Language Processing",
|
| 67 |
+
month = dec,
|
| 68 |
+
year = "2023",
|
| 69 |
+
address = "Singapore",
|
| 70 |
+
publisher = "Association for Computational Linguistics",
|
| 71 |
+
url = "https://aclanthology.org/2023.emnlp-main.20",
|
| 72 |
+
doi = "10.18653/v1/2023.emnlp-main.20",
|
| 73 |
+
pages = "292--305",
|
| 74 |
+
abstract = "Inspired by the superior language abilities of large language models (LLM), large vision-language models (LVLM) have been recently proposed by integrating powerful LLMs for improving the performance on complex multimodal tasks. Despite the promising progress on LVLMs, we find that they suffer from object hallucinations, i.e., they tend to generate objects inconsistent with the target images in the descriptions. To investigate it, this work presents the first systematic study on object hallucination of LVLMs. We conduct the evaluation experiments on several representative LVLMs, and show that they mostly suffer from severe object hallucination issues. We further discuss that the visual instructions may influence the hallucination, and find that: objects that frequently appear in the visual instructions or co-occur with the image objects are obviously prone to be hallucinated by LVLMs. Besides, we further design a polling-based query method called POPE for better evaluation of object hallucination. Experiment results show that our POPE can evaluate object hallucination in a more stable and flexible way.",
|
| 75 |
+
}
|
| 76 |
+
"""
|
| 77 |
+
# pylint: enable=line-too-long
|
| 78 |
+
|
| 79 |
+
# When running locally (recommended), copy files as above and use these:
|
| 80 |
+
_POPE_PATH = '/tmp/data/pope/'
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
class POPEConfig(tfds.core.BuilderConfig):
|
| 84 |
+
"""Configuration to build the dataset."""
|
| 85 |
+
|
| 86 |
+
pass
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
class POPE(tfds.core.GeneratorBasedBuilder):
|
| 90 |
+
"""DatasetBuilder for POPE dataset."""
|
| 91 |
+
|
| 92 |
+
VERSION = tfds.core.Version('1.0.0')
|
| 93 |
+
RELEASE_NOTES = {'1.0.0': 'First release.'}
|
| 94 |
+
BUILDER_CONFIGS = [
|
| 95 |
+
POPEConfig(name='pope_random', description='Random set'),
|
| 96 |
+
POPEConfig(name='pope_popular', description='Popular set'),
|
| 97 |
+
POPEConfig(name='pope_adversarial', description='Adversarial set'),
|
| 98 |
+
]
|
| 99 |
+
|
| 100 |
+
def _info(self):
|
| 101 |
+
"""Returns the metadata."""
|
| 102 |
+
return tfds.core.DatasetInfo(
|
| 103 |
+
builder=self,
|
| 104 |
+
description=_DESCRIPTION,
|
| 105 |
+
features=tfds.features.FeaturesDict({
|
| 106 |
+
'question_id': tfds.features.Scalar(np.int32),
|
| 107 |
+
'image/filename': tfds.features.Text(),
|
| 108 |
+
'image': tfds.features.Image(encoding_format='png'),
|
| 109 |
+
'question': tfds.features.Text(),
|
| 110 |
+
'answer': tfds.features.Text(),
|
| 111 |
+
'thing': tfds.features.Text(),
|
| 112 |
+
}),
|
| 113 |
+
supervised_keys=None,
|
| 114 |
+
homepage='https://github.com/AoiDragon/POPE',
|
| 115 |
+
citation=_CITATION,
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
def _split_generators(self, dl_manager: tfds.download.DownloadManager):
|
| 119 |
+
"""Returns SplitGenerators."""
|
| 120 |
+
return {'test': self._generate_examples('test', self.builder_config.name)}
|
| 121 |
+
|
| 122 |
+
def _generate_examples(self, split: str, source: str):
|
| 123 |
+
"""Yields (key, example) tuples from test set."""
|
| 124 |
+
annot_fname = os.path.join(
|
| 125 |
+
_POPE_PATH, f'pope/coco_{source}.json'
|
| 126 |
+
)
|
| 127 |
+
|
| 128 |
+
with open(annot_fname, 'r') as f:
|
| 129 |
+
data = [json.loads(line) for line in f]
|
| 130 |
+
|
| 131 |
+
for idx, v in enumerate(data):
|
| 132 |
+
question = v['text']
|
| 133 |
+
thing = (
|
| 134 |
+
question.replace('Is there an ', '')
|
| 135 |
+
.replace('Is there a ', '')
|
| 136 |
+
.replace(' in the image?', '')
|
| 137 |
+
)
|
| 138 |
+
yield idx, {
|
| 139 |
+
'question_id': idx,
|
| 140 |
+
'image/filename': v['image'],
|
| 141 |
+
'image': os.path.join(_POPE_PATH, 'images/val2014/', v['image']),
|
| 142 |
+
'question': question,
|
| 143 |
+
'answer': v['label'],
|
| 144 |
+
'thing': thing,
|
| 145 |
+
}
|
Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/coco_caption.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""Evaluator for caption generation metrics used for the MS COCO dataset."""
|
| 16 |
+
import collections
|
| 17 |
+
import functools
|
| 18 |
+
import os
|
| 19 |
+
import tempfile
|
| 20 |
+
|
| 21 |
+
import big_vision.evaluators.common as c
|
| 22 |
+
import big_vision.input_pipeline
|
| 23 |
+
import big_vision.pp.builder
|
| 24 |
+
import big_vision.pp.tokenizer
|
| 25 |
+
import big_vision.utils as u
|
| 26 |
+
|
| 27 |
+
from pycocoevalcap.bleu import bleu
|
| 28 |
+
from pycocoevalcap.cider import cider
|
| 29 |
+
from pycocoevalcap.meteor import meteor
|
| 30 |
+
from pycocoevalcap.rouge import rouge
|
| 31 |
+
from pycocoevalcap.spice import spice
|
| 32 |
+
from pycocoevalcap.tokenizer import ptbtokenizer
|
| 33 |
+
|
| 34 |
+
import jax
|
| 35 |
+
|
| 36 |
+
from tensorflow.io import gfile
|
| 37 |
+
|
| 38 |
+
# Temporary global flag to facilitate backwards compatability. Will be removed
|
| 39 |
+
# by the end of year 2023.
|
| 40 |
+
API = "jit"
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
class Evaluator:
|
| 44 |
+
"""Evaluator for caption generation metrics used for the MS COCO dataset.
|
| 45 |
+
|
| 46 |
+
See https://arxiv.org/pdf/1504.00325.pdf or the repository implementing it
|
| 47 |
+
https://github.com/tylin/coco-caption for details on the metrics. This code
|
| 48 |
+
uses the python3 pip package from: https://github.com/salaniz/pycocoevalcap
|
| 49 |
+
|
| 50 |
+
Note that both the model caption and the ground truth reference captions are
|
| 51 |
+
further processed with the PTBTokenizer before computing scores.
|
| 52 |
+
|
| 53 |
+
`predict_fn` accepts arbitrary dictionaries of parameters and data, where
|
| 54 |
+
the data dictionary is produced by the `pp_fn` op. It is expected to output a
|
| 55 |
+
dict containing tokenized captions.
|
| 56 |
+
|
| 57 |
+
`pp_fn` must have fields: "image/id" and "captions".
|
| 58 |
+
"""
|
| 59 |
+
|
| 60 |
+
def __init__(
|
| 61 |
+
self, predict_fn, tokenizer=None,
|
| 62 |
+
metrics=("cider",), # Default to only cider. We often just look at that.
|
| 63 |
+
preds_outfile="{workdir}/{name}_{split}_preds.json",
|
| 64 |
+
annot_outfile="{workdir}/{name}_{split}_annotations.json",
|
| 65 |
+
*, data, devices, **kw
|
| 66 |
+
):
|
| 67 |
+
self.get_data_iter, self.steps = c.eval_input_pipeline(
|
| 68 |
+
keep_on_cpu={"image/id", "captions"}, data=data, devices=devices, **kw)
|
| 69 |
+
|
| 70 |
+
self.preds_outfile = c.resolve_outfile(
|
| 71 |
+
preds_outfile, name=data.get("name"), split=data.get("split"))
|
| 72 |
+
self.annot_outfile = c.resolve_outfile(
|
| 73 |
+
annot_outfile, name=data.get("name"), split=data.get("split"))
|
| 74 |
+
|
| 75 |
+
self.metrics = metrics
|
| 76 |
+
self.tok = big_vision.pp.tokenizer.get_tokenizer(tokenizer)
|
| 77 |
+
self.decode = functools.partial(
|
| 78 |
+
predict_fn, devices=devices, eos_token=self.tok.eos_token)
|
| 79 |
+
|
| 80 |
+
def run(self, train_state):
|
| 81 |
+
"""Run eval."""
|
| 82 |
+
gts = []
|
| 83 |
+
res = []
|
| 84 |
+
|
| 85 |
+
for _, batch in zip(range(self.steps), self.get_data_iter()):
|
| 86 |
+
# (batch, seqlen) array of decoded generated tokens.
|
| 87 |
+
tokens = self.decode(train_state, batch)
|
| 88 |
+
|
| 89 |
+
# (local_batch,)
|
| 90 |
+
tokens = u.get_local_slice_from_fsarray(tokens)
|
| 91 |
+
ex_masks = u.get_local_slice_from_fsarray(batch["_mask"])
|
| 92 |
+
|
| 93 |
+
image_ids = batch["image/id"][ex_masks]
|
| 94 |
+
pred_captions = self.tok.to_str(tokens[ex_masks])
|
| 95 |
+
|
| 96 |
+
for image_id, caption in zip(image_ids, pred_captions):
|
| 97 |
+
res.append({"image_id": image_id.item(), "caption": caption})
|
| 98 |
+
|
| 99 |
+
for image_id, captions in zip(image_ids, batch["captions"]):
|
| 100 |
+
for caption in captions:
|
| 101 |
+
gts.append({"image_id": image_id.item(), "caption": caption.item()})
|
| 102 |
+
|
| 103 |
+
# Write model outputs following: https://cocodataset.org/#format-results
|
| 104 |
+
# Use same format for gt although that is not the usual format for them.
|
| 105 |
+
res = c.multiprocess_write_json(self.preds_outfile, res)
|
| 106 |
+
gts = c.multiprocess_write_json(self.annot_outfile, gts)
|
| 107 |
+
|
| 108 |
+
if jax.process_index(): # Host0 gets all preds and does eval.
|
| 109 |
+
return
|
| 110 |
+
|
| 111 |
+
outs = self.evaluate(gts, res)
|
| 112 |
+
for key, score in outs.items():
|
| 113 |
+
yield key, score
|
| 114 |
+
|
| 115 |
+
def evaluate(self, gt_annotations, res_annotations):
|
| 116 |
+
"""Creates scorers and run evaluation."""
|
| 117 |
+
scorers = {
|
| 118 |
+
"rouge": rouge.Rouge,
|
| 119 |
+
"cider": cider.Cider,
|
| 120 |
+
"bleu-4": bleu.Bleu,
|
| 121 |
+
"spice": spice.Spice,
|
| 122 |
+
"meteor": meteor.Meteor,
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
# Reformat gts and res from [{"image_id": int|str, "caption": str}] to
|
| 126 |
+
# {int_image_id: [{"caption": str}]} as expected by tokenizer and scorers.
|
| 127 |
+
# Note there are multiple reference captions for the ground truth but only
|
| 128 |
+
# one for the model predictions.
|
| 129 |
+
iid_map = collections.defaultdict(lambda: len(iid_map))
|
| 130 |
+
res = {iid_map[x["image_id"]]: [x] for x in res_annotations}
|
| 131 |
+
gts = collections.defaultdict(list)
|
| 132 |
+
for x in gt_annotations:
|
| 133 |
+
gts[iid_map[x["image_id"]]].append(x)
|
| 134 |
+
assert sorted(gts.keys()) == sorted(res.keys())
|
| 135 |
+
|
| 136 |
+
# Tokenize captions and predictions using coco tokenizer.
|
| 137 |
+
coco_tokenizer = ptbtokenizer.PTBTokenizer()
|
| 138 |
+
gts = coco_tokenizer.tokenize(gts)
|
| 139 |
+
res = coco_tokenizer.tokenize(res)
|
| 140 |
+
|
| 141 |
+
scores = {}
|
| 142 |
+
for metric in self.metrics:
|
| 143 |
+
scorer = scorers[metric]()
|
| 144 |
+
scores[metric], _ = scorer.compute_score(gts, res)
|
| 145 |
+
return scores
|
Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/rsvqa.py
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""Evaluator for simple VQA variants with per answer-type metrics.
|
| 16 |
+
|
| 17 |
+
According to the (A-)OKVAQ papers, the eval for these datasets should follow
|
| 18 |
+
VQAv2. But here we don't track different answer-types, and don't do any
|
| 19 |
+
leave-one-out averaging, as this isn't done in the official implementation at
|
| 20 |
+
https://github.com/allenai/aokvqa/blob/main/evaluation/eval_predictions.py
|
| 21 |
+
either.
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
import functools
|
| 25 |
+
|
| 26 |
+
import big_vision.evaluators.common as c
|
| 27 |
+
import big_vision.pp.tokenizer
|
| 28 |
+
import big_vision.utils as u
|
| 29 |
+
import editdistance
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
# Temporary global flag to facilitate backwards compatability. Will be removed
|
| 33 |
+
# by the end of year 2023.
|
| 34 |
+
API = "jit"
|
| 35 |
+
|
| 36 |
+
QUESTION_TYPES = ("comp", "count", "presence", "rural_urban", "area")
|
| 37 |
+
|
| 38 |
+
ACC_SUBSETS = (
|
| 39 |
+
("nonum", ("comp", "presence", "rural_urban")), # rsvqa_lr
|
| 40 |
+
("nonum", ("comp", "presence")), # rsvqa_hr
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
class Evaluator:
|
| 45 |
+
"""Evaluator for simple VQA tasks."""
|
| 46 |
+
|
| 47 |
+
def __init__(
|
| 48 |
+
self, predict_fn, tokenizer, to_lower=False,
|
| 49 |
+
outfile="{workdir}/{split}.json",
|
| 50 |
+
*, data, devices, **kw):
|
| 51 |
+
self.get_data_iter, self.steps = c.eval_input_pipeline(
|
| 52 |
+
keep_on_cpu={"answers", "answer", "question_id", "question_type"},
|
| 53 |
+
data=data, devices=devices, **kw)
|
| 54 |
+
|
| 55 |
+
self.outfile = c.resolve_outfile(outfile, split=data.get("split"))
|
| 56 |
+
|
| 57 |
+
# We'll need the tokenizer to detokenize the model outputs later.
|
| 58 |
+
self.tok = big_vision.pp.tokenizer.get_tokenizer(tokenizer)
|
| 59 |
+
self.postproc = (lambda s: s.lower()) if to_lower else lambda s: s
|
| 60 |
+
self.decode = functools.partial(
|
| 61 |
+
predict_fn, devices=devices, eos_token=self.tok.eos_token)
|
| 62 |
+
|
| 63 |
+
def run(self, train_state):
|
| 64 |
+
"""Does one evaluation run, yields metrics."""
|
| 65 |
+
|
| 66 |
+
accuracies = []
|
| 67 |
+
accuracies_any = []
|
| 68 |
+
counts_per_type = {t: 0 for t in QUESTION_TYPES}
|
| 69 |
+
accuracies_per_type = {t: [] for t in QUESTION_TYPES}
|
| 70 |
+
anls_values = []
|
| 71 |
+
json_out = []
|
| 72 |
+
for _, batch in zip(range(self.steps), self.get_data_iter()):
|
| 73 |
+
# (batch, seqlen) array of decoded generated tokens.
|
| 74 |
+
tokens = self.decode(train_state, batch) # (B,L,E)
|
| 75 |
+
|
| 76 |
+
# (local_batch,) that indicates padding examples (0) vs real examples (1).
|
| 77 |
+
tokens = u.get_local_slice_from_fsarray(tokens)
|
| 78 |
+
ex_masks = u.get_local_slice_from_fsarray(batch["_mask"])
|
| 79 |
+
|
| 80 |
+
# Turn predictions into texts and then scores, one by one.
|
| 81 |
+
for i in range(len(tokens)):
|
| 82 |
+
if ex_masks[i] == 0: # Skip last-batch padding examples
|
| 83 |
+
continue
|
| 84 |
+
|
| 85 |
+
answer = self.postproc(self.tok.to_str(tokens[i], stop_at_eos=True))
|
| 86 |
+
|
| 87 |
+
# Now we have two commonly used VQA evaluation modes:
|
| 88 |
+
if "answer" in batch:
|
| 89 |
+
# single GT (eg ocrvqa): just compare to that answer, done.
|
| 90 |
+
gt = self.postproc(batch["answer"][i])
|
| 91 |
+
gts = [gt]
|
| 92 |
+
accuracies.append(float(answer == gt))
|
| 93 |
+
accuracies_any.append(float(answer == gt))
|
| 94 |
+
anls_values.append(anls_metric(gt, answer))
|
| 95 |
+
elif "answers" in batch and (gt_answers := batch["answers"][i]).size:
|
| 96 |
+
# multiple GTs (eg okvqa): introduced by VQA, compare to each of them
|
| 97 |
+
# with a threshold, see also: https://visualqa.org/evaluation.html
|
| 98 |
+
gts = [self.postproc(a) for a in gt_answers]
|
| 99 |
+
num_match = sum([answer == gt for gt in gts])
|
| 100 |
+
accuracies.append(min(1.0, num_match / 3.0))
|
| 101 |
+
accuracies_any.append(min(1.0, float(num_match)))
|
| 102 |
+
anls_values.append(max(anls_metric(gt, answer) for gt in gts))
|
| 103 |
+
accuracies_per_type[batch["question_type"][i]].append(
|
| 104 |
+
accuracies_any[-1]
|
| 105 |
+
)
|
| 106 |
+
counts_per_type[batch["question_type"][i]] += 1
|
| 107 |
+
else:
|
| 108 |
+
gts = []
|
| 109 |
+
|
| 110 |
+
json_out.append({
|
| 111 |
+
"question_id": batch["question_id"][i].item(),
|
| 112 |
+
"answer": answer} | ({"gts": gts} if gts else {}))
|
| 113 |
+
|
| 114 |
+
# At this point `accuracies` is a list of per-example scores. However,
|
| 115 |
+
# remember that each host holds a different subset of the examples! So if
|
| 116 |
+
# we were to just return the mean accuracy here, we would effectively only
|
| 117 |
+
# have evaluated on the main host's (who writes metrics) subset!
|
| 118 |
+
# So now, we need to compute global means.
|
| 119 |
+
# There is one more caveat: `process_sum` needs the summands on each host
|
| 120 |
+
# to have the same size. So we either need to include dummy values for
|
| 121 |
+
# the padding examples (last batch, annoying), or we only sum scalars as in
|
| 122 |
+
# sufficient statistics, which we do here.
|
| 123 |
+
sum_accs, sum_accs_any, sum_anls, num_accs, num = c.process_sum(
|
| 124 |
+
[sum(accuracies), sum(accuracies_any), sum(anls_values),
|
| 125 |
+
len(accuracies), len(json_out)])
|
| 126 |
+
|
| 127 |
+
sum_accs_per_type, sum_cnts_per_type = c.process_sum(
|
| 128 |
+
[{k: sum(v) for k, v in accuracies_per_type.items()}, counts_per_type]
|
| 129 |
+
)
|
| 130 |
+
|
| 131 |
+
# Yielding metric_name, value means logging the metric.
|
| 132 |
+
if num_accs:
|
| 133 |
+
yield "acc", sum_accs / num_accs
|
| 134 |
+
yield "acc_any", sum_accs_any / num_accs # Overall Accuracy (OA).
|
| 135 |
+
yield "anls", sum_anls / num_accs
|
| 136 |
+
acc_types = {}
|
| 137 |
+
for k, v in sum_accs_per_type.items():
|
| 138 |
+
if sum_cnts_per_type[k]:
|
| 139 |
+
acc_types[k] = v / sum_cnts_per_type[k]
|
| 140 |
+
yield f"acc_{k}", acc_types[k]
|
| 141 |
+
yield "acc_avg", sum(acc_types.values()) / len(acc_types) # Avg acc (AA).
|
| 142 |
+
for postfix, types in ACC_SUBSETS:
|
| 143 |
+
if all(t in acc_types for t in types):
|
| 144 |
+
yield f"acc_avg_{postfix}", sum(
|
| 145 |
+
[v for k, v in acc_types.items() if k in types]
|
| 146 |
+
) / len(types) # Average accuracy per question types subset.
|
| 147 |
+
yield "num", num # Just for sanity checks.
|
| 148 |
+
c.multiprocess_write_json(self.outfile, json_out)
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def anls_metric(target: str, prediction: str, theta: float = 0.5):
|
| 152 |
+
"""Calculates ANLS for DocVQA.
|
| 153 |
+
|
| 154 |
+
There does not seem to be an official evaluation script.
|
| 155 |
+
Public implementation on which this implementation is based:
|
| 156 |
+
https://github.com/herobd/layoutlmv2/blob/main/eval_docvqa.py#L92
|
| 157 |
+
|
| 158 |
+
Original paper (see Eq 1): https://arxiv.org/pdf/1907.00490.pdf
|
| 159 |
+
|
| 160 |
+
Args:
|
| 161 |
+
target: Target string.
|
| 162 |
+
prediction: Predicted string.
|
| 163 |
+
theta: Filter threshold set to 0.5 for DocVQA.
|
| 164 |
+
|
| 165 |
+
Returns:
|
| 166 |
+
ANLS score.
|
| 167 |
+
"""
|
| 168 |
+
if target:
|
| 169 |
+
edit_distance = editdistance.eval(target, prediction)
|
| 170 |
+
normalized_ld = edit_distance / max(len(target), len(prediction))
|
| 171 |
+
return 1 - normalized_ld if normalized_ld < theta else 0
|
| 172 |
+
else:
|
| 173 |
+
return float(prediction == "")
|
Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/science_qa.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""Evaluator for ScienceQA.
|
| 16 |
+
|
| 17 |
+
based on the official implementation at
|
| 18 |
+
https://github.com/lupantech/ScienceQA/blob/main/models/run_gpt3.py
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
import functools
|
| 22 |
+
import re
|
| 23 |
+
|
| 24 |
+
import big_vision.evaluators.common as c
|
| 25 |
+
import big_vision.pp.tokenizer
|
| 26 |
+
import big_vision.utils as u
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
# Temporary global flag to facilitate backwards compatability. Will be removed
|
| 30 |
+
# by the end of year 2023.
|
| 31 |
+
API = "jit"
|
| 32 |
+
FAILURE = "failed"
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
class Evaluator:
|
| 36 |
+
"""Evaluator for simple VQA tasks."""
|
| 37 |
+
|
| 38 |
+
def __init__(
|
| 39 |
+
self, predict_fn, tokenizer,
|
| 40 |
+
outfile="{workdir}/{split}.json",
|
| 41 |
+
out_question_key="question_id",
|
| 42 |
+
*, data, devices, **kw):
|
| 43 |
+
self.get_data_iter, self.steps = c.eval_input_pipeline(
|
| 44 |
+
keep_on_cpu={"answer", "question_id"}, data=data, devices=devices, **kw)
|
| 45 |
+
|
| 46 |
+
self.outfile = c.resolve_outfile(outfile, split=data.get("split"))
|
| 47 |
+
self.out_question_key = out_question_key
|
| 48 |
+
|
| 49 |
+
# We'll need the tokenizer to detokenize the model outputs later.
|
| 50 |
+
self.tok = big_vision.pp.tokenizer.get_tokenizer(tokenizer)
|
| 51 |
+
self.decode = functools.partial(
|
| 52 |
+
predict_fn, devices=devices, eos_token=self.tok.eos_token
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
def postproc(self, raw_answer):
|
| 56 |
+
"""Post-processes the raw answer. extract a, b, c from the string."""
|
| 57 |
+
match = re.match(
|
| 58 |
+
pattern=r"the answer is ([a-z])\.", string=raw_answer.lower()
|
| 59 |
+
)
|
| 60 |
+
if match:
|
| 61 |
+
return match.groups()[0] # 'a', 'b', ...
|
| 62 |
+
else:
|
| 63 |
+
return FAILURE
|
| 64 |
+
|
| 65 |
+
def run(self, train_state):
|
| 66 |
+
"""Does one evaluation run, yields metrics."""
|
| 67 |
+
|
| 68 |
+
accuracies = []
|
| 69 |
+
fail_parse = []
|
| 70 |
+
json_out = []
|
| 71 |
+
for _, batch in zip(range(self.steps), self.get_data_iter()):
|
| 72 |
+
# (batch, seqlen) array of decoded generated tokens.
|
| 73 |
+
tokens = self.decode(train_state, batch)
|
| 74 |
+
|
| 75 |
+
# (local_batch,) that indicates padding examples (0) vs real examples (1).
|
| 76 |
+
tokens = u.get_local_slice_from_fsarray(tokens)
|
| 77 |
+
ex_masks = u.get_local_slice_from_fsarray(batch["_mask"])
|
| 78 |
+
|
| 79 |
+
# Turn predictions into texts and then scores, one by one.
|
| 80 |
+
for i in range(len(tokens)):
|
| 81 |
+
if ex_masks[i] == 0: # Skip last-batch padding examples
|
| 82 |
+
continue
|
| 83 |
+
|
| 84 |
+
raw_answer = self.tok.to_str(tokens[i], stop_at_eos=True)
|
| 85 |
+
answer = self.postproc(raw_answer)
|
| 86 |
+
if "answer" in batch:
|
| 87 |
+
gt = self.postproc(batch["answer"][i])
|
| 88 |
+
gts = [gt]
|
| 89 |
+
accuracies.append(float(answer == gt))
|
| 90 |
+
fail_parse.append(float(answer == FAILURE))
|
| 91 |
+
else:
|
| 92 |
+
gts = []
|
| 93 |
+
|
| 94 |
+
json_out.append(
|
| 95 |
+
{
|
| 96 |
+
self.out_question_key: batch["question_id"][i].item(),
|
| 97 |
+
"raw_answer": raw_answer,
|
| 98 |
+
"answer": answer,
|
| 99 |
+
}
|
| 100 |
+
| ({"gts": gts} if gts else {})
|
| 101 |
+
)
|
| 102 |
+
|
| 103 |
+
# At this point `accuracies` is a list of per-example scores. However,
|
| 104 |
+
# remember that each host holds a different subset of the examples! So if
|
| 105 |
+
# we were to just return the mean accuracy here, we would effectively only
|
| 106 |
+
# have evaluated on the main host's (who writes metrics) subset!
|
| 107 |
+
# So now, we need to compute global means.
|
| 108 |
+
# There is one more caveat: `process_sum` needs the summands on each host
|
| 109 |
+
# to have the same size. So we either need to include dummy values for
|
| 110 |
+
# the padding examples (last batch, annoying), or we only sum scalars as in
|
| 111 |
+
# sufficient statistics, which we do here.
|
| 112 |
+
sum_accs, num_parsefail, num_accs, num = c.process_sum(
|
| 113 |
+
[sum(accuracies), sum(fail_parse), len(accuracies), len(json_out)]
|
| 114 |
+
)
|
| 115 |
+
|
| 116 |
+
# Yielding metric_name, value means logging the metric.
|
| 117 |
+
if num_accs > 0:
|
| 118 |
+
yield "acc", sum_accs / num_accs
|
| 119 |
+
yield "parsefail", num_parsefail / num_accs
|
| 120 |
+
|
| 121 |
+
yield "num", num # Just for sanity checks.
|
| 122 |
+
c.multiprocess_write_json(self.outfile, json_out)
|
Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/segmentation.py
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""Evaluator for segmentation."""
|
| 16 |
+
|
| 17 |
+
import functools
|
| 18 |
+
|
| 19 |
+
import big_vision.evaluators.common as c
|
| 20 |
+
import big_vision.pp.tokenizer
|
| 21 |
+
import big_vision.utils as u
|
| 22 |
+
import flax.linen as nn
|
| 23 |
+
import jax
|
| 24 |
+
import jax.numpy as jnp
|
| 25 |
+
import numpy as np
|
| 26 |
+
import PIL.Image
|
| 27 |
+
|
| 28 |
+
from tensorflow.io import gfile
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
# Temporary global flag to facilitate backwards compatability. Will be removed
|
| 32 |
+
# by the end of year 2023.
|
| 33 |
+
API = 'jit'
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def _inrange(a, min_value, max_value):
|
| 37 |
+
return (np.clip(a, min_value, max_value) == a).all()
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def _area(y1, x1, y2, x2):
|
| 41 |
+
return max(x2 - x1, 0.0) * max(y2 - y1, 0.0)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
class Evaluator:
|
| 45 |
+
"""Evaluator for instance segmentation."""
|
| 46 |
+
|
| 47 |
+
def __init__(self, predict_fn, tokenizer,
|
| 48 |
+
model='oi', det_ious=(0.5, 0.75),
|
| 49 |
+
*, devices, **kw):
|
| 50 |
+
self.get_data_iter, self.steps = c.eval_input_pipeline(
|
| 51 |
+
keep_on_cpu={'prefix', 'suffix', 'objects/mask', 'objects/bbox'},
|
| 52 |
+
devices=devices, **kw)
|
| 53 |
+
|
| 54 |
+
self.tok = big_vision.pp.tokenizer.get_tokenizer(tokenizer)
|
| 55 |
+
self.decode = functools.partial(
|
| 56 |
+
predict_fn, devices=devices, eos_token=self.tok.eos_token)
|
| 57 |
+
tok = big_vision.pp.tokenizer.get_tokenizer(tokenizer)
|
| 58 |
+
self.loc0 = np.array(tok.to_int('<loc0000>'))
|
| 59 |
+
self.seg0 = np.array(tok.to_int('<seg000>'))
|
| 60 |
+
# Verify tokenizer has `tokensets=("loc", "seg")`
|
| 61 |
+
assert self.loc0.shape == (1,), self.loc0
|
| 62 |
+
assert self.seg0.shape == (1,), self.seg0
|
| 63 |
+
self.reconstruct_masks = get_reconstruct_masks(model)
|
| 64 |
+
self.det_ious = det_ious
|
| 65 |
+
|
| 66 |
+
def run(self, train_state):
|
| 67 |
+
"""Does one evaluation run, yields metrics."""
|
| 68 |
+
ious = [] # NOTE: no point to split in s/m/l: all objects are L (>96px²)
|
| 69 |
+
det_by_iou = {iou: [] for iou in self.det_ious}
|
| 70 |
+
invalid = total = 0
|
| 71 |
+
for _, batch in zip(range(self.steps), self.get_data_iter()):
|
| 72 |
+
|
| 73 |
+
decoded = self.decode(train_state, batch)
|
| 74 |
+
|
| 75 |
+
not_padding = u.get_local_slice_from_fsarray(batch['_mask'])
|
| 76 |
+
decoded = u.get_local_slice_from_fsarray(decoded)[not_padding]
|
| 77 |
+
|
| 78 |
+
# Note, gt masks are in full original image resolution.
|
| 79 |
+
gt_masks = [gt[:, :, 0] > 0 for gt in batch['objects/mask'][not_padding]]
|
| 80 |
+
gt_bbs = [gt for gt in batch['objects/bbox'][not_padding]]
|
| 81 |
+
|
| 82 |
+
valid = []
|
| 83 |
+
tokens = np.zeros([decoded.shape[0], 4 + 16], np.int32)
|
| 84 |
+
for i, dec in enumerate(decoded):
|
| 85 |
+
# TODO: b/andstein - do we need to optimize this loop?
|
| 86 |
+
t = np.r_[dec[:4] - self.loc0, dec[4:4 + 16] - self.seg0] # Ignore rest
|
| 87 |
+
if (
|
| 88 |
+
len(t) == 4 + 16 # Full prediction
|
| 89 |
+
and _inrange(t[:4], 0, 1023) # Valid box tokens
|
| 90 |
+
and _inrange(t[4:], 0, 127) # Valid seg tokens
|
| 91 |
+
and t[2] > t[0] and t[3] > t[1] # Valid box
|
| 92 |
+
):
|
| 93 |
+
valid.append(True)
|
| 94 |
+
tokens[i] = t
|
| 95 |
+
else:
|
| 96 |
+
valid.append(False)
|
| 97 |
+
|
| 98 |
+
tocpu = lambda x: jax.device_put(x, jax.local_devices(backend='cpu')[0])
|
| 99 |
+
seg_indices = np.array(tokens[:, 4:])
|
| 100 |
+
mask64 = jax.device_get(self.reconstruct_masks(tocpu(seg_indices)))
|
| 101 |
+
mask64 = mask64[..., 0]
|
| 102 |
+
bbox = tokens[:, :4] / 1023 # Back to [0.0 ... 1.0]
|
| 103 |
+
|
| 104 |
+
for v, m64, gtm, bb, gtbb in zip(valid, mask64, gt_masks, bbox, gt_bbs):
|
| 105 |
+
# TODO: b/andstein - do we need to optimize this loop?
|
| 106 |
+
total += 1
|
| 107 |
+
h, w = gtm.shape # gt is full/original image resolution mask.
|
| 108 |
+
|
| 109 |
+
# First, compute detection iou, in [0.0 ... 1.0] coordinate space.
|
| 110 |
+
y1, x1, y2, x2 = bb
|
| 111 |
+
gty1, gtx1, gty2, gtx2 = gtbb
|
| 112 |
+
ibb = max(y1, gty1), max(x1, gtx1), min(y2, gty2), min(x2, gtx2)
|
| 113 |
+
box_iou = _area(*ibb) / (_area(*bb) + _area(*gtbb) - _area(*ibb))
|
| 114 |
+
for iou_thresh in det_by_iou:
|
| 115 |
+
det_by_iou[iou_thresh].append(iou_thresh <= box_iou)
|
| 116 |
+
|
| 117 |
+
# Next, we convert to pixel coordinates and compute mask iou.
|
| 118 |
+
gt_area = gtm.sum()
|
| 119 |
+
y1, x1, y2, x2 = map(int, (y1 * h, x1 * w, y2 * h, x2 * w))
|
| 120 |
+
|
| 121 |
+
# Avoid compute-intensive mask stuff for invalid preds:
|
| 122 |
+
if not v or x2 <= x1 or y2 <= y1: # Can still happen after int().
|
| 123 |
+
iou = 0.0
|
| 124 |
+
invalid += 1
|
| 125 |
+
else:
|
| 126 |
+
mi = np.asarray(
|
| 127 |
+
PIL.Image.fromarray(m64).resize( # pytype: disable=wrong-arg-types # pillow-102-upgrade
|
| 128 |
+
[x2 - x1, y2 - y1], resample=PIL.Image.BILINEAR # pytype: disable=module-attr
|
| 129 |
+
)
|
| 130 |
+
) # Predicted mask in box-sized image.
|
| 131 |
+
mi = mi > 0.0 # Mask decoder output in [-1.0 ... 1.0]
|
| 132 |
+
iarea = (gtm[y1:y2, x1:x2] & mi).sum() # Intersection pixels.
|
| 133 |
+
iou = iarea / (gt_area + mi.sum() - iarea)
|
| 134 |
+
ious.append(iou)
|
| 135 |
+
|
| 136 |
+
# Done going over all batches, now collect results from all processes.
|
| 137 |
+
sum_ious, num_ious, sum_dets, num_dets, num_invalid, num = c.process_sum([
|
| 138 |
+
sum(ious), len(ious),
|
| 139 |
+
{k: sum(v) for k, v in det_by_iou.items()},
|
| 140 |
+
{k: len(v) for k, v in det_by_iou.items()},
|
| 141 |
+
invalid, total
|
| 142 |
+
])
|
| 143 |
+
|
| 144 |
+
yield 'miou', sum_ious / num_ious
|
| 145 |
+
for k in sum_dets:
|
| 146 |
+
yield f'boxacc/{k}', sum_dets[k] / num_dets[k]
|
| 147 |
+
yield 'invalid', num_invalid
|
| 148 |
+
yield 'total', num
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
_KNOWN_MODELS = {
|
| 152 |
+
# Trained on open images.
|
| 153 |
+
'oi': 'gs://big_vision/paligemma/vae-oid.npz',
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
def _get_params(checkpoint):
|
| 158 |
+
"""Converts PyTorch checkpoint to Flax params."""
|
| 159 |
+
|
| 160 |
+
def transp(kernel):
|
| 161 |
+
return np.transpose(kernel, (2, 3, 1, 0))
|
| 162 |
+
|
| 163 |
+
def conv(name):
|
| 164 |
+
return {
|
| 165 |
+
'bias': checkpoint[name + '.bias'],
|
| 166 |
+
'kernel': transp(checkpoint[name + '.weight']),
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
def resblock(name):
|
| 170 |
+
return {
|
| 171 |
+
'Conv_0': conv(name + '.0'),
|
| 172 |
+
'Conv_1': conv(name + '.2'),
|
| 173 |
+
'Conv_2': conv(name + '.4'),
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
return {
|
| 177 |
+
'_embeddings': checkpoint['_vq_vae._embedding'],
|
| 178 |
+
'Conv_0': conv('decoder.0'),
|
| 179 |
+
'ResBlock_0': resblock('decoder.2.net'),
|
| 180 |
+
'ResBlock_1': resblock('decoder.3.net'),
|
| 181 |
+
'ConvTranspose_0': conv('decoder.4'),
|
| 182 |
+
'ConvTranspose_1': conv('decoder.6'),
|
| 183 |
+
'ConvTranspose_2': conv('decoder.8'),
|
| 184 |
+
'ConvTranspose_3': conv('decoder.10'),
|
| 185 |
+
'Conv_1': conv('decoder.12'),
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
def _quantized_values_from_codebook_indices(codebook_indices, embeddings):
|
| 190 |
+
batch_size, num_tokens = codebook_indices.shape
|
| 191 |
+
assert num_tokens == 16, codebook_indices.shape
|
| 192 |
+
unused_num_embeddings, embedding_dim = embeddings.shape
|
| 193 |
+
|
| 194 |
+
encodings = jnp.take(embeddings, codebook_indices.reshape((-1)), axis=0)
|
| 195 |
+
encodings = encodings.reshape((batch_size, 4, 4, embedding_dim))
|
| 196 |
+
return encodings
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
class ResBlock(nn.Module):
|
| 200 |
+
features: int
|
| 201 |
+
|
| 202 |
+
@nn.compact
|
| 203 |
+
def __call__(self, x):
|
| 204 |
+
original_x = x
|
| 205 |
+
x = nn.Conv(features=self.features, kernel_size=(3, 3), padding=1)(x)
|
| 206 |
+
x = nn.relu(x)
|
| 207 |
+
x = nn.Conv(features=self.features, kernel_size=(3, 3), padding=1)(x)
|
| 208 |
+
x = nn.relu(x)
|
| 209 |
+
x = nn.Conv(features=self.features, kernel_size=(1, 1), padding=0)(x)
|
| 210 |
+
return x + original_x
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
class Decoder(nn.Module):
|
| 214 |
+
"""Upscales quantized vectors to mask."""
|
| 215 |
+
|
| 216 |
+
@nn.compact
|
| 217 |
+
def __call__(self, x):
|
| 218 |
+
num_res_blocks = 2
|
| 219 |
+
dim = 128
|
| 220 |
+
num_upsample_layers = 4
|
| 221 |
+
|
| 222 |
+
x = nn.Conv(features=dim, kernel_size=(1, 1), padding=0)(x)
|
| 223 |
+
x = nn.relu(x)
|
| 224 |
+
|
| 225 |
+
for _ in range(num_res_blocks):
|
| 226 |
+
x = ResBlock(features=dim)(x)
|
| 227 |
+
|
| 228 |
+
for _ in range(num_upsample_layers):
|
| 229 |
+
x = nn.ConvTranspose(
|
| 230 |
+
features=dim,
|
| 231 |
+
kernel_size=(4, 4),
|
| 232 |
+
strides=(2, 2),
|
| 233 |
+
padding=2,
|
| 234 |
+
transpose_kernel=True,
|
| 235 |
+
)(x)
|
| 236 |
+
x = nn.relu(x)
|
| 237 |
+
dim //= 2
|
| 238 |
+
|
| 239 |
+
x = nn.Conv(features=1, kernel_size=(1, 1), padding=0)(x)
|
| 240 |
+
|
| 241 |
+
return x
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
@functools.cache
|
| 245 |
+
def get_reconstruct_masks(model):
|
| 246 |
+
"""Reconstructs masks from codebook indices.
|
| 247 |
+
|
| 248 |
+
Based on code from https://arxiv.org/abs/2301.02229
|
| 249 |
+
|
| 250 |
+
Verified in
|
| 251 |
+
https://colab.research.google.com/drive/1AOr0cokOpM6-N9Z5HmxoeGxGj6jS37Vl
|
| 252 |
+
|
| 253 |
+
Args:
|
| 254 |
+
model: Model to use for conversion.
|
| 255 |
+
|
| 256 |
+
Returns:
|
| 257 |
+
A function that expects indices shaped `[B, 16]` of dtype int32, each
|
| 258 |
+
ranging from 0 to 127 (inclusive), and that returns a decoded masks sized
|
| 259 |
+
`[B, 64, 64, 1]`, of dtype float32, in range [-1, 1].
|
| 260 |
+
"""
|
| 261 |
+
def reconstruct_masks(codebook_indices):
|
| 262 |
+
quantized = _quantized_values_from_codebook_indices(
|
| 263 |
+
codebook_indices, params['_embeddings']
|
| 264 |
+
)
|
| 265 |
+
return Decoder().apply({'params': params}, quantized)
|
| 266 |
+
|
| 267 |
+
with gfile.GFile(_KNOWN_MODELS.get(model, model), 'rb') as f:
|
| 268 |
+
params = _get_params(dict(np.load(f)))
|
| 269 |
+
|
| 270 |
+
return jax.jit(reconstruct_masks, backend='cpu')
|
Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/storepreds.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""Evaluator to run inference and store results."""
|
| 16 |
+
import functools
|
| 17 |
+
|
| 18 |
+
import big_vision.evaluators.common as c
|
| 19 |
+
import big_vision.input_pipeline
|
| 20 |
+
import big_vision.pp.builder
|
| 21 |
+
import big_vision.pp.tokenizer
|
| 22 |
+
import big_vision.utils as u
|
| 23 |
+
|
| 24 |
+
import jax
|
| 25 |
+
|
| 26 |
+
# Temporary global flag to facilitate backwards compatability. Will be removed
|
| 27 |
+
# by the end of year 2023.
|
| 28 |
+
API = "jit"
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class Evaluator:
|
| 32 |
+
"""Evaluator to run inference and store results."""
|
| 33 |
+
|
| 34 |
+
def __init__(
|
| 35 |
+
self, predict_fn, tokenizer=None,
|
| 36 |
+
preds_outfile="{workdir}/{name}_{split}_preds.json",
|
| 37 |
+
annot_outfile="{workdir}/{name}_{split}_annotations.json",
|
| 38 |
+
id_key="id",
|
| 39 |
+
*, data, devices, **kw
|
| 40 |
+
):
|
| 41 |
+
self.id_key = id_key
|
| 42 |
+
self.get_data_iter, self.steps = c.eval_input_pipeline(
|
| 43 |
+
keep_on_cpu={id_key}, data=data, devices=devices, **kw)
|
| 44 |
+
|
| 45 |
+
self.preds_outfile = c.resolve_outfile(
|
| 46 |
+
preds_outfile, name=data.get("name"), split=data.get("split", ""))
|
| 47 |
+
self.annot_outfile = c.resolve_outfile(
|
| 48 |
+
annot_outfile, name=data.get("name"), split=data.get("split", ""))
|
| 49 |
+
|
| 50 |
+
self.tok = big_vision.pp.tokenizer.get_tokenizer(tokenizer)
|
| 51 |
+
self.decode = functools.partial(
|
| 52 |
+
predict_fn, devices=devices, eos_token=self.tok.eos_token)
|
| 53 |
+
|
| 54 |
+
def run(self, train_state):
|
| 55 |
+
"""Run eval."""
|
| 56 |
+
res = []
|
| 57 |
+
|
| 58 |
+
for _, batch in zip(range(self.steps), self.get_data_iter()):
|
| 59 |
+
# (batch, seqlen) array of decoded generated tokens.
|
| 60 |
+
tokens = self.decode(train_state, batch)
|
| 61 |
+
|
| 62 |
+
# (local_batch,)
|
| 63 |
+
tokens = u.get_local_slice_from_fsarray(tokens)
|
| 64 |
+
ex_masks = u.get_local_slice_from_fsarray(batch["_mask"])
|
| 65 |
+
|
| 66 |
+
image_ids = batch[self.id_key][ex_masks]
|
| 67 |
+
pred_captions = self.tok.to_str(tokens[ex_masks])
|
| 68 |
+
|
| 69 |
+
for image_id, caption in zip(image_ids, pred_captions):
|
| 70 |
+
res.append({self.id_key: str(image_id), "caption": caption})
|
| 71 |
+
|
| 72 |
+
res = c.multiprocess_write_json(self.preds_outfile, res)
|
| 73 |
+
|
| 74 |
+
if jax.process_index(): # Host0 gets all preds and does eval.
|
| 75 |
+
return
|
| 76 |
+
|
| 77 |
+
yield "num_examples", len(res)
|
Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/tallyqa.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""Evaluator for TallyQA dataset."""
|
| 16 |
+
|
| 17 |
+
import functools
|
| 18 |
+
|
| 19 |
+
import big_vision.evaluators.common as c
|
| 20 |
+
import big_vision.pp.tokenizer
|
| 21 |
+
import big_vision.utils as u
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
# Temporary global flag to facilitate backwards compatability. Will be removed
|
| 25 |
+
# by the end of year 2023.
|
| 26 |
+
API = "jit"
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
# Largest count we want to track.
|
| 30 |
+
_LARGEST_COUNT = 15
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
class Evaluator:
|
| 34 |
+
"""TallyQA evaluator."""
|
| 35 |
+
|
| 36 |
+
def __init__(self, predict_fn, tokenizer, *, devices, **kw):
|
| 37 |
+
self.get_data_iter, self.steps = c.eval_input_pipeline(
|
| 38 |
+
keep_on_cpu={"answer", "issimple"}, devices=devices, **kw)
|
| 39 |
+
|
| 40 |
+
# We'll need the tokenizer to detokenize the model outputs later.
|
| 41 |
+
self.tok = big_vision.pp.tokenizer.get_tokenizer(tokenizer)
|
| 42 |
+
self.decode = functools.partial(
|
| 43 |
+
predict_fn, devices=devices, eos_token=self.tok.eos_token
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
def run(self, train_state):
|
| 47 |
+
"""Does one evaluation run, yields metrics."""
|
| 48 |
+
|
| 49 |
+
accuracies_by_type = {"all": [], "simple": [], "complex": []}
|
| 50 |
+
# Add per-count entries. Cannot use a `defaultdict` as we need to `tree_map`
|
| 51 |
+
# over keys later in `c.process_sum`.
|
| 52 |
+
accuracies_by_type.update(
|
| 53 |
+
{f"count_{i}": [] for i in range(_LARGEST_COUNT + 1)}
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
for _, batch in zip(range(self.steps), self.get_data_iter()):
|
| 57 |
+
# (batch, seqlen) array of decoded (generated) token sequences suffixes.
|
| 58 |
+
tokens = self.decode(train_state, batch)
|
| 59 |
+
|
| 60 |
+
# (local_batch,) that indicates padding examples (0) vs real examples (1).
|
| 61 |
+
tokens = u.get_local_slice_from_fsarray(tokens)
|
| 62 |
+
ex_masks = u.get_local_slice_from_fsarray(batch["_mask"])
|
| 63 |
+
|
| 64 |
+
# Turn predictions into texts and then scores, one by one.
|
| 65 |
+
# We always compare the gt (string digit, e.g. "1") to the answer by the
|
| 66 |
+
# model (e.g. "1").
|
| 67 |
+
for i in range(len(tokens)):
|
| 68 |
+
if ex_masks[i] == 0: # Skip last-batch padding examples
|
| 69 |
+
continue
|
| 70 |
+
|
| 71 |
+
# Extract the suffix/answer from the generated string, skip bos.
|
| 72 |
+
answer = self.tok.to_str(tokens[i], stop_at_eos=True)
|
| 73 |
+
# Standardize the reponse, i.e., convert number words ("one") to
|
| 74 |
+
# numerals ("1").
|
| 75 |
+
answer = _number_word_to_numeral(answer)
|
| 76 |
+
|
| 77 |
+
# Always need to do light space-processing:
|
| 78 |
+
gt = _number_word_to_numeral(batch["answer"][i])
|
| 79 |
+
accuracies_by_type["all"].append(float(answer == gt))
|
| 80 |
+
|
| 81 |
+
if "issimple" in batch:
|
| 82 |
+
# Simple/complex split.
|
| 83 |
+
if batch["issimple"][i] == 1:
|
| 84 |
+
accuracies_by_type["simple"].append(float(answer == gt))
|
| 85 |
+
elif batch["issimple"][i] == 0:
|
| 86 |
+
accuracies_by_type["complex"].append(float(answer == gt))
|
| 87 |
+
else:
|
| 88 |
+
# Train set is not annotated with simple/complex (but has dummy
|
| 89 |
+
# value of `-1` in this field).
|
| 90 |
+
pass
|
| 91 |
+
|
| 92 |
+
# Store accuracies per count.
|
| 93 |
+
accuracies_by_type[f"count_{gt}"].append(float(answer == gt))
|
| 94 |
+
|
| 95 |
+
# At this point `accuracies` is a list of per-example scores. However,
|
| 96 |
+
# remember that each host holds a different subset of the examples! So if
|
| 97 |
+
# we were to just return the mean accuracy here, we would effectively only
|
| 98 |
+
# have evaluated on the main host's (who writes metrics) subset!
|
| 99 |
+
# So now, we need to compute global means.
|
| 100 |
+
# There is one more caveat: `process_sum` needs the summands on each host
|
| 101 |
+
# to have the same size. So we either need to include dummy values for
|
| 102 |
+
# the padding examples (last batch, annoying), or we only sum scalars as in
|
| 103 |
+
# sufficient statistics, which we do here.
|
| 104 |
+
sum_accs = c.process_sum({k: sum(v) for k, v in accuracies_by_type.items()})
|
| 105 |
+
num_accs = c.process_sum({k: len(v) for k, v in accuracies_by_type.items()})
|
| 106 |
+
|
| 107 |
+
if n := num_accs["all"]:
|
| 108 |
+
yield "acc", sum_accs["all"] / n
|
| 109 |
+
yield "num", n # Just for sanity checks.
|
| 110 |
+
for key in sum_accs.keys():
|
| 111 |
+
if (key != "all") and (num_accs[key]):
|
| 112 |
+
yield f"acc/{key}", sum_accs[key] / num_accs[key]
|
| 113 |
+
yield f"num/{key}", num_accs[key] # Just for sanity checks.
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def _number_word_to_numeral(s: str) -> str:
|
| 117 |
+
"""Returns numeral for a given number word, e.g., "one" -> "1" (up to 20)."""
|
| 118 |
+
return REPLACEMENTS.get(s.lower(), s)
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
REPLACEMENTS = {
|
| 122 |
+
"none": "0",
|
| 123 |
+
"zero": "0",
|
| 124 |
+
"one": "1",
|
| 125 |
+
"two": "2",
|
| 126 |
+
"three": "3",
|
| 127 |
+
"four": "4",
|
| 128 |
+
"five": "5",
|
| 129 |
+
"six": "6",
|
| 130 |
+
"seven": "7",
|
| 131 |
+
"eight": "8",
|
| 132 |
+
"nine": "9",
|
| 133 |
+
"ten": "10",
|
| 134 |
+
"eleven": "11",
|
| 135 |
+
"twelve": "12",
|
| 136 |
+
"thirteen": "13",
|
| 137 |
+
"fourteen": "14",
|
| 138 |
+
"fifteen": "15",
|
| 139 |
+
"sixteen": "16",
|
| 140 |
+
"seventeen": "17",
|
| 141 |
+
"eighteen": "18",
|
| 142 |
+
"nineteen": "19",
|
| 143 |
+
"twenty": "20",
|
| 144 |
+
}
|
Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/vqa.py
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""Evaluator for simple VQA variants (OCR-VQA, OKVQA, A-OKVQA).
|
| 16 |
+
|
| 17 |
+
According to the (A-)OKVAQ papers, the eval for these datasets should follow
|
| 18 |
+
VQAv2. But here we don't track different answer-types, and don't do any
|
| 19 |
+
leave-one-out averaging, as this isn't done in the official implementation at
|
| 20 |
+
https://github.com/allenai/aokvqa/blob/main/evaluation/eval_predictions.py
|
| 21 |
+
either.
|
| 22 |
+
|
| 23 |
+
Please read the description of how evaluators work at (internal link).
|
| 24 |
+
This evaluator follows the pattern of also parallelizing the CPU computations
|
| 25 |
+
(ie postprocessing, score computation) across hosts for more scalability.
|
| 26 |
+
|
| 27 |
+
For now, simple decoding is implemented as part of the evaluator. We'll soon
|
| 28 |
+
unify and move to a library of decoding functions, including fancier and more
|
| 29 |
+
efficient ones.
|
| 30 |
+
"""
|
| 31 |
+
import functools
|
| 32 |
+
|
| 33 |
+
import big_vision.evaluators.common as c
|
| 34 |
+
import big_vision.pp.tokenizer
|
| 35 |
+
import big_vision.utils as u
|
| 36 |
+
import editdistance
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
# Temporary global flag to facilitate backwards compatability. Will be removed
|
| 40 |
+
# by the end of year 2023.
|
| 41 |
+
API = "jit"
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
class Evaluator:
|
| 45 |
+
"""Evaluator for simple VQA tasks.
|
| 46 |
+
|
| 47 |
+
This evaluator expects the batch to contain a field `question_id` and a field
|
| 48 |
+
`answer` for single ground truth or `answers` for multiple ground truths.
|
| 49 |
+
|
| 50 |
+
The field names used when writting the json result can be controlled with
|
| 51 |
+
`out_question_key` and `out_answer_key`.
|
| 52 |
+
"""
|
| 53 |
+
|
| 54 |
+
def __init__(
|
| 55 |
+
self, predict_fn, tokenizer, to_lower=False,
|
| 56 |
+
outfile="{workdir}/{split}.json",
|
| 57 |
+
out_question_key="question_id", out_answer_key="answer",
|
| 58 |
+
*, data, devices, **kw):
|
| 59 |
+
self.get_data_iter, self.steps = c.eval_input_pipeline(
|
| 60 |
+
keep_on_cpu={"answers", "answer", "question_id"},
|
| 61 |
+
data=data, devices=devices, **kw)
|
| 62 |
+
|
| 63 |
+
self.outfile = c.resolve_outfile(outfile, split=data.get("split"))
|
| 64 |
+
self.out_question_key = out_question_key
|
| 65 |
+
self.out_answer_key = out_answer_key
|
| 66 |
+
|
| 67 |
+
# We'll need the tokenizer to detokenize the model outputs later.
|
| 68 |
+
self.tok = big_vision.pp.tokenizer.get_tokenizer(tokenizer)
|
| 69 |
+
self.postproc = (lambda s: s.lower()) if to_lower else lambda s: s
|
| 70 |
+
self.decode = functools.partial(
|
| 71 |
+
predict_fn, devices=devices, eos_token=self.tok.eos_token)
|
| 72 |
+
|
| 73 |
+
def run(self, train_state):
|
| 74 |
+
"""Does one evaluation run, yields metrics."""
|
| 75 |
+
|
| 76 |
+
accuracies = []
|
| 77 |
+
accuracies_any = []
|
| 78 |
+
anls_values = []
|
| 79 |
+
json_out = []
|
| 80 |
+
for _, batch in zip(range(self.steps), self.get_data_iter()):
|
| 81 |
+
# (batch, seqlen) array of decoded generated tokens.
|
| 82 |
+
tokens = self.decode(train_state, batch)
|
| 83 |
+
|
| 84 |
+
# (local_batch,) that indicates padding examples (0) vs real examples (1).
|
| 85 |
+
tokens = u.get_local_slice_from_fsarray(tokens)
|
| 86 |
+
ex_masks = u.get_local_slice_from_fsarray(batch["_mask"])
|
| 87 |
+
|
| 88 |
+
# Turn predictions into texts and then scores, one by one.
|
| 89 |
+
for i in range(len(tokens)):
|
| 90 |
+
if ex_masks[i] == 0: # Skip last-batch padding examples
|
| 91 |
+
continue
|
| 92 |
+
|
| 93 |
+
answer = self.postproc(self.tok.to_str(tokens[i], stop_at_eos=True))
|
| 94 |
+
|
| 95 |
+
# Now we have two commonly used VQA evaluation modes:
|
| 96 |
+
if "answer" in batch:
|
| 97 |
+
# single GT (eg ocrvqa): just compare to that answer, done.
|
| 98 |
+
gt = self.postproc(batch["answer"][i])
|
| 99 |
+
gts = [gt]
|
| 100 |
+
accuracies.append(float(answer == gt))
|
| 101 |
+
accuracies_any.append(float(answer == gt))
|
| 102 |
+
anls_values.append(anls_metric(gt, answer))
|
| 103 |
+
elif "answers" in batch and (gt_answers := batch["answers"][i]).size:
|
| 104 |
+
# multiple GTs (eg okvqa): introduced by VQA, compare to each of them
|
| 105 |
+
# with a threshold, see also: https://visualqa.org/evaluation.html
|
| 106 |
+
gts = [self.postproc(a) for a in gt_answers]
|
| 107 |
+
num_match = sum([answer == gt for gt in gts])
|
| 108 |
+
accuracies.append(min(1.0, num_match / 3.0))
|
| 109 |
+
accuracies_any.append(min(1.0, float(num_match)))
|
| 110 |
+
anls_values.append(max(anls_metric(gt, answer) for gt in gts))
|
| 111 |
+
else:
|
| 112 |
+
gts = []
|
| 113 |
+
|
| 114 |
+
json_out.append({
|
| 115 |
+
self.out_question_key: batch["question_id"][i].item(),
|
| 116 |
+
self.out_answer_key: answer} | ({"gts": gts} if gts else {}))
|
| 117 |
+
|
| 118 |
+
# At this point `accuracies` is a list of per-example scores. However,
|
| 119 |
+
# remember that each host holds a different subset of the examples! So if
|
| 120 |
+
# we were to just return the mean accuracy here, we would effectively only
|
| 121 |
+
# have evaluated on the main host's (who writes metrics) subset!
|
| 122 |
+
# So now, we need to compute global means.
|
| 123 |
+
# There is one more caveat: `process_sum` needs the summands on each host
|
| 124 |
+
# to have the same size. So we either need to include dummy values for
|
| 125 |
+
# the padding examples (last batch, annoying), or we only sum scalars as in
|
| 126 |
+
# sufficient statistics, which we do here.
|
| 127 |
+
sum_accs, sum_accs_any, sum_anls, num_accs, num = c.process_sum(
|
| 128 |
+
[sum(accuracies), sum(accuracies_any), sum(anls_values),
|
| 129 |
+
len(accuracies), len(json_out)])
|
| 130 |
+
|
| 131 |
+
# Yielding metric_name, value means logging the metric.
|
| 132 |
+
if num_accs:
|
| 133 |
+
yield "acc", sum_accs / num_accs
|
| 134 |
+
yield "acc_any", sum_accs_any / num_accs
|
| 135 |
+
yield "anls", sum_anls / num_accs
|
| 136 |
+
|
| 137 |
+
yield "num", num # Just for sanity checks.
|
| 138 |
+
c.multiprocess_write_json(self.outfile, json_out)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
def anls_metric(target: str, prediction: str, theta: float = 0.5):
|
| 142 |
+
"""Calculates ANLS for DocVQA.
|
| 143 |
+
|
| 144 |
+
There does not seem to be an official evaluation script.
|
| 145 |
+
Public implementation on which this implementation is based:
|
| 146 |
+
https://github.com/herobd/layoutlmv2/blob/main/eval_docvqa.py#L92
|
| 147 |
+
|
| 148 |
+
Original paper (see Eq 1): https://arxiv.org/pdf/1907.00490.pdf
|
| 149 |
+
|
| 150 |
+
Args:
|
| 151 |
+
target: Target string.
|
| 152 |
+
prediction: Predicted string.
|
| 153 |
+
theta: Filter threshold set to 0.5 for DocVQA.
|
| 154 |
+
|
| 155 |
+
Returns:
|
| 156 |
+
ANLS score.
|
| 157 |
+
"""
|
| 158 |
+
if target:
|
| 159 |
+
edit_distance = editdistance.eval(target, prediction)
|
| 160 |
+
normalized_ld = edit_distance / max(len(target), len(prediction))
|
| 161 |
+
return 1 - normalized_ld if normalized_ld < theta else 0
|
| 162 |
+
else:
|
| 163 |
+
return float(prediction == "")
|
Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/vqav2.py
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""Evaluator for VQAV2 dataset.
|
| 16 |
+
"""
|
| 17 |
+
import functools
|
| 18 |
+
import re
|
| 19 |
+
|
| 20 |
+
import big_vision.evaluators.common as c
|
| 21 |
+
import big_vision.pp.tokenizer
|
| 22 |
+
import big_vision.utils as u
|
| 23 |
+
import numpy as np
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
# Temporary global flag to facilitate backwards compatability. Will be removed
|
| 27 |
+
# by the end of year 2023.
|
| 28 |
+
API = "jit"
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class Evaluator:
|
| 32 |
+
"""VQAv2 evaluator."""
|
| 33 |
+
|
| 34 |
+
def __init__(
|
| 35 |
+
self, predict_fn, tokenizer, outfile="{workdir}/{split}.json",
|
| 36 |
+
*, data, devices, **kw):
|
| 37 |
+
self.get_data_iter, self.steps = c.eval_input_pipeline(
|
| 38 |
+
keep_on_cpu={"answers", "answer_type", "question_type", "question_id"},
|
| 39 |
+
data=data, devices=devices, **kw)
|
| 40 |
+
|
| 41 |
+
self.outfile = c.resolve_outfile(outfile, split=data.get("split"))
|
| 42 |
+
|
| 43 |
+
# We'll need the tokenizer to detokenize the model outputs later.
|
| 44 |
+
self.tok = big_vision.pp.tokenizer.get_tokenizer(tokenizer)
|
| 45 |
+
self.decode = functools.partial(
|
| 46 |
+
predict_fn, devices=devices, eos_token=self.tok.eos_token)
|
| 47 |
+
|
| 48 |
+
def run(self, train_state):
|
| 49 |
+
"""Does one evaluation run, yields metrics."""
|
| 50 |
+
accuracies_by_type = {"yes/no": [], "number": [], "other": []}
|
| 51 |
+
json_out = []
|
| 52 |
+
|
| 53 |
+
for _, batch in zip(range(self.steps), self.get_data_iter()):
|
| 54 |
+
# (batch, seqlen) array of decoded (generated) token sequences suffixes.
|
| 55 |
+
tokens = self.decode(train_state, batch)
|
| 56 |
+
|
| 57 |
+
# (local_batch,) that indicates padding examples (0) vs real examples (1).
|
| 58 |
+
tokens = u.get_local_slice_from_fsarray(tokens)
|
| 59 |
+
ex_masks = u.get_local_slice_from_fsarray(batch["_mask"])
|
| 60 |
+
|
| 61 |
+
# Turn predictions into texts and then scores, one by one.
|
| 62 |
+
for i in range(len(tokens)):
|
| 63 |
+
if ex_masks[i] == 0: # Skip last-batch padding examples
|
| 64 |
+
continue
|
| 65 |
+
|
| 66 |
+
# Extract the suffix/answer from the generated string, skip bos.
|
| 67 |
+
answer = self.tok.to_str(tokens[i], stop_at_eos=True)
|
| 68 |
+
json = {"question_id": batch["question_id"][i].item(), "answer": answer}
|
| 69 |
+
|
| 70 |
+
# The rest is computation of VQA-score which compares to multiple GTs.
|
| 71 |
+
# This is described better here: https://visualqa.org/evaluation.html
|
| 72 |
+
if (gt_answers := batch["answers"][i]).size:
|
| 73 |
+
# Always need to do light space-processing:
|
| 74 |
+
gt_answers = [stripspace_vqav2(a) for a in gt_answers]
|
| 75 |
+
answer = stripspace_vqav2(answer)
|
| 76 |
+
|
| 77 |
+
# Only post-process if not all agree. Supposedly avoids postproc OCR:
|
| 78 |
+
# https://github.com/GT-Vision-Lab/VQA/issues/14#issuecomment-1334695361
|
| 79 |
+
if len(set(gt_answers)) > 1:
|
| 80 |
+
answer = postprocess_vqav2_text(answer)
|
| 81 |
+
gt_answers = [postprocess_vqav2_text(a) for a in gt_answers]
|
| 82 |
+
|
| 83 |
+
# Accuracy is avg over all ten leave-one-out GT's.
|
| 84 |
+
# https://github.com/GT-Vision-Lab/VQA/issues/1#issuecomment-199921352
|
| 85 |
+
# An answer is counted 100% correct as soon as 3 GT's agree with it.
|
| 86 |
+
matches = answer == np.array(gt_answers)
|
| 87 |
+
acc = np.mean([
|
| 88 |
+
np.clip(np.sum(np.delete(matches, i_leave_out)) / 3, 0, 1)
|
| 89 |
+
for i_leave_out in range(10)
|
| 90 |
+
])
|
| 91 |
+
|
| 92 |
+
accuracies_by_type[batch["answer_type"][i]].append(acc)
|
| 93 |
+
|
| 94 |
+
# Update json with fully post-processed answer and gt:
|
| 95 |
+
json["answer_raw"] = json["answer"]
|
| 96 |
+
json["answer"] = answer
|
| 97 |
+
json["gts"] = gt_answers
|
| 98 |
+
|
| 99 |
+
json_out.append(json)
|
| 100 |
+
|
| 101 |
+
# At this point `accuracies` is a list of per-example scores. However,
|
| 102 |
+
# remember that each host holds a different subset of the examples! So if
|
| 103 |
+
# we were to just return the mean accuracy here, we would effectively only
|
| 104 |
+
# have evaluated on the main host's (who writes metrics) subset!
|
| 105 |
+
# So now, we need to compute global means.
|
| 106 |
+
# There is one more caveat: `process_sum` needs the summands on each host
|
| 107 |
+
# to have the same size. So we either need to include dummy values for
|
| 108 |
+
# the padding examples (last batch, annoying), or we only sum scalars as in
|
| 109 |
+
# sufficient statistics, which we do here.
|
| 110 |
+
sum_accs = c.process_sum({k: sum(v) for k, v in accuracies_by_type.items()})
|
| 111 |
+
num_accs = c.process_sum({k: len(v) for k, v in accuracies_by_type.items()})
|
| 112 |
+
num = c.process_sum(len(json_out))
|
| 113 |
+
|
| 114 |
+
# Yielding metric_name, value means logging the metric.
|
| 115 |
+
if n := sum(num_accs.values()):
|
| 116 |
+
yield "acc", sum(sum_accs.values()) / n
|
| 117 |
+
if n := num_accs["yes/no"]:
|
| 118 |
+
yield "acc/yesno", sum_accs["yes/no"] / n
|
| 119 |
+
yield "num/yesno", n
|
| 120 |
+
if n := num_accs["number"]:
|
| 121 |
+
yield "acc/number", sum_accs["number"] / n
|
| 122 |
+
yield "num/number", n
|
| 123 |
+
if n := num_accs["other"]:
|
| 124 |
+
yield "acc/other", sum_accs["other"] / n
|
| 125 |
+
yield "num/other", n
|
| 126 |
+
|
| 127 |
+
yield "num", num # Just for sanity checks.
|
| 128 |
+
c.multiprocess_write_json(self.outfile, json_out)
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
# Post-processing required is described at https://visualqa.org/evaluation.html
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def stripspace_vqav2(txt):
|
| 135 |
+
return txt.replace("\n", " ").replace("\t", " ").strip()
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def postprocess_vqav2_text(txt):
|
| 139 |
+
"""Cleanup string according to VQA."""
|
| 140 |
+
has_digit_comma = re.search(r"(\d)(\,)(\d)", txt) is not None
|
| 141 |
+
|
| 142 |
+
out = txt
|
| 143 |
+
for p in PUNCT:
|
| 144 |
+
# NOTE: digit_comma here looks like a bug in official code, so we follow it.
|
| 145 |
+
if has_digit_comma or f"{p} " in txt or f" {p}" in txt:
|
| 146 |
+
out = out.replace(p, "")
|
| 147 |
+
else:
|
| 148 |
+
out = out.replace(p, " ")
|
| 149 |
+
|
| 150 |
+
# Remove full-stops that aren't part of a number.
|
| 151 |
+
out = re.sub(r"(?!<=\d)(\.)(?!\d)", "", out, flags=re.UNICODE)
|
| 152 |
+
|
| 153 |
+
words = []
|
| 154 |
+
for word in out.lower().split():
|
| 155 |
+
if word not in ARTICLES:
|
| 156 |
+
words.append(REPLACEMENTS.get(word, word))
|
| 157 |
+
return " ".join(words)
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
# pylint: disable=line-too-long
|
| 161 |
+
REPLACEMENTS = {
|
| 162 |
+
# CONTRACTIONS
|
| 163 |
+
"aint": "ain't", "arent": "aren't", "cant": "can't", "couldve": "could've", "couldnt": "couldn't",
|
| 164 |
+
"couldn'tve": "couldn't've", "couldnt've": "couldn't've", "didnt": "didn't", "doesnt": "doesn't", "dont": "don't", "hadnt": "hadn't",
|
| 165 |
+
"hadnt've": "hadn't've", "hadn'tve": "hadn't've", "hasnt": "hasn't", "havent": "haven't", "hed": "he'd", "hed've": "he'd've",
|
| 166 |
+
"he'dve": "he'd've", "hes": "he's", "howd": "how'd", "howll": "how'll", "hows": "how's", "Id've": "I'd've", "I'dve": "I'd've",
|
| 167 |
+
"Im": "I'm", "Ive": "I've", "isnt": "isn't", "itd": "it'd", "itd've": "it'd've", "it'dve": "it'd've", "itll": "it'll", "let's": "let's",
|
| 168 |
+
"maam": "ma'am", "mightnt": "mightn't", "mightnt've": "mightn't've", "mightn'tve": "mightn't've", "mightve": "might've",
|
| 169 |
+
"mustnt": "mustn't", "mustve": "must've", "neednt": "needn't", "notve": "not've", "oclock": "o'clock", "oughtnt": "oughtn't",
|
| 170 |
+
"ow's'at": "'ow's'at", "'ows'at": "'ow's'at", "'ow'sat": "'ow's'at", "shant": "shan't", "shed've": "she'd've", "she'dve": "she'd've",
|
| 171 |
+
"she's": "she's", "shouldve": "should've", "shouldnt": "shouldn't", "shouldnt've": "shouldn't've", "shouldn'tve": "shouldn't've",
|
| 172 |
+
"somebody'd": "somebodyd", "somebodyd've": "somebody'd've", "somebody'dve": "somebody'd've", "somebodyll": "somebody'll",
|
| 173 |
+
"somebodys": "somebody's", "someoned": "someone'd", "someoned've": "someone'd've", "someone'dve": "someone'd've",
|
| 174 |
+
"someonell": "someone'll", "someones": "someone's", "somethingd": "something'd", "somethingd've": "something'd've",
|
| 175 |
+
"something'dve": "something'd've", "somethingll": "something'll", "thats": "that's", "thered": "there'd", "thered've": "there'd've",
|
| 176 |
+
"there'dve": "there'd've", "therere": "there're", "theres": "there's", "theyd": "they'd", "theyd've": "they'd've",
|
| 177 |
+
"they'dve": "they'd've", "theyll": "they'll", "theyre": "they're", "theyve": "they've", "twas": "'twas", "wasnt": "wasn't",
|
| 178 |
+
"wed've": "we'd've", "we'dve": "we'd've", "weve": "we've", "werent": "weren't", "whatll": "what'll", "whatre": "what're",
|
| 179 |
+
"whats": "what's", "whatve": "what've", "whens": "when's", "whered": "where'd", "wheres": "where's", "whereve": "where've",
|
| 180 |
+
"whod": "who'd", "whod've": "who'd've", "who'dve": "who'd've", "wholl": "who'll", "whos": "who's", "whove": "who've", "whyll": "why'll",
|
| 181 |
+
"whyre": "why're", "whys": "why's", "wont": "won't", "wouldve": "would've", "wouldnt": "wouldn't", "wouldnt've": "wouldn't've",
|
| 182 |
+
"wouldn'tve": "wouldn't've", "yall": "y'all", "yall'll": "y'all'll", "y'allll": "y'all'll", "yall'd've": "y'all'd've",
|
| 183 |
+
"y'alld've": "y'all'd've", "y'all'dve": "y'all'd've", "youd": "you'd", "youd've": "you'd've", "you'dve": "you'd've",
|
| 184 |
+
"youll": "you'll", "youre": "you're", "youve": "you've",
|
| 185 |
+
# NUMBERS
|
| 186 |
+
"none": "0", "zero": "0", "one": "1", "two": "2",
|
| 187 |
+
"three": "3", "four": "4", "five": "5", "six": "6",
|
| 188 |
+
"seven": "7", "eight": "8", "nine": "9", "ten": "10",
|
| 189 |
+
}
|
| 190 |
+
# pylint: enable=line-too-long
|
| 191 |
+
|
| 192 |
+
PUNCT = [
|
| 193 |
+
";", "/", "[", "]", "\"", "{", "}",
|
| 194 |
+
"(", ")", "=", "+", "\\", "_", "-",
|
| 195 |
+
">", "<", "@", "`", ",", "?", "!"
|
| 196 |
+
]
|
| 197 |
+
ARTICLES = {"a", "an", "the"}
|
Tipsomaly/model/big_vision/pp/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (166 Bytes). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (154 Bytes). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/__init__.cpython-39.pyc
ADDED
|
Binary file (166 Bytes). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/builder.cpython-311.pyc
ADDED
|
Binary file (3.66 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/builder.cpython-312.pyc
ADDED
|
Binary file (3.26 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/builder.cpython-39.pyc
ADDED
|
Binary file (2.43 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/ops_general.cpython-311.pyc
ADDED
|
Binary file (27.4 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/ops_general.cpython-312.pyc
ADDED
|
Binary file (23.7 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/ops_general.cpython-39.pyc
ADDED
|
Binary file (16.6 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/ops_image.cpython-311.pyc
ADDED
|
Binary file (18.1 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/ops_image.cpython-312.pyc
ADDED
|
Binary file (17.5 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/ops_image.cpython-39.pyc
ADDED
|
Binary file (11.8 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/ops_text.cpython-311.pyc
ADDED
|
Binary file (23.5 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/ops_text.cpython-312.pyc
ADDED
|
Binary file (20.8 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/ops_text.cpython-39.pyc
ADDED
|
Binary file (14.3 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/registry.cpython-311.pyc
ADDED
|
Binary file (7.83 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/registry.cpython-312.pyc
ADDED
|
Binary file (6.88 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/registry.cpython-39.pyc
ADDED
|
Binary file (5.14 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/tokenizer.cpython-311.pyc
ADDED
|
Binary file (5.68 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/tokenizer.cpython-312.pyc
ADDED
|
Binary file (4.9 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/tokenizer.cpython-39.pyc
ADDED
|
Binary file (4.11 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/utils.cpython-311.pyc
ADDED
|
Binary file (2.26 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/utils.cpython-312.pyc
ADDED
|
Binary file (2.04 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/__pycache__/utils.cpython-39.pyc
ADDED
|
Binary file (1.64 kB). View file
|
|
|
Tipsomaly/model/big_vision/pp/archive/__init__.py
ADDED
|
File without changes
|
Tipsomaly/model/big_vision/pp/archive/autoaugment.py
ADDED
|
@@ -0,0 +1,700 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""AutoAugment and RandAugment policies for enhanced image preprocessing.
|
| 16 |
+
|
| 17 |
+
AutoAugment Reference: https://arxiv.org/abs/1805.09501
|
| 18 |
+
RandAugment Reference: https://arxiv.org/abs/1909.13719
|
| 19 |
+
|
| 20 |
+
This code is forked from
|
| 21 |
+
https://github.com/tensorflow/tpu/blob/11d0db15cf1c3667f6e36fecffa111399e008acd/models/official/efficientnet/autoaugment.py
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
from __future__ import absolute_import
|
| 25 |
+
from __future__ import division
|
| 26 |
+
from __future__ import print_function
|
| 27 |
+
|
| 28 |
+
import dataclasses
|
| 29 |
+
import inspect
|
| 30 |
+
import math
|
| 31 |
+
import tensorflow.compat.v1 as tf
|
| 32 |
+
from tensorflow_addons import image as contrib_image
|
| 33 |
+
|
| 34 |
+
# This signifies the max integer that the controller RNN could predict for the
|
| 35 |
+
# augmentation scheme.
|
| 36 |
+
_MAX_LEVEL = 10.
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
@dataclasses.dataclass
|
| 40 |
+
class HParams:
|
| 41 |
+
"""Parameters for AutoAugment and RandAugment."""
|
| 42 |
+
cutout_const: int
|
| 43 |
+
translate_const: int
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def policy_v0():
|
| 47 |
+
"""Autoaugment policy that was used in AutoAugment Paper."""
|
| 48 |
+
# Each tuple is an augmentation operation of the form
|
| 49 |
+
# (operation, probability, magnitude). Each element in policy is a
|
| 50 |
+
# sub-policy that will be applied sequentially on the image.
|
| 51 |
+
policy = [
|
| 52 |
+
[('Equalize', 0.8, 1), ('ShearY', 0.8, 4)],
|
| 53 |
+
[('Color', 0.4, 9), ('Equalize', 0.6, 3)],
|
| 54 |
+
[('Color', 0.4, 1), ('Rotate', 0.6, 8)],
|
| 55 |
+
[('Solarize', 0.8, 3), ('Equalize', 0.4, 7)],
|
| 56 |
+
[('Solarize', 0.4, 2), ('Solarize', 0.6, 2)],
|
| 57 |
+
[('Color', 0.2, 0), ('Equalize', 0.8, 8)],
|
| 58 |
+
[('Equalize', 0.4, 8), ('SolarizeAdd', 0.8, 3)],
|
| 59 |
+
[('ShearX', 0.2, 9), ('Rotate', 0.6, 8)],
|
| 60 |
+
[('Color', 0.6, 1), ('Equalize', 1.0, 2)],
|
| 61 |
+
[('Invert', 0.4, 9), ('Rotate', 0.6, 0)],
|
| 62 |
+
[('Equalize', 1.0, 9), ('ShearY', 0.6, 3)],
|
| 63 |
+
[('Color', 0.4, 7), ('Equalize', 0.6, 0)],
|
| 64 |
+
[('Posterize', 0.4, 6), ('AutoContrast', 0.4, 7)],
|
| 65 |
+
[('Solarize', 0.6, 8), ('Color', 0.6, 9)],
|
| 66 |
+
[('Solarize', 0.2, 4), ('Rotate', 0.8, 9)],
|
| 67 |
+
[('Rotate', 1.0, 7), ('TranslateY', 0.8, 9)],
|
| 68 |
+
[('ShearX', 0.0, 0), ('Solarize', 0.8, 4)],
|
| 69 |
+
[('ShearY', 0.8, 0), ('Color', 0.6, 4)],
|
| 70 |
+
[('Color', 1.0, 0), ('Rotate', 0.6, 2)],
|
| 71 |
+
[('Equalize', 0.8, 4), ('Equalize', 0.0, 8)],
|
| 72 |
+
[('Equalize', 1.0, 4), ('AutoContrast', 0.6, 2)],
|
| 73 |
+
[('ShearY', 0.4, 7), ('SolarizeAdd', 0.6, 7)],
|
| 74 |
+
[('Posterize', 0.8, 2), ('Solarize', 0.6, 10)],
|
| 75 |
+
[('Solarize', 0.6, 8), ('Equalize', 0.6, 1)],
|
| 76 |
+
[('Color', 0.8, 6), ('Rotate', 0.4, 5)],
|
| 77 |
+
]
|
| 78 |
+
return policy
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def policy_vtest():
|
| 82 |
+
"""Autoaugment test policy for debugging."""
|
| 83 |
+
# Each tuple is an augmentation operation of the form
|
| 84 |
+
# (operation, probability, magnitude). Each element in policy is a
|
| 85 |
+
# sub-policy that will be applied sequentially on the image.
|
| 86 |
+
policy = [
|
| 87 |
+
[('TranslateX', 1.0, 4), ('Equalize', 1.0, 10)],
|
| 88 |
+
]
|
| 89 |
+
return policy
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def blend(image1, image2, factor):
|
| 93 |
+
"""Blend image1 and image2 using 'factor'.
|
| 94 |
+
Factor can be above 0.0. A value of 0.0 means only image1 is used.
|
| 95 |
+
A value of 1.0 means only image2 is used. A value between 0.0 and
|
| 96 |
+
1.0 means we linearly interpolate the pixel values between the two
|
| 97 |
+
images. A value greater than 1.0 "extrapolates" the difference
|
| 98 |
+
between the two pixel values, and we clip the results to values
|
| 99 |
+
between 0 and 255.
|
| 100 |
+
Args:
|
| 101 |
+
image1: An image Tensor of type uint8.
|
| 102 |
+
image2: An image Tensor of type uint8.
|
| 103 |
+
factor: A floating point value above 0.0.
|
| 104 |
+
Returns:
|
| 105 |
+
A blended image Tensor of type uint8.
|
| 106 |
+
"""
|
| 107 |
+
if factor == 0.0:
|
| 108 |
+
return tf.convert_to_tensor(image1)
|
| 109 |
+
if factor == 1.0:
|
| 110 |
+
return tf.convert_to_tensor(image2)
|
| 111 |
+
|
| 112 |
+
image1 = tf.to_float(image1)
|
| 113 |
+
image2 = tf.to_float(image2)
|
| 114 |
+
|
| 115 |
+
difference = image2 - image1
|
| 116 |
+
scaled = factor * difference
|
| 117 |
+
|
| 118 |
+
# Do addition in float.
|
| 119 |
+
temp = tf.to_float(image1) + scaled
|
| 120 |
+
|
| 121 |
+
# Interpolate
|
| 122 |
+
if factor > 0.0 and factor < 1.0:
|
| 123 |
+
# Interpolation means we always stay within 0 and 255.
|
| 124 |
+
return tf.cast(temp, tf.uint8)
|
| 125 |
+
|
| 126 |
+
# Extrapolate:
|
| 127 |
+
#
|
| 128 |
+
# We need to clip and then cast.
|
| 129 |
+
return tf.cast(tf.clip_by_value(temp, 0.0, 255.0), tf.uint8)
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def cutout(image, pad_size, replace=0):
|
| 133 |
+
"""Apply cutout (https://arxiv.org/abs/1708.04552) to image.
|
| 134 |
+
This operation applies a (2*pad_size x 2*pad_size) mask of zeros to
|
| 135 |
+
a random location within `img`. The pixel values filled in will be of the
|
| 136 |
+
value `replace`. The located where the mask will be applied is randomly
|
| 137 |
+
chosen uniformly over the whole image.
|
| 138 |
+
Args:
|
| 139 |
+
image: An image Tensor of type uint8.
|
| 140 |
+
pad_size: Specifies how big the zero mask that will be generated is that
|
| 141 |
+
is applied to the image. The mask will be of size
|
| 142 |
+
(2*pad_size x 2*pad_size).
|
| 143 |
+
replace: What pixel value to fill in the image in the area that has
|
| 144 |
+
the cutout mask applied to it.
|
| 145 |
+
Returns:
|
| 146 |
+
An image Tensor that is of type uint8.
|
| 147 |
+
"""
|
| 148 |
+
image_height = tf.shape(image)[0]
|
| 149 |
+
image_width = tf.shape(image)[1]
|
| 150 |
+
|
| 151 |
+
# Sample the center location in the image where the zero mask will be applied.
|
| 152 |
+
cutout_center_height = tf.random_uniform(
|
| 153 |
+
shape=[], minval=0, maxval=image_height,
|
| 154 |
+
dtype=tf.int32)
|
| 155 |
+
|
| 156 |
+
cutout_center_width = tf.random_uniform(
|
| 157 |
+
shape=[], minval=0, maxval=image_width,
|
| 158 |
+
dtype=tf.int32)
|
| 159 |
+
|
| 160 |
+
lower_pad = tf.maximum(0, cutout_center_height - pad_size)
|
| 161 |
+
upper_pad = tf.maximum(0, image_height - cutout_center_height - pad_size)
|
| 162 |
+
left_pad = tf.maximum(0, cutout_center_width - pad_size)
|
| 163 |
+
right_pad = tf.maximum(0, image_width - cutout_center_width - pad_size)
|
| 164 |
+
|
| 165 |
+
cutout_shape = [image_height - (lower_pad + upper_pad),
|
| 166 |
+
image_width - (left_pad + right_pad)]
|
| 167 |
+
padding_dims = [[lower_pad, upper_pad], [left_pad, right_pad]]
|
| 168 |
+
mask = tf.pad(
|
| 169 |
+
tf.zeros(cutout_shape, dtype=image.dtype),
|
| 170 |
+
padding_dims, constant_values=1)
|
| 171 |
+
mask = tf.expand_dims(mask, -1)
|
| 172 |
+
mask = tf.tile(mask, [1, 1, 3])
|
| 173 |
+
image = tf.where(
|
| 174 |
+
tf.equal(mask, 0),
|
| 175 |
+
tf.ones_like(image, dtype=image.dtype) * replace,
|
| 176 |
+
image)
|
| 177 |
+
return image
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
def solarize(image, threshold=128):
|
| 181 |
+
# For each pixel in the image, select the pixel
|
| 182 |
+
# if the value is less than the threshold.
|
| 183 |
+
# Otherwise, subtract 255 from the pixel.
|
| 184 |
+
return tf.where(image < threshold, image, 255 - image)
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
def solarize_add(image, addition=0, threshold=128):
|
| 188 |
+
# For each pixel in the image less than threshold
|
| 189 |
+
# we add 'addition' amount to it and then clip the
|
| 190 |
+
# pixel value to be between 0 and 255. The value
|
| 191 |
+
# of 'addition' is between -128 and 128.
|
| 192 |
+
added_image = tf.cast(image, tf.int64) + addition
|
| 193 |
+
added_image = tf.cast(tf.clip_by_value(added_image, 0, 255), tf.uint8)
|
| 194 |
+
return tf.where(image < threshold, added_image, image)
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
def color(image, factor):
|
| 198 |
+
"""Equivalent of PIL Color."""
|
| 199 |
+
degenerate = tf.image.grayscale_to_rgb(tf.image.rgb_to_grayscale(image))
|
| 200 |
+
return blend(degenerate, image, factor)
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
def contrast(image, factor):
|
| 204 |
+
"""Equivalent of PIL Contrast."""
|
| 205 |
+
degenerate = tf.image.rgb_to_grayscale(image)
|
| 206 |
+
# Cast before calling tf.histogram.
|
| 207 |
+
degenerate = tf.cast(degenerate, tf.int32)
|
| 208 |
+
|
| 209 |
+
# Compute the grayscale histogram, then compute the mean pixel value,
|
| 210 |
+
# and create a constant image size of that value. Use that as the
|
| 211 |
+
# blending degenerate target of the original image.
|
| 212 |
+
hist = tf.histogram_fixed_width(degenerate, [0, 255], nbins=256)
|
| 213 |
+
mean = tf.reduce_sum(tf.cast(hist, tf.float32)) / 256.0
|
| 214 |
+
degenerate = tf.ones_like(degenerate, dtype=tf.float32) * mean
|
| 215 |
+
degenerate = tf.clip_by_value(degenerate, 0.0, 255.0)
|
| 216 |
+
degenerate = tf.image.grayscale_to_rgb(tf.cast(degenerate, tf.uint8))
|
| 217 |
+
return blend(degenerate, image, factor)
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
def brightness(image, factor):
|
| 221 |
+
"""Equivalent of PIL Brightness."""
|
| 222 |
+
degenerate = tf.zeros_like(image)
|
| 223 |
+
return blend(degenerate, image, factor)
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
def posterize(image, bits):
|
| 227 |
+
"""Equivalent of PIL Posterize."""
|
| 228 |
+
shift = 8 - bits
|
| 229 |
+
return tf.bitwise.left_shift(tf.bitwise.right_shift(image, shift), shift)
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
def rotate(image, degrees, replace):
|
| 233 |
+
"""Rotates the image by degrees either clockwise or counterclockwise.
|
| 234 |
+
Args:
|
| 235 |
+
image: An image Tensor of type uint8.
|
| 236 |
+
degrees: Float, a scalar angle in degrees to rotate all images by. If
|
| 237 |
+
degrees is positive the image will be rotated clockwise otherwise it will
|
| 238 |
+
be rotated counterclockwise.
|
| 239 |
+
replace: A one or three value 1D tensor to fill empty pixels caused by
|
| 240 |
+
the rotate operation.
|
| 241 |
+
Returns:
|
| 242 |
+
The rotated version of image.
|
| 243 |
+
"""
|
| 244 |
+
# Convert from degrees to radians.
|
| 245 |
+
degrees_to_radians = math.pi / 180.0
|
| 246 |
+
radians = degrees * degrees_to_radians
|
| 247 |
+
|
| 248 |
+
# In practice, we should randomize the rotation degrees by flipping
|
| 249 |
+
# it negatively half the time, but that's done on 'degrees' outside
|
| 250 |
+
# of the function.
|
| 251 |
+
image = contrib_image.rotate(wrap(image), radians)
|
| 252 |
+
return unwrap(image, replace)
|
| 253 |
+
|
| 254 |
+
|
| 255 |
+
def translate_x(image, pixels, replace):
|
| 256 |
+
"""Equivalent of PIL Translate in X dimension."""
|
| 257 |
+
image = contrib_image.translate(wrap(image), [-pixels, 0])
|
| 258 |
+
return unwrap(image, replace)
|
| 259 |
+
|
| 260 |
+
|
| 261 |
+
def translate_y(image, pixels, replace):
|
| 262 |
+
"""Equivalent of PIL Translate in Y dimension."""
|
| 263 |
+
image = contrib_image.translate(wrap(image), [0, -pixels])
|
| 264 |
+
return unwrap(image, replace)
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
def shear_x(image, level, replace):
|
| 268 |
+
"""Equivalent of PIL Shearing in X dimension."""
|
| 269 |
+
# Shear parallel to x axis is a projective transform
|
| 270 |
+
# with a matrix form of:
|
| 271 |
+
# [1 level
|
| 272 |
+
# 0 1].
|
| 273 |
+
image = contrib_image.transform(
|
| 274 |
+
wrap(image), [1., level, 0., 0., 1., 0., 0., 0.])
|
| 275 |
+
return unwrap(image, replace)
|
| 276 |
+
|
| 277 |
+
|
| 278 |
+
def shear_y(image, level, replace):
|
| 279 |
+
"""Equivalent of PIL Shearing in Y dimension."""
|
| 280 |
+
# Shear parallel to y axis is a projective transform
|
| 281 |
+
# with a matrix form of:
|
| 282 |
+
# [1 0
|
| 283 |
+
# level 1].
|
| 284 |
+
image = contrib_image.transform(
|
| 285 |
+
wrap(image), [1., 0., 0., level, 1., 0., 0., 0.])
|
| 286 |
+
return unwrap(image, replace)
|
| 287 |
+
|
| 288 |
+
|
| 289 |
+
def autocontrast(image):
|
| 290 |
+
"""Implements Autocontrast function from PIL using TF ops.
|
| 291 |
+
Args:
|
| 292 |
+
image: A 3D uint8 tensor.
|
| 293 |
+
Returns:
|
| 294 |
+
The image after it has had autocontrast applied to it and will be of type
|
| 295 |
+
uint8.
|
| 296 |
+
"""
|
| 297 |
+
|
| 298 |
+
def scale_channel(image):
|
| 299 |
+
"""Scale the 2D image using the autocontrast rule."""
|
| 300 |
+
# A possibly cheaper version can be done using cumsum/unique_with_counts
|
| 301 |
+
# over the histogram values, rather than iterating over the entire image.
|
| 302 |
+
# to compute mins and maxes.
|
| 303 |
+
lo = tf.to_float(tf.reduce_min(image))
|
| 304 |
+
hi = tf.to_float(tf.reduce_max(image))
|
| 305 |
+
|
| 306 |
+
# Scale the image, making the lowest value 0 and the highest value 255.
|
| 307 |
+
def scale_values(im):
|
| 308 |
+
scale = 255.0 / (hi - lo)
|
| 309 |
+
offset = -lo * scale
|
| 310 |
+
im = tf.to_float(im) * scale + offset
|
| 311 |
+
im = tf.clip_by_value(im, 0.0, 255.0)
|
| 312 |
+
return tf.cast(im, tf.uint8)
|
| 313 |
+
|
| 314 |
+
result = tf.cond(hi > lo, lambda: scale_values(image), lambda: image)
|
| 315 |
+
return result
|
| 316 |
+
|
| 317 |
+
# Assumes RGB for now. Scales each channel independently
|
| 318 |
+
# and then stacks the result.
|
| 319 |
+
s1 = scale_channel(image[:, :, 0])
|
| 320 |
+
s2 = scale_channel(image[:, :, 1])
|
| 321 |
+
s3 = scale_channel(image[:, :, 2])
|
| 322 |
+
image = tf.stack([s1, s2, s3], 2)
|
| 323 |
+
return image
|
| 324 |
+
|
| 325 |
+
|
| 326 |
+
def sharpness(image, factor):
|
| 327 |
+
"""Implements Sharpness function from PIL using TF ops."""
|
| 328 |
+
orig_image = image
|
| 329 |
+
image = tf.cast(image, tf.float32)
|
| 330 |
+
# Make image 4D for conv operation.
|
| 331 |
+
image = tf.expand_dims(image, 0)
|
| 332 |
+
# SMOOTH PIL Kernel.
|
| 333 |
+
kernel = tf.constant(
|
| 334 |
+
[[1, 1, 1], [1, 5, 1], [1, 1, 1]], dtype=tf.float32,
|
| 335 |
+
shape=[3, 3, 1, 1]) / 13.
|
| 336 |
+
# Tile across channel dimension.
|
| 337 |
+
kernel = tf.tile(kernel, [1, 1, 3, 1])
|
| 338 |
+
strides = [1, 1, 1, 1]
|
| 339 |
+
with tf.device('/cpu:0'):
|
| 340 |
+
# Some augmentation that uses depth-wise conv will cause crashing when
|
| 341 |
+
# training on GPU. See ((internal link)) for details.
|
| 342 |
+
degenerate = tf.nn.depthwise_conv2d(
|
| 343 |
+
image, kernel, strides, padding='VALID', rate=[1, 1])
|
| 344 |
+
degenerate = tf.clip_by_value(degenerate, 0.0, 255.0)
|
| 345 |
+
degenerate = tf.squeeze(tf.cast(degenerate, tf.uint8), [0])
|
| 346 |
+
|
| 347 |
+
# For the borders of the resulting image, fill in the values of the
|
| 348 |
+
# original image.
|
| 349 |
+
mask = tf.ones_like(degenerate)
|
| 350 |
+
padded_mask = tf.pad(mask, [[1, 1], [1, 1], [0, 0]])
|
| 351 |
+
padded_degenerate = tf.pad(degenerate, [[1, 1], [1, 1], [0, 0]])
|
| 352 |
+
result = tf.where(tf.equal(padded_mask, 1), padded_degenerate, orig_image)
|
| 353 |
+
|
| 354 |
+
# Blend the final result.
|
| 355 |
+
return blend(result, orig_image, factor)
|
| 356 |
+
|
| 357 |
+
|
| 358 |
+
def equalize(image):
|
| 359 |
+
"""Implements Equalize function from PIL using TF ops."""
|
| 360 |
+
def scale_channel(im, c):
|
| 361 |
+
"""Scale the data in the channel to implement equalize."""
|
| 362 |
+
im = tf.cast(im[:, :, c], tf.int32)
|
| 363 |
+
# Compute the histogram of the image channel.
|
| 364 |
+
histo = tf.histogram_fixed_width(im, [0, 255], nbins=256)
|
| 365 |
+
|
| 366 |
+
# For the purposes of computing the step, filter out the nonzeros.
|
| 367 |
+
nonzero = tf.where(tf.not_equal(histo, 0))
|
| 368 |
+
nonzero_histo = tf.reshape(tf.gather(histo, nonzero), [-1])
|
| 369 |
+
step = (tf.reduce_sum(nonzero_histo) - nonzero_histo[-1]) // 255
|
| 370 |
+
|
| 371 |
+
def build_lut(histo, step):
|
| 372 |
+
# Compute the cumulative sum, shifting by step // 2
|
| 373 |
+
# and then normalization by step.
|
| 374 |
+
lut = (tf.cumsum(histo) + (step // 2)) // step
|
| 375 |
+
# Shift lut, prepending with 0.
|
| 376 |
+
lut = tf.concat([[0], lut[:-1]], 0)
|
| 377 |
+
# Clip the counts to be in range. This is done
|
| 378 |
+
# in the C code for image.point.
|
| 379 |
+
return tf.clip_by_value(lut, 0, 255)
|
| 380 |
+
|
| 381 |
+
# If step is zero, return the original image. Otherwise, build
|
| 382 |
+
# lut from the full histogram and step and then index from it.
|
| 383 |
+
result = tf.cond(tf.equal(step, 0),
|
| 384 |
+
lambda: im,
|
| 385 |
+
lambda: tf.gather(build_lut(histo, step), im))
|
| 386 |
+
|
| 387 |
+
return tf.cast(result, tf.uint8)
|
| 388 |
+
|
| 389 |
+
# Assumes RGB for now. Scales each channel independently
|
| 390 |
+
# and then stacks the result.
|
| 391 |
+
s1 = scale_channel(image, 0)
|
| 392 |
+
s2 = scale_channel(image, 1)
|
| 393 |
+
s3 = scale_channel(image, 2)
|
| 394 |
+
image = tf.stack([s1, s2, s3], 2)
|
| 395 |
+
return image
|
| 396 |
+
|
| 397 |
+
|
| 398 |
+
def invert(image):
|
| 399 |
+
"""Inverts the image pixels."""
|
| 400 |
+
image = tf.convert_to_tensor(image)
|
| 401 |
+
return 255 - image
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
def wrap(image):
|
| 405 |
+
"""Returns 'image' with an extra channel set to all 1s."""
|
| 406 |
+
shape = tf.shape(image)
|
| 407 |
+
extended_channel = tf.ones([shape[0], shape[1], 1], image.dtype)
|
| 408 |
+
extended = tf.concat([image, extended_channel], 2)
|
| 409 |
+
return extended
|
| 410 |
+
|
| 411 |
+
|
| 412 |
+
def unwrap(image, replace):
|
| 413 |
+
"""Unwraps an image produced by wrap.
|
| 414 |
+
Where there is a 0 in the last channel for every spatial position,
|
| 415 |
+
the rest of the three channels in that spatial dimension are grayed
|
| 416 |
+
(set to 128). Operations like translate and shear on a wrapped
|
| 417 |
+
Tensor will leave 0s in empty locations. Some transformations look
|
| 418 |
+
at the intensity of values to do preprocessing, and we want these
|
| 419 |
+
empty pixels to assume the 'average' value, rather than pure black.
|
| 420 |
+
Args:
|
| 421 |
+
image: A 3D Image Tensor with 4 channels.
|
| 422 |
+
replace: A one or three value 1D tensor to fill empty pixels.
|
| 423 |
+
Returns:
|
| 424 |
+
image: A 3D image Tensor with 3 channels.
|
| 425 |
+
"""
|
| 426 |
+
image_shape = tf.shape(image)
|
| 427 |
+
# Flatten the spatial dimensions.
|
| 428 |
+
flattened_image = tf.reshape(image, [-1, image_shape[2]])
|
| 429 |
+
|
| 430 |
+
# Find all pixels where the last channel is zero.
|
| 431 |
+
alpha_channel = flattened_image[:, 3]
|
| 432 |
+
|
| 433 |
+
replace = tf.concat([replace, tf.ones([1], image.dtype)], 0)
|
| 434 |
+
|
| 435 |
+
# Where they are zero, fill them in with 'replace'.
|
| 436 |
+
flattened_image = tf.where(
|
| 437 |
+
tf.equal(alpha_channel, 0),
|
| 438 |
+
tf.ones_like(flattened_image, dtype=image.dtype) * replace,
|
| 439 |
+
flattened_image)
|
| 440 |
+
|
| 441 |
+
image = tf.reshape(flattened_image, image_shape)
|
| 442 |
+
image = tf.slice(image, [0, 0, 0], [image_shape[0], image_shape[1], 3])
|
| 443 |
+
return image
|
| 444 |
+
|
| 445 |
+
|
| 446 |
+
NAME_TO_FUNC = {
|
| 447 |
+
'AutoContrast': autocontrast,
|
| 448 |
+
'Equalize': equalize,
|
| 449 |
+
'Invert': invert,
|
| 450 |
+
'Rotate': rotate,
|
| 451 |
+
'Posterize': posterize,
|
| 452 |
+
'Solarize': solarize,
|
| 453 |
+
'SolarizeAdd': solarize_add,
|
| 454 |
+
'Color': color,
|
| 455 |
+
'Contrast': contrast,
|
| 456 |
+
'Brightness': brightness,
|
| 457 |
+
'Sharpness': sharpness,
|
| 458 |
+
'ShearX': shear_x,
|
| 459 |
+
'ShearY': shear_y,
|
| 460 |
+
'TranslateX': translate_x,
|
| 461 |
+
'TranslateY': translate_y,
|
| 462 |
+
'Cutout': cutout,
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
|
| 466 |
+
def _randomly_negate_tensor(tensor):
|
| 467 |
+
"""With 50% prob turn the tensor negative."""
|
| 468 |
+
should_flip = tf.cast(tf.floor(tf.random_uniform([]) + 0.5), tf.bool)
|
| 469 |
+
final_tensor = tf.cond(should_flip, lambda: tensor, lambda: -tensor)
|
| 470 |
+
return final_tensor
|
| 471 |
+
|
| 472 |
+
|
| 473 |
+
def _rotate_level_to_arg(level):
|
| 474 |
+
level = (level/_MAX_LEVEL) * 30.
|
| 475 |
+
level = _randomly_negate_tensor(level)
|
| 476 |
+
return (level,)
|
| 477 |
+
|
| 478 |
+
|
| 479 |
+
def _shrink_level_to_arg(level):
|
| 480 |
+
"""Converts level to ratio by which we shrink the image content."""
|
| 481 |
+
if level == 0:
|
| 482 |
+
return (1.0,) # if level is zero, do not shrink the image
|
| 483 |
+
# Maximum shrinking ratio is 2.9.
|
| 484 |
+
level = 2. / (_MAX_LEVEL / level) + 0.9
|
| 485 |
+
return (level,)
|
| 486 |
+
|
| 487 |
+
|
| 488 |
+
def _enhance_level_to_arg(level):
|
| 489 |
+
return ((level/_MAX_LEVEL) * 1.8 + 0.1,)
|
| 490 |
+
|
| 491 |
+
|
| 492 |
+
def _shear_level_to_arg(level):
|
| 493 |
+
level = (level/_MAX_LEVEL) * 0.3
|
| 494 |
+
# Flip level to negative with 50% chance.
|
| 495 |
+
level = _randomly_negate_tensor(level)
|
| 496 |
+
return (level,)
|
| 497 |
+
|
| 498 |
+
|
| 499 |
+
def _translate_level_to_arg(level, translate_const):
|
| 500 |
+
level = (level/_MAX_LEVEL) * float(translate_const)
|
| 501 |
+
# Flip level to negative with 50% chance.
|
| 502 |
+
level = _randomly_negate_tensor(level)
|
| 503 |
+
return (level,)
|
| 504 |
+
|
| 505 |
+
|
| 506 |
+
def level_to_arg(hparams):
|
| 507 |
+
return {
|
| 508 |
+
'AutoContrast': lambda level: (),
|
| 509 |
+
'Equalize': lambda level: (),
|
| 510 |
+
'Invert': lambda level: (),
|
| 511 |
+
'Rotate': _rotate_level_to_arg,
|
| 512 |
+
'Posterize': lambda level: (int((level/_MAX_LEVEL) * 4),),
|
| 513 |
+
'Solarize': lambda level: (int((level/_MAX_LEVEL) * 256),),
|
| 514 |
+
'SolarizeAdd': lambda level: (int((level/_MAX_LEVEL) * 110),),
|
| 515 |
+
'Color': _enhance_level_to_arg,
|
| 516 |
+
'Contrast': _enhance_level_to_arg,
|
| 517 |
+
'Brightness': _enhance_level_to_arg,
|
| 518 |
+
'Sharpness': _enhance_level_to_arg,
|
| 519 |
+
'ShearX': _shear_level_to_arg,
|
| 520 |
+
'ShearY': _shear_level_to_arg,
|
| 521 |
+
'Cutout': lambda level: (int((level/_MAX_LEVEL) * hparams.cutout_const),),
|
| 522 |
+
'TranslateX': lambda level: _translate_level_to_arg(
|
| 523 |
+
level, hparams.translate_const),
|
| 524 |
+
'TranslateY': lambda level: _translate_level_to_arg(
|
| 525 |
+
level, hparams.translate_const),
|
| 526 |
+
# pylint:enable=g-long-lambda
|
| 527 |
+
}
|
| 528 |
+
|
| 529 |
+
|
| 530 |
+
def _parse_policy_info(name, prob, level, replace_value, augmentation_hparams):
|
| 531 |
+
"""Return the function that corresponds to `name` and update `level` param."""
|
| 532 |
+
func = NAME_TO_FUNC[name]
|
| 533 |
+
args = level_to_arg(augmentation_hparams)[name](level)
|
| 534 |
+
|
| 535 |
+
# Check to see if prob is passed into function. This is used for operations
|
| 536 |
+
# where we alter bboxes independently.
|
| 537 |
+
# pytype:disable=wrong-arg-types
|
| 538 |
+
if 'prob' in inspect.getfullargspec(func).args:
|
| 539 |
+
args = tuple([prob] + list(args))
|
| 540 |
+
# pytype:enable=wrong-arg-types
|
| 541 |
+
|
| 542 |
+
# Add in replace arg if it is required for the function that is being called.
|
| 543 |
+
# pytype:disable=wrong-arg-types
|
| 544 |
+
if 'replace' in inspect.getfullargspec(func).args:
|
| 545 |
+
# Make sure replace is the final argument
|
| 546 |
+
assert 'replace' == inspect.getfullargspec(func).args[-1]
|
| 547 |
+
args = tuple(list(args) + [replace_value])
|
| 548 |
+
# pytype:enable=wrong-arg-types
|
| 549 |
+
|
| 550 |
+
return (func, prob, args)
|
| 551 |
+
|
| 552 |
+
|
| 553 |
+
def _apply_func_with_prob(func, image, args, prob):
|
| 554 |
+
"""Apply `func` to image w/ `args` as input with probability `prob`."""
|
| 555 |
+
assert isinstance(args, tuple)
|
| 556 |
+
|
| 557 |
+
# If prob is a function argument, then this randomness is being handled
|
| 558 |
+
# inside the function, so make sure it is always called.
|
| 559 |
+
# pytype:disable=wrong-arg-types
|
| 560 |
+
if 'prob' in inspect.getfullargspec(func).args:
|
| 561 |
+
prob = 1.0
|
| 562 |
+
# pytype:enable=wrong-arg-types
|
| 563 |
+
|
| 564 |
+
# Apply the function with probability `prob`.
|
| 565 |
+
should_apply_op = tf.cast(
|
| 566 |
+
tf.floor(tf.random_uniform([], dtype=tf.float32) + prob), tf.bool)
|
| 567 |
+
augmented_image = tf.cond(
|
| 568 |
+
should_apply_op,
|
| 569 |
+
lambda: func(image, *args),
|
| 570 |
+
lambda: image)
|
| 571 |
+
return augmented_image
|
| 572 |
+
|
| 573 |
+
|
| 574 |
+
def select_and_apply_random_policy(policies, image):
|
| 575 |
+
"""Select a random policy from `policies` and apply it to `image`."""
|
| 576 |
+
policy_to_select = tf.random_uniform([], maxval=len(policies), dtype=tf.int32)
|
| 577 |
+
# Note that using tf.case instead of tf.conds would result in significantly
|
| 578 |
+
# larger graphs and would even break export for some larger policies.
|
| 579 |
+
for (i, policy) in enumerate(policies):
|
| 580 |
+
image = tf.cond(
|
| 581 |
+
tf.equal(i, policy_to_select),
|
| 582 |
+
lambda selected_policy=policy: selected_policy(image),
|
| 583 |
+
lambda: image)
|
| 584 |
+
return image
|
| 585 |
+
|
| 586 |
+
|
| 587 |
+
def build_and_apply_nas_policy(policies, image,
|
| 588 |
+
augmentation_hparams):
|
| 589 |
+
"""Build a policy from the given policies passed in and apply to image.
|
| 590 |
+
Args:
|
| 591 |
+
policies: list of lists of tuples in the form `(func, prob, level)`, `func`
|
| 592 |
+
is a string name of the augmentation function, `prob` is the probability
|
| 593 |
+
of applying the `func` operation, `level` is the input argument for
|
| 594 |
+
`func`.
|
| 595 |
+
image: tf.Tensor that the resulting policy will be applied to.
|
| 596 |
+
augmentation_hparams: Hparams associated with the NAS learned policy.
|
| 597 |
+
Returns:
|
| 598 |
+
A version of image that now has data augmentation applied to it based on
|
| 599 |
+
the `policies` pass into the function.
|
| 600 |
+
"""
|
| 601 |
+
replace_value = [128, 128, 128]
|
| 602 |
+
|
| 603 |
+
# func is the string name of the augmentation function, prob is the
|
| 604 |
+
# probability of applying the operation and level is the parameter associated
|
| 605 |
+
# with the tf op.
|
| 606 |
+
|
| 607 |
+
# tf_policies are functions that take in an image and return an augmented
|
| 608 |
+
# image.
|
| 609 |
+
tf_policies = []
|
| 610 |
+
for policy in policies:
|
| 611 |
+
tf_policy = []
|
| 612 |
+
# Link string name to the correct python function and make sure the correct
|
| 613 |
+
# argument is passed into that function.
|
| 614 |
+
for policy_info in policy:
|
| 615 |
+
policy_info = list(policy_info) + [replace_value, augmentation_hparams]
|
| 616 |
+
|
| 617 |
+
tf_policy.append(_parse_policy_info(*policy_info))
|
| 618 |
+
# Now build the tf policy that will apply the augmentation procedue
|
| 619 |
+
# on image.
|
| 620 |
+
def make_final_policy(tf_policy_):
|
| 621 |
+
def final_policy(image_):
|
| 622 |
+
for func, prob, args in tf_policy_:
|
| 623 |
+
image_ = _apply_func_with_prob(
|
| 624 |
+
func, image_, args, prob)
|
| 625 |
+
return image_
|
| 626 |
+
return final_policy
|
| 627 |
+
tf_policies.append(make_final_policy(tf_policy))
|
| 628 |
+
|
| 629 |
+
augmented_image = select_and_apply_random_policy(
|
| 630 |
+
tf_policies, image)
|
| 631 |
+
return augmented_image
|
| 632 |
+
|
| 633 |
+
|
| 634 |
+
def distort_image_with_autoaugment(image, augmentation_name):
|
| 635 |
+
"""Applies the AutoAugment policy to `image`.
|
| 636 |
+
AutoAugment is from the paper: https://arxiv.org/abs/1805.09501.
|
| 637 |
+
Args:
|
| 638 |
+
image: `Tensor` of shape [height, width, 3] representing an image.
|
| 639 |
+
augmentation_name: The name of the AutoAugment policy to use. The available
|
| 640 |
+
options are `v0` and `test`. `v0` is the policy used for
|
| 641 |
+
all of the results in the paper and was found to achieve the best results
|
| 642 |
+
on the COCO dataset. `v1`, `v2` and `v3` are additional good policies
|
| 643 |
+
found on the COCO dataset that have slight variation in what operations
|
| 644 |
+
were used during the search procedure along with how many operations are
|
| 645 |
+
applied in parallel to a single image (2 vs 3).
|
| 646 |
+
Returns:
|
| 647 |
+
A tuple containing the augmented versions of `image`.
|
| 648 |
+
"""
|
| 649 |
+
available_policies = {'v0': policy_v0,
|
| 650 |
+
'test': policy_vtest}
|
| 651 |
+
if augmentation_name not in available_policies:
|
| 652 |
+
raise ValueError('Invalid augmentation_name: {}'.format(augmentation_name))
|
| 653 |
+
|
| 654 |
+
policy = available_policies[augmentation_name]()
|
| 655 |
+
# Hparams that will be used for AutoAugment.
|
| 656 |
+
augmentation_hparams = HParams(
|
| 657 |
+
cutout_const=100, translate_const=250)
|
| 658 |
+
|
| 659 |
+
return build_and_apply_nas_policy(policy, image, augmentation_hparams)
|
| 660 |
+
|
| 661 |
+
|
| 662 |
+
def distort_image_with_randaugment(image, num_layers, magnitude):
|
| 663 |
+
"""Applies the RandAugment policy to `image`.
|
| 664 |
+
RandAugment is from the paper https://arxiv.org/abs/1909.13719,
|
| 665 |
+
Args:
|
| 666 |
+
image: `Tensor` of shape [height, width, 3] representing an image.
|
| 667 |
+
num_layers: Integer, the number of augmentation transformations to apply
|
| 668 |
+
sequentially to an image. Represented as (N) in the paper. Usually best
|
| 669 |
+
values will be in the range [1, 3].
|
| 670 |
+
magnitude: Integer, shared magnitude across all augmentation operations.
|
| 671 |
+
Represented as (M) in the paper. Usually best values are in the range
|
| 672 |
+
[5, 30].
|
| 673 |
+
Returns:
|
| 674 |
+
The augmented version of `image`.
|
| 675 |
+
"""
|
| 676 |
+
replace_value = [128] * 3
|
| 677 |
+
tf.logging.info('Using RandAug.')
|
| 678 |
+
augmentation_hparams = HParams(
|
| 679 |
+
cutout_const=40, translate_const=100)
|
| 680 |
+
available_ops = [
|
| 681 |
+
'AutoContrast', 'Equalize', 'Invert', 'Rotate', 'Posterize',
|
| 682 |
+
'Solarize', 'Color', 'Contrast', 'Brightness', 'Sharpness',
|
| 683 |
+
'ShearX', 'ShearY', 'TranslateX', 'TranslateY', 'Cutout', 'SolarizeAdd']
|
| 684 |
+
|
| 685 |
+
for layer_num in range(num_layers):
|
| 686 |
+
op_to_select = tf.random_uniform(
|
| 687 |
+
[], maxval=len(available_ops), dtype=tf.int32)
|
| 688 |
+
random_magnitude = float(magnitude)
|
| 689 |
+
with tf.name_scope('randaug_layer_{}'.format(layer_num)):
|
| 690 |
+
for (i, op_name) in enumerate(available_ops):
|
| 691 |
+
prob = tf.random_uniform([], minval=0.2, maxval=0.8, dtype=tf.float32)
|
| 692 |
+
func, _, args = _parse_policy_info(op_name, prob, random_magnitude,
|
| 693 |
+
replace_value, augmentation_hparams)
|
| 694 |
+
image = tf.cond(
|
| 695 |
+
tf.equal(i, op_to_select),
|
| 696 |
+
lambda selected_func=func, selected_args=args: selected_func(
|
| 697 |
+
image, *selected_args),
|
| 698 |
+
# pylint:enable=g-long-lambda
|
| 699 |
+
lambda: image)
|
| 700 |
+
return image
|
Tipsomaly/model/big_vision/pp/archive/randaug.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""RandAug depends on deprecated tfa.image package, now defunct."""
|
| 16 |
+
|
| 17 |
+
from big_vision.pp import registry
|
| 18 |
+
from big_vision.pp import utils
|
| 19 |
+
from big_vision.pp.archive import autoaugment
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@registry.Registry.register("preprocess_ops.randaug")
|
| 23 |
+
@utils.InKeyOutKey()
|
| 24 |
+
def get_randaug(num_layers: int = 2, magnitude: int = 10):
|
| 25 |
+
"""Creates a function that applies RandAugment.
|
| 26 |
+
|
| 27 |
+
RandAugment is from the paper https://arxiv.org/abs/1909.13719,
|
| 28 |
+
|
| 29 |
+
Args:
|
| 30 |
+
num_layers: Integer, the number of augmentation transformations to apply
|
| 31 |
+
sequentially to an image. Represented as (N) in the paper. Usually best
|
| 32 |
+
values will be in the range [1, 3].
|
| 33 |
+
magnitude: Integer, shared magnitude across all augmentation operations.
|
| 34 |
+
Represented as (M) in the paper. Usually best values are in the range [5,
|
| 35 |
+
30].
|
| 36 |
+
|
| 37 |
+
Returns:
|
| 38 |
+
a function that applies RandAugment.
|
| 39 |
+
"""
|
| 40 |
+
|
| 41 |
+
def _randaug(image):
|
| 42 |
+
return autoaugment.distort_image_with_randaugment(
|
| 43 |
+
image, num_layers, magnitude
|
| 44 |
+
)
|
| 45 |
+
|
| 46 |
+
return _randaug
|
Tipsomaly/model/big_vision/pp/proj/clippo/download_unifont.sh
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2022 Big Vision Authors.
|
| 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 |
+
#!/bin/bash
|
| 16 |
+
# This is intended to be run from the big_vision repository root:
|
| 17 |
+
#
|
| 18 |
+
# bash big_vision/pp/proj/clippo/download_unifont.sh
|
| 19 |
+
wget https://unifoundry.com/pub/unifont/unifont-9.0.06/font-builds/unifont-9.0.06.hex.gz https://unifoundry.com/pub/unifont/unifont-9.0.06/font-builds/unifont_upper-9.0.06.hex.gz
|
| 20 |
+
gunzip unifont-9.0.06.hex.gz unifont_upper-9.0.06.hex.gz
|
| 21 |
+
mv unifont-9.0.06.hex unifont_upper-9.0.06.hex big_vision/pp/proj/clippo/
|
Tipsomaly/model/big_vision/pp/proj/givt/pp_ops.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""GIVT-specific preprocessing ops."""
|
| 16 |
+
|
| 17 |
+
from big_vision.pp import registry
|
| 18 |
+
from big_vision.pp import utils
|
| 19 |
+
import tensorflow as tf
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
@registry.Registry.register("preprocess_ops.bin_nyu_depth")
|
| 23 |
+
@utils.InKeyOutKey(indefault="labels", outdefault="labels")
|
| 24 |
+
def get_bin_nyu_depth(min_depth=0.001, max_depth=10.0, num_bins=256):
|
| 25 |
+
"""Binning of NYU depth for UViM in preprocessing rather than model."""
|
| 26 |
+
|
| 27 |
+
def _bin_depth(labels): # pylint: disable=missing-docstring
|
| 28 |
+
labels = (labels - min_depth) / (max_depth - min_depth)
|
| 29 |
+
labels *= num_bins
|
| 30 |
+
labels = tf.cast(tf.floor(labels), tf.int32)
|
| 31 |
+
labels = tf.minimum(labels, num_bins - 1)
|
| 32 |
+
labels = tf.maximum(labels, 0)
|
| 33 |
+
return labels
|
| 34 |
+
|
| 35 |
+
return _bin_depth
|
| 36 |
+
|
Tipsomaly/model/big_vision/pp/proj/image_text/ops_naflex.py
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Big Vision Authors.
|
| 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 |
+
"""NaFlex (NaViT + FlexiViT) preprocessing ops."""
|
| 16 |
+
|
| 17 |
+
from big_vision.pp import utils
|
| 18 |
+
from big_vision.pp.registry import Registry
|
| 19 |
+
import big_vision.utils as u
|
| 20 |
+
import tensorflow as tf
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
def _get_image_size_for_seq(
|
| 24 |
+
image_hw,
|
| 25 |
+
patch_size: int,
|
| 26 |
+
max_sequence_len: int,
|
| 27 |
+
divisible_by_patch: bool = True,
|
| 28 |
+
eps: float = 1e-5):
|
| 29 |
+
"""Determine scaling ratio and image size for `get_resize_to_sequence`.
|
| 30 |
+
|
| 31 |
+
Did not prove monotonicity necessary for binary search correctness, but this
|
| 32 |
+
works well in practice.
|
| 33 |
+
|
| 34 |
+
Args:
|
| 35 |
+
image_hw: Image height and width.
|
| 36 |
+
patch_size: Patchification patch size.
|
| 37 |
+
max_sequence_len: Maximum allowed sequence length for the resulting image.
|
| 38 |
+
divisible_by_patch: If True, the resulting image height and width must be
|
| 39 |
+
divisible by patch size.
|
| 40 |
+
eps: Small number used for binary search convergence.
|
| 41 |
+
|
| 42 |
+
Returns:
|
| 43 |
+
ratio: Scaling ratio to applied to image.
|
| 44 |
+
target_hw: Target image height and width taking into account the scaling
|
| 45 |
+
ratio and the `divisible_by_patch` constraint.
|
| 46 |
+
"""
|
| 47 |
+
def search_not_done(lb, rb):
|
| 48 |
+
return (rb - lb) >= eps
|
| 49 |
+
|
| 50 |
+
def prepare_target_hw(ratio):
|
| 51 |
+
target_hw = tf.cast(image_hw, tf.float32) * ratio
|
| 52 |
+
if divisible_by_patch:
|
| 53 |
+
# Round to multiple of patch size as we want to avoid dropping patches.
|
| 54 |
+
target_hw = patch_size * tf.math.ceil(target_hw / patch_size)
|
| 55 |
+
# Ensure that the image is at least 1 patch in height / width.
|
| 56 |
+
target_hw = tf.maximum(target_hw, patch_size)
|
| 57 |
+
target_hw = tf.cast(target_hw, tf.int32)
|
| 58 |
+
return target_hw
|
| 59 |
+
|
| 60 |
+
def is_feasible(ratio):
|
| 61 |
+
target_hw = prepare_target_hw(ratio)
|
| 62 |
+
num_patches = target_hw / patch_size
|
| 63 |
+
sequence_len = tf.math.reduce_prod(num_patches)
|
| 64 |
+
return sequence_len <= max_sequence_len
|
| 65 |
+
|
| 66 |
+
def _search_fn(lb, rb):
|
| 67 |
+
mid = (lb + rb) / 2
|
| 68 |
+
return tf.cond(is_feasible(mid), lambda: (mid, rb), lambda: (lb, mid))
|
| 69 |
+
|
| 70 |
+
# Left and right boundaries for the binary search.
|
| 71 |
+
state = (tf.constant(eps / 10.), tf.constant(100.0))
|
| 72 |
+
ratio, _ = tf.while_loop(
|
| 73 |
+
search_not_done, _search_fn, state, parallel_iterations=1)
|
| 74 |
+
tf.assert_greater(
|
| 75 |
+
ratio, eps, message="Binary search failed - image too large?")
|
| 76 |
+
tf.assert_less(
|
| 77 |
+
ratio, 100.0, message="Binary search failed - image too small?")
|
| 78 |
+
|
| 79 |
+
return ratio, prepare_target_hw(ratio)
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
@Registry.register("preprocess_ops.resize_to_sequence")
|
| 83 |
+
@utils.InKeyOutKey(indefault="image", outdefault="image")
|
| 84 |
+
def get_resize_to_sequence(
|
| 85 |
+
patch_size: int,
|
| 86 |
+
max_sequence_len: int,
|
| 87 |
+
divisible_by_patch: bool = True,
|
| 88 |
+
eps: float = 1e-5):
|
| 89 |
+
"""Resizes image if it violates restrictions on sequence/side length.
|
| 90 |
+
|
| 91 |
+
This op attempts to resize the image in an AR-preserving manner such that:
|
| 92 |
+
- The sequence length of the resulting image (after patchification) is
|
| 93 |
+
maximized, but <= `max_sequence_len`.
|
| 94 |
+
|
| 95 |
+
This op *violates* the AR-preserving property if:
|
| 96 |
+
- Image size resulting from the above procedure is not a multiple of patch
|
| 97 |
+
size. In this case AR is distorted to ensure this condition is satisfied.
|
| 98 |
+
|
| 99 |
+
Args:
|
| 100 |
+
patch_size: Patchification patch size.
|
| 101 |
+
max_sequence_len: Maximum allowed sequence length for the resulting image.
|
| 102 |
+
divisible_by_patch: If True, the resulting image height and width must be
|
| 103 |
+
divisible by patch size.
|
| 104 |
+
eps: Small number used for binary search convergence.
|
| 105 |
+
|
| 106 |
+
Returns:
|
| 107 |
+
Pre-processing op.
|
| 108 |
+
"""
|
| 109 |
+
def _resize_fn(image):
|
| 110 |
+
"""Performs binary search to find a feasible image size."""
|
| 111 |
+
image_hw = tf.shape(image)[:2]
|
| 112 |
+
_, target_hw = _get_image_size_for_seq(
|
| 113 |
+
image_hw,
|
| 114 |
+
patch_size,
|
| 115 |
+
max_sequence_len,
|
| 116 |
+
divisible_by_patch=divisible_by_patch,
|
| 117 |
+
eps=eps)
|
| 118 |
+
|
| 119 |
+
# Actually resize image.
|
| 120 |
+
image = tf.image.resize(
|
| 121 |
+
image,
|
| 122 |
+
target_hw,
|
| 123 |
+
preserve_aspect_ratio=False,
|
| 124 |
+
antialias=True)
|
| 125 |
+
return tf.ensure_shape(image, [None, None, 3])
|
| 126 |
+
return _resize_fn
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
@Registry.register("preprocess_ops.central_crop_to_sequence")
|
| 130 |
+
@utils.InKeyOutKey(indefault="image", outdefault="image")
|
| 131 |
+
def get_central_crop_to_sequence(
|
| 132 |
+
patch_size: int,
|
| 133 |
+
max_sequence_len: int,
|
| 134 |
+
divisible_by_patch: bool = True,
|
| 135 |
+
eps: float = 1e-5):
|
| 136 |
+
"""Central crops image such that patch sequence length satisfies constraints.
|
| 137 |
+
|
| 138 |
+
Constraints used are the as in `resize_to_sequence`.
|
| 139 |
+
|
| 140 |
+
Args:
|
| 141 |
+
patch_size: Patchification patch size.
|
| 142 |
+
max_sequence_len: Maximum allowed sequence length for the resulting image.
|
| 143 |
+
divisible_by_patch: If True, the resulting image height and width must be
|
| 144 |
+
divisible by patch size.
|
| 145 |
+
eps: Small number used for binary search convergence.
|
| 146 |
+
|
| 147 |
+
Returns:
|
| 148 |
+
Pre-processing op.
|
| 149 |
+
"""
|
| 150 |
+
def _central_crop_fn(image):
|
| 151 |
+
image_hw = tf.shape(image)[:2]
|
| 152 |
+
_, target_hw = _get_image_size_for_seq(
|
| 153 |
+
image_hw,
|
| 154 |
+
patch_size,
|
| 155 |
+
max_sequence_len,
|
| 156 |
+
divisible_by_patch=divisible_by_patch,
|
| 157 |
+
eps=eps)
|
| 158 |
+
|
| 159 |
+
tf.assert_greater(
|
| 160 |
+
image_hw + 1, target_hw,
|
| 161 |
+
"For central crop the image must be larger than target HW.")
|
| 162 |
+
offset_hw = (image_hw - target_hw) // 2
|
| 163 |
+
image = image[
|
| 164 |
+
offset_hw[0]:offset_hw[0] + target_hw[0],
|
| 165 |
+
offset_hw[1]:offset_hw[1] + target_hw[1],
|
| 166 |
+
:]
|
| 167 |
+
return tf.ensure_shape(image, [None, None, 3])
|
| 168 |
+
return _central_crop_fn
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
@Registry.register("preprocess_ops.patchify")
|
| 172 |
+
@utils.InKeyOutKey(indefault="image", outdefault="image")
|
| 173 |
+
def get_patchify(patch_size):
|
| 174 |
+
"""Reshapes image into patches and provides patch coordinates."""
|
| 175 |
+
ph, pw = utils.maybe_repeat(patch_size, 2)
|
| 176 |
+
|
| 177 |
+
def _patchify(img):
|
| 178 |
+
patches = tf.image.extract_patches(
|
| 179 |
+
img[None, ...], sizes=[1, ph, pw, 1], strides=[1, ph, pw, 1],
|
| 180 |
+
rates=[1, 1, 1, 1], padding="VALID")[0]
|
| 181 |
+
# Patches is now (nh, nw, ph*pw*3), i.e. contains flattened patches.
|
| 182 |
+
nh, nw, d = tf.shape(patches)[0], tf.shape(patches)[1], tf.shape(patches)[2]
|
| 183 |
+
|
| 184 |
+
# Get two (nh, nw) tensors of y/x indices of the patches.
|
| 185 |
+
gy, gx = tf.meshgrid(tf.range(nh), tf.range(nw), indexing="ij")
|
| 186 |
+
|
| 187 |
+
return {
|
| 188 |
+
"patches": tf.reshape(patches, (nh * nw, d)),
|
| 189 |
+
"yidx": tf.reshape(gy, [nh * nw]),
|
| 190 |
+
"xidx": tf.reshape(gx, [nh * nw]),
|
| 191 |
+
"type": tf.fill([nh * nw], 1),
|
| 192 |
+
}
|
| 193 |
+
return _patchify
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
@Registry.register("preprocess_ops.tuplify")
|
| 197 |
+
def get_tuplify(inkeys: list[str], outkey: str):
|
| 198 |
+
"""Create a tuple of multiple inputs."""
|
| 199 |
+
def tuplify(data):
|
| 200 |
+
data[outkey] = tuple(u.tree_get(data, k) for k in inkeys)
|
| 201 |
+
return data
|
| 202 |
+
return tuplify
|
Tipsomaly/model/big_vision/tools/lit_demo/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# LiT-Demo
|
| 2 |
+
|
| 3 |
+
See https://blog.tensorflow.org/2022/08/jax-on-web-with-tensorflowjs.html
|
| 4 |
+
|
| 5 |
+
Demo originally appeared on Twitter
|
| 6 |
+
https://twitter.com/AndreasPSteiner/status/1514722383818543106
|
| 7 |
+
|
| 8 |
+
App published at
|
| 9 |
+
https://google-research.github.io/vision_transformer/lit
|
| 10 |
+
|
| 11 |
+
## Build
|
| 12 |
+
|
| 13 |
+
Install packages (tested with node v16.17.0 and yarn 1.22.19)
|
| 14 |
+
|
| 15 |
+
```bash
|
| 16 |
+
yarn
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
## Run
|
| 21 |
+
|
| 22 |
+
The web app will appear on http://localhost:8000
|
| 23 |
+
|
| 24 |
+
```
|
| 25 |
+
node build.js
|
| 26 |
+
```
|