AlirezaSalehi99 commited on
Commit
0c3fcb9
·
verified ·
1 Parent(s): c14fe32

Add files using upload-large-folder tool

Browse files
Files changed (50) hide show
  1. Tipsomaly/model/big_vision/configs/proj/paligemma/transfers/tallyqa.py +191 -0
  2. Tipsomaly/model/big_vision/configs/proj/paligemma/transfers/textcaps.py +181 -0
  3. Tipsomaly/model/big_vision/models/__pycache__/__init__.cpython-311.pyc +0 -0
  4. Tipsomaly/model/big_vision/models/__pycache__/__init__.cpython-312.pyc +0 -0
  5. Tipsomaly/model/big_vision/models/__pycache__/__init__.cpython-39.pyc +0 -0
  6. Tipsomaly/model/big_vision/models/__pycache__/common.cpython-311.pyc +0 -0
  7. Tipsomaly/model/big_vision/models/__pycache__/common.cpython-312.pyc +0 -0
  8. Tipsomaly/model/big_vision/models/__pycache__/vit.cpython-311.pyc +0 -0
  9. Tipsomaly/model/big_vision/models/__pycache__/vit.cpython-312.pyc +0 -0
  10. Tipsomaly/model/big_vision/models/ppp/__init__.py +0 -0
  11. Tipsomaly/model/big_vision/models/ppp/gemma.py +651 -0
  12. Tipsomaly/model/big_vision/models/proj/__init__.py +0 -0
  13. Tipsomaly/model/big_vision/models/proj/cappa/cappa.py +428 -0
  14. Tipsomaly/model/big_vision/models/proj/clippo/one_tower.py +96 -0
  15. Tipsomaly/model/big_vision/models/proj/flaxformer/bert.py +94 -0
  16. Tipsomaly/model/big_vision/models/proj/flaxformer/bert_test.py +77 -0
  17. Tipsomaly/model/big_vision/models/proj/flaxformer/bert_test_util.py +261 -0
  18. Tipsomaly/model/big_vision/models/proj/flexi/vit.py +226 -0
  19. Tipsomaly/model/big_vision/models/proj/flexi/vit_test.py +127 -0
  20. Tipsomaly/model/big_vision/models/proj/givt/adaptor.py +174 -0
  21. Tipsomaly/model/big_vision/models/proj/givt/adaptor_test.py +50 -0
  22. Tipsomaly/model/big_vision/models/proj/givt/cnn.py +376 -0
  23. Tipsomaly/model/big_vision/models/proj/givt/decode.py +386 -0
  24. Tipsomaly/model/big_vision/models/proj/givt/decode_test.py +121 -0
  25. Tipsomaly/model/big_vision/models/proj/givt/givt.py +820 -0
  26. Tipsomaly/model/big_vision/models/proj/givt/givt_test.py +124 -0
  27. Tipsomaly/model/big_vision/models/proj/givt/parallel_decode.py +523 -0
  28. Tipsomaly/model/big_vision/models/proj/givt/parallel_decode_test.py +154 -0
  29. Tipsomaly/model/big_vision/models/proj/givt/vae.py +94 -0
  30. Tipsomaly/model/big_vision/models/proj/givt/vit.py +188 -0
  31. Tipsomaly/model/big_vision/models/proj/image_text/naflex_vit.py +300 -0
  32. Tipsomaly/model/big_vision/models/proj/image_text/two_towers.py +178 -0
  33. Tipsomaly/model/big_vision/pp/proj/clippo/pp_ops.py +153 -0
  34. Tipsomaly/model/big_vision/pp/proj/flaxformer/bert_ops.py +86 -0
  35. Tipsomaly/model/big_vision/pp/proj/flaxformer/bert_ops_test.py +69 -0
  36. Tipsomaly/model/big_vision/pp/proj/image_text/__pycache__/ops_naflex.cpython-311.pyc +0 -0
  37. Tipsomaly/model/big_vision/pp/proj/image_text/__pycache__/ops_naflex.cpython-312.pyc +0 -0
  38. Tipsomaly/model/big_vision/pp/proj/image_text/__pycache__/ops_naflex.cpython-39.pyc +0 -0
  39. Tipsomaly/model/big_vision/pp/proj/image_text/ops_naflex_test.py +77 -0
  40. Tipsomaly/model/big_vision/pp/proj/paligemma/__pycache__/ops.cpython-311.pyc +0 -0
  41. Tipsomaly/model/big_vision/pp/proj/paligemma/__pycache__/ops.cpython-312.pyc +0 -0
  42. Tipsomaly/model/big_vision/pp/proj/paligemma/__pycache__/ops.cpython-39.pyc +0 -0
  43. Tipsomaly/model/big_vision/pp/proj/paligemma/ops.py +168 -0
  44. Tipsomaly/model/big_vision/pp/proj/paligemma/robustness.py +72 -0
  45. Tipsomaly/model/big_vision/pp/proj/paligemma/sciqa_ops.py +65 -0
  46. Tipsomaly/model/big_vision/pp/proj/paligemma/segmentation.py +160 -0
  47. Tipsomaly/model/big_vision/pp/proj/paligemma/video.py +103 -0
  48. Tipsomaly/model/big_vision/pp/proj/paligemma/widgetcap.py +36 -0
  49. Tipsomaly/model/big_vision/pp/proj/uvim/pp_ops.py +206 -0
  50. Tipsomaly/model/big_vision/pp/proj/uvim/pp_ops_test.py +128 -0
Tipsomaly/model/big_vision/configs/proj/paligemma/transfers/tallyqa.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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"""PaliGemma transfer to TallyQA.
17
+ """
18
+
19
+ import big_vision.configs.common as bvcc
20
+ from big_vision.configs.proj.paligemma.transfers.common import combine_and_keep_train, combine_and_keep_eval, TOKENIZER
21
+
22
+
23
+ def training_data(res, text_len=32):
24
+ """Creates training data config.
25
+
26
+ See (internal link)
27
+ You can add more arguments beside `res`, but give them good defaults.
28
+
29
+ Args:
30
+ res: The requested image resolution (eg 224)
31
+ text_len: sequence length
32
+
33
+ Returns:
34
+ The ConfigDict for the input section.
35
+ """
36
+ c = bvcc.parse_arg('') # Just make a configdict without extra import.
37
+ c.data = dict(
38
+ name='tallyqa',
39
+ split='train',
40
+ )
41
+
42
+ c.pp = '|'.join([
43
+ f'decode|resize({res}, antialias=True)|value_range(-1, 1)',
44
+ 'strfmt("answer en {question}", outkey="prefix")',
45
+ 'strfmt("{answer}", outkey="suffix")',
46
+ combine_and_keep_train(text_len),
47
+ ])
48
+ return c
49
+
50
+
51
+ def countbenchqa_eval_data(res, text_len=32):
52
+ """Creates eval data config for CountBenchQA."""
53
+ c = bvcc.parse_arg('') # Just make a configdict without extra import.
54
+ c.data = dict(
55
+ name='countbenchqa',
56
+ split='huggingface',
57
+ )
58
+ c.pp = '|'.join([
59
+ f'decode|resize({res}, antialias=True)|value_range(-1, 1)',
60
+ 'strfmt("answer en {question}", outkey="prefix")',
61
+ 'strfmt("{number}", outkey="answer")',
62
+ combine_and_keep_eval(text_len, keep=('answer',)),
63
+ ])
64
+ return c
65
+
66
+
67
+ def add_eval(c, res, text_len=32, **kw):
68
+ """Add eval configs."""
69
+ tallyqa_pp_eval = '|'.join([
70
+ f'decode|resize({res}, antialias=True)|value_range(-1, 1)',
71
+ 'strfmt("answer en {question}", outkey="prefix")',
72
+ 'strfmt("{answer}", outkey="answer")',
73
+ combine_and_keep_eval(text_len, keep=('answer', 'issimple')),
74
+ ])
75
+
76
+ for freq, name, split in [
77
+ (0.1, 'minitrain', 'train[:5%]'),
78
+ # (0.1, 'minival', 'train[-5%:]'),
79
+ (1/4, 'eval', 'test'),
80
+ ]:
81
+ c.evals[f'tallyqa/{name}'] = dict(
82
+ type='proj.paligemma.transfers.tallyqa',
83
+ pred='decode', pred_kw={'max_decode_len': text_len},
84
+ data={**training_data(res, text_len).data, 'split': split},
85
+ log_percent=freq, tokenizer=TOKENIZER, pp_fn=tallyqa_pp_eval)
86
+ c.evals[f'tallyqa/{name}'].update(kw)
87
+
88
+ # CountBenchQA eval. We use the TallyQA eval for this but just pass in
89
+ # different data.
90
+ c.evals['countbenchqa/eval'] = dict(
91
+ type='proj.paligemma.transfers.tallyqa',
92
+ pred='decode', pred_kw={'max_decode_len': text_len},
93
+ data=countbenchqa_eval_data(res, text_len).data,
94
+ log_percent=0.1, # This is a very small and cheap eval set.
95
+ tokenizer=TOKENIZER,
96
+ pp_fn=countbenchqa_eval_data(res, text_len).pp)
97
+ c.evals['countbenchqa/eval'].update(kw)
98
+
99
+
100
+ def add_eval_pplx(c, res, text_len=32):
101
+ """Perplexity evaluator to test runs before implementing the real deal."""
102
+ c_train = training_data(res, text_len) # Use mostly same settings as training.
103
+ for name, split in [
104
+ ('minitrain', 'train[:5%]'), # To gauge memorization.
105
+ # ('minival', 'train[-5%:]'), # To tune hparams.
106
+ ('eval', 'test'), # To compute final publishable scores.
107
+ ]:
108
+ c.evals[f'tallyqa/{name}/pplx'] = dict(
109
+ type='proj.paligemma.perplexity', pred='logits',
110
+ key='text', shift_labels=True,
111
+ log_percent=0.1, # Eval ~10x per run; it's cheap.
112
+ data={**c_train.data, 'split': split},
113
+ pp_fn=c_train.pp,
114
+ )
115
+
116
+
117
+ def sweep_best(add, arg=None): # pylint: disable=unused-argument
118
+ """Train with best hyper-params."""
119
+ add(total_epochs=2, lr=1e-5, wd=0.00, **bvcc.arg(res=224))
120
+ add(total_epochs=2, lr=1e-5, wd=1e-6, **bvcc.arg(res=448))
121
+ add(total_epochs=2, lr=7e-6, wd=7e-7, **bvcc.arg(res=896))
122
+
123
+
124
+ sweep = sweep_best # Choose which sweep to run.
125
+
126
+
127
+ def get_config(arg=None):
128
+ """Config for training."""
129
+ c = bvcc.parse_arg(arg, mode='xm', res=224)
130
+
131
+ c.input = training_data(c.res)
132
+
133
+ # Instead of epochs, you can also use `total_examples` or `total_steps`.
134
+ c.total_epochs = 2
135
+ c.input.batch_size = 256
136
+ c.optax_name = 'scale_by_adam'
137
+ c.optax = dict(b2=0.999)
138
+ c.lr = 1e-5
139
+ c.wd = 0.0
140
+ c.grad_clip_norm = 1.0
141
+ c.label_smoothing = 0.0
142
+ c.schedule = dict(decay_type='cosine', warmup_percent=0.05)
143
+
144
+ # Add evaluators.
145
+ c.evals = {}
146
+ add_eval(c, c.res, batch_size=256)
147
+ add_eval_pplx(c, c.res)
148
+
149
+ # Model section.
150
+ c.model_name = 'proj.paligemma.paligemma'
151
+ c.model = {}
152
+ c.model.img = dict(variant='So400m/14', pool_type='none', scan=True)
153
+ c.model.llm = dict(vocab_size=256_000 + 1024 + 128, dropout=0.0)
154
+ c.model_init = f'pt_{c.res}'
155
+
156
+ # FSDP strategy.
157
+ c.mesh = [('data', -1)]
158
+ c.sharding_strategy = [('.*', 'fsdp(axis="data")')]
159
+ c.sharding_rules = [('act_batch', ('data',))]
160
+
161
+ # These probably do not need any change/tuning
162
+ c.input.shuffle_buffer_size = 50_000
163
+ c.log_training_steps = 50
164
+ c.ckpt_steps = 1_000
165
+ c.pp_modules = ['ops_general', 'ops_image', 'ops_text', 'proj.paligemma.ops']
166
+
167
+ # Update configs for quicker local runs and avoid swapping.
168
+ if c.mode in ('runlocal', 'mock'):
169
+ c.input.shuffle_buffer_size = None
170
+ for ev in c.evals.values():
171
+ ev.data.split = ev.data.split.split('[')[0] + '[:16]'
172
+
173
+ if c.mode == 'runlocal':
174
+ c.log_training_steps = 1
175
+ c.input.batch_size = 2
176
+
177
+ c.seed = 0
178
+ return c
179
+
180
+
181
+ def metrics(arg=None): # pylint: disable=unused-argument
182
+ """Returns a list of metric names."""
183
+ return [
184
+ 'training_loss',
185
+ 'countbenchqa/eval/acc',
186
+ 'tallyqa/minitrain/pplx/avg',
187
+ 'tallyqa/eval/pplx/avg',
188
+ 'tallyqa/eval/acc',
189
+ 'tallyqa/eval/acc/complex',
190
+ 'tallyqa/eval/acc/simple',
191
+ ]
Tipsomaly/model/big_vision/configs/proj/paligemma/transfers/textcaps.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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"""PaliGemma transfer to TextCaps captioning task.
17
+ """
18
+
19
+ import big_vision.configs.common as bvcc
20
+ from big_vision.configs.proj.paligemma.transfers.common import combine_and_keep_train, combine_and_keep_eval, TOKENIZER
21
+
22
+
23
+ def training_data(res, *, final_split, text_len=32, crop='rs'):
24
+ """Creates training data config.
25
+
26
+ See (internal link)
27
+ You can add more arguments beside `res`, but give them good defaults.
28
+
29
+ Args:
30
+ res: The requested image resolution (eg 224).
31
+ final_split: Train on all train data or train[:98%].
32
+ text_len: sequence length.
33
+ crop: one of {'ic', 'rc', 'rs'}.
34
+
35
+ Returns:
36
+ The ConfigDict for the input section.
37
+ """
38
+ c = bvcc.parse_arg('') # Just make a configdict without extra import.
39
+ c.data = dict(
40
+ name='text_caps',
41
+ split='train' if final_split else 'train[:98%]',
42
+ )
43
+
44
+ if crop == 'ic':
45
+ crop = f'inception_crop({res}, area_min=50)'
46
+ elif crop == 'rc':
47
+ crop = f'resize_small({res*8//7})|random_crop({res})'
48
+ elif crop == 'rs':
49
+ crop = f'resize({res})'
50
+ else:
51
+ raise ValueError(f'Unknown crop: {crop}')
52
+
53
+ c.pp = '|'.join([
54
+ 'flatten',
55
+ 'decode', crop, 'value_range(-1, 1)',
56
+ 'choice_no_replacement(inkey="texts", outkey="suffix")',
57
+ 'strfmt("caption en", outkey="prefix")',
58
+ 'lower(key="suffix")',
59
+ combine_and_keep_train(text_len),
60
+ ])
61
+ return c
62
+
63
+
64
+ def add_eval(c, res, text_len=32, **kw):
65
+ """Captioning evaluator with cider/bleu-4/meteor/rouge/spice metrics."""
66
+ # Input eval pp without ground truth text and random crop.
67
+ pp_eval = '|'.join([
68
+ 'decode', f'resize({res})', 'value_range(-1, 1)',
69
+ 'flatten', 'copy("texts", "captions")', # GT for evaluator.
70
+ 'strfmt("caption en", outkey="prefix")',
71
+ combine_and_keep_eval(text_len, keep=('image/id', 'captions')),
72
+ ])
73
+
74
+ for name, split in [
75
+ ('minitrain', 'train[:2%]'),
76
+ ('minival', 'train[-2%:]'),
77
+ ('eval', 'val'),
78
+ ]:
79
+ c.evals[f'textcaps/{name}'] = dict(
80
+ type='proj.paligemma.transfers.coco_caption',
81
+ pred='decode', pred_kw={'max_decode_len': text_len},
82
+ log_percent=0.1, tokenizer=TOKENIZER,
83
+ data={'name': 'text_caps', 'split': split},
84
+ pp_fn=pp_eval,
85
+ )
86
+ c.evals[f'textcaps/{name}'].update(kw)
87
+
88
+
89
+ def add_eval_pplx(c, res, text_len=32):
90
+ """Perplexity evaluator to test runs before implementing the real deal."""
91
+ c_train = training_data(res, final_split=True, text_len=text_len, crop='rs') # Use mostly same settings as training.
92
+ for name, split in [
93
+ ('minitrain', 'train[:2%]'),
94
+ ('minival', 'train[-2%:]'),
95
+ ('eval', 'val'),
96
+ ]:
97
+ c.evals[f'textcaps/{name}/pplx'] = dict(
98
+ type='proj.paligemma.perplexity', pred='logits',
99
+ key='text', shift_labels=True,
100
+ log_percent=0.05, # Eval ~20x per run; it's cheap.
101
+ data={**c_train.data, 'split': split},
102
+ pp_fn=c_train.pp,
103
+ )
104
+
105
+
106
+ def get_config(arg=None):
107
+ """Config for training."""
108
+ c = bvcc.parse_arg(arg, mode='xm', crop='rs', res=224, beam_size=3, final_split=False)
109
+
110
+ c.input = training_data(c.res, final_split=c.final_split, crop=c.crop)
111
+
112
+ c.total_epochs = 5 # Note each example has 5 captions.
113
+ c.input.batch_size = 256
114
+ c.optax_name = 'scale_by_adam'
115
+ c.optax = dict(b2=0.999)
116
+ c.lr = 1e-5
117
+ c.wd = 0.0
118
+ c.grad_clip_norm = 1.0
119
+ c.label_smoothing = 0.0
120
+ c.schedule = dict(decay_type='cosine', warmup_percent=0.05)
121
+
122
+ # Add evaluators.
123
+ c.evals = {}
124
+ add_eval_pplx(c, c.res)
125
+
126
+ if c.beam_size:
127
+ decode_kw = {'pred': 'beam_decode', 'pred_kw': {'beam_size': c.beam_size}}
128
+ else:
129
+ decode_kw = {}
130
+
131
+ add_eval(c, c.res, batch_size=1024, **decode_kw)
132
+
133
+ # Model section.
134
+ c.model_name = 'proj.paligemma.paligemma'
135
+ c.model = {}
136
+ c.model.img = dict(variant='So400m/14', pool_type='none', scan=True)
137
+ c.model.llm = dict(vocab_size=256_000 + 1024 + 128, dropout=0.0)
138
+ c.model_init = f'pt_{c.res}'
139
+
140
+ # FSDP strategy.
141
+ c.mesh = [('data', -1)]
142
+ c.sharding_strategy = [('.*', 'fsdp(axis="data")')]
143
+ c.sharding_rules = [('act_batch', ('data',))]
144
+
145
+ # These probably do not need any change/tuning
146
+ c.input.shuffle_buffer_size = 50_000
147
+ c.log_training_steps = 50
148
+ c.ckpt_steps = 1_000
149
+ c.pp_modules = ['ops_general', 'ops_image', 'ops_text', 'proj.paligemma.ops']
150
+
151
+ # Update configs for quicker local runs and avoid swapping.
152
+ if c.mode in ('runlocal', 'mock'):
153
+ c.input.shuffle_buffer_size = None
154
+ for ev in c.evals.values():
155
+ ev.data.split = ev.data.split.split('[')[0] + '[:16]'
156
+
157
+ if c.mode == 'runlocal':
158
+ c.log_training_steps = 1
159
+ c.input.batch_size = 2
160
+
161
+ c.seed = 0
162
+ return c
163
+
164
+
165
+ def sweep_best(add, arg=None):
166
+ """Train with best hyper-params."""
167
+ c = bvcc.parse_arg(arg, final_split=False)
168
+ # Note: wd=0.0 probably works as good.
169
+ add(lr=1e-5, wd=1e-6, total_epochs=5, **bvcc.arg(res=224, **c))
170
+ add(lr=1e-5, wd=1e-6, total_epochs=5, **bvcc.arg(res=448, **c))
171
+
172
+
173
+ sweep = sweep_best # Choose which sweep to run.
174
+
175
+
176
+ def metrics(arg=None): # pylint: disable=unused-argument
177
+ m = ['training_loss']
178
+ for split in ('eval', 'minival', 'minitrain'):
179
+ m.append(('epoch', f'textcaps/{split}/cider'))
180
+ m.append(('epoch', f'textcaps/{split}/pplx/avg'))
181
+ return m
Tipsomaly/model/big_vision/models/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (170 Bytes). View file
 
Tipsomaly/model/big_vision/models/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (158 Bytes). View file
 
Tipsomaly/model/big_vision/models/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (170 Bytes). View file
 
Tipsomaly/model/big_vision/models/__pycache__/common.cpython-311.pyc ADDED
Binary file (7.68 kB). View file
 
Tipsomaly/model/big_vision/models/__pycache__/common.cpython-312.pyc ADDED
Binary file (6.65 kB). View file
 
Tipsomaly/model/big_vision/models/__pycache__/vit.cpython-311.pyc ADDED
Binary file (27.9 kB). View file
 
Tipsomaly/model/big_vision/models/__pycache__/vit.cpython-312.pyc ADDED
Binary file (26.2 kB). View file
 
