|
from itertools import repeat |
|
import collections.abc |
|
import logging |
|
import math |
|
import numpy as np |
|
|
|
import torch |
|
from torch import nn as nn |
|
from torchvision.ops.misc import FrozenBatchNorm2d |
|
import torch.nn.functional as F |
|
|
|
|
|
def resize_clip_pos_embed(state_dict, model, interpolation: str = 'bicubic', seq_dim=1): |
|
|
|
old_pos_embed = state_dict.get('visual.positional_embedding', None) |
|
if old_pos_embed is None or not hasattr(model.visual, 'grid_size'): |
|
return |
|
grid_size = to_2tuple(model.visual.grid_size) |
|
extra_tokens = 1 |
|
new_seq_len = grid_size[0] * grid_size[1] + extra_tokens |
|
if new_seq_len == old_pos_embed.shape[0]: |
|
return |
|
|
|
if extra_tokens: |
|
pos_emb_tok, pos_emb_img = old_pos_embed[:extra_tokens], old_pos_embed[extra_tokens:] |
|
else: |
|
pos_emb_tok, pos_emb_img = None, old_pos_embed |
|
old_grid_size = to_2tuple(int(math.sqrt(len(pos_emb_img)))) |
|
|
|
logging.info('Resizing position embedding grid-size from %s to %s', old_grid_size, grid_size) |
|
pos_emb_img = pos_emb_img.reshape(1, old_grid_size[0], old_grid_size[1], -1).permute(0, 3, 1, 2) |
|
pos_emb_img = F.interpolate( |
|
pos_emb_img, |
|
size=grid_size, |
|
mode=interpolation, |
|
align_corners=True, |
|
) |
|
pos_emb_img = pos_emb_img.permute(0, 2, 3, 1).reshape(1, grid_size[0] * grid_size[1], -1)[0] |
|
if pos_emb_tok is not None: |
|
new_pos_embed = torch.cat([pos_emb_tok, pos_emb_img], dim=0) |
|
else: |
|
new_pos_embed = pos_emb_img |
|
state_dict['visual.positional_embedding'] = new_pos_embed |
|
|
|
|
|
def resize_visual_pos_embed(state_dict, model, interpolation: str = 'bicubic', seq_dim=1): |
|
|
|
old_pos_embed = state_dict.get('positional_embedding', None) |
|
if old_pos_embed is None or not hasattr(model.visual, 'grid_size'): |
|
return |
|
grid_size = to_2tuple(model.visual.grid_size) |
|
extra_tokens = 1 |
|
new_seq_len = grid_size[0] * grid_size[1] + extra_tokens |
|
if new_seq_len == old_pos_embed.shape[0]: |
|
return |
|
|
|
if extra_tokens: |
|
pos_emb_tok, pos_emb_img = old_pos_embed[:extra_tokens], old_pos_embed[extra_tokens:] |
|
else: |
|
pos_emb_tok, pos_emb_img = None, old_pos_embed |
|
old_grid_size = to_2tuple(int(math.sqrt(len(pos_emb_img)))) |
|
|
|
logging.info('Resizing position embedding grid-size from %s to %s', old_grid_size, grid_size) |
|
pos_emb_img = pos_emb_img.reshape(1, old_grid_size[0], old_grid_size[1], -1).permute(0, 3, 1, 2) |
|
pos_emb_img = F.interpolate( |
|
pos_emb_img, |
|
size=grid_size, |
|
mode=interpolation, |
|
align_corners=True, |
|
) |
|
pos_emb_img = pos_emb_img.permute(0, 2, 3, 1).reshape(1, grid_size[0] * grid_size[1], -1)[0] |
|
if pos_emb_tok is not None: |
|
new_pos_embed = torch.cat([pos_emb_tok, pos_emb_img], dim=0) |
|
else: |
|
new_pos_embed = pos_emb_img |
|
state_dict['positional_embedding'] = new_pos_embed |
|
|
|
def resize_evaclip_pos_embed(state_dict, model, interpolation: str = 'bicubic', seq_dim=1): |
|
all_keys = list(state_dict.keys()) |
|
|
|
if 'visual.pos_embed' in state_dict: |
|
pos_embed_checkpoint = state_dict['visual.pos_embed'] |
|
embedding_size = pos_embed_checkpoint.shape[-1] |
|
num_patches = model.visual.patch_embed.num_patches |
|
num_extra_tokens = model.visual.pos_embed.shape[-2] - num_patches |
|
|
|
orig_size = int((pos_embed_checkpoint.shape[-2] - num_extra_tokens) ** 0.5) |
|
|
|
new_size = int(num_patches ** 0.5) |
|
|
|
if orig_size != new_size: |
|
print("Position interpolate from %dx%d to %dx%d" % (orig_size, orig_size, new_size, new_size)) |
|
extra_tokens = pos_embed_checkpoint[:, :num_extra_tokens] |
|
|
|
pos_tokens = pos_embed_checkpoint[:, num_extra_tokens:] |
|
pos_tokens = pos_tokens.reshape(-1, orig_size, orig_size, embedding_size).permute(0, 3, 1, 2) |
|
pos_tokens = torch.nn.functional.interpolate( |
|
pos_tokens, size=(new_size, new_size), mode='bicubic', align_corners=False) |
|
pos_tokens = pos_tokens.permute(0, 2, 3, 1).flatten(1, 2) |
|
new_pos_embed = torch.cat((extra_tokens, pos_tokens), dim=1) |
|
state_dict['visual.pos_embed'] = new_pos_embed |
|
|
|
patch_embed_proj = state_dict['visual.patch_embed.proj.weight'] |
|
patch_size = model.visual.patch_embed.patch_size |
|
state_dict['visual.patch_embed.proj.weight'] = torch.nn.functional.interpolate( |
|
patch_embed_proj.float(), size=patch_size, mode='bicubic', align_corners=False) |
|
|
|
|
|
def resize_eva_pos_embed(state_dict, model, interpolation: str = 'bicubic', seq_dim=1): |
|
all_keys = list(state_dict.keys()) |
|
|
|
if 'pos_embed' in state_dict: |
|
pos_embed_checkpoint = state_dict['pos_embed'] |
|
embedding_size = pos_embed_checkpoint.shape[-1] |
|
num_patches = model.visual.patch_embed.num_patches |
|
num_extra_tokens = model.visual.pos_embed.shape[-2] - num_patches |
|
|
|
orig_size = int((pos_embed_checkpoint.shape[-2] - num_extra_tokens) ** 0.5) |
|
|
|
new_size = int(num_patches ** 0.5) |
|
|
|
if orig_size != new_size: |
|
print("Position interpolate from %dx%d to %dx%d" % (orig_size, orig_size, new_size, new_size)) |
|
extra_tokens = pos_embed_checkpoint[:, :num_extra_tokens] |
|
|
|
pos_tokens = pos_embed_checkpoint[:, num_extra_tokens:] |
|
pos_tokens = pos_tokens.reshape(-1, orig_size, orig_size, embedding_size).permute(0, 3, 1, 2) |
|
pos_tokens = torch.nn.functional.interpolate( |
|
pos_tokens, size=(new_size, new_size), mode='bicubic', align_corners=False) |
|
pos_tokens = pos_tokens.permute(0, 2, 3, 1).flatten(1, 2) |
|
new_pos_embed = torch.cat((extra_tokens, pos_tokens), dim=1) |
|
state_dict['pos_embed'] = new_pos_embed |
|
|
|
patch_embed_proj = state_dict['patch_embed.proj.weight'] |
|
patch_size = model.visual.patch_embed.patch_size |
|
state_dict['patch_embed.proj.weight'] = torch.nn.functional.interpolate( |
|
patch_embed_proj.float(), size=patch_size, mode='bicubic', align_corners=False) |
|
|
|
|
|
def resize_rel_pos_embed(state_dict, model, interpolation: str = 'bicubic', seq_dim=1): |
|
all_keys = list(state_dict.keys()) |
|
for key in all_keys: |
|
if "relative_position_index" in key: |
|
state_dict.pop(key) |
|
|
|
if "relative_position_bias_table" in key: |
|
rel_pos_bias = state_dict[key] |
|
src_num_pos, num_attn_heads = rel_pos_bias.size() |
|
dst_num_pos, _ = model.visual.state_dict()[key].size() |
|
dst_patch_shape = model.visual.patch_embed.patch_shape |
|
if dst_patch_shape[0] != dst_patch_shape[1]: |
|
raise NotImplementedError() |
|
num_extra_tokens = dst_num_pos - (dst_patch_shape[0] * 2 - 1) * (dst_patch_shape[1] * 2 - 1) |
|
src_size = int((src_num_pos - num_extra_tokens) ** 0.5) |
|
dst_size = int((dst_num_pos - num_extra_tokens) ** 0.5) |
|
if src_size != dst_size: |
|
print("Position interpolate for %s from %dx%d to %dx%d" % ( |
|
key, src_size, src_size, dst_size, dst_size)) |
|
extra_tokens = rel_pos_bias[-num_extra_tokens:, :] |
|
rel_pos_bias = rel_pos_bias[:-num_extra_tokens, :] |
|
|
|
def geometric_progression(a, r, n): |
|
return a * (1.0 - r ** n) / (1.0 - r) |
|
|
|
left, right = 1.01, 1.5 |
|
while right - left > 1e-6: |
|
q = (left + right) / 2.0 |
|
gp = geometric_progression(1, q, src_size // 2) |
|
if gp > dst_size // 2: |
|
right = q |
|
else: |
|
left = q |
|
|
|
|
|
|
|
|
|
dis = [] |
|
cur = 1 |
|
for i in range(src_size // 2): |
|
dis.append(cur) |
|
cur += q ** (i + 1) |
|
|
|
r_ids = [-_ for _ in reversed(dis)] |
|
|
|
x = r_ids + [0] + dis |
|
y = r_ids + [0] + dis |
|
|
|
t = dst_size // 2.0 |
|
dx = np.arange(-t, t + 0.1, 1.0) |
|
dy = np.arange(-t, t + 0.1, 1.0) |
|
|
|
print("Original positions = %s" % str(x)) |
|
print("Target positions = %s" % str(dx)) |
|
|
|
all_rel_pos_bias = [] |
|
|
|
for i in range(num_attn_heads): |
|
z = rel_pos_bias[:, i].view(src_size, src_size).float().numpy() |
|
f = F.interpolate.interp2d(x, y, z, kind='cubic') |
|
all_rel_pos_bias.append( |
|
torch.Tensor(f(dx, dy)).contiguous().view(-1, 1).to(rel_pos_bias.device)) |
|
|
|
rel_pos_bias = torch.cat(all_rel_pos_bias, dim=-1) |
|
|
|
new_rel_pos_bias = torch.cat((rel_pos_bias, extra_tokens), dim=0) |
|
state_dict[key] = new_rel_pos_bias |
|
|
|
|
|
if 'pos_embed' in state_dict: |
|
pos_embed_checkpoint = state_dict['pos_embed'] |
|
embedding_size = pos_embed_checkpoint.shape[-1] |
|
num_patches = model.visual.patch_embed.num_patches |
|
num_extra_tokens = model.visual.pos_embed.shape[-2] - num_patches |
|
|
|
orig_size = int((pos_embed_checkpoint.shape[-2] - num_extra_tokens) ** 0.5) |
|
|
|
new_size = int(num_patches ** 0.5) |
|
|
|
if orig_size != new_size: |
|
print("Position interpolate from %dx%d to %dx%d" % (orig_size, orig_size, new_size, new_size)) |
|
extra_tokens = pos_embed_checkpoint[:, :num_extra_tokens] |
|
|
|
pos_tokens = pos_embed_checkpoint[:, num_extra_tokens:] |
|
pos_tokens = pos_tokens.reshape(-1, orig_size, orig_size, embedding_size).permute(0, 3, 1, 2) |
|
pos_tokens = torch.nn.functional.interpolate( |
|
pos_tokens, size=(new_size, new_size), mode='bicubic', align_corners=False) |
|
pos_tokens = pos_tokens.permute(0, 2, 3, 1).flatten(1, 2) |
|
new_pos_embed = torch.cat((extra_tokens, pos_tokens), dim=1) |
|
state_dict['pos_embed'] = new_pos_embed |
|
|
|
patch_embed_proj = state_dict['patch_embed.proj.weight'] |
|
patch_size = model.visual.patch_embed.patch_size |
|
state_dict['patch_embed.proj.weight'] = torch.nn.functional.interpolate( |
|
patch_embed_proj.float(), size=patch_size, mode='bicubic', align_corners=False) |
|
|
|
|
|
def freeze_batch_norm_2d(module, module_match={}, name=''): |
|
""" |
|
Converts all `BatchNorm2d` and `SyncBatchNorm` layers of provided module into `FrozenBatchNorm2d`. If `module` is |
|
itself an instance of either `BatchNorm2d` or `SyncBatchNorm`, it is converted into `FrozenBatchNorm2d` and |
|
returned. Otherwise, the module is walked recursively and submodules are converted in place. |
|
|
|
Args: |
|
module (torch.nn.Module): Any PyTorch module. |
|
module_match (dict): Dictionary of full module names to freeze (all if empty) |
|
name (str): Full module name (prefix) |
|
|
|
Returns: |
|
torch.nn.Module: Resulting module |
|
|
|
Inspired by https://github.com/pytorch/pytorch/blob/a5895f85be0f10212791145bfedc0261d364f103/torch/nn/modules/batchnorm.py#L762 |
|
""" |
|
res = module |
|
is_match = True |
|
if module_match: |
|
is_match = name in module_match |
|
if is_match and isinstance(module, (nn.modules.batchnorm.BatchNorm2d, nn.modules.batchnorm.SyncBatchNorm)): |
|
res = FrozenBatchNorm2d(module.num_features) |
|
res.num_features = module.num_features |
|
res.affine = module.affine |
|
if module.affine: |
|
res.weight.data = module.weight.data.clone().detach() |
|
res.bias.data = module.bias.data.clone().detach() |
|
res.running_mean.data = module.running_mean.data |
|
res.running_var.data = module.running_var.data |
|
res.eps = module.eps |
|
else: |
|
for child_name, child in module.named_children(): |
|
full_child_name = '.'.join([name, child_name]) if name else child_name |
|
new_child = freeze_batch_norm_2d(child, module_match, full_child_name) |
|
if new_child is not child: |
|
res.add_module(child_name, new_child) |
|
return res |
|
|
|
|
|
|
|
def _ntuple(n): |
|
def parse(x): |
|
if isinstance(x, collections.abc.Iterable): |
|
return x |
|
return tuple(repeat(x, n)) |
|
return parse |
|
|
|
|
|
to_1tuple = _ntuple(1) |
|
to_2tuple = _ntuple(2) |
|
to_3tuple = _ntuple(3) |
|
to_4tuple = _ntuple(4) |
|
to_ntuple = lambda n, x: _ntuple(n)(x) |
|
|
|
|
|
def is_logging(args): |
|
def is_global_master(args): |
|
return args.rank == 0 |
|
|
|
def is_local_master(args): |
|
return args.local_rank == 0 |
|
|
|
def is_master(args, local=False): |
|
return is_local_master(args) if local else is_global_master(args) |
|
return is_master |
|
|
|
|
|
class AllGather(torch.autograd.Function): |
|
"""An autograd function that performs allgather on a tensor. |
|
Performs all_gather operation on the provided tensors. |
|
*** Warning ***: torch.distributed.all_gather has no gradient. |
|
""" |
|
|
|
@staticmethod |
|
def forward(ctx, tensor, rank, world_size): |
|
tensors_gather = [torch.empty_like(tensor) for _ in range(world_size)] |
|
torch.distributed.all_gather(tensors_gather, tensor) |
|
ctx.rank = rank |
|
ctx.batch_size = tensor.shape[0] |
|
return torch.cat(tensors_gather, 0) |
|
|
|
@staticmethod |
|
def backward(ctx, grad_output): |
|
return ( |
|
grad_output[ctx.batch_size * ctx.rank: ctx.batch_size * (ctx.rank + 1)], |
|
None, |
|
None |
|
) |
|
|
|
allgather = AllGather.apply |