Repository navigation
Expand file tree
/
Copy pathutils.py
More file actions
137 lines (116 loc) · 5.3 KB
/
Copy pathutils.py
File metadata and controls
137 lines (116 loc) · 5.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import os
from torchvision.datasets.utils import download_url
import torch
import torchvision.models as torchvision_models
import timm
import math
import warnings
# code from SiT repository
pretrained_models = {'last.pt'}
@torch.no_grad()
def load_encoders(enc_type, device, resolution=256, dinov3_repo=None):
assert (resolution == 256) or (resolution == 512)
enc_names = enc_type.split(',')
encoders, architectures, encoder_types = [], [], []
for enc_name in enc_names:
encoder_type, architecture, model_config = enc_name.split('-')
# Currently, we only support 512x512 experiments with DINOv2 encoders.
if resolution == 512:
if encoder_type != 'dinov2' and encoder_type != 'dinov3':
raise NotImplementedError(
"Currently, we only support 512x512 experiments with DINOv2 encoders."
)
architectures.append(architecture)
encoder_types.append(encoder_type)
if 'dinov3' in encoder_type:
import timm
REPO_DIR = dinov3_repo or os.environ.get('DINOV3_REPO')
if REPO_DIR is None:
raise ValueError(
"DINOv3-Sat teacher required for GSA. Pass --dinov3-repo or set $DINOV3_REPO "
"to a local clone of facebookresearch/dinov3 containing the sat493m weights."
)
if model_config == '7b':
encoder = torch.hub.load(REPO_DIR, 'dinov3_vit7b16', source='local',
weights='dinov3_vit7b16_pretrain_sat493m-a6675841.pth')
elif model_config == 'l':
encoder = torch.hub.load(REPO_DIR, 'dinov3_vitl16', source='local',
weights='dinov3_vitl16_pretrain_sat493m-eadcf0ff.pth')
del encoder.head
encoder.head = torch.nn.Identity()
encoder = encoder.to(device)
encoder.eval()
elif 'dinov2' in encoder_type:
import timm
if 'reg' in encoder_type:
encoder = torch.hub.load('facebookresearch/dinov2', f'dinov2_vit{model_config}14_reg')
else:
encoder = torch.hub.load('facebookresearch/dinov2', f'dinov2_vit{model_config}14')
del encoder.head
patch_resolution = 16 * (resolution // 256)
encoder.pos_embed.data = timm.layers.pos_embed.resample_abs_pos_embed(
encoder.pos_embed.data, [patch_resolution, patch_resolution],
)
encoder.head = torch.nn.Identity()
encoder = encoder.to(device)
encoder.eval()
elif 'dinov1' == encoder_type:
import timm
from models import dinov1
encoder = dinov1.vit_base()
ckpt = torch.load(f'./ckpts/dinov1_vit{model_config}.pth')
if 'pos_embed' in ckpt.keys():
ckpt['pos_embed'] = timm.layers.pos_embed.resample_abs_pos_embed(
ckpt['pos_embed'], [16, 16],
)
del encoder.head
encoder.head = torch.nn.Identity()
encoder.load_state_dict(ckpt, strict=True)
encoder = encoder.to(device)
encoder.forward_features = encoder.forward
encoder.eval()
encoders.append(encoder)
return encoders, encoder_types, architectures
def _no_grad_trunc_normal_(tensor, mean, std, a, b):
# Cut & paste from PyTorch official master until it's in a few official releases - RW
# Method based on https://people.sc.fsu.edu/~jburkardt/presentations/truncated_normal.pdf
def norm_cdf(x):
# Computes standard normal cumulative distribution function
return (1. + math.erf(x / math.sqrt(2.))) / 2.
if (mean < a - 2 * std) or (mean > b + 2 * std):
warnings.warn("mean is more than 2 std from [a, b] in nn.init.trunc_normal_. "
"The distribution of values may be incorrect.",
stacklevel=2)
with torch.no_grad():
# Values are generated by using a truncated uniform distribution and
# then using the inverse CDF for the normal distribution.
# Get upper and lower cdf values
l = norm_cdf((a - mean) / std)
u = norm_cdf((b - mean) / std)
# Uniformly fill tensor with values from [l, u], then translate to
# [2l-1, 2u-1].
tensor.uniform_(2 * l - 1, 2 * u - 1)
# Use inverse cdf transform for normal distribution to get truncated
# standard normal
tensor.erfinv_()
# Transform to proper mean, std
tensor.mul_(std * math.sqrt(2.))
tensor.add_(mean)
# Clamp to ensure it's in the proper range
tensor.clamp_(min=a, max=b)
return tensor
def trunc_normal_(tensor, mean=0., std=1., a=-2., b=2.):
return _no_grad_trunc_normal_(tensor, mean, std, a, b)
def load_legacy_checkpoints(state_dict, encoder_depth):
new_state_dict = dict()
for key, value in state_dict.items():
if 'decoder_blocks' in key:
parts = key.split('.')
new_idx = int(parts[1]) + encoder_depth
parts[0] = 'blocks'
parts[1] = str(new_idx)
new_key = '.'.join(parts)
new_state_dict[new_key] = value
else:
new_state_dict[key] = value
return new_state_dict