Tipsomaly/model/big_vision/models/ppp/__init__.py ADDED
File without changes
Tipsomaly/model/big_vision/models/ppp/gemma.py ADDED
@@ -0,0 +1,651 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """gemma reimplementation for big_vision.
16
+
17
+ We follow this einsum axis naming convention:
18
+ B: batch
19
+ T: query length
20
+ S: k/v length
21
+ N: num query heads
22
+ K: num k/v heads
23
+ G: num query heads per k/v head
24
+ H: head dim
25
+ D: d_model ("features")
26
+
27
+ Example Colab using the models via the PaliGemma decoding logic:
28
+ (internal link)
29
+
30
+ Doc locating the variable initializers in the original code and validating them:
31
+ (internal link)
32
+
33
+ This implementation does *not* currently support the local sliding attention
34
+ pattern used in the v2 models. But since we mostly use sequences <4096 tokens,
35
+ this shouldn't make any difference. Since RoPE embedding is used throughout,
36
+ it's unclear if there is any practical difference (other than wasting some
37
+ memory).
38
+ """
39
+
40
+
41
+ from big_vision.models import common
42
+ import big_vision.utils as u
43
+ import einops
44
+ import flax
45
+ import flax.linen as nn
46
+ import jax
47
+ import jax.numpy as jnp
48
+ import ml_collections
49
+ import numpy as np
50
+ import orbax.checkpoint
51
+
52
+
53
+ def get_config(variant):
54
+ """Returns config for specified gemma variant."""
55
+ if variant == "gemma_2b":
56
+ return ml_collections.ConfigDict(
57
+ dict(
58
+ variant=variant,
59
+ width=2048,
60
+ depth=18,
61
+ mlp_dim=16_384,
62
+ num_heads=8,
63
+ num_kv_heads=1,
64
+ head_dim=256,
65
+ norm_eps=1e-6,
66
+ vocab_size=256_000,
67
+ scan=True,
68
+ remat_policy="nothing_saveable",
69
+ )
70
+ )
71
+ if variant == "gemma_7b":
72
+ return ml_collections.ConfigDict(
73
+ dict(
74
+ variant=variant,
75
+ width=3072,
76
+ depth=28,
77
+ mlp_dim=24_576,
78
+ num_heads=16,
79
+ num_kv_heads=16,
80
+ head_dim=256,
81
+ norm_eps=1e-6,
82
+ vocab_size=256_000,
83
+ scan=True,
84
+ remat_policy="nothing_saveable",
85
+ )
86
+ )
87
+ if variant == "gemma2_2b":
88
+ return ml_collections.ConfigDict(
89
+ dict(
90
+ variant=variant,
91
+ width=2304,
92
+ depth=26,
93
+ mlp_dim=9_216,
94
+ num_heads=8,
95
+ num_kv_heads=4,
96
+ head_dim=256,
97
+ norm_eps=1e-6,
98
+ vocab_size=256_000,
99
+ final_logits_softcap=30.0,
100
+ attn_logits_softcap=50.0,
101
+ post_norms=True,
102
+ scan=True,
103
+ remat_policy="nothing_saveable",
104
+ )
105
+ )
106
+ if variant == "gemma2_9b":
107
+ return ml_collections.ConfigDict(
108
+ dict(
109
+ variant=variant,
110
+ width=3584,
111
+ depth=42,
112
+ mlp_dim=14_336,
113
+ num_heads=16,
114
+ num_kv_heads=8,
115
+ head_dim=256,
116
+ norm_eps=1e-6,
117
+ vocab_size=256_000,
118
+ final_logits_softcap=30.0,
119
+ attn_logits_softcap=50.0,
120
+ post_norms=True,
121
+ scan=True,
122
+ remat_policy="nothing_saveable",
123
+ )
124
+ )
125
+ if variant == "gemma2_27b":
126
+ return ml_collections.ConfigDict(
127
+ dict(
128
+ variant=variant,
129
+ width=4608,
130
+ depth=46,
131
+ mlp_dim=36_864,
132
+ num_heads=32,
133
+ num_kv_heads=16,
134
+ head_dim=128,
135
+ norm_eps=1e-6,
136
+ vocab_size=256_000,
137
+ query_pre_attn_norm="rsqrt_emb_per_head",
138
+ final_logits_softcap=30.0,
139
+ attn_logits_softcap=50.0,
140
+ post_norms=True,
141
+ scan=True,
142
+ remat_policy="nothing_saveable",
143
+ )
144
+ )
145
+ raise ValueError(f"Unknown variant: {variant}")
146
+
147
+
148
+ def _apply_rope(x, *, positions, max_wavelength=10_000):
149
+ """Applies RoPE positions [B, L] to x [B, L, H, D]."""
150
+ freq_exponents = (2. / x.shape[-1]) * jnp.arange(x.shape[-1] // 2)
151
+ timescale = (max_wavelength ** freq_exponents)
152
+ radians = positions[..., None] / timescale[None, None, :]
153
+ radians = radians[..., None, :]
154
+ # radians.shape = [...,L,1,d=D/2]
155
+ sin, cos = jnp.sin(radians), jnp.cos(radians)
156
+ x1, x2 = jnp.split(x, 2, axis=-1)
157
+ res = jnp.concatenate([x1 * cos - x2 * sin, x2 * cos + x1 * sin], axis=-1)
158
+ return res
159
+
160
+
161
+ def _update_kv_cache(module, k, v, cache_size, cache_dtype):
162
+ """Updates KV cache and returns its current contents."""
163
+ initialized = module.has_variable("cache", "idx")
164
+ batch_size, update_len, num_heads, head_dim = k.shape
165
+ cache_dtype = cache_dtype or k.dtype
166
+
167
+ # Idx of which cache row to update next is the same for all examples, so that
168
+ # it allows to update with dynamic_update_slice. But in order to keep things
169
+ # nicely partitioned we store it with leading batch dimension and use only
170
+ # the first entry.
171
+ idx = module.variable("cache", "idx", jnp.zeros, (batch_size,), jnp.int32)
172
+
173
+ kv_shape = (batch_size, cache_size, num_heads, head_dim)
174
+ k_cache = module.variable(
175
+ "cache", "k_cache", jnp.zeros, kv_shape, cache_dtype)
176
+ v_cache = module.variable(
177
+ "cache", "v_cache", jnp.zeros, kv_shape, cache_dtype)
178
+
179
+ if initialized: # write k, v in the next cache position.
180
+ assert update_len == 1, update_len
181
+ # Note: idx is the same for all examples. Use value from example 0.
182
+ indices = (0, idx.value[0], 0, 0)
183
+ k_cache.value = jax.lax.dynamic_update_slice(
184
+ k_cache.value, k.astype(cache_dtype), indices)
185
+ v_cache.value = jax.lax.dynamic_update_slice(
186
+ v_cache.value, v.astype(cache_dtype), indices)
187
+ idx.value = idx.value + 1
188
+ else: # init cache with k, v after padding to cache_size.
189
+ prefill_len = k.shape[1]
190
+ pad_width = ((0, 0), (0, cache_size - prefill_len), (0, 0), (0, 0))
191
+ k_cache.value = jnp.pad(k.astype(cache_dtype), pad_width)
192
+ v_cache.value = jnp.pad(v.astype(cache_dtype), pad_width)
193
+ idx.value = idx.value + prefill_len
194
+
195
+ return k_cache.value.astype(k.dtype), v_cache.value.astype(v.dtype)
196
+
197
+
198
+ def trunc_norm_init(in_axis, out_axis, batch_axis):
199
+ return nn.initializers.variance_scaling(
200
+ 1.0, "fan_in", "truncated_normal",
201
+ in_axis=in_axis, out_axis=out_axis, batch_axis=batch_axis)
202
+
203
+
204
+ class Einsum(nn.Module):
205
+ shape: tuple[int, ...]
206
+ w_init: nn.initializers.Initializer = nn.initializers.zeros_init()
207
+
208
+ @nn.compact
209
+ def __call__(self, eqn, x):
210
+ w = self.param("w", self.w_init, self.shape)
211
+ return jnp.einsum(eqn, x, w)
212
+
213
+
214
+ class RMSNorm(nn.Module):
215
+
216
+ @nn.compact
217
+ def __call__(self, x):
218
+ scale = self.param("scale", nn.initializers.zeros_init(), (x.shape[-1]))
219
+ var = jnp.mean(jnp.square(x), axis=-1, keepdims=True)
220
+ normed_inputs = jnp.asarray(x * jnp.reciprocal(jnp.sqrt(var + 1e-06)))
221
+ normed_inputs = normed_inputs * (1 + scale)
222
+ return normed_inputs
223
+
224
+
225
+ class Embedder(nn.Module):
226
+ """Embedder module."""
227
+
228
+ vocab_size: int
229
+ embed_dim: int
230
+
231
+ def setup(self):
232
+ self.input_embedding_table = self.param(
233
+ "input_embedding",
234
+ nn.initializers.variance_scaling(
235
+ scale=1.0, mode="fan_in", distribution="normal",
236
+ in_axis=1, out_axis=0,),
237
+ (self.vocab_size, self.embed_dim),
238
+ )
239
+
240
+ def encode(self, x):
241
+ x = self.input_embedding_table[(x,)]
242
+ x *= jnp.sqrt(self.embed_dim).astype(x.dtype)
243
+ return x
244
+
245
+ def decode(self, x):
246
+ return jnp.dot(x, self.input_embedding_table.T)
247
+
248
+
249
+ class Attention(nn.Module):
250
+ """Attention module."""
251
+
252
+ num_heads: int
253
+ num_kv_heads: int
254
+ features: int
255
+ head_dim: int
256
+
257
+ query_pre_attn_norm: str
258
+ attn_logits_softcap: float | None
259
+
260
+ cache_dtype: str | None = None
261
+
262
+ def setup(self):
263
+ if self.num_kv_heads == self.num_heads:
264
+ self.qkv_einsum = Einsum(
265
+ shape=(3, self.num_heads, self.features, self.head_dim),
266
+ w_init=trunc_norm_init(
267
+ in_axis=(2,), out_axis=(0, 1, 3), batch_axis=()),
268
+ )
269
+ else:
270
+ # MQA / GQA
271
+ self.q_einsum = Einsum(
272
+ shape=(self.num_heads, self.features, self.head_dim),
273
+ w_init=trunc_norm_init(in_axis=(1,), out_axis=(0, 2), batch_axis=()),
274
+ )
275
+ self.kv_einsum = Einsum(
276
+ shape=(2, self.num_kv_heads, self.features, self.head_dim),
277
+ w_init=trunc_norm_init(
278
+ in_axis=(2,), out_axis=(0, 1, 3), batch_axis=()),
279
+ )
280
+ self.attn_vec_einsum = Einsum(
281
+ shape=(self.num_heads, self.head_dim, self.features),
282
+ w_init=trunc_norm_init(in_axis=(0, 1), out_axis=(2,), batch_axis=()),
283
+ )
284
+
285
+ @nn.compact
286
+ def __call__(self, x, positions, attn_mask, decode, deterministic=True):
287
+ if self.num_kv_heads == self.num_heads:
288
+ q, k, v = self.qkv_einsum("BSD,3KDH->3BSKH", x)
289
+ else:
290
+ q = self.q_einsum("BTD,NDH->BTNH", x)
291
+ k, v = self.kv_einsum("BSD,2KDH->2BSKH", x)
292
+
293
+ q = _apply_rope(q, positions=positions)
294
+ if self.query_pre_attn_norm == "rsqrt_head_dim":
295
+ q *= self.head_dim**-0.5
296
+ elif self.query_pre_attn_norm == "rsqrt_emb_per_head":
297
+ q *= (self.features // self.num_heads)**-0.5
298
+ else:
299
+ raise ValueError(
300
+ f"Unknown query_pre_attn_norm: {self.query_pre_attn_norm}"
301
+ )
302
+
303
+ k = _apply_rope(k, positions=positions)
304
+ if decode:
305
+ k, v = _update_kv_cache(self, k, v,
306
+ cache_size=attn_mask.shape[-1],
307
+ cache_dtype=self.cache_dtype)
308
+
309
+ q = einops.rearrange(q, "B T (K G) H -> B T K G H", K=self.num_kv_heads)
310
+ logits = jnp.einsum("BTKGH,BSKH->BKGTS", q, k)
311
+ logits = logits.astype(jnp.float32)
312
+
313
+ if self.attn_logits_softcap:
314
+ logits = jnp.tanh(logits / self.attn_logits_softcap)
315
+ logits = logits * self.attn_logits_softcap
316
+
317
+ if attn_mask.shape != (q.shape[0], 1, q.shape[1], k.shape[1]):
318
+ raise ValueError(
319
+ f"Attention mask with shape {attn_mask.shape} but shapes for q and k "
320
+ f"are: {q.shape} and {k.shape}"
321
+ )
322
+
323
+ # big_neg = jnp.finfo(logits.dtype).min
324
+ big_neg = -2.3819763e38 # See gemma/modules.py
325
+ masked_logits = jnp.where(attn_mask[:, :, None, :, :], logits, big_neg)
326
+
327
+ probs = jax.nn.softmax(masked_logits, axis=-1).astype(k.dtype)
328
+
329
+ encoded = jnp.einsum("BKGTS,BSKH->BTKGH", probs, v)
330
+ encoded = einops.rearrange(encoded, "B T K G H -> B T (K G) H")
331
+ attn_output = self.attn_vec_einsum("BTNH,NHD->BTD", encoded)
332
+
333
+ return attn_output
334
+
335
+
336
+ class FeedForward(nn.Module):
337
+ """Feed forward module."""
338
+
339
+ features: int
340
+ hidden_dim: int
341
+
342
+ @nn.compact
343
+ def __call__(self, x):
344
+ w_gating = self.param(
345
+ "gating_einsum",
346
+ trunc_norm_init(in_axis=(1,), out_axis=(0, 2), batch_axis=()),
347
+ ((2, self.features, self.hidden_dim)),
348
+ )
349
+ ff_gate = jnp.dot(x, w_gating[0])
350
+ gate_value = nn.gelu(ff_gate)
351
+
352
+ ff1 = jnp.dot(x, w_gating[1])
353
+ activations = gate_value * ff1
354
+
355
+ w_linear = self.param(
356
+ "linear",
357
+ trunc_norm_init(in_axis=(0,), out_axis=(1,), batch_axis=()),
358
+ (self.hidden_dim, self.features),
359
+ )
360
+ outputs = jnp.dot(activations, w_linear)
361
+
362
+ return outputs
363
+
364
+
365
+ class Block(nn.Module):
366
+ """Transformer block."""
367
+
368
+ num_heads: int
369
+ num_kv_heads: int
370
+ embed_dim: int
371
+ head_dim: int
372
+ hidden_dim: int
373
+
374
+ query_pre_attn_norm: str
375
+ attn_logits_softcap: float | None
376
+ post_norms: bool
377
+
378
+ dropout: float = 0.0
379
+ dropout_bdims: tuple[int, ...] = ()
380
+ cache_dtype: str | None = None
381
+
382
+ def setup(self):
383
+ self.pre_attention_norm = RMSNorm()
384
+ self.attn = Attention(
385
+ num_heads=self.num_heads,
386
+ num_kv_heads=self.num_kv_heads,
387
+ features=self.embed_dim,
388
+ head_dim=self.head_dim,
389
+ cache_dtype=self.cache_dtype,
390
+ query_pre_attn_norm=self.query_pre_attn_norm,
391
+ attn_logits_softcap=self.attn_logits_softcap,
392
+ )
393
+ self.pre_ffw_norm = RMSNorm()
394
+ self.mlp = FeedForward(features=self.embed_dim, hidden_dim=self.hidden_dim)
395
+ if self.dropout:
396
+ self.drop = nn.Dropout(self.dropout, self.dropout_bdims)
397
+ else:
398
+ self.drop = lambda x, _: x
399
+ if self.post_norms:
400
+ self.post_attention_norm = RMSNorm()
401
+ self.post_ffw_norm = RMSNorm()
402
+
403
+ def __call__(self, x, unused_scan_arg, positions, attn_mask,
404
+ decode, deterministic=True):
405
+ x = nn.with_logical_constraint(x, ("act_batch", "act_len", "act_emb"))
406
+ inputs_normalized = self.pre_attention_norm(x)
407
+ attn_output = self.attn(inputs_normalized, positions, attn_mask,
408
+ decode, deterministic)
409
+ if self.post_norms:
410
+ attn_output = self.post_attention_norm(attn_output)
411
+ attn_output = self.drop(attn_output, deterministic)
412
+ attn_output += x
413
+ residual = attn_output
414
+ attn_output = self.pre_ffw_norm(attn_output)
415
+ outputs = self.mlp(attn_output)
416
+ outputs = self.drop(outputs, deterministic)
417
+ if self.post_norms:
418
+ outputs = self.post_ffw_norm(outputs)
419
+ outputs = residual + outputs
420
+ return outputs, unused_scan_arg
421
+
422
+
423
+ class Model(nn.Module):
424
+ """gemma model."""
425
+
426
+ variant: str
427
+
428
+ width: int
429
+ depth: int
430
+ mlp_dim: int
431
+ num_heads: int
432
+ num_kv_heads: int
433
+ head_dim: int
434
+ norm_eps: float
435
+ vocab_size: int
436
+
437
+ query_pre_attn_norm: str = "rsqrt_head_dim"
438
+ final_logits_softcap: float = 0.0
439
+ attn_logits_softcap: float = 0.0
440
+ post_norms: bool = False
441
+
442
+ dropout: float = 0.0
443
+ dropout_bdims: tuple[int, ...] = () # Every float is dropped independently.
444
+ cache_dtype: str | None = None
445
+
446
+ # TODO: Wire this in all places needed so that the model can be
447
+ # run with different activation dtype. For now only float32 runs.
448
+ embed_dtype: str = "float32"
449
+
450
+ scan: bool = False
451
+ remat_policy: str = "none"
452
+
453
+ @nn.compact
454
+ def __call__(
455
+ self, tokens, *,
456
+ embedded_prefix=None,
457
+ embed_only=False,
458
+ pre_logits=None,
459
+ positions=None, mask=None,
460
+ decode=False, deterministic=True,
461
+ ):
462
+ """Embed only, or complete forward pass.
463
+
464
+ Args:
465
+ tokens: Embedded, then and appended to `embedded_prefix`. Can be None.
466
+ embedded_prefix: Optional prefix that is already embedded.
467
+ embed_only: Whether to compute embeddings only.
468
+ pre_logits: If present computes logits from pre_logits and returns.
469
+ positions: Optional `[B, T]` allows to specify the absolute position of
470
+ the tokens.
471
+ mask: Optional attention mask `[B, T, S]`.
472
+ decode: Whether to use kv-cache. Caller must pass masks and positions.
473
+ deterministic: Forwarded to all dropout layers.
474
+
475
+ Returns:
476
+ If `embed_only=False`, then `(logits, out)` will be returned.
477
+ If `embed_only=True`, then the embeddings will be returned.
478
+ """
479
+ out = {}
480
+
481
+ embedder = Embedder(
482
+ vocab_size=self.vocab_size,
483
+ embed_dim=self.width,
484
+ name="embedder")
485
+
486
+ if pre_logits is not None:
487
+ x = out["pre_logits"] = pre_logits
488
+ logits = out["logits"] = embedder.decode(x)
489
+ return logits, out
490
+
491
+ x = []
492
+ if embedded_prefix is not None:
493
+ x.append(embedded_prefix)
494
+ if tokens is not None:
495
+ x.append(embedder.encode(tokens))
496
+
497
+ x = jnp.concatenate(x, axis=-2)
498
+ x = x.astype(self.embed_dtype)
499
+ batch_size, seq_len, width = x.shape
500
+
501
+ if embed_only:
502
+ return x
503
+
504
+ if decode:
505
+ assert positions is not None and mask is not None, (
506
+ "Must explicitly pass positions and mask for decoding.")
507
+
508
+ if positions is None:
509
+ positions = jnp.arange(seq_len).astype(jnp.int32)[None, :]
510
+ assert positions.shape[1] == x.shape[1], (positions.shape, x.shape)
511
+
512
+ if mask is None:
513
+ mask = nn.attention.make_causal_mask(jnp.ones([batch_size, seq_len]))
514
+ if mask.ndim == 3:
515
+ mask = mask[:, None, :, :]
516
+ cache_size = max(seq_len, mask.shape[-1])
517
+ assert mask.shape == (batch_size, 1, seq_len, cache_size), mask.shape
518
+
519
+ if self.remat_policy == "none":
520
+ block_cls = Block
521
+ else:
522
+ block_cls = nn.remat(
523
+ Block,
524
+ prevent_cse=not self.scan,
525
+ static_argnums=(5, 6), # 0=self, 5=decode, 6=deterministic
526
+ policy=getattr(jax.checkpoint_policies, self.remat_policy),
527
+ )
528
+
529
+ block_kw = dict(
530
+ num_heads=self.num_heads,
531
+ head_dim=self.head_dim,
532
+ num_kv_heads=self.num_kv_heads,
533
+ embed_dim=width,
534
+ hidden_dim=self.mlp_dim,
535
+ dropout=self.dropout,
536
+ dropout_bdims=self.dropout_bdims,
537
+ cache_dtype=self.cache_dtype,
538
+ query_pre_attn_norm=self.query_pre_attn_norm,
539
+ attn_logits_softcap=self.attn_logits_softcap,
540
+ post_norms=self.post_norms,
541
+ )
542
+ layers = self.scope.push("layers") # pytype: disable=attribute-error
543
+ if self.scan:
544
+ blocks = [nn.scan(
545
+ block_cls,
546
+ # cache has axis 1 since we want leading dimension to be batch size.
547
+ variable_axes={"params": 0, "cache": 1},
548
+ split_rngs={"params": True, "dropout": True},
549
+ in_axes=nn.broadcast,
550
+ length=self.depth,
551
+ )(
552
+ parent=layers, **block_kw
553
+ )]
554
+ else:
555
+ blocks = [
556
+ block_cls(
557
+ parent=layers.push(str(layer)),
558
+ **block_kw,
559
+ )
560
+ for layer in range(self.depth)
561
+ ]
562
+ unused_scan_arg = ()
563
+ for block in blocks:
564
+ x, unused_scan_arg = block(
565
+ x, unused_scan_arg, positions, mask, decode, deterministic)
566
+
567
+ assert x.dtype == jnp.dtype(self.embed_dtype) # Sanity check.
568
+ out["encoded"] = x
569
+
570
+ x = RMSNorm(name="final_norm")(x)
571
+ out["pre_logits"] = x
572
+
573
+ x = embedder.decode(x)
574
+ out["logits_pre_norm"] = x
575
+ if self.final_logits_softcap:
576
+ x = jnp.tanh(x / self.final_logits_softcap) * self.final_logits_softcap
577
+ out["logits"] = x
578
+
579
+ return x, out
580
+
581
+
582
+ _ORBAX_INITS = {}
583
+ _BV_INITS = {}
584
+
585
+
586
+ def _load_orbax(path):
587
+ """Loads and coverts Orbax gemma checkpoint."""
588
+ checkpointer = orbax.checkpoint.PyTreeCheckpointer()
589
+ params = checkpointer.restore(path)
590
+ params = flax.traverse_util.unflatten_dict(params, sep="/")["transformer"]
591
+ n = sum(1 for k in params if k.startswith("layer_"))
592
+ params["layers"] = jax.tree.map(
593
+ lambda *xs: np.stack(xs), *(params.pop(f"layer_{i}") for i in range(n))
594
+ )
595
+ mlp = params["layers"]["mlp"]
596
+ mlp["gating_einsum"] = mlp["gating_einsum"].pop("w")
597
+ mlp["linear"] = mlp["linear"].pop("w")
598
+ return params
599
+
600
+
601
+ def _del_pad_rows(params):
602
+ """Some checkpoints have 128 unused padding tokens."""
603
+ emb = params["embedder"]["input_embedding"]
604
+ if emb.shape[0] == 256_128:
605
+ params["embedder"]["input_embedding"] = jax.device_get(emb)[:256_000]
606
+ assert params["embedder"]["input_embedding"].shape[0] == 256_000
607
+
608
+
609
+ def _maybe_transpose_gating_einsum(params):
610
+ """The `transpose_gating_einsum` case in gemma/modules.py."""
611
+ mlp = params["layers"]["mlp"]
612
+ *_, d1, d2 = mlp["gating_einsum"].shape
613
+ if d1 > d2:
614
+ *ns, n1, n2 = range(len(mlp["gating_einsum"].shape))
615
+ mlp["gating_einsum"] = mlp["gating_einsum"].transpose(*ns, n2, n1)
616
+
617
+
618
+ def _load_like_bv(params):
619
+ params = jax.tree.map(lambda x: x, params)
620
+ _del_pad_rows(params)
621
+ _maybe_transpose_gating_einsum(params)
622
+ return params
623
+
624
+
625
+ def load(init_params, init_file, model_cfg=None, dont_load=()):
626
+ """Loads existing weights."""
627
+ model_cfg = model_cfg or {}
628
+ variant = model_cfg.get("variant", "gemma_2b")
629
+ init_variant = f"{init_file} {variant}"
630
+ if init_variant in _ORBAX_INITS:
631
+ params = _load_like_bv(_load_orbax(_ORBAX_INITS[init_variant]))
632
+ elif init_variant in _BV_INITS:
633
+ params = _load_like_bv(u.load_params(_BV_INITS[init_variant]))
634
+ else:
635
+ params = u.load_params(init_file)
636
+
637
+ def extend_rows(emb1, target_rows):
638
+ if (missing_rows := target_rows - emb1.shape[0]) == 0:
639
+ return emb1
640
+ assert missing_rows > 0, "You're asking to shrink vocab?!"
641
+ new_rows = np.random.randn(missing_rows, emb1.shape[1])
642
+ new_rows = (new_rows * 0.02).astype(emb1.dtype)
643
+ return np.r_[np.asarray(emb1), new_rows]
644
+
645
+ if "vocab_size" in model_cfg:
646
+ params["embedder"]["input_embedding"] = extend_rows(
647
+ params["embedder"]["input_embedding"],
648
+ model_cfg["vocab_size"],
649
+ )
650
+
651
+ return common.merge_params(params, init_params, dont_load)
Tipsomaly/model/big_vision/models/proj/__init__.py ADDED
File without changes
Tipsomaly/model/big_vision/models/proj/cappa/cappa.py ADDED
@@ -0,0 +1,428 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2023 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
+ """Model definitions for CapPa (https://arxiv.org/abs/2306.07915).
16
+
17
+ Used abbreviations for dimension annotations:
18
+ B: batch size.
19
+ H: image height.
20
+ W: image width.
21
+ P: number of patches (PH/PW: number of patches in height/width dimensions).
22
+ E: embedding size.
23
+ L: sequence length of text tokens.
24
+ V: vocab size.
25
+ """
26
+
27
+ from collections.abc import Sequence
28
+
29
+ from big_vision import utils
30
+ from big_vision.models import common
31
+ from big_vision.models import vit
32
+ import flax
33
+ import flax.linen as nn
34
+ from flax.linen import partitioning
35
+ import jax
36
+ import jax.numpy as jnp
37
+
38
+
39
+ def shift_right(x, axis=1, constant_values=0):
40
+ """Shift to the right on given axis with padding value 0."""
41
+ pad_widths = [(0, 0)] * len(x.shape)
42
+ pad_widths[axis] = (1, 0)
43
+ padded = jnp.pad(x, pad_widths, constant_values=constant_values)
44
+ # Cuts off the rightmost slice of size along the `axis` dimension.
45
+ # Note that `list[:-1]`` is the same as `list[slice(-1)]`.
46
+ return padded[tuple(slice(-1 if i == axis else None) for i in range(x.ndim))]
47
+
48
+
49
+ class MlpBlock(nn.Module):
50
+ """Transformer MLP / feed-forward block with option to deactivate bias."""
51
+ mlp_dim: int | None = None # Defaults to 4x input dim
52
+ dropout: float = 0.0
53
+ use_bias: bool = True
54
+
55
+ @nn.compact
56
+ def __call__(self, x, deterministic=True):
57
+ """Applies Transformer MlpBlock module."""
58
+ inits = dict(
59
+ kernel_init=nn.initializers.xavier_uniform(),
60
+ bias_init=nn.initializers.normal(stddev=1e-6),
61
+ )
62
+
63
+ n, l, d = x.shape # pylint: disable=unused-variable
64
+ x = nn.Dense(self.mlp_dim or 4 * d, use_bias=self.use_bias, **inits)(x)
65
+ x = nn.gelu(x)
66
+ x = nn.Dropout(rate=self.dropout)(x, deterministic)
67
+ x = nn.Dense(d, use_bias=self.use_bias, **inits)(x)
68
+ return x
69
+
70
+
71
+ class EncoderDecoderBlock(nn.Module):
72
+ """Transformer encoder-decoder layer."""
73
+ mlp_dim: int
74
+ num_heads: int
75
+ dropout_rate: float = 0.
76
+ decode: bool = False
77
+ use_bias: bool = True
78
+
79
+ @nn.compact
80
+ def __call__(self, targets, encoded, decoder_mask=None, deterministic=True):
81
+ """Applies EncoderDecoder1DBlock module.
82
+
83
+ Args:
84
+ targets: target text embeddings [B, L, E].
85
+ encoded: encoded image patches from encoder [B, P, E].
86
+ decoder_mask: decoder self-attention mask.
87
+ deterministic: bool, deterministic or not (to apply dropout).
88
+
89
+ Returns:
90
+ output after transformer encoder-decoder block [B, L, E].
91
+ """
92
+ def wlc(f):
93
+ dim_names = ("act_batch", "act_len", "act_emb")
94
+ return nn.with_logical_constraint(f, dim_names)
95
+
96
+ # Decoder block.
97
+ x = wlc(nn.LayerNorm(name="LayerNorm1", use_bias=self.use_bias)(targets))
98
+ x = wlc(nn.SelfAttention(
99
+ num_heads=self.num_heads, use_bias=False, broadcast_dropout=False,
100
+ dropout_rate=self.dropout_rate, decode=self.decode, name="SelfAttn")(
101
+ x, decoder_mask, deterministic=deterministic))
102
+ x = wlc(nn.Dropout(rate=self.dropout_rate)(x, deterministic=deterministic))
103
+ x = wlc(x + targets)
104
+
105
+ if encoded is not None:
106
+ # Encoder-Decoder block.
107
+ y = wlc(nn.LayerNorm(name="LayerNorm2", use_bias=self.use_bias)(x))
108
+ y = wlc(nn.MultiHeadDotProductAttention(
109
+ num_heads=self.num_heads, use_bias=False, broadcast_dropout=False,
110
+ dropout_rate=self.dropout_rate, name="CrossAttn")(
111
+ y, encoded, deterministic=deterministic))
112
+ y = wlc(
113
+ nn.Dropout(rate=self.dropout_rate)(y, deterministic=deterministic))
114
+ y = wlc(y + x)
115
+ else:
116
+ y = x
117
+
118
+ # MLP block.
119
+ z = wlc(nn.LayerNorm(name="LayerNorm3", use_bias=self.use_bias)(y))
120
+ z = wlc(MlpBlock(
121
+ mlp_dim=self.mlp_dim, dropout=self.dropout_rate, use_bias=self.use_bias,
122
+ name="MLP")(z, deterministic=deterministic))
123
+
124
+ return wlc(y + z), None
125
+
126
+
127
+ class Decoder(nn.Module):
128
+ """Transformer decoder with parallel prediction."""
129
+ emb_dim: int
130
+ mlp_dim: int
131
+ num_heads: int
132
+ num_layers: int
133
+ dropout_rate: float = 0.
134
+ output_vocab_size: int = 32_000
135
+
136
+ # Masked prediction training mode
137
+ masked_pred_prob: float = 0.
138
+ masking_ratio: float = 0.
139
+
140
+ # Whether to use bias in MLP blocks and LN
141
+ use_bias: bool = True
142
+
143
+ scan: bool = False
144
+ remat_policy: str = "nothing_saveable"
145
+
146
+ @nn.compact
147
+ def __call__(self,
148
+ encoded,
149
+ targets,
150
+ pos_emb,
151
+ decoder_mask=None,
152
+ decode=False,
153
+ deterministic=True,
154
+ max_decode_length=None):
155
+ """Applies Transformer model on the inputs.
156
+
157
+ Args:
158
+ encoded: encoded image patches from encoder [B, P, E].
159
+ targets: target text tokens [B, L].
160
+ pos_emb: positional embeddings.
161
+ decoder_mask: decoder self-attention mask.
162
+ decode: bool, whether to perform fast autoregressive decoding with cache.
163
+ deterministic: bool, deterministic or not (to apply dropout).
164
+ max_decode_length: optional max length for positional embeddings.
165
+
166
+ Returns:
167
+ output of a transformer decoder [B, L, V].
168
+ """
169
+ y = targets.astype("int32")
170
+ if not decode:
171
+ if self.masked_pred_prob > 0.0 and not deterministic:
172
+ # Binary random variable indicating whether to do masked prediction
173
+
174
+ def _add_random_masks(a):
175
+ # Generate random mask
176
+ n_masked = int(self.masking_ratio * a.shape[1])
177
+ mask_locations = jnp.zeros(a.shape[:2], dtype=jnp.int32)
178
+ mask_locations = mask_locations.at[:, :n_masked].set(1)
179
+ mask_locations = jax.random.permutation(
180
+ self.make_rng("dropout"), mask_locations, axis=1, independent=True
181
+ )
182
+ # Replace mask locations with mask token index (=vocab_size)
183
+ a_masked = jnp.where(mask_locations, self.output_vocab_size, a)
184
+ return a_masked
185
+
186
+ def where(mask, x, y):
187
+ mask = mask.reshape((-1,) + (1,) * (x.ndim - 1))
188
+ return jnp.where(mask, x, y)
189
+
190
+ do_masked_pred = (
191
+ jax.random.uniform(self.make_rng("dropout"), (len(y),))
192
+ < self.masked_pred_prob
193
+ )
194
+ y = where(do_masked_pred, _add_random_masks(y), shift_right(y))
195
+ decoder_mask = where(
196
+ do_masked_pred, jnp.ones_like(decoder_mask), decoder_mask
197
+ )
198
+
199
+ else:
200
+ y = shift_right(y)
201
+
202
+ embed = nn.Embed(
203
+ self.output_vocab_size + (1 if self.masked_pred_prob > 0.0 else 0),
204
+ self.emb_dim,
205
+ name="EmbedTargets",
206
+ embedding_init=nn.initializers.normal(stddev=1.0),
207
+ )
208
+ y = embed(y)
209
+
210
+ y = common.AddPositionEmbs(
211
+ decode=decode, name="PosEmbedTargets")(y, pos_emb)
212
+ # NOTE: One could apply dropout on the decoder's inputs here. Whether to do
213
+ # it or not, and if so, what is the best/common way, is to be determined.
214
+ # y = nn.Dropout(rate=self.dropout_rate)(y, deterministic=deterministic)
215
+
216
+ if self.scan:
217
+ # Mostly followed
218
+ # https://github.com/google/maxtext/blob/4d99e30b3e0e0cb1d1aa11c7db7fffe18e301498/MaxText/layers.py#L1126
219
+ # for the scanned version.
220
+ # 1. remat
221
+ enc_dec_block_remat = nn.remat(
222
+ EncoderDecoderBlock,
223
+ prevent_cse=False,
224
+ static_argnums=(-1,),
225
+ policy=getattr(jax.checkpoint_policies, self.remat_policy, None))
226
+ # 2. scan
227
+ initializing = self.is_mutable_collection("params")
228
+ param_scan_axis = 1
229
+ params_spec = (param_scan_axis if initializing
230
+ else partitioning.ScanIn(param_scan_axis))
231
+ dec_scanned = nn.scan(enc_dec_block_remat,
232
+ variable_axes={
233
+ "params": params_spec,
234
+ "cache": 0,
235
+ },
236
+ split_rngs={"params": True, "dropout": True},
237
+ in_axes=nn.broadcast,
238
+ length=self.num_layers)
239
+ # 3. fprop
240
+ y, _ = dec_scanned(num_heads=self.num_heads, mlp_dim=self.mlp_dim,
241
+ dropout_rate=self.dropout_rate, decode=decode,
242
+ use_bias=self.use_bias, name="EncDecBlock")(
243
+ y, encoded, decoder_mask, deterministic)
244
+ else:
245
+ for lyr in range(self.num_layers):
246
+ y, _ = EncoderDecoderBlock(
247
+ num_heads=self.num_heads, mlp_dim=self.mlp_dim,
248
+ dropout_rate=self.dropout_rate, decode=decode,
249
+ use_bias=self.use_bias, name=f"EncDecBlock{lyr}")(
250
+ y, encoded, decoder_mask=decoder_mask,
251
+ deterministic=deterministic)
252
+
253
+ y = nn.LayerNorm(name="LayerNorm")(y)
254
+
255
+ logits = nn.Dense(
256
+ self.output_vocab_size,
257
+ kernel_init=nn.initializers.zeros,
258
+ name="LogitsDense",
259
+ )(y)
260
+ return logits
261
+
262
+
263
+ class Model(nn.Module):
264
+ """Transformer Model for sequence to sequence translation."""
265
+ # Encoder/decoder:
266
+ num_heads: int = 8
267
+ num_layers: int = 6
268
+ mlp_dim: int = 2048
269
+ emb_dim: int = 512
270
+ enc_dropout_rate: float = 0.
271
+ vocab_size: int = 32_000
272
+ seq_len: int = 256
273
+
274
+ # Encoder:
275
+ patches: Sequence[int] = (16, 16)
276
+ input_seq_len: int = 768
277
+ posemb_type: str = "learn"
278
+ patch_dropout: float = 0.
279
+
280
+ # Decoder:
281
+ decoder_num_heads: int = 0
282
+ decoder_num_layers: int = 0
283
+ decoder_mlp_dim: int = 0
284
+ decoder_emb_dim: int = 0
285
+ dec_dropout_rate: float = 0.
286
+ # Probability of masked prediction rather than autoregressive prediciton.
287
+ masked_pred_prob: float = 0.
288
+ # Masking ratio for masked prediction.
289
+ masking_ratio: float = 0.
290
+ # Whether to use bias in decoder MLP blocks and LN.
291
+ decoder_bias: bool = True
292
+
293
+ scan: bool = False
294
+ remat_policy: str = "nothing_saveable"
295
+
296
+ def setup(self):
297
+
298
+ self.encoder = vit.Model(
299
+ patch_size=self.patches,
300
+ width=self.emb_dim,
301
+ depth=self.num_layers,
302
+ mlp_dim=self.mlp_dim,
303
+ num_heads=self.num_heads,
304
+ dropout=self.enc_dropout_rate,
305
+ posemb=self.posemb_type,
306
+ scan=self.scan,
307
+ remat_policy=self.remat_policy,
308
+ )
309
+
310
+ self.pos_emb_for_decoder = vit.get_posemb(
311
+ self,
312
+ self.posemb_type,
313
+ (1, self.seq_len),
314
+ self.decoder_emb_dim or self.emb_dim,
315
+ "pos_embedding_decoder",
316
+ )
317
+ self.decoder = Decoder(
318
+ num_layers=self.decoder_num_layers or self.num_layers,
319
+ mlp_dim=self.decoder_mlp_dim or self.mlp_dim,
320
+ num_heads=self.decoder_num_heads or self.num_heads,
321
+ dropout_rate=self.dec_dropout_rate,
322
+ emb_dim=self.decoder_emb_dim or self.emb_dim,
323
+ output_vocab_size=self.vocab_size,
324
+ masked_pred_prob=self.masked_pred_prob,
325
+ masking_ratio=self.masking_ratio,
326
+ use_bias=self.decoder_bias,
327
+ scan=self.scan,
328
+ remat_policy=self.remat_policy,
329
+ )
330
+
331
+ def encode(self, image, train=False, return_enc_features=False):
332
+ """Encodes input image or embeddings."""
333
+
334
+ _, out = self.encoder(image, train=train)
335
+ encoded = out["encoded"]
336
+
337
+ # Return intermediate features if required
338
+ if return_enc_features:
339
+ return encoded, out
340
+
341
+ return encoded
342
+
343
+ def decode(self, encoded, targets, decode=False, train=False,
344
+ max_decode_length=None):
345
+ """Applies Transformer decoder-branch on encoded-input and target.
346
+
347
+ Args:
348
+ encoded: encoded image patches from encoder [B, P, E].
349
+ targets: target text tokens [B, L].
350
+ decode: whether to prepare and use an autoregressive cache.
351
+ train: whether it is training.
352
+ max_decode_length: optional max length for positional embeddings.
353
+
354
+ Returns:
355
+ logits array from transformer decoder [B, L, V].
356
+ """
357
+ decoder_mask = None if decode else nn.make_causal_mask(targets)
358
+ logits = self.decoder(
359
+ encoded,
360
+ targets,
361
+ pos_emb=self.pos_emb_for_decoder,
362
+ decoder_mask=decoder_mask,
363
+ decode=decode,
364
+ deterministic=not train,
365
+ max_decode_length=max_decode_length)
366
+ return logits
367
+
368
+ def __call__(self, image, text, *, decode=False,
369
+ train=False, return_enc_features=False):
370
+ """Applies Transformer model on the inputs.
371
+
372
+ Args:
373
+ image: batch of images [B, H, W, 3].
374
+ text: batch of tokenized texts [B, L].
375
+ decode: whether to prepare and use an autoregressive cache.
376
+ train: whether it is training.
377
+ return_enc_features: whether to return the encoder features.
378
+
379
+ Returns:
380
+ logits array from full transformer [B, L, V].
381
+ """
382
+ if return_enc_features:
383
+ encoded, out = self.encode(image, train=train, return_enc_features=True)
384
+ return encoded, out
385
+
386
+ encoded = self.encode(image, train=train)
387
+
388
+ decoded = self.decode(encoded, text, decode=decode, train=train)
389
+ return decoded
390
+
391
+
392
+ def load(init_params, init_files, model_params=None,
393
+ dont_load=("head/kernel", "head/bias", "cls")):
394
+ """Loads params from init checkpoint and merges into init_params."""
395
+
396
+ if isinstance(init_files, str):
397
+ # A shortcut for a single file checkpoint of a vtt model.
398
+ ckpt_params = utils.load_params(init_files)
399
+ ckpt_params = flax.training.checkpoints.convert_pre_linen(ckpt_params)
400
+ ckpt_params = common.merge_params(ckpt_params, init_params, dont_load)
401
+
402
+ # Detect attempts to load non-scan checkpoint into scan model if possible.
403
+ if (model_params.get("scan") and
404
+ "encoderblock" not in ckpt_params["encoder"]["Transformer"]):
405
+ raise NotImplementedError("Loading a non-scan checkpoint into a "
406
+ "scan model is not supported yet!")
407
+ if (not model_params.get("scan")
408
+ and "encoderblock" in ckpt_params["encoder"]["Transformer"]):
409
+ assert "decoder.*" in dont_load or "decoder/.*" in dont_load, (
410
+ "Converting scan decoder to a non-scan one is not supported yet!")
411
+ ckpt_params["encoder"] = utils.jit_cpu()(
412
+ vit.scan_to_pyloop)(ckpt_params["encoder"])
413
+
414
+ else:
415
+ assert set(init_files) == {"encoder"}, "Only encoder init supported"
416
+ enc_init = init_files["encoder"]
417
+ ckpt_params = flax.core.freeze(init_params).unfreeze()
418
+ vit_params = ckpt_params["encoder"]
419
+ encoder_params = vit.load(
420
+ vit_params, enc_init, model_cfg={},
421
+ dont_load=dont_load)
422
+ ckpt_params["encoder"] = encoder_params
423
+
424
+ ckpt_params["encoder"]["pos_embedding"] = vit.resample_posemb(
425
+ old=ckpt_params["encoder"]["pos_embedding"],
426
+ new=init_params["encoder"]["pos_embedding"])
427
+
428
+ return ckpt_params
Tipsomaly/model/big_vision/models/proj/clippo/one_tower.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Model definition to train a single ViT model with the contrastive trainer."""
16
+
17
+ import importlib
18
+ from typing import Optional, Any
19
+
20
+ from big_vision import utils
21
+ import flax.linen as nn
22
+ import jax.numpy as jnp
23
+
24
+ ConfigDict = Any
25
+
26
+
27
+ class Model(nn.Module):
28
+ """Single ViT to encode regular images and text images."""
29
+ image: Optional[ConfigDict] = None
30
+ image_model: str = "vit"
31
+ out_dim: int = 768
32
+ temperature_init: float = 10.0
33
+
34
+ @nn.compact
35
+ def __call__(self, image, text=None, **kw):
36
+ """Returns (B, C) image and (B, C) text representations, and some extras."""
37
+ ztxt, zimg = None, None
38
+ kw = kw or {}
39
+
40
+ image_model = importlib.import_module(
41
+ f"big_vision.models.{self.image_model}"
42
+ ).Model(**{"num_classes": self.out_dim, **(self.image or {})}, name="img") # pylint: disable=not-a-mapping
43
+
44
+ def _compute_embedding(input_image, prefix):
45
+ zemb, out_emb = image_model(input_image, **kw)
46
+ out = {f"{prefix}/{k}": v for k, v in out_emb.items()}
47
+
48
+ # Normalize the embeddings.
49
+ out[f"{prefix}/norm"] = jnp.linalg.norm(zemb, axis=1, keepdims=True)
50
+ out[f"{prefix}/normalized"] = zemb = zemb / (out[f"{prefix}/norm"] + 1e-8)
51
+ return zemb, out
52
+
53
+ out = {}
54
+ if image is not None:
55
+ zimg, out_img = _compute_embedding(image, "img")
56
+ out.update(out_img)
57
+
58
+ if text is not None:
59
+ ztxt, out_txt = _compute_embedding(text, "txt")
60
+ out.update(out_txt)
61
+
62
+ temp_init = jnp.log(self.temperature_init)
63
+ t = self.param("t",
64
+ lambda key, shape, dtype: temp_init*jnp.ones(shape, dtype),
65
+ (1,), jnp.float32)
66
+ out["t"] = jnp.exp(t)
67
+ out["t/parameter"] = t
68
+
69
+ return zimg, ztxt, out
70
+
71
+
72
+ def load(init_params, init_files, model_cfg, img_load_kw={}): # pylint: disable=dangerous-default-value
73
+ """Loads the ViT parameters - adapted from proj/image_text/two_towers.py."""
74
+ if isinstance(init_files, str):
75
+ # A shortcut for a single file checkpoint of a two_towers model.
76
+ init_files = {k: f"{init_files}:{k}" for k in ("img", "t")}
77
+ else:
78
+ init_files = {**init_files} # Shallow copy because we'll pop stuff off.
79
+
80
+ restored_params = {**init_params}
81
+
82
+ img_init = init_files.pop("image", init_files.pop("img", None))
83
+ if img_init:
84
+ restored_params["img"] = importlib.import_module(
85
+ f"big_vision.models.{model_cfg.image_model}"
86
+ ).load(init_params["img"], img_init, model_cfg.image, **img_load_kw)
87
+
88
+ t_init = init_files.pop("temperature", init_files.pop("t", None))
89
+ if t_init:
90
+ restored_params["t"] = utils.load_params(None, t_init)
91
+
92
+ assert not init_files, (
93
+ f"There's something unused left in `config.model_init`. You probably got "
94
+ f"a typo. Here it is: {init_files}")
95
+
96
+ return restored_params
Tipsomaly/model/big_vision/models/proj/flaxformer/bert.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """BERT encoder, optionally loading pre-trained checkpoints."""
16
+
17
+ import dataclasses
18
+ from typing import Optional
19
+
20
+ from absl import logging
21
+ from big_vision import utils
22
+ from big_vision.models import common
23
+ import flax
24
+ import flax.linen as nn
25
+ import jax.numpy as jnp
26
+ from tensorflow.io import gfile
27
+
28
+ from flaxformer.architectures.bert import bert
29
+ from flaxformer.architectures.bert import bert_checkpoint_converter
30
+ from flaxformer.architectures.bert import configs
31
+
32
+
33
+ class Model(nn.Module):
34
+ """BERT encoder with linear projection on last layer CLS token."""
35
+
36
+ config: str
37
+ num_classes: Optional[int] = None
38
+ head_zeroinit: bool = True
39
+
40
+ @nn.compact
41
+ def __call__(self, text, *, train=False):
42
+ out = {}
43
+
44
+ batch_size, max_len = text.shape
45
+ bert_model = bert.BertEncoder(**dataclasses.asdict({
46
+ "base": configs.BertBaseConfig(),
47
+ "large": configs.BertLargeConfig(),
48
+ }[self.config]))
49
+ x = out["transformed"] = bert_model(
50
+ token_ids=text,
51
+ position_ids=jnp.tile(
52
+ jnp.arange(0, max_len, dtype=jnp.int32), [batch_size, 1]),
53
+ segment_ids=jnp.zeros([batch_size, max_len], dtype=jnp.int32),
54
+ input_mask=text.astype(jnp.bool_).astype(jnp.int32),
55
+ enable_dropout=train,
56
+ )
57
+
58
+ x = out["pre_logits"] = x[:, 0] # CLS token
59
+
60
+ if self.num_classes:
61
+ kw = {"kernel_init": nn.initializers.zeros} if self.head_zeroinit else {}
62
+ x = out["logits"] = nn.Dense(self.num_classes, name="head", **kw)(x)
63
+
64
+ return x, out
65
+
66
+
67
+ def load(params, path, model_cfg=None, dont_load=()):
68
+ """Returns `params` with BERT weights replaced from checkpoint at `path`."""
69
+ del model_cfg
70
+
71
+ checkpoint_path = f"{path}/bert_model.ckpt"
72
+ if gfile.exists(f"{checkpoint_path}.index"):
73
+ logging.info("Loading original BERT checkpoint from '%s'", checkpoint_path)
74
+ params = flax.core.FrozenDict(params).unfreeze() # Recursive copy.
75
+ max_len = (
76
+ params["BertEncoder_0"]["embedder"]["embedders_position_ids"]
77
+ ["embedding"].shape[0])
78
+ bert_params, pooler_params = (
79
+ bert_checkpoint_converter.load_params_from_tf_checkpoint(
80
+ checkpoint_path=f"{path}/bert_model.ckpt"))
81
+ del pooler_params
82
+ if isinstance(bert_params, flax.core.FrozenDict):
83
+ bert_params = bert_params.unfreeze()
84
+ bert_params["embedder"]["embedders_position_ids"]["embedding"] = (
85
+ bert_params["embedder"]["embedders_position_ids"]["embedding"][:max_len]
86
+ )
87
+ return common.merge_params(
88
+ {"BertEncoder_0": bert_params}, params, dont_load)
89
+
90
+ logging.info(
91
+ "Could not find original BERT checkpoint path '%s', "
92
+ "loading big_vision checkpoint '%s'", checkpoint_path, path)
93
+ restored_params = utils.load_params(path)
94
+ return common.merge_params(restored_params, params, dont_load)
Tipsomaly/model/big_vision/models/proj/flaxformer/bert_test.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
+ """Tests for bert."""
16
+
17
+ import tempfile
18
+
19
+ from big_vision import input_pipeline
20
+ from big_vision.models.proj.flaxformer import bert
21
+ from big_vision.models.proj.flaxformer import bert_test_util
22
+ import big_vision.pp.builder as pp_builder
23
+ import big_vision.pp.ops_general # pylint: disable=unused-import
24
+ import big_vision.pp.proj.flaxformer.bert_ops # pylint: disable=unused-import
25
+ import flax
26
+ import jax
27
+ import jax.numpy as jnp
28
+ import tensorflow as tf
29
+
30
+
31
+ # BERT vocabulary for testing.
32
+ _BERT_VOCAB = [
33
+ "[PAD]",
34
+ "[UNK]",
35
+ "this",
36
+ "is",
37
+ "a",
38
+ "test",
39
+ "[CLS]",
40
+ "[SEP]",
41
+ ]
42
+ _TOKEN_LEN = 16
43
+
44
+
45
+ class BertTest(tf.test.TestCase):
46
+
47
+ def test_load_apply(self):
48
+ inkey = "text"
49
+ vocab_path = f"{tempfile.mkdtemp()}/vocab.txt"
50
+ with open(vocab_path, "w") as f:
51
+ f.write("\n".join(_BERT_VOCAB))
52
+ ds2, _ = input_pipeline.make_for_inference(
53
+ tf.data.Dataset.from_tensor_slices(
54
+ {inkey: tf.ragged.constant([["this is a test"]])}),
55
+ num_ex_per_process=[1],
56
+ preprocess_fn=pp_builder.get_preprocess_fn(
57
+ f"bert_tokenize(inkey='{inkey}', vocab_path='{vocab_path}', "
58
+ f"max_len={_TOKEN_LEN})"
59
+ "|keep('labels')"),
60
+ batch_size=1,
61
+ )
62
+ text = jnp.array(next(iter(ds2))["labels"])
63
+ model = bert.Model(config="base")
64
+ variables = model.init(jax.random.PRNGKey(0), text)
65
+ params = bert.load(flax.core.unfreeze(variables)["params"],
66
+ bert_test_util.create_base_checkpoint())
67
+ x, out = model.apply({"params": params}, text)
68
+ self.assertAllEqual(jax.tree_map(jnp.shape, x), (1, 768))
69
+ self.assertAllEqual(
70
+ jax.tree_map(jnp.shape, out), {
71
+ "transformed": (1, 16, 768),
72
+ "pre_logits": (1, 768),
73
+ })
74
+
75
+
76
+ if __name__ == "__main__":
77
+ tf.test.main()
Tipsomaly/model/big_vision/models/proj/flaxformer/bert_test_util.py ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Utilities for fake BERT checkpoint."""
16
+
17
+ import tempfile
18
+
19
+ import tensorflow.compat.v1 as tf
20
+
21
+ # Checkpoint structure was extracted with the following (Colab) snippet:
22
+ #
23
+ # !wget https://storage.googleapis.com/bert_models/2020_02_20/uncased_L-12_H-768_A-12.zip # pylint: disable=line-too-long
24
+ # !unzip uncased_L-12_H-768_A-12.zip
25
+ #
26
+ # import tensorflow.compat.v1 as tf
27
+ #
28
+ # ckpt_reader = tf.train.load_checkpoint('bert_model.ckpt')
29
+ # tf_params = {
30
+ # tf_name: ckpt_reader.get_tensor(tf_name)
31
+ # for tf_name in ckpt_reader.get_variable_to_dtype_map()
32
+ # }
33
+ #
34
+ # 'shapes_dtypes = {\n%s\n}' % '\n'.join(
35
+ # f' "{k}": ({v.shape}, "{v.dtype}"),'
36
+ # for k, v, in tf_params.items()
37
+ # )
38
+
39
+ # pylint: disable=line-too-long
40
+ _BASE_SHAPES_DTYPES = {
41
+ "cls/seq_relationship/output_bias": ((2,), "float32"),
42
+ "cls/predictions/transform/LayerNorm/gamma": ((768,), "float32"),
43
+ "cls/predictions/transform/LayerNorm/beta": ((768,), "float32"),
44
+ "bert/pooler/dense/kernel": ((768, 768), "float32"),
45
+ "bert/encoder/layer_5/attention/output/dense/bias": ((768,), "float32"),
46
+ "bert/encoder/layer_9/output/dense/bias": ((768,), "float32"),
47
+ "bert/encoder/layer_9/output/LayerNorm/gamma": ((768,), "float32"),
48
+ "bert/encoder/layer_3/attention/self/value/bias": ((768,), "float32"),
49
+ "bert/encoder/layer_7/output/dense/bias": ((768,), "float32"),
50
+ "bert/encoder/layer_9/output/LayerNorm/beta": ((768,), "float32"),
51
+ "bert/encoder/layer_7/attention/output/LayerNorm/beta": ((768,), "float32"),
52
+ "bert/encoder/layer_9/intermediate/dense/bias": ((3072,), "float32"),
53
+ "bert/encoder/layer_9/attention/self/query/kernel": ((768, 768), "float32"),
54
+ "bert/encoder/layer_9/attention/self/query/bias": ((768,), "float32"),
55
+ "bert/encoder/layer_9/attention/output/LayerNorm/gamma": ((768,), "float32"),
56
+ "bert/encoder/layer_9/attention/output/LayerNorm/beta": ((768,), "float32"),
57
+ "bert/encoder/layer_8/output/dense/bias": ((768,), "float32"),
58
+ "bert/encoder/layer_4/attention/self/value/kernel": ((768, 768), "float32"),
59
+ "bert/encoder/layer_8/output/LayerNorm/gamma": ((768,), "float32"),
60
+ "bert/encoder/layer_8/output/LayerNorm/beta": ((768,), "float32"),
61
+ "bert/encoder/layer_11/output/LayerNorm/beta": ((768,), "float32"),
62
+ "bert/encoder/layer_11/output/LayerNorm/gamma": ((768,), "float32"),
63
+ "bert/encoder/layer_8/intermediate/dense/kernel": ((768, 3072), "float32"),
64
+ "bert/encoder/layer_8/attention/self/value/kernel": ((768, 768), "float32"),
65
+ "bert/encoder/layer_2/output/dense/kernel": ((3072, 768), "float32"),
66
+ "bert/encoder/layer_8/attention/self/value/bias": ((768,), "float32"),
67
+ "bert/encoder/layer_1/attention/self/value/bias": ((768,), "float32"),
68
+ "bert/encoder/layer_8/attention/output/dense/kernel": ((768, 768), "float32"),
69
+ "bert/encoder/layer_3/attention/output/LayerNorm/beta": ((768,), "float32"),
70
+ "bert/encoder/layer_8/attention/self/query/bias": ((768,), "float32"),
71
+ "bert/encoder/layer_8/attention/output/LayerNorm/gamma": ((768,), "float32"),
72
+ "bert/encoder/layer_8/attention/output/LayerNorm/beta": ((768,), "float32"),
73
+ "bert/encoder/layer_7/output/LayerNorm/gamma": ((768,), "float32"),
74
+ "bert/encoder/layer_7/intermediate/dense/bias": ((3072,), "float32"),
75
+ "bert/encoder/layer_8/intermediate/dense/bias": ((3072,), "float32"),
76
+ "bert/encoder/layer_7/attention/self/value/kernel": ((768, 768), "float32"),
77
+ "bert/encoder/layer_7/attention/self/value/bias": ((768,), "float32"),
78
+ "bert/encoder/layer_9/attention/self/key/kernel": ((768, 768), "float32"),
79
+ "bert/encoder/layer_7/attention/self/query/kernel": ((768, 768), "float32"),
80
+ "bert/encoder/layer_7/attention/self/key/kernel": ((768, 768), "float32"),
81
+ "bert/encoder/layer_6/output/dense/kernel": ((3072, 768), "float32"),
82
+ "bert/encoder/layer_6/output/LayerNorm/gamma": ((768,), "float32"),
83
+ "bert/encoder/layer_6/intermediate/dense/kernel": ((768, 3072), "float32"),
84
+ "bert/encoder/layer_0/attention/self/query/bias": ((768,), "float32"),
85
+ "bert/encoder/layer_6/attention/output/dense/bias": ((768,), "float32"),
86
+ "bert/encoder/layer_7/output/LayerNorm/beta": ((768,), "float32"),
87
+ "bert/encoder/layer_4/attention/self/key/kernel": ((768, 768), "float32"),
88
+ "bert/encoder/layer_5/output/dense/bias": ((768,), "float32"),
89
+ "bert/encoder/layer_2/attention/self/value/kernel": ((768, 768), "float32"),
90
+ "bert/encoder/layer_5/output/LayerNorm/gamma": ((768,), "float32"),
91
+ "bert/encoder/layer_5/output/LayerNorm/beta": ((768,), "float32"),
92
+ "bert/encoder/layer_5/intermediate/dense/kernel": ((768, 3072), "float32"),
93
+ "bert/encoder/layer_9/attention/self/value/kernel": ((768, 768), "float32"),
94
+ "bert/encoder/layer_3/attention/self/query/kernel": ((768, 768), "float32"),
95
+ "bert/encoder/layer_8/attention/self/key/kernel": ((768, 768), "float32"),
96
+ "bert/encoder/layer_5/intermediate/dense/bias": ((3072,), "float32"),
97
+ "bert/encoder/layer_5/attention/self/query/kernel": ((768, 768), "float32"),
98
+ "bert/encoder/layer_5/attention/self/key/bias": ((768,), "float32"),
99
+ "bert/encoder/layer_5/attention/output/dense/kernel": ((768, 768), "float32"),
100
+ "bert/encoder/layer_5/attention/self/value/kernel": ((768, 768), "float32"),
101
+ "bert/encoder/layer_5/attention/output/LayerNorm/gamma": ((768,), "float32"),
102
+ "bert/encoder/layer_5/attention/output/LayerNorm/beta": ((768,), "float32"),
103
+ "bert/encoder/layer_4/output/dense/bias": ((768,), "float32"),
104
+ "bert/embeddings/token_type_embeddings": ((2, 768), "float32"),
105
+ "bert/encoder/layer_4/output/LayerNorm/gamma": ((768,), "float32"),
106
+ "bert/encoder/layer_4/output/LayerNorm/beta": ((768,), "float32"),
107
+ "bert/encoder/layer_7/output/dense/kernel": ((3072, 768), "float32"),
108
+ "bert/encoder/layer_4/intermediate/dense/kernel": ((768, 3072), "float32"),
109
+ "bert/encoder/layer_9/attention/self/key/bias": ((768,), "float32"),
110
+ "bert/encoder/layer_10/attention/self/key/bias": ((768,), "float32"),
111
+ "bert/encoder/layer_6/attention/self/value/kernel": ((768, 768), "float32"),
112
+ "bert/encoder/layer_4/attention/self/query/bias": ((768,), "float32"),
113
+ "cls/seq_relationship/output_weights": ((2, 768), "float32"),
114
+ "bert/encoder/layer_7/intermediate/dense/kernel": ((768, 3072), "float32"),
115
+ "bert/encoder/layer_4/attention/output/dense/kernel": ((768, 768), "float32"),
116
+ "bert/encoder/layer_4/attention/output/dense/bias": ((768,), "float32"),
117
+ "bert/encoder/layer_4/attention/output/LayerNorm/gamma": ((768,), "float32"),
118
+ "bert/encoder/layer_3/output/dense/kernel": ((3072, 768), "float32"),
119
+ "bert/encoder/layer_1/output/LayerNorm/beta": ((768,), "float32"),
120
+ "bert/encoder/layer_2/attention/self/value/bias": ((768,), "float32"),
121
+ "bert/encoder/layer_8/attention/self/query/kernel": ((768, 768), "float32"),
122
+ "bert/encoder/layer_4/output/dense/kernel": ((3072, 768), "float32"),
123
+ "bert/encoder/layer_3/output/dense/bias": ((768,), "float32"),
124
+ "bert/encoder/layer_4/attention/self/value/bias": ((768,), "float32"),
125
+ "bert/encoder/layer_3/intermediate/dense/bias": ((3072,), "float32"),
126
+ "bert/encoder/layer_1/intermediate/dense/bias": ((3072,), "float32"),
127
+ "bert/encoder/layer_3/attention/self/value/kernel": ((768, 768), "float32"),
128
+ "bert/encoder/layer_10/attention/self/value/bias": ((768,), "float32"),
129
+ "bert/encoder/layer_3/attention/self/query/bias": ((768,), "float32"),
130
+ "bert/encoder/layer_1/attention/self/key/kernel": ((768, 768), "float32"),
131
+ "bert/encoder/layer_0/attention/self/query/kernel": ((768, 768), "float32"),
132
+ "bert/encoder/layer_10/output/dense/bias": ((768,), "float32"),
133
+ "bert/encoder/layer_3/attention/self/key/kernel": ((768, 768), "float32"),
134
+ "bert/encoder/layer_3/attention/output/dense/kernel": ((768, 768), "float32"),
135
+ "bert/encoder/layer_1/output/LayerNorm/gamma": ((768,), "float32"),
136
+ "bert/encoder/layer_3/attention/output/dense/bias": ((768,), "float32"),
137
+ "bert/encoder/layer_1/attention/output/dense/bias": ((768,), "float32"),
138
+ "bert/encoder/layer_3/attention/output/LayerNorm/gamma": ((768,), "float32"),
139
+ "bert/encoder/layer_2/output/dense/bias": ((768,), "float32"),
140
+ "bert/encoder/layer_6/attention/self/key/bias": ((768,), "float32"),
141
+ "bert/encoder/layer_11/attention/output/dense/kernel": ((768, 768), "float32"),
142
+ "bert/encoder/layer_2/intermediate/dense/kernel": ((768, 3072), "float32"),
143
+ "bert/encoder/layer_2/attention/self/key/kernel": ((768, 768), "float32"),
144
+ "bert/encoder/layer_2/attention/output/dense/bias": ((768,), "float32"),
145
+ "bert/encoder/layer_2/attention/self/key/bias": ((768,), "float32"),
146
+ "bert/encoder/layer_6/attention/self/query/bias": ((768,), "float32"),
147
+ "bert/encoder/layer_11/intermediate/dense/kernel": ((768, 3072), "float32"),
148
+ "bert/encoder/layer_6/output/LayerNorm/beta": ((768,), "float32"),
149
+ "bert/encoder/layer_11/intermediate/dense/bias": ((3072,), "float32"),
150
+ "bert/encoder/layer_11/attention/self/query/bias": ((768,), "float32"),
151
+ "bert/encoder/layer_11/attention/self/value/kernel": ((768, 768), "float32"),
152
+ "bert/encoder/layer_10/output/LayerNorm/gamma": ((768,), "float32"),
153
+ "bert/encoder/layer_11/attention/self/key/kernel": ((768, 768), "float32"),
154
+ "bert/encoder/layer_6/attention/self/key/kernel": ((768, 768), "float32"),
155
+ "bert/encoder/layer_6/attention/output/LayerNorm/beta": ((768,), "float32"),
156
+ "bert/encoder/layer_11/attention/self/key/bias": ((768,), "float32"),
157
+ "bert/encoder/layer_10/attention/self/value/kernel": ((768, 768), "float32"),
158
+ "bert/encoder/layer_4/intermediate/dense/bias": ((3072,), "float32"),
159
+ "bert/encoder/layer_11/attention/output/dense/bias": ((768,), "float32"),
160
+ "bert/encoder/layer_10/attention/self/query/bias": ((768,), "float32"),
161
+ "bert/embeddings/LayerNorm/gamma": ((768,), "float32"),
162
+ "bert/encoder/layer_2/attention/output/LayerNorm/gamma": ((768,), "float32"),
163
+ "bert/encoder/layer_11/output/dense/kernel": ((3072, 768), "float32"),
164
+ "bert/encoder/layer_11/attention/output/LayerNorm/beta": ((768,), "float32"),
165
+ "bert/encoder/layer_5/output/dense/kernel": ((3072, 768), "float32"),
166
+ "bert/encoder/layer_3/attention/self/key/bias": ((768,), "float32"),
167
+ "bert/encoder/layer_10/output/LayerNorm/beta": ((768,), "float32"),
168
+ "bert/encoder/layer_10/intermediate/dense/kernel": ((768, 3072), "float32"),
169
+ "bert/embeddings/word_embeddings": ((30522, 768), "float32"),
170
+ "bert/encoder/layer_9/output/dense/kernel": ((3072, 768), "float32"),
171
+ "bert/encoder/layer_9/attention/self/value/bias": ((768,), "float32"),
172
+ "bert/encoder/layer_6/attention/output/LayerNorm/gamma": ((768,), "float32"),
173
+ "bert/encoder/layer_10/intermediate/dense/bias": ((3072,), "float32"),
174
+ "bert/encoder/layer_6/attention/self/value/bias": ((768,), "float32"),
175
+ "bert/encoder/layer_1/attention/output/LayerNorm/gamma": ((768,), "float32"),
176
+ "bert/encoder/layer_5/attention/self/value/bias": ((768,), "float32"),
177
+ "bert/encoder/layer_2/output/LayerNorm/beta": ((768,), "float32"),
178
+ "bert/encoder/layer_0/output/dense/bias": ((768,), "float32"),
179
+ "bert/encoder/layer_3/intermediate/dense/kernel": ((768, 3072), "float32"),
180
+ "cls/predictions/output_bias": ((30522,), "float32"),
181
+ "bert/encoder/layer_0/attention/self/value/bias": ((768,), "float32"),
182
+ "bert/encoder/layer_6/output/dense/bias": ((768,), "float32"),
183
+ "bert/encoder/layer_0/attention/output/dense/kernel": ((768, 768), "float32"),
184
+ "bert/encoder/layer_2/attention/output/LayerNorm/beta": ((768,), "float32"),
185
+ "bert/encoder/layer_10/attention/output/LayerNorm/beta": ((768,), "float32"),
186
+ "bert/encoder/layer_5/attention/self/query/bias": ((768,), "float32"),
187
+ "bert/encoder/layer_4/attention/self/query/kernel": ((768, 768), "float32"),
188
+ "bert/encoder/layer_0/attention/self/key/kernel": ((768, 768), "float32"),
189
+ "bert/encoder/layer_0/output/dense/kernel": ((3072, 768), "float32"),
190
+ "bert/encoder/layer_10/attention/output/LayerNorm/gamma": ((768,), "float32"),
191
+ "bert/encoder/layer_7/attention/output/dense/bias": ((768,), "float32"),
192
+ "bert/encoder/layer_3/output/LayerNorm/gamma": ((768,), "float32"),
193
+ "bert/encoder/layer_2/attention/self/query/bias": ((768,), "float32"),
194
+ "bert/encoder/layer_8/output/dense/kernel": ((3072, 768), "float32"),
195
+ "bert/embeddings/LayerNorm/beta": ((768,), "float32"),
196
+ "bert/encoder/layer_1/attention/self/value/kernel": ((768, 768), "float32"),
197
+ "bert/encoder/layer_10/attention/output/dense/kernel": ((768, 768), "float32"),
198
+ "bert/encoder/layer_2/intermediate/dense/bias": ((3072,), "float32"),
199
+ "bert/encoder/layer_6/intermediate/dense/bias": ((3072,), "float32"),
200
+ "bert/encoder/layer_2/attention/output/dense/kernel": ((768, 768), "float32"),
201
+ "bert/encoder/layer_11/attention/self/value/bias": ((768,), "float32"),
202
+ "bert/encoder/layer_9/attention/output/dense/bias": ((768,), "float32"),
203
+ "bert/encoder/layer_0/attention/output/LayerNorm/gamma": ((768,), "float32"),
204
+ "bert/encoder/layer_10/attention/output/dense/bias": ((768,), "float32"),
205
+ "bert/encoder/layer_10/output/dense/kernel": ((3072, 768), "float32"),
206
+ "bert/encoder/layer_1/attention/output/dense/kernel": ((768, 768), "float32"),
207
+ "bert/encoder/layer_8/attention/self/key/bias": ((768,), "float32"),
208
+ "bert/encoder/layer_0/intermediate/dense/bias": ((3072,), "float32"),
209
+ "bert/encoder/layer_1/intermediate/dense/kernel": ((768, 3072), "float32"),
210
+ "bert/encoder/layer_1/attention/self/key/bias": ((768,), "float32"),
211
+ "bert/encoder/layer_7/attention/output/dense/kernel": ((768, 768), "float32"),
212
+ "bert/encoder/layer_2/attention/self/query/kernel": ((768, 768), "float32"),
213
+ "bert/encoder/layer_8/attention/output/dense/bias": ((768,), "float32"),
214
+ "cls/predictions/transform/dense/kernel": ((768, 768), "float32"),
215
+ "bert/encoder/layer_6/attention/self/query/kernel": ((768, 768), "float32"),
216
+ "bert/encoder/layer_5/attention/self/key/kernel": ((768, 768), "float32"),
217
+ "bert/encoder/layer_0/attention/self/value/kernel": ((768, 768), "float32"),
218
+ "bert/encoder/layer_7/attention/self/query/bias": ((768,), "float32"),
219
+ "bert/encoder/layer_7/attention/self/key/bias": ((768,), "float32"),
220
+ "bert/encoder/layer_1/output/dense/kernel": ((3072, 768), "float32"),
221
+ "bert/encoder/layer_11/attention/output/LayerNorm/gamma": ((768,), "float32"),
222
+ "bert/encoder/layer_4/attention/output/LayerNorm/beta": ((768,), "float32"),
223
+ "bert/encoder/layer_1/attention/output/LayerNorm/beta": ((768,), "float32"),
224
+ "bert/encoder/layer_9/attention/output/dense/kernel": ((768, 768), "float32"),
225
+ "bert/encoder/layer_2/output/LayerNorm/gamma": ((768,), "float32"),
226
+ "bert/encoder/layer_0/output/LayerNorm/gamma": ((768,), "float32"),
227
+ "bert/encoder/layer_10/attention/self/query/kernel": ((768, 768), "float32"),
228
+ "bert/encoder/layer_1/attention/self/query/bias": ((768,), "float32"),
229
+ "bert/encoder/layer_3/output/LayerNorm/beta": ((768,), "float32"),
230
+ "bert/encoder/layer_6/attention/output/dense/kernel": ((768, 768), "float32"),
231
+ "bert/encoder/layer_1/attention/self/query/kernel": ((768, 768), "float32"),
232
+ "bert/encoder/layer_11/output/dense/bias": ((768,), "float32"),
233
+ "cls/predictions/transform/dense/bias": ((768,), "float32"),
234
+ "bert/encoder/layer_0/intermediate/dense/kernel": ((768, 3072), "float32"),
235
+ "bert/encoder/layer_11/attention/self/query/kernel": ((768, 768), "float32"),
236
+ "bert/encoder/layer_0/attention/self/key/bias": ((768,), "float32"),
237
+ "bert/encoder/layer_0/attention/output/dense/bias": ((768,), "float32"),
238
+ "bert/encoder/layer_7/attention/output/LayerNorm/gamma": ((768,), "float32"),
239
+ "bert/encoder/layer_4/attention/self/key/bias": ((768,), "float32"),
240
+ "bert/encoder/layer_10/attention/self/key/kernel": ((768, 768), "float32"),
241
+ "bert/embeddings/position_embeddings": ((512, 768), "float32"),
242
+ "bert/encoder/layer_1/output/dense/bias": ((768,), "float32"),
243
+ "bert/encoder/layer_9/intermediate/dense/kernel": ((768, 3072), "float32"),
244
+ "bert/encoder/layer_0/output/LayerNorm/beta": ((768,), "float32"),
245
+ "bert/pooler/dense/bias": ((768,), "float32"),
246
+ "bert/encoder/layer_0/attention/output/LayerNorm/beta": ((768,), "float32"),
247
+ }
248
+ # pylint: enable=line-too-long
249
+
250
+
251
+ def create_base_checkpoint():
252
+ """Returns path to fake Bert "base" checkpoint directory (zero init)."""
253
+ directory = tempfile.mkdtemp()
254
+ path = f"{directory}/bert_model.ckpt"
255
+ with tf.Session() as sess:
256
+ for name, (shape, dtype) in _BASE_SHAPES_DTYPES.items():
257
+ tf.Variable(tf.zeros(shape, dtype), name=name)
258
+ saver = tf.train.Saver()
259
+ sess.run(tf.global_variables_initializer())
260
+ saver.save(sess, path)
261
+ return directory
Tipsomaly/model/big_vision/models/proj/flexi/vit.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """A version of ViT with flexible seqlen ((internal link))."""
16
+
17
+ from typing import Optional, Sequence
18
+
19
+ from absl import logging
20
+ from big_vision import utils
21
+ from big_vision.models import common
22
+ from big_vision.models import vit
23
+ import flax.linen as nn
24
+ import jax
25
+ import jax.numpy as jnp
26
+ import numpy as np
27
+ import tensorflow as tf
28
+
29
+
30
+ def resample_patchemb(old, new_hw):
31
+ """Resample the weights of the patch embedding kernel to target resolution.
32
+
33
+ We resample the patch embedding kernel by approximately inverting the effect
34
+ of patch resizing. Colab with detailed explanation:
35
+ (internal link)
36
+ With this resizing, we can for example load a B/8 filter into a B/16 model
37
+ and, on 2x larger input image, the result will match.
38
+ See (internal link)
39
+ Args:
40
+ old: original parameter to be resized.
41
+ new_hw: target shape (height, width)-only.
42
+ Returns:
43
+ Resized patch embedding kernel.
44
+ """
45
+ assert len(old.shape) == 4, "Four dimensions expected"
46
+ assert len(new_hw) == 2, "New shape should only be hw"
47
+ if tuple(old.shape[:2]) == tuple(new_hw):
48
+ return old
49
+
50
+ logging.info("FlexiViT: resize embedding %s to %s", old.shape, new_hw)
51
+
52
+ def resize(x_np, new_shape):
53
+ x_tf = tf.constant(x_np)[None, ..., None]
54
+ # NOTE: we are using tf.image.resize here to match the resize operations in
55
+ # the data preprocessing pipeline.
56
+ x_upsampled = tf.image.resize(
57
+ x_tf, new_shape, method="bilinear")[0, ..., 0].numpy()
58
+ return x_upsampled
59
+
60
+ def get_resize_mat(old_shape, new_shape):
61
+ mat = []
62
+ for i in range(np.prod(old_shape)):
63
+ basis_vec = np.zeros(old_shape)
64
+ basis_vec[np.unravel_index(i, old_shape)] = 1.
65
+ mat.append(resize(basis_vec, new_shape).reshape(-1))
66
+ return np.stack(mat).T
67
+
68
+ resize_mat = get_resize_mat(old.shape[:2], new_hw)
69
+ resize_mat_pinv = np.linalg.pinv(resize_mat.T)
70
+
71
+ def resample_kernel(kernel):
72
+ resampled_kernel = resize_mat_pinv @ kernel.reshape(-1)
73
+ return resampled_kernel.reshape(new_hw)
74
+ v_resample_kernel = jax.vmap(jax.vmap(resample_kernel, 2, 2), 3, 3)
75
+ return v_resample_kernel(old)
76
+
77
+
78
+ class Patchify(nn.Module):
79
+ """As a class just to match param names with original ViT."""
80
+
81
+ patch_size: Sequence[int] = (32, 32)
82
+ width: int = 768
83
+ seqhw: Optional[int] = None
84
+
85
+ @nn.compact
86
+ def __call__(self, image, seqhw=None):
87
+ n, h, w, c = image.shape # pylint: disable=unused-variable
88
+
89
+ w_emb = self.param(
90
+ "kernel", nn.initializers.normal(stddev=1/np.sqrt(self.width)),
91
+ (*self.patch_size, c, self.width), image.dtype)
92
+ b_emb = self.param("bias", nn.initializers.zeros, self.width, image.dtype)
93
+
94
+ # Compute required patch-size to reach `seqhw` given `image` size.
95
+ seqhw = seqhw or self.seqhw
96
+ if seqhw is None and self.is_initializing():
97
+ patch_size = self.patch_size
98
+ else:
99
+ patch_size = tuple(np.array((h, w)) // np.array((seqhw, seqhw)))
100
+
101
+ if patch_size != self.patch_size:
102
+ w_emb = resample_patchemb(old=w_emb, new_hw=patch_size)
103
+
104
+ x = jax.lax.conv_general_dilated(
105
+ image, w_emb, window_strides=patch_size, padding="VALID",
106
+ dimension_numbers=("NHWC", "HWIO", "NHWC"))
107
+ return x + b_emb
108
+
109
+
110
+ class _Model(nn.Module):
111
+ """ViT model."""
112
+
113
+ num_classes: int
114
+ patch_size: Sequence[int] = (32, 32)
115
+ posemb_size: Sequence[int] = (7, 7)
116
+ width: int = 768
117
+ depth: int = 12
118
+ mlp_dim: Optional[int] = None # Defaults to 4x input dim
119
+ num_heads: int = 12
120
+ posemb: str = "learn" # Can also be "sincos2d"
121
+ pool_type: str = "gap" # Can also be "map" or "tok"
122
+ head_zeroinit: bool = True
123
+
124
+ seqhw: Optional[int] = None
125
+
126
+ @nn.compact
127
+ def __call__(self, image, *, seqhw=None, train=False):
128
+ out = {}
129
+
130
+ x = out["stem"] = Patchify(
131
+ self.patch_size, self.width, self.seqhw, name="embedding")(image, seqhw)
132
+
133
+ # == Flattening + posemb
134
+ n, h, w, c = x.shape
135
+ x = jnp.reshape(x, [n, h * w, c])
136
+
137
+ pos_emb = vit.get_posemb(
138
+ self, self.posemb, self.posemb_size, c, "pos_embedding", x.dtype)
139
+ if pos_emb.shape[1] != h * w:
140
+ pos_emb = jnp.reshape(pos_emb, (1, *self.posemb_size, c))
141
+ pos_emb = jax.image.resize(pos_emb, (1, h, w, c), "linear")
142
+ pos_emb = jnp.reshape(pos_emb, (1, h * w, c))
143
+
144
+ x = out["with_posemb"] = x + pos_emb
145
+
146
+ # == Optional [cls] token
147
+ if self.pool_type == "tok":
148
+ cls = self.param("cls", nn.initializers.zeros, (1, 1, c), x.dtype)
149
+ x = jnp.concatenate([jnp.tile(cls, [n, 1, 1]), x], axis=1)
150
+
151
+ # == Encoder
152
+ n, l, c = x.shape # pylint: disable=unused-variable
153
+
154
+ x, out["encoder"] = vit.Encoder(
155
+ depth=self.depth,
156
+ mlp_dim=self.mlp_dim,
157
+ num_heads=self.num_heads,
158
+ name="Transformer")(x)
159
+ encoded = out["encoded"] = x
160
+
161
+ if self.pool_type == "map":
162
+ x = out["head_input"] = vit.MAPHead(
163
+ num_heads=self.num_heads, mlp_dim=self.mlp_dim)(x)
164
+ elif self.pool_type == "gap":
165
+ x = out["head_input"] = jnp.mean(x, axis=1)
166
+ elif self.pool_type == "tok":
167
+ x = out["head_input"] = x[:, 0]
168
+ encoded = encoded[:, 1:]
169
+ else:
170
+ raise ValueError(f"Unknown pool type: '{self.pool_type}'")
171
+
172
+ x_2d = jnp.reshape(encoded, [n, h, w, -1])
173
+
174
+ out["pre_logits_2d"] = x_2d
175
+ out["pre_logits"] = x
176
+
177
+ if self.num_classes:
178
+ kw = {"kernel_init": nn.initializers.zeros} if self.head_zeroinit else {}
179
+ head = nn.Dense(self.num_classes, name="head", **kw)
180
+ x_2d = out["logits_2d"] = head(x_2d)
181
+ x = out["logits"] = head(x)
182
+
183
+ return x, out
184
+
185
+
186
+ def Model(num_classes, *, variant=None, **kw): # pylint: disable=invalid-name
187
+ """Factory function, because linen really don't like what I'm doing!"""
188
+ return _Model(num_classes, **{**vit.decode_variant(variant), **kw})
189
+
190
+
191
+ def load(init_params, init_file, model_cfg, dont_load=()): # pylint: disable=invalid-name because we had to CamelCase above.
192
+ """Load init from checkpoint, both old model and this one. +Hi-res posemb."""
193
+ init_file = {**vit.VANITY_NAMES, **VANITY_NAMES}.get(init_file, init_file)
194
+ restored_params = utils.load_params(init_file)
195
+
196
+ restored_params = vit.fix_old_checkpoints(restored_params)
197
+
198
+ # Potentially resize the position embedings if seqlen differs.
199
+ restored_params["pos_embedding"] = vit.resample_posemb(
200
+ old=restored_params["pos_embedding"],
201
+ new=init_params["pos_embedding"])
202
+
203
+ # Potentially resize the patch embedding kernel.
204
+ old_patchemb = restored_params["embedding"]["kernel"]
205
+ restored_params["embedding"]["kernel"] = resample_patchemb(
206
+ old=old_patchemb, new_hw=model_cfg.patch_size)
207
+
208
+ # possibly use the random init for some of the params (such as, the head).
209
+ restored_params = common.merge_params(restored_params, init_params, dont_load)
210
+
211
+ return restored_params
212
+
213
+
214
+ # Shortcut names for some canonical paper checkpoints:
215
+ VANITY_NAMES = {
216
+ # pylint: disable=line-too-long
217
+ "FlexiViT-L i1k": "gs://big_vision/flexivit/flexivit_l_i1k.npz",
218
+ "FlexiViT-B i1k": "gs://big_vision/flexivit/flexivit_b_i1k.npz",
219
+ "FlexiViT-S i1k": "gs://big_vision/flexivit/flexivit_s_i1k.npz",
220
+ "FlexiViT-B i21k 90ep": "gs://big_vision/flexivit/flexivit_b_i21k_90ep.npz",
221
+ "FlexiViT-B i21k 300ep": "gs://big_vision/flexivit/flexivit_b_i21k_300ep.npz",
222
+ "FlexiViT-B i21k 1000ep": "gs://big_vision/flexivit/flexivit_b_i21k_1000ep.npz",
223
+ "ViT-B/16 i21k": "gs://big_vision/flexivit/vit_b16_i21k_300ep.npz",
224
+ "ViT-B/30 i21k": "gs://big_vision/flexivit/vit_b30_i21k_300ep.npz",
225
+ # pylint: enable=line-too-long
226
+ }
Tipsomaly/model/big_vision/models/proj/flexi/vit_test.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Tests for the FlexiViT model."""
16
+
17
+ from absl.testing import absltest
18
+ from big_vision.models.proj.flexi import vit
19
+ import jax
20
+ from jax import config
21
+ from jax import numpy as jnp
22
+ import numpy as np
23
+ import tensorflow as tf
24
+
25
+ config.update("jax_enable_x64", True)
26
+
27
+
28
+ class PatchEmbTest(absltest.TestCase):
29
+
30
+ def _test_patch_emb_resize(self, old_shape, new_shape, n_patches=100):
31
+ # This test verifies that if we resize the input image patch and resample
32
+ # the patch embedding accordingly, the output does not change.
33
+ # NOTE: if the image contains more than one patch, then the embeddings will
34
+ # change due to patch interaction during the resizing.
35
+ patch_shape = old_shape[:-2]
36
+ resized_patch_shape = new_shape[:-2]
37
+ patches = np.random.randn(n_patches, *old_shape[:-1])
38
+ w_emb = jnp.asarray(np.random.randn(*old_shape))
39
+
40
+ old_embeddings = jax.lax.conv_general_dilated(
41
+ patches, w_emb, window_strides=patch_shape, padding="VALID",
42
+ dimension_numbers=("NHWC", "HWIO", "NHWC"), precision="highest")
43
+
44
+ patch_resized = tf.image.resize(
45
+ tf.constant(patches), resized_patch_shape, method="bilinear").numpy()
46
+ patch_resized = jnp.asarray(patch_resized).astype(jnp.float64)
47
+ w_emb_resampled = vit.resample_patchemb(w_emb, resized_patch_shape)
48
+ self.assertEqual(w_emb_resampled.shape, new_shape)
49
+
50
+ new_embeddings = jax.lax.conv_general_dilated(
51
+ patch_resized, w_emb_resampled, window_strides=resized_patch_shape,
52
+ padding="VALID", dimension_numbers=("NHWC", "HWIO", "NHWC"),
53
+ precision="highest")
54
+
55
+ self.assertEqual(old_embeddings.shape, new_embeddings.shape)
56
+ np.testing.assert_allclose(
57
+ old_embeddings, new_embeddings, rtol=1e-1, atol=1e-4)
58
+
59
+ def test_resize_square(self):
60
+ out_channels = 256
61
+ patch_sizes = [48, 40, 30, 24, 20, 16, 15, 12, 10, 8, 6, 5]
62
+ for s in patch_sizes:
63
+ old_shape = (s, s, 3, out_channels)
64
+ for t in patch_sizes:
65
+ new_shape = (t, t, 3, out_channels)
66
+ if s <= t:
67
+ self._test_patch_emb_resize(old_shape, new_shape)
68
+
69
+ def test_resize_rectangular(self):
70
+ out_channels = 256
71
+ old_shape = (8, 10, 3, out_channels)
72
+ new_shape = (10, 12, 3, out_channels)
73
+ self._test_patch_emb_resize(old_shape, new_shape)
74
+
75
+ old_shape = (8, 6, 3, out_channels)
76
+ new_shape = (9, 15, 3, out_channels)
77
+ self._test_patch_emb_resize(old_shape, new_shape)
78
+
79
+ old_shape = (8, 6, 3, out_channels)
80
+ new_shape = (15, 9, 3, out_channels)
81
+ self._test_patch_emb_resize(old_shape, new_shape)
82
+
83
+ def test_input_channels(self):
84
+ out_channels = 256
85
+ for c in [1, 3, 10]:
86
+ old_shape = (8, 10, c, out_channels)
87
+ new_shape = (10, 12, c, out_channels)
88
+ self._test_patch_emb_resize(old_shape, new_shape)
89
+
90
+ def _test_works(self, old_shape, new_shape):
91
+ old = jnp.asarray(np.random.randn(*old_shape))
92
+ resampled = vit.resample_patchemb(old, new_shape[:2])
93
+ self.assertEqual(resampled.shape, new_shape)
94
+ self.assertEqual(resampled.dtype, old.dtype)
95
+
96
+ def test_downsampling(self):
97
+ # NOTE: for downsampling we cannot guarantee that the outputs would match
98
+ # before and after downsampling. So, we simply test that the code runs and
99
+ # produces an output of the correct shape and type.
100
+ out_channels = 256
101
+ for t in [4, 5, 6, 7]:
102
+ for c in [1, 3, 5]:
103
+ old_shape = (8, 8, c, out_channels)
104
+ new_shape = (t, t, c, out_channels)
105
+ self._test_works(old_shape, new_shape)
106
+
107
+ def _test_raises(self, old_shape, new_shape):
108
+ old = jnp.asarray(np.random.randn(*old_shape))
109
+ with self.assertRaises(AssertionError):
110
+ vit.resample_patchemb(old, new_shape)
111
+
112
+ def test_raises_incorrect_dims(self):
113
+ old_shape = (8, 10, 3, 256)
114
+ new_shape = (10, 12, 1, 256)
115
+ self._test_raises(old_shape, new_shape)
116
+
117
+ old_shape = (8, 10, 1, 256)
118
+ new_shape = (10, 12, 3, 256)
119
+ self._test_raises(old_shape, new_shape)
120
+
121
+ old_shape = (8, 10, 3, 128)
122
+ new_shape = (10, 12, 3, 256)
123
+ self._test_raises(old_shape, new_shape)
124
+
125
+
126
+ if __name__ == "__main__":
127
+ absltest.main()
Tipsomaly/model/big_vision/models/proj/givt/adaptor.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Invertible adaptor based on iRevNet.
16
+
17
+ Based on the PyTorch version from:
18
+ https://github.com/jhjacobsen/pytorch-i-revnet/blob/master/models/iRevNet.py
19
+ """
20
+
21
+ from typing import Any, Optional, Sequence
22
+
23
+ from big_vision import utils
24
+ from big_vision.models import common
25
+ from big_vision.models.proj.givt import cnn
26
+ import einops
27
+ import flax.core
28
+ import flax.linen as nn
29
+ import jax
30
+ import jax.numpy as jnp
31
+
32
+
33
+ def _split(x: jax.Array) -> tuple[jax.Array, jax.Array]:
34
+ n = x.shape[-1] // 2
35
+ x1 = x[:, :, :, :n]
36
+ x2 = x[:, :, :, n:]
37
+ return x1, x2
38
+
39
+
40
+ def _merge(x1: jax.Array, x2: jax.Array) -> jax.Array:
41
+ return jnp.concatenate((x1, x2), axis=-1)
42
+
43
+
44
+ class IRevNetBlock(nn.Module):
45
+ """iRevNet Block."""
46
+ first: int = False
47
+ dropout_rate: float = 0.
48
+ num_channels: int = 2
49
+ num_channels_bottleneck: Optional[int] = None
50
+ num_grps_norm: int = 32
51
+
52
+ @nn.compact
53
+ def _fx2(self, x: jax.Array, train: bool = True) -> jax.Array:
54
+ if not self.first:
55
+ y = nn.GroupNorm(num_groups=self.num_grps_norm, name="gn_0")(x)
56
+ y = nn.relu(y)
57
+ else:
58
+ y = x
59
+
60
+ ks = (3, 3) # hardcode kernel-size 3 for now
61
+ y = nn.Conv(self.num_channels_bottleneck or self.num_channels,
62
+ kernel_size=ks, padding=1, use_bias=False)(y)
63
+ y = nn.GroupNorm(num_groups=self.num_grps_norm, name="gn_1")(y)
64
+ y = nn.relu(y)
65
+
66
+ y = nn.Conv(self.num_channels_bottleneck or self.num_channels,
67
+ kernel_size=ks, padding=1, use_bias=False)(y)
68
+ y = nn.Dropout(rate=self.dropout_rate, deterministic=(not train))(y)
69
+ y = nn.GroupNorm(num_groups=self.num_grps_norm, name="gn_2")(y)
70
+ y = nn.relu(y)
71
+
72
+ y = nn.Conv(self.num_channels, kernel_size=ks, padding=1, use_bias=False)(y)
73
+
74
+ return y
75
+
76
+ def forward(
77
+ self,
78
+ x: tuple[jax.Array, jax.Array],
79
+ train: bool = True,
80
+ ) -> tuple[jax.Array, jax.Array]:
81
+ """Bijective block forward."""
82
+ x1, x2 = x[0], x[1]
83
+ fx2 = self._fx2(x2, train=train)
84
+ y1 = fx2 + x1
85
+ return (x2, y1)
86
+
87
+ def inverse(self,
88
+ x: tuple[jax.Array, jax.Array],
89
+ train: bool = True
90
+ ) -> tuple[jax.Array, jax.Array]:
91
+ """Bijective block inverse."""
92
+ x2, y1 = x[0], x[1]
93
+ fx2 = -self._fx2(x2, train=train)
94
+ x1 = fx2 + y1
95
+ return (x1, x2)
96
+
97
+
98
+ class IRevNet(nn.Module):
99
+ """iRevNet."""
100
+ num_blocks: int = 4
101
+ num_channels: int = 4
102
+ num_channels_bottleneck: Optional[int] = None
103
+ dropout_rate: float = 0.0
104
+
105
+ def setup(self) -> None:
106
+ num_grps_norm = min(32, self.num_channels // 2)
107
+ self.modules = [
108
+ IRevNetBlock(
109
+ first=(i == 0),
110
+ num_channels=self.num_channels // 2,
111
+ num_channels_bottleneck=(
112
+ self.num_channels_bottleneck or self.num_channels) // 2,
113
+ num_grps_norm=num_grps_norm,
114
+ dropout_rate=self.dropout_rate,
115
+ )
116
+ for i in range(self.num_blocks)
117
+ ]
118
+
119
+ def forward(self, x: jax.Array, train: bool = True) -> jax.Array:
120
+ out = _split(x)
121
+ for m in self.modules:
122
+ out = m.forward(out, train=train)
123
+ out_bij = _merge(out[0], out[1])
124
+ return out_bij
125
+
126
+ def inverse(self, out_bij: jax.Array, train: bool = True) -> jax.Array:
127
+ out = _split(out_bij)
128
+ for m in reversed(self.modules):
129
+ out = m.inverse(out, train=train)
130
+ out = _merge(out[0], out[1])
131
+ return out
132
+
133
+ def __call__(self, x: jax.Array, train: bool = True) -> jax.Array:
134
+ return self.forward(x, train=train)
135
+
136
+
137
+ class Model(IRevNet):
138
+ """Wrapper for IRevNet to function as an adaptor in our setup."""
139
+
140
+ pixel_shuffle_patch_size: tuple[int, int] = (1, 1)
141
+
142
+ def forward(self, x: jax.Array, train: bool = True) -> jax.Array:
143
+ # (b, code_len, ch) --> (b, h, w, ch) --> (b, code_len, ch)
144
+ # h, w are the spatial dimensions after space-to-depth transformation
145
+ h, w = cnn.get_h_w_pixelshuffle(x.shape[1], self.pixel_shuffle_patch_size)
146
+ x = einops.rearrange(x, "b (h w) c -> b h w c", h=h, w=w)
147
+ x = super().forward(x, train)
148
+ x = einops.rearrange(x, "b h w c -> b (h w) c") # (b, codelen, codeword_d)
149
+
150
+ return x
151
+
152
+ def inverse(self, out_bij: jax.Array, train: bool = True) -> jax.Array:
153
+ # (b, code_len, ch) --> (b, h, w, ch) --> (b, code_len, ch)
154
+ h, w = cnn.get_h_w_pixelshuffle(
155
+ out_bij.shape[1], self.pixel_shuffle_patch_size)
156
+ out_bij = einops.rearrange(out_bij, "b (h w) c -> b h w c", h=h, w=w)
157
+ out_bij = super().inverse(out_bij, train)
158
+ out_bij = einops.rearrange(out_bij, "b h w c -> b (h w) c")
159
+
160
+ return out_bij
161
+
162
+
163
+ def load(
164
+ init_params: Any,
165
+ init_file: str,
166
+ model_params: Any = None,
167
+ dont_load: Sequence[str] = (),
168
+ ) -> Any:
169
+ """Loads params from init checkpoint and merges into init_params."""
170
+ del model_params
171
+ ckpt_params = flax.core.unfreeze(utils.load_params(init_file))
172
+ if init_params is not None:
173
+ ckpt_params = common.merge_params(ckpt_params, init_params, dont_load)
174
+ return ckpt_params
Tipsomaly/model/big_vision/models/proj/givt/adaptor_test.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Tests for the IRevNet adaptor."""
16
+
17
+ from big_vision.models.proj.givt import adaptor
18
+ import jax
19
+ from jax import random
20
+ import jax.numpy as jnp
21
+
22
+ from absl.testing import absltest
23
+
24
+
25
+ class AdaptorTest(googletest.TestCase):
26
+
27
+ def test_inversion(self):
28
+ num_channels = 8
29
+ input_shape = (1, 24, 24, num_channels)
30
+
31
+ rng = random.PRNGKey(758493)
32
+ _, inp_rng, init_rng, data_rng = jax.random.split(rng, 4)
33
+
34
+ dummy_x = random.normal(inp_rng, shape=input_shape)
35
+ real_x = jax.random.normal(data_rng, shape=input_shape)
36
+
37
+ model = adaptor.IRevNet(
38
+ num_blocks=4,
39
+ num_channels=num_channels,
40
+ dropout_rate=0.0,
41
+ )
42
+ params = model.init(init_rng, dummy_x)
43
+
44
+ real_y = model.apply(params, real_x, method=model.forward)
45
+ real_x_ = model.apply(params, real_y, method=model.inverse)
46
+ self.assertTrue(jnp.allclose(real_x, real_x_, atol=1e-5))
47
+
48
+
49
+ if __name__ == "__main__":
50
+ googletest.main()
Tipsomaly/model/big_vision/models/proj/givt/cnn.py ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """CNN encoder/decoder architecture based on the VQ-GAN and MaskGIT papers.
16
+
17
+ Adapted from https://github.com/google-research/maskgit/blob/main/maskgit/nets/vqgan_tokenizer.py. # pylint: disable=line-too-long
18
+ """
19
+
20
+ import dataclasses
21
+ import functools
22
+ import math
23
+ from typing import Any, Sequence
24
+
25
+ from big_vision import utils
26
+ from big_vision.models import common
27
+ from big_vision.models.proj.givt import vae
28
+
29
+ import einops
30
+ import flax.linen as nn
31
+ import flax.training.checkpoints
32
+
33
+ import jax
34
+ import jax.numpy as jnp
35
+
36
+
37
+ def _get_norm_layer(train, dtype, norm_type="BN"):
38
+ """Create normalization layers.
39
+
40
+ Args:
41
+ train: Whether to use the layer in training or inference mode.
42
+ dtype: Layer output type.
43
+ norm_type: Which normalization to use "BN", "LN", or "GN".
44
+
45
+ Returns:
46
+ An instance of the the layer.
47
+ """
48
+ if norm_type == "BN":
49
+ return functools.partial(
50
+ nn.BatchNorm,
51
+ use_running_average=not train,
52
+ momentum=0.9,
53
+ epsilon=1e-5,
54
+ axis_name=None,
55
+ axis_index_groups=None,
56
+ dtype=jnp.float32,
57
+ use_fast_variance=False)
58
+ elif norm_type == "LN":
59
+ return functools.partial(nn.LayerNorm, dtype=dtype, use_fast_variance=False)
60
+ elif norm_type == "GN":
61
+ return functools.partial(nn.GroupNorm, dtype=dtype, use_fast_variance=False)
62
+ else:
63
+ raise NotImplementedError
64
+
65
+
66
+ def _tensorflow_style_avg_pooling(x, window_shape, strides, padding: str):
67
+ """Avg pooling as done by TF (Flax layer gives different results).
68
+
69
+ To be specific, Flax includes padding cells when taking the average,
70
+ while TF does not.
71
+
72
+ Args:
73
+ x: Input tensor
74
+ window_shape: Shape of pooling window; if 1-dim tuple is just 1d pooling, if
75
+ 2-dim tuple one gets 2d pooling.
76
+ strides: Must have the same dimension as the window_shape.
77
+ padding: Either 'SAME' or 'VALID' to indicate pooling method.
78
+
79
+ Returns:
80
+ pooled: Tensor after applying pooling.
81
+ """
82
+ pool_sum = jax.lax.reduce_window(x, 0.0, jax.lax.add,
83
+ (1,) + window_shape + (1,),
84
+ (1,) + strides + (1,), padding)
85
+ pool_denom = jax.lax.reduce_window(
86
+ jnp.ones_like(x), 0.0, jax.lax.add, (1,) + window_shape + (1,),
87
+ (1,) + strides + (1,), padding)
88
+ return pool_sum / pool_denom
89
+
90
+
91
+ def _upsample(x, factor=2, method="nearest"):
92
+ n, h, w, c = x.shape
93
+ x = jax.image.resize(x, (n, h * factor, w * factor, c), method=method)
94
+ return x
95
+
96
+
97
+ def _dsample(x):
98
+ return _tensorflow_style_avg_pooling(
99
+ x, (2, 2), strides=(2, 2), padding="same")
100
+
101
+
102
+ def get_h_w_pixelshuffle(hw, pixel_shuffle_patch_size):
103
+ # Compute h, w after space-to-depth transformation and before flattening,
104
+ # assuming the imge before space-to-depth transformation was square.
105
+ ph, pw = pixel_shuffle_patch_size
106
+ s = int(math.sqrt(hw * ph * pw))
107
+ h, w = s // ph, s // pw
108
+ assert h * w == hw, f"Length {hw} incompatible with pixelshuffle ({ph}, {pw})"
109
+ return h, w
110
+
111
+
112
+ class ResBlock(nn.Module):
113
+ """Basic Residual Block."""
114
+ filters: int
115
+ norm_fn: Any
116
+ conv_fn: Any
117
+ dtype: int = jnp.float32
118
+ activation_fn: Any = nn.relu
119
+ use_conv_shortcut: bool = False
120
+
121
+ @nn.compact
122
+ def __call__(self, x: jax.Array) -> jax.Array:
123
+ input_dim = x.shape[-1]
124
+ residual = x
125
+ x = self.norm_fn()(x)
126
+ x = self.activation_fn(x)
127
+ x = self.conv_fn(self.filters, kernel_size=(3, 3), use_bias=False)(x)
128
+ x = self.norm_fn()(x)
129
+ x = self.activation_fn(x)
130
+ x = self.conv_fn(self.filters, kernel_size=(3, 3), use_bias=False)(x)
131
+ if input_dim != self.filters:
132
+ if self.use_conv_shortcut:
133
+ residual = self.conv_fn(
134
+ self.filters, kernel_size=(3, 3), use_bias=False)(
135
+ x)
136
+ else:
137
+ residual = self.conv_fn(
138
+ self.filters, kernel_size=(1, 1), use_bias=False)(
139
+ x)
140
+ return x + residual
141
+
142
+
143
+ class Encoder(nn.Module):
144
+ """Encoder Blocks."""
145
+
146
+ filters: int
147
+ num_res_blocks: int
148
+ channel_multipliers: list[int]
149
+ embedding_dim: int
150
+ conv_downsample: bool = False
151
+ norm_type: str = "GN"
152
+ activation_fn_str: str = "swish"
153
+ dtype: int = jnp.float32
154
+
155
+ def setup(self) -> None:
156
+ if self.activation_fn_str == "relu":
157
+ self.activation_fn = nn.relu
158
+ elif self.activation_fn_str == "swish":
159
+ self.activation_fn = nn.swish
160
+ else:
161
+ raise NotImplementedError
162
+
163
+ @nn.compact
164
+ def __call__(self, x: jax.Array, train: bool = False) -> jax.Array:
165
+ conv_fn = nn.Conv
166
+ norm_fn = _get_norm_layer(
167
+ train=train, dtype=self.dtype, norm_type=self.norm_type)
168
+ block_args = dict(
169
+ norm_fn=norm_fn,
170
+ conv_fn=conv_fn,
171
+ dtype=self.dtype,
172
+ activation_fn=self.activation_fn,
173
+ use_conv_shortcut=False,
174
+ )
175
+ x = conv_fn(self.filters, kernel_size=(3, 3), use_bias=False)(x)
176
+ num_blocks = len(self.channel_multipliers)
177
+ for i in range(num_blocks):
178
+ filters = self.filters * self.channel_multipliers[i]
179
+ for _ in range(self.num_res_blocks):
180
+ x = ResBlock(filters, **block_args)(x)
181
+ if i < num_blocks - 1:
182
+ if self.conv_downsample:
183
+ x = conv_fn(filters, kernel_size=(4, 4), strides=(2, 2))(x)
184
+ else:
185
+ x = _dsample(x)
186
+ for _ in range(self.num_res_blocks):
187
+ x = ResBlock(filters, **block_args)(x)
188
+ x = norm_fn()(x)
189
+ x = self.activation_fn(x)
190
+ x = conv_fn(self.embedding_dim, kernel_size=(1, 1))(x)
191
+ return x
192
+
193
+
194
+ class Decoder(nn.Module):
195
+ """Decoder Blocks."""
196
+
197
+ filters: int
198
+ num_res_blocks: int
199
+ channel_multipliers: list[int]
200
+ norm_type: str = "GN"
201
+ activation_fn_str: str = "swish"
202
+ output_dim: int = 3
203
+ dtype: Any = jnp.float32
204
+
205
+ def setup(self) -> None:
206
+ if self.activation_fn_str == "relu":
207
+ self.activation_fn = nn.relu
208
+ elif self.activation_fn_str == "swish":
209
+ self.activation_fn = nn.swish
210
+ else:
211
+ raise NotImplementedError
212
+
213
+ @nn.compact
214
+ def __call__(self, x: jax.Array, train: bool = False) -> jax.Array:
215
+ conv_fn = nn.Conv
216
+ norm_fn = _get_norm_layer(
217
+ train=train, dtype=self.dtype, norm_type=self.norm_type)
218
+ block_args = dict(
219
+ norm_fn=norm_fn,
220
+ conv_fn=conv_fn,
221
+ dtype=self.dtype,
222
+ activation_fn=self.activation_fn,
223
+ use_conv_shortcut=False,
224
+ )
225
+ num_blocks = len(self.channel_multipliers)
226
+ filters = self.filters * self.channel_multipliers[-1]
227
+ x = conv_fn(filters, kernel_size=(3, 3), use_bias=True)(x)
228
+ for _ in range(self.num_res_blocks):
229
+ x = ResBlock(filters, **block_args)(x)
230
+ for i in reversed(range(num_blocks)):
231
+ filters = self.filters * self.channel_multipliers[i]
232
+ for _ in range(self.num_res_blocks):
233
+ x = ResBlock(filters, **block_args)(x)
234
+ if i > 0:
235
+ x = _upsample(x, 2)
236
+ x = conv_fn(filters, kernel_size=(3, 3))(x)
237
+ x = norm_fn()(x)
238
+ x = self.activation_fn(x)
239
+ x = conv_fn(self.output_dim, kernel_size=(3, 3))(x)
240
+ return x
241
+
242
+
243
+ class Model(vae.Model):
244
+ """CNN Model."""
245
+
246
+ filters: int = 128
247
+ num_res_blocks: int = 2
248
+ channel_multipliers: list[int] = dataclasses.field(default_factory=list)
249
+ conv_downsample: bool = False
250
+ activation_fn: str = "swish"
251
+ norm_type: str = "GN"
252
+ output_dim: int = 3
253
+ dtype: Any = jnp.float32
254
+ # If True, rescale the input [-1, 1] -> [0, 1] and clip logvar to [-30, 20]
255
+ malib_ckpt: bool = False
256
+ pixel_shuffle_patch_size: tuple[int, int] = (1, 1)
257
+
258
+ def setup(self) -> None:
259
+ # Encoder and decoder
260
+ self.encoder = Encoder(
261
+ filters=self.filters,
262
+ num_res_blocks=self.num_res_blocks,
263
+ channel_multipliers=self.channel_multipliers,
264
+ norm_type=self.norm_type,
265
+ activation_fn_str=self.activation_fn,
266
+ embedding_dim=2 * self.codeword_dim,
267
+ conv_downsample=self.conv_downsample,
268
+ dtype=self.dtype,
269
+ name="cnn_encoder",
270
+ )
271
+ self.decoder = Decoder(
272
+ filters=self.filters,
273
+ num_res_blocks=self.num_res_blocks,
274
+ channel_multipliers=self.channel_multipliers,
275
+ norm_type=self.norm_type,
276
+ activation_fn_str=self.activation_fn,
277
+ output_dim=self.output_dim,
278
+ dtype=self.dtype,
279
+ name="cnn_decoder",
280
+ )
281
+
282
+ def _maybe_rescale_input(self, x):
283
+ return (x + 1.0) / 2.0 if self.malib_ckpt else x
284
+
285
+ def _maybe_rescale_output(self, x):
286
+ return 2.0 * x - 1.0 if self.malib_ckpt else x
287
+
288
+ def _maybe_clip_logvar(self, logvar):
289
+ return jnp.clip(logvar, -30.0, 20.0) if self.malib_ckpt else logvar
290
+
291
+ def encode(
292
+ self,
293
+ x: jax.Array,
294
+ *,
295
+ train: bool = False,
296
+ ) -> tuple[jax.Array, jax.Array]:
297
+ x = self._maybe_rescale_input(x)
298
+ x = self.encoder(x, train=train) # (2, 16, 16, 64)
299
+ assert x.shape[1] == x.shape[2], f"Square spatial dims. required: {x.shape}"
300
+ mu, logvar = jnp.split(x, 2, axis=-1) # (2, 16, 16, 32) x 2
301
+ logvar = self._maybe_clip_logvar(logvar)
302
+
303
+ def _space_to_depth(z):
304
+ ph, pw = self.pixel_shuffle_patch_size
305
+ return einops.rearrange(
306
+ z, "b (h ph) (w pw) c -> b (h w) (c ph pw)",
307
+ ph=ph, pw=pw
308
+ ) # (2, 256 // (ph * pw), 64 * ph * pw)
309
+
310
+ mu, logvar = _space_to_depth(mu), _space_to_depth(logvar)
311
+
312
+ return mu, logvar
313
+
314
+ def decode(self, x: jax.Array, train: bool = False) -> jax.Array:
315
+ # Decode
316
+ ph, pw = self.pixel_shuffle_patch_size
317
+ h, w = get_h_w_pixelshuffle(x.shape[1], (ph, pw))
318
+
319
+ x = einops.rearrange(
320
+ x, "b (h w) (c ph pw) -> b (h ph) (w pw) c",
321
+ h=h, w=w,
322
+ ph=ph, pw=pw
323
+ ) # (2, 16, 16, 32)
324
+ x = self.decoder(x, train=train) # (2, 256, 256, 3)
325
+ x = self._maybe_rescale_output(x)
326
+ x = jnp.clip(x, -1.0, 1.0)
327
+
328
+ return x
329
+
330
+
331
+ def load(
332
+ init_params: Any,
333
+ init_file: str,
334
+ model_params: Any = None,
335
+ dont_load: Sequence[str] = (),
336
+ malib_ckpt: bool = False,
337
+ use_ema_params: bool = False,
338
+ ) -> Any:
339
+ """Loads params from init checkpoint and merges into init_params.
340
+
341
+ Args:
342
+ init_params: pytree with (previously initialized) model parameters.
343
+ init_file: Path of the checkpoint to load.
344
+ model_params: Dict containing the model config.
345
+ dont_load: Sequence of (flattened) parameter names which should not be
346
+ loaded.
347
+ malib_ckpt: Whether the given init_file is a malib checkpoint.
348
+ use_ema_params: Whether to load the EMA params (for malib checkpoints).
349
+
350
+ Returns:
351
+ pytree containing the loaded model parameters.
352
+ """
353
+ # `model_params` is unused here, but we still include it to conform with the
354
+ # general big_vision interface, cf. the core models in big_vision/models/.
355
+ del model_params
356
+
357
+ assert malib_ckpt or (not use_ema_params), (
358
+ "Loading EMA parameters is only supported for malib checkpoints.")
359
+
360
+ if malib_ckpt:
361
+ # Locally disable transfer guard since restore_checkpoint does not allow for
362
+ # fine-grained sharding control.
363
+ with jax.transfer_guard("allow"):
364
+ vaegan_params = flax.training.checkpoints.restore_checkpoint(
365
+ init_file, None)
366
+ vaegan_params_flat = utils.tree_flatten_with_names(vaegan_params)[0]
367
+ prefix_old = "ema_params/" if use_ema_params else "g_params/"
368
+ vaegan_params_flat = [(k.replace(prefix_old, "cnn_"), v)
369
+ for k, v in vaegan_params_flat if prefix_old in k]
370
+ params = utils.tree_unflatten(vaegan_params_flat)
371
+ else:
372
+ params = flax.core.unfreeze(utils.load_params(init_file))
373
+
374
+ if init_params is not None:
375
+ params = common.merge_params(params, init_params, dont_load)
376
+ return params
Tipsomaly/model/big_vision/models/proj/givt/decode.py ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Autorgregressive sampler for GIVT."""
16
+
17
+ import functools
18
+ from typing import Any, Optional
19
+
20
+ from big_vision.models.proj.givt import parallel_decode
21
+ import flax
22
+ from flax import linen as nn
23
+ import jax
24
+ from jax import lax
25
+ from jax import numpy as jnp
26
+ import ml_collections
27
+
28
+
29
+ def _sample_gmm(
30
+ gmm_pdf,
31
+ *,
32
+ rng,
33
+ cfg_inference_weight=None,
34
+ gmm_pdf_uncond=None,
35
+ ):
36
+ """Draw a single sample from a GMM."""
37
+ if cfg_inference_weight is not None:
38
+ assert gmm_pdf_uncond is not None
39
+ gmm_pdf = parallel_decode.CFGDensity(
40
+ gmm_pdf, gmm_pdf_uncond, w=cfg_inference_weight, rng=rng
41
+ )
42
+ samples = gmm_pdf.sample(seed=rng)
43
+ logprobs = gmm_pdf.log_prob(samples)
44
+ if logprobs.ndim == 2:
45
+ logprobs = logprobs[..., None]
46
+ return samples, logprobs
47
+
48
+
49
+ # Beam search reshaping utils
50
+ def _flatten_samples_dim(x):
51
+ """Flattens samples dimension into batch dimension."""
52
+ if x.ndim == 0: # ignore scalars (e.g. cache index)
53
+ return x
54
+ return x.reshape((x.shape[0] * x.shape[1],) + x.shape[2:])
55
+
56
+
57
+ def _unflatten_samples_dim(x, batch_size, num_samples):
58
+ """Unflattens first dimension into batch and samples dimensions."""
59
+ if x.ndim == 0: # ignore scalars (e.g. cache index)
60
+ return x
61
+ assert batch_size * num_samples == x.shape[0]
62
+ return x.reshape((batch_size, num_samples) + x.shape[1:])
63
+
64
+
65
+ def _cache_map(fn, cache, scan=False):
66
+ """Maps function over cache."""
67
+ if scan:
68
+ # Assuming the chache is scanned over the first dimension, we apply a map
69
+ # function over this dimension for scanned models
70
+ fn_mod = lambda x: jax.lax.map(fn, x) if x.ndim > 0 else fn(x)
71
+ else:
72
+ fn_mod = fn
73
+
74
+ frozen = isinstance(cache, flax.core.FrozenDict)
75
+ if frozen:
76
+ cache = flax.core.unfreeze(cache)
77
+ flat_cache = flax.traverse_util.flatten_dict(cache)
78
+ # Exclude cached relative position bias from beam expansion, etc.
79
+ keyvals = {k: v for k, v in flat_cache.items() if k[-1] != "cached_bias"}
80
+ keyvals = jax.tree_map(fn_mod, keyvals)
81
+ flat_cache.update(keyvals)
82
+ new_cache = flax.traverse_util.unflatten_dict(flat_cache)
83
+ if frozen:
84
+ new_cache = flax.core.freeze(new_cache)
85
+ return new_cache
86
+
87
+
88
+ @flax.struct.dataclass
89
+ class LoopState:
90
+ """Internal state of the sampling loop."""
91
+ # Terminology
92
+ # b: batch size
93
+ # nb: number of beams
94
+ # nf: number of fans
95
+ # s: seaquence length
96
+ # d: feature dimension
97
+ rng: jnp.ndarray # PRNGKey of the loop state.
98
+ cache: Any # Cache for fast auto-regressive decoding.
99
+ sequences: jnp.ndarray # (b * nb, s, d)
100
+ logprobs: jnp.ndarray # (b * nb, s, d)
101
+ cache_u: Any # Uncond cache if cfg, otherwise None
102
+
103
+
104
+ def _create_cache(
105
+ labels,
106
+ model,
107
+ init_sequence,
108
+ params,
109
+ encoded,
110
+ uncond=False,
111
+ ):
112
+ """Creates the cache and returns initial logits."""
113
+ if uncond:
114
+ assert labels is not None # Need labels for CFG!
115
+ drop_labels = jnp.ones((labels.shape[0],), dtype=jnp.bool_)
116
+ else:
117
+ drop_labels = None
118
+
119
+ def init_cache(model):
120
+ return model.decode(
121
+ init_sequence, labels, encoded, decode=True, drop_labels=drop_labels
122
+ )
123
+
124
+ cache = nn.apply(init_cache, model, mutable=True)(params)[1]["cache"]
125
+
126
+ def prefill_cache(model):
127
+ return model.prefill(
128
+ labels, init_sequence.shape[0], encoded, drop_labels=drop_labels
129
+ )
130
+
131
+ # prefill class label or BOS token
132
+ prefill_logits, aux = nn.apply(prefill_cache, model, mutable=True)(
133
+ {"params": params["params"], "cache": cache})
134
+ cache = aux["cache"]
135
+ return cache, prefill_logits
136
+
137
+
138
+ def generate(
139
+ params: Any,
140
+ seed: jax.Array,
141
+ *,
142
+ model: nn.Module,
143
+ seq_len: int,
144
+ feature_dim: int,
145
+ labels: Optional[jnp.ndarray] = None,
146
+ cond_image: Optional[jnp.ndarray] = None,
147
+ batch_size: Optional[int] = None,
148
+ config: Optional[ml_collections.ConfigDict] = None,
149
+ ) -> tuple[jax.Array, jax.Array]:
150
+ """Sampling loop for GIVT."""
151
+ if model.style != "ar": # pytype: disable=wrong-arg-types
152
+ raise ValueError(f"Invalid style: {model.style}")
153
+ if model.has_encoder != (cond_image is not None):
154
+ raise ValueError("Need cond_image if and only if the model has an encoder!")
155
+
156
+ assert labels is not None or batch_size, (
157
+ "Please provide either labels or batch_size.")
158
+
159
+ config = config or {}
160
+ config = dict(config) # copy
161
+
162
+ # For sampling, we support keep_gt (a bool mask), and gt (ground truth)
163
+ # tokens to use instead of samples.
164
+ keep_gt = config.pop("keep_gt", None)
165
+ gt = config.pop("gt", None)
166
+
167
+ if isinstance(seed, int):
168
+ seed = jax.random.PRNGKey(seed)
169
+
170
+ beam_size = config.pop("beam_size", 1)
171
+ fan_size = config.pop("fan_size", 1)
172
+
173
+ if labels is not None:
174
+ batch_size = labels.shape[0]
175
+ # fold beams into batch dimension
176
+ labels = labels.repeat(beam_size, axis=0)
177
+
178
+ # initialize sequence and logprobs (we track per feature dim logprobs)
179
+ init_sequence = jnp.zeros((batch_size * beam_size, seq_len, feature_dim))
180
+ init_logprobs = jnp.zeros_like(init_sequence)
181
+
182
+ if cond_image is not None:
183
+ # embed conditioning image if provided
184
+ def encode_cond_img(model, cond_img):
185
+ return model.encode(cond_img)
186
+ encoded = nn.apply(encode_cond_img, model)(params, cond_image)
187
+ encoded = jnp.repeat(encoded, beam_size, axis=0)
188
+ else:
189
+ encoded = None
190
+
191
+ cache, prefill_logits = _create_cache(
192
+ labels, model, init_sequence, params, encoded
193
+ )
194
+
195
+ cfg_inference_weight = config.pop("cfg_inference_weight", None)
196
+ if cfg_inference_weight == 0.0:
197
+ cfg_inference_weight = None
198
+ cfg = cfg_inference_weight is not None
199
+
200
+ get_pdf = functools.partial(
201
+ model.get_pdf,
202
+ temperature_scales=config.pop("temp", None),
203
+ temperature_probs=config.pop("temp_probs", None),
204
+ )
205
+
206
+ # setup sampling function
207
+ sample = functools.partial(
208
+ _sample_gmm, cfg_inference_weight=cfg_inference_weight
209
+ )
210
+
211
+ # draw first output token
212
+ pdf_first = get_pdf(prefill_logits)
213
+ rng_first, rng = jax.random.split(seed)
214
+
215
+ if cfg:
216
+ assert beam_size == 1 and fan_size == 1 # CFG + Beam not supported.
217
+ cache_u, prefill_logits_u = _create_cache(
218
+ labels, model, init_sequence, params, encoded, uncond=True
219
+ )
220
+ pdf_first_u = get_pdf(prefill_logits_u)
221
+ else:
222
+ cache_u = None
223
+ pdf_first_u = None
224
+
225
+ tokens_first, logprobs_first = sample(
226
+ pdf_first, rng=rng_first, gmm_pdf_uncond=pdf_first_u
227
+ )
228
+ init_sequence = init_sequence.at[:, 0].set(tokens_first.squeeze(axis=1))
229
+ init_logprobs = init_logprobs.at[:, 0].set(logprobs_first.squeeze(axis=1))
230
+
231
+ def tokens_to_logits(tokens, cache, uncond=False):
232
+ if uncond:
233
+ drop_labels = jnp.ones((labels.shape[0],), dtype=jnp.bool_)
234
+ else:
235
+ drop_labels = None
236
+
237
+ def decode_step(model, tokens):
238
+ return model.decode(tokens, labels, encoded,
239
+ decode=True, drop_labels=drop_labels)
240
+
241
+ logits, aux = nn.apply(decode_step, model, mutable=True)(
242
+ {"params": params["params"], "cache": cache}, tokens)
243
+ return logits, aux["cache"]
244
+
245
+ init_state = LoopState(
246
+ cache=cache,
247
+ sequences=init_sequence, # (b * nb, s, d)
248
+ logprobs=init_logprobs, # (b * nb, s, d)
249
+ rng=rng,
250
+ cache_u=cache_u,
251
+ )
252
+
253
+ rand_top_k = config.pop("rand_top_k", False)
254
+ rand_top_k_temp = config.pop("rand_top_k_temp", 1.0)
255
+
256
+ assert not config, f"Sampling config is expected to be empty: {config}"
257
+
258
+ def sampling_iteration(i, state):
259
+ rng_sampling, rng_local = jax.random.split(state.rng)
260
+ cur_tokens = state.sequences[:, i][:, None]
261
+ # (b * nb, d)
262
+ cur_logits, cache = tokens_to_logits(cur_tokens, state.cache)
263
+
264
+ # (b, nb, d)
265
+ cur_logits = _unflatten_samples_dim(
266
+ cur_logits, batch_size, beam_size).squeeze(axis=2)
267
+
268
+ # (b, nb * nf, d)
269
+ cur_pdf = get_pdf(cur_logits.repeat(fan_size, axis=1))
270
+
271
+ if cfg:
272
+ cur_logits_u, cache_u = tokens_to_logits(
273
+ cur_tokens, state.cache_u, uncond=True
274
+ )
275
+ cur_logits_u = _unflatten_samples_dim(
276
+ cur_logits_u, batch_size, beam_size).squeeze(axis=2)
277
+ cur_pdf_u = get_pdf(cur_logits_u.repeat(fan_size, axis=1))
278
+ new_tokens, new_logprobs = sample(
279
+ cur_pdf, rng=rng_sampling, gmm_pdf_uncond=cur_pdf_u
280
+ )
281
+ else:
282
+ new_tokens, new_logprobs = sample(cur_pdf, rng=rng_sampling)
283
+ cache_u = None
284
+
285
+ if gt is not None:
286
+ assert keep_gt is not None
287
+ new_tokens = jnp.where(keep_gt[i], gt[:, i, :][:, None], new_tokens)
288
+
289
+ # Skip beam search if not needed
290
+ if beam_size == fan_size == 1:
291
+ sampled_tokens = new_tokens.squeeze(axis=1)
292
+ sequences = state.sequences.at[:, i + 1].set(sampled_tokens)
293
+ return LoopState(
294
+ cache=cache,
295
+ rng=rng_local,
296
+ sequences=sequences,
297
+ logprobs=state.logprobs,
298
+ cache_u=cache_u,
299
+ )
300
+
301
+ # (b, nb, s, d)
302
+ logprobs = _unflatten_samples_dim(state.logprobs, batch_size, beam_size)
303
+ cur_logprobs = logprobs[:, :, i] # (b, nb, d)
304
+ # (b, nb * nf, d)
305
+ new_logprobs = new_logprobs + cur_logprobs.repeat(fan_size, axis=1)
306
+ beam_logprobs = new_logprobs.sum(axis=-1) # (b, nb * nf)
307
+
308
+ if rand_top_k:
309
+ # randomize top-k sampling via sampling from a categorical distribution
310
+ def stoc_top_k(r, x, p):
311
+ return jax.random.choice(r, x, shape=(beam_size,), replace=False, p=p)
312
+ # construct index grid
313
+ index_grid = jnp.arange(beam_logprobs.shape[1], dtype=jnp.int32)
314
+ # (b, nb * nf)
315
+ index_grid = index_grid[None].repeat(beam_logprobs.shape[0], axis=0)
316
+ top_k_rng, rng_local = jax.random.split(rng_local)
317
+ top_k_rng = jax.random.split(top_k_rng, beam_logprobs.shape[0])
318
+ # vmap categorical sampling
319
+ top_beam_fan_indices = jax.vmap(stoc_top_k, in_axes=(0, 0, 0))(
320
+ top_k_rng,
321
+ index_grid,
322
+ nn.softmax(beam_logprobs / rand_top_k_temp, axis=-1))
323
+ else:
324
+ _, top_beam_fan_indices = lax.top_k(beam_logprobs, k=beam_size) # (b, nb)
325
+
326
+ top_beam_indices = top_beam_fan_indices // fan_size
327
+
328
+ def _gather_beams(x):
329
+ if x.ndim == 0:
330
+ return x
331
+ # checkify.check(jnp.all(top_beam_indices < x.shape[1]),
332
+ # f"`take_along_axis` out of bounds in `_gather_beams`: "
333
+ # f"{top_beam_indices.max()} vs. {x.shape[1]}")
334
+ # (b, nb, 1 ... 1)
335
+ expanded_indices = top_beam_indices.reshape(
336
+ top_beam_indices.shape + (1,) * (x.ndim - 2))
337
+ return jnp.take_along_axis(x, expanded_indices, axis=1)
338
+
339
+ def _gather_tokens(x):
340
+ # (b, nb * nf, d) -> (b, nb, d)
341
+ # checkify.check(jnp.all(top_beam_fan_indices < x.shape[1]),
342
+ # f"`take_along_axis` out of bounds in `_gather_tokens`: "
343
+ # f"{top_beam_fan_indices.max()} vs. {x.shape[1]}")
344
+ return jnp.take_along_axis(x, top_beam_fan_indices[..., None], axis=1)
345
+ # (b, nb, s, d)
346
+ sequences = _unflatten_samples_dim(state.sequences, batch_size, beam_size)
347
+ sequences = _gather_beams(sequences) # (b, nb, s, d)
348
+ sequences = sequences.at[:, :, i + 1].set(_gather_tokens(new_tokens))
349
+ # (b, nb, s, d)
350
+ sequences = _flatten_samples_dim(sequences)
351
+
352
+ logprobs = _gather_beams(logprobs)
353
+ logprobs = logprobs.at[:, :, i + 1].set(_gather_tokens(new_logprobs))
354
+ logprobs = _flatten_samples_dim(logprobs)
355
+
356
+ scanned_cache = getattr(model, "scan", False)
357
+ cache = _cache_map(
358
+ lambda x: _unflatten_samples_dim(x, batch_size, beam_size),
359
+ cache, scanned_cache)
360
+ cache = _cache_map(_gather_beams, cache, scanned_cache)
361
+ cache = _cache_map(_flatten_samples_dim, cache, scanned_cache)
362
+
363
+ if cfg:
364
+ assert cache_u is not None
365
+ cache_u = _cache_map(
366
+ lambda x: _unflatten_samples_dim(x, batch_size, beam_size),
367
+ cache_u, scanned_cache
368
+ )
369
+ cache_u = _cache_map(_gather_beams, cache_u, scanned_cache)
370
+ cache_u = _cache_map(_flatten_samples_dim, cache_u, scanned_cache)
371
+ else:
372
+ assert cache_u is None
373
+
374
+ return LoopState(
375
+ cache=cache,
376
+ rng=rng_local,
377
+ sequences=sequences,
378
+ logprobs=logprobs,
379
+ cache_u=cache_u,
380
+ )
381
+
382
+ final_state = lax.fori_loop(0, seq_len, sampling_iteration, init_state)
383
+ final_logprobs = final_state.logprobs[::beam_size][:, -1].sum(axis=-1)
384
+
385
+ # return top beams and corresponding log probs
386
+ return final_state.sequences[::beam_size], final_logprobs
Tipsomaly/model/big_vision/models/proj/givt/decode_test.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from absl.testing import parameterized
16
+ from big_vision.models.proj.givt import decode
17
+ from big_vision.models.proj.givt import givt
18
+ import jax
19
+ import jax.numpy as jnp
20
+
21
+ from absl.testing import absltest
22
+
23
+
24
+ _BATCH_SIZE = 2
25
+ _OUT_DIM = 4
26
+ _IMG_DIM = 8
27
+ _PATCH_SIZE = 2
28
+ _SEQ_LEN = _IMG_DIM // _PATCH_SIZE * _IMG_DIM // _PATCH_SIZE
29
+ _NUM_MIXTURES = 4
30
+
31
+
32
+ def _make_test_model(**overwrites):
33
+ config = dict(
34
+ num_heads=2,
35
+ num_decoder_layers=1,
36
+ mlp_dim=64,
37
+ emb_dim=16,
38
+ patches=(_PATCH_SIZE, _PATCH_SIZE),
39
+ input_size=(_IMG_DIM, _IMG_DIM),
40
+ seq_len=_SEQ_LEN,
41
+ out_dim=_OUT_DIM,
42
+ num_mixtures=_NUM_MIXTURES,
43
+ style="ar",
44
+ )
45
+ config.update(overwrites)
46
+ return givt.Model(**config)
47
+
48
+
49
+ class DecodeTest(parameterized.TestCase):
50
+
51
+ def _make_model(self, **overwrites):
52
+ model = _make_test_model(**overwrites)
53
+ sequence = jax.random.uniform(
54
+ jax.random.PRNGKey(0), (_BATCH_SIZE, _SEQ_LEN, _OUT_DIM)
55
+ )
56
+ labels = jax.random.uniform(
57
+ jax.random.PRNGKey(0), (_BATCH_SIZE,), maxval=10
58
+ ).astype(jnp.int32)
59
+ variables = model.init(
60
+ jax.random.PRNGKey(0),
61
+ sequence,
62
+ labels,
63
+ train=False,
64
+ image=jnp.zeros((_BATCH_SIZE, _IMG_DIM, _IMG_DIM, 3), dtype=jnp.float32)
65
+ if model.has_encoder
66
+ else None,
67
+ )
68
+ return model, variables
69
+
70
+ def _test_model(self, rng, model, variables, config):
71
+ labels = jnp.ones((_BATCH_SIZE,), dtype=jnp.int32)
72
+ if model.has_encoder:
73
+ cond_image = jnp.zeros(
74
+ (_BATCH_SIZE, _IMG_DIM, _IMG_DIM, 3), dtype=jnp.float32
75
+ )
76
+ else:
77
+ cond_image = None
78
+ result, logprobs = decode.generate(
79
+ params=variables,
80
+ seed=rng,
81
+ seq_len=_SEQ_LEN,
82
+ feature_dim=_OUT_DIM,
83
+ labels=labels,
84
+ model=model,
85
+ config=config,
86
+ cond_image=cond_image,
87
+ )
88
+ # TODO: More expressive tests? Eg for causality, and caching.
89
+ self.assertEqual(result.shape, (_BATCH_SIZE, _SEQ_LEN, _OUT_DIM))
90
+ self.assertTrue(jnp.allclose(logprobs, jnp.zeros_like(logprobs), atol=1e-5))
91
+
92
+ @parameterized.product(
93
+ rng_seed=[1, 2],
94
+ encoder=[True, False],
95
+ )
96
+ def test_simple(self, rng_seed, encoder):
97
+ rng = jax.random.PRNGKey(rng_seed)
98
+ model, variables = self._make_model(
99
+ num_layers=1 if encoder else 0
100
+ )
101
+ assert model.has_encoder == encoder
102
+ self._test_model(rng, model, variables, config={})
103
+
104
+ @parameterized.product(
105
+ rng_seed=[1, 2],
106
+ cfg_inference_weight=[0.0, 1.0, 3.0],
107
+ per_channel_mixtures=[True, False],
108
+ )
109
+ def test_cfg(self, rng_seed, cfg_inference_weight, per_channel_mixtures):
110
+ rng = jax.random.PRNGKey(rng_seed)
111
+ model, variables = self._make_model(
112
+ num_mixtures=1 if per_channel_mixtures else 3,
113
+ drop_labels_probability=0.1,
114
+ per_channel_mixtures=per_channel_mixtures,
115
+ )
116
+ config = {"cfg_inference_weight": cfg_inference_weight}
117
+ self._test_model(rng, model, variables, config)
118
+
119
+
120
+ if __name__ == "__main__":
121
+ googletest.main()
Tipsomaly/model/big_vision/models/proj/givt/givt.py ADDED
@@ -0,0 +1,820 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Decoder-only and encoder-decoder GIVT model.
16
+
17
+ Used abbreviations for dimension annotations:
18
+ B: batch size.
19
+ E: embedding size.
20
+ L: (soft) token sequence length.
21
+ D: soft token dimension.
22
+ P: number of patches (extracted by a ViT encoder in GIVT-based UViM)
23
+ """
24
+
25
+ import enum
26
+ import itertools
27
+ from typing import Literal, Optional, Sequence, Any, Mapping
28
+
29
+ from absl import logging
30
+ from big_vision import utils
31
+ from big_vision.models import common
32
+ from big_vision.models import vit
33
+ import distrax
34
+ import einops
35
+ import flax.linen as nn
36
+ from flax.linen import partitioning
37
+ import jax
38
+ import jax.numpy as jnp
39
+ import numpy as np
40
+
41
+
42
+ class _SpecialLabel(enum.Enum):
43
+
44
+ MASK = "mask"
45
+ NOMASK = "nomask"
46
+ REPLACE = "replace"
47
+ NOLABEL = "nolabel" # For CFG
48
+
49
+
50
+ def _random_mask_with_ratios(rng, ratios: jax.Array, seq_len: int):
51
+ """Generates masks where a fraction of tokens is uncovered.
52
+
53
+ Args:
54
+ rng: RNG.
55
+ ratios: Ratios, must be a 1D matrix of shape (B,). Values must be in
56
+ [0, 1], and indicate at ratios[i] how many of the i-th tokens are
57
+ uncovered (ie. equal to `True`).
58
+ seq_len: How many tokens this mask has to cover.
59
+
60
+ Returns:
61
+ Mask of dtype bool, shape (B, L).
62
+
63
+ Raises:
64
+ ValueError: Incorrect inputs.
65
+ """
66
+ if ratios.ndim != 1:
67
+ raise ValueError("Ratios must have shape (B,)!")
68
+ ratios = jnp.clip(ratios, 0, 1)
69
+ indices = jnp.arange(seq_len, dtype=jnp.float32) # Shape: (L,)
70
+ ratios = ratios[:, jnp.newaxis] * seq_len # Shape: (B, 1)
71
+ # This is a binary array where the first ratios * seq_len positions are True
72
+ mask = (indices < ratios).astype(jnp.bool_) # Shape: (B, L)
73
+ # Shuffle to a actual mask.
74
+ return jax.random.shuffle(rng, mask, axis=-1)
75
+
76
+
77
+ def apply_mask_schedule(ratio: float | jax.Array, method: str) -> jax.Array:
78
+ """Generate a mask rate by scheduling mask functions R."""
79
+ if method == "cosine":
80
+ mask_ratio = jax.lax.cos(jnp.pi / 2. * ratio)
81
+ elif "pow:" in method:
82
+ exponent = float(method.replace("pow:", ""))
83
+ mask_ratio = 1. - ratio**exponent
84
+ else:
85
+ raise NotImplementedError(method)
86
+ # Clamps mask into [epsilon, 1)
87
+ mask_ratio = jnp.clip(mask_ratio, 1e-6, 1.)
88
+ return mask_ratio
89
+
90
+
91
+ class EncoderDecoderBlock(nn.Module):
92
+ """Transformer encoder-decoder layer."""
93
+ mlp_dim: int
94
+ num_heads: int
95
+ dropout_rate: float = 0.
96
+ decode: bool = False
97
+
98
+ @nn.compact
99
+ def __call__(
100
+ self,
101
+ targets: jax.Array,
102
+ encoded: jax.Array | None = None,
103
+ decoder_mask: jax.Array | None = None,
104
+ deterministic: bool = True,
105
+ ) -> tuple[jax.Array, jax.Array]:
106
+ """Applies EncoderDecoderBlock module.
107
+
108
+ Args:
109
+ targets: target text embeddings [B, L, D].
110
+ encoded: encoded image patches from encoder [B, P, E].
111
+ decoder_mask: decoder self-attention mask.
112
+ deterministic: bool, deterministic or not (to apply dropout).
113
+
114
+ Returns:
115
+ output after transformer encoder-decoder block [B, L, E].
116
+ """
117
+ # Helper function for axis annotation.
118
+ def wlc(f):
119
+ dim_names = ("act_batch", "act_len", "act_emb")
120
+ return nn.with_logical_constraint(f, dim_names)
121
+ # Decoder block.
122
+ x = wlc(nn.LayerNorm(name="LayerNorm1", use_bias=False)(targets))
123
+ x = wlc(nn.SelfAttention(
124
+ num_heads=self.num_heads, use_bias=False, broadcast_dropout=False,
125
+ dropout_rate=self.dropout_rate, decode=self.decode, name="SelfAttn")(
126
+ x, decoder_mask, deterministic=deterministic))
127
+ x = wlc(nn.Dropout(rate=self.dropout_rate)(x, deterministic=deterministic))
128
+ x = wlc(x + targets)
129
+
130
+ if encoded is None:
131
+ y = x
132
+ else:
133
+ # Encoder-Decoder block.
134
+ y = wlc(nn.LayerNorm(name="LayerNorm2", use_bias=False)(x))
135
+ y = wlc(nn.MultiHeadDotProductAttention(
136
+ num_heads=self.num_heads, use_bias=False, broadcast_dropout=False,
137
+ dropout_rate=self.dropout_rate, name="CrossAttn")(
138
+ y, encoded, deterministic=deterministic))
139
+ y = wlc(
140
+ nn.Dropout(rate=self.dropout_rate)(y, deterministic=deterministic))
141
+ y = wlc(y + x)
142
+
143
+ # MLP block.
144
+ z = wlc(nn.LayerNorm(name="LayerNorm3", use_bias=False)(y))
145
+ z = wlc(vit.MlpBlock(mlp_dim=self.mlp_dim, dropout=self.dropout_rate,
146
+ name="MLP")(z, deterministic=deterministic))
147
+
148
+ # nn.scan requires a carry (second element in tuple)
149
+ out = wlc(y + z)
150
+ return out, out
151
+
152
+
153
+ class Decoder(nn.Module):
154
+ """Transformer decoder model with optional cross-attention."""
155
+ emb_dim: int
156
+ mlp_dim: int
157
+ num_heads: int
158
+ num_layers: int
159
+ out_dim: int
160
+ seq_len: int
161
+ style: Literal["ar", "masked"]
162
+ dropout_rate: float = 0.
163
+ zero_embedding_init: bool = False
164
+
165
+ scan: bool = False
166
+ remat_policy: str = "nothing_saveable"
167
+
168
+ @nn.compact
169
+ def __call__(
170
+ self,
171
+ targets: jax.Array,
172
+ encoded: jax.Array | None = None,
173
+ decoder_mask: jax.Array | None = None,
174
+ decode: bool = False,
175
+ deterministic: bool = True,
176
+ return_reps: bool = False,
177
+ ) -> jax.Array | tuple[jax.Array, Mapping[str, jax.Array]]:
178
+ """Applies Transformer model on the inputs.
179
+
180
+ Args:
181
+ targets: target text tokens [B, L].
182
+ encoded: encoded sequence from an encoder [B, P, E].
183
+ decoder_mask: decoder self-attention mask.
184
+ decode: bool, whether to perform fast autoregressive decoding with cache.
185
+ deterministic: bool, deterministic or not (to apply dropout).
186
+ return_reps: bool, whether to return intermediate representations.
187
+
188
+ Returns:
189
+ output of a transformer decoder [B, L, out_dim], where out_dim is usually
190
+ a multiple of D.
191
+ """
192
+ if self.style == "masked" and decode:
193
+ raise ValueError("Cannot run masked model in cached mode!")
194
+
195
+ pos_emb = vit.get_posemb(
196
+ self, "learn", self.seq_len, self.emb_dim,
197
+ "pos_emb")
198
+
199
+ y = common.AddPositionEmbs(
200
+ decode=decode, name="PosEmbedTargets")(targets, pos_emb)
201
+
202
+ out = {}
203
+ if self.scan:
204
+ # Mostly followed
205
+ # https://github.com/google/maxtext/blob/4d99e30b3e0e0cb1d1aa11c7db7fffe18e301498/MaxText/layers.py#L1126
206
+ # for the scanned version.
207
+
208
+ # 1. remat
209
+ enc_dec_block_remat = nn.remat(
210
+ EncoderDecoderBlock,
211
+ prevent_cse=False,
212
+ static_argnums=(-1, -2),
213
+ policy=getattr(jax.checkpoint_policies, self.remat_policy, None))
214
+ # 2. scan
215
+ initializing = self.is_mutable_collection("params")
216
+ param_scan_axis = 1
217
+ params_spec = (param_scan_axis if initializing
218
+ else partitioning.ScanIn(param_scan_axis))
219
+ dec_scanned = nn.scan(enc_dec_block_remat,
220
+ variable_axes={
221
+ "params": params_spec,
222
+ "cache": 0,
223
+ },
224
+ split_rngs={"params": True, "dropout": True},
225
+ in_axes=nn.broadcast,
226
+ length=self.num_layers)
227
+ # 3. fprop
228
+ y, out = dec_scanned(num_heads=self.num_heads, mlp_dim=self.mlp_dim,
229
+ dropout_rate=self.dropout_rate, decode=decode,
230
+ name="EncDecBlock")(
231
+ y, encoded, decoder_mask, deterministic)
232
+ # Extracting the intermediate representation from the stacked activation
233
+ # tensor `out`, which is a [num_layers, B, L, E] tensor. Indexing along
234
+ # the first axis to extract individual layers, and then averaging across
235
+ # the second axis, which corresponds to the sequence dimension after
236
+ # indexing.
237
+ assert out.shape[0] == self.num_layers and (
238
+ decode or out.shape[2] == self.seq_len), (
239
+ (out.shape, self.num_layers, self.seq_len))
240
+ out = {f"block{l}_rep": jnp.mean(out[l], axis=1)
241
+ for l in range(self.num_layers)}
242
+ else:
243
+ for lyr in range(self.num_layers):
244
+ y, _ = EncoderDecoderBlock(
245
+ num_heads=self.num_heads, mlp_dim=self.mlp_dim,
246
+ dropout_rate=self.dropout_rate, decode=decode,
247
+ name=f"EncDecBlock{lyr}")(y, encoded, decoder_mask=decoder_mask,
248
+ deterministic=deterministic)
249
+ out[f"block{lyr}_rep"] = jnp.mean(y, axis=1)
250
+ y = nn.LayerNorm(name="LayerNorm")(y)
251
+ out["pre_logits"] = jnp.mean(y, axis=1)
252
+
253
+ logits = nn.Dense(
254
+ self.out_dim,
255
+ kernel_init=nn.initializers.zeros,
256
+ name="LogitsDense",
257
+ )(y)
258
+ out["logits"] = logits
259
+ if return_reps:
260
+ return logits, out
261
+ return logits
262
+
263
+
264
+ class Model(nn.Module):
265
+ """GIVT model supporting decoder-only and encoder-decoder applications."""
266
+ num_heads: int = 8
267
+ # num_layers = 0 means no encoder
268
+ num_layers: int = 0
269
+ num_decoder_layers: int = 6
270
+ mlp_dim: int = 2048
271
+ enc_dropout_rate: float = 0.
272
+ dec_dropout_rate: float = 0.
273
+ # Decoder params:
274
+ emb_dim: int = 512
275
+ num_labels: Optional[int] = 1000
276
+ seq_len: int = 256
277
+ # Encoder params:
278
+ patches: Sequence[int] = (16, 16)
279
+ input_size: Sequence[int] = (256, 256)
280
+ posemb_type: Literal["learn", "sincos2d"] = "learn"
281
+ zero_decoder_seq: bool = False
282
+ style: Literal["ar", "masked"] = "ar"
283
+
284
+ zero_embedding_init: bool = False
285
+
286
+ num_mixtures: int = 4
287
+ multivariate: bool = False
288
+ out_dim: int = 32
289
+ scale_tol: float = 1e-6
290
+
291
+ # Mask specific params.
292
+ mask_schedule_train: str = "cosine"
293
+ # Results in at least 40% masked tokens with cosine.
294
+ min_masking_rate_training: float = 0.3
295
+
296
+ # How to fuse mask at input:
297
+ # - replace: replace token[masked] with lookup(MASK)
298
+ # - concat: replace token[mask] with lookup(REPLACE) and concat either
299
+ # lookup(NOMASK) or lookup(MASK).
300
+ mask_style: str = "replace"
301
+
302
+ # Set to >0 for CFG support.
303
+ drop_labels_probability: float = 0.0
304
+
305
+ fix_square_plus: bool = False
306
+
307
+ # If True, and mixture >1, create a GMM per channel. Otherwise, create
308
+ # a GMM of `dim`-dimensional Gaussians.
309
+ per_channel_mixtures: bool = True
310
+
311
+ scan: bool = False
312
+ remat_policy: str = "nothing_saveable"
313
+
314
+ @property
315
+ def has_encoder(self) -> bool:
316
+ return self.num_layers > 0
317
+
318
+ @property
319
+ def num_logits(self) -> int:
320
+ if self.multivariate:
321
+ assert self.num_mixtures == 1
322
+ # d**2 covariance, d means.
323
+ # Note: `round` makes pytype happy.
324
+ return round(self.out_dim ** 2) + self.out_dim
325
+
326
+ elif self.per_channel_mixtures:
327
+ # One (mu, sigma, pi) per output dimension and mixture component.
328
+ # Note that we predict a distribution for each output dimensions in
329
+ # parallel.
330
+ return 3 * self.num_mixtures * self.out_dim
331
+
332
+ else:
333
+ # Mixture weights plus mean/scale per mixture
334
+ return self.num_mixtures + 2 * self.num_mixtures * self.out_dim
335
+
336
+ def setup(self) -> None:
337
+ assert self.posemb_type == "learn"
338
+ assert self.num_mixtures > 0
339
+
340
+ if self.multivariate and self.num_mixtures != 1:
341
+ raise ValueError("Cannot do multivariate GMM!")
342
+
343
+ if self.num_layers > 0:
344
+ grid_size = np.array(self.input_size) // np.array(self.patches)
345
+
346
+ self.pos_emb_for_encoder = vit.get_posemb(
347
+ self, self.posemb_type, grid_size, self.emb_dim,
348
+ "pos_embedding_encoder")
349
+
350
+ self.conv = nn.Conv(self.emb_dim, self.patches, padding="VALID",
351
+ strides=self.patches, name="EmbedPatches")
352
+
353
+ self.encoder = vit.Encoder(
354
+ depth=self.num_layers,
355
+ mlp_dim=self.mlp_dim,
356
+ num_heads=self.num_heads,
357
+ dropout=self.enc_dropout_rate,
358
+ scan=self.scan,
359
+ remat_policy=self.remat_policy,)
360
+ else:
361
+ self.encoder = None
362
+
363
+ # Iterator that will lead free label IDs.
364
+ next_label = itertools.count(self.num_labels or 0)
365
+ special_labels = {}
366
+
367
+ if self.style == "ar":
368
+ pass
369
+ elif self.style == "masked":
370
+ if self.mask_style == "replace":
371
+ special_labels = {_SpecialLabel.MASK: next(next_label)}
372
+ elif self.mask_style == "concat":
373
+ special_labels = {
374
+ _SpecialLabel.MASK: next(next_label),
375
+ _SpecialLabel.NOMASK: next(next_label),
376
+ _SpecialLabel.REPLACE: next(next_label),
377
+ }
378
+ else:
379
+ raise NotImplementedError(self.mask_style)
380
+ else:
381
+ raise NotImplementedError(self.style)
382
+
383
+ if self.drop_labels_probability > 0:
384
+ special_labels[_SpecialLabel.NOLABEL] = next(next_label)
385
+
386
+ self.special_labels = special_labels
387
+ lookup_size = (self.num_labels or 1) + len(self.special_labels)
388
+
389
+ self.labels_emb = nn.Embed(
390
+ lookup_size,
391
+ self.emb_dim,
392
+ name="EmbedLabels",
393
+ embedding_init=nn.initializers.zeros
394
+ if self.zero_embedding_init
395
+ else nn.initializers.normal(stddev=1.0),
396
+ )
397
+
398
+ self.targets_emb = nn.Dense(self.emb_dim, name="EmbedTargets")
399
+
400
+ self.decoder = Decoder(
401
+ num_layers=self.num_decoder_layers or self.num_layers,
402
+ mlp_dim=self.mlp_dim,
403
+ num_heads=self.num_heads,
404
+ out_dim=self.num_logits,
405
+ # In masked mode, we run with 1 more token at the input.
406
+ seq_len=self.seq_len + int(self.style == "masked"),
407
+ dropout_rate=self.dec_dropout_rate,
408
+ emb_dim=self.emb_dim,
409
+ zero_embedding_init=self.zero_embedding_init,
410
+ style=self.style,
411
+ scan=self.scan,
412
+ remat_policy=self.remat_policy,
413
+ )
414
+
415
+ def encode(self, image: jax.Array, train: bool = False) -> jax.Array:
416
+ """Encodes input image or embeddings."""
417
+ emb = self.conv(image)
418
+ patch_embeddings = einops.rearrange(emb, "B PH PW E -> B (PH PW) E")
419
+ encoded, _ = self.encoder(
420
+ patch_embeddings + self.pos_emb_for_encoder, deterministic=not train)
421
+ return encoded
422
+
423
+ def embed_labels(
424
+ self,
425
+ labels: jax.Array | None = None,
426
+ batch_size: int | None = None,
427
+ ) -> jax.Array:
428
+ if labels is not None:
429
+ # Embed class label, add a sequence dim (output shape (B, 1, E))
430
+ return self.labels_emb(labels)[:, None, :]
431
+
432
+ assert ((self.num_labels == 1 or self.num_labels is None)
433
+ and batch_size is not None)
434
+ # Create [BOS] token embedding
435
+ return self.labels_emb(jnp.zeros((batch_size,), jnp.int32))[:, None, :]
436
+
437
+ def prefill(
438
+ self, labels=None, batch_size=None, encoded=None, drop_labels=None
439
+ ):
440
+ labels = self._drop_labels(drop_labels, labels)
441
+ labels_for_prefill = self.embed_labels(labels=labels, batch_size=batch_size)
442
+ return self.decoder(
443
+ labels_for_prefill,
444
+ encoded=encoded,
445
+ decode=True)
446
+
447
+ def _decode_ar(
448
+ self,
449
+ targets: jax.Array,
450
+ labels: jax.Array | None = None,
451
+ encoded: jax.Array | None = None,
452
+ decode: bool = False,
453
+ train: bool = False,
454
+ ) -> tuple[jax.Array, Mapping[str, jax.Array]]:
455
+ """Autoregressive decoding."""
456
+ targets_embedded = self.targets_emb(targets)
457
+
458
+ if decode:
459
+ decoder_mask = None
460
+ else:
461
+ decoder_mask = nn.make_causal_mask(targets[:, :, 0])
462
+ b = targets.shape[0]
463
+ labels_embedded = self.embed_labels(labels, b)
464
+ assert labels_embedded.shape == (b, 1, self.emb_dim), (
465
+ labels_embedded.shape, (b, 1, self.emb_dim))
466
+ targets_embedded = jnp.concatenate(
467
+ [labels_embedded, targets_embedded[:, : -1]], axis=1)
468
+
469
+ logits, out = self.decoder(
470
+ targets_embedded,
471
+ encoded=encoded,
472
+ decoder_mask=decoder_mask,
473
+ decode=decode,
474
+ deterministic=not train,
475
+ return_reps=True)
476
+
477
+ return logits, out
478
+
479
+ def _get_special_label(self, size, label: _SpecialLabel):
480
+ return self.labels_emb(
481
+ jnp.full(size, self.special_labels[label], jnp.int32)
482
+ )
483
+
484
+ def _decode_masked(
485
+ self,
486
+ targets,
487
+ input_mask,
488
+ labels=None,
489
+ encoded=None,
490
+ train=False,
491
+ ):
492
+ """Masked decoding."""
493
+ b, s, _ = targets.shape
494
+ assert input_mask.shape == (b, s)
495
+
496
+ if self.mask_style == "replace":
497
+ targets_embedded = jnp.where(
498
+ input_mask[:, :, None],
499
+ self._get_special_label((b, s), _SpecialLabel.MASK),
500
+ self.targets_emb(targets),
501
+ )
502
+ elif self.mask_style == "concat":
503
+ masks = jnp.where(
504
+ input_mask[:, :, None],
505
+ self._get_special_label((b, s), _SpecialLabel.MASK),
506
+ self._get_special_label((b, s), _SpecialLabel.NOMASK),
507
+ )
508
+ embedded_targets = self.targets_emb(targets)
509
+ targets_embedded = jnp.where(
510
+ input_mask[:, :, None],
511
+ self._get_special_label((b, s), _SpecialLabel.REPLACE),
512
+ embedded_targets,
513
+ )
514
+ # Only take half of each to get the right embedding size.
515
+ targets_embedded = jnp.concatenate(
516
+ [masks[..., ::2], targets_embedded[..., ::2]], axis=-1
517
+ )
518
+ else:
519
+ raise ValueError(self.mask_style)
520
+
521
+ labels_embedded = self.embed_labels(labels, b)
522
+ assert labels_embedded.shape == (b, 1, self.emb_dim)
523
+ # Note that we do not truncate the input here, so this has shape
524
+ # (B, L+1, E).
525
+ targets_embedded = jnp.concatenate(
526
+ [labels_embedded, targets_embedded], axis=1)
527
+
528
+ logits = self.decoder(
529
+ targets_embedded,
530
+ encoded=encoded,
531
+ decoder_mask=None,
532
+ decode=False,
533
+ deterministic=not train)
534
+
535
+ logits = logits[:, 1:, ...] # Remove class label
536
+ assert logits.shape[:2] == (b, s)
537
+ return logits
538
+
539
+ def _drop_labels(self, drop_labels_mask, labels):
540
+ if labels is None:
541
+ return None
542
+ if self.drop_labels_probability >= 0.999:
543
+ logging.warning("Dropping all labels...")
544
+ return jnp.full_like(labels, self.special_labels[_SpecialLabel.NOLABEL])
545
+ if drop_labels_mask is None:
546
+ return labels
547
+ assert _SpecialLabel.NOLABEL in self.special_labels
548
+ nolabel = jnp.full_like(
549
+ labels, self.special_labels[_SpecialLabel.NOLABEL]
550
+ )
551
+ return jnp.where(drop_labels_mask, nolabel, labels)
552
+
553
+ def decode(
554
+ self,
555
+ targets: jax.Array,
556
+ labels: jax.Array | None = None,
557
+ encoded: jax.Array | None = None,
558
+ decode: bool = False,
559
+ train: bool = False,
560
+ max_decode_length: int | None = None,
561
+ input_mask: jax.Array | None = None,
562
+ drop_labels: jax.Array | None = None,
563
+ return_reps: bool = False,
564
+ ) -> jax.Array | tuple[jax.Array, Mapping[str, jax.Array]]:
565
+ """Applies Transformer decoder-branch on encoded-input and target.
566
+
567
+ Args:
568
+ targets: target text tokens [B, L, out_dim].
569
+ labels: optional class labes, [B].
570
+ encoded: encoded image patches from encoder [B, P, E].
571
+ decode: whether to prepare and use an autoregressive cache.
572
+ train: whether it is training.
573
+ max_decode_length: optional max length for positional embeddings.
574
+ input_mask: If given, mask input. Required for style=="masked".
575
+ Shape [B, L], bool tensor. True means the token will be removed
576
+ from the input.
577
+ drop_labels: Drop labels at corresponding locations [B].
578
+ return_reps: whether to return intermediate representations.
579
+
580
+ Returns:
581
+ logits array from transformer decoder [B, L, 3 * num_mixtures * out_dim].
582
+ """
583
+ del max_decode_length
584
+ labels = self._drop_labels(drop_labels, labels)
585
+ if self.style == "ar":
586
+ logits, out = self._decode_ar(
587
+ targets, labels, encoded, decode, train)
588
+ if return_reps:
589
+ return logits, out
590
+ return logits
591
+ elif self.style == "masked":
592
+ assert not decode # Cache not supported.
593
+ assert input_mask is not None
594
+ assert not return_reps # Not implemented.
595
+ return self._decode_masked(targets, input_mask, labels, encoded, train)
596
+ else:
597
+ raise NotImplementedError(self.style)
598
+
599
+ def _square_plus(self, x):
600
+ # Via https://twitter.com/jon_barron/status/1387167648669048833
601
+ if self.fix_square_plus:
602
+ return (x + jnp.sqrt(jnp.square(x) + 4)) / 2
603
+ else:
604
+ return x + jnp.sqrt(jnp.square(x) + 4) / 2
605
+
606
+ def get_pdf(
607
+ self,
608
+ logits: jax.Array,
609
+ temperature_scales: float | None = None,
610
+ temperature_probs: float | None = None,
611
+ ) -> distrax.Distribution:
612
+ assert logits.shape[-1] == self.num_logits
613
+ if self.multivariate:
614
+ scales = logits[..., :self.out_dim ** 2]
615
+ locs = logits[..., self.out_dim ** 2:]
616
+ assert locs.shape[-1] == self.out_dim
617
+ scales = self._square_plus(scales)
618
+ # Turn into a square matrix.
619
+ *leading, _ = scales.shape
620
+ scales = scales.reshape(*leading, self.out_dim, self.out_dim)
621
+ # Make sure the diagonals are non zero.
622
+ diag_scale_tol = jnp.eye(self.out_dim) * self.scale_tol
623
+ scales = jnp.maximum(scales, diag_scale_tol)
624
+ if (t := temperature_scales) is not None:
625
+ scales = scales * t
626
+
627
+ # Note that there is `tfd.MultivariateNormalFullCovariance`` but it just
628
+ # calls linalg.cholesky on the covariance and then uses the
629
+ # MultivariateNormalTri class. Using ... direcly avoids having to
630
+ # construct a hermetian matrix.
631
+ #
632
+ # Note that only the lower triag part of `scales` is used by applying
633
+ # jnp.tril. The other elements are replaced with zeros.
634
+ #
635
+ # Note on output shapes:
636
+ # - .sample() -> shape (..., seq_len, out_dim)
637
+ # - .prob() -> shape (..., seq_len).
638
+ return distrax.MultivariateNormalTri(locs, scales)
639
+
640
+ elif self.per_channel_mixtures:
641
+ # [..., 3 * num_mixtures * out_dim] -> [..., 3 * out_dim, num_mixtures]
642
+ logits = jnp.reshape(logits, logits.shape[: -1] + (-1, self.num_mixtures))
643
+ # 3 tensors with shape [..., out_dim, num_mixtures]
644
+ probs, locs, scales = jnp.split(logits, 3, axis=-2)
645
+ if (t := temperature_probs) is not None:
646
+ probs = probs * t
647
+
648
+ # normalize mixture probabilities
649
+ probs = nn.softmax(probs)
650
+ scales = self._square_plus(scales)
651
+ # threshold scale
652
+ scales = jnp.maximum(scales, self.scale_tol)
653
+ if (t := temperature_scales) is not None:
654
+ scales = scales * t
655
+
656
+ # Note on output shapes:
657
+ # - .sample() -> shape (..., seq_len, out_dim)
658
+ # - .prob() -> shape (..., seq_len, out_dim).
659
+ return distrax.MixtureSameFamily(
660
+ mixture_distribution=distrax.Categorical(probs=probs),
661
+ components_distribution=distrax.Normal(loc=locs, scale=scales),
662
+ )
663
+ else:
664
+ *shape, num_logits = logits.shape
665
+ assert num_logits == self.num_logits, (num_logits, self.num_logits)
666
+ prob_logits, other_logits = (
667
+ logits[..., : self.num_mixtures],
668
+ logits[..., self.num_mixtures :],
669
+ )
670
+ if (t := temperature_probs) is not None:
671
+ prob_logits = prob_logits * t
672
+ other_logits = jnp.reshape(
673
+ other_logits, (*shape, self.num_mixtures, 2, self.out_dim)
674
+ )
675
+ locs = other_logits[..., 0, :]
676
+ scales = self._square_plus(other_logits[..., 1, :])
677
+
678
+ scales = jnp.maximum(scales, self.scale_tol) # Threshold scale
679
+ if (t := temperature_scales) is not None:
680
+ scales = scales * t
681
+
682
+ # prob_logits has shape (b, seq_len, m)
683
+ # locs/scales has shape (b, seq_len, m, d)
684
+ assert prob_logits.ndim == locs.ndim - 1, (prob_logits.shape, locs.shape)
685
+ assert locs.shape == scales.shape, (locs.shape, scales.shape)
686
+
687
+ # Note on output shapes:
688
+ # - .sample() -> shape (..., seq_len, out_dim)
689
+ # - .prob() -> shape (..., seq_len,)
690
+ # - .nll() -> shape (..., seq_len,)
691
+ return distrax.MixtureSameFamily(
692
+ mixture_distribution=distrax.Categorical(logits=prob_logits),
693
+ components_distribution=distrax.MultivariateNormalDiag(
694
+ loc=locs, scale_diag=scales
695
+ ),
696
+ )
697
+
698
+ def __call__(
699
+ self,
700
+ sequence: jax.Array,
701
+ labels: jax.Array | None = None,
702
+ *,
703
+ image: jax.Array | None = None,
704
+ decode: bool = False,
705
+ input_mask: jax.Array | None = None,
706
+ drop_labels: jax.Array | None = None,
707
+ train: bool = False,
708
+ ) -> tuple[jax.Array, distrax.Distribution]:
709
+ """Applies Transformer model on the inputs.
710
+
711
+ Args:
712
+ sequence: batch of sequences [B, L].
713
+ labels: class labels for class conditional generation [B].
714
+ image: batch of images [B, H, W, 3].
715
+ decode: whether to prepare and use an autoregressive cache.
716
+ input_mask: If given, mask input. Required for style=="masked" [B, L].
717
+ drop_labels: If given, drop labels of the corresponding batches [B].
718
+ train: whether it is training.
719
+
720
+ Returns:
721
+ logits array from full transformer [B, L, out_dim].
722
+ """
723
+ if self.style == "masked" and input_mask is None:
724
+ raise ValueError("Cannot run masked model without input mask!")
725
+
726
+ if self.encoder is not None:
727
+ assert image is not None
728
+ encoded = self.encode(image, train=train)
729
+ else:
730
+ assert image is None
731
+ encoded = None
732
+
733
+ logits = self.decode(sequence, labels=labels, encoded=encoded,
734
+ decode=decode, input_mask=input_mask, train=train)
735
+ pdf = self.get_pdf(logits)
736
+ return logits, pdf
737
+
738
+ def get_input_mask_training(
739
+ self,
740
+ rng: jax.Array,
741
+ shape: tuple[int, int],
742
+ ) -> jax.Array | None:
743
+ """Creates a random maask of shape (B, L) for training masked models."""
744
+ if self.style == "ar":
745
+ return None
746
+ b, s = shape
747
+ # Sample b values in [0, 1-min_mask_ratio].
748
+ keep = jax.random.uniform(
749
+ rng, shape=(b,), maxval=1.0 - self.min_masking_rate_training
750
+ )
751
+ mask_ratio = apply_mask_schedule(keep, self.mask_schedule_train)
752
+ return _random_mask_with_ratios(rng, ratios=mask_ratio, seq_len=s)
753
+
754
+ def get_input_mask_teacher_forced(
755
+ self,
756
+ shape: tuple[int, int],
757
+ ) -> jax.Array | None:
758
+ """Creates a random maask of shape (B, L) for training masked models."""
759
+ if self.style == "ar":
760
+ return None
761
+ return jnp.zeros(shape, dtype=jnp.bool_)
762
+
763
+ def get_drop_labels(
764
+ self,
765
+ rng: jax.Array,
766
+ batch_size: int,
767
+ ) -> jax.Array | None:
768
+ if (p := self.drop_labels_probability) > 0:
769
+ return jax.random.uniform(rng, shape=(batch_size,)) <= p
770
+ else:
771
+ return None
772
+
773
+
774
+ def load(
775
+ init_params: Any,
776
+ init_files: str | Mapping[str, str],
777
+ model_params: Any = None,
778
+ dont_load: Sequence[str] = (),
779
+ resample_encoder_posemb: bool = False,
780
+ trim_decoder_posemb: bool = False,
781
+ ) -> Any:
782
+ """Loads params from init checkpoint and merges into init_params."""
783
+ del model_params
784
+ if isinstance(init_files, str):
785
+ ckpt_params = utils.load_params(init_files)
786
+ ckpt_params = common.merge_params(ckpt_params, init_params, dont_load)
787
+
788
+ if resample_encoder_posemb:
789
+ if init_params and "pos_embedding_encoder" in init_params:
790
+ ckpt_params["pos_embedding_encoder"] = vit.resample_posemb(
791
+ old=ckpt_params["pos_embedding_encoder"],
792
+ new=init_params["pos_embedding_encoder"])
793
+
794
+ if trim_decoder_posemb:
795
+ if init_params and "pos_embedding_decoder" in init_params:
796
+ ckpt_params["pos_embedding_decoder"] = (
797
+ ckpt_params["pos_embedding_decoder"][
798
+ :, :init_params["pos_embedding_decoder"].shape[1], :])
799
+
800
+ else:
801
+ init_files = {**init_files} # Shallow copy because we'll pop stuff off.
802
+
803
+ enc_init = init_files.pop("encoder", None)
804
+ if enc_init:
805
+ ckpt_params = init_params.copy()
806
+ vit_params = {
807
+ "pos_embedding": ckpt_params["pos_embedding_encoder"],
808
+ "Transformer": ckpt_params["encoder"],
809
+ "embedding": ckpt_params["EmbedPatches"],
810
+ }
811
+ encoder_params = vit.load(
812
+ vit_params, enc_init, model_cfg={},
813
+ dont_load=dont_load)
814
+ ckpt_params["encoder"] = encoder_params["Transformer"]
815
+ ckpt_params["pos_embedding_encoder"] = encoder_params["pos_embedding"]
816
+ ckpt_params["EmbedPatches"] = encoder_params["embedding"]
817
+ else:
818
+ raise ValueError("Only encoder init is supported: {}.".format(init_files))
819
+
820
+ return ckpt_params
Tipsomaly/model/big_vision/models/proj/givt/givt_test.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Tests for GIVT model."""
16
+
17
+ from absl.testing import parameterized
18
+ from big_vision.models.proj.givt import givt
19
+ import jax
20
+ import jax.numpy as jnp
21
+ import numpy as np
22
+
23
+ from absl.testing import absltest
24
+
25
+
26
+ _BATCH_SIZE = 2
27
+ _OUT_DIM = 4
28
+ _SEQ_LEN = 16
29
+ _NUM_MIXTURES = 4
30
+
31
+
32
+ def _make_test_model(**overwrites):
33
+ config = dict(
34
+ num_heads=2,
35
+ num_decoder_layers=1,
36
+ mlp_dim=64,
37
+ emb_dim=16,
38
+ seq_len=_SEQ_LEN,
39
+ out_dim=_OUT_DIM,
40
+ num_mixtures=_NUM_MIXTURES,
41
+ )
42
+ config.update(overwrites)
43
+ return givt.Model(**config)
44
+
45
+
46
+ class MaskedTransformerTest(parameterized.TestCase):
47
+
48
+ @parameterized.product(rng_seed=[0])
49
+ def test_masks(self, rng_seed):
50
+ m = _make_test_model(style="masked")
51
+ mask = m.get_input_mask_training(jax.random.PRNGKey(rng_seed), (2, 16))
52
+ self.assertEqual(mask.shape, (2, 16))
53
+ # At least one should definitly be masked out.
54
+ self.assertTrue(np.all(mask.sum(-1) > 1))
55
+
56
+ @parameterized.product(
57
+ train=[True, False],
58
+ multivariate=[True, False],
59
+ per_channel_mixtures=[True, False],
60
+ drop_labels_probability=[0.0, 0.1],
61
+ style=["masked", "ar"],
62
+ )
63
+ def test_apply(
64
+ self,
65
+ train,
66
+ multivariate,
67
+ per_channel_mixtures,
68
+ drop_labels_probability,
69
+ style,
70
+ ):
71
+ if per_channel_mixtures and multivariate:
72
+ self.skipTest("Not supported")
73
+ model = _make_test_model(
74
+ style=style,
75
+ multivariate=multivariate,
76
+ num_mixtures=1 if multivariate else _NUM_MIXTURES,
77
+ per_channel_mixtures=per_channel_mixtures,
78
+ drop_labels_probability=drop_labels_probability,
79
+ )
80
+ sequence = jax.random.uniform(
81
+ jax.random.PRNGKey(0), (_BATCH_SIZE, _SEQ_LEN, _OUT_DIM)
82
+ )
83
+ labels = jax.random.uniform(
84
+ jax.random.PRNGKey(0), (_BATCH_SIZE,), maxval=10
85
+ ).astype(jnp.int32)
86
+ input_mask = jax.random.uniform(
87
+ jax.random.PRNGKey(0), (_BATCH_SIZE, _SEQ_LEN)
88
+ ).astype(jnp.bool_)
89
+ variables = model.init(
90
+ jax.random.PRNGKey(0),
91
+ sequence,
92
+ labels,
93
+ input_mask=input_mask,
94
+ train=train,
95
+ )
96
+ logits, pdf = model.apply(
97
+ variables, sequence, labels, input_mask=input_mask, train=train
98
+ )
99
+ nll = -pdf.log_prob(sequence)
100
+ self.assertFalse(np.any(np.isnan(nll)))
101
+ if multivariate:
102
+ self.assertEqual(
103
+ logits.shape, (_BATCH_SIZE, _SEQ_LEN, _OUT_DIM**2 + _OUT_DIM)
104
+ )
105
+ self.assertEqual(nll.shape, (_BATCH_SIZE, _SEQ_LEN))
106
+ elif per_channel_mixtures:
107
+ self.assertEqual(
108
+ logits.shape,
109
+ (_BATCH_SIZE, _SEQ_LEN, 3 * _NUM_MIXTURES * _OUT_DIM),
110
+ )
111
+ self.assertEqual(nll.shape, (_BATCH_SIZE, _SEQ_LEN, _OUT_DIM))
112
+ else:
113
+ self.assertEqual(
114
+ logits.shape,
115
+ (_BATCH_SIZE, _SEQ_LEN, _NUM_MIXTURES + _NUM_MIXTURES * _OUT_DIM * 2),
116
+ )
117
+ self.assertEqual(nll.shape, (_BATCH_SIZE, _SEQ_LEN))
118
+
119
+ sample = pdf.sample(seed=jax.random.PRNGKey(0))
120
+ self.assertEqual(sample.shape, (_BATCH_SIZE, _SEQ_LEN, _OUT_DIM))
121
+
122
+
123
+ if __name__ == "__main__":
124
+ googletest.main()
Tipsomaly/model/big_vision/models/proj/givt/parallel_decode.py ADDED
@@ -0,0 +1,523 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Decode autoregressive/bidirectional masked transformers.
16
+
17
+
18
+ Currently, we implement MaskGIT style temperature sampling:
19
+
20
+ In each step:
21
+ 1. Get P = model(inputs), predicted GMMs
22
+ 2. Get samples = sample_from(P)
23
+ 3. Get probs = P[samples], ie, model evaluated at samples.
24
+ We use this now as a confidence metric, but we scale the probs:
25
+ 4. probs = probs ^ 1/choice_temperature
26
+ 4. set probs[already_uncovered_points] = inf, ie, we will always keep
27
+ uncovered points (no resampling!)
28
+ 5. Now pick top K points from probs to keep for the next steps, where
29
+ K = some monotonically increasing ratio of points as we go along decoding
30
+ """
31
+
32
+ import dataclasses
33
+ from typing import Literal
34
+
35
+ from absl import logging
36
+ from big_vision.models.proj.givt import givt
37
+ import distrax
38
+ import flax
39
+ import jax
40
+ import jax.numpy as jnp
41
+
42
+
43
+ _CONFIDENCE_OF_KNOWN_TOKENS = jnp.inf
44
+
45
+
46
+ @jax.vmap
47
+ def _get_per_batch_mask(arr, k):
48
+ (d,) = arr.shape
49
+ indices = jnp.argsort(arr)
50
+ valid_indices = jnp.arange(d) < k
51
+ return jnp.zeros((d,), jnp.bool_).at[indices].set(valid_indices)
52
+
53
+
54
+ def _get_bottom_k_mask(arr, k):
55
+ *leading, d = arr.shape
56
+ arr = arr.reshape((-1, d))
57
+ mask = _get_per_batch_mask(arr, k)
58
+ return mask.reshape(*leading, -1)
59
+
60
+
61
+ def mask_by_random_topk(rng, mask_len, probs, temperature=1.0):
62
+ """Create a mask.
63
+
64
+ Adaption of jax.random.choice where probabilities are changed by scaling with
65
+ `temperature` (probs = probs ^ (1/temperature)).
66
+
67
+ Additionally, this function returns a mask of tokens to mask out, which
68
+ are picked to be the low confidence ones. Thus, this function is roughly
69
+ equivalent to (but not exactly at edge cases such as prob = inf..):
70
+
71
+ keep = jax.random.choice(
72
+ rng, seq_len,
73
+ shape=(seq_len - mask_len,),
74
+ # NOTE: probabilities are updated with `temperature`.
75
+ p=jnp.power(probs, 1/temperature),
76
+ replace=False
77
+ )
78
+ mask = jnp.ones((seq_len,), dtype=jnp.bool_)
79
+ return mask.at[..., keep].set(False)
80
+
81
+ Args:
82
+ rng: a PRNG key used as the random key.
83
+ mask_len: the number to mask.
84
+ probs: the probabilities associated with each entry.
85
+ temperature: when temperature = 1.0, it's identical to jax's implementation.
86
+ The larger this value is, the more random the masking is picked.
87
+
88
+ Returns:
89
+ A binary masking map [batch_size, seq_len]. Contains True where we should
90
+ mask (at mask_len locations), and False where we should keep.
91
+ """
92
+ confidence = jnp.log(probs) + temperature * jax.random.gumbel(
93
+ rng, probs.shape)
94
+ return _get_bottom_k_mask(confidence, mask_len)
95
+
96
+
97
+ @flax.struct.dataclass
98
+ class DecodeState:
99
+ """Holds decoding state data."""
100
+
101
+ rng: jax.Array # Sampling random state.
102
+ # The position of the decoding loop in the length dimension. Scalar int32.
103
+ step: jax.Array
104
+ # What we input at each step. Starts from all masks and is uncovered by
105
+ # sampling. Note that this is an array with leading
106
+ # dimension `num_steps + 1` because we start with all masked tokens and then
107
+ # need `num_steps` to uncover all, i.e., the final output is given by
108
+ # all_inputs_q[-1, ...].
109
+ all_inputs_q: jax.Array # float32 [num_steps + 1, batch, seq_len, c]
110
+ # Has a 1 for every _uncovered_ point.
111
+ uncovered_per_step: jax.Array # bool_ [num_steps, batch, seq_len]
112
+ logits_per_step: jax.Array # [num_steps, batch, seq_len, num_logits]
113
+ uncond_logits_per_step: jax.Array # [num_steps, batch, seq_len, num_logits]
114
+ prob_per_step: jax.Array # Probability per step.
115
+ # If CFG: Rejection sampling success rate.
116
+ rejection_sampling_success_per_step: jax.Array
117
+
118
+ @classmethod
119
+ def make(
120
+ cls,
121
+ initial_rng: jax.Array,
122
+ all_masked_input: jax.Array,
123
+ num_logits: int,
124
+ num_steps: int,
125
+ ) -> "DecodeState":
126
+ """Creates the initial state."""
127
+ b, seq_len, c = all_masked_input.shape
128
+ all_inputs_q = jnp.broadcast_to(
129
+ all_masked_input,
130
+ (num_steps + 1, b, seq_len, c),
131
+ )
132
+ return cls(
133
+ initial_rng,
134
+ step=jnp.array(0),
135
+ all_inputs_q=all_inputs_q,
136
+ uncovered_per_step=jnp.full((num_steps, b, seq_len), False, jnp.bool_),
137
+ logits_per_step=jnp.full(
138
+ (num_steps, b, seq_len, num_logits), jnp.nan, jnp.float32
139
+ ),
140
+ uncond_logits_per_step=jnp.full(
141
+ (num_steps, b, seq_len, num_logits), jnp.nan, jnp.float32
142
+ ),
143
+ prob_per_step=jnp.full((num_steps, b, seq_len), jnp.nan, jnp.float32),
144
+ rejection_sampling_success_per_step=jnp.full(
145
+ (num_steps,), jnp.nan, jnp.float32
146
+ ),
147
+ )
148
+
149
+ @property
150
+ def current_inputs_q(self) -> jax.Array:
151
+ """Returns the current quantized input."""
152
+ return self.all_inputs_q[self.step, ...]
153
+
154
+ @property
155
+ def num_steps(self) -> int:
156
+ """Returns number of decode steps."""
157
+ return self.uncovered_per_step.shape[0]
158
+
159
+ def _steps_mask(self) -> jax.Array:
160
+ return jnp.arange(self.num_steps) <= self.step
161
+
162
+ @property
163
+ def total_uncovered(self) -> jax.Array:
164
+ """Returns the total uncovered mask up to and including current step."""
165
+ return self.uncovered_per_step.sum(
166
+ axis=0, where=self._steps_mask()[:, jnp.newaxis, jnp.newaxis]
167
+ ).astype(jnp.bool_)
168
+
169
+ def split_rng(self) -> tuple["DecodeState", jax.Array]:
170
+ """Splits of RNG for the current step."""
171
+ rng, step_rng = jax.random.split(self.rng, 2)
172
+ return self.replace(rng=rng), step_rng
173
+
174
+ def set_next_input(self, next_input_q: jax.Array) -> "DecodeState":
175
+ """Sets the input for the next step."""
176
+ return self._set_row("all_inputs_q", self.step + 1, next_input_q)
177
+
178
+ def set_uncover_at_current_step(self, uncovered: jax.Array) -> "DecodeState":
179
+ """Sets what was uncovered after the current step."""
180
+ return self._set_row("uncovered_per_step", self.step, uncovered)
181
+
182
+ def set_logits_at_current_step(self, logits: jax.Array) -> "DecodeState":
183
+ return self._set_row("logits_per_step", self.step, logits)
184
+
185
+ def set_uncond_logits_at_current_step(
186
+ self, logits: jax.Array
187
+ ) -> "DecodeState":
188
+ return self._set_row("uncond_logits_per_step", self.step, logits)
189
+
190
+ def set_rejection_sampling_success_at_current_step(
191
+ self, success: jax.Array
192
+ ) -> "DecodeState":
193
+ return self._set_row(
194
+ "rejection_sampling_success_per_step", self.step, success
195
+ )
196
+
197
+ def set_prob_at_current_step(self, prob: jax.Array) -> "DecodeState":
198
+ return self._set_row("prob_per_step", self.step, prob)
199
+
200
+ def increment_step(self) -> "DecodeState":
201
+ """Increments step."""
202
+ return self.replace(step=self.step + 1)
203
+
204
+ def _set_row(self, attr_name, row_index, row_value):
205
+ """Sets one row of the variables that have shape (num_steps, ...)."""
206
+ current_value = getattr(self, attr_name)
207
+ _, *expected_shape = current_value.shape
208
+ if row_value.shape != tuple(expected_shape):
209
+ raise ValueError(f"Expected {row_value.shape} == {expected_shape}!")
210
+ if row_value.dtype != current_value.dtype:
211
+ raise ValueError(f"Expected {row_value.dtype} == {current_value.dtype}")
212
+ new_value = current_value.at[row_index, ...].set(row_value)
213
+ return self.replace(**{attr_name: new_value})
214
+
215
+
216
+ @dataclasses.dataclass(frozen=True)
217
+ class MaskedGenerationConfig:
218
+ """Config for masked generation.
219
+
220
+ Attributes:
221
+ num_steps: Number of sampling steps.
222
+ should_anneal_temperature: If given, anneal choice temperature as we go
223
+ through the sampling steps.
224
+ choice_temperature: Temperature for picking points.
225
+ ordering: How to order to select. Supports:
226
+ maskgit: Maskgit style, use P[samples]
227
+ schedule: Inference mask schedule.
228
+ cfg_inference_weight: CFG Inference weight.
229
+ """
230
+ num_steps: int = 16
231
+ should_anneal_temperature: bool = True
232
+ choice_temperature: float = 1.0
233
+ ordering: Literal["maskgit"] = "maskgit"
234
+ schedule: str = "cosine"
235
+ cfg_inference_weight: float = 0.0
236
+
237
+
238
+ def _assert_single_component_get_loc_scale(
239
+ pdf: distrax.Distribution, rng=None, mixture=None
240
+ ):
241
+ """Extracts loc and scale from a single mixture GMM."""
242
+ if not isinstance(pdf, distrax.MixtureSameFamily):
243
+ raise ValueError(f"Expected mixture! Got {type(pdf)}")
244
+ components_d = pdf.components_distribution
245
+ if isinstance(components_d, distrax.MultivariateNormalDiag):
246
+ loc, scale_diag = components_d.loc, components_d.scale_diag
247
+ b, s, m, _ = loc.shape
248
+ if mixture is None:
249
+ assert rng is not None
250
+ # Shape (b, seq)
251
+ mixture = pdf.mixture_distribution.sample(seed=rng)
252
+ mixture = jax.nn.one_hot(mixture, num_classes=m, axis=-1)
253
+ assert mixture.shape == (b, s, m), (mixture.shape, loc.shape)
254
+ loc = (loc * mixture[..., None]).sum(-2)
255
+ scale_diag = (scale_diag * mixture[..., None]).sum(-2)
256
+ return loc, scale_diag, mixture
257
+ else:
258
+ loc, scale = components_d.loc, components_d.scale
259
+ if loc.shape[-1] != 1 or scale.shape[-1] != 1:
260
+ raise ValueError(f"Expected one mixture! {loc.shape}/{scale.shape}")
261
+ return loc[..., 0], scale[..., 0], None
262
+
263
+
264
+ class CFGDensity:
265
+ """Helper to get probability and samples via CFG."""
266
+
267
+ pdf_c: distrax.Distribution
268
+ pdf_u: distrax.Distribution
269
+ w: float
270
+ simple: distrax.Distribution
271
+ fac: jax.Array
272
+
273
+ def __init__(
274
+ self,
275
+ pdf_c: distrax.Distribution,
276
+ pdf_u: distrax.Distribution,
277
+ w: float,
278
+ rng: jax.Array,
279
+ ) -> None:
280
+ loc_c, scale_c, mixture = _assert_single_component_get_loc_scale(pdf_c, rng)
281
+ # Note: RNG only needed when we have mixtures, to select components.
282
+ loc_u, scale_u, _ = _assert_single_component_get_loc_scale(
283
+ pdf_u, rng, mixture=mixture
284
+ )
285
+
286
+ # Definitly wider than whatever we had before. The mean should be slightly
287
+ # away though!
288
+ loc_simple = loc_c
289
+ scale_simple = jnp.stack([scale_c, scale_u], -1).max(-1) * 2
290
+ self.simple = distrax.Normal(loc_simple, scale_simple)
291
+
292
+ self.pdf_c = distrax.Normal(loc_c, scale_c)
293
+ self.pdf_u = distrax.Normal(loc_u, scale_u)
294
+ self.w = w
295
+
296
+ assert loc_c.ndim == 3, loc_c.shape
297
+ points = loc_c[jnp.newaxis, ...] + jnp.linspace(-10, 10, 1001).reshape(
298
+ -1, 1, 1, 1
299
+ )
300
+ p_at_c, _ = self._unnormalized_p(points)
301
+
302
+ self.fac = jnp.max(p_at_c / self.simple.prob(loc_c), axis=0)
303
+ jax.debug.print("🎲 CFG {fac}", fac=self.fac.mean())
304
+
305
+ def _unnormalized_p(self, x):
306
+ w = self.w
307
+ logp_cfg = (1 + w) * self.pdf_c.log_prob(x) - w * self.pdf_u.log_prob(x)
308
+ return jnp.exp(logp_cfg), logp_cfg
309
+
310
+ def rejection_sample(
311
+ self,
312
+ seed: jax.Array,
313
+ max_samples: int = 1_000,
314
+ ) -> tuple[jax.Array, jax.Array]:
315
+ """Rejection sampling, try `max_samples`, take first match."""
316
+ rng_sample, rng_uni = jax.random.split(seed, 2)
317
+ # Shape (max_samples, b, seq_len, c)
318
+ xs = self.simple.sample(seed=rng_sample, sample_shape=(max_samples,))
319
+ facq = self.fac * self.simple.prob(xs)
320
+ ys = jax.random.uniform(rng_uni, shape=facq.shape, minval=0.0, maxval=facq)
321
+ # Shape (max_samples, b, seq_len, c), True where `xs` is a valid sample
322
+ # from p. We might have anywhere between 0 and `max_samples` valid samples!
323
+ p, _ = self._unnormalized_p(xs)
324
+ mask = ys < p
325
+ # Now we need to do fancy tricks to get the first element in `mask` that is
326
+ # True. We do this by making a shifted mask that is False for every element
327
+ # after the first True.
328
+ # > Example:
329
+ # mask [0, 1, 0, 1, 0, 0, 1, 0]
330
+ # > implies:
331
+ # cmask [0, 1, 1, 1, 1, 1, 1, 1]
332
+ # shifted_cmask [0, 0, 1, 1, 1, 1, 1, 1]
333
+ # keep [0, 1, 0, 0, 0, 0, 0, 0] # <- picks the first valid!
334
+ cmask = jnp.cumsum(mask, axis=0).astype(jnp.bool_)
335
+ shifted_cmask = jnp.pad(
336
+ cmask, [(1, 0), (0, 0), (0, 0), (0, 0)], constant_values=False
337
+ )[:-1]
338
+ assert shifted_cmask.shape == mask.shape
339
+ keep = jnp.logical_and(cmask, jnp.logical_not(shifted_cmask))
340
+ # Now we can grab the first valid sample by doing a sum over the
341
+ # `max_samples` dimension.
342
+ sample = jnp.where(keep, xs, 0).sum(0)
343
+ # If the rejection sampler fails, we fall back to the conditional
344
+ # distribution.
345
+ ok = mask.sum(0) > 0 # Shape (b, seq_len, c)
346
+ # jax.debug.print("🎲 CFG ok {ok}%", ok=ok.mean() * 100)
347
+ sample = jnp.where(
348
+ ok, sample, self.pdf_c.sample(seed=rng_sample)
349
+ )
350
+ return sample, ok.mean() * 100
351
+
352
+ def sample(
353
+ self,
354
+ seed: jax.Array,
355
+ max_samples: int = 1_000,
356
+ ) -> jax.Array:
357
+ result, ok = self.rejection_sample(seed, max_samples)
358
+ jax.debug.print("Debug ok={ok}%", ok=ok)
359
+ return result
360
+
361
+ # Unnormalized! But we only use it for ordering.
362
+ def prob(self, xs: jax.Array) -> jax.Array:
363
+ p, _ = self._unnormalized_p(xs)
364
+ return p
365
+
366
+ def log_prob(self, xs: jax.Array) -> jax.Array:
367
+ _, lp = self._unnormalized_p(xs)
368
+ return lp
369
+
370
+
371
+ def decode_masked(
372
+ rng: jax.Array,
373
+ labels: jax.Array,
374
+ seq_len: int,
375
+ feature_dim: int,
376
+ model: givt.Model,
377
+ variables: flax.core.FrozenDict,
378
+ config: MaskedGenerationConfig,
379
+ ) -> DecodeState:
380
+ """Implements an masked bidirectional sampling loop.
381
+
382
+ This function implements the loop from the docstring.
383
+
384
+ Args:
385
+ rng: RNG, only required if sampling.
386
+ labels: Shape (b,), labels per batch. Determines batch size.
387
+ seq_len: How many tokens to sample per batch.
388
+ feature_dim: Output dimension of the VAE, i.e., number of channels, `c`.
389
+ model: GIVT model to sample from.
390
+ variables: Variables of the model.
391
+ config: Configures style.
392
+
393
+ Returns:
394
+ Final state.
395
+ """
396
+ logging.info("Masked Generation Config:\n%s", config)
397
+
398
+ if model.style != "masked":
399
+ raise ValueError(f"Need masked model! Got `{model.style}`.")
400
+
401
+ (b,) = labels.shape
402
+ all_masked_input = jnp.zeros((b, seq_len, feature_dim))
403
+ init_state = DecodeState.make(
404
+ rng,
405
+ all_masked_input,
406
+ num_logits=model.num_logits,
407
+ num_steps=config.num_steps,
408
+ )
409
+
410
+ def loop_cond_fn(state: DecodeState):
411
+ return state.step < state.num_steps
412
+
413
+ def tokens_to_logits(tokens, input_mask, drop_labels=None):
414
+ return model.apply(
415
+ variables,
416
+ tokens,
417
+ labels=labels,
418
+ # Note that the model applies the mask token internally given the input.
419
+ input_mask=input_mask,
420
+ drop_labels=drop_labels,
421
+ method="decode",
422
+ )
423
+
424
+ def loop_body_fn(state: DecodeState) -> DecodeState:
425
+ # 1 where we should mask, cumulative.
426
+ unknown = jnp.logical_not(state.total_uncovered)
427
+
428
+ # Defines the mask ratio for the next round. The number to mask out is
429
+ # determined by mask_ratio * unknown_number_in_the_beginning.
430
+ ratio = (state.step + 1) / config.num_steps
431
+ # Note that the mask schedule inverts the function, so `mask_ratio` givts
432
+ # near 1 and goes to 0 monotonically.
433
+ mask_ratio = givt.apply_mask_schedule(ratio, method=config.schedule)
434
+ mask_len = jnp.floor(seq_len * mask_ratio).reshape(1, 1)
435
+ num_unknown = jnp.sum(unknown, axis=-1, keepdims=True)
436
+ mask_len = jnp.maximum(
437
+ 0,
438
+ # Keeps at least one of prediction in this round: Avoids the case where
439
+ # mask_len is equal to num_unknown, in which case the mask is not
440
+ # updated! We substract 1 to always remove at least one masked token.
441
+ jnp.minimum(num_unknown - 1, mask_len))
442
+
443
+ # Run model ---
444
+ logits = tokens_to_logits(state.current_inputs_q, unknown)
445
+ # Book keeping: store all logits.
446
+ state = state.set_logits_at_current_step(logits)
447
+
448
+ pdf = model.get_pdf(logits)
449
+ state, sample_rng = state.split_rng()
450
+ if config.cfg_inference_weight > 0:
451
+ drop_all_labels = jnp.full((b,), True, jnp.bool_)
452
+ logits_uncond = tokens_to_logits(
453
+ state.current_inputs_q, unknown, drop_labels=drop_all_labels
454
+ )
455
+ state = state.set_uncond_logits_at_current_step(logits_uncond)
456
+ pdf_uncond = model.get_pdf(logits_uncond)
457
+ state, cfg_rng = state.split_rng()
458
+ pdf = CFGDensity(
459
+ pdf_c=pdf,
460
+ pdf_u=pdf_uncond,
461
+ w=config.cfg_inference_weight,
462
+ rng=cfg_rng,
463
+ )
464
+ sample, rejection_sampling_success = pdf.rejection_sample(sample_rng)
465
+ state = state.set_rejection_sampling_success_at_current_step(
466
+ rejection_sampling_success
467
+ )
468
+ else:
469
+ sample = pdf.sample(seed=sample_rng)
470
+
471
+ # Sample at the unknown spots.
472
+ sampled = jnp.where(unknown[:, :, None], sample, state.current_inputs_q)
473
+ assert sampled.shape == (b, seq_len, feature_dim), (
474
+ sampled.shape,
475
+ b,
476
+ seq_len,
477
+ feature_dim,
478
+ )
479
+
480
+ prob = pdf.prob(sampled)
481
+ if model.multivariate:
482
+ assert prob.ndim == 2 # (b, seq_len) already
483
+ elif model.per_channel_mixtures or config.cfg_inference_weight > 0:
484
+ # Independence accross channels.
485
+ # This reduction is also required when using CFG and also
486
+ # `model.per_channel_mixtures == False` due to the 2-step CFG redefining
487
+ # the pdf, but the reduction is not needed without CFG.
488
+ prob = prob.prod(-1)
489
+ state = state.set_prob_at_current_step(prob)
490
+
491
+ if config.ordering == "maskgit":
492
+ ordering = jnp.where(unknown, prob, _CONFIDENCE_OF_KNOWN_TOKENS)
493
+ else:
494
+ raise NotImplementedError(config.ordering)
495
+
496
+ assert ordering.shape == (b, seq_len), (ordering.shape, b, seq_len)
497
+
498
+ temp = config.choice_temperature
499
+ if config.should_anneal_temperature:
500
+ temp *= (1. - ratio)
501
+
502
+ # True where we should mask input. Note that this is cumulative (ie this
503
+ # starts with all True and keeps getting more False entries as we go through
504
+ # the steps).
505
+ state, choice_rng = state.split_rng()
506
+ masking = mask_by_random_topk(choice_rng, mask_len, ordering, temp)
507
+ assert masking.shape == (b, seq_len)
508
+ masking = jnp.where(mask_len == 0, jnp.zeros_like(masking), masking)
509
+
510
+ # Remove the masked tokens from the sampled array for safety (the model will
511
+ # again apply the mask anyway...).
512
+ sampled = jnp.where(masking[:, :, None], jnp.zeros_like(sampled), sampled)
513
+
514
+ # Get next_uncover ---
515
+ # New tokens to uncover (non cumulative): where it was unknown
516
+ # but is now known.
517
+ next_uncover = jnp.logical_and(unknown, jnp.logical_not(masking))
518
+ assert next_uncover.shape == (b, seq_len), (next_uncover.shape, b, seq_len)
519
+ state = state.set_uncover_at_current_step(next_uncover)
520
+ state = state.set_next_input(sampled)
521
+ return state.increment_step()
522
+
523
+ return jax.lax.while_loop(loop_cond_fn, loop_body_fn, init_state)
Tipsomaly/model/big_vision/models/proj/givt/parallel_decode_test.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
+ from absl.testing import parameterized
16
+ from big_vision.models.proj.givt import givt
17
+ from big_vision.models.proj.givt import parallel_decode
18
+ import chex
19
+ import jax
20
+ import jax.numpy as jnp
21
+
22
+ from absl.testing import absltest
23
+
24
+
25
+ _BATCH_SIZE = 2
26
+ _OUT_DIM = 4
27
+ _SEQ_LEN = 6
28
+ _NUM_MIXTURES = 4
29
+
30
+
31
+ def _make_test_model(**overwrites):
32
+ config = dict(
33
+ num_heads=2,
34
+ num_decoder_layers=1,
35
+ mlp_dim=64,
36
+ emb_dim=16,
37
+ seq_len=_SEQ_LEN,
38
+ out_dim=_OUT_DIM,
39
+ num_mixtures=_NUM_MIXTURES,
40
+ style="masked",
41
+ )
42
+ config.update(overwrites)
43
+ return givt.Model(**config)
44
+
45
+
46
+ def _mask(*flags):
47
+ return jnp.asarray(flags).astype(jnp.bool_)
48
+
49
+
50
+ class HelperTest(googletest.TestCase):
51
+
52
+ def test_get_first_n(self):
53
+ with self.subTest("ordered"):
54
+ values = jnp.asarray([4, 3, 2, 1, 0])
55
+ k = jnp.asarray([3], jnp.int32)
56
+ chex.assert_trees_all_equal(
57
+ parallel_decode._get_bottom_k_mask(values, k), _mask(0, 0, 1, 1, 1)
58
+ )
59
+
60
+ with self.subTest("equal_values"):
61
+ values = jnp.ones((5,))
62
+ k = jnp.asarray([3], jnp.int32)
63
+ chex.assert_trees_all_equal(
64
+ parallel_decode._get_bottom_k_mask(values, k), _mask(1, 1, 1, 0, 0)
65
+ )
66
+
67
+ with self.subTest("equal_values"):
68
+ values = jnp.asarray([1, 2, 2, 2, 3])
69
+ k = jnp.asarray([3], jnp.int32)
70
+ chex.assert_trees_all_equal(
71
+ parallel_decode._get_bottom_k_mask(values, k), _mask(1, 1, 1, 0, 0)
72
+ )
73
+
74
+
75
+ class ParallelDecodeTest(parameterized.TestCase):
76
+
77
+ def _make_model(self, **overwrites):
78
+ model = _make_test_model(**overwrites)
79
+ sequence = jax.random.uniform(
80
+ jax.random.PRNGKey(0), (_BATCH_SIZE, _SEQ_LEN, _OUT_DIM)
81
+ )
82
+ labels = jax.random.uniform(
83
+ jax.random.PRNGKey(0), (_BATCH_SIZE,), maxval=10
84
+ ).astype(jnp.int32)
85
+ input_mask = jax.random.uniform(
86
+ jax.random.PRNGKey(0), (_BATCH_SIZE, _SEQ_LEN)
87
+ ).astype(jnp.bool_)
88
+ variables = model.init(
89
+ jax.random.PRNGKey(0),
90
+ sequence,
91
+ labels,
92
+ input_mask=input_mask,
93
+ train=False,
94
+ )
95
+ return model, variables
96
+
97
+ def _test_model(self, rng, model, variables, config):
98
+ labels = jnp.ones((_BATCH_SIZE,), dtype=jnp.int32)
99
+ state = parallel_decode.decode_masked(
100
+ rng,
101
+ seq_len=_SEQ_LEN,
102
+ feature_dim=_OUT_DIM,
103
+ labels=labels,
104
+ model=model,
105
+ variables=variables,
106
+ config=config,
107
+ )
108
+ self.assertEqual(int(state.step), 4)
109
+ # Each point uncovered exactly once.
110
+ chex.assert_trees_all_equal(
111
+ state.uncovered_per_step.sum(0),
112
+ jnp.ones((_BATCH_SIZE, _SEQ_LEN), dtype=jnp.int32),
113
+ )
114
+
115
+ @parameterized.product(
116
+ rng_seed=[1, 2],
117
+ choice_temperature=[1.0, 4.0],
118
+ multivariate=[True, False],
119
+ )
120
+ def test_decode_masked(self, rng_seed, choice_temperature, multivariate):
121
+ rng = jax.random.PRNGKey(rng_seed)
122
+ model, variables = self._make_model(
123
+ num_mixtures=1 if multivariate else _NUM_MIXTURES,
124
+ multivariate=multivariate,
125
+ )
126
+ config = parallel_decode.MaskedGenerationConfig(
127
+ num_steps=4,
128
+ choice_temperature=choice_temperature,
129
+ )
130
+ self._test_model(rng, model, variables, config)
131
+
132
+ @parameterized.product(
133
+ rng_seed=[1, 2],
134
+ choice_temperature=[1.0, 4.0],
135
+ w=[0.0, 1.0, 3.0],
136
+ per_channel_mixtures=[True, False],
137
+ )
138
+ def test_cfg(self, rng_seed, choice_temperature, w, per_channel_mixtures):
139
+ rng = jax.random.PRNGKey(rng_seed)
140
+ model, variables = self._make_model(
141
+ num_mixtures=1 if per_channel_mixtures else 3,
142
+ drop_labels_probability=0.1,
143
+ per_channel_mixtures=per_channel_mixtures,
144
+ )
145
+ config = parallel_decode.MaskedGenerationConfig(
146
+ num_steps=4,
147
+ choice_temperature=choice_temperature,
148
+ cfg_inference_weight=w,
149
+ )
150
+ self._test_model(rng, model, variables, config)
151
+
152
+
153
+ if __name__ == "__main__":
154
+ googletest.main()
Tipsomaly/model/big_vision/models/proj/givt/vae.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Abstract VAE model class.
16
+
17
+ Gaussian encoder and decoder (the latter assumed to have constant variance).
18
+
19
+ Inspiration drawn from https://github.com/pytorch/examples/tree/main/vae.
20
+ """
21
+
22
+ import abc
23
+ from typing import Optional, Mapping
24
+
25
+
26
+ import flax.linen as nn
27
+ import jax
28
+ import jax.numpy as jnp
29
+
30
+
31
+ class Model(nn.Module, metaclass=abc.ABCMeta):
32
+ """Abstract VAE model class."""
33
+
34
+ codeword_dim: Optional[int] = None
35
+ code_len: int = 256
36
+ code_dropout: str = "none"
37
+
38
+ @abc.abstractmethod
39
+ def encode(
40
+ self,
41
+ x: jax.Array,
42
+ *,
43
+ train: bool = False,
44
+ ) -> tuple[jax.Array, jax.Array]:
45
+ ...
46
+
47
+ def reparametrize(
48
+ self,
49
+ mu: jax.Array,
50
+ logvar: jax.Array,
51
+ rng: jax.Array | None = None,
52
+ ) -> jax.Array:
53
+ std = jnp.exp(0.5 * logvar)
54
+ if rng is None:
55
+ rng = self.make_rng("dropout")
56
+ eps = jax.random.normal(rng, shape=std.shape, dtype=std.dtype)
57
+ return mu + std * eps
58
+
59
+ @abc.abstractmethod
60
+ def decode(
61
+ self, x: jax.Array,
62
+ train: bool = False,
63
+ ) -> jax.Array | Mapping[str, jax.Array]:
64
+ ...
65
+
66
+ def code_dropout_fn(self, z: jax.Array, *, train: bool = False) -> jax.Array:
67
+ # "seq" drops out tokens later in the sequence with higher probablility than
68
+ # tokens earlier in the sequence.
69
+ assert self.code_dropout in ["none", "seq", "random"]
70
+ if train and self.code_dropout != "none":
71
+ importance = jnp.linspace(1.0, 0.0, self.code_len + 2)[1:-1]
72
+ thr = jax.random.uniform(self.make_rng("dropout"), z.shape[:1])
73
+ mask = importance[None, :] > thr[:, None]
74
+ if self.code_dropout == "random":
75
+ mask = jax.random.permutation(
76
+ self.make_rng("dropout"), mask, axis=-1, independent=True)
77
+ z = z * mask[:, :, None]
78
+ return z
79
+
80
+ def __call__(
81
+ self,
82
+ x: jax.Array,
83
+ *,
84
+ train: bool = False,
85
+ ) -> tuple[jax.Array | Mapping[str, jax.Array], Mapping[str, jax.Array]]:
86
+ mu, logvar = self.encode(x, train=train)
87
+ # Only reparametrize when training for simplicity.
88
+ if train:
89
+ z = self.reparametrize(mu, logvar)
90
+ else:
91
+ z = mu
92
+ z = self.code_dropout_fn(z, train=train)
93
+ x = self.decode(z, train=train)
94
+ return x, {"mu": mu, "logvar": logvar, "z": z}
Tipsomaly/model/big_vision/models/proj/givt/vit.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Simple VAE fork of the UViM VQ-VAE (proj/uvim/vit.py) with small changes."""
16
+
17
+ from typing import Optional, Sequence, Mapping, Any
18
+
19
+ from big_vision import utils
20
+ from big_vision.models import common
21
+ from big_vision.models import vit
22
+ from big_vision.models.proj.givt import vae
23
+
24
+ import einops
25
+ import flax.linen as nn
26
+ import flax.training.checkpoints
27
+ import jax
28
+ import jax.numpy as jnp
29
+ import numpy as np
30
+
31
+
32
+ class Model(vae.Model):
33
+ """ViT model."""
34
+
35
+ input_size: Sequence[int] = (256, 256)
36
+ patch_size: Sequence[int] = (16, 16)
37
+ width: int = 768
38
+ enc_depth: int = 6
39
+ dec_depth: int = 6
40
+ mlp_dim: Optional[int] = None
41
+ num_heads: int = 12
42
+ posemb: str = "learn" # Can also be "sincos2d"
43
+ dropout: float = 0.0
44
+ head_zeroinit: bool = True
45
+ bottleneck_resize: bool = False
46
+ inout_specs: Optional[Mapping[str, tuple[int, int]]] = None
47
+ scan: bool = False
48
+ remat_policy: str = "nothing_saveable"
49
+
50
+ def setup(self) -> None:
51
+ self.grid_size = np.array(self.input_size) // np.array(self.patch_size)
52
+
53
+ self.embedding = nn.Conv(
54
+ self.width, self.patch_size, strides=self.patch_size,
55
+ padding="VALID", name="embedding")
56
+
57
+ self.pos_embedding_encoder = vit.get_posemb(
58
+ self, self.posemb, self.grid_size, self.width, "pos_embedding_encoder")
59
+ self.encoder = vit.Encoder(
60
+ depth=self.enc_depth,
61
+ mlp_dim=self.mlp_dim,
62
+ num_heads=self.num_heads,
63
+ dropout=self.dropout,
64
+ scan=self.scan,
65
+ remat_policy=self.remat_policy,
66
+ name="encoder")
67
+
68
+ if not self.bottleneck_resize:
69
+ self.bottleneck_downsample = self.param(
70
+ "bottleneck_downsample",
71
+ nn.initializers.xavier_uniform(),
72
+ (np.prod(self.grid_size), self.code_len))
73
+
74
+ if not self.bottleneck_resize:
75
+ self.bottleneck_upsample = self.param(
76
+ "bottleneck_upsample",
77
+ nn.initializers.xavier_uniform(),
78
+ (self.code_len, np.prod(self.grid_size)))
79
+
80
+ self.pos_embedding_decoder = vit.get_posemb(
81
+ self, self.posemb, self.grid_size, self.width, "pos_embedding_decoder")
82
+ self.decoder = vit.Encoder(
83
+ depth=self.dec_depth,
84
+ mlp_dim=self.mlp_dim,
85
+ num_heads=self.num_heads,
86
+ dropout=self.dropout,
87
+ scan=self.scan,
88
+ remat_policy=self.remat_policy,
89
+ name="decoder")
90
+
91
+ # Setting num_outputs to 2 * codeword_dim to predict mean and variance per
92
+ # element
93
+ self.encoder_head = nn.Dense(self.codeword_dim * 2 or self.width * 2)
94
+ self.decoder_stem = nn.Dense(self.width)
95
+
96
+ kw = {"kernel_init": nn.initializers.zeros} if self.head_zeroinit else {}
97
+
98
+ if self.inout_specs is not None:
99
+ num_out_channels = sum(
100
+ num_classes for _, num_classes in self.inout_specs.values())
101
+ else:
102
+ num_out_channels = 3
103
+
104
+ self.head = nn.Dense(
105
+ num_out_channels * np.prod(self.patch_size),
106
+ name="decoder_head", **kw)
107
+
108
+ def encode(
109
+ self,
110
+ x: jax.Array,
111
+ *,
112
+ train: bool = False,
113
+ ) -> tuple[jax.Array, jax.Array]:
114
+ if self.inout_specs is not None:
115
+ one_hot_inputs = []
116
+ for in_ch, num_classes in self.inout_specs.values():
117
+ one_hot_inputs.append(nn.one_hot(x[..., in_ch], num_classes))
118
+ x = jnp.concatenate(one_hot_inputs, axis=-1)
119
+ x = self.embedding(x)
120
+ x = einops.rearrange(x, "b h w c -> b (h w) c")
121
+
122
+ x, _ = self.encoder(x + self.pos_embedding_encoder, deterministic=not train)
123
+
124
+ if self.bottleneck_resize:
125
+ x = einops.rearrange(x, "b (h w) c -> b h w c",
126
+ h=self.grid_size[0], w=self.grid_size[1])
127
+ l = int(np.round(self.code_len ** 0.5))
128
+ x = jax.image.resize(
129
+ x, (x.shape[0], l, l, x.shape[3]),
130
+ method="linear")
131
+ x = einops.rearrange(x, "b h w c -> b (h w) c")
132
+ else:
133
+ x = jnp.einsum("btc,tn->bnc", x, self.bottleneck_downsample)
134
+
135
+ x = self.encoder_head(x)
136
+
137
+ mu, logvar = jnp.split(x, 2, axis=-1)
138
+ return mu, logvar
139
+
140
+ def decode(
141
+ self,
142
+ x: jax.Array,
143
+ train: bool = False,
144
+ ) -> jax.Array | Mapping[str, jax.Array]:
145
+ x = self.decoder_stem(x)
146
+
147
+ if self.bottleneck_resize:
148
+ l = int(np.round(self.code_len ** 0.5))
149
+ x = einops.rearrange(x, "b (h w) c -> b h w c", h=l, w=l)
150
+ x = jax.image.resize(
151
+ x, (x.shape[0], self.grid_size[0], self.grid_size[1], x.shape[3]),
152
+ method="linear")
153
+ x = einops.rearrange(x, "b h w c -> b (h w) c")
154
+ else:
155
+ x = jnp.einsum("bnc,nt->btc", x, self.bottleneck_upsample)
156
+
157
+ x, _ = self.decoder(x + self.pos_embedding_decoder, deterministic=not train)
158
+ x = self.head(x)
159
+ # c = 3 for RGB images
160
+ x = einops.rearrange(x, "b (h w) (p q c) -> b (h p) (w q) c",
161
+ h=self.grid_size[0], w=self.grid_size[1],
162
+ p=self.patch_size[0], q=self.patch_size[1])
163
+
164
+ if self.inout_specs is None:
165
+ x = jnp.clip(x, -1.0, 1.0)
166
+ else:
167
+ x_dict = {}
168
+ channel_index = 0
169
+ for name, (_, num_channels) in self.inout_specs.items():
170
+ x_dict[name] = x[..., channel_index : channel_index + num_channels]
171
+ channel_index += num_channels
172
+ x = x_dict
173
+
174
+ return x
175
+
176
+
177
+ def load(
178
+ init_params: Any,
179
+ init_file: str,
180
+ model_params: Any = None,
181
+ dont_load: Sequence[str] = (),
182
+ ) -> Any:
183
+ """Loads params from init checkpoint and merges into init_params."""
184
+ del model_params
185
+ params = flax.core.unfreeze(utils.load_params(init_file))
186
+ if init_params is not None:
187
+ params = common.merge_params(params, init_params, dont_load)
188
+ return params
Tipsomaly/model/big_vision/models/proj/image_text/naflex_vit.py ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ViT = NaViT + FlexiViT.
16
+
17
+ Based on:
18
+ * FlexiViT: https://arxiv.org/abs/2212.08013
19
+ * NaViT: https://arxiv.org/abs/2307.06304
20
+ """
21
+
22
+ import re
23
+ from big_vision.models import vit
24
+ import big_vision.models.proj.image_text.utils as it_utils
25
+ import flax.linen as nn
26
+ import jax
27
+ import jax.numpy as jnp
28
+ import numpy as np
29
+
30
+
31
+ def _decode_posemb(posemb):
32
+ if (m := re.fullmatch(r"learn_2d(\(\d+\))", posemb)):
33
+ grid_size = int(m.groups()[0][1:-1])
34
+ return "learn_2d", grid_size
35
+ return posemb, None
36
+
37
+
38
+ def _pos_emb_resize(pos_emb, shapes, coords, l):
39
+ """Resizes the positional embeddings to match the input image size.
40
+
41
+ Args:
42
+ pos_emb: Positional embeddings.
43
+ shapes: Image shapes (usually `coords.max(axis=1) + 1`).
44
+ coords: Patch coordinates.
45
+ l: Maximum number of patches per side. Necesary in order to have a static
46
+ return shape.
47
+
48
+ Setting l to 64 is a heuristic. Ideally, we would use
49
+ `l = tokens.shape[1]` here, but that requires too much memory,
50
+ especially for high-resolution inputs. Using a lower value
51
+ effectively limits the maximum resolution to `l x patch_size`.
52
+ Resolutions above that will lead to NaNs in the positional
53
+ embeddings and NaN model outputs.
54
+ Note: this value can be adjusted post-hoc without retraining.
55
+
56
+ Returns:
57
+ Postional embeddings for every patch.
58
+ """
59
+
60
+ def resize_fn(shape, coords):
61
+ emb = jax.image.scale_and_translate(
62
+ pos_emb,
63
+ shape=(l, l, pos_emb.shape[-1]),
64
+ spatial_dims=(0, 1),
65
+ scale=shape / jnp.asarray(pos_emb.shape[:2]),
66
+ translation=jnp.asarray([0, 0]),
67
+ method="bilinear", antialias=True)
68
+ gather_dim = jax.lax.GatherDimensionNumbers(
69
+ offset_dims=(1,),
70
+ collapsed_slice_dims=(0, 1),
71
+ start_index_map=(0, 1, 2)
72
+ )
73
+ return jax.lax.gather(
74
+ emb,
75
+ jnp.pad(coords, [[0, 0], [0, 1]]),
76
+ gather_dim,
77
+ [1, 1, emb.shape[-1]],
78
+ mode="fill")
79
+ return it_utils.batch_shmap(
80
+ jax.vmap(resize_fn, in_axes=(0, 0), out_axes=0),
81
+ shapes, coords)
82
+
83
+
84
+ class Encoder1DBlock(nn.Module):
85
+ """Single transformer encoder block (MHSA + MLP)."""
86
+ mlp_dim: int | None = None # Defaults to 4x input dim
87
+ num_heads: int = 12
88
+ dropout: float = 0.0
89
+ dtype_mm: str = "float32"
90
+
91
+ @nn.compact
92
+ def __call__(self, x, mask=None, deterministic=True):
93
+ if mask is not None:
94
+ mask = mask[..., None, :, :] # Broadcast mask along the head dim.
95
+
96
+ out = {}
97
+ x = nn.with_logical_constraint(x, ("act_batch", "act_len", "act_emb"))
98
+ y = nn.LayerNorm()(x)
99
+ y = out["sa"] = nn.MultiHeadDotProductAttention(
100
+ num_heads=self.num_heads,
101
+ kernel_init=nn.initializers.xavier_uniform(),
102
+ deterministic=deterministic,
103
+ dtype=self.dtype_mm,
104
+ )(y, y, mask=mask)
105
+ y = nn.with_logical_constraint(y, ("act_batch", "act_len", "act_emb"))
106
+ y = nn.Dropout(rate=self.dropout)(y, deterministic)
107
+ x = out["+sa"] = x + y
108
+
109
+ y = nn.LayerNorm()(x)
110
+ y = out["mlp"] = vit.MlpBlock(
111
+ mlp_dim=self.mlp_dim, dropout=self.dropout,
112
+ dtype_mm=self.dtype_mm,
113
+ )(y, deterministic)
114
+ y = nn.with_logical_constraint(y, ("act_batch", "act_len", "act_emb"))
115
+ y = nn.Dropout(rate=self.dropout)(y, deterministic)
116
+ x = out["+mlp"] = x + y
117
+ x = nn.with_logical_constraint(x, ("act_batch", "act_len", "act_emb"))
118
+ return x, out
119
+
120
+
121
+ class Encoder(nn.Module):
122
+ """Transformer Model Encoder for sequence to sequence translation."""
123
+ depth: int
124
+ mlp_dim: int | None = None # Defaults to 4x input dim
125
+ num_heads: int = 12
126
+ dropout: float = 0.0
127
+ scan: bool = False
128
+ remat_policy: str = "nothing_saveable"
129
+ dtype_mm: str = "float32"
130
+
131
+ @nn.compact
132
+ def __call__(self, x, mask=None, deterministic=True):
133
+ out = {}
134
+
135
+ if self.scan:
136
+ block = nn.remat(
137
+ Encoder1DBlock,
138
+ prevent_cse=False,
139
+ static_argnums=(3,), # 0=self, 3=deterministic
140
+ policy=getattr(jax.checkpoint_policies, self.remat_policy, None),
141
+ )
142
+ x, scan_out = nn.scan(
143
+ block,
144
+ variable_axes={"params": 0},
145
+ split_rngs={"params": True, "dropout": True},
146
+ in_axes=nn.broadcast,
147
+ length=self.depth)(
148
+ name="encoderblock",
149
+ dtype_mm=self.dtype_mm,
150
+ mlp_dim=self.mlp_dim,
151
+ num_heads=self.num_heads,
152
+ dropout=self.dropout)(x, mask, deterministic)
153
+ for lyr in range(self.depth):
154
+ out[f"block{lyr:02d}"] = jax.tree.map(lambda o, l=lyr: o[l], scan_out)
155
+ else:
156
+ # Input Encoder
157
+ for lyr in range(self.depth):
158
+ block_cur = Encoder1DBlock(
159
+ name=f"encoderblock_{lyr}",
160
+ dtype_mm=self.dtype_mm,
161
+ mlp_dim=self.mlp_dim, num_heads=self.num_heads,
162
+ dropout=self.dropout)
163
+ x, out[f"block{lyr:02d}"] = block_cur(x, mask, deterministic)
164
+ out["pre_ln"] = x # Alias for last block, but without the number in it.
165
+
166
+ return nn.LayerNorm(name="encoder_norm")(x), out
167
+
168
+
169
+ class MAPHead(nn.Module):
170
+ """Multihead Attention Pooling."""
171
+ mlp_dim: int | None = None # Defaults to 4x input dim
172
+ num_heads: int = 12
173
+
174
+ @nn.compact
175
+ def __call__(self, x, mask=None):
176
+ n, l, d = x.shape # pylint: disable=unused-variable
177
+ probe = self.param("probe", nn.initializers.xavier_uniform(),
178
+ (1, 1, d), x.dtype)
179
+ probe = jnp.tile(probe, [n, 1, 1])
180
+
181
+ if mask is not None:
182
+ mask = mask[..., None, None, :] # Add query and head dims.
183
+
184
+ x = nn.MultiHeadDotProductAttention(
185
+ num_heads=self.num_heads,
186
+ kernel_init=nn.initializers.xavier_uniform())(probe, x, mask=mask)
187
+
188
+ y = nn.LayerNorm()(x)
189
+ x = x + vit.MlpBlock(mlp_dim=self.mlp_dim)(y)
190
+ return x[:, 0]
191
+
192
+
193
+ class _Model(nn.Module):
194
+ """ViT model."""
195
+
196
+ num_classes: int | None = None
197
+ width: int = 768
198
+ depth: int = 12
199
+ mlp_dim: int | None = None # Defaults to 4x input dim
200
+ num_heads: int = 12
201
+ rep_size: int | bool = False
202
+ pool_type: str = "gap" # Can also be "map" or "tok"
203
+ head_zeroinit: bool = True
204
+ scan: bool = False
205
+ # or "dots_with_no_batch_dims_saveable" for more speed (memory costly)
206
+ remat_policy: str = "nothing_saveable"
207
+ dtype_mm: str = "float32"
208
+
209
+ posemb: str = "learn_2d(64)"
210
+ nposemb: int | None = None # Needs to be overwritten
211
+
212
+ patchln_pre: bool = False
213
+ patchln_post: bool = False
214
+
215
+ @nn.compact
216
+ def __call__(self, image, *, train=False):
217
+ out = {}
218
+
219
+ patches, ptype, yabs, xabs = image
220
+ patches = jnp.asarray(patches, self.dtype_mm) # BN(hw3) of float32
221
+
222
+ if self.patchln_pre:
223
+ patches = nn.LayerNorm(name="patchln_pre")(patches)
224
+
225
+ # Embed the patches.
226
+ tokens = out["stem"] = nn.Dense(
227
+ self.width, name="embedding", dtype=self.dtype_mm)(patches)
228
+
229
+ if self.patchln_post:
230
+ tokens = nn.LayerNorm(name="patchln_post")(tokens)
231
+
232
+ x = tokens
233
+ posemb, posemb_grid_size = _decode_posemb(self.posemb)
234
+ if posemb == "learn_2d":
235
+ posembs = self.param(
236
+ "pos_embedding",
237
+ nn.initializers.normal(stddev=1/np.sqrt(self.width)),
238
+ (self.nposemb, self.nposemb, self.width), self.dtype_mm)
239
+ coords = jnp.stack([yabs, xabs], axis=-1)
240
+ shapes = coords.max(axis=1) + 1
241
+ # See comment in `_pos_emb_resize` for details.
242
+ x += _pos_emb_resize(posembs, shapes, coords, posemb_grid_size or 64)
243
+ else:
244
+ raise ValueError(f"Unknown posemb: '{self.posemb}'")
245
+
246
+ out["with_posemb"] = x
247
+
248
+ # Only use patch tokens in self-attention:
249
+ sa_mask = ptype == 1 # 1 == patch (pad is 0).
250
+ sa_mask = jnp.logical_and(sa_mask[..., :, None], sa_mask[..., None, :])
251
+ x, out["encoder"] = Encoder(
252
+ depth=self.depth,
253
+ mlp_dim=self.mlp_dim,
254
+ num_heads=self.num_heads,
255
+ scan=self.scan,
256
+ remat_policy=self.remat_policy,
257
+ dtype_mm=self.dtype_mm,
258
+ name="Transformer")(
259
+ x, mask=sa_mask, deterministic=not train)
260
+ out["encoded"] = x
261
+
262
+ # Ignore the padding tokens when pooling:
263
+ pool_mask = (ptype == 1) # 1 == patch (not pad)
264
+ if self.pool_type == "map":
265
+ maphead = MAPHead(num_heads=self.num_heads, mlp_dim=self.mlp_dim)
266
+ x = maphead(x, mask=pool_mask)
267
+ elif self.pool_type == "gap":
268
+ pool_mask = pool_mask[..., None]
269
+ x = jnp.sum(x * pool_mask, axis=1) / jnp.sum(pool_mask, axis=1)
270
+ elif self.pool_type == "max":
271
+ # Tested in (internal link)
272
+ pool_mask = pool_mask[..., None]
273
+ ignore = jnp.where(pool_mask, 0, jnp.finfo(x.dtype).min)
274
+ x = jnp.max(pool_mask * x + ignore, axis=1)
275
+ elif self.pool_type == "none":
276
+ pass
277
+ else:
278
+ raise ValueError(f"Unknown pool type: '{self.pool_type}'")
279
+ out["head_input"] = x
280
+
281
+ if self.rep_size:
282
+ rep_size = self.width if self.rep_size is True else self.rep_size
283
+ hid = nn.Dense(rep_size, name="pre_logits")
284
+ x = nn.tanh(hid(x))
285
+
286
+ out["pre_logits"] = x
287
+
288
+ if self.num_classes:
289
+ kw = {"kernel_init": nn.initializers.zeros} if self.head_zeroinit else {}
290
+ head = nn.Dense(self.num_classes, name="head", **kw)
291
+ x = out["logits"] = head(x)
292
+
293
+ return x, out
294
+
295
+
296
+ def Model(num_classes=None, *, variant=None, **kw): # pylint: disable=invalid-name
297
+ """Factory function, because linen really don't like what I'm doing!"""
298
+ return _Model(num_classes, **{**vit.decode_variant(variant), **kw})
299
+
300
+ load = vit.load
Tipsomaly/model/big_vision/models/proj/image_text/two_towers.py ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Transformer encoders both for text and for images."""
16
+
17
+ import importlib
18
+ from typing import Any, Optional, Tuple, Union
19
+ from absl import logging
20
+
21
+ from big_vision import utils
22
+ import flax.linen as nn
23
+ import jax.numpy as jnp
24
+
25
+ ConfigDict = Any
26
+
27
+
28
+ class Model(nn.Module):
29
+ """Two towers transformer."""
30
+ image: Optional[ConfigDict] = None
31
+ text: Optional[ConfigDict] = None
32
+ text_model: str = "proj.image_text.text_transformer"
33
+ image_model: str = "vit"
34
+ out_dim: Union[int, Tuple[int, int]] = 128
35
+ temperature_init: float = 1.0
36
+ bias_init: Optional[float] = None
37
+
38
+ @nn.compact
39
+ def __call__(self, image, text=None, learnable_prompts=None, learning_method=None, **kw):
40
+ """Returns (B,C) image and (B,C) text representations."""
41
+
42
+ # Support calling without text or without image, for example for few-shot.
43
+ ztxt, zimg = None, None
44
+ out = {}
45
+ out_dims = self.out_dim
46
+ if isinstance(out_dims, int):
47
+ out_dims = (out_dims, out_dims)
48
+
49
+ # Embed the text:
50
+ if text is not None:
51
+ text_model = importlib.import_module(
52
+ f"big_vision.models.{self.text_model}"
53
+ ).Model(**{"num_classes": out_dims[1], **(self.text or {})}, name="txt")
54
+
55
+ ztxt, out_txt = text_model(text, learnable_prompts=learnable_prompts, learning_method=learning_method, **kw)
56
+ for k, v in out_txt.items():
57
+ out[f"txt/{k}"] = v
58
+
59
+ # Normalize the embeddings the models give us.
60
+ out["txt/norm"] = jnp.linalg.norm(ztxt, axis=1, keepdims=True)
61
+ out["txt/normalized"] = ztxt = ztxt / (out["txt/norm"] + 1e-8)
62
+
63
+ if image is not None:
64
+ image_model = importlib.import_module(
65
+ f"big_vision.models.{self.image_model}"
66
+ ).Model(**{"num_classes": out_dims[0], **(self.image or {})}, name="img") # pylint: disable=not-a-mapping
67
+
68
+ zimg, out_img = image_model(image, **kw)
69
+ for k, v in out_img.items():
70
+ out[f"img/{k}"] = v
71
+
72
+ # Normalize the embeddings the models give us.
73
+ out["img/norm"] = jnp.linalg.norm(zimg, axis=1, keepdims=True)
74
+ out["img/normalized"] = zimg = zimg / (out["img/norm"] + 1e-8)
75
+
76
+ out["img/2d_norm"] = jnp.linalg.norm(out_img['encoded'], axis=2, keepdims=True)
77
+ out["img/2d_normalized"] = out_img['encoded'] / (out["img/2d_norm"] + 1e-8)
78
+
79
+ temp_init = jnp.log(self.temperature_init)
80
+ t = self.param("t",
81
+ lambda key, shape, dtype: temp_init * jnp.ones(shape, dtype),
82
+ (1,), jnp.float32)
83
+ out["t"] = jnp.exp(t)
84
+
85
+ out["t/parameter"] = t
86
+ if (b_init := self.bias_init) is not None:
87
+ out["b"] = self.param("b", lambda k, s, d: b_init * jnp.ones(s, d),
88
+ (1,), jnp.float32)
89
+
90
+ # We could actually play with pre-multiplying by temperature here, such
91
+ # that out["t"] is nothing special to the trainer anymore.
92
+
93
+ return zimg, ztxt, out
94
+
95
+ def load(init_params, init_files, model_cfg, img_load_kw={}, txt_load_kw={}): # pylint: disable=dangerous-default-value
96
+ """Loads both towers, `init_files` is now a dict with `img` and `txt` keys."""
97
+ if isinstance(init_files, str):
98
+ init_files = VANITY_NAMES.get(init_files, init_files)
99
+
100
+ if isinstance(init_files, str):
101
+ # A shortcut for a single file checkpoint of a two_towers model.
102
+ if "bias_init" in model_cfg.keys():
103
+ logging.info("loading img, txt, t, and b from a single checkpoint.")
104
+ init_files = {k: f"{init_files}:{k}" for k in ("img", "txt", "t", "b")}
105
+ else:
106
+ logging.info("loading img, txt, and t from a single checkpoint.")
107
+ init_files = {k: f"{init_files}:{k}" for k in ("img", "txt", "t")}
108
+ else:
109
+ init_files = {**init_files} # Shallow copy because we'll pop stuff off.
110
+
111
+ if not init_params: # Convenience to skip checks in colab.
112
+ init_params = {"img": None, "txt": None}
113
+ restored_params = {**init_params}
114
+
115
+ img_init = init_files.pop("image", init_files.pop("img", None))
116
+ if img_init:
117
+ restored_params["img"] = importlib.import_module(
118
+ f"big_vision.models.{model_cfg.get('image_model', 'vit')}"
119
+ ).load(init_params["img"], img_init, model_cfg.image, **img_load_kw)
120
+
121
+ txt_init = init_files.pop("text", init_files.pop("txt", None))
122
+ if txt_init:
123
+ restored_params["txt"] = importlib.import_module(
124
+ f"big_vision.models.{model_cfg.get('text_model', 'proj.image_text.text_transformer')}" # pylint: disable=line-too-long
125
+ ).load(init_params["txt"], txt_init, model_cfg.text, **txt_load_kw)
126
+
127
+ t_init = init_files.pop("temperature", init_files.pop("t", None))
128
+ if t_init:
129
+ restored_params["t"] = utils.load_params(t_init)
130
+
131
+ b_init = init_files.pop("bias", init_files.pop("b", None))
132
+ if b_init:
133
+ restored_params["b"] = utils.load_params(b_init)
134
+
135
+ assert not init_files, (
136
+ f"There's something unused left in `config.model_init`. You probably got "
137
+ f"a typo. Here it is: {init_files}")
138
+
139
+ return restored_params
140
+
141
+
142
+ # Shortcut names for some canonical paper checkpoints:
143
+ VANITY_NAMES = {
144
+ # pylint: disable=line-too-long
145
+ # SigLIP image encoder checkpoints from https://arxiv.org/abs/2303.15343
146
+ "SigLIP B/16 224": "gs://big_vision/siglip/webli_en_b16_224_63724782.npz",
147
+ "SigLIP B/16 256": "gs://big_vision/siglip/webli_en_b16_256_60500360.npz",
148
+ "SigLIP B/16 384": "gs://big_vision/siglip/webli_en_b16_384_68578854.npz",
149
+ "SigLIP B/16 512": "gs://big_vision/siglip/webli_en_b16_512_68580893.npz",
150
+ "SigLIP L/16 256": "gs://big_vision/siglip/webli_en_l16_256_60552751.npz",
151
+ "SigLIP L/16 384": "gs://big_vision/siglip/webli_en_l16_384_63634585.npz",
152
+ "SigLIP So400m/14 224": "gs://big_vision/siglip/webli_en_so400m_224_57633886.npz",
153
+ "SigLIP So400m/14 384": "gs://big_vision/siglip/webli_en_so400m_384_58765454.npz",
154
+ "SigLIP B/16-i18n 256": "gs://big_vision/siglip/webli_i18n_b16_256_66117334.npz",
155
+
156
+ # SigLIP 2 image and text encoder checkpoints from https://arxiv.org/abs/2502.14786
157
+ "SigLIP2 B/16 224": "gs://big_vision/siglip2/siglip2_b16_224.npz",
158
+ "SigLIP2 B/16 256": "gs://big_vision/siglip2/siglip2_b16_256.npz",
159
+ "SigLIP2 B/16 384": "gs://big_vision/siglip2/siglip2_b16_384.npz",
160
+ "SigLIP2 B/16 512": "gs://big_vision/siglip2/siglip2_b16_512.npz",
161
+ "SigLIP2 B/32 256": "gs://big_vision/siglip2/siglip2_b32_256.npz",
162
+ "SigLIP2 L/16 256": "gs://big_vision/siglip2/siglip2_l16_256.npz",
163
+ "SigLIP2 L/16 384": "gs://big_vision/siglip2/siglip2_l16_384.npz",
164
+ "SigLIP2 L/16 512": "gs://big_vision/siglip2/siglip2_l16_512.npz",
165
+ "SigLIP2 So400m/14 224": "gs://big_vision/siglip2/siglip2_so400m14_224.npz",
166
+ "SigLIP2 So400m/14 384": "gs://big_vision/siglip2/siglip2_so400m14_384.npz",
167
+ "SigLIP2 So400m/16 256": "gs://big_vision/siglip2/siglip2_so400m16_256.npz",
168
+ "SigLIP2 So400m/16 384": "gs://big_vision/siglip2/siglip2_so400m16_384.npz",
169
+ "SigLIP2 So400m/16 512": "gs://big_vision/siglip2/siglip2_so400m16_512.npz",
170
+ "SigLIP2 g-opt/16 256": "gs://big_vision/siglip2/siglip2_g-opt16_256.npz",
171
+ "SigLIP2 g-opt/16 384": "gs://big_vision/siglip2/siglip2_g-opt16_384.npz",
172
+ # SigLIP 2 NaFlex image and text encoder checkpoints.
173
+ # These need `image_model="proj.image_text.naflex_vit"` for the image encoder
174
+ # and a non-standard preprocessing, see configs/proj/image_text/README_siglip2.md.
175
+ "SigLIP2 B/16 NaFlex": "gs://big_vision/siglip2/siglip2_b16_naflex.npz",
176
+ "SigLIP2 So400m/16 NaFlex": "gs://big_vision/siglip2/siglip2_so400m16_naflex.npz",
177
+ # pylint: enable=line-too-long
178
+ }
Tipsomaly/model/big_vision/pp/proj/clippo/pp_ops.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Preprocessing functions for CLIP with Pixels Only (CLIPPO)."""
16
+ from absl import logging
17
+ from big_vision.pp import utils
18
+ from big_vision.pp.registry import Registry
19
+ import numpy as np
20
+ import tensorflow as tf
21
+
22
+
23
+ @Registry.register("preprocess_ops.render_unifont")
24
+ @utils.InKeyOutKey(indefault="texts", outdefault="image")
25
+ def get_pp_render_text(image_size: int, font_size: int = 16, max_chars=768,
26
+ background_brightness=127, text_brightness=0,
27
+ lower=True, monospace=False, spacing=1, min_width=4,
28
+ resize_method="area"):
29
+ """Renders text as image, using binary Unifont.
30
+
31
+ Largely based on Jeffrey Sorensen's text rendering implementation.
32
+
33
+ Args:
34
+ image_size: Width/height of output image.
35
+ font_size: Font size to use. Recommended to leave at 16, as this requires
36
+ no resizing, and is safe.
37
+ max_chars: Maximum inpute characters to render, to make faster.
38
+ background_brightness: (r, g, b) of background pixels.
39
+ text_brightness: (r, g, b) of text pixels.
40
+ lower: whether to lowercase.
41
+ monospace: if False, text characters are horizontally trimmed according to
42
+ `spacing` and `minwidth` args.
43
+ spacing: # pixels between each letter.
44
+ min_width: Minimum width of each letter. Useful to make sure e.g. spaces and
45
+ full stops aren't collapsed to nothing.
46
+ resize_method: resize method to use if fontsize != 16.
47
+
48
+ Returns:
49
+ Function which renders text as an image.
50
+ """
51
+ bit_embedding = np.zeros((0x200000, 32), dtype=np.uint8)
52
+ colpattern = {64: range(32),
53
+ 32: sorted(tuple(range(0, 32, 4)) + tuple(range(2, 32, 4)))}
54
+
55
+ unifont_path = "big_vision/pp/proj/clippo/unifont-9.0.06.hex"
56
+ unifont_upper_path = "big_vision/pp/proj/clippo/unifont_upper-9.0.06.hex"
57
+
58
+ with tf.io.gfile.GFile(unifont_path) as f:
59
+ for line in f:
60
+ row = int(line[0:4], 16)
61
+ hexbits = line[5:-1]
62
+ bit_embedding[row, colpattern[len(hexbits)]] = bytearray.fromhex(hexbits)
63
+
64
+ with tf.io.gfile.GFile(unifont_upper_path) as f:
65
+ for line in f:
66
+ row = int(line[0:6], 16)
67
+ hexbits = line[7:-1]
68
+ bit_embedding[row, colpattern[len(hexbits)]] = bytearray.fromhex(hexbits)
69
+
70
+ params = tf.constant(bit_embedding, dtype=tf.uint8)
71
+
72
+ def trim_letter(letter):
73
+ """Remove white space based on the letter size."""
74
+ v = tf.reduce_max(letter, axis=0)
75
+ has_pixels = tf.reshape(tf.where(v), (-1,), name="RS5")
76
+ no_pixels = tf.equal(tf.reduce_max(v), 0)
77
+ first = tf.cond(no_pixels, lambda: tf.constant(0, tf.int64),
78
+ lambda: has_pixels[0])
79
+ last = tf.cond(no_pixels, lambda: tf.constant(0, tf.int64),
80
+ lambda: has_pixels[-1])
81
+
82
+ first = tf.maximum(first - spacing, 0)
83
+ last = tf.maximum(last + spacing, first + min_width)
84
+ return tf.RaggedTensor.from_tensor(tf.transpose(letter[:, first:last]))
85
+
86
+ def to_image(rendered, width, height=None):
87
+ """Makes a nice square image from a long string of rendered charcaters."""
88
+ height = height or width
89
+ max_letter_width = tf.reduce_max(rendered.row_lengths(1))
90
+ row_lengths = tf.cast(tf.cumsum(rendered.row_lengths(1)), tf.float32)
91
+ div = tf.cast(width - max_letter_width, tf.float32) # For rounding errors.
92
+ row_idx = tf.cast(tf.floor(row_lengths / div), tf.int64)
93
+ row_idx = tf.RaggedTensor.from_value_rowids(tf.range(tf.shape(rendered)[0]),
94
+ row_idx)
95
+ trimmed = tf.gather(rendered, row_idx, axis=0)
96
+ trimmed = trimmed.merge_dims(1, 2)
97
+ trimmed = trimmed.to_tensor(default_value=0)
98
+ trimmed = tf.transpose(trimmed, (0, 2, 1))
99
+ trimmed = tf.reshape(trimmed, (-1, tf.shape(trimmed)[-1]), name="RS4")
100
+ trimmed = trimmed[:height]
101
+
102
+ wpad = width - tf.shape(trimmed)[1]
103
+ hpad = height - tf.shape(trimmed)[0]
104
+ padded = tf.pad(trimmed, [[0, hpad], [0, wpad]])
105
+ tf.assert_equal(tf.shape(padded), tf.constant((height, width)))
106
+ return tf.ensure_shape(padded, (width, height))
107
+
108
+ def render(text):
109
+ if lower:
110
+ text = tf.strings.lower(text)
111
+ text = tf.reshape(text, (-1,))[0]
112
+ ids = tf.strings.unicode_decode(text, "UTF-8")
113
+ if max_chars:
114
+ ids = ids[:max_chars]
115
+ embed = tf.nn.embedding_lookup(params, ids) # Get the letters
116
+ # Each letter is 32 uint8s, but we want binary 16x16 grid.
117
+ # The following does that in a rather hard to parse way.
118
+ vertical = tf.reshape(embed, [1, -1])
119
+ repl = tf.reshape(tf.transpose(tf.tile(vertical, multiples=[8, 1])), [-1])
120
+ ones = tf.ones_like(repl)
121
+ index = tf.cumsum(ones, exclusive=True)
122
+ sevens = tf.cast(tf.fill(tf.shape(repl), 7), tf.uint8)
123
+ moded = tf.bitwise.bitwise_and(index, sevens)
124
+ shifted = tf.bitwise.right_shift(repl,
125
+ tf.bitwise.bitwise_xor(moded, sevens))
126
+ anded = tf.bitwise.bitwise_and(shifted, ones)
127
+ # And finally, letters; binary, 0 = background, 1 = letter.
128
+ letters = tf.reshape(anded, [tf.shape(ids)[0], 16, 16])
129
+
130
+ if font_size != 16:
131
+ logging.warning("The unifont text rendering function is highly optimized "
132
+ "for font size 16; using font size %i might lead to "
133
+ "suboptimal rendering and might degrade performance.",
134
+ font_size)
135
+ letters = tf.image.resize(letters[..., None], (font_size, font_size),
136
+ method=resize_method, antialias=True)
137
+ letters = tf.squeeze(letters, axis=-1)
138
+
139
+ if monospace:
140
+ letters = tf.RaggedTensor.from_tensor(tf.transpose(letters, (0, 2, 1)))
141
+ else:
142
+ letters = tf.RaggedTensor.from_tensor(letters)
143
+ signature = tf.RaggedTensorSpec(shape=(None, font_size), ragged_rank=1,
144
+ dtype=letters.dtype)
145
+ letters = tf.map_fn(trim_letter, letters, fn_output_signature=signature)
146
+
147
+ img = to_image(letters, image_size)[..., None] # A nice square image.
148
+ img *= (text_brightness - background_brightness) # Rescale value range.
149
+ img += background_brightness
150
+
151
+ return tf.image.grayscale_to_rgb(tf.cast(img, tf.uint8))
152
+
153
+ return render
Tipsomaly/model/big_vision/pp/proj/flaxformer/bert_ops.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """BERT-related preprocessing ops (using WordPiece tokenizer)."""
16
+
17
+ from big_vision.pp import utils
18
+ from big_vision.pp.registry import Registry
19
+ import tensorflow as tf
20
+ import tensorflow_text
21
+
22
+
23
+ # Internally using
24
+ # BasicTokenizer
25
+ # https://github.com/tensorflow/text/blob/df5250d6cf1069990df4bf55154867391ab5381a/tensorflow_text/python/ops/bert_tokenizer.py#L67
26
+ # WordpieceTokenizer
27
+ # https://github.com/tensorflow/text/blob/master/tensorflow_text/python/ops/wordpiece_tokenizer.py
28
+ def _create_bert_tokenizer(vocab_path):
29
+ """Returns cls_token id and tokenizer to use in a tf.Dataset.map function."""
30
+ # Create tokenizer inside a tf.init_scope so the vocab is only loaded from
31
+ # disk once per dataset iterator (see: http://(internal link)).
32
+ # TODO: Make a local copy of vocab if creating many iterators.
33
+ with tf.init_scope():
34
+ tokenizer = tensorflow_text.BertTokenizer(
35
+ vocab_path,
36
+ token_out_type=tf.int32,
37
+ lower_case=True,
38
+ )
39
+
40
+ with tf.io.gfile.GFile(vocab_path) as f:
41
+ vocab = f.read().split("\n")
42
+ cls_token = vocab.index("[CLS]")
43
+
44
+ return cls_token, tokenizer
45
+
46
+
47
+ @Registry.register("preprocess_ops.bert_tokenize")
48
+ @utils.InKeyOutKey(indefault=None, outdefault="labels")
49
+ def get_pp_bert_tokenize(vocab_path, max_len, sample_if_multi=True):
50
+ """Extracts tokens with tensorflow_text.BertTokenizer.
51
+
52
+ Args:
53
+ vocab_path: Path to a file containing the vocabulry for the WordPiece
54
+ tokenizer. It's the "vocab.txt" file in the zip file downloaded from
55
+ the original repo https://github.com/google-research/bert
56
+ max_len: Number of tokens after tokenization.
57
+ sample_if_multi: Whether the first text should be taken (if set to `False`),
58
+ or whether a random text should be tokenized.
59
+
60
+ Returns:
61
+ A preprocessing Op.
62
+ """
63
+
64
+ cls_token, tokenizer = _create_bert_tokenizer(vocab_path)
65
+
66
+ def _pp_bert_tokenize(labels):
67
+
68
+ labels = tf.reshape(labels, (-1,))
69
+ labels = tf.concat([labels, [""]], axis=0)
70
+ if sample_if_multi:
71
+ num_texts = tf.maximum(tf.shape(labels)[0] - 1, 1) # Don't sample "".
72
+ txt = labels[tf.random.uniform([], 0, num_texts, dtype=tf.int32)]
73
+ else:
74
+ txt = labels[0] # Always works, since we append "" earlier on.
75
+
76
+ token_ids = tokenizer.tokenize(txt[None])
77
+ padded_token_ids, mask = tensorflow_text.pad_model_inputs(
78
+ token_ids, max_len - 1)
79
+ del mask # Recovered from zero padding in model.
80
+ count = tf.shape(padded_token_ids)[0]
81
+ padded_token_ids = tf.concat(
82
+ [tf.fill([count, 1], cls_token), padded_token_ids], axis=1)
83
+ return padded_token_ids[0]
84
+
85
+ return _pp_bert_tokenize
86
+
Tipsomaly/model/big_vision/pp/proj/flaxformer/bert_ops_test.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Tests for bert_ops."""
16
+
17
+ import tempfile
18
+
19
+ from big_vision import input_pipeline
20
+ import big_vision.pp.builder as pp_builder
21
+ import big_vision.pp.ops_general # pylint: disable=unused-import
22
+ from big_vision.pp.proj.flaxformer import bert_ops # pylint: disable=unused-import
23
+ import tensorflow as tf
24
+
25
+
26
+ # BERT vocabulary for testing.
27
+ _BERT_VOCAB = [
28
+ "[PAD]",
29
+ "[UNK]",
30
+ "more",
31
+ "than",
32
+ "one",
33
+ "[CLS]",
34
+ "[SEP]",
35
+ ]
36
+
37
+
38
+ def _create_ds(pp_str, tensor_slices, num_examples):
39
+ return input_pipeline.make_for_inference(
40
+ tf.data.Dataset.from_tensor_slices(tensor_slices),
41
+ num_ex_per_process=[num_examples],
42
+ preprocess_fn=pp_builder.get_preprocess_fn(pp_str),
43
+ batch_size=num_examples,
44
+ )[0]
45
+
46
+
47
+ class BertOpsTest(tf.test.TestCase):
48
+
49
+ def test_tokenize(self):
50
+ inkey = "texts"
51
+ vocab_path = f"{tempfile.mkdtemp()}/vocab.txt"
52
+ with open(vocab_path, "w") as f:
53
+ f.write("\n".join(_BERT_VOCAB))
54
+ pp_str = (
55
+ f"bert_tokenize(inkey='{inkey}', vocab_path='{vocab_path}', max_len=5)"
56
+ f"|keep('labels')"
57
+ )
58
+ tensor_slices = {
59
+ inkey: tf.ragged.constant([["one more"], ["more than one"], [""]])
60
+ }
61
+ ds = _create_ds(pp_str, tensor_slices, 3)
62
+ self.assertAllEqual(
63
+ next(iter(ds))["labels"],
64
+ [[5, 4, 2, 0, 0], [5, 2, 3, 4, 0], [5, 0, 0, 0, 0]],
65
+ )
66
+
67
+
68
+ if __name__ == "__main__":
69
+ tf.test.main()
Tipsomaly/model/big_vision/pp/proj/image_text/__pycache__/ops_naflex.cpython-311.pyc ADDED
Binary file (10.6 kB). View file
 
Tipsomaly/model/big_vision/pp/proj/image_text/__pycache__/ops_naflex.cpython-312.pyc ADDED
Binary file (9.94 kB). View file
 
Tipsomaly/model/big_vision/pp/proj/image_text/__pycache__/ops_naflex.cpython-39.pyc ADDED
Binary file (7.08 kB). View file
 
Tipsomaly/model/big_vision/pp/proj/image_text/ops_naflex_test.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
+ """Tests for NaFlex preprocessing ops."""
16
+
17
+ import copy
18
+
19
+ from absl.testing import parameterized
20
+ from big_vision.pp.proj.image_text import ops_naflex as pp
21
+ import numpy as np
22
+ import tensorflow as tf
23
+
24
+
25
+ def get_image_data(h, w):
26
+ img = tf.random.uniform((h, w, 3), 0, 255, tf.int32) # Can't ask uint8!?
27
+ return {"image": tf.cast(img, tf.uint8)}
28
+
29
+
30
+ class NaflexTest(tf.test.TestCase, parameterized.TestCase):
31
+
32
+ def tfrun(self, ppfn, data):
33
+ # Run once as standalone, as could happen eg in colab.
34
+ yield tf.nest.map_structure(np.array, ppfn(copy.deepcopy(data)))
35
+
36
+ # And then once again as part of tfdata pipeline.
37
+ # You'd be surprised how much these two differ!
38
+ tfdata = tf.data.Dataset.from_tensors(copy.deepcopy(data))
39
+ for npdata in tfdata.map(ppfn).as_numpy_iterator():
40
+ yield npdata
41
+
42
+ @parameterized.parameters(
43
+ (6, 8),
44
+ (7, 9),
45
+ (8, 10),
46
+ )
47
+ def test_patchify_valid(self, h, w):
48
+ """Tests the patchification op."""
49
+ op = pp.get_patchify((3, 4))
50
+ inputs = get_image_data(h, w)
51
+ for data in self.tfrun(op, inputs):
52
+ self.assertEqual(data["image"]["patches"].shape, (4, 3*4*3))
53
+ self.assertAllEqual(
54
+ data["image"]["patches"][-1],
55
+ np.array(inputs["image"])[3:6, 4:8, :].flatten())
56
+ self.assertAllEqual(data["image"]["yidx"], [0, 0, 1, 1])
57
+ self.assertAllEqual(data["image"]["xidx"], [0, 1, 0, 1])
58
+
59
+ @parameterized.named_parameters([
60
+ ("square_121_exact", (48, 48), 3, 121, (33, 33)),
61
+ ("square_225_inexact", (112, 109), 7, 225, (105, 105)),
62
+ ("square_64_exact", (176, 176), 11, 64, (88, 88)),
63
+ ("rect_12_exact", (256, 64), 16, 12, (96, 32)),
64
+ ("rect_15_exact_ps8", (256, 64), 8, 15, (56, 16)),
65
+ ("rect_16_inexact", (63, 241), 16, 16, (32, 128)),
66
+ ("rect_less_than_patch", (16, 512), 16, 16, (16, 256)),
67
+ ])
68
+ def test_pp_resize_to_sequence(
69
+ self, image_size, patch_size, seq_len, expected_image_size):
70
+ """Tests the AR-preserving `resize_to_sequence` op."""
71
+ op = pp.get_resize_to_sequence(patch_size, seq_len)
72
+ inputs = get_image_data(*image_size)
73
+ for outputs in self.tfrun(op, inputs):
74
+ self.assertAllEqual(outputs["image"].shape, expected_image_size + (3,))
75
+
76
+ if __name__ == "__main__":
77
+ tf.test.main()
Tipsomaly/model/big_vision/pp/proj/paligemma/__pycache__/ops.cpython-311.pyc ADDED
Binary file (10 kB). View file
 
Tipsomaly/model/big_vision/pp/proj/paligemma/__pycache__/ops.cpython-312.pyc ADDED
Binary file (8.75 kB). View file
 
Tipsomaly/model/big_vision/pp/proj/paligemma/__pycache__/ops.cpython-39.pyc ADDED
Binary file (5.94 kB). View file
 
Tipsomaly/model/big_vision/pp/proj/paligemma/ops.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """pp ops."""
16
+
17
+ import functools
18
+
19
+ from big_vision.pp import ops_text
20
+ from big_vision.pp import utils
21
+ from big_vision.pp.registry import Registry
22
+ import big_vision.pp.tokenizer as bv_tok
23
+ import numpy as np
24
+ import tensorflow as tf
25
+
26
+
27
+ @Registry.register('tokenizers.gemma')
28
+ def get_tokenizer_gemma(
29
+ tokensets=(),
30
+ model='gs://big_vision/gemma_tokenizer.model',
31
+ ):
32
+ # See (internal link) for colab playground.
33
+ return ops_text.SentencepieceTokenizer(model=model, tokensets=tokensets)
34
+
35
+
36
+ @functools.cache
37
+ def tokenize_constant(model, text, bos='no', eos='no', length=None):
38
+ """Tokenize a constant string, with memoization."""
39
+ assert eos in ('no', 'yes', 'sticky')
40
+ assert bos in ('no', 'yes')
41
+ tokenizer = bv_tok.get_tokenizer(model)
42
+ tokens = tokenizer.to_int(
43
+ text, bos=bos == 'yes', eos=eos in ('yes', 'sticky'))
44
+
45
+ if length is None:
46
+ return tokens
47
+
48
+ if len(tokens) > length:
49
+ if eos == 'sticky':
50
+ return np.r_[tokens[:length-1], tokens[-1]]
51
+ else:
52
+ return tokens[:length]
53
+ else:
54
+ return np.pad(tokens, [(0, length - len(tokens))],
55
+ constant_values=tokenizer.pad_token)
56
+
57
+
58
+ @Registry.register('preprocess_ops.tolen')
59
+ @utils.InKeyOutKey(indefault=None, outdefault=None, with_data=True)
60
+ def get_tolen(length, *, sticky_end=False, pad_value=None, pad_key=None):
61
+ """Gets token to a fixed length."""
62
+ def _tolen(x, data):
63
+ if not length:
64
+ return x
65
+
66
+ xlen = tf.shape(x)[0]
67
+
68
+ if sticky_end:
69
+ trunc_fn = lambda: tf.concat([x[:length - 1], x[-1:]], axis=0)
70
+ else:
71
+ trunc_fn = lambda: x[:length]
72
+
73
+ # Potentially get the pad value from a data key (to be tokenizer agnostic).
74
+ pad_value_ = pad_value
75
+ if pad_key:
76
+ pad_value_ = data[pad_key]
77
+ # If coming from a previous tokenization op, it's probably 1D; take first.
78
+ if getattr(pad_value_, 'ndim', 0) == 1:
79
+ pad_value_ = pad_value_[0]
80
+ assert pad_value_ is not None, 'Need either pad_value or pad_key.'
81
+
82
+ pad_fn = lambda: tf.pad(x, [(0, length - xlen)], constant_values=pad_value_)
83
+ out = tf.cond(xlen >= length, trunc_fn, pad_fn)
84
+ out.set_shape([length])
85
+ return out
86
+ return _tolen
87
+
88
+
89
+ @Registry.register('preprocess_ops.tok')
90
+ def get_tokenize(model, length=None, *, bos='no', eos='no',
91
+ text=None, key=None, inkey=None, outkey=None):
92
+ """Tokenizes and optionally truncates/pads a string."""
93
+
94
+ assert eos in ('no', 'yes', 'sticky')
95
+ assert bos in ('no', 'yes')
96
+ outkey_ = outkey or key
97
+ inkey_ = inkey or key
98
+
99
+ if text is not None:
100
+ assert inkey is None, 'Either inkey or text, not both.'
101
+ tokens = tokenize_constant(model, text, bos=bos, eos=eos, length=length)
102
+ tokens = tf.cast(tokens, tf.int32) # Same dtype as in-graph tokenizer.
103
+ def _pp_tokenize_text(data):
104
+ data[outkey_] = tokens
105
+ return data
106
+ return _pp_tokenize_text
107
+
108
+ tokenizer = bv_tok.get_tokenizer(model)
109
+
110
+ def _pp_tokenize(data):
111
+ assert getattr(data[inkey_], 'ndim', 0) == 0, (
112
+ f'Can only tokenize single string ({inkey_}, {data[inkey_].ndim}-D)')
113
+
114
+ toks = tokenizer.to_int_tf_op(
115
+ data[inkey_], bos=bos == 'yes', eos=eos in ('yes', 'sticky'))
116
+ toks = tf.ensure_shape(toks, [None])
117
+ tolen = get_tolen(
118
+ length, sticky_end=eos == 'sticky',
119
+ pad_value=bv_tok.get_tokenizer(model).pad_token,
120
+ key='tmp',
121
+ )
122
+ toks = tolen({'tmp': toks})['tmp']
123
+
124
+ data[outkey_] = toks
125
+ return data
126
+ return _pp_tokenize
127
+
128
+
129
+ @Registry.register('preprocess_ops.masked_concat')
130
+ def get_masked_concat(keys, outkey='text', **masks):
131
+ assert all(len(keys) == len(m) for m in masks.values()), (keys, masks)
132
+ def _masked_concat(data):
133
+ # Refer to original inputs to support using same key as input/output.
134
+ inputs = dict(**data)
135
+ data[outkey] = tf.concat([inputs[k] for k in keys], axis=0)
136
+ for mask_name, mask_vals in masks.items():
137
+ m = [tf.fill(tf.shape(inputs[k]), v) for k, v in zip(keys, mask_vals)]
138
+ data[mask_name] = tf.concat(m, axis=0)
139
+ return data
140
+ return _masked_concat
141
+
142
+
143
+ @Registry.register('preprocess_ops.strjoin')
144
+ @utils.InKeyOutKey()
145
+ def get_strjoin(glue, axis=None):
146
+ def _strjoin(x):
147
+ return tf.strings.reduce_join(x, axis=axis, separator=glue)
148
+ return _strjoin
149
+
150
+
151
+ @Registry.register('preprocess_ops.majority')
152
+ @utils.InKeyOutKey()
153
+ def get_majority():
154
+ def _majority(x):
155
+ val, _, count = tf.unique_with_counts(x) # Sadly, stablesorted.
156
+ return val[tf.argmax(count)]
157
+ return _majority
158
+
159
+
160
+ @Registry.register('preprocess_ops.getidx')
161
+ def getidx(inkey, index_key, outkey=None):
162
+ """Indexes a tensor and stores result in outkey."""
163
+ def _getidx(data):
164
+ idx = data[index_key]
165
+ array = data[inkey]
166
+ data[outkey or inkey] = array[idx]
167
+ return data
168
+ return _getidx
Tipsomaly/model/big_vision/pp/proj/paligemma/robustness.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """pp ops."""
16
+
17
+ import math
18
+
19
+ from big_vision.pp import utils
20
+ from big_vision.pp.registry import Registry
21
+ import tensorflow as tf
22
+
23
+
24
+ @Registry.register("preprocess_ops.resize_r")
25
+ @utils.InKeyOutKey()
26
+ def get_resize_r(size):
27
+ """Like standard `resize` but randomize some of its parameters."""
28
+ size = utils.maybe_repeat(size, 2)
29
+
30
+ # Sadly TF won't let us pass symbolic arguments, so we need to pre-create all
31
+ # variants of function calls we'd like to randomize over...
32
+ resize_fns = [
33
+ lambda x, m=m, a=a: tf.image.resize(x, size, method=m, antialias=a)
34
+ for m in ["bilinear", "bicubic", "lanczos3", "area", "mitchellcubic"]
35
+ for a in [True, False]
36
+ ]
37
+
38
+ def _resize_r(image):
39
+ """Resizes image to a given size."""
40
+ dtype = image.dtype
41
+ tf_dtype = tf.type_spec_from_value(image).dtype
42
+ ifn = tf.random.uniform((), 0, len(resize_fns), tf.int32)
43
+ image = tf.switch_case(ifn, [lambda fn=fn: fn(image) for fn in resize_fns])
44
+ return tf.cast(tf.clip_by_value(image, tf_dtype.min, tf_dtype.max), dtype)
45
+
46
+ return _resize_r
47
+
48
+
49
+ @Registry.register("preprocess_ops.random_jpeg")
50
+ @utils.InKeyOutKey()
51
+ def get_random_jpeg(p):
52
+ """With probability `p`, randomly encode-decode as jpeg."""
53
+
54
+ fns = [
55
+ lambda x: tf.image.adjust_jpeg_quality(
56
+ x, dct_method="INTEGER_FAST",
57
+ jpeg_quality=tf.random.uniform((), 75, 96, dtype=tf.int32),
58
+ ),
59
+ lambda x: tf.image.adjust_jpeg_quality(
60
+ x, dct_method="INTEGER_ACCURATE",
61
+ jpeg_quality=tf.random.uniform((), 75, 96, dtype=tf.int32),
62
+ ),
63
+ ]
64
+
65
+ def _random_jpeg(image):
66
+ """Resizes image to a given size."""
67
+ funcs = [lambda: image] + [lambda fn=fn: fn(image) for fn in fns]
68
+ logits = [math.log(prob) for prob in [1 - p] + [p / len(fns)] * len(fns)]
69
+ fn_idx = tf.random.categorical([logits], 1, dtype=tf.int32)[0, 0]
70
+ return tf.switch_case(fn_idx, funcs)
71
+
72
+ return _random_jpeg
Tipsomaly/model/big_vision/pp/proj/paligemma/sciqa_ops.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """pp ops."""
16
+
17
+ from big_vision.pp.registry import Registry
18
+ import tensorflow as tf
19
+
20
+
21
+ @Registry.register('preprocess_ops.sci_qa_choices_shuffle')
22
+ def sci_qa_choices_shuffle(
23
+ choice_str_inkey='choices',
24
+ ans_inkey='answer',
25
+ indexed_choices_outkey='indexed_choices',
26
+ indexed_answer_outkey='indexed_answer',
27
+ ):
28
+ """Random shuffle the sci_qa's choice on the fly.
29
+
30
+ Args:
31
+ choice_str_inkey: the original choice list from
32
+ sciqa,e.g['apple','banana',..]
33
+ ans_inkey: the original answer from sciqa e.g. 1
34
+ indexed_choices_outkey: shuffled choice (with index suffix concat to string)
35
+ e.g."(A) banana, (B) apple"
36
+ indexed_answer_outkey: shuffled answer with abc index, e,g
37
+ 1(original)->2(shuffled)->'B' (alphabet index)
38
+
39
+ Returns:
40
+ """
41
+ def _template(data):
42
+ alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
43
+ abc_tensor = tf.constant([f'({a})' for a in alphabet])
44
+ abcans_tensor = tf.constant([f'{a}' for a in alphabet])
45
+ choices = data[choice_str_inkey]
46
+ indices = tf.range(len(choices))
47
+ # Shuffle the indices
48
+ shuffled_indices = tf.random.shuffle(indices)
49
+ # Use the shuffled indices to shuffle the tensor
50
+ shuffled_tensor = tf.gather(choices, shuffled_indices)
51
+
52
+ abc_tensor = tf.gather(abc_tensor, indices)
53
+
54
+ data[indexed_choices_outkey] = tf.strings.reduce_join(
55
+ tf.strings.join([abc_tensor, shuffled_tensor], separator=' '),
56
+ separator=', ',
57
+ )
58
+
59
+ answer_tensor = data[ans_inkey]
60
+ new_ans_indice = tf.where(tf.equal(shuffled_indices, answer_tensor))
61
+ new_ans_indice = tf.gather(abcans_tensor, new_ans_indice)
62
+ data[indexed_answer_outkey] = tf.strings.reduce_join(new_ans_indice)
63
+ return data
64
+
65
+ return _template
Tipsomaly/model/big_vision/pp/proj/paligemma/segmentation.py ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Segmentation-related ops."""
16
+
17
+ import functools
18
+
19
+ from big_vision.pp import registry
20
+ import numpy as np
21
+ import tensorflow as tf
22
+
23
+ from tensorflow.io import gfile
24
+
25
+
26
+ _KNOWN_MODELS = {
27
+ 'oi': 'gs://big_vision/paligemma/vae-oid.npz',
28
+ }
29
+
30
+
31
+ @functools.cache
32
+ def get_checkpoint(model):
33
+ with gfile.GFile(_KNOWN_MODELS.get(model, model), 'rb') as f:
34
+ return dict(np.load(f))
35
+
36
+
37
+ @registry.Registry.register('preprocess_ops.refcoco_mask2str')
38
+ def get_refcoco_mask2str(model='oi'):
39
+ """Returns op for tokenizing a mask."""
40
+
41
+ seg_tokens = tf.constant(['<seg%03d>' % i for i in range(128)])
42
+ loc_tokens = tf.constant(['<loc%04d>' % i for i in range(1024)])
43
+ checkpoint = get_checkpoint(model)
44
+
45
+ def refcoco_mask2str(data):
46
+
47
+ mask = data['objects/mask']
48
+ tf.ensure_shape(mask, [None, None, 3]) # requires choice()
49
+ sentence = data['objects/refs/sentence']
50
+ tf.ensure_shape(sentence, []) # requires choice()
51
+ bbox = data['objects/bbox']
52
+ tf.ensure_shape(bbox, [4]) # requires choice()
53
+
54
+ h = tf.cast(tf.shape(mask)[0], tf.float32)
55
+ w = tf.cast(tf.shape(mask)[1], tf.float32)
56
+ y1 = tf.cast(tf.round(h * bbox[0]), tf.int32)
57
+ x1 = tf.cast(tf.round(w * bbox[1]), tf.int32)
58
+ y2 = tf.cast(tf.round(h * bbox[2]), tf.int32)
59
+ x2 = tf.cast(tf.round(w * bbox[3]), tf.int32)
60
+
61
+ assert mask.dtype == tf.uint8, mask.dtype
62
+ mask = tf.image.resize(
63
+ mask[None, y1:y2, x1:x2, :1],
64
+ [64, 64],
65
+ method='bilinear',
66
+ antialias=True,
67
+ ) / 255.0
68
+
69
+ mask_indices = encode_to_codebook_indices(checkpoint, mask)[0]
70
+ mask_string = tf.strings.reduce_join(tf.gather(seg_tokens, mask_indices))
71
+
72
+ binned_loc = tf.cast(tf.round(bbox * 1023), tf.int32)
73
+ binned_loc = tf.clip_by_value(binned_loc, 0, 1023)
74
+ loc_string = tf.strings.reduce_join(tf.gather(loc_tokens, binned_loc))
75
+
76
+ data['prefix'] = sentence
77
+ data['suffix'] = tf.strings.join([loc_string, mask_string])
78
+
79
+ return data
80
+
81
+ return refcoco_mask2str
82
+
83
+
84
+ # Based on https://arxiv.org/abs/2301.02229.
85
+
86
+ NUM_DOWNSAMPLE_LAYERS = 4
87
+ NUM_RES_BLOCKS = 2
88
+
89
+
90
+ def encode_to_codebook_indices(checkpoint, masks):
91
+ """Encode a batch of binary segmentation masks into 16 tokens each.
92
+
93
+ Based on code from https://arxiv.org/abs/2301.02229
94
+
95
+ Args:
96
+ checkpoint: model weights from PyTorch model.
97
+ masks: Must be in range `[0..1]`, and of shape `[None, 64, 64, 1]`.
98
+
99
+ Returns:
100
+ A tensor of shape `[None, 16]` with elements in `range(128)`.
101
+ """
102
+
103
+ # We require that the input masks are already resized to 64x64.
104
+ x = tf.ensure_shape(masks, [None, 64, 64, 1])
105
+ x = _norm(x)
106
+
107
+ for n in range(NUM_DOWNSAMPLE_LAYERS):
108
+ x = _conv_tf(
109
+ checkpoint, x, strides=2, padding='SAME', layer_name=f'encoder.{2*n}'
110
+ )
111
+ x = tf.nn.relu(x)
112
+
113
+ for n in range(NUM_RES_BLOCKS):
114
+ x = _resblock_tf(checkpoint, x, layer_name=f'encoder.{8+n}.net')
115
+
116
+ x = _conv_tf(
117
+ checkpoint, x, strides=1, padding='SAME', layer_name='encoder.10'
118
+ )
119
+
120
+ return _get_codebook_indices(checkpoint, x)
121
+
122
+
123
+ def _norm(x):
124
+ return 2.0 * (x - 0.5)
125
+
126
+
127
+ def _conv_tf(checkpoint, x, strides, padding, layer_name):
128
+ kernel = checkpoint[layer_name + '.weight']
129
+ kernel = np.transpose(kernel, (2, 3, 1, 0))
130
+ bias = checkpoint[layer_name + '.bias']
131
+ return tf.nn.conv2d(x, kernel, strides=strides, padding=padding) + bias
132
+
133
+
134
+ def _resblock_tf(checkpoint, x, layer_name):
135
+ """Apply a residual block of the mask encoder."""
136
+ original_x = x
137
+ x = _conv_tf(
138
+ checkpoint, x, padding='SAME', strides=1, layer_name=layer_name + '.0'
139
+ )
140
+ x = tf.nn.relu(x)
141
+ x = _conv_tf(
142
+ checkpoint, x, padding='SAME', strides=1, layer_name=layer_name + '.2'
143
+ )
144
+ x = tf.nn.relu(x)
145
+ x = _conv_tf(
146
+ checkpoint, x, padding='SAME', strides=1, layer_name=layer_name + '.4'
147
+ )
148
+ return x + original_x
149
+
150
+
151
+ def _get_codebook_indices(checkpoint, encoder_output):
152
+ embeddings = checkpoint['_vq_vae._embedding']
153
+ flat_input = tf.reshape(encoder_output, [-1, embeddings.shape[1]])
154
+ distances = (
155
+ tf.reduce_sum(flat_input**2, axis=1, keepdims=True)
156
+ + tf.reduce_sum(embeddings**2, axis=1)
157
+ - 2 * tf.matmul(flat_input, embeddings.T)
158
+ )
159
+ indices = tf.argmin(distances, axis=1)
160
+ return tf.reshape(indices, [-1, 16])
Tipsomaly/model/big_vision/pp/proj/paligemma/video.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Preprocessing for videos."""
16
+
17
+ from big_vision.pp import utils
18
+ from big_vision.pp.registry import Registry
19
+
20
+ import tensorflow as tf
21
+
22
+
23
+ @Registry.register('preprocess_ops.video_decode')
24
+ def video_decode(res):
25
+ """Preprocessing."""
26
+
27
+ def _pp_per_image(img):
28
+ # decode
29
+ return tf.image.resize(tf.io.decode_jpeg(img), (res, res))
30
+
31
+ def _pp(data):
32
+ images = data['episodic_images']
33
+ # resize
34
+ images = tf.map_fn(_pp_per_image, images, fn_output_signature=tf.float32)
35
+ # rescale
36
+ images = 2 * (images / 255.) - 1.0
37
+ data['image'] = images
38
+ return data
39
+
40
+ return _pp
41
+
42
+
43
+ @Registry.register('preprocess_ops.video_ensure_shape')
44
+ def video_ensure_shape(key, shape):
45
+ """Preprocessing."""
46
+ def _video_ensure_shape(data):
47
+ data[key] = tf.ensure_shape(data[key], shape)
48
+ return data
49
+
50
+ return _video_ensure_shape
51
+
52
+
53
+ @Registry.register('preprocess_ops.video_replicate_img')
54
+ def video_replicate_img(replicas, num_frames):
55
+ """Ensure that for short videos, we have the correct number of frames.
56
+
57
+ We replicate and select.
58
+
59
+ Args:
60
+ replicas: num_replicas before selection. Should be less than num_frames.
61
+ num_frames: number of frames
62
+
63
+ Returns:
64
+ _replicate_img: preprocessing function
65
+ """
66
+
67
+ def _replicate_img(data):
68
+ # visual analogies + query
69
+ image = data['image']
70
+ image = tf.tile(image, [replicas, 1, 1, 1])
71
+ data['image'] = image[:num_frames]
72
+ return data
73
+
74
+ return _replicate_img
75
+
76
+
77
+ @Registry.register('preprocess_ops.video_choice')
78
+ @utils.InKeyOutKey()
79
+ def video_choice(empty_fallback=None):
80
+ """Randomly takes one entry out of a tensor after flattening."""
81
+
82
+ def _choice(x):
83
+ x = tf.reshape(x, (-1,)) # Ensure it's a 1D array
84
+
85
+ # Append the fallback value so we gracefully handle empty cases.
86
+ x0 = tf.zeros(1, x.dtype) if empty_fallback is None else [empty_fallback]
87
+ x = tf.concat([x, x0], axis=0)
88
+
89
+ num_choices = tf.maximum(tf.shape(x)[0] - 1, 1) # Don't sample x0.
90
+ return x[tf.random.uniform([], 0, num_choices, dtype=tf.int32)]
91
+
92
+ return _choice
93
+
94
+
95
+ @Registry.register('preprocess_ops.stack_images')
96
+ def stack_images(inkeys=(), outkey='image'):
97
+
98
+ def _pp(data):
99
+ images = tf.stack([data[inkey] for inkey in inkeys])
100
+ data[outkey] = images
101
+ return data
102
+
103
+ return _pp
Tipsomaly/model/big_vision/pp/proj/paligemma/widgetcap.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
+ """Widgetcap pp ops."""
16
+
17
+ from big_vision.pp.registry import Registry
18
+ import tensorflow as tf
19
+
20
+
21
+ @Registry.register("preprocess_ops.draw_bbox")
22
+ def get_draw_bbox(image_key="image", bbox_key="bbox"):
23
+ """Draw a single bounding box."""
24
+
25
+ def _draw_bbox(data):
26
+ """Draw a single bounding box."""
27
+ image = tf.cast(data[image_key], tf.float32)
28
+ image = tf.image.draw_bounding_boxes(
29
+ tf.expand_dims(image, 0),
30
+ tf.reshape(data[bbox_key], [1, 1, 4]),
31
+ tf.constant([255, 0, 0], dtype=tf.float32, shape=[1, 3]),
32
+ )
33
+ data[image_key] = tf.squeeze(image)
34
+ return data
35
+
36
+ return _draw_bbox
Tipsomaly/model/big_vision/pp/proj/uvim/pp_ops.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Preprocessing ops."""
16
+ from big_vision.pp import utils
17
+ from big_vision.pp.registry import Registry
18
+ import numpy as np
19
+ import tensorflow as tf
20
+
21
+
22
+ @Registry.register("preprocess_ops.rgb_to_grayscale_to_rgb")
23
+ @utils.InKeyOutKey(indefault="image", outdefault="image")
24
+ def get_rgb_to_grayscale_to_rgb():
25
+ def _rgb_to_grayscale_to_rgb(image):
26
+ return tf.image.grayscale_to_rgb(tf.image.rgb_to_grayscale(image))
27
+ return _rgb_to_grayscale_to_rgb
28
+
29
+
30
+ @Registry.register("preprocess_ops.nyu_eval_crop")
31
+ def get_nyu_eval_crop():
32
+ """Crops labels and image to valid eval area."""
33
+ # crop_h = slice(45, 471)
34
+ # crop_w = slice(41, 601)
35
+ crop_h_start = 54
36
+ crop_h_size = 426
37
+ crop_w_start = 41
38
+ crop_w_size = 560
39
+
40
+ def _pp(data):
41
+ tf.debugging.assert_equal(tf.shape(data["labels"]), (480, 640, 1))
42
+ tf.debugging.assert_equal(tf.shape(data["image"]), (480, 640, 3))
43
+ data["labels"] = tf.slice(data["labels"],
44
+ [crop_h_start, crop_w_start, 0],
45
+ [crop_h_size, crop_w_size, -1])
46
+ data["image"] = tf.slice(data["image"],
47
+ [crop_h_start, crop_w_start, 0],
48
+ [crop_h_size, crop_w_size, -1])
49
+ return data
50
+ return _pp
51
+
52
+
53
+ @Registry.register("preprocess_ops.nyu_depth")
54
+ @utils.InKeyOutKey(indefault="depth", outdefault="labels")
55
+ def get_nyu_depth():
56
+ """Preprocesses NYU depth data."""
57
+ def _pp(depth):
58
+ return tf.expand_dims(tf.cast(depth, tf.float32), -1)
59
+ return _pp
60
+
61
+
62
+ @Registry.register("preprocess_ops.coco_panoptic")
63
+ def get_coco_panoptic_pp():
64
+ """COCO-panoptic: produces a mask with labels and a mask with instance ids.
65
+
66
+ Instance channel will have values between 1 and N, and -1 for non-annotated
67
+ pixels.
68
+
69
+ Returns:
70
+ COCO panoptic preprocessign op.
71
+ """
72
+ def _coco_panoptic(data):
73
+ instance_ids = tf.cast(data["panoptic_objects"]["id"], tf.int32)
74
+ instance_labels = tf.cast(data["panoptic_objects"]["label"], tf.int32)
75
+
76
+ # Convert image with ids split in 3 channels into a an integer id.
77
+ id_mask = tf.einsum(
78
+ "hwc,c->hw",
79
+ tf.cast(data["panoptic_image"], tf.int32),
80
+ tf.constant([1, 256, 256**2], tf.int32))
81
+
82
+ # Broadcast into N boolean masks one per instance_id.
83
+ n_masks = tf.cast(
84
+ id_mask[:, :, None] == instance_ids[None, None, :], tf.int32)
85
+
86
+ # Merge into a semantic and an instance id mask.
87
+ # Note: pixels which do not belong to any mask, will have value=-1
88
+ # which creates an empty one_hot masks.
89
+ # Number instances starting at 1 (0 is treated specially by make_canonical).
90
+ instance_idx = tf.range(tf.shape(instance_ids)[-1])
91
+ instances = tf.einsum("hwc,c->hw", n_masks, instance_idx + 1)
92
+ semantics = tf.einsum("hwc,c->hw", n_masks, instance_labels + 1)
93
+
94
+ data["instances"] = instances[:, :, None]
95
+ data["semantics"] = semantics[:, :, None]
96
+ return data
97
+
98
+ return _coco_panoptic
99
+
100
+
101
+ @Registry.register("preprocess_ops.make_canonical")
102
+ @utils.InKeyOutKey(indefault="labels", outdefault="labels")
103
+ def get_make_canonical(random=False, main_sort_axis="y"):
104
+ """Makes id mask ordered from left to right based on the center of mass."""
105
+ # By convention, instances are in the last channel.
106
+ def _make_canonical(image):
107
+ """Op."""
108
+ instimg = image[..., -1]
109
+
110
+ # Compute binary instance masks. Note, we do not touch 0 and neg. ids.
111
+ ids = tf.unique(tf.reshape(instimg, [-1])).y
112
+ ids = ids[ids > 0]
113
+ n_masks = tf.cast(
114
+ instimg[None, :, :] == ids[:, None, None], tf.int32)
115
+
116
+ if not random:
117
+ f = lambda x: tf.reduce_mean(tf.cast(tf.where(x), tf.float32), axis=0)
118
+ centers = tf.map_fn(f, tf.cast(n_masks, tf.int64), dtype=tf.float32)
119
+ centers = tf.reshape(centers, (tf.shape(centers)[0], 2))
120
+ major = {"y": 0, "x": 1}[main_sort_axis]
121
+ perm = tf.argsort(
122
+ centers[:, 1 - major] +
123
+ tf.cast(tf.shape(instimg)[major], tf.float32) * centers[:, major])
124
+ n_masks = tf.gather(n_masks, perm)
125
+ else:
126
+ n_masks = tf.random.shuffle(n_masks)
127
+
128
+ idx = tf.range(tf.shape(ids)[0])
129
+ can_mask = tf.einsum("chw,c->hw", n_masks, idx + 2) - 1
130
+ # Now, all 0 and neg. ids have collapsed to -1. Thus, we recover 0 id from
131
+ # the original mask.
132
+ can_mask = tf.where(instimg == 0, 0, can_mask)
133
+ return tf.concat([image[..., :-1], can_mask[..., None]], axis=-1)
134
+
135
+ return _make_canonical
136
+
137
+
138
+ @Registry.register("preprocess_ops.inception_box")
139
+ def get_inception_box(
140
+ *, area=(0.05, 1.0), aspect=(0.75, 1.33), min_obj_cover=0.0,
141
+ outkey="box", inkey="image"):
142
+ """Creates an inception style bounding box which can be used to crop."""
143
+ def _inception_box(data):
144
+ _, _, box = tf.image.sample_distorted_bounding_box(
145
+ tf.shape(data[inkey]),
146
+ area_range=area,
147
+ aspect_ratio_range=aspect,
148
+ min_object_covered=min_obj_cover,
149
+ bounding_boxes=(data["objects"]["bbox"][None, :, :]
150
+ if min_obj_cover else tf.zeros([0, 0, 4])),
151
+ use_image_if_no_bounding_boxes=True)
152
+ # bbox is [[[y0,x0,y1,x1]]]
153
+ data[outkey] = (box[0, 0, :2], box[0, 0, 2:] - box[0, 0, :2])
154
+ return data
155
+ return _inception_box
156
+
157
+
158
+ @Registry.register("preprocess_ops.crop_box")
159
+ @utils.InKeyOutKey(with_data=True)
160
+ def get_crop_box(*, boxkey="box"):
161
+ """Crops an image according to bounding box in `boxkey`."""
162
+ def _crop_box(image, data):
163
+ shape = tf.shape(image)[:-1]
164
+ begin, size = data[boxkey]
165
+ begin = tf.cast(begin * tf.cast(shape, tf.float32), tf.int32)
166
+ size = tf.cast(size * tf.cast(shape, tf.float32), tf.int32)
167
+ begin = tf.concat([begin, tf.constant((0,))], axis=0)
168
+ size = tf.concat([size, tf.constant((-1,))], axis=0)
169
+ crop = tf.slice(image, begin, size)
170
+ # Unfortunately, the above operation loses the depth-dimension. So we need
171
+ # to restore it the manual way.
172
+ crop.set_shape([None, None, image.shape[-1]])
173
+ return crop
174
+ return _crop_box
175
+
176
+
177
+ @Registry.register("preprocess_ops.randu")
178
+ def get_randu(key):
179
+ """Creates a random uniform float [0, 1) in `key`."""
180
+ def _randu(data):
181
+ data[key] = tf.random.uniform([])
182
+ return data
183
+ return _randu
184
+
185
+
186
+ @Registry.register("preprocess_ops.det_fliplr")
187
+ @utils.InKeyOutKey(with_data=True)
188
+ def get_det_fliplr(*, randkey="fliplr"):
189
+ """Flips an image horizontally based on `randkey`."""
190
+ # NOTE: we could unify this with regular flip when randkey=None.
191
+ def _det_fliplr(orig_image, data):
192
+ flip_image = tf.image.flip_left_right(orig_image)
193
+ flip = tf.cast(data[randkey] > 0.5, orig_image.dtype)
194
+ return flip_image * flip + orig_image * (1 - flip)
195
+ return _det_fliplr
196
+
197
+
198
+ @Registry.register("preprocess_ops.strong_hash")
199
+ @utils.InKeyOutKey(indefault="tfds_id", outdefault="tfds_id")
200
+ def get_strong_hash():
201
+ """Preprocessing that hashes a string."""
202
+ def _strong_hash(string):
203
+ return tf.strings.to_hash_bucket_strong(
204
+ string,
205
+ np.iinfo(int).max, [3714561454027272724, 8800639020734831960])
206
+ return _strong_hash
Tipsomaly/model/big_vision/pp/proj/uvim/pp_ops_test.py ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ """Tests for pp_ops."""
16
+ import copy
17
+
18
+ from big_vision.pp.proj.uvim import pp_ops as pp
19
+ import numpy as np
20
+ import tensorflow as tf
21
+
22
+
23
+ def get_image_data(dtype=tf.uint8):
24
+ img = tf.random.uniform((640, 320, 3), 0, 255, tf.int32) # Can't ask uint8!?
25
+ return {"image": tf.cast(img, dtype)}
26
+
27
+
28
+ class PreprocessOpsTest(tf.test.TestCase):
29
+
30
+ def tfrun(self, ppfn, data={}): # pylint: disable=dangerous-default-value
31
+ # Run once as standalone, as could happen eg in colab.
32
+ yield {k: np.array(v) for k, v in ppfn(copy.deepcopy(data)).items()}
33
+
34
+ if not data: # tf.data doesn't like completely empty dict...k
35
+ data = {"dummy": 0.0}
36
+
37
+ # And then once again as part of tfdata pipeline.
38
+ # You'd be surprised how much these two differ!
39
+ tfdata = tf.data.Dataset.from_tensors(copy.deepcopy(data))
40
+ for npdata in tfdata.map(ppfn).as_numpy_iterator():
41
+ yield npdata
42
+
43
+ def test_randu(self):
44
+ for output in self.tfrun(pp.get_randu("flip")):
45
+ self.assertEqual(output["flip"].shape, ())
46
+ self.assertAllGreaterEqual(output["flip"], 0.0)
47
+ self.assertAllLessEqual(output["flip"], 1.0)
48
+
49
+ def test_det_flip_lr(self):
50
+ # Test both dtypes to make it can be applied correctly to both.
51
+ for dtype in [tf.uint8, tf.float32]:
52
+ image_data = get_image_data(dtype)
53
+ for out in self.tfrun(pp.get_det_fliplr(randkey="rand"),
54
+ {"rand": 0.1, **image_data}):
55
+ self.assertTrue(np.all(image_data["image"] == out["image"]))
56
+ self.assertEqual(out["image"].dtype, dtype)
57
+ for out in self.tfrun(pp.get_det_fliplr(randkey="rand"),
58
+ {"rand": 0.6, **image_data}):
59
+ self.assertTrue(np.all(image_data["image"][:, ::-1, :] == out["image"]))
60
+ self.assertEqual(out["image"].dtype, dtype)
61
+
62
+ def test_inception_box(self):
63
+ for out in self.tfrun(pp.get_inception_box(), get_image_data()):
64
+ self.assertEqual(out["box"][0].shape, (2,))
65
+ self.assertEqual(out["box"][1].shape, (2,))
66
+
67
+ def test_crop_box(self):
68
+ data = get_image_data()
69
+ data["box"] = (tf.constant([0.5, 0.4]), tf.constant([0.25, 0.3]))
70
+ for out in self.tfrun(pp.get_crop_box(), data):
71
+ self.assertEqual(out["image"].shape, (160, 96, 3))
72
+ self.assertAllEqual(
73
+ data["image"][320:320 + 160, 128:128 + 96],
74
+ out["image"])
75
+
76
+ def test_make_canonical(self):
77
+ orig = np.array([
78
+ [1, 0, 3, 3, -1],
79
+ [1, 0, 3, 3, -1],
80
+ [1, 0, 2, 2, 2],
81
+ [1, 0, 0, -1, -1]
82
+ ], np.int32)[:, :, None]
83
+ expected = np.array([
84
+ [2, 0, 1, 1, -1],
85
+ [2, 0, 1, 1, -1],
86
+ [2, 0, 3, 3, 3],
87
+ [2, 0, 0, -1, -1]
88
+ ], np.int32)[:, :, None]
89
+ for out in self.tfrun(pp.get_make_canonical(), {"labels": orig}):
90
+ self.assertTrue(np.all(out["labels"] == expected))
91
+
92
+ # Test it only affects last channel.
93
+ for out in self.tfrun(pp.get_make_canonical(),
94
+ {"labels": tf.tile(orig, (1, 1, 3))}):
95
+ self.assertAllEqual(out["labels"][..., 0], orig[..., 0])
96
+ self.assertAllEqual(out["labels"][..., 1], orig[..., 0])
97
+ self.assertAllEqual(out["labels"][..., 2], expected[..., 0])
98
+
99
+ def test_nyu_depth(self):
100
+ image = tf.zeros((5, 7, 3), dtype=tf.uint8)
101
+ depth = tf.zeros((5, 7), dtype=tf.float16)
102
+ data = {
103
+ "image": image,
104
+ "depth": depth
105
+ }
106
+ output = pp.get_nyu_depth()(data)
107
+ self.assertEqual(output["image"].shape, (5, 7, 3))
108
+ self.assertEqual(output["image"].dtype, tf.uint8)
109
+ self.assertEqual(output["labels"].shape, (5, 7, 1))
110
+ self.assertEqual(output["labels"].dtype, tf.float32)
111
+
112
+ def test_nyu_eval_crop(self):
113
+ image = tf.zeros((480, 640, 3), dtype=tf.uint8)
114
+ depth = tf.zeros((480, 640), dtype=tf.float16)
115
+ data = {
116
+ "image": image,
117
+ "depth": depth
118
+ }
119
+ data = pp.get_nyu_depth()(data)
120
+ output = pp.get_nyu_eval_crop()(data)
121
+ self.assertEqual(output["image"].shape, (426, 560, 3))
122
+ self.assertEqual(output["image"].dtype, tf.uint8)
123
+ self.assertEqual(output["labels"].shape, (426, 560, 1))
124
+ self.assertEqual(output["labels"].dtype, tf.float32)
125
+
126
+
127
+ if __name__ == "__main__":
128
+ tf.test.main()