AlirezaSalehi99 commited on
Commit
c14fe32
·
verified ·
1 Parent(s): 95cc73b

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Tipsomaly/model/big_vision/datasets/ai2d/ai2d.py +209 -0
  2. Tipsomaly/model/big_vision/datasets/aokvqa/aokvqa.py +182 -0
  3. Tipsomaly/model/big_vision/datasets/chartqa/chartqa.py +122 -0
  4. Tipsomaly/model/big_vision/datasets/coco35l/coco35l.py +154 -0
  5. Tipsomaly/model/big_vision/datasets/countbenchqa/countbenchqa.py +164 -0
  6. Tipsomaly/model/big_vision/datasets/docvqa/docvqa.py +110 -0
  7. Tipsomaly/model/big_vision/datasets/gqa/gqa.py +167 -0
  8. Tipsomaly/model/big_vision/datasets/imagenet/class_names.py +0 -0
  9. Tipsomaly/model/big_vision/datasets/infovqa/infovqa.py +141 -0
  10. Tipsomaly/model/big_vision/datasets/okvqa/okvqa.py +213 -0
  11. Tipsomaly/model/big_vision/datasets/pope/pope.py +145 -0
  12. Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/coco_caption.py +145 -0
  13. Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/rsvqa.py +173 -0
  14. Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/science_qa.py +122 -0
  15. Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/segmentation.py +270 -0
  16. Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/storepreds.py +77 -0
  17. Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/tallyqa.py +144 -0
  18. Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/vqa.py +163 -0
  19. Tipsomaly/model/big_vision/evaluators/proj/paligemma/transfers/vqav2.py +197 -0
  20. Tipsomaly/model/big_vision/pp/__pycache__/__init__.cpython-311.pyc +0 -0
  21. Tipsomaly/model/big_vision/pp/__pycache__/__init__.cpython-312.pyc +0 -0
  22. Tipsomaly/model/big_vision/pp/__pycache__/__init__.cpython-39.pyc +0 -0
  23. Tipsomaly/model/big_vision/pp/__pycache__/builder.cpython-311.pyc +0 -0
  24. Tipsomaly/model/big_vision/pp/__pycache__/builder.cpython-312.pyc +0 -0
  25. Tipsomaly/model/big_vision/pp/__pycache__/builder.cpython-39.pyc +0 -0
  26. Tipsomaly/model/big_vision/pp/__pycache__/ops_general.cpython-311.pyc +0 -0
  27. Tipsomaly/model/big_vision/pp/__pycache__/ops_general.cpython-312.pyc +0 -0
  28. Tipsomaly/model/big_vision/pp/__pycache__/ops_general.cpython-39.pyc +0 -0
  29. Tipsomaly/model/big_vision/pp/__pycache__/ops_image.cpython-311.pyc +0 -0
  30. Tipsomaly/model/big_vision/pp/__pycache__/ops_image.cpython-312.pyc +0 -0
  31. Tipsomaly/model/big_vision/pp/__pycache__/ops_image.cpython-39.pyc +0 -0
  32. Tipsomaly/model/big_vision/pp/__pycache__/ops_text.cpython-311.pyc +0 -0
  33. Tipsomaly/model/big_vision/pp/__pycache__/ops_text.cpython-312.pyc +0 -0
  34. Tipsomaly/model/big_vision/pp/__pycache__/ops_text.cpython-39.pyc +0 -0
  35. Tipsomaly/model/big_vision/pp/__pycache__/registry.cpython-311.pyc +0 -0
  36. Tipsomaly/model/big_vision/pp/__pycache__/registry.cpython-312.pyc +0 -0
  37. Tipsomaly/model/big_vision/pp/__pycache__/registry.cpython-39.pyc +0 -0
  38. Tipsomaly/model/big_vision/pp/__pycache__/tokenizer.cpython-311.pyc +0 -0
  39. Tipsomaly/model/big_vision/pp/__pycache__/tokenizer.cpython-312.pyc +0 -0
  40. Tipsomaly/model/big_vision/pp/__pycache__/tokenizer.cpython-39.pyc +0 -0
  41. Tipsomaly/model/big_vision/pp/__pycache__/utils.cpython-311.pyc +0 -0
  42. Tipsomaly/model/big_vision/pp/__pycache__/utils.cpython-312.pyc +0 -0
  43. Tipsomaly/model/big_vision/pp/__pycache__/utils.cpython-39.pyc +0 -0
  44. Tipsomaly/model/big_vision/pp/archive/__init__.py +0 -0
  45. Tipsomaly/model/big_vision/pp/archive/autoaugment.py +700 -0
  46. Tipsomaly/model/big_vision/pp/archive/randaug.py +46 -0
  47. Tipsomaly/model/big_vision/pp/proj/clippo/download_unifont.sh +21 -0
  48. Tipsomaly/model/big_vision/pp/proj/givt/pp_ops.py +36 -0
  49. Tipsomaly/model/big_vision/pp/proj/image_text/ops_naflex.py +202 -0
  50. 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
+ ```