Add files using upload-large-folder tool
Browse files- Tipsomaly/model/big_vision/configs/proj/paligemma/transfers/tallyqa.py +191 -0
- Tipsomaly/model/big_vision/configs/proj/paligemma/transfers/textcaps.py +181 -0
- Tipsomaly/model/big_vision/models/__pycache__/__init__.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/models/__pycache__/__init__.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/models/__pycache__/__init__.cpython-39.pyc +0 -0
- Tipsomaly/model/big_vision/models/__pycache__/common.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/models/__pycache__/common.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/models/__pycache__/vit.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/models/__pycache__/vit.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/models/ppp/__init__.py +0 -0
- Tipsomaly/model/big_vision/models/ppp/gemma.py +651 -0
- Tipsomaly/model/big_vision/models/proj/__init__.py +0 -0
- Tipsomaly/model/big_vision/models/proj/cappa/cappa.py +428 -0
- Tipsomaly/model/big_vision/models/proj/clippo/one_tower.py +96 -0
- Tipsomaly/model/big_vision/models/proj/flaxformer/bert.py +94 -0
- Tipsomaly/model/big_vision/models/proj/flaxformer/bert_test.py +77 -0
- Tipsomaly/model/big_vision/models/proj/flaxformer/bert_test_util.py +261 -0
- Tipsomaly/model/big_vision/models/proj/flexi/vit.py +226 -0
- Tipsomaly/model/big_vision/models/proj/flexi/vit_test.py +127 -0
- Tipsomaly/model/big_vision/models/proj/givt/adaptor.py +174 -0
- Tipsomaly/model/big_vision/models/proj/givt/adaptor_test.py +50 -0
- Tipsomaly/model/big_vision/models/proj/givt/cnn.py +376 -0
- Tipsomaly/model/big_vision/models/proj/givt/decode.py +386 -0
- Tipsomaly/model/big_vision/models/proj/givt/decode_test.py +121 -0
- Tipsomaly/model/big_vision/models/proj/givt/givt.py +820 -0
- Tipsomaly/model/big_vision/models/proj/givt/givt_test.py +124 -0
- Tipsomaly/model/big_vision/models/proj/givt/parallel_decode.py +523 -0
- Tipsomaly/model/big_vision/models/proj/givt/parallel_decode_test.py +154 -0
- Tipsomaly/model/big_vision/models/proj/givt/vae.py +94 -0
- Tipsomaly/model/big_vision/models/proj/givt/vit.py +188 -0
- Tipsomaly/model/big_vision/models/proj/image_text/naflex_vit.py +300 -0
- Tipsomaly/model/big_vision/models/proj/image_text/two_towers.py +178 -0
- Tipsomaly/model/big_vision/pp/proj/clippo/pp_ops.py +153 -0
- Tipsomaly/model/big_vision/pp/proj/flaxformer/bert_ops.py +86 -0
- Tipsomaly/model/big_vision/pp/proj/flaxformer/bert_ops_test.py +69 -0
- Tipsomaly/model/big_vision/pp/proj/image_text/__pycache__/ops_naflex.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/pp/proj/image_text/__pycache__/ops_naflex.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/pp/proj/image_text/__pycache__/ops_naflex.cpython-39.pyc +0 -0
- Tipsomaly/model/big_vision/pp/proj/image_text/ops_naflex_test.py +77 -0
- Tipsomaly/model/big_vision/pp/proj/paligemma/__pycache__/ops.cpython-311.pyc +0 -0
- Tipsomaly/model/big_vision/pp/proj/paligemma/__pycache__/ops.cpython-312.pyc +0 -0
- Tipsomaly/model/big_vision/pp/proj/paligemma/__pycache__/ops.cpython-39.pyc +0 -0
- Tipsomaly/model/big_vision/pp/proj/paligemma/ops.py +168 -0
- Tipsomaly/model/big_vision/pp/proj/paligemma/robustness.py +72 -0
- Tipsomaly/model/big_vision/pp/proj/paligemma/sciqa_ops.py +65 -0
- Tipsomaly/model/big_vision/pp/proj/paligemma/segmentation.py +160 -0
- Tipsomaly/model/big_vision/pp/proj/paligemma/video.py +103 -0
- Tipsomaly/model/big_vision/pp/proj/paligemma/widgetcap.py +36 -0
- Tipsomaly/model/big_vision/pp/proj/uvim/pp_ops.py +206 -0
- 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()
|