yuxi-liu-wired commited on
Commit
b65a332
1 Parent(s): ae78120
CSD/CSD/loss_utils.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torchvision.transforms as transforms
2
+ import torchvision.transforms.functional as F
3
+ import numpy as np
4
+ import torch
5
+ from torch import nn
6
+ np.random.seed(0)
7
+
8
+
9
+ class GaussianBlur(object):
10
+ """blur a single image on CPU"""
11
+ def __init__(self, kernel_size):
12
+ radias = kernel_size // 2
13
+ kernel_size = radias * 2 + 1
14
+ self.blur_h = nn.Conv2d(3, 3, kernel_size=(kernel_size, 1),
15
+ stride=1, padding=0, bias=False, groups=3)
16
+ self.blur_v = nn.Conv2d(3, 3, kernel_size=(1, kernel_size),
17
+ stride=1, padding=0, bias=False, groups=3)
18
+ self.k = kernel_size
19
+ self.r = radias
20
+
21
+ self.blur = nn.Sequential(
22
+ nn.ReflectionPad2d(radias),
23
+ self.blur_h,
24
+ self.blur_v
25
+ )
26
+
27
+ self.pil_to_tensor = transforms.ToTensor()
28
+ self.tensor_to_pil = transforms.ToPILImage()
29
+
30
+ def __call__(self, img):
31
+ img = self.pil_to_tensor(img).unsqueeze(0)
32
+
33
+ sigma = np.random.uniform(0.1, 2.0)
34
+ x = np.arange(-self.r, self.r + 1)
35
+ x = np.exp(-np.power(x, 2) / (2 * sigma * sigma))
36
+ x = x / x.sum()
37
+ x = torch.from_numpy(x).view(1, -1).repeat(3, 1)
38
+
39
+ self.blur_h.weight.data.copy_(x.view(3, 1, self.k, 1))
40
+ self.blur_v.weight.data.copy_(x.view(3, 1, 1, self.k))
41
+
42
+ with torch.no_grad():
43
+ img = self.blur(img)
44
+ img = img.squeeze()
45
+
46
+ img = self.tensor_to_pil(img)
47
+
48
+ return
49
+
50
+
51
+ s=1
52
+ size = 224
53
+
54
+ normalize = transforms.Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711))
55
+
56
+ transforms_branch0 = transforms.Compose([
57
+ transforms.Resize(size=size, interpolation=F.InterpolationMode.BICUBIC),
58
+ transforms.CenterCrop(size),
59
+ transforms.ToTensor(),
60
+ normalize,
61
+ ])
62
+
63
+ transforms_branch1 = transforms.Compose([
64
+ transforms.RandomResizedCrop(size, interpolation=F.InterpolationMode.BICUBIC),
65
+ transforms.RandomHorizontalFlip(),
66
+ transforms.RandomVerticalFlip(p=0.3),
67
+ transforms.RandomRotation(degrees=np.random.choice([0,90,180,270])),
68
+ transforms.ToTensor(),
69
+ normalize,
70
+ ])
71
+
72
+ color_jitter = transforms.ColorJitter(0.8 * s, 0.8 * s, 0.8 * s, 0.2 * s)
73
+ transforms_branch2 = transforms.Compose([
74
+ # transforms.RandomResizedCrop(size=size, interpolation=F.InterpolationMode.BICUBIC),
75
+ transforms.Resize(size=size, interpolation=F.InterpolationMode.BICUBIC),
76
+ transforms.CenterCrop(size),
77
+ transforms.RandomHorizontalFlip(),
78
+ transforms.RandomApply([transforms.ColorJitter(brightness=0.5, contrast=0.5,
79
+ saturation=0.5,hue=0.1)
80
+ ], p=0.6),
81
+ transforms.RandomApply([transforms.RandomInvert(),transforms.RandomGrayscale(), transforms.GaussianBlur(kernel_size=(5,5), sigma=(0.1, 4))], p=0.8),
82
+ # GaussianBlur(kernel_size=int(0.1 * size)),
83
+ transforms.ToTensor(),
84
+ normalize
85
+ ])
86
+
87
+
88
+ class ContrastiveTransformations(object):
89
+
90
+ def __init__(self, transforms_b0, transforms_b1,transforms_b2):
91
+ self.transforms_b0 = transforms_b0
92
+ self.transforms_b1 = transforms_b1
93
+ self.transforms_b2 = transforms_b2
94
+
95
+ def __call__(self, x):
96
+ return [self.transforms_b0(x), self.transforms_b1(x), self.transforms_b2(x)]
CSD/CSD/losses.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Author: Yonglong Tian (yonglong@mit.edu)
3
+ Date: May 07, 2020
4
+ Code from https://github.com/HobbitLong/SupContrast/blob/master/losses.py
5
+ """
6
+ from __future__ import print_function
7
+
8
+ import torch
9
+ import torch.nn as nn
10
+
11
+
12
+ class SupConLoss(nn.Module):
13
+ """Supervised Contrastive Learning: https://arxiv.org/pdf/2004.11362.pdf.
14
+ It also supports the unsupervised contrastive loss in SimCLR"""
15
+ def __init__(self, temperature=0.07, contrast_mode='all',
16
+ base_temperature=1.0):
17
+ super(SupConLoss, self).__init__()
18
+ self.temperature = temperature
19
+ self.contrast_mode = contrast_mode
20
+ self.base_temperature = base_temperature
21
+
22
+ def forward(self, features, labels=None, mask=None):
23
+ """Compute loss for model. If both `labels` and `mask` are None,
24
+ it degenerates to SimCLR unsupervised loss:
25
+ https://arxiv.org/pdf/2002.05709.pdf
26
+
27
+ Args:
28
+ features: hidden vector of shape [bsz, n_views, ...].
29
+ labels: ground truth of shape [bsz].
30
+ mask: contrastive mask of shape [bsz, bsz], mask_{i,j}=1 if sample j
31
+ has the same class as sample i. Can be asymmetric.
32
+ Returns:
33
+ A loss scalar.
34
+ """
35
+ device = (torch.device('cuda')
36
+ if features.is_cuda
37
+ else torch.device('cpu'))
38
+
39
+ if len(features.shape) < 3:
40
+ raise ValueError('`features` needs to be [bsz, n_views, ...],'
41
+ 'at least 3 dimensions are required')
42
+ if len(features.shape) > 3:
43
+ features = features.view(features.shape[0], features.shape[1], -1)
44
+
45
+ batch_size = features.shape[0]
46
+ if labels is not None and mask is not None:
47
+ raise ValueError('Cannot define both `labels` and `mask`')
48
+ elif labels is None and mask is None:
49
+ mask = torch.eye(batch_size, dtype=torch.float32).to(device)
50
+ elif labels is not None:
51
+ labels = labels.contiguous().view(-1, 1)
52
+ if labels.shape[0] != batch_size:
53
+ raise ValueError('Num of labels does not match num of features')
54
+ mask = torch.eq(labels, labels.T).float().to(device)
55
+ else:
56
+ mask = mask.float().to(device)
57
+
58
+ contrast_count = features.shape[1]
59
+ contrast_feature = torch.cat(torch.unbind(features, dim=1), dim=0)
60
+ if self.contrast_mode == 'one':
61
+ anchor_feature = features[:, 0]
62
+ anchor_count = 1
63
+ elif self.contrast_mode == 'all':
64
+ anchor_feature = contrast_feature
65
+ anchor_count = contrast_count
66
+ else:
67
+ raise ValueError('Unknown mode: {}'.format(self.contrast_mode))
68
+
69
+ anchor_dot_contrast = torch.div(
70
+ torch.matmul(anchor_feature, contrast_feature.T),
71
+ self.temperature)
72
+ # for numerical stability
73
+ logits_max, _ = torch.max(anchor_dot_contrast, dim=1, keepdim=True)
74
+ logits = anchor_dot_contrast - logits_max.detach()
75
+
76
+ # tile mask
77
+ mask = mask.repeat(anchor_count, contrast_count)
78
+ # mask-out self-contrast cases
79
+ logits_mask = torch.scatter(
80
+ torch.ones_like(mask),
81
+ 1,
82
+ torch.arange(batch_size * anchor_count).view(-1, 1).to(device),
83
+ 0
84
+ )
85
+ mask = mask * logits_mask
86
+
87
+ # compute log_prob
88
+ exp_logits = torch.exp(logits) * logits_mask
89
+ log_prob = logits - torch.log(exp_logits.sum(1, keepdim=True) + 1e-6) # NOTE: modified based on https://github.com/HobbitLong/SupContrast/issues/104
90
+
91
+ # compute mean of log-likelihood over positive, adding a small value in case mask row is 0
92
+ mean_log_prob_pos = (mask * log_prob).sum(1) / (mask.sum(1) + 1e-6)
93
+
94
+ # loss
95
+ loss = - (self.temperature / self.base_temperature) * mean_log_prob_pos
96
+ loss = loss.view(anchor_count, batch_size).mean()
97
+
98
+ return loss
99
+
CSD/CSD/model.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import clip
4
+ import copy
5
+ from torch.autograd import Function
6
+
7
+
8
+ from .utils import convert_weights_float
9
+
10
+
11
+ class ReverseLayerF(Function):
12
+
13
+ @staticmethod
14
+ def forward(ctx, x, alpha):
15
+ ctx.alpha = alpha
16
+
17
+ return x.view_as(x)
18
+
19
+ @staticmethod
20
+ def backward(ctx, grad_output):
21
+ output = grad_output.neg() * ctx.alpha
22
+
23
+ return output, None
24
+
25
+
26
+ ## taken from https://github.com/moein-shariatnia/OpenAI-CLIP/blob/master/modules.py
27
+ class ProjectionHead(nn.Module):
28
+ def __init__(
29
+ self,
30
+ embedding_dim,
31
+ projection_dim,
32
+ dropout=0
33
+ ):
34
+ super().__init__()
35
+ self.projection = nn.Linear(embedding_dim, projection_dim)
36
+ self.gelu = nn.GELU()
37
+ self.fc = nn.Linear(projection_dim, projection_dim)
38
+ self.dropout = nn.Dropout(dropout)
39
+ self.layer_norm = nn.LayerNorm(projection_dim)
40
+
41
+ def forward(self, x):
42
+ projected = self.projection(x)
43
+ x = self.gelu(projected)
44
+ x = self.fc(x)
45
+ x = self.dropout(x)
46
+ x = x + projected
47
+ x = self.layer_norm(x)
48
+ return x
49
+
50
+
51
+ def init_weights(m): # TODO: do we need init for layernorm?
52
+ if isinstance(m, nn.Linear):
53
+ torch.nn.init.xavier_uniform_(m.weight)
54
+ if m.bias is not None:
55
+ nn.init.normal_(m.bias, std=1e-6)
56
+
57
+
58
+ class CSD_CLIP(nn.Module):
59
+ """backbone + projection head"""
60
+ def __init__(self, name='vit_large',content_proj_head='default'):
61
+ super(CSD_CLIP, self).__init__()
62
+ self.content_proj_head = content_proj_head
63
+ if name == 'vit_large':
64
+ clipmodel, _ = clip.load("ViT-L/14")
65
+ self.backbone = clipmodel.visual
66
+ self.embedding_dim = 1024
67
+ elif name == 'vit_base':
68
+ clipmodel, _ = clip.load("ViT-B/16")
69
+ self.backbone = clipmodel.visual
70
+ self.embedding_dim = 768
71
+ self.feat_dim = 512
72
+ else:
73
+ raise Exception('This model is not implemented')
74
+
75
+ convert_weights_float(self.backbone)
76
+ self.last_layer_style = copy.deepcopy(self.backbone.proj)
77
+ if content_proj_head == 'custom':
78
+ self.last_layer_content = ProjectionHead(self.embedding_dim,self.feat_dim)
79
+ self.last_layer_content.apply(init_weights)
80
+
81
+ else:
82
+ self.last_layer_content = copy.deepcopy(self.backbone.proj)
83
+
84
+ self.backbone.proj = None
85
+
86
+ @property
87
+ def dtype(self):
88
+ return self.backbone.conv1.weight.dtype
89
+
90
+ def forward(self, input_data, alpha=None):
91
+
92
+ feature = self.backbone(input_data)
93
+
94
+ if alpha is not None:
95
+ reverse_feature = ReverseLayerF.apply(feature, alpha)
96
+ else:
97
+ reverse_feature = feature
98
+
99
+ style_output = feature @ self.last_layer_style
100
+ style_output = nn.functional.normalize(style_output, dim=1, p=2)
101
+
102
+ # if alpha is not None:
103
+ if self.content_proj_head == 'custom':
104
+ content_output = self.last_layer_content(reverse_feature)
105
+ else:
106
+ content_output = reverse_feature @ self.last_layer_content
107
+ content_output = nn.functional.normalize(content_output, dim=1, p=2)
108
+ return feature, content_output, style_output
CSD/CSD/train_csd.py ADDED
@@ -0,0 +1,496 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ import argparse
4
+ import json
5
+ import math
6
+ import os
7
+ import pathlib
8
+ import sys
9
+ import time
10
+ import datetime
11
+ import numpy as np
12
+ import copy
13
+ import torch
14
+ import torch.backends.cudnn as cudnn
15
+ import torch.nn as nn
16
+ import torch.nn.parallel
17
+ import torch.optim
18
+ import torch.utils.data
19
+ import torch.utils.data.distributed
20
+ from pathlib import Path
21
+
22
+ sys.path.insert(0, str(pathlib.Path(__file__).parent.resolve()))
23
+
24
+ from CSD import utils
25
+ from data.wikiart import WikiArtTrain
26
+ from data.laion import LAION, LAIONDedup
27
+ from CSD.loss_utils import ContrastiveTransformations, transforms_branch0, transforms_branch1, transforms_branch2
28
+ from CSD.model import CSD_CLIP
29
+ from CSD.losses import SupConLoss
30
+
31
+
32
+ def get_args_parser():
33
+
34
+ parser = argparse.ArgumentParser('CSD', add_help=False)
35
+
36
+ # Model
37
+ parser.add_argument("-a","--arch",default='vit_base', type=str)
38
+
39
+ # Data
40
+ parser.add_argument('--train_set', default='wikiart', # 'wikiart' or 'laion'
41
+ help='Wiki art data path')
42
+ parser.add_argument('--train_path', required=True,
43
+ help='Wiki art data path')
44
+ parser.add_argument('--train_anno_path',
45
+ default='-projects/diffusion_rep/data/laion_style_subset',
46
+ help='Annotation dir, used only for LAION')
47
+ parser.add_argument("--min_images_per_label", default=1, type=int,
48
+ help="minimum images for a label (used only for laion)")
49
+ parser.add_argument("--max_images_per_label", default=100000, type=int,
50
+ help="minimum images for a label (used only for laion)")
51
+
52
+ parser.add_argument('--eval_set', default='wikiart', # 'domainnet' or 'wikiart'
53
+ help='Wiki art data path')
54
+ parser.add_argument('--eval_path',required=True,
55
+ help='Path to query dataset.')
56
+ parser.add_argument("--maxsize", default=512, type=int,
57
+ help="maximum size of the val dataset to be used")
58
+
59
+ # Optimization
60
+ parser.add_argument( "--use_fp16", action="store_true",
61
+ help="use fp16")
62
+ parser.add_argument( "--use_distributed_loss", action="store_true",
63
+ help="use distributed loss")
64
+ parser.add_argument('--clip_grad', type=float, default=3.0,
65
+ help="""Maximal parameter gradient norm if using
66
+ gradient clipping. Clipping with norm .3 ~ 1.0 can
67
+ help optimization for larger ViT architectures.
68
+ 0 for disabling.""")
69
+ parser.add_argument("--iters", default=100000, type=int, # default: eval only
70
+ help="number of total iterations to run")
71
+ parser.add_argument("-b", "--batch_size_per_gpu", default=64, type=int,
72
+ help="batch size per GPU (default: 64)")
73
+ parser.add_argument("--lr", "--learning_rate", default=0.003, type=float,
74
+ help="learning rate", dest="lr",)
75
+ parser.add_argument("--lr_bb", "--learning_rate_bb", default=0.0001, type=float,
76
+ help="learning rat for backbone", dest="lr_bb",)
77
+ parser.add_argument("--wd", "--weight_decay", default=1e-4, type=float,
78
+ help="weight decay (default: 1e-4)", dest="weight_decay")
79
+ parser.add_argument("--warmup_iters", default=30000, type=int,
80
+ help="Number of iterations for the linear learning-rate warm up.")
81
+ parser.add_argument('--min_lr', type=float, default=1e-6, help="""Target LR at the
82
+ end of optimization. We use a cosine LR schedule with linear warmup.""")
83
+ parser.add_argument('--lr_scheduler_type', type=str, default='constant_with_warmup')
84
+ parser.add_argument('--freeze_last_layer', default=0, type=int,
85
+ help="""Number of iterations during which we keep the
86
+ output layer fixed. Typically doing so during
87
+ first few iters helps training. Try increasing this
88
+ value if the loss does not decrease.""")
89
+
90
+ parser.add_argument('--content_proj_head', type=str, default='default')
91
+ parser.add_argument('--lambda_s', default=1, type=float, help='Weighting on style loss')
92
+ parser.add_argument('--lambda_c', default=0, type=float, help='Weighting on content loss')
93
+ parser.add_argument('--lam_sup', default=5, type=float, help='Supervised style loss lambda')
94
+ parser.add_argument('--temp', default=0.1, type=float, help='contrastive temperature')
95
+
96
+ parser.add_argument('--clamp_content_loss', default=None, type=float, help='Clipping the content loss')
97
+ parser.add_argument( "--non_adv_train", action="store_true",
98
+ help="dont train content adversarially, use neg of content loss")
99
+ parser.add_argument('--eval_embed', type=str, default='head', help='which embeddings to use in evaluation')
100
+ parser.add_argument('--style_loss_type', type=str, default='SupCon', help='which loss function for style loss computation')
101
+ # Logging Params
102
+ parser.add_argument('--output_dir', required=True, type=str, help='Path to save logs and checkpoints.')
103
+ parser.add_argument('--print_freq', default=100, type=int, help='Print the logs every x iterations.')
104
+ parser.add_argument('--saveckp_freq', default=5000, type=int, help='Save checkpoint every x iterations.')
105
+ parser.add_argument('--eval_freq', default=5000, type=int, help='Eval the model every x iterations.')
106
+ parser.add_argument('--eval_k', type=int, nargs='+', default=[1, 5, 100], help='eval map and recall at these k values.')
107
+
108
+ # Misc
109
+ parser.add_argument("--resume_if_available", action="store_true")
110
+ parser.add_argument("--seed", default=42, type=int,
111
+ help="seed for initializing training. ")
112
+ parser.add_argument("-j", "--workers", default=4, type=int,
113
+ help="number of data loading workers (default: 32)")
114
+ parser.add_argument("--rank", default=-1, type=int,
115
+ help="node rank for distributed training")
116
+ parser.add_argument("--dist_url", default="env://",
117
+ help="url used to set up distributed training")
118
+ parser.add_argument("--local_rank", default=0, type=int,
119
+ help="Please ignore and do not set this argument.")
120
+ return parser
121
+
122
+
123
+ def sample_infinite_data(loader, seed=0):
124
+ rng = torch.Generator()
125
+ rng.manual_seed(seed)
126
+ BIG_NUMBER = 9999999999999
127
+ while True:
128
+ # Randomize dataloader indices before every epoch:
129
+ try: # Only relevant for distributed sampler:
130
+ shuffle_seed = torch.randint(0, BIG_NUMBER, (1,), generator=rng).item()
131
+ loader.sampler.set_epoch(shuffle_seed)
132
+ except AttributeError:
133
+ pass
134
+ for batch in loader:
135
+ yield batch
136
+
137
+
138
+ def main():
139
+ parser = argparse.ArgumentParser('CSD', parents=[get_args_parser()])
140
+ args = parser.parse_args()
141
+
142
+ if args.non_adv_train:
143
+ assert args.clamp_content_loss is not None, 'You have to clamp content loss in non-adv style of training'
144
+ utils.init_distributed_mode(args)
145
+ if args.seed is not None:
146
+ utils.fix_random_seeds(args.seed)
147
+
148
+ print("\n".join("%s: %s" % (k, str(v)) for k, v in sorted(dict(vars(args)).items())))
149
+ cudnn.benchmark = True
150
+
151
+ # ======================= setup logging =======================
152
+ if utils.is_main_process() and args.iters > 0:
153
+ os.makedirs(args.output_dir, exist_ok=True)
154
+
155
+ # ======================= preparing data =======================
156
+ if args.lambda_c < 1e-3:
157
+ train_transforms = ContrastiveTransformations(transforms_branch1, transforms_branch1, transforms_branch2)
158
+ else:
159
+ train_transforms = ContrastiveTransformations(transforms_branch0, transforms_branch1, transforms_branch2)
160
+
161
+ if args.train_set == 'wikiart':
162
+ train_dataset = WikiArtTrain(
163
+ args.train_path, 'database',
164
+ transform=train_transforms)
165
+ elif args.train_set == 'laion':
166
+ train_dataset = LAION(
167
+ args.train_path, args.train_anno_path,
168
+ min_images_per_label=args.min_images_per_label,
169
+ max_images_per_label=args.max_images_per_label,
170
+ transform=train_transforms)
171
+ elif args.train_set == 'laion_dedup':
172
+ train_dataset = LAIONDedup(
173
+ args.train_path, args.train_anno_path,
174
+ transform=train_transforms)
175
+ else:
176
+ raise NotImplementedError
177
+
178
+ train_sampler = torch.utils.data.DistributedSampler(train_dataset, shuffle=True)
179
+ train_loader = torch.utils.data.DataLoader(
180
+ train_dataset, batch_size=args.batch_size_per_gpu, drop_last=True,
181
+ num_workers=args.workers, pin_memory=True, sampler=train_sampler)
182
+ train_loader = sample_infinite_data(train_loader, args.seed)
183
+
184
+ if args.eval_set == 'wikiart':
185
+ vq_dataset = WikiArtTrain(
186
+ args.eval_path, 'query', transform=transforms_branch0, maxsize=args.maxsize)
187
+ vidx_dataset = WikiArtTrain(
188
+ args.eval_path, 'database', transform=transforms_branch0, maxsize=8*args.maxsize)
189
+
190
+ vq_loader = torch.utils.data.DataLoader(
191
+ vq_dataset, batch_size=2*args.batch_size_per_gpu, drop_last=True,
192
+ num_workers=min(args.workers, 2), pin_memory=True, shuffle=False)
193
+ vidx_loader = torch.utils.data.DataLoader(
194
+ vidx_dataset, batch_size=2*args.batch_size_per_gpu, drop_last=True,
195
+ num_workers=min(args.workers, 2), pin_memory=True, shuffle=False)
196
+ print(f"Data loaded: there are {len(train_dataset)} train images.")
197
+ print(f"Data loaded: there are {len(vq_dataset)} query and {len(vidx_dataset)} index images.")
198
+
199
+ # ======================= building model =======================
200
+ model = CSD_CLIP(args.arch, args.content_proj_head) # TODO: projection dim into hyperparam
201
+ model = model.cuda()
202
+ # synchronize batch norms (if any)
203
+ if utils.has_batchnorms(model):
204
+ model = nn.SyncBatchNorm.convert_sync_batchnorm(model)
205
+
206
+ if args.distributed:
207
+ model = nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu])
208
+ model_without_ddp = model.module
209
+ else:
210
+ model_without_ddp = model
211
+
212
+ print(f"Model built with {args.arch} network.")
213
+
214
+ # ======================= setup loss and optimizers =======================
215
+ loss_content = SupConLoss(temperature=args.temp) # TODO: Do we want 2 diff
216
+ loss_style = SupConLoss(temperature=args.temp)
217
+
218
+ params_groups = utils.get_params_groups(model_without_ddp.backbone)
219
+ # lr is set by scheduler
220
+ opt_bb = torch.optim.SGD(
221
+ params_groups, lr=0, momentum=0.9, weight_decay=args.weight_decay)
222
+
223
+ if args.content_proj_head != 'default':
224
+ opt_proj = torch.optim.SGD(
225
+ [{'params': model_without_ddp.last_layer_style},
226
+ {'params': model_without_ddp.last_layer_content.parameters()},],
227
+ # [model_without_ddp.last_layer_style, *model_without_ddp.last_layer_content.parameters()],
228
+ lr=0, momentum=0.9, weight_decay=0, # we do not apply weight decay
229
+ )
230
+ else:
231
+ opt_proj = torch.optim.SGD(
232
+ [model_without_ddp.last_layer_style, model_without_ddp.last_layer_content],
233
+ lr=0, momentum=0.9, weight_decay=0, # we do not apply weight decay
234
+ )
235
+
236
+ fp16_scaler = None
237
+ if args.use_fp16:
238
+ fp16_scaler = torch.cuda.amp.GradScaler()
239
+
240
+ # ======================= init schedulers =======================
241
+ if args.lr_scheduler_type =='cosine':
242
+ lr_schedule_bb = utils.cosine_scheduler(
243
+ args.lr_bb * (args.batch_size_per_gpu * utils.get_world_size()) / 256., # linear scaling rule
244
+ min(args.min_lr, args.lr_bb),
245
+ max(args.iters, 1), warmup_iters=min(args.warmup_iters, args.iters)
246
+ )
247
+
248
+ lr_schedule_proj = utils.cosine_scheduler(
249
+ args.lr * (args.batch_size_per_gpu * utils.get_world_size()) / 256., # linear scaling rule
250
+ min(args.min_lr, args.lr),
251
+ max(args.iters, 1), warmup_iters=min(args.warmup_iters, args.iters)
252
+ )
253
+ elif args.lr_scheduler_type =='constant_with_warmup':
254
+ lr_schedule_bb = utils.constant_with_warmup_scheduler(
255
+ args.lr_bb * (args.batch_size_per_gpu * utils.get_world_size()) / 256., # linear scaling rule
256
+ max(args.iters, 1), warmup_iters=min(args.warmup_iters, args.iters),
257
+ )
258
+
259
+ lr_schedule_proj = utils.constant_with_warmup_scheduler(
260
+ args.lr * (args.batch_size_per_gpu * utils.get_world_size()) / 256., # linear scaling rule
261
+ max(args.iters, 1), warmup_iters=min(args.warmup_iters, args.iters),
262
+ )
263
+ else:
264
+ print('Using constant LR for training')
265
+ lr_schedule_bb = utils.constant_with_warmup_scheduler(
266
+ args.lr_bb * (args.batch_size_per_gpu * utils.get_world_size()) / 256., # linear scaling rule
267
+ max(args.iters, 1), warmup_iters=0,
268
+ )
269
+
270
+ lr_schedule_proj = utils.constant_with_warmup_scheduler(
271
+ args.lr * (args.batch_size_per_gpu * utils.get_world_size()) / 256., # linear scaling rule
272
+ max(args.iters, 1), warmup_iters=0,
273
+ )
274
+
275
+ print(f"Loss, optimizer and schedulers ready.")
276
+
277
+ # ======================= optionally resume training =======================
278
+ to_restore = {"iter": 0}
279
+ if args.resume_if_available:
280
+ if not args.output_dir.endswith(".pth"):
281
+ ckpt_path = os.path.join(args.output_dir, "checkpoint.pth")
282
+ else:
283
+ ckpt_path = args.output_dir
284
+ utils.restart_from_checkpoint(
285
+ ckpt_path,
286
+ run_variables=to_restore,
287
+ model_state_dict=model,
288
+ opt_bb=opt_bb,
289
+ opt_proj=opt_proj,
290
+ fp16_scaler=fp16_scaler,
291
+ )
292
+ print(f"Start iter: {to_restore['iter']}")
293
+ start_iter = to_restore["iter"]
294
+ save_dict = None
295
+ print("Running eval before training!")
296
+ val_stats = evaluate(model, vq_loader, vidx_loader, fp16_scaler is not None, args.eval_k, args.eval_embed)
297
+ if start_iter >= args.iters:
298
+ print(f"Start iter {start_iter} >= Max iters {args.iters} training!")
299
+ return
300
+
301
+ start_time = time.time()
302
+ print("Starting CSD training !")
303
+ metric_logger = utils.MetricLogger(delimiter=" ", max_len=args.iters)
304
+ header = 'Iter:'
305
+
306
+ #TODO: Check if we need to set model to train mode
307
+ model.eval()
308
+ for iter, batch in enumerate(metric_logger.log_every(train_loader, 100, header)):
309
+ # ======================= training =======================
310
+
311
+ if iter < start_iter:
312
+ continue
313
+
314
+ if iter >= args.iters:
315
+ break
316
+
317
+ # update learning rates according to their schedule
318
+ # it = len(train_loader) * epoch + it # global training iteration
319
+ p = float(iter) / args.iters
320
+
321
+ for param_group in opt_bb.param_groups:
322
+ param_group["lr"] = lr_schedule_bb[iter]
323
+
324
+ for param_group in opt_proj.param_groups:
325
+ param_group["lr"] = lr_schedule_proj[iter]
326
+ if args.non_adv_train:
327
+ alpha = None
328
+ else:
329
+ alpha = 2. / (1. + np.exp(-10 * p)) - 1
330
+ images, artists, *_ = batch
331
+ if args.lambda_c < 1e-3:
332
+ images = torch.cat([images[0],images[1]], dim=0)
333
+ else:
334
+ images = torch.cat(images, dim=0)
335
+
336
+ # import torchvision
337
+ # torchvision.utils.save_image(images,'./temp.png')
338
+ images= images.cuda(non_blocking=True)
339
+ artists = artists.cuda(non_blocking=True).float()
340
+
341
+ with torch.cuda.amp.autocast(fp16_scaler is not None):
342
+ _ , content_output, style_output = model(images, alpha)
343
+
344
+ # Normalize the output features for each image
345
+ content_output = nn.functional.normalize(content_output, dim=1, p=2)
346
+ style_output = nn.functional.normalize(style_output, dim=1, p=2)
347
+
348
+ # Split the output features for each image and its views
349
+ style_output = utils.split_reshape(style_output, args.batch_size_per_gpu, [0, 1])
350
+ content_output = utils.split_reshape(content_output, args.batch_size_per_gpu, [0, -1])
351
+
352
+ # Gather tensors from all GPUs
353
+ if args.use_distributed_loss:
354
+ style_output = torch.cat(utils.GatherLayer.apply(style_output), dim=0)
355
+ content_output = torch.cat(utils.GatherLayer.apply(content_output), dim=0)
356
+
357
+ # Compute content loss (SimCLR loss, doesn't use labels)
358
+ loss_c = loss_content(content_output)
359
+ if args.clamp_content_loss is not None:
360
+ loss_c = loss_c.clamp(max = args.clamp_content_loss)
361
+ if args.non_adv_train:
362
+ loss_c = -1 * loss_c
363
+
364
+ # Compute style loss
365
+ if args.use_distributed_loss:
366
+ artists = torch.cat(utils.GatherLayer.apply(artists), dim=0)
367
+
368
+ label_mask = artists @ artists.t()
369
+ if args.style_loss_type == 'SimClr':
370
+ loss_s_ssl = loss_style(style_output)
371
+ loss_s_sup = torch.Tensor([0]).to(model.device)
372
+ elif args.style_loss_type == 'OnlySup':
373
+ loss_s_ssl = torch.Tensor([0]).to(model.device)
374
+ loss_s_sup = loss_style(style_output[:, 0:1, :], mask=label_mask)
375
+ else:
376
+ loss_s_sup = loss_style(style_output[:, 0:1, :], mask=label_mask)
377
+ loss_s_ssl = loss_style(style_output)
378
+
379
+ loss_s = args.lam_sup*loss_s_sup + loss_s_ssl
380
+
381
+ loss = args.lambda_c * loss_c + args.lambda_s * loss_s
382
+
383
+ if not math.isfinite(loss.item()):
384
+ print("Loss is {}, stopping training".format(loss.item()))
385
+ sys.exit(1)
386
+
387
+ opt_bb.zero_grad()
388
+ opt_proj.zero_grad()
389
+ param_norms = None
390
+ if fp16_scaler is None:
391
+ loss.backward()
392
+ if args.clip_grad:
393
+ param_norms = utils.clip_gradients(model, args.clip_grad)
394
+ utils.cancel_gradients_last_layer(iter, model, args.freeze_last_layer)
395
+ opt_bb.step()
396
+ opt_proj.step()
397
+ else:
398
+ fp16_scaler.scale(loss).backward()
399
+ if args.clip_grad:
400
+ fp16_scaler.unscale_(opt_bb) # unscale the gradients of optimizer's assigned params in-place
401
+ fp16_scaler.unscale_(opt_proj)
402
+ param_norms = utils.clip_gradients(model, args.clip_grad)
403
+ utils.cancel_gradients_last_layer(iter, model, args.freeze_last_layer)
404
+ fp16_scaler.step(opt_bb)
405
+ fp16_scaler.step(opt_proj)
406
+ fp16_scaler.update()
407
+
408
+ # logging
409
+ torch.cuda.synchronize()
410
+ metric_logger.update(loss=loss.item())
411
+ metric_logger.update(content_loss=loss_c.item())
412
+ metric_logger.update(style_loss=loss_s.item())
413
+ metric_logger.update(style_loss_sup=loss_s_sup.item())
414
+ metric_logger.update(style_loss_ssl=loss_s_ssl.item())
415
+ metric_logger.update(lr_bb=opt_bb.param_groups[0]["lr"])
416
+ # metric_logger.update(wd_bb=opt_bb.param_groups[0]["weight_decay"])
417
+ metric_logger.update(lr_proj=opt_proj.param_groups[0]["lr"])
418
+ # metric_logger.update(wd_proj=opt_proj.param_groups[0]["weight_decay"])
419
+
420
+ # ============ writing logs ... ============
421
+ save_dict = {
422
+ 'model_state_dict': model.state_dict(),
423
+ 'opt_bb': opt_bb.state_dict(),
424
+ 'opt_proj': opt_proj.state_dict(),
425
+ 'iter': iter+1,
426
+ 'args': args,
427
+ }
428
+ if fp16_scaler is not None:
429
+ save_dict['fp16_scaler'] = fp16_scaler.state_dict()
430
+
431
+ if (iter+1) % args.saveckp_freq == 0:
432
+ utils.save_on_master(save_dict, os.path.join(args.output_dir, 'checkpoint.pth'))
433
+ utils.save_on_master(save_dict, os.path.join(args.output_dir, f'checkpoint{iter+1:08}.pth'))
434
+
435
+ train_stats = {k: meter.global_avg for k, meter in metric_logger.meters.items()}
436
+ log_stats = {**{f'train_{k}': v for k, v in train_stats.items()},
437
+ 'iter': iter+1}
438
+
439
+ if utils.is_main_process() and (iter+1) % args.print_freq == 0:
440
+ with (Path(args.output_dir) / "log.txt").open("a") as f:
441
+ f.write(json.dumps(log_stats) + "\n")
442
+
443
+ # Eval
444
+ if (iter+1) % args.eval_freq==0:
445
+ # gather the stats from all processes
446
+ metric_logger.synchronize_between_processes()
447
+ print("Averaged stats:", metric_logger)
448
+
449
+ val_stats = evaluate(model, vq_loader, vidx_loader, fp16_scaler is not None, args.eval_k, args.eval_embed)
450
+
451
+ if args.iters > 0 and save_dict is not None:
452
+ utils.save_on_master(save_dict, os.path.join(args.output_dir, 'checkpoint.pth'))
453
+
454
+ total_time = time.time() - start_time
455
+ total_time_str = str(datetime.timedelta(seconds=int(total_time)))
456
+ print('Training time {}'.format(total_time_str))
457
+
458
+
459
+ def evaluate(model, vq_loader, vidx_loader, use_fp16=False, eval_k=[1, 5, 100], eval_embed='head'):
460
+ metric_logger = utils.MetricLogger(delimiter=" ")
461
+ # Valid loader is the query set
462
+ # Train loader is the search set
463
+ use_cuda = True
464
+ db_features = utils.extract_features(model, vidx_loader,use_cuda, use_fp16, eval_embed)
465
+ q_features = utils.extract_features(model, vq_loader, use_cuda, use_fp16, eval_embed)
466
+
467
+ # Aggregate style features across GPUs
468
+ if utils.get_rank() != 0:
469
+ return
470
+
471
+ # Find the nearest neighbor indices for each query
472
+ similarities = q_features @ db_features.T
473
+ similarities = torch.argsort(similarities, dim=1, descending=True).cpu()
474
+
475
+ # Map neighbor indices to labels (assuming one hot labels)
476
+ q_labels = vq_loader.dataset.labels
477
+ db_labels = vidx_loader.dataset.labels
478
+ gts = q_labels @ db_labels.T
479
+ #TODO: vectorize this
480
+ preds = np.array([gts[i][similarities[i]] for i in range(len(gts))])
481
+
482
+ # Compute metrics
483
+ for topk in eval_k:
484
+ mode_recall = utils.Metrics.get_recall_bin(copy.deepcopy(preds), topk)
485
+ mode_mrr = utils.Metrics.get_mrr_bin(copy.deepcopy(preds), topk)
486
+ mode_map = utils.Metrics.get_map_bin(copy.deepcopy(preds), topk)
487
+ # print(f'Recall@{topk}: {mode_recall:.2f}, mAP@{topk}: {mode_map:.2f}')
488
+ metric_logger.update(**{f'recall@{topk}': mode_recall, f'mAP@{topk}': mode_map, f'MRR@{topk}': mode_mrr})
489
+
490
+ # gather the stats from all processes
491
+ print("Averaged stats:", metric_logger)
492
+ return {k: meter.global_avg for k, meter in metric_logger.meters.items()}
493
+
494
+
495
+ if __name__ == "__main__":
496
+ main()
CSD/CSD/utils.py ADDED
@@ -0,0 +1,853 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
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
+ Misc functions.
16
+
17
+ Mostly copy-paste from torchvision references or other public repos like DETR:
18
+ https://github.com/facebookresearch/detr/blob/master/util/misc.py
19
+ """
20
+ import os
21
+ import sys
22
+ import time
23
+ import math
24
+ import random
25
+ import datetime
26
+ import subprocess
27
+ from collections import defaultdict, deque, OrderedDict
28
+
29
+ import numpy as np
30
+ import torch
31
+ from torch import nn
32
+ import torch.distributed as dist
33
+ import warnings
34
+ import argparse
35
+ from PIL import ImageFilter, ImageOps
36
+
37
+
38
+ class GaussianBlur(object):
39
+ """
40
+ Apply Gaussian Blur to the PIL image.
41
+ """
42
+
43
+ def __init__(self, p=0.5, radius_min=0.1, radius_max=2.):
44
+ self.prob = p
45
+ self.radius_min = radius_min
46
+ self.radius_max = radius_max
47
+
48
+ def __call__(self, img):
49
+ do_it = random.random() <= self.prob
50
+ if not do_it:
51
+ return img
52
+
53
+ return img.filter(
54
+ ImageFilter.GaussianBlur(
55
+ radius=random.uniform(self.radius_min, self.radius_max)
56
+ )
57
+ )
58
+
59
+
60
+ class Solarization(object):
61
+ """
62
+ Apply Solarization to the PIL image.
63
+ """
64
+
65
+ def __init__(self, p):
66
+ self.p = p
67
+
68
+ def __call__(self, img):
69
+ if random.random() < self.p:
70
+ return ImageOps.solarize(img)
71
+ else:
72
+ return img
73
+
74
+
75
+ def clip_gradients(model, clip):
76
+ norms = []
77
+ for name, p in model.named_parameters():
78
+ if p.grad is not None:
79
+ param_norm = p.grad.data.norm(2)
80
+ norms.append(param_norm.item())
81
+ clip_coef = clip / (param_norm + 1e-6)
82
+ if clip_coef < 1:
83
+ p.grad.data.mul_(clip_coef)
84
+ return norms
85
+
86
+
87
+ def restart_from_checkpoint(ckp_path, run_variables=None, **kwargs):
88
+ """
89
+ Re-start from checkpoint
90
+ """
91
+ if not os.path.isfile(ckp_path):
92
+ return
93
+ print("Found checkpoint at {}".format(ckp_path))
94
+
95
+ # open checkpoint file
96
+ checkpoint = torch.load(ckp_path, map_location="cpu")
97
+
98
+ # key is what to look for in the checkpoint file
99
+ # value is the object to load
100
+ # example: {'state_dict': model}
101
+ for key, value in kwargs.items():
102
+ if key in checkpoint and value is not None:
103
+ try:
104
+ msg = value.load_state_dict(checkpoint[key], strict=False)
105
+ print("=> loaded '{}' from checkpoint '{}' with msg {}".format(key, ckp_path, msg))
106
+ except TypeError:
107
+ try:
108
+ msg = value.load_state_dict(checkpoint[key])
109
+ print("=> loaded '{}' from checkpoint: '{}'".format(key, ckp_path))
110
+ except ValueError:
111
+ print("=> failed to load '{}' from checkpoint: '{}'".format(key, ckp_path))
112
+ else:
113
+ print("=> key '{}' not found in checkpoint: '{}'".format(key, ckp_path))
114
+
115
+ # re load variable important for the run
116
+ if run_variables is not None:
117
+ for var_name in run_variables:
118
+ if var_name in checkpoint:
119
+ run_variables[var_name] = checkpoint[var_name]
120
+
121
+
122
+ def convert_state_dict(state_dict):
123
+ new_state_dict = OrderedDict()
124
+ for k, v in state_dict.items():
125
+ if k.startswith("module."):
126
+ k = k.replace("module.", "")
127
+ new_state_dict[k] = v
128
+ return new_state_dict
129
+
130
+
131
+ def cosine_scheduler(base_value, final_value, iters, warmup_iters, start_warmup_value=0):
132
+ warmup_schedule = np.array([])
133
+
134
+ if warmup_iters > 0:
135
+ warmup_schedule = np.linspace(start_warmup_value, base_value, warmup_iters)
136
+
137
+ post_warmup_iters = np.arange(iters - warmup_iters)
138
+ schedule = final_value + 0.5 * (base_value - final_value) * (
139
+ 1 + np.cos(np.pi * post_warmup_iters / len(post_warmup_iters)))
140
+
141
+ schedule = np.concatenate((warmup_schedule, schedule))
142
+ assert len(schedule) == iters
143
+ return schedule
144
+
145
+
146
+ def constant_with_warmup_scheduler(base_value, iters, warmup_iters=0, start_warmup_value=0):
147
+ warmup_schedule = np.array([])
148
+
149
+ if warmup_iters > 0:
150
+ warmup_schedule = np.linspace(start_warmup_value, base_value, warmup_iters)
151
+
152
+ num_iters = iters - warmup_iters
153
+ schedule = np.array([base_value] * num_iters)
154
+
155
+ schedule = np.concatenate((warmup_schedule, schedule))
156
+ assert len(schedule) == iters
157
+ return schedule
158
+
159
+
160
+ def bool_flag(s):
161
+ """
162
+ Parse boolean arguments from the command line.
163
+ """
164
+ FALSY_STRINGS = {"off", "false", "0"}
165
+ TRUTHY_STRINGS = {"on", "true", "1"}
166
+ if s.lower() in FALSY_STRINGS:
167
+ return False
168
+ elif s.lower() in TRUTHY_STRINGS:
169
+ return True
170
+ else:
171
+ raise argparse.ArgumentTypeError("invalid value for a boolean flag")
172
+
173
+
174
+ def fix_random_seeds(seed=31):
175
+ """
176
+ Fix random seeds.
177
+ """
178
+ torch.manual_seed(seed)
179
+ torch.cuda.manual_seed_all(seed)
180
+ np.random.seed(seed)
181
+
182
+
183
+ class SmoothedValue(object):
184
+ """Track a series of values and provide access to smoothed values over a
185
+ window or the global series average.
186
+ """
187
+
188
+ def __init__(self, window_size=20, fmt=None):
189
+ if fmt is None:
190
+ fmt = "{median:.6f} ({global_avg:.6f})"
191
+ self.deque = deque(maxlen=window_size)
192
+ self.total = 0.0
193
+ self.count = 0
194
+ self.fmt = fmt
195
+
196
+ def update(self, value, n=1):
197
+ self.deque.append(value)
198
+ self.count += n
199
+ self.total += value * n
200
+
201
+ def synchronize_between_processes(self):
202
+ """
203
+ Warning: does not synchronize the deque!
204
+ """
205
+ if not is_dist_avail_and_initialized():
206
+ return
207
+ t = torch.tensor([self.count, self.total], dtype=torch.float64, device='cuda')
208
+ dist.barrier()
209
+ dist.all_reduce(t)
210
+ t = t.tolist()
211
+ self.count = int(t[0])
212
+ self.total = t[1]
213
+
214
+ @property
215
+ def median(self):
216
+ d = torch.tensor(list(self.deque))
217
+ return d.median().item()
218
+
219
+ @property
220
+ def avg(self):
221
+ d = torch.tensor(list(self.deque), dtype=torch.float32)
222
+ return d.mean().item()
223
+
224
+ @property
225
+ def global_avg(self):
226
+ return self.total / self.count
227
+
228
+ @property
229
+ def max(self):
230
+ return max(self.deque)
231
+
232
+ @property
233
+ def value(self):
234
+ return self.deque[-1]
235
+
236
+ def __str__(self):
237
+ return self.fmt.format(
238
+ median=self.median,
239
+ avg=self.avg,
240
+ global_avg=self.global_avg,
241
+ max=self.max,
242
+ value=self.value)
243
+
244
+
245
+ def reduce_dict(input_dict, average=True):
246
+ """
247
+ Args:
248
+ input_dict (dict): all the values will be reduced
249
+ average (bool): whether to do average or sum
250
+ Reduce the values in the dictionary from all processes so that all processes
251
+ have the averaged results. Returns a dict with the same fields as
252
+ input_dict, after reduction.
253
+ """
254
+ world_size = get_world_size()
255
+ if world_size < 2:
256
+ return input_dict
257
+ with torch.no_grad():
258
+ names = []
259
+ values = []
260
+ # sort the keys so that they are consistent across processes
261
+ for k in sorted(input_dict.keys()):
262
+ names.append(k)
263
+ values.append(input_dict[k])
264
+ values = torch.stack(values, dim=0)
265
+ dist.all_reduce(values)
266
+ if average:
267
+ values /= world_size
268
+ reduced_dict = {k: v for k, v in zip(names, values)}
269
+ return reduced_dict
270
+
271
+
272
+ class MetricLogger(object):
273
+ def __init__(self, delimiter="\t", max_len=100):
274
+ self.meters = defaultdict(SmoothedValue)
275
+ self.delimiter = delimiter
276
+ self.max_len = max_len
277
+
278
+ def update(self, **kwargs):
279
+ for k, v in kwargs.items():
280
+ if isinstance(v, torch.Tensor):
281
+ v = v.item()
282
+ assert isinstance(v, (float, int))
283
+ self.meters[k].update(v)
284
+
285
+ def __getattr__(self, attr):
286
+ if attr in self.meters:
287
+ return self.meters[attr]
288
+ if attr in self.__dict__:
289
+ return self.__dict__[attr]
290
+ raise AttributeError("'{}' object has no attribute '{}'".format(
291
+ type(self).__name__, attr))
292
+
293
+ def __str__(self):
294
+ loss_str = []
295
+ for name, meter in self.meters.items():
296
+ loss_str.append(
297
+ "{}: {}".format(name, str(meter))
298
+ )
299
+ return self.delimiter.join(loss_str)
300
+
301
+ def synchronize_between_processes(self):
302
+ for meter in self.meters.values():
303
+ meter.synchronize_between_processes()
304
+
305
+ def add_meter(self, name, meter):
306
+ self.meters[name] = meter
307
+
308
+ def log_every(self, iterable, print_freq, header=None):
309
+ i = 0
310
+ if not header:
311
+ header = ''
312
+ start_time = time.time()
313
+ end = time.time()
314
+ iter_time = SmoothedValue(fmt='{avg:.6f}')
315
+ data_time = SmoothedValue(fmt='{avg:.6f}')
316
+ space_fmt = ':' + str(len(str(self.max_len))) + 'd'
317
+ if torch.cuda.is_available():
318
+ log_msg = self.delimiter.join([
319
+ header,
320
+ '[{0' + space_fmt + '}/{1}]',
321
+ 'eta: {eta}',
322
+ '{meters}',
323
+ 'time: {time}',
324
+ 'data: {data}',
325
+ 'max mem: {memory:.0f}'
326
+ ])
327
+ else:
328
+ log_msg = self.delimiter.join([
329
+ header,
330
+ '[{0' + space_fmt + '}/{1}]',
331
+ 'eta: {eta}',
332
+ '{meters}',
333
+ 'time: {time}',
334
+ 'data: {data}'
335
+ ])
336
+ MB = 1024.0 * 1024.0
337
+ for obj in iterable:
338
+ data_time.update(time.time() - end)
339
+ yield obj
340
+ iter_time.update(time.time() - end)
341
+ if i % print_freq == 0 or i == self.max_len - 1:
342
+ eta_seconds = iter_time.global_avg * (self.max_len - i)
343
+ eta_string = str(datetime.timedelta(seconds=int(eta_seconds)))
344
+ if torch.cuda.is_available():
345
+ print(log_msg.format(
346
+ i, self.max_len,
347
+ eta=eta_string,
348
+ meters=str(self),
349
+ time=str(iter_time), data=str(data_time),
350
+ memory=torch.cuda.max_memory_allocated() / MB))
351
+ else:
352
+ print(log_msg.format(
353
+ i, self.max_len,
354
+ eta=eta_string,
355
+ meters=str(self),
356
+ time=str(iter_time), data=str(data_time)))
357
+ i += 1
358
+ end = time.time()
359
+ total_time = time.time() - start_time
360
+ total_time_str = str(datetime.timedelta(seconds=int(total_time)))
361
+ print('{} Total time: {} ({:.6f} s / it)'.format(
362
+ header, total_time_str, total_time / self.max_len))
363
+
364
+
365
+ def get_sha():
366
+ cwd = os.path.dirname(os.path.abspath(__file__))
367
+
368
+ def _run(command):
369
+ return subprocess.check_output(command, cwd=cwd).decode('ascii').strip()
370
+
371
+ sha = 'N/A'
372
+ diff = "clean"
373
+ branch = 'N/A'
374
+ try:
375
+ sha = _run(['git', 'rev-parse', 'HEAD'])
376
+ subprocess.check_output(['git', 'diff'], cwd=cwd)
377
+ diff = _run(['git', 'diff-index', 'HEAD'])
378
+ diff = "has uncommited changes" if diff else "clean"
379
+ branch = _run(['git', 'rev-parse', '--abbrev-ref', 'HEAD'])
380
+ except Exception:
381
+ pass
382
+ message = f"sha: {sha}, status: {diff}, branch: {branch}"
383
+ return message
384
+
385
+
386
+ def is_dist_avail_and_initialized():
387
+ if not dist.is_available():
388
+ return False
389
+ if not dist.is_initialized():
390
+ return False
391
+ return True
392
+
393
+
394
+ def get_world_size():
395
+ if not is_dist_avail_and_initialized():
396
+ return 1
397
+ return dist.get_world_size()
398
+
399
+
400
+ def get_rank():
401
+ if not is_dist_avail_and_initialized():
402
+ return 0
403
+ return dist.get_rank()
404
+
405
+
406
+ def is_main_process():
407
+ return get_rank() == 0
408
+
409
+
410
+ def save_on_master(*args, **kwargs):
411
+ if is_main_process():
412
+ torch.save(*args, **kwargs)
413
+
414
+
415
+ def setup_for_distributed(is_master):
416
+ """
417
+ This function disables printing when not in master process
418
+ """
419
+ import builtins as __builtin__
420
+ builtin_print = __builtin__.print
421
+
422
+ def print(*args, **kwargs):
423
+ force = kwargs.pop('force', False)
424
+ if is_master or force:
425
+ builtin_print(*args, **kwargs)
426
+
427
+ __builtin__.print = print
428
+
429
+
430
+ def init_distributed_mode(args):
431
+ # launched with torch.distributed.launch
432
+ if 'RANK' in os.environ and 'WORLD_SIZE' in os.environ:
433
+ args.rank = int(os.environ["RANK"])
434
+ args.world_size = int(os.environ['WORLD_SIZE'])
435
+ args.gpu = int(os.environ['LOCAL_RANK'])
436
+ # launched with submitit on a slurm cluster
437
+ elif 'SLURM_PROCID' in os.environ:
438
+ args.rank = int(os.environ['SLURM_PROCID'])
439
+ args.gpu = args.rank % torch.cuda.device_count()
440
+ # launched naively with `python main_dino.py`
441
+ # we manually add MASTER_ADDR and MASTER_PORT to env variables
442
+ elif torch.cuda.is_available():
443
+ print('Will run the code on one GPU.')
444
+ args.rank, args.gpu, args.world_size = 0, 0, 1
445
+ os.environ['MASTER_ADDR'] = '127.0.0.1'
446
+ os.environ['MASTER_PORT'] = '29500'
447
+ else:
448
+ print('Does not support training without GPU.')
449
+ sys.exit(1)
450
+
451
+ if torch.cuda.device_count() > 0:
452
+ args.distributed = True
453
+ else:
454
+ args.distributed = False
455
+
456
+ dist.init_process_group(
457
+ backend="nccl",
458
+ init_method=args.dist_url,
459
+ world_size=args.world_size,
460
+ rank=args.rank,
461
+ )
462
+
463
+ torch.cuda.set_device(args.gpu)
464
+ print('| distributed init (rank {}): {}'.format(
465
+ args.rank, args.dist_url), flush=True)
466
+ dist.barrier()
467
+ setup_for_distributed(args.rank == 0)
468
+
469
+
470
+ def accuracy(output, target, topk=(1,)):
471
+ """Computes the accuracy over the k top predictions for the specified values of k"""
472
+ maxk = max(topk)
473
+ batch_size = target.size(0)
474
+ _, pred = output.topk(maxk, 1, True, True)
475
+ pred = pred.t()
476
+ correct = pred.eq(target.reshape(1, -1).expand_as(pred))
477
+ return [correct[:k].reshape(-1).float().sum(0) * 100. / batch_size for k in topk]
478
+
479
+
480
+ def _no_grad_trunc_normal_(tensor, mean, std, a, b):
481
+ # Cut & paste from PyTorch official master until it's in a few official releases - RW
482
+ # Method based on https://people.sc.fsu.edu/~jburkardt/presentations/truncated_normal.pdf
483
+ def norm_cdf(x):
484
+ # Computes standard normal cumulative distribution function
485
+ return (1. + math.erf(x / math.sqrt(2.))) / 2.
486
+
487
+ if (mean < a - 2 * std) or (mean > b + 2 * std):
488
+ warnings.warn("mean is more than 2 std from [a, b] in nn.init.trunc_normal_. "
489
+ "The distribution of values may be incorrect.",
490
+ stacklevel=2)
491
+
492
+ with torch.no_grad():
493
+ # Values are generated by using a truncated uniform distribution and
494
+ # then using the inverse CDF for the normal distribution.
495
+ # Get upper and lower cdf values
496
+ l = norm_cdf((a - mean) / std)
497
+ u = norm_cdf((b - mean) / std)
498
+
499
+ # Uniformly fill tensor with values from [l, u], then translate to
500
+ # [2l-1, 2u-1].
501
+ tensor.uniform_(2 * l - 1, 2 * u - 1)
502
+
503
+ # Use inverse cdf transform for normal distribution to get truncated
504
+ # standard normal
505
+ tensor.erfinv_()
506
+
507
+ # Transform to proper mean, std
508
+ tensor.mul_(std * math.sqrt(2.))
509
+ tensor.add_(mean)
510
+
511
+ # Clamp to ensure it's in the proper range
512
+ tensor.clamp_(min=a, max=b)
513
+ return tensor
514
+
515
+
516
+ def trunc_normal_(tensor, mean=0., std=1., a=-2., b=2.):
517
+ # type: (Tensor, float, float, float, float) -> Tensor
518
+ return _no_grad_trunc_normal_(tensor, mean, std, a, b)
519
+
520
+
521
+ class LARS(torch.optim.Optimizer):
522
+ """
523
+ Almost copy-paste from https://github.com/facebookresearch/barlowtwins/blob/main/main.py
524
+ """
525
+
526
+ def __init__(self, params, lr=0, weight_decay=0, momentum=0.9, eta=0.001,
527
+ weight_decay_filter=None, lars_adaptation_filter=None):
528
+ defaults = dict(lr=lr, weight_decay=weight_decay, momentum=momentum,
529
+ eta=eta, weight_decay_filter=weight_decay_filter,
530
+ lars_adaptation_filter=lars_adaptation_filter)
531
+ super().__init__(params, defaults)
532
+
533
+ @torch.no_grad()
534
+ def step(self):
535
+ for g in self.param_groups:
536
+ for p in g['params']:
537
+ dp = p.grad
538
+
539
+ if dp is None:
540
+ continue
541
+
542
+ if p.ndim != 1:
543
+ dp = dp.add(p, alpha=g['weight_decay'])
544
+
545
+ if p.ndim != 1:
546
+ param_norm = torch.norm(p)
547
+ update_norm = torch.norm(dp)
548
+ one = torch.ones_like(param_norm)
549
+ q = torch.where(param_norm > 0.,
550
+ torch.where(update_norm > 0,
551
+ (g['eta'] * param_norm / update_norm), one), one)
552
+ dp = dp.mul(q)
553
+
554
+ param_state = self.state[p]
555
+ if 'mu' not in param_state:
556
+ param_state['mu'] = torch.zeros_like(p)
557
+ mu = param_state['mu']
558
+ mu.mul_(g['momentum']).add_(dp)
559
+
560
+ p.add_(mu, alpha=-g['lr'])
561
+
562
+
563
+ class MultiCropWrapper(nn.Module):
564
+ """
565
+ Perform forward pass separately on each resolution input.
566
+ The inputs corresponding to a single resolution are clubbed and single
567
+ forward is run on the same resolution inputs. Hence we do several
568
+ forward passes = number of different resolutions used. We then
569
+ concatenate all the output features and run the head forward on these
570
+ concatenated features.
571
+ """
572
+
573
+ def __init__(self, backbone, head):
574
+ super(MultiCropWrapper, self).__init__()
575
+ # disable layers dedicated to ImageNet labels classification
576
+ backbone.fc, backbone.head = nn.Identity(), nn.Identity()
577
+ self.backbone = backbone
578
+ self.head = head
579
+
580
+ def forward(self, x):
581
+ # convert to list
582
+ if not isinstance(x, list):
583
+ x = [x]
584
+ idx_crops = torch.cumsum(torch.unique_consecutive(
585
+ torch.tensor([inp.shape[-1] for inp in x]),
586
+ return_counts=True,
587
+ )[1], 0)
588
+ start_idx, output = 0, torch.empty(0).to(x[0].device)
589
+ for end_idx in idx_crops:
590
+ _out = self.backbone(torch.cat(x[start_idx: end_idx]))
591
+ # The output is a tuple with XCiT model. See:
592
+ # https://github.com/facebookresearch/xcit/blob/master/xcit.py#L404-L405
593
+ if isinstance(_out, tuple):
594
+ _out = _out[0]
595
+ # accumulate outputs
596
+ output = torch.cat((output, _out))
597
+ start_idx = end_idx
598
+ # Run the head forward on the concatenated features.
599
+ return self.head(output)
600
+
601
+
602
+ def get_params_groups(model):
603
+ regularized = []
604
+ not_regularized = []
605
+ for name, param in model.named_parameters():
606
+ if not param.requires_grad:
607
+ continue
608
+ # we do not regularize biases nor Norm parameters
609
+ if name.endswith(".bias") or len(param.shape) == 1:
610
+ not_regularized.append(param)
611
+ else:
612
+ regularized.append(param)
613
+ return [{'params': regularized}, {'params': not_regularized, 'weight_decay': 0.}]
614
+
615
+
616
+ def cancel_gradients_last_layer(epoch, model, freeze_last_layer):
617
+ if epoch >= freeze_last_layer:
618
+ return
619
+ for n, p in model.named_parameters():
620
+ if "last_layer" in n:
621
+ p.grad = None
622
+
623
+
624
+ def has_batchnorms(model):
625
+ bn_types = (nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d, nn.SyncBatchNorm)
626
+ for name, module in model.named_modules():
627
+ if isinstance(module, bn_types):
628
+ return True
629
+ return False
630
+
631
+
632
+ #####
633
+ def convert_weights_float(model: nn.Module):
634
+ """Convert applicable model parameters to fp32"""
635
+
636
+ def _convert_weights_to_fp32(l):
637
+ if isinstance(l, (nn.Conv1d, nn.Conv2d, nn.Linear)):
638
+ l.weight.data = l.weight.data.float()
639
+ if l.bias is not None:
640
+ l.bias.data = l.bias.data.float()
641
+
642
+ if isinstance(l, nn.MultiheadAttention):
643
+ for attr in [*[f"{s}_proj_weight" for s in ["in", "q", "k", "v"]], "in_proj_bias", "bias_k", "bias_v"]:
644
+ tensor = getattr(l, attr)
645
+ if tensor is not None:
646
+ tensor.data = tensor.data.float()
647
+
648
+ for name in ["text_projection", "proj"]:
649
+ if hasattr(l, name):
650
+ attr = getattr(l, name)
651
+ if attr is not None:
652
+ attr.data = attr.data.float()
653
+
654
+ model.apply(_convert_weights_to_fp32)
655
+
656
+
657
+ def split_reshape(x, bs, combination=None):
658
+ n = len(x) // bs
659
+ assert n in [2, 3], "The num augs should be 2 or 3 in number"
660
+ f = torch.split(x, [bs] * n, dim=0)
661
+ if combination is None:
662
+ x_reshape = torch.cat([f[i].unsqueeze(1) for i in range(n)], dim=1)
663
+ else:
664
+ x_reshape = torch.cat([f[i].unsqueeze(1) for i in combination], dim=1)
665
+
666
+ # if repeatcase:
667
+ # x_reshape = torch.cat([f1.unsqueeze(1), f1.unsqueeze(1)], dim=1)
668
+ return x_reshape
669
+
670
+
671
+ class AverageMeter(object):
672
+ """Computes and stores the average and current value"""
673
+
674
+ def __init__(self, name, fmt=":f"):
675
+ self.name = name
676
+ self.fmt = fmt
677
+ self.reset()
678
+
679
+ def reset(self):
680
+ self.val = 0
681
+ self.avg = 0
682
+ self.sum = 0
683
+ self.count = 0
684
+
685
+ def update(self, val, n=1):
686
+ self.val = val
687
+ self.sum += val * n
688
+ self.count += n
689
+ self.avg = self.sum / self.count
690
+
691
+ def __str__(self):
692
+ fmtstr = "{name} {val" + self.fmt + "} ({avg" + self.fmt + "})"
693
+ return fmtstr.format(**self.__dict__)
694
+
695
+
696
+ class ProgressMeter(object):
697
+ def __init__(self, num_batches, meters, prefix=""):
698
+ self.batch_fmtstr = self._get_batch_fmtstr(num_batches)
699
+ self.meters = meters
700
+ self.prefix = prefix
701
+
702
+ def display(self, batch):
703
+ entries = [self.prefix + self.batch_fmtstr.format(batch)]
704
+ entries += [str(meter) for meter in self.meters]
705
+ print("\t".join(entries))
706
+
707
+ def _get_batch_fmtstr(self, num_batches):
708
+ num_digits = len(str(num_batches // 1))
709
+ fmt = "{:" + str(num_digits) + "d}"
710
+ return "[" + fmt + "/" + fmt.format(num_batches) + "]"
711
+
712
+
713
+ @torch.no_grad()
714
+ def extract_features(model, data_loader, use_cuda=True, use_fp16=False, eval_embed='head'):
715
+ metric_logger = MetricLogger(delimiter=" ")
716
+ features = None
717
+ # count = 0
718
+ for samples, *_, index in metric_logger.log_every(data_loader, 100):
719
+ # print(f'At the index {index}')
720
+ samples = samples.cuda(non_blocking=True)
721
+ index = index.cuda(non_blocking=True)
722
+ if use_fp16:
723
+ with torch.cuda.amp.autocast():
724
+ bb_feats, cont_feats, style_feats = model(samples)
725
+
726
+ if eval_embed == 'backbone':
727
+ feats = bb_feats.clone()
728
+ else:
729
+ feats = style_feats.clone()
730
+
731
+ else:
732
+ bb_feats, cont_feats, style_feats = model(samples)
733
+ if eval_embed == 'backbone':
734
+ feats = bb_feats.clone()
735
+ else:
736
+ feats = style_feats.clone()
737
+ # init storage feature matrix
738
+ if dist.get_rank() == 0 and features is None:
739
+ features = torch.zeros(len(data_loader.dataset), feats.shape[-1], dtype=feats.dtype)
740
+ if use_cuda:
741
+ features = features.cuda(non_blocking=True)
742
+ print(f"Storing features into tensor of shape {features.shape}")
743
+
744
+ # get indexes from all processes
745
+ y_all = torch.empty(dist.get_world_size(), index.size(0), dtype=index.dtype, device=index.device)
746
+ y_l = list(y_all.unbind(0))
747
+ y_all_reduce = torch.distributed.all_gather(y_l, index, async_op=True)
748
+ y_all_reduce.wait()
749
+ index_all = torch.cat(y_l)
750
+
751
+ # share features between processes
752
+ feats_all = torch.empty(
753
+ dist.get_world_size(),
754
+ feats.size(0),
755
+ feats.size(1),
756
+ dtype=feats.dtype,
757
+ device=feats.device,
758
+ )
759
+ output_l = list(feats_all.unbind(0))
760
+ output_all_reduce = torch.distributed.all_gather(output_l, feats, async_op=True)
761
+ output_all_reduce.wait()
762
+
763
+ # update storage feature matrix
764
+ if dist.get_rank() == 0:
765
+ if use_cuda:
766
+ features.index_copy_(0, index_all, torch.cat(output_l))
767
+ else:
768
+ features.index_copy_(0, index_all.cpu(), torch.cat(output_l).cpu())
769
+ return features
770
+
771
+
772
+ # Copy from https://github.com/learn2phoenix/dynamicDistances/blob/main/metrics/metrics.py
773
+ class Metrics(object):
774
+ def __init__(self):
775
+ self.data = None
776
+
777
+ @staticmethod
778
+ def get_recall(preds, gts, topk=5):
779
+ preds = preds[:, :topk]
780
+ preds -= gts[:, None]
781
+ found = np.where(np.amin(np.absolute(preds), axis=1) == 0)[0]
782
+ return found.shape[0] / gts.shape[0]
783
+
784
+ @staticmethod
785
+ def get_mrr(preds, gts, topk=5):
786
+ preds = preds[:, :topk]
787
+ preds -= gts[:, None]
788
+ rows, cols = np.where(preds == 0)
789
+ _, unique_rows = np.unique(rows, return_index=True)
790
+ valid_cols = cols[unique_rows]
791
+ valid_cols += 1
792
+ return np.mean(1 / valid_cols)
793
+
794
+ @staticmethod
795
+ def get_map(preds, gts, topk=5):
796
+ preds = preds[:, :topk]
797
+ preds -= gts[:, None]
798
+ rows, cols = np.where(preds == 0)
799
+ _, unique_rows = np.unique(rows, return_index=True)
800
+ row_cols = np.split(cols, unique_rows)[1:]
801
+ row_cols = [np.hstack([x[0], np.diff(x), topk - x[-1]]) for x in row_cols]
802
+ row_cols = [np.pad(x, (0, topk + 1 - x.shape[0]), 'constant', constant_values=(0, 0)) for x in row_cols]
803
+ precision = np.asarray([np.repeat(np.arange(topk + 1), x) / np.arange(1, topk + 1) for x in row_cols])
804
+ return np.sum(np.mean(precision, axis=1)) / preds.shape[0]
805
+
806
+ @staticmethod
807
+ def get_recall_bin(preds, topk=5):
808
+ # preds is a binary matrix of size Q x K
809
+ preds = preds[:, :topk]
810
+ found = np.where(np.amax(preds, axis=1) == True)[0]
811
+ return found.shape[0] / preds.shape[0]
812
+
813
+ @staticmethod
814
+ def get_mrr_bin(preds, topk=5):
815
+ # preds is a binary matrix of size Q x K
816
+ preds = preds[:, :topk]
817
+ rows, cols = np.where(preds)
818
+ _, unique_rows = np.unique(rows, return_index=True)
819
+ valid_cols = cols[unique_rows]
820
+ valid_cols += 1
821
+ return np.mean(1 / valid_cols)
822
+
823
+ @staticmethod
824
+ def get_map_bin(preds, topk=5):
825
+ # preds is a binary matrix of size Q x K
826
+ preds = preds[:, :topk]
827
+ rows, cols = np.where(preds)
828
+ _, unique_rows = np.unique(rows, return_index=True)
829
+ row_cols = np.split(cols, unique_rows)[1:]
830
+ row_cols = [np.hstack([x[0], np.diff(x), topk - x[-1]]) for x in row_cols]
831
+ row_cols = [np.pad(x, (0, topk + 1 - x.shape[0]), 'constant', constant_values=(0, 0)) for x in row_cols]
832
+ precision = np.asarray([np.repeat(np.arange(topk + 1), x) / np.arange(1, topk + 1) for x in row_cols])
833
+ return np.sum(np.mean(precision, axis=1)) / preds.shape[0]
834
+
835
+
836
+ class GatherLayer(torch.autograd.Function):
837
+ """Gather tensors from all process, supporting backward propagation.
838
+ """
839
+
840
+ @staticmethod
841
+ def forward(ctx, input):
842
+ ctx.save_for_backward(input)
843
+ output = [torch.zeros_like(input) \
844
+ for _ in range(dist.get_world_size())]
845
+ dist.all_gather(output, input)
846
+ return tuple(output)
847
+
848
+ @staticmethod
849
+ def backward(ctx, *grads):
850
+ input, = ctx.saved_tensors
851
+ grad_out = torch.zeros_like(input)
852
+ grad_out[:] = grads[dist.get_rank()]
853
+ return grad_out
CSD/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2024 learn2phoenix
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
CSD/README.md ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Measuring Style Similarity in Diffusion Models
2
+ Check out the paper here - [arxiv](https://arxiv.org/abs/2404.01292).
3
+
4
+ ![alt text](github_teaser.jpg "Generations from Stable Diffusion and corresponding matches from LAION-Styles split")
5
+
6
+ ## Create and activate the environment
7
+
8
+ ```
9
+ conda env create -f environment.yml
10
+ conda activate style
11
+ ```
12
+
13
+ ## Download the pretrained weights for the CSD model
14
+
15
+ Please download the CSD model (ViT-L) weights [here](https://drive.google.com/file/d/1FX0xs8p-C7Ob-h5Y4cUhTeOepHzXv_46/view?usp=sharing).
16
+
17
+
18
+ ## Download the pretrained weights for the baseline models
19
+
20
+ You need these only if you want to test the baseline numbers. For `CLIP` and `DINO`, pretrained weights will be downloaded automatically. For `SSCD` and `MoCo`, please download the weights
21
+ from the links below and put them in `./pretrainedmodels` folder.
22
+
23
+ * SSCD: [resnet50](https://dl.fbaipublicfiles.com/sscd-copy-detection/sscd_disc_mixup.torchscript.pt)
24
+ * MoCO: [ViT-B](https://dl.fbaipublicfiles.com/moco-v3/vit-b-300ep/vit-b-300ep.pth.tar)
25
+
26
+
27
+
28
+ ## Download the WikiArt dataset
29
+ WikiArt can be downloaded from [here](https://drive.google.com/file/d/1vTChp3nU5GQeLkPwotrybpUGUXj12BTK/view?usp=drivesdk0)
30
+ or [here1](http://web.fsktm.um.edu.my/~cschan/source/ICIP2017/wikiart.zip)
31
+
32
+ After dataset is downloaded please put `./wikiart.csv` in the parent directory of the dataset. The final directory structure should look like this:
33
+ ```
34
+ path/to/WikiArt
35
+ ├── wikiart
36
+    ├── Abstract_Expressionism
37
+       ├── <filename>.jpg
38
+    ├── ...
39
+ └── wikiart.csv
40
+ ```
41
+
42
+ Also, make sure that you add a column `path` in the `wikiart.csv` file which contains the absolute path to the image.
43
+
44
+ ## Generate the embeddings
45
+
46
+ Once WikiArt dataset is set up, you can generate the CSD embeddings by running the following command. Please adjust
47
+ the `--data-dir` and `--embed_dir` accordingly. You should also adjust the batch size `--b` and number of workers `--j`
48
+ according to your machine. The command to generate baseline embeddings is same, you just need to change the `--pt_style`
49
+ with any of the following: `clip`, `dino`, `sscd`, `moco`.
50
+
51
+ ```angular2html
52
+ python main_sim.py --dataset wikiart -a vit_large --pt_style csd --feattype normal --world-size 1
53
+ --dist-url tcp://localhost:6001 -b 128 -j 8 --embed_dir ./embeddings --data-dir <path to WikiArt dataset>
54
+ --model_path <path to CSD weights>
55
+ ```
56
+
57
+ ## Evaluate
58
+ Once you've generated the embeddings, run the following command:
59
+
60
+ ```angular2html
61
+ python search.py --mode artist --dataset wikiart --chunked --query-chunk-dir <path to query embeddings above>
62
+ --database-chunk-dir <path to database embeddings above> --topk 1 10 100 1000 --method IP --data-dir <path to WikiArt dataset>
63
+ ```
64
+
65
+ ## Train CSD on LAION-Styles
66
+
67
+ You can also train style descriptors for your own datasets. A sample code for training on LAION-styles dataset is provided below.
68
+
69
+ We have started to release the **Contra-Styles** (referred to as LAION-Styles in the paper) dataset. The dataset is available [here](https://huggingface.co/datasets/tomg-group-umd/ContraStyles)
70
+ and will keep getting updated over the next few days as we are running profanity checks through NSFW and PhotoDNA. We will update here once the dataset has been completely uploaded.
71
+
72
+ ```
73
+ export PYTHONPATH="$PWD:$PYTHONPATH"
74
+
75
+ torchrun --standalone --nproc_per_node=4 CSD/train_csd.py --arch vit_base -j 8 -b 32 --maxsize 512 --resume_if_available --eval_k 1 10 100 --use_fp16 --use_distributed_loss --train_set laion_dedup --train_path <PATH to LAION-Styles> --eval_path <PATH to WikiArt/some val set> --output_dir <PATH to save checkpoint>
76
+ ```
77
+
78
+ ## Pending items
79
+
80
+ We will soon release the code to compute the artists' prototypical style representations and compute similarity score against any given generation. ETA end of June'24.
81
+
82
+ ## Cite us
83
+
84
+ ```
85
+ @article{somepalli2024measuring,
86
+ title={Measuring Style Similarity in Diffusion Models},
87
+ author={Somepalli, Gowthami and Gupta, Anubhav and Gupta, Kamal and Palta, Shramay and Goldblum, Micah and Geiping, Jonas and Shrivastava, Abhinav and Goldstein, Tom},
88
+ journal={arXiv preprint arXiv:2404.01292},
89
+ year={2024}
90
+ }
91
+ ```
CSD/__init__.py ADDED
File without changes
CSD/artists_400.txt ADDED
@@ -0,0 +1,400 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ leonid afremov
2
+ georges seurat
3
+ amedeo modigliani
4
+ Alan bean
5
+ scott naismith
6
+ antoine blanchard
7
+ frederic remington
8
+ Artgerm
9
+ Greg Rutkowski
10
+ mucha
11
+ Alphonse Mucha
12
+ WLOP
13
+ Ilya Kuvshinov
14
+ stanley artgerm
15
+ Makoto Shinkai
16
+ rossdraws
17
+ James Jean
18
+ Magali Villeneuve
19
+ Donato Giancola
20
+ loish
21
+ Ruan Jia
22
+ Studio Ghibli
23
+ Beeple
24
+ Ross Tran
25
+ Beksinski
26
+ Peter Mohrbacher
27
+ Marc Simonetti
28
+ Tom Bagshaw
29
+ Craig Mullins
30
+ Pixar
31
+ Boris Vallejo
32
+ joseph christian leyendecker
33
+ Charlie Bowater
34
+ Dan Mumford
35
+ Moebius
36
+ amano
37
+ tomasz alen kopera
38
+ Norman Rockwell
39
+ Thomas Kinkade
40
+ Giger
41
+ Michael Garmash
42
+ Victo Ngai
43
+ Lois van Baarle
44
+ Klimt
45
+ RHADS
46
+ Jordan Grimmer
47
+ Bruce Pennington
48
+ James Gurney
49
+ disney
50
+ Michael Whelan
51
+ Frank Frazetta
52
+ Tim Hildebrandt
53
+ Raphael
54
+ Caravaggio
55
+ James Gilleard
56
+ Simon Stalenhag
57
+ Gil Elvgren
58
+ Zdzislaw Beksinski
59
+ Edward Hopper
60
+ gaston bussiere
61
+ Larry Elmore
62
+ Fenghua Zhong
63
+ Mike Mignola
64
+ Karol Bak
65
+ Francis Bacon
66
+ Brom
67
+ Syd Mead
68
+ Gustav Klimt
69
+ Jesper Ejsing
70
+ Noah Bradley
71
+ Steve McCurry
72
+ Gustave Dore
73
+ Atey Ghailan
74
+ gustav dore
75
+ Alex Ross
76
+ Mark Brooks
77
+ albert aublet
78
+ Raphael Lacoste
79
+ John Collier
80
+ Alex Grey
81
+ Rembrandt
82
+ Eddie Mendoza
83
+ Julie Bell
84
+ Android Jones
85
+ Miyazaki
86
+ Greg Hildebrandt
87
+ Gerald Brom
88
+ Darek Zabrocki
89
+ Titian
90
+ Jim Burns
91
+ Guy Denning
92
+ Mattias Adolfsson
93
+ Raymond Swanland
94
+ Ernst
95
+ Wes Anderson
96
+ Feng Zhu
97
+ Luis Royo
98
+ Justin Gerard
99
+ Hayao Miyazaki
100
+ Takato Yamamoto
101
+ Tyler Edlin
102
+ Bob Eggleton
103
+ Jakub Rozalski
104
+ Tuomas Korpi
105
+ Maxfield Parrish
106
+ Kilian Eng
107
+ Rebecca Guay
108
+ ferdinand knab
109
+ Jamie Wyeth
110
+ John Berkey
111
+ John Singer Sargent
112
+ Rene Magritte
113
+ Zaha Hadid
114
+ Josan Gonzalez
115
+ Shaddy Safadi
116
+ Carl Spitzweg
117
+ hajime sorayama
118
+ Conrad Roset
119
+ lovecraft
120
+ Simon Stålenhag
121
+ Masamune Shirow
122
+ Leonardo da Vinci
123
+ Gediminas Pranckevicius
124
+ charles vess
125
+ Jason Chan
126
+ Anton Fadeev
127
+ Albert Bierstadt
128
+ hr giger
129
+ Dali
130
+ Roger Dean
131
+ Zdzisław Beksiński
132
+ Bayard Wu
133
+ Ivan Shishkin
134
+ Bob Ross
135
+ Andreas Rocha
136
+ Warhol
137
+ Joe Fenton
138
+ Hiroshi Yoshida
139
+ Goro Fujita
140
+ Cedric Peyravernay
141
+ Jan van Eyck
142
+ Ismail Inceoglu
143
+ Ralph Horsley
144
+ Andy Warhol
145
+ Tomer Hanuka
146
+ Jean Giraud
147
+ Gustave Courbet
148
+ Roberto Ferri
149
+ Dustin Nguyen
150
+ Mark Arian
151
+ Louis Wain
152
+ Ernst Haeckel
153
+ Ivan Aivazovsky
154
+ Salvador Dali
155
+ Arthur Rackham
156
+ Louis Comfort Tiffany
157
+ Maciej Kuciara
158
+ John Harris
159
+ Andrew Wyeth
160
+ Mark Ryden
161
+ Junji Ito
162
+ sung choi
163
+ Alan Lee
164
+ sylvain sarrailh
165
+ Gaudi
166
+ Max Ernst
167
+ Filip Hodas
168
+ Daarken
169
+ Ralph McQuarrie
170
+ Sailor Moon
171
+ roger deakins
172
+ Rosa Bonheur
173
+ Brad Kunkle
174
+ Lee Madgwick
175
+ Caspar David Friedrich
176
+ Alberto Vargas
177
+ Chris Foss
178
+ Alena Aenami
179
+ Ian McQue
180
+ Wadim Kashin
181
+ Jean Delville
182
+ Fra Angelico
183
+ Peter Elson
184
+ Martin Johnson Heade
185
+ John Howe
186
+ Anna Dittmann
187
+ Zack Snyder
188
+ Jim Lee
189
+ Hieronymus Bosch
190
+ Josephine Wall
191
+ jessica rossier
192
+ Michelangelo
193
+ Michaelangelo
194
+ Ryohei Hase
195
+ Ilya Repin
196
+ Annie Leibovitz
197
+ Picasso
198
+ Stephan Martiniere
199
+ Frank Stella
200
+ Eugene von Guerard
201
+ Hokusai
202
+ Alexander McQueen
203
+ Tyler Jacobson
204
+ Monet
205
+ William Turner
206
+ Van Gogh
207
+ Anne Stokes
208
+ Jeff Koons
209
+ Frank Miller
210
+ Anton Pieck
211
+ Christopher Balaskas
212
+ Ernst Fuchs
213
+ Thomas Cole
214
+ Carne Griffiths
215
+ Mikhail Vrubel
216
+ John William Waterhouse
217
+ John William Godward
218
+ Arcimboldo
219
+ Vermeer
220
+ Daniel Merriam
221
+ James Paick
222
+ Takashi Murakami
223
+ Murakami
224
+ Jan Matejko
225
+ Banksy
226
+ Cyril Rolando
227
+ Amanda Sage
228
+ Miho Hirano
229
+ Eric Zener
230
+ Remedios Varo
231
+ Liam Wong
232
+ Art Green
233
+ Ed Roth
234
+ Drew Struzan
235
+ Jacek Yerka
236
+ Kelly McKernan
237
+ Raja Ravi Varma
238
+ ashley wood
239
+ Kandinsky
240
+ Sam Spratt
241
+ Rolf Armstrong
242
+ Bauhaus
243
+ Esao Andrews
244
+ ESAO
245
+ Richter
246
+ Gertrude Abercrombie
247
+ Yuumei
248
+ Jack Kirby
249
+ Victor Nizovtsev
250
+ Roy Lichtenstein
251
+ Lichtenstein
252
+ Harumi Hironaka
253
+ Paul Lehr
254
+ Les Edwards
255
+ Mike Winkelmann
256
+ Dan Luvisi
257
+ Art Frahm
258
+ ridley scott
259
+ Diego Rivera
260
+ irakli nadar
261
+ Dante Gabriel Rossetti
262
+ Francisco Goya
263
+ Evelyn De Morgan
264
+ Frederic Edwin Church
265
+ Frederick Edwin Church
266
+ Jon Foster
267
+ John Carpenter
268
+ Giuseppe Arcimboldo
269
+ Marcel Duchamp
270
+ MC Escher
271
+ Giorgio de Chirico
272
+ Frans Hals
273
+ Winslow Homer
274
+ adrian ghenie
275
+ Gerhard Richter
276
+ Cecil Beaton
277
+ Martine Johanna
278
+ Tom Whalen
279
+ Brian Froud
280
+ Sandra Chevrier
281
+ Vincent Van Gogh
282
+ Yasutomo Oka
283
+ Gregory Crewdson
284
+ George Stubbs
285
+ Eyvind Earle
286
+ Gustave Baumann
287
+ Yanjun Cheng
288
+ Tran Nguyen
289
+ Marina Abramović
290
+ Cy Twombly
291
+ Anselm Kiefer
292
+ John James Audubon
293
+ Chris Moore
294
+ Hasui Kawase
295
+ Scott Listfield
296
+ Hugh Ferriss
297
+ Claude Monet
298
+ Jeff Easley
299
+ Michael Komarck
300
+ Jeremy Geddes
301
+ Yves Tanguy
302
+ Svetlin Velinov
303
+ Lucian Freud
304
+ Viktor Vasnetsov
305
+ Gustave Doré
306
+ Hikari Shimoda
307
+ Edmund Dulac
308
+ William Blake
309
+ Thomas Eakins
310
+ Frederic Church
311
+ Gian Lorenzo Bernini
312
+ Bill Sienkiewicz
313
+ David Hockney
314
+ Lucas Graciano
315
+ national geographic
316
+ Frida Kahlo
317
+ Kahlo
318
+ Jaime Jones
319
+ Donald Judd
320
+ Kawase Hasui
321
+ Tim Okamura
322
+ Anton Otto Fischer
323
+ Tom Lovell
324
+ Richard Hamilton
325
+ Emiliano Ponzi
326
+ Charles Marion Russell
327
+ Ina Wong
328
+ Adam Paquette
329
+ Otto Dix
330
+ Gabriel Dawe
331
+ Mary Cassatt
332
+ Arkhip Kuindzhi
333
+ Jason Felix
334
+ Piranesi
335
+ Marianne North
336
+ Peter Lindbergh
337
+ Georges de La Tour
338
+ Francis Picabia
339
+ Kay Nielsen
340
+ Sanford Robinson Gifford
341
+ Hans Baluschek
342
+ Audrey Kawasaki
343
+ Mark Rothko
344
+ Frank Auerbach
345
+ Winston Churchill
346
+ Cynthia Sheppard
347
+ Chris Rahn
348
+ Todd Lockwood
349
+ Harry Clarke
350
+ Coby Whitmore
351
+ Margaret Keane
352
+ Man Ray
353
+ Hubert Robert
354
+ Dorothea Tanning
355
+ Ivan Bilibin
356
+ Austin Osman Spare
357
+ Paul Klee
358
+ Frederic Leighton
359
+ Alfonse Mucha
360
+ Fernando Botero
361
+ Marco Mazzoni
362
+ Evgeny Lushpin
363
+ John Atkinson Grimshaw
364
+ Peter Paul Rubens
365
+ Thomas Lawrence
366
+ Yasar Vurdem
367
+ Isaac Levitan
368
+ Asher Brown Durand
369
+ Yoann Lossel
370
+ Henry Ossawa Tanner
371
+ Bill Ward
372
+ Jean Arp
373
+ Jenny Saville
374
+ Katsushika Hokusai
375
+ Kim Keever
376
+ Pablo Picasso
377
+ Robert Delaunay
378
+ Delaunay
379
+ Chris Rallis
380
+ Oleg Oprisco
381
+ Anka Zhuravleva
382
+ Walt Disney
383
+ Tom Chambers
384
+ Salvador Dalí
385
+ Dalí
386
+ Edward Gorey
387
+ William Morris
388
+ Takeshi Obata
389
+ Juan Luna
390
+ Christophe Vacher
391
+ Grzegorz Rutkowski
392
+ Tamara de Lempicka
393
+ Tadao Ando
394
+ Peter Gric
395
+ sparth
396
+ Leonora Carrington
397
+ Mœbius
398
+ Constant
399
+ John Anster Fitzgerald
400
+ Patrick Nagel
CSD/data/laion.py ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from PIL import Image
3
+ from torch.utils.data import Dataset
4
+ import numpy as np
5
+ from tqdm import tqdm
6
+ import pickle
7
+ import vaex as vx
8
+
9
+
10
+ def create_laion_cache(root_dir, anno_dir, keys=['artist', 'medium', 'movement']):
11
+ # -projects/diffusion_rep/data/laion_style_subset
12
+ # read all the picke files in the anno_dir
13
+ paths = []
14
+ labels = [] # list of lists since each image can have multiple labels
15
+ labels_to_index = {} # dictionary that maps each label to an list of image indices
16
+
17
+ keys_offset = {k: 1000000 * i for i, k in enumerate(keys)} # offset each key labels by a large number
18
+
19
+ str_to_list = lambda x, offset: [offset + int(a) for a in x.strip().split(',') if len(a) > 0]
20
+ for f in tqdm(os.listdir(anno_dir)):
21
+ if f.endswith('.pkl'):
22
+ with open(os.path.join(anno_dir, f), 'rb') as tmp:
23
+ ann = pickle.load(tmp)
24
+
25
+ for i, path in enumerate(ann['key']):
26
+ cur_label = {
27
+ k: str_to_list(ann[k][i], keys_offset[k])
28
+ for k in keys
29
+ }
30
+ cur_label = sum(cur_label.values(), [])
31
+ if len(cur_label) > 0:
32
+ image_path = os.path.join(root_dir, 'data', path[:5], path + '.jpg')
33
+
34
+ # if not os.path.exists(image_path):
35
+ # continue
36
+
37
+ paths.append(image_path)
38
+ labels.append(set(cur_label))
39
+ for l in cur_label: labels_to_index.setdefault(l, []).append(i)
40
+
41
+ cache_path = os.path.join(anno_dir, '_'.join(keys) + '.cache')
42
+ with open(cache_path, 'wb') as tmp:
43
+ pickle.dump((paths, labels, labels_to_index), tmp)
44
+ return paths, labels, labels_to_index
45
+
46
+
47
+ class LAION(Dataset):
48
+ def __init__(self, root_dir, anno_dir, split='database', transform=None,
49
+ keys=['artist', 'medium', 'movement'],
50
+ min_images_per_label=1, max_images_per_label=100000,
51
+ num_queries_per_label=10, maxsize=None, model_type='dann'):
52
+ # -projects/diffusion_rep/data/laion_style_subset
53
+ self.root_dir = root_dir
54
+ self.transform = transform
55
+ self.model_type = model_type
56
+
57
+ # read all the picke files in the anno_dir
58
+ paths = []
59
+ labels = [] # list of lists since each image can have multiple labels
60
+ labels_to_index = {} # dictionary that maps each label to an list of image indices
61
+
62
+ cache_path = os.path.join(anno_dir, '_'.join(keys) + '.cache')
63
+ if os.path.exists(cache_path):
64
+ with open(cache_path, 'rb') as tmp:
65
+ paths, labels, labels_to_index = pickle.load(tmp)
66
+ else:
67
+ paths, labels, labels_to_index = create_laion_cache(root_dir, anno_dir, keys)
68
+
69
+ maxout_labels = [l for l, v in labels_to_index.items() if len(v) > max_images_per_label]
70
+ maxout_labels.append('') # Artificially add an empty label
71
+ print(f"Removing {len(maxout_labels)} tags with > {max_images_per_label} images")
72
+
73
+ minout_labels = [l for l, v in labels_to_index.items() if len(v) < min_images_per_label]
74
+ print(f"Removing {len(minout_labels)} tags with < {min_images_per_label} images")
75
+
76
+ # Get all possible tags
77
+ self.index_to_labels = list(set(labels_to_index.keys()) - set(maxout_labels) - set(minout_labels))
78
+ self.labels_to_index = {l: i for i, l in enumerate(self.index_to_labels)}
79
+
80
+ self.pathlist = []
81
+ self.labels = []
82
+ eye = np.eye(len(self.index_to_labels))
83
+ print("Filtering out labels")
84
+ for path, label in tqdm(zip(paths, labels)):
85
+ for l in maxout_labels:
86
+ if l in label:
87
+ label.remove(l)
88
+
89
+ for l in minout_labels:
90
+ if l in label:
91
+ label.remove(l)
92
+
93
+ if len(label) > 0:
94
+ self.pathlist.append(path)
95
+ cur_label = np.sum(eye[[self.labels_to_index[l] for l in label]], axis=0).astype(bool)
96
+ self.labels.append(cur_label)
97
+ self.labels = np.array(self.labels)
98
+
99
+ ## Split the dataset into index and query
100
+ keys_offset = {k: 1000000 * i for i, k in enumerate(keys)}
101
+ self.name_to_label = {}
102
+ for k in keys:
103
+ key_labels_path = os.path.join(
104
+ anno_dir, '../clip-interrogator/clip_interrogator/data',
105
+ k + "s_filtered_new.txt")
106
+ with open(os.path.join(key_labels_path)) as f:
107
+ for i, l in enumerate(f.readlines()):
108
+ self.name_to_label[l.strip().replace("@", " ")] = keys_offset[k] + i
109
+
110
+ with open(os.path.join(anno_dir, 'top612_artists_shortlist_400.txt'), 'r') as f:
111
+ q_names = [l.lower().strip() for l in f.readlines()]
112
+ q_labels = [self.name_to_label[n] for n in q_names]
113
+ q_index = [self.labels_to_index[l] for l in q_labels]
114
+
115
+ query_ind = np.unique(np.concatenate(
116
+ [np.where(self.labels[:, i])[0][:num_queries_per_label]
117
+ for i in q_index]))
118
+
119
+ if split == "database":
120
+ self.pathlist = [self.pathlist[i] for i in range(len(self.pathlist)) if i not in query_ind]
121
+ self.labels = np.delete(self.labels, query_ind, axis=0)
122
+ else:
123
+ self.pathlist = [self.pathlist[i] for i in query_ind]
124
+ self.labels = self.labels[query_ind]
125
+
126
+ self.namelist = list(map(lambda x: x.split('/')[-1], self.pathlist))
127
+ # Select maxsize number of images
128
+ if maxsize is not None:
129
+ ind = np.random.randint(0, len(self.pathlist), maxsize)
130
+ self.pathlist = [self.pathlist[i] for i in ind]
131
+ self.labels = self.labels[ind]
132
+ self.namelist = [self.namelist[i] for i in ind]
133
+
134
+ def __len__(self):
135
+ return len(self.pathlist)
136
+
137
+ def __getitem__(self, idx):
138
+ img_loc = self.pathlist[idx]
139
+ image = Image.open(img_loc).convert("RGB")
140
+
141
+ if self.transform:
142
+ images = self.transform(image)
143
+
144
+ style = self.labels[idx]
145
+ if self.model_type == 'dann':
146
+ return images, style, idx
147
+ else:
148
+ return images, idx
149
+
150
+
151
+ def create_laion_dedup_cache(dedup_dir):
152
+ # -projects/diffusion_rep/data/laion_style_subset/dedup_info
153
+ keys = None
154
+ labels = None
155
+ rejects = None
156
+ matching_info = None
157
+
158
+ files = [f for f in os.listdir(dedup_dir) if f.endswith('.parquet')]
159
+ for f in tqdm(sorted(files, key=lambda x: int(x.split('_')[2]))):
160
+ # Load dedup info
161
+ df = vx.open(os.path.join(dedup_dir, f))
162
+ if keys is None:
163
+ keys = df['name'].tolist()
164
+
165
+ # Updating reject information
166
+ cur_reject = df['matched'].to_numpy()
167
+ if rejects is not None:
168
+ rejects += cur_reject
169
+ else:
170
+ rejects = cur_reject
171
+
172
+ # Load labels
173
+ cur_labels = np.load(os.path.join(dedup_dir, f.replace('parquet', 'npz').replace('val_db', 'multilabel')))
174
+ cur_labels = cur_labels["arr_0"]
175
+ if labels is not None:
176
+ labels += cur_labels
177
+ else:
178
+ labels = cur_labels
179
+
180
+ # Load matching info
181
+ cur_matching_info = pickle.load(
182
+ open(os.path.join(dedup_dir, f.replace('parquet', 'pkl').replace('val_db', 'matching_info')), 'rb'))
183
+ if matching_info is not None:
184
+ matching_info.extend(cur_matching_info)
185
+ else:
186
+ matching_info = cur_matching_info
187
+
188
+ # Propagating labels
189
+ for i in tqdm(range(len(matching_info) - 1, -1, -1)):
190
+ labels[i] += np.sum(labels[matching_info[i], :], axis=0, dtype=bool)
191
+
192
+ cache_path = os.path.join(dedup_dir, 'joined.cache')
193
+ with open(cache_path, 'wb') as tmp:
194
+ pickle.dump((keys, labels, rejects), tmp)
195
+ return keys, labels, rejects
196
+
197
+
198
+ class LAIONDedup(Dataset):
199
+ def __init__(self, root_dir, anno_dir, transform=None, model_type='dann', eval_mode=False, artist_mode=False):
200
+ self.root_dir = root_dir
201
+ self.transform = transform
202
+ self.model_type = model_type
203
+
204
+ dedup_dir = os.path.join(anno_dir, 'dedup_info')
205
+ cache_path = os.path.join(dedup_dir, 'joined.cache')
206
+ if os.path.exists(cache_path):
207
+ with open(cache_path, 'rb') as tmp:
208
+ keys, labels, rejects = pickle.load(tmp)
209
+ else:
210
+ keys, labels, rejects = create_laion_dedup_cache(dedup_dir)
211
+
212
+ keys = np.array(keys)[~rejects]
213
+ self.pathlist = [os.path.join(root_dir, 'data', key[:5], key + '.jpg') for key in keys]
214
+ self.labels = labels[~rejects]
215
+ self.namelist = list(map(lambda x: x.split('/')[-1], self.pathlist))
216
+
217
+ if eval_mode:
218
+ q_dset = LAION(root_dir, anno_dir, split='query')
219
+ self.query_db = vx.from_arrays(
220
+ name=[x.split('.')[0] for x in q_dset.namelist],
221
+ multilabel=q_dset.labels)
222
+
223
+ self.name_to_label = q_dset.name_to_label
224
+ self.labels_to_index = q_dset.labels_to_index
225
+ self.index_to_labels = q_dset.index_to_labels
226
+
227
+ self.val_db = vx.from_arrays(
228
+ name=keys.tolist(),
229
+ multilabel=self.labels)
230
+
231
+ if artist_mode:
232
+ # Filtering the db to include images which have hit on an artist
233
+ artist_inds = []
234
+ for label, index in self.labels_to_index.items():
235
+ if label < 1000000:
236
+ artist_inds.append(index)
237
+ artist_labels = self.labels[:, artist_inds]
238
+ artist_images = np.argwhere(np.sum(artist_labels, axis=1) > 0)
239
+ self.val_db = self.val_db.take(artist_images.squeeze()).extract()
240
+
241
+ def __len__(self):
242
+ return len(self.pathlist)
243
+
244
+ def __getitem__(self, idx):
245
+ img_loc = self.pathlist[idx]
246
+ image = Image.open(img_loc).convert("RGB")
247
+
248
+ if self.transform:
249
+ images = self.transform(image)
250
+
251
+ style = self.labels[idx]
252
+ if self.model_type == 'dann':
253
+ return images, style, idx
254
+ else:
255
+ return images, idx
256
+
257
+ def get_query_col(self, col):
258
+ return np.asarray(self.query_db[col].tolist())
259
+
260
+ def get_val_col(self, col):
261
+ return np.asarray(self.val_db[col].tolist())
262
+
263
+
264
+ class SDSynth400:
265
+ def __init__(self, root_dir, query_split='user_caps', transform=None, eval_mode=False):
266
+ self.root_dir = root_dir
267
+ self.transform = transform
268
+ self.query_split = query_split
269
+ assert query_split in ['user_caps', 'simple_caps', 'woman_caps', 'house_caps', 'dog_caps']
270
+ assert os.path.exists(os.path.join(root_dir, f'{query_split}.csv'))
271
+ annotations = vx.from_csv(f'{self.root_dir}/{query_split}.csv')
272
+
273
+ self.pathlist = annotations['filepath'].tolist()
274
+ self.namelist = list(map(lambda x: x.split('/')[-1], self.pathlist))
275
+
276
+ # Dummy variables, not actually needed
277
+ self.query_images = []
278
+ self.val_images = []
279
+
280
+ if eval_mode:
281
+ data_dir = '-datasets/improved_aesthetics_6plus'
282
+ anno_dir = '-projects/diffusion_rep/data/laion_style_subset'
283
+ val_dset = LAIONDedup(data_dir, anno_dir, transform=transform, eval_mode=True, artist_mode=True)
284
+ # val_dset = LAION(data_dir, anno_dir, transform=transform)
285
+ # Needed for search code
286
+ filenames = [f.split('.')[0] for f in self.namelist]
287
+ q_names = [[l.lower().strip() for l in eval(label)] for label in annotations['labels'].tolist()]
288
+ q_labels = [[val_dset.name_to_label[n] for n in names if n in val_dset.name_to_label] for names in q_names]
289
+ q_index = [[val_dset.labels_to_index[l] for l in labels if l in val_dset.labels_to_index] for labels in
290
+ q_labels]
291
+
292
+ eye = np.eye(len(val_dset.index_to_labels))
293
+ q_binlabels = [np.sum(eye[ind], axis=0).astype(bool) for ind in q_index]
294
+ self.query_db = vx.from_arrays(
295
+ name=filenames, multilabel=q_binlabels)
296
+ self.val_db = val_dset.val_db
297
+
298
+ def __len__(self):
299
+ return len(self.namelist)
300
+
301
+ def __getitem__(self, idx):
302
+ img_loc = self.pathlist[idx]
303
+ image = Image.open(img_loc).convert("RGB")
304
+ if self.transform:
305
+ image = self.transform(image)
306
+
307
+ return image, idx
308
+
309
+ def get_query_col(self, col):
310
+ return np.asarray(self.query_db[col].tolist())
311
+
312
+ def get_val_col(self, col):
313
+ return np.asarray(self.val_db[col].tolist())
314
+
315
+
316
+ if __name__ == "__main__":
317
+ # dset = WikiArt(
318
+ # "-projects/diffusion_rep/data/wikiart", 'database')
319
+
320
+ dset = LAION(
321
+ "-datasets/improved_aesthetics_6plus",
322
+ "-projects/diffusion_rep/data/laion_style_subset",
323
+ split='database')
324
+ print(f"{len(dset)} images in the dataset")
325
+
326
+ index_to_labels = []
327
+ index_to_keys = []
328
+ index_to_texts = []
329
+ label_to_name = {v: k for k, v in dset.name_to_label.items()}
330
+ for label in dset.index_to_labels:
331
+ index_to_texts.append(label_to_name[label])
332
+ index_to_labels.append(label)
333
+ if label < 1000000:
334
+ index_to_keys.append('artist')
335
+ elif label < 2000000:
336
+ index_to_keys.append('medium')
337
+ else:
338
+ index_to_keys.append('movement')
339
+
340
+ path = "-projects/diffusion_rep/data/laion_style_subset/index_to_labels_keys_texts.pkl"
341
+ with open(path, 'wb') as tmp:
342
+ pickle.dump((index_to_labels, index_to_keys, index_to_texts), tmp)
343
+
344
+ # dset = LAION(
345
+ # "-datasets/improved_aesthetics_6plus",
346
+ # "-projects/diffusion_rep/data/laion_style_subset",
347
+ # split='query',
348
+ # min_images_per_label=10,
349
+ # max_images_per_label=100000)
350
+
351
+ # print(f"{len(dset)} images in the dataset")
352
+
353
+ # dset = LAIONDedup(
354
+ # "-datasets/improved_aesthetics_6plus",
355
+ # "-projects/diffusion_rep/data/laion_style_subset",
356
+ # eval_mode=True)
CSD/data/wikiart.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pathlib
2
+ import os
3
+ import sys
4
+ import os.path as osp
5
+ from PIL import Image
6
+ from torch.utils.data import Dataset
7
+ import pandas as pd
8
+ import vaex as vx
9
+ import numpy as np
10
+
11
+
12
+ sys.path.insert(0, str(pathlib.Path(__file__).parent.resolve()))
13
+
14
+
15
+ class WikiArt(object):
16
+ def __init__(self, root_dir):
17
+ assert osp.exists(osp.join(root_dir, 'wikiart.csv'))
18
+ self.root_dir = root_dir
19
+ annotations = vx.from_csv(f'{self.root_dir}/wikiart.csv')
20
+ acceptable_artists = list(set(annotations[annotations['split'] == 'database']['artist'].tolist()))
21
+ temprepo = annotations[annotations['artist'].isin(acceptable_artists)]
22
+ self.query_images = temprepo[temprepo['split'] == 'query']['name'].tolist()
23
+ self.val_images = temprepo[temprepo['split'] == 'database']['name'].tolist()
24
+ self.query_db = annotations[annotations['name'].isin(self.query_images)]
25
+ self.val_db = annotations[annotations['name'].isin(self.val_images)]
26
+ self.query_db['name'] = self.query_db['name'].apply(lambda x: '.'.join(x.split('.')[:-1]))
27
+ self.val_db['name'] = self.val_db['name'].apply(lambda x: '.'.join(x.split('.')[:-1]))
28
+
29
+ def get_query_col(self, col):
30
+ return np.asarray(self.query_db[col].tolist())
31
+
32
+ def get_val_col(self, col):
33
+ return np.asarray(self.val_db[col].tolist())
34
+
35
+
36
+ class WikiArtD(Dataset):
37
+ def __init__(self, root_dir, split, transform=None):
38
+ self.root_dir = root_dir
39
+ self.transform = transform
40
+ self.split = split
41
+ assert osp.exists(osp.join(root_dir, 'wikiart.csv'))
42
+ annotations = vx.from_csv(f'{self.root_dir}/wikiart.csv')
43
+ acceptable_artists = list(set(annotations[annotations['split'] == 'database']['artist'].tolist()))
44
+ temprepo = annotations[annotations['artist'].isin(acceptable_artists)]
45
+ self.pathlist = temprepo[temprepo['split'] == split]['path'].tolist()
46
+
47
+ self.namelist = list(map(lambda x: x.split('/')[-1], self.pathlist))
48
+
49
+ def __len__(self):
50
+ return len(self.namelist)
51
+
52
+ def __getitem__(self, idx):
53
+ img_loc = self.pathlist[idx] # os.path.join(self.root_dir, self.split,self.artists[idx] ,self.pathlist[idx])
54
+ image = Image.open(img_loc).convert("RGB")
55
+ if self.transform:
56
+ image = self.transform(image)
57
+
58
+ return image, idx
59
+
60
+
61
+ class WikiArtTrain(Dataset):
62
+ def __init__(self, root_dir, split='database', transform=None, maxsize=None):
63
+ self.root_dir = root_dir
64
+ self.transform = transform
65
+ self.split = split
66
+ assert os.path.exists(os.path.join(root_dir, 'wikiart.csv'))
67
+ annotations = pd.read_csv(f'{self.root_dir}/wikiart.csv')
68
+ acceptable_artists = list(
69
+ set(annotations[annotations['split'] == 'database']['artist'].tolist())
70
+ )
71
+ temprepo = annotations[annotations['artist'].isin(acceptable_artists)]
72
+ self.pathlist = temprepo[temprepo['split'] == split]['path'].tolist()
73
+ self.labels = temprepo[temprepo['split'] == split]['artist'].tolist()
74
+
75
+ self.artist_to_index = {artist: i for i, artist in enumerate(acceptable_artists)}
76
+ self.index_to_artist = acceptable_artists
77
+
78
+ # Convert labels to one-hot
79
+ self.labels = list(map(lambda x: self.artist_to_index[x], self.labels))
80
+ self.labels = np.eye(len(acceptable_artists))[self.labels].astype(bool)
81
+ self.namelist = list(map(lambda x: x.split('/')[-1], self.pathlist))
82
+
83
+ # Select maxsize number of images
84
+ if maxsize is not None:
85
+ ind = np.random.randint(0, len(self.namelist), maxsize)
86
+ self.namelist = [self.namelist[i] for i in ind]
87
+ self.pathlist = [self.pathlist[i] for i in ind]
88
+ self.labels = self.labels[ind]
89
+
90
+ def __len__(self):
91
+ return len(self.namelist)
92
+
93
+ def __getitem__(self, idx):
94
+
95
+ img_loc = self.pathlist[idx]
96
+ image = Image.open(img_loc).convert("RGB")
97
+
98
+ if self.transform:
99
+ images = self.transform(image)
100
+
101
+ artist = self.labels[idx]
102
+ return images, artist, idx
CSD/embeddings/.gitkeep ADDED
File without changes
CSD/environment.yaml ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: style
2
+ channels:
3
+ - pytorch
4
+ - defaults
5
+ - conda-forge
6
+ dependencies:
7
+ - pillow
8
+ - pip
9
+ - python=3.9
10
+ - pytorch=*=*cuda11.3*
11
+ - cudatoolkit>=11.3
12
+ - scipy
13
+ - torchvision
14
+ - jupyterlab
15
+ - ipywidgets
16
+ - scikit-image
17
+ - faiss-gpu
18
+ - tensorboard
19
+ - pip:
20
+ - git+https://github.com/openai/CLIP.git
21
+ - pandas
22
+ - ipdb
23
+ - wandb
24
+ - timm==0.6.12
25
+ - matplotlib
26
+ - einops
27
+ - vaex
28
+ - seaborn
29
+ - scikit-learn
CSD/github_teaser.jpg ADDED
CSD/laion-styles-subset-tags.txt ADDED
@@ -0,0 +1,3480 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ a j casson
2
+ aaron bohrod
3
+ aaron douglas
4
+ aaron jasinski
5
+ aaron miller
6
+ aaron nagel
7
+ abbott handerson thayer
8
+ abdur rahman chughtai
9
+ abraham bloemaert
10
+ abraham de vries
11
+ abraham hondius
12
+ abraham mignon
13
+ abraham storck
14
+ abraham van den tempel
15
+ abraham willaerts
16
+ abram arkhipov
17
+ adam bruce thomson
18
+ adam elsheimer
19
+ adam paquette
20
+ adam rex
21
+ adolf dietrich
22
+ adolf schrödter
23
+ adolf ulric wertmüller
24
+ adolph gottlieb
25
+ adolph menzel
26
+ adriaen brouwer
27
+ adriaen coorte
28
+ adriaen hanneman
29
+ adriaen isenbrant
30
+ adriaen van de velde
31
+ adriaen van de venne
32
+ adriaen van der werff
33
+ adriaen van ostade
34
+ adrian ghenie
35
+ adrian zingg
36
+ aelbert cuyp
37
+ aert de gelder
38
+ aert van der neer
39
+ afewerk tekle
40
+ affandi
41
+ agnes martin
42
+ agnolo bronzino
43
+ agnolo gaddi
44
+ agostino carracci
45
+ ai weiwei
46
+ ai xuan
47
+ aimé barraud
48
+ akihiko yoshida
49
+ akira toriyama
50
+ al feldstein
51
+ al williamson
52
+ alan bean
53
+ alan davis
54
+ alan lee
55
+ alasdair gray
56
+ albert anker
57
+ albert aublet
58
+ albert bierstadt
59
+ albert dorne
60
+ albert edelfelt
61
+ albert gleizes
62
+ albert guillaume
63
+ albert joseph moore
64
+ albert marquet
65
+ albert namatjira
66
+ alberto giacometti
67
+ alberto morrocco
68
+ alberto seveso
69
+ alberto vargas
70
+ albrecht altdorfer
71
+ albrecht dürer
72
+ alejandro burdisio
73
+ aleksander gierymski
74
+ aleksander kobzdej
75
+ aleksandr gerasimov
76
+ aleksi briclot
77
+ alena aenami
78
+ alessandro allori
79
+ alesso baldovinetti
80
+ alex grey
81
+ alex horley
82
+ alex katz
83
+ alex ross
84
+ alex toth
85
+ alexander archipenko
86
+ alexander brook
87
+ alexander calder
88
+ alexander carse
89
+ alexander deyneka
90
+ alexander ivanov
91
+ alexander jansson
92
+ alexander johnston
93
+ alexander kanoldt
94
+ alexander kucharsky
95
+ alexander litovchenko
96
+ alexander mann
97
+ alexander mcqueen
98
+ alexander nasmyth
99
+ alexander robertson
100
+ alexander rodchenko
101
+ alexander roslin
102
+ alexander scott
103
+ alexander sharpe ross
104
+ alexander stirling calder
105
+ alexandre benois
106
+ alexandre cabanel
107
+ alexandre falguière
108
+ alexei kondratyevich savrasov
109
+ alexej von jawlensky
110
+ alexey venetsianov
111
+ alexis grimou
112
+ alexis simon belle
113
+ alfons walde
114
+ alfonse mucha
115
+ alfred east
116
+ alfred edward chalon
117
+ alfred eisenstaedt
118
+ alfred freddy krupa
119
+ alfred janes
120
+ alfred jensen
121
+ alfred kubin
122
+ alfred leslie
123
+ alfred leyman
124
+ alfred richard gurrey
125
+ alfred sisley
126
+ alfred thompson bricher
127
+ algernon talmage
128
+ alice bailly
129
+ alice mason
130
+ alice neel
131
+ alice prin
132
+ alison watt
133
+ allaert van everdingen
134
+ allan brooks
135
+ allan linder
136
+ allan ramsay
137
+ allen butler talcott
138
+ allen jones
139
+ allen tupper true
140
+ alma thomas
141
+ almada negreiros
142
+ almeida júnior
143
+ aloysius okelly
144
+ alphonse legros
145
+ alphonse mucha
146
+ alvan fisher
147
+ amadeo de souza cardoso
148
+ amalia lindegren
149
+ amanda sage
150
+ amano
151
+ ambrose mccarthy patterson
152
+ ambrosius benson
153
+ ambrosius bosschaert
154
+ ambrosius holbein
155
+ amedeo modigliani
156
+ americo makk
157
+ amir zand
158
+ ammi phillips
159
+ amos sewell
160
+ amy sol
161
+ amy weber
162
+ an gyeon
163
+ anato finnstark
164
+ anders zorn
165
+ andré charles biéler
166
+ andre derain
167
+ andré derain
168
+ andré françois
169
+ andré kertész
170
+ andré lhote
171
+ andré masson
172
+ andrea del sarto
173
+ andrea del verrocchio
174
+ andrea kowch
175
+ andrea mantegna
176
+ andrea orcagna
177
+ andrea pozzo
178
+ andreas achenbach
179
+ andreas gursky
180
+ andreas rocha
181
+ andrei riabovitchev
182
+ andrei rublev
183
+ andrei ryabushkin
184
+ andrew bell
185
+ andrew ferez
186
+ andrew geddes
187
+ andrew henderson
188
+ andrew law
189
+ andrew loomis
190
+ andrew robertson
191
+ andrew robinson
192
+ andrew stevovich
193
+ andrew wyeth
194
+ android jones
195
+ andrzej wróblewski
196
+ andy goldsworthy
197
+ andy warhol
198
+ ángel botello
199
+ angelica kauffman
200
+ aniello falcone
201
+ anish kapoor
202
+ anita kunz
203
+ anka zhuravleva
204
+ anna ancher
205
+ anna boch
206
+ anna dittmann
207
+ anna mary robertson moses
208
+ anne dunn
209
+ anne geddes
210
+ anne redpath
211
+ anne ryan
212
+ anne said
213
+ anne savage
214
+ anne stokes
215
+ anni albers
216
+ annibale carracci
217
+ annie leibovitz
218
+ annie rose laing
219
+ ansel adams
220
+ anselm kiefer
221
+ antanas sutkus
222
+ anthony devas
223
+ anthony palumbo
224
+ anthony van dyck
225
+ antoine blanchard
226
+ antoine ignace melling
227
+ antoine le nain
228
+ antoine wiertz
229
+ anton ažbe
230
+ anton fadeev
231
+ anton graff
232
+ anton mauve
233
+ anton otto fischer
234
+ anton pieck
235
+ anton räderscheidt
236
+ antonello da messina
237
+ antoni brodowski
238
+ antonin artaud
239
+ antonín chittussi
240
+ antonín slavíček
241
+ antonio canova
242
+ antonio cavallucci
243
+ antonio ciseri
244
+ antonio de la gandara
245
+ antonio donghi
246
+ antonio mancini
247
+ antônio parreiras
248
+ antonio rotta
249
+ apelles
250
+ apollinary vasnetsov
251
+ apollonia saintclair
252
+ archibald motley
253
+ archibald robertson
254
+ archibald skirving
255
+ archibald standish hartrick
256
+ arcimboldo
257
+ arie smit
258
+ aristide maillol
259
+ arkhip kuindzhi
260
+ armand guillaumin
261
+ armin hansen
262
+ arnold blanch
263
+ arnold böcklin
264
+ arnold mesches
265
+ arnold newman
266
+ arshile gorky
267
+ art fitzpatrick
268
+ art frahm
269
+ art green
270
+ art spiegelman
271
+ artemisia gentileschi
272
+ artgerm
273
+ arthur adams
274
+ arthur b carles
275
+ arthur boyd
276
+ arthur burdett frost
277
+ arthur dove
278
+ arthur hughes
279
+ arthur lismer
280
+ arthur melville
281
+ arthur pan
282
+ arthur quartley
283
+ arthur rackham
284
+ arthur sarkissian
285
+ arthur streeton
286
+ artur grottger
287
+ arvid nyholm
288
+ asaf hanuka
289
+ asai chū
290
+ asher brown durand
291
+ ashley wood
292
+ atey ghailan
293
+ attila meszlenyi
294
+ aubrey beardsley
295
+ audrey kawasaki
296
+ august friedrich schenck
297
+ august macke
298
+ august sander
299
+ auguste herbin
300
+ augustus earle
301
+ augustus john
302
+ augustus vincent tack
303
+ auseklis ozols
304
+ austin briggs
305
+ austin english
306
+ austin osman spare
307
+ ayo
308
+ ayami kojima
309
+ balthasar van der ast
310
+ balthus
311
+ banksy
312
+ barbara longhi
313
+ barclay shaw
314
+ barent fabritius
315
+ barkley hendricks
316
+ barnett newman
317
+ barron storey
318
+ bartholomeus breenbergh
319
+ bartholomeus strobel
320
+ bartholomeus van bassen
321
+ bartholomeus van der helst
322
+ bartolomé esteban murillo
323
+ bartolomeo vivarini
324
+ bascove
325
+ basil blackshaw
326
+ basuki abdullah
327
+ bayard wu
328
+ beatrice ethel lithiby
329
+ beatrix potter
330
+ beauford delaney
331
+ beeple
332
+ beksinski
333
+ ben enwonwu
334
+ ben nicholson
335
+ ben shahn
336
+ ben stahl
337
+ ben templesmith
338
+ ben thompson
339
+ benito quinquela martín
340
+ benjamin block
341
+ benjamin franklin
342
+ benjamin gerritsz cuyp
343
+ benjamin west
344
+ benjamin williams leader
345
+ benoit b mandelbrot
346
+ bernard buffet
347
+ bernard meninsky
348
+ bernard van orley
349
+ bernardo bellotto
350
+ bernardo cavallino
351
+ bernardo daddi
352
+ bernardo strozzi
353
+ bernie wrightson
354
+ bert hardy
355
+ 3d render
356
+ black white photo
357
+ bert stern
358
+ cartoon
359
+ berthe morisot
360
+ character portrait
361
+ charcoal drawing
362
+ bronze sculpture
363
+ bertalan székely
364
+ colorized photo
365
+ cave painting
366
+ color pencil sketch
367
+ cross stitch
368
+ cubist painting
369
+ detailed drawing
370
+ bhupen khakhar
371
+ detailed painting
372
+ diagram
373
+ digital painting
374
+ digital rendering
375
+ drawing
376
+ fine art painting
377
+ bill ward
378
+ gouache
379
+ billy childish
380
+ hyperrealistic painting
381
+ jigsaw puzzle
382
+ bob byerley
383
+ bob eggleton
384
+ bob ross
385
+ flemish baroque
386
+ matte painting
387
+ hologram
388
+ macro photograph
389
+ manga drawing
390
+ mosaic
391
+ low poly render
392
+ pastel
393
+ pencil sketch
394
+ boris kustodiev
395
+ microscopic photo
396
+ bourgeois
397
+ photorealistic painting
398
+ pointillism painting
399
+ photocopy
400
+ brad kunkle
401
+ pop art painting
402
+ brassaï
403
+ polaroid photo
404
+ renaissance painting
405
+ screenprint
406
+ screenshot
407
+ silk screen
408
+ sketch
409
+ statue
410
+ still life
411
+ stipple
412
+ brett whiteley
413
+ brian froud
414
+ surrealist painting
415
+ storybook illustration
416
+ tattoo
417
+ tilt shift photo
418
+ watercolor painting
419
+ surrealist sculpture
420
+ woodcut
421
+ abstract drawing
422
+ brom
423
+ abstract painting
424
+ acrylic painting
425
+ brothers hildebrandt
426
+ brooke shaden
427
+ album cover
428
+ bruce davidson
429
+ bruce gilden
430
+ airbrush painting
431
+ bruce pennington
432
+ etching
433
+ bruno liljefors
434
+ impressionist painting
435
+ ink drawing
436
+ oil canvas painting
437
+ buckminster fuller
438
+ art deco painting
439
+ chalk art
440
+ computer graphics
441
+ concept art
442
+ cyberpunk art
443
+ cagnaccio di san pietro
444
+ egyptian art
445
+ graffiti art
446
+ camille corot
447
+ lineart
448
+ camille pissarro
449
+ poster art
450
+ vector art
451
+ camille bombois
452
+ canaletto
453
+ camilo egas
454
+ camilo mori
455
+ candido portinari
456
+ cao zhibai
457
+ caravaggio
458
+ carel fabritius
459
+ carel weight
460
+ carel willink
461
+ carl barks
462
+ carl eytel
463
+ carl frederik von breda
464
+ carl gustaf pilo
465
+ carl heinrich bloch
466
+ carl hoppe
467
+ carl larsson
468
+ carl rahl
469
+ carl spitzweg
470
+ carl walter liner
471
+ carla wyzgala
472
+ carlo carrà
473
+ carlo crivelli
474
+ carlo galli bibiena
475
+ carlo mense
476
+ carlos schwabe
477
+ carne griffiths
478
+ carol bove
479
+ carol sutton
480
+ caroline lucy scott
481
+ caroline mytinger
482
+ carrie mae weems
483
+ casey baugh
484
+ caspar david friedrich
485
+ caspar netscher
486
+ caspar van wittel
487
+ caspar wolf
488
+ cassandra austen
489
+ cassius marcellus coolidge
490
+ catrin welzstein
491
+ cecil beaton
492
+ cecilia beaux
493
+ cecily brown
494
+ cedric peyravernay
495
+ cerith wyn evans
496
+ cézanne
497
+ chagall
498
+ chaim soutine
499
+ chaïm soutine
500
+ charles alston
501
+ charles angrand
502
+ charles bird king
503
+ charles blackman
504
+ charles codman
505
+ charles conder
506
+ charles cundall
507
+ charles dana gibson
508
+ charles demuth
509
+ charles e burchfield
510
+ charles furneaux
511
+ charles ginner
512
+ charles gleyre
513
+ charles h woodbury
514
+ charles harold davis
515
+ charles haslewood shannon
516
+ charles hopkinson
517
+ charles joshua chaplin
518
+ charles le brun
519
+ charles mahoney
520
+ charles marion russell
521
+ charles martin
522
+ charles mcauley
523
+ charles ragland bunnell
524
+ charles rennie mackintosh
525
+ charles ricketts
526
+ charles roka
527
+ charles schulz
528
+ charles thomson
529
+ charles vess
530
+ charles w bartlett
531
+ charles williams
532
+ charles willson peale
533
+ charlie bowater
534
+ charlotte harding
535
+ charlotte nasmyth
536
+ chase stone
537
+ chen chi
538
+ chen chun
539
+ chen daofu
540
+ chen hong
541
+ chen hongshou
542
+ chen lin
543
+ chen lu
544
+ chen yifei
545
+ cheng shifa
546
+ cheng zhengkui
547
+ chesley bonestell
548
+ chiharu shiota
549
+ childe hassam
550
+ chip zdarsky
551
+ chippy
552
+ choi buk
553
+ chris cold
554
+ chris foss
555
+ chris friel
556
+ chris labrooy
557
+ chris moore
558
+ chris rahn
559
+ chris rallis
560
+ chris ware
561
+ christen dalsgaard
562
+ christen købke
563
+ christian jane fergusson
564
+ christian krohg
565
+ christian rohlfs
566
+ christo
567
+ christoffer wilhelm eckersberg
568
+ christoph amberger
569
+ christoph ludwig agricola
570
+ christophe vacher
571
+ christopher balaskas
572
+ christopher moeller
573
+ christopher perkins
574
+ christopher williams
575
+ christopher wood
576
+ christopher wren
577
+ chuck close
578
+ cicely mary barker
579
+ cimabue
580
+ cindy sherman
581
+ cindy wright
582
+ claire dalby
583
+ claire hummel
584
+ clara miller burd
585
+ clara peeters
586
+ clara weaver parrish
587
+ clarence holbrook carter
588
+ clarice beckett
589
+ clark voorhees
590
+ claude cahun
591
+ claude lorrain
592
+ claude monet
593
+ cleon peterson
594
+ cleve gray
595
+ cliff childs
596
+ clifford ross
597
+ clint cearley
598
+ clyde caldwell
599
+ clyfford still
600
+ coby whitmore
601
+ coles phillips
602
+ colijn de coter
603
+ colin campbell cooper
604
+ colin gill
605
+ colin hayes
606
+ colin mccahon
607
+ colin middleton
608
+ colin moss
609
+ conrad roset
610
+ conroy maddox
611
+ constant
612
+ constant permeke
613
+ constantin hansen
614
+ corneille
615
+ cornelia parker
616
+ cornelis anthonisz
617
+ cornelis bisschop
618
+ cornelis de heem
619
+ cornelis de man
620
+ cornelis dusart
621
+ cornelis saftleven
622
+ cornelis van haarlem
623
+ correggio
624
+ cosmo alexander
625
+ craig davison
626
+ craig mullins
627
+ craig thompson
628
+ craola
629
+ cristofano allori
630
+ csaba markus
631
+ cuno amiet
632
+ cy twombly
633
+ cynthia sheppard
634
+ cyril rolando
635
+ d howard hitchcock
636
+ daarken
637
+ dai jin
638
+ dai xi
639
+ dali
640
+ dalí
641
+ damien hirst
642
+ dan frazier
643
+ dan hillier
644
+ dan luvisi
645
+ dan mumford
646
+ dan scott
647
+ dan smith
648
+ daniel f gerhartz
649
+ daniel garber
650
+ daniel lieske
651
+ daniel ljunggren
652
+ daniel maclise
653
+ daniel merriam
654
+ daniël mijtens
655
+ daniel taylor
656
+ dante gabriel rossetti
657
+ daphne fedarb
658
+ darek zabrocki
659
+ daren bader
660
+ dariusz zawadzki
661
+ dave arredondo
662
+ dave dorman
663
+ dave gibbons
664
+ dave kendall
665
+ dave mckean
666
+ david alfaro siqueiros
667
+ david allan
668
+ david annand
669
+ david bailly
670
+ david bomberg
671
+ david boyd
672
+ david brewster
673
+ david budd
674
+ david burliuk
675
+ david chipperfield
676
+ david diao
677
+ david donaldson
678
+ david eugene henry
679
+ david gilmour blythe
680
+ david hockney
681
+ david inshaw
682
+ david lachapelle
683
+ david ligare
684
+ david martin
685
+ david octavius hill
686
+ david palumbo
687
+ david park
688
+ david roberts
689
+ david simpson
690
+ david small
691
+ david teniers iii
692
+ david wilkie
693
+ david wojnarowicz
694
+ david young cameron
695
+ dean cornwell
696
+ dean ellis
697
+ dean roger
698
+ delaunay
699
+ delphin enjolras
700
+ dennis flanders
701
+ dennis miller bunker
702
+ derek gores
703
+ derek hill
704
+ derek jarman
705
+ derf
706
+ desmond morris
707
+ diane arbus
708
+ diane dillon
709
+ diego giacometti
710
+ diego gisbert llorens
711
+ diego rivera
712
+ diego velázquez
713
+ dieric bouts
714
+ ding guanpeng
715
+ ding yunpeng
716
+ dino valls
717
+ dionisio baixeras verdaguer
718
+ dirck de bray
719
+ dirck hals
720
+ dirck van baburen
721
+ dirck van delen
722
+ disney
723
+ ditlev blunck
724
+ dmitry levitzky
725
+ dod procter
726
+ domenichino
727
+ domenico di pace beccafumi
728
+ domenico ghirlandaio
729
+ domenico induno
730
+ domenico zampieri
731
+ don eddy
732
+ donald judd
733
+ donald roller wilson
734
+ donato giancola
735
+ dong kingman
736
+ dong qichang
737
+ dong yuan
738
+ dora carrington
739
+ dora maar
740
+ dorothea lange
741
+ dorothea tanning
742
+ dorothy burroughes
743
+ dorothy hood
744
+ dorothy johnstone
745
+ dorothy king
746
+ dosso dossi
747
+ douglas shuler
748
+ dr atl
749
+ dr seuss
750
+ drew struzan
751
+ drew tucker
752
+ du jin
753
+ duccio
754
+ dugald sutherland maccoll
755
+ abstract art
756
+ abstract expressionism
757
+ dürer
758
+ academic art
759
+ action painting
760
+ aestheticism
761
+ afrofuturism
762
+ duncan grant
763
+ dwight william tryon
764
+ american impressionism
765
+ american realism
766
+ american romanticism
767
+ american scene painting
768
+ earle bergey
769
+ e charlton fortune
770
+ arabesque
771
+ ed benedict
772
+ ed binkley
773
+ art brut
774
+ art deco
775
+ ed roth
776
+ art nouveau
777
+ art photography
778
+ eddie mendoza
779
+ edgar degas
780
+ arts crafts movement
781
+ ashcan school
782
+ assemblage
783
+ eddie campbell
784
+ edith lawrence
785
+ barbizon school
786
+ baroque
787
+ bauhaus
788
+ edmund blampied
789
+ edmund charles tarbell
790
+ edmund dulac
791
+ brutalism
792
+ classical realism
793
+ edmund leighton
794
+ cobra
795
+ color field
796
+ computer art
797
+ conceptual art
798
+ édouard manet
799
+ constructivism
800
+ concrete art
801
+ crayon art
802
+ eduardo kingman
803
+ cubism
804
+ eduard von grützner
805
+ edvard munch
806
+ dada
807
+ edward armitage
808
+ edward atkinson hornel
809
+ de stijl
810
+ edward arthur walton
811
+ digital art
812
+ deconstructivism
813
+ environmental art
814
+ edward clark
815
+ expressionism
816
+ fantastic realism
817
+ fantasy art
818
+ fauvism
819
+ edward henry potthast
820
+ edward gorey
821
+ edward hopper
822
+ figurative art
823
+ fine art
824
+ edward lamson henry
825
+ folk art
826
+ edward lear
827
+ edward mitchell bannister
828
+ futurism
829
+ furry art
830
+ edward robert hughes
831
+ figurativism
832
+ edward simmons
833
+ graffiti
834
+ gothic art
835
+ edward weston
836
+ happening
837
+ harlem renaissance
838
+ edwin deakin
839
+ holography
840
+ edwin austin abbey
841
+ edward willis redfield
842
+ hyperrealism
843
+ hudson river school
844
+ edwin georgi
845
+ edwin landseer
846
+ impressionism
847
+ eero järnefelt
848
+ egon schiele
849
+ egbert van der poel
850
+ eiq
851
+ interactive art
852
+ land art
853
+ kinetic art
854
+ les nabis
855
+ egbert van heemskerck
856
+ light space
857
+ lowbrow
858
+ ejnar nielsen
859
+ el greco
860
+ magic realism
861
+ magical realism
862
+ mail art
863
+ mannerism
864
+ el lissitzky
865
+ maximalism
866
+ metaphysical painting
867
+ lyrical abstraction
868
+ minimalism
869
+ elaine de kooning
870
+ modernism
871
+ eleanor fortescuebrickdale
872
+ naive art
873
+ naturalism
874
+ mingei
875
+ eleanor vere boyle
876
+ eliot hodgkin
877
+ élisabeth vigée le brun
878
+ eliseu visconti
879
+ neoclassicism
880
+ neogeo
881
+ elizabeth forbes
882
+ elizabeth jane lloyd
883
+ net art
884
+ new objectivity
885
+ elizabeth murray
886
+ elizabeth shippen green
887
+ new sculpture
888
+ elke vogelsang
889
+ op art
890
+ optical illusion
891
+ elliott erwitt
892
+ orphism
893
+ elmer bischoff
894
+ photorealism
895
+ pixel art
896
+ ellsworth kelly
897
+ plein air
898
+ pointillism
899
+ pop art
900
+ pop surrealism
901
+ elsa beskow
902
+ postimpressionism
903
+ elmyr de hory
904
+ precisionism
905
+ emanuel leutze
906
+ emanuel de witte
907
+ process art
908
+ psychedelic art
909
+ emil bisttram
910
+ emil carlsen
911
+ primitivism
912
+ emil fuchs
913
+ emil nolde
914
+ realism
915
+ regionalism
916
+ émile bernard
917
+ renaissance
918
+ retrofuturism
919
+ rococo
920
+ romanesque
921
+ emily carr
922
+ romanticism
923
+ emiliano ponzi
924
+ shin hanga
925
+ emiliano di cavalcanti
926
+ socialist realism
927
+ emily shanks
928
+ space art
929
+ street art
930
+ emory douglas
931
+ emma lampert cooper
932
+ superflat
933
+ suprematism
934
+ surrealism
935
+ symbolism
936
+ enrique simonet
937
+ enrique grau
938
+ enki bilal
939
+ tachisme
940
+ temporary art
941
+ tonalism
942
+ eric auld
943
+ eric deschamps
944
+ ukiyoe
945
+ eric peterson
946
+ eric taylor
947
+ eric zener
948
+ vanitas
949
+ erich heckel
950
+ video art
951
+ erin hanson
952
+ visual art
953
+ ernest biéler
954
+ underground comix
955
+ ernest buckmaster
956
+ ernest hébert
957
+ ernest lawson
958
+ ernest morgan
959
+ ernest procter
960
+ ernest william christmas
961
+ ernie barnes
962
+ ernst
963
+ ernst fuchs
964
+ ernst haeckel
965
+ ernst ludwig kirchner
966
+ ernst thoms
967
+ ernst wilhelm nay
968
+ erwin bowien
969
+ esaias van de velde
970
+ esao
971
+ esao andrews
972
+ esteban vicente
973
+ etienne delessert
974
+ ettore tito
975
+ euan uglow
976
+ eugène boudin
977
+ eugène burnand
978
+ eugène carrière
979
+ eugene delacroix
980
+ eugène delacroix
981
+ eugène grasset
982
+ eugène isabey
983
+ childs drawing
984
+ eugene von guerard
985
+ eugeniusz zak
986
+ eva gonzalès
987
+ évariste vital luminais
988
+ evaristo baschenis
989
+ evelyn abelson
990
+ evelyn de morgan
991
+ everett raymond kinstler
992
+ everett shinn
993
+ computer rendering
994
+ evert collier
995
+ evgeny lushpin
996
+ eyvind earle
997
+ f scott hess
998
+ fabien charuau
999
+ fairfield porter
1000
+ fan kuan
1001
+ fan qi
1002
+ fang congyi
1003
+ farel dalrymple
1004
+ fede galizia
1005
+ federico barocci
1006
+ federico uribe
1007
+ federico zandomeneghi
1008
+ federico zuccari
1009
+ fedot sychkov
1010
+ detailed matte painting
1011
+ felice casorati
1012
+ felicity charlton
1013
+ fei danxu
1014
+ félix vallotton
1015
+ félix ziem
1016
+ feng zhu
1017
+ fenghua zhong
1018
+ ferdinand bol
1019
+ ferdinand hodler
1020
+ ferdinand knab
1021
+ ferdynand ruszczyc
1022
+ fern coppedge
1023
+ fernand léger
1024
+ fernand pelez
1025
+ fernand toussaint
1026
+ fernando amorsolo
1027
+ fernando botero
1028
+ filip hodas
1029
+ filippino lippi
1030
+ fiona stephenson
1031
+ fitz henry lane
1032
+ fitz hugh lane
1033
+ fletcher martin
1034
+ flora macdonald reid
1035
+ floris van dyck
1036
+ floris van schooten
1037
+ ford madox brown
1038
+ fra angelico
1039
+ fra bartolomeo
1040
+ fra filippo lippi
1041
+ frances c fairman
1042
+ frances hodgkins
1043
+ frances macdonald
1044
+ francesco albani
1045
+ francesco bartolozzi
1046
+ francesco bonsignori
1047
+ francesco clemente
1048
+ francesco del cossa
1049
+ francesco filippini
1050
+ francesco guardi
1051
+ francesco hayez
1052
+ francesco raibolini
1053
+ francis bacon
1054
+ francis bourgeois
1055
+ francis cadell
1056
+ francis davis millet
1057
+ francis ernest jackson
1058
+ francis focer brown
1059
+ francis helps
1060
+ francis picabia
1061
+ marble sculpture
1062
+ francisco de holanda
1063
+ francisco de zurbarán
1064
+ francisco goya
1065
+ francisco oller
1066
+ francisco zúñiga
1067
+ franciszek smuglewicz
1068
+ françois barraud
1069
+ françois bocion
1070
+ françois boucher
1071
+ françois clouet
1072
+ françois joseph heim
1073
+ françois quesnel
1074
+ frank auerbach
1075
+ minimalist painting
1076
+ frank buchser
1077
+ frank dumond
1078
+ frank frazetta
1079
+ frank leonard brooks
1080
+ frank mason
1081
+ frank mckelvey
1082
+ frank miller
1083
+ frank montague moore
1084
+ frank omeara
1085
+ frank schoonover
1086
+ frank stella
1087
+ frank weston benson
1088
+ frank xavier leyendecker
1089
+ franklin booth
1090
+ franklin carmichael
1091
+ frans hals
1092
+ frans koppelaar
1093
+ frans masereel
1094
+ františek kaván
1095
+ františek kupka
1096
+ franz kline
1097
+ franz marc
1098
+ franz sedlacek
1099
+ franz stuck
1100
+ franz vohwinkel
1101
+ franz von lenbach
1102
+ franz xaver winterhalter
1103
+ fred cress
1104
+ fred ludekens
1105
+ fred mitchell
1106
+ fred williams
1107
+ frédéric bazille
1108
+ frederic church
1109
+ frederic edwin church
1110
+ frederic leighton
1111
+ frederic remington
1112
+ frederick carl frieseke
1113
+ frederick edwin church
1114
+ frederick goodall
1115
+ frederick hammersley
1116
+ frederick lord leighton
1117
+ frederick mccubbin
1118
+ frederik de moucheron
1119
+ frederik vermehren
1120
+ frida kahlo
1121
+ friedel dzubas
1122
+ friedensreich hundertwasser
1123
+ friedrich gauermann
1124
+ friedrich von amerling
1125
+ frieke janssens
1126
+ frits thaulow
1127
+ fritz von dardel
1128
+ fritz von uhde
1129
+ fu baoshi
1130
+ fujishima takeji
1131
+ fyodor alekseyev
1132
+ fyodor rokotov
1133
+ fyodor vasilyev
1134
+ gabriel ba
1135
+ gabriel dawe
1136
+ gabriel metsu
1137
+ gabriele münter
1138
+ gaetano previati
1139
+ gai qi
1140
+ galen dara
1141
+ gao cen
1142
+ gao fenghan
1143
+ garry winogrand
1144
+ gaston anglade
1145
+ gaston bussiere
1146
+ gaston bussière
1147
+ gaudi
1148
+ gaugin
1149
+ gavin hamilton
1150
+ gawen hamilton
1151
+ gediminas pranckevicius
1152
+ geertgen tot sint jans
1153
+ gen paul
1154
+ gene davis
1155
+ gentile bellini
1156
+ geof darrow
1157
+ geoffrey dyer
1158
+ georg baselitz
1159
+ georg friedrich kersting
1160
+ georg friedrich schmidt
1161
+ georg muche
1162
+ georg scholz
1163
+ georg schrimpf
1164
+ george abe
1165
+ george ault
1166
+ george bain
1167
+ george barbier
1168
+ george barker
1169
+ george barret sr
1170
+ george bell
1171
+ george bellows
1172
+ george benjamin luks
1173
+ george biddle
1174
+ george caleb bingham
1175
+ george catlin
1176
+ george cruikshank
1177
+ george fiddes watt
1178
+ george frederic watts
1179
+ george frederick harris
1180
+ george gardner symons
1181
+ george grosz
1182
+ george hendrik breitner
1183
+ george henry
1184
+ george hurrell
1185
+ george inness
1186
+ george jamesone
1187
+ george lucas
1188
+ george luks
1189
+ george morrison
1190
+ george paul chalmers
1191
+ george pirie
1192
+ george reid
1193
+ george romney
1194
+ george stubbs
1195
+ george tooker
1196
+ abstract sculpture
1197
+ georges braque
1198
+ georges de la tour
1199
+ georges lacombe
1200
+ georges lemmen
1201
+ georges rouault
1202
+ georges seurat
1203
+ georges stein
1204
+ georgia okeeffe
1205
+ gerald brom
1206
+ gerald kelly
1207
+ gerard david
1208
+ gerard de lairesse
1209
+ gerard houckgeest
1210
+ gerard seghers
1211
+ gerard sekoto
1212
+ anime drawing
1213
+ gerard ter borch
1214
+ gerard soest
1215
+ gerda wegener
1216
+ gerhard richter
1217
+ gerbrand van den eeckhout
1218
+ germaine krull
1219
+ gerrit adriaenszoon berckheyde
1220
+ gerrit dou
1221
+ gertrude abercrombie
1222
+ art deco sculpture
1223
+ gertrude harvey
1224
+ géza dósa
1225
+ géza udvary
1226
+ engraving
1227
+ giacomo balla
1228
+ gian lorenzo bernini
1229
+ giger
1230
+ gil elvgren
1231
+ gilbert stuart
1232
+ gilles beloeil
1233
+ gillis rombouts
1234
+ gino severini
1235
+ giorgio de chirico
1236
+ giorgio morandi
1237
+ giorgione
1238
+ giotto
1239
+ giovanni antonio galli
1240
+ giovanni battista cipriani
1241
+ giovanni battista gaulli
1242
+ giovanni battista piazzetta
1243
+ giovanni battista piranesi
1244
+ giovanni battista tiepolo
1245
+ giovanni bellini
1246
+ giovanni bernardino azzolini
1247
+ giovanni boldini
1248
+ giovanni fattori
1249
+ giovanni francesco barbieri
1250
+ giovanni giacometti
1251
+ giovanni lanfranco
1252
+ ultrafine detailed painting
1253
+ giovanni paolo pannini
1254
+ giuseppe abbati
1255
+ giuseppe antonio petrini
1256
+ giuseppe arcimboldo
1257
+ giuseppe bernardino bison
1258
+ giuseppe camuncoli
1259
+ giuseppe de nittis
1260
+ giuseppe grisoni
1261
+ giuseppe tominz
1262
+ glen angus
1263
+ glen keane
1264
+ glenn fabry
1265
+ glennray tutor
1266
+ gloria stoll karn
1267
+ godfried schalcken
1268
+ gong xian
1269
+ gordon parks
1270
+ goro fujita
1271
+ gottfried helnwein
1272
+ govert dircksz camphuysen
1273
+ govert flinck
1274
+ goyō hashiguchi
1275
+ grace cossington smith
1276
+ grace english
1277
+ graham forsythe
1278
+ graham sutherland
1279
+ grandma moses
1280
+ grant wood
1281
+ grayson perry
1282
+ greg hildebrandt
1283
+ greg rutkowski
1284
+ greg spalenka
1285
+ greg staples
1286
+ gregory crewdson
1287
+ gregory gillespie
1288
+ gregory manchess
1289
+ grete stern
1290
+ grigoriy myasoyedov
1291
+ grzegorz rutkowski
1292
+ gu an
1293
+ gu hongzhong
1294
+ guan daosheng
1295
+ guido borelli da caluso
1296
+ guido reni
1297
+ guillermo del toro
1298
+ guo xi
1299
+ gustaf tenggren
1300
+ gustav dore
1301
+ gustav doré
1302
+ gustav klimt
1303
+ gustave baumann
1304
+ gustave boulanger
1305
+ gustave caillebotte
1306
+ gustave courbet
1307
+ gustave dore
1308
+ gustave doré
1309
+ gustave moreau
1310
+ gustave van de woestijne
1311
+ guy denning
1312
+ guy rose
1313
+ gwen john
1314
+ gwenny griffiths
1315
+ gwilym prichard
1316
+ gyula aggházy
1317
+ gyula batthyány
1318
+ gyula benczúr
1319
+ gyula derkovits
1320
+ h r giger
1321
+ hp lovecraft
1322
+ haddon sundblom
1323
+ hajime sorayama
1324
+ hal foster
1325
+ hamilton sloan
1326
+ hamish macdonald
1327
+ han gan
1328
+ hannabarbera
1329
+ hannah frank
1330
+ hanns katz
1331
+ hans asper
1332
+ hans baldung
1333
+ hans baluschek
1334
+ hans bellmer
1335
+ hans bol
1336
+ hans burgkmair
1337
+ hans erni
1338
+ hans fischer
1339
+ hans gude
1340
+ hans hofmann
1341
+ hans makart
1342
+ hans memling
1343
+ hans mertens
1344
+ hans von aachen
1345
+ hans von bartels
1346
+ harald giersing
1347
+ harold gilman
1348
+ harold harvey
1349
+ harold sandys williamson
1350
+ harold von schmidt
1351
+ harriet backer
1352
+ harrington mann
1353
+ harrison fisher
1354
+ harry clarke
1355
+ harry morley
1356
+ harumi hironaka
1357
+ harvey dunn
1358
+ harvey kurtzman
1359
+ harvey pratt
1360
+ hasegawa tōhaku
1361
+ hasui kawase
1362
+ hayao miyazaki
1363
+ heather hudson
1364
+ hedda sterne
1365
+ heinrich hofmann
1366
+ heinrich kley
1367
+ heinrich lefler
1368
+ heinrich maria davringhausen
1369
+ heinz anger
1370
+ helen edwards
1371
+ helen frankenthaler
1372
+ helen huang
1373
+ helene schjerfbeck
1374
+ helmut newton
1375
+ hendrick avercamp
1376
+ hendrick bloemaert
1377
+ hendrick terbrugghen
1378
+ hendrick van balen
1379
+ hendrick van streeck
1380
+ hendrik goltzius
1381
+ hendrik martenszoon sorgh
1382
+ hendrik van steenwijk i
1383
+ hendrik van steenwijk ii
1384
+ hendrik willem mesdag
1385
+ henri alphonse barnoin
1386
+ henri biva
1387
+ henri cartierbresson
1388
+ henri harpignies
1389
+ henri le sidaner
1390
+ henri matisse
1391
+ henri rousseau
1392
+ henriette wyeth
1393
+ henrik weber
1394
+ henry bright
1395
+ henry carr
1396
+ henry fuseli
1397
+ henry heerup
1398
+ henry justice ford
1399
+ henry lamb
1400
+ henry moore
1401
+ henry ossawa tanner
1402
+ henry otto wix
1403
+ henry raeburn
1404
+ henry raleigh
1405
+ henry scott tuke
1406
+ henry tonks
1407
+ henry van de velde
1408
+ henry wallis
1409
+ henry woods
1410
+ henryk siemiradzki
1411
+ herb ritts
1412
+ herbert bayer
1413
+ herbert james gunn
1414
+ herman saftleven
1415
+ herman van swanevelt
1416
+ hermenegildo anglada camarasa
1417
+ hieronymous bosch
1418
+ hieronymus bosch
1419
+ hikari shimoda
1420
+ hilma af klint
1421
+ hiromu arakawa
1422
+ hiroshi nagai
1423
+ hiroshi yoshida
1424
+ hiroshige
1425
+ hishikawa moronobu
1426
+ hisui sugiura
1427
+ hokusai
1428
+ holger roed
1429
+ honoré daumier
1430
+ horace vernet
1431
+ horatio mcculloch
1432
+ horatio nelson poole
1433
+ hovsep pushman
1434
+ howard butterworth
1435
+ howard chandler christy
1436
+ howard chaykin
1437
+ howard finster
1438
+ howard lyon
1439
+ howard pyle
1440
+ hr giger
1441
+ hu jieqing
1442
+ hua yan
1443
+ huang binhong
1444
+ huang ding
1445
+ huang gongwang
1446
+ huang guangjian
1447
+ huang ji
1448
+ huang shen
1449
+ huang tingjian
1450
+ hubert robert
1451
+ hubert van eyck
1452
+ hubert von herkomer
1453
+ hugh ferriss
1454
+ hugh william williams
1455
+ hugo anton fisher
1456
+ hugo heyrman
1457
+ hugo scheiber
1458
+ hugo simberg
1459
+ hugo van der goes
1460
+ humberto castro
1461
+ hundertwasser
1462
+ hyacinthe rigaud
1463
+ ian mcque
1464
+ ian miller
1465
+ ian spriggs
1466
+ ida rentoul outhwaite
1467
+ ignacio zuloaga
1468
+ ignacy witkiewicz
1469
+ ignat bednarik
1470
+ igor grabar
1471
+ igor kieryluk
1472
+ igor morski
1473
+ igor zenin
1474
+ ikuo hirayama
1475
+ illarion pryanishnikov
1476
+ ilya glazunov
1477
+ ilya kuvshinov
1478
+ ilya ostroukhov
1479
+ ilya repin
1480
+ ilya yefimovich repin
1481
+ ina wong
1482
+ ino
1483
+ ion andreescu
1484
+ irakli nadar
1485
+ irma stern
1486
+ isaac grünewald
1487
+ isaac levitan
1488
+ isaac soyer
1489
+ isabel codrington
1490
+ isabel naftel
1491
+ isamu noguchi
1492
+ isidor kaufman
1493
+ ismail acar
1494
+ ismail gulgee
1495
+ ismail inceoglu
1496
+ israel tsvaygenbaum
1497
+ istván csók
1498
+ istván orosz
1499
+ istván réti
1500
+ itō jakuchū
1501
+ itō shinsui
1502
+ itshak holtz
1503
+ ivan aivazovsky
1504
+ ivan albright
1505
+ ivan bilibin
1506
+ ivan generalić
1507
+ ivan kramskoi
1508
+ ivan mrkvička
1509
+ ivan shishkin
1510
+ ivan trush
1511
+ ivana kobilca
1512
+ ivor davies
1513
+ ivor williams
1514
+ iwasa matabei
1515
+ j alden weir
1516
+ j c leyendecker
1517
+ j frederick smith
1518
+ j l lund
1519
+ j m w turner
1520
+ j ottis adams
1521
+ jc leyendecker
1522
+ jmw turner
1523
+ jacek malczewski
1524
+ jacek yerka
1525
+ jack boul
1526
+ jack butler yeats
1527
+ jack davis
1528
+ jack kirby
1529
+ jack levine
1530
+ jack roth
1531
+ jack smith
1532
+ jackson pollock
1533
+ jacob adriaensz backer
1534
+ jacob burck
1535
+ jacob collins
1536
+ jacob de heusch
1537
+ jacob gerritsz cuyp
1538
+ jacob jordaens
1539
+ jacob kainen
1540
+ jacob koninck
1541
+ jacob lawrence
1542
+ jacob maris
1543
+ jacob more
1544
+ jacob ochtervelt
1545
+ jacob philipp hackert
1546
+ jacob pynas
1547
+ jacob savery
1548
+ jacob toorenvliet
1549
+ jacob van campen
1550
+ jacob van der ulft
1551
+ jacob van ruisdael
1552
+ jacopo amigoni
1553
+ jacopo bassano
1554
+ jacopo bellini
1555
+ jacopo de barbari
1556
+ jacopo pontormo
1557
+ jacques blanchard
1558
+ jacques callot
1559
+ jacques daret
1560
+ jacques sablet
1561
+ jacques villon
1562
+ jacqueslouis david
1563
+ jaime colson
1564
+ jaime jones
1565
+ jakob gauermann
1566
+ jakub rozalski
1567
+ jakub różalski
1568
+ jakub schikaneder
1569
+ james abbott mcneill whistler
1570
+ james barry
1571
+ james bateman
1572
+ james baynes
1573
+ james bolivar manson
1574
+ james c christensen
1575
+ james cadenhead
1576
+ james campbell noble
1577
+ james christensen
1578
+ james cowie
1579
+ james cromar watt
1580
+ james dickson innes
1581
+ james ensor
1582
+ james giles
1583
+ james gilleard
1584
+ james gillick
1585
+ james gillray
1586
+ james gurney
1587
+ james guthrie
1588
+ james humbert craig
1589
+ james jean
1590
+ james mcbey
1591
+ james mcintosh patrick
1592
+ james mcneill whistler
1593
+ james montgomery flagg
1594
+ james morris
1595
+ james morrison
1596
+ james paick
1597
+ james paterson
1598
+ james peale
1599
+ james pittendrigh macgillivray
1600
+ james rosenquist
1601
+ james ryman
1602
+ james thomas watts
1603
+ james tissot
1604
+ james warhola
1605
+ james wood
1606
+ jamie hewlett
1607
+ jamie wyeth
1608
+ jan antonisz van ravesteyn
1609
+ jan asselijn
1610
+ jan baptist weenix
1611
+ jan brett
1612
+ jan cornelisz vermeyen
1613
+ jan cox
1614
+ jan davidsz de heem
1615
+ jan de baen
1616
+ jan de bray
1617
+ jan gossaert
1618
+ jan griffier
1619
+ jan hackaert
1620
+ jan kip
1621
+ jan lievens
1622
+ jan matejko
1623
+ jan miel
1624
+ jan miense molenaer
1625
+ jan steen
1626
+ jan toorop
1627
+ jan van bijlert
1628
+ jan van de cappelle
1629
+ jan van der heyden
1630
+ jan van eyck
1631
+ jan van goyen
1632
+ jan van huysum
1633
+ jan van mieris
1634
+ jan verkolje
1635
+ jan victors
1636
+ jan wijnants
1637
+ jan wyck
1638
+ jan zrzavý
1639
+ jane carpanini
1640
+ jane frank
1641
+ jane freeman
1642
+ jane freilicher
1643
+ jane hawkins
1644
+ jane kelly
1645
+ jane nasmyth
1646
+ jane small
1647
+ janet archer
1648
+ janet dawson
1649
+ janet fish
1650
+ jános vaszary
1651
+ january suchodolski
1652
+ jarosław jaśnikowski
1653
+ jason benjamin
1654
+ jason chan
1655
+ jason edmiston
1656
+ jason felix
1657
+ jasper francis cropsey
1658
+ jasper johns
1659
+ jean antoine watteau
1660
+ jean arp
1661
+ jean auguste dominique ingres
1662
+ jean baptiste debret
1663
+ jean béraud
1664
+ jean clark
1665
+ jean colombe
1666
+ jean delville
1667
+ jean dubuffet
1668
+ jean dufy
1669
+ jean fouquet
1670
+ jean giraud
1671
+ jean hélion
1672
+ jean hey
1673
+ jean jouvenet
1674
+ jean metzinger
1675
+ jean micheal basquiat
1676
+ jean moebius giraud
1677
+ jean petitot
1678
+ jeanaugustedominique ingres
1679
+ jeanlouisernest meissonier
1680
+ jeanmarc nattier
1681
+ jeanmichel basquiat
1682
+ jeanna bauck
1683
+ jeanne hébuterne
1684
+ jeff easley
1685
+ jeff koons
1686
+ jeff miracola
1687
+ jeffrey catherine jones
1688
+ jeffrey smith
1689
+ jennifer janesko
1690
+ jenny eakin delony
1691
+ jenny saville
1692
+ jenő barcsay
1693
+ jens ferdinand willumsen
1694
+ jens juel
1695
+ jeong seon
1696
+ jeremiah ketner
1697
+ jeremy chong
1698
+ jeremy geddes
1699
+ jerry pinkney
1700
+ jerry schatzberg
1701
+ jerry weiss
1702
+ jerzy kossak
1703
+ jesper ejsing
1704
+ jesper myrfors
1705
+ jesse richards
1706
+ jessica rossier
1707
+ jessie willcox smith
1708
+ jiao bingzhen
1709
+ jim burns
1710
+ jim davis
1711
+ jim dine
1712
+ jim lee
1713
+ jim murray
1714
+ jim nelson
1715
+ jin nong
1716
+ jiro yoshihara
1717
+ joachim patinir
1718
+ joan brown
1719
+ joan miro
1720
+ joan miró
1721
+ joan snyder
1722
+ joanna carrington
1723
+ joaquín clausell
1724
+ joaquín sorolla
1725
+ jodorowsky
1726
+ joe bowler
1727
+ joe de mers
1728
+ joe fenton
1729
+ joe jusko
1730
+ joe machine
1731
+ joe mangrum
1732
+ joe shuster
1733
+ johan christian dahl
1734
+ johan jongkind
1735
+ johann berthelsen
1736
+ johann bodin
1737
+ johann christian brand
1738
+ johann friedrich overbeck
1739
+ johann gottfried steffan
1740
+ johann heinrich bleuler
1741
+ johann heinrich meyer
1742
+ johann jakob biedermann
1743
+ johann ludwig bleuler
1744
+ johann zoffany
1745
+ johannes cornelisz verspronck
1746
+ johannes helgeson
1747
+ johannes itten
1748
+ johannes lingelbach
1749
+ johannes mytens
1750
+ johannes vermeer
1751
+ johannes voss
1752
+ johfra bosschart
1753
+ john alexander
1754
+ john anster fitzgerald
1755
+ john armstrong
1756
+ john atherton
1757
+ john atkinson grimshaw
1758
+ john avon
1759
+ john bauer
1760
+ john bellany
1761
+ john berkey
1762
+ john blair
1763
+ john blanche
1764
+ john brack
1765
+ john brown
1766
+ john brown abercromby
1767
+ john button
1768
+ john byrne
1769
+ john cale
1770
+ john carpenter
1771
+ john clayton
1772
+ john clayton adams
1773
+ john collier
1774
+ john constable
1775
+ john duncan fergusson
1776
+ john e berninger
1777
+ john elwood bundy
1778
+ john everett millais
1779
+ john eyre
1780
+ john f francis
1781
+ john f peto
1782
+ john fabian carlson
1783
+ john frederick herring jr
1784
+ john frederick herring sr
1785
+ john frederick kensett
1786
+ john french sloan
1787
+ john fulton folinsbee
1788
+ john george sowerby
1789
+ john gibson
1790
+ john harris
1791
+ john henderson
1792
+ john henry lorimer
1793
+ john henry twachtman
1794
+ john howe
1795
+ john hutton
1796
+ john j park
1797
+ john james audubon
1798
+ john kay
1799
+ john keane
1800
+ john la gatta
1801
+ john lavery
1802
+ john linnell
1803
+ john lowrie morrison
1804
+ john luke
1805
+ john macdonald aiken
1806
+ john marin
1807
+ john martin
1808
+ john maxwell
1809
+ john mclaughlin
1810
+ john michael wright
1811
+ john murdoch
1812
+ john noble barlow
1813
+ john opie
1814
+ john parker
1815
+ john pettie
1816
+ john philip falter
1817
+ john platt
1818
+ john plumb
1819
+ john quinton pringle
1820
+ john robertson reid
1821
+ john romita jr
1822
+ john salminen
1823
+ john singer sargent
1824
+ john singleton copley
1825
+ john skinner prout
1826
+ john sloan
1827
+ john souch
1828
+ john steell
1829
+ john steuart curry
1830
+ john stuart ingle
1831
+ john trumbull
1832
+ john watson gordon
1833
+ john william godward
1834
+ john william waterhouse
1835
+ john wilson
1836
+ john wollaston
1837
+ john wonnacott
1838
+ jon foster
1839
+ jon whitcomb
1840
+ jonas de ro
1841
+ jonathan solter
1842
+ joos de momper
1843
+ jordan grimmer
1844
+ jorge jacinto
1845
+ jørgen roed
1846
+ josan gonzalez
1847
+ josé clemente orozco
1848
+ josé malhoa
1849
+ josef abel
1850
+ josef albers
1851
+ josef mánes
1852
+ josep rovira soler
1853
+ joseph badger
1854
+ joseph beuys
1855
+ joseph bowler
1856
+ joseph christian leyendecker
1857
+ joseph cornell
1858
+ joseph decamp
1859
+ joseph delaney
1860
+ joseph ducreux
1861
+ joseph dwight strong
1862
+ joseph henderson
1863
+ joseph kleitsch
1864
+ joseph noel paton
1865
+ joseph raphael
1866
+ joseph severn
1867
+ joseph stella
1868
+ joseph von führich
1869
+ joseph werner
1870
+ joseph wright of derby
1871
+ analytical art
1872
+ antipodeans
1873
+ josephine wall
1874
+ josetsu
1875
+ joshua reynolds
1876
+ josse lieferinxe
1877
+ jozef israëls
1878
+ józef mehoffer
1879
+ józef pankiewicz
1880
+ jozef simmler
1881
+ art language
1882
+ józsef borsos
1883
+ ju chao
1884
+ ju lian
1885
+ juan de flandes
1886
+ juan giménez
1887
+ juan gris
1888
+ juan luna
1889
+ juan ogorman
1890
+ judith brown
1891
+ judith leyster
1892
+ judy cassab
1893
+ judy takács
1894
+ jules bastienlepage
1895
+ jules breton
1896
+ jules chéret
1897
+ jules joseph lefebvre
1898
+ jules pascin
1899
+ arte povera
1900
+ jules tavernier
1901
+ julia margaret cameron
1902
+ julian fałat
1903
+ julian onderdonk
1904
+ julian schnabel
1905
+ julie bell
1906
+ ascii art
1907
+ julio gonzález
1908
+ julio larraz
1909
+ julius exner
1910
+ julius leblanc stewart
1911
+ juliusz kossak
1912
+ jung park
1913
+ junji ito
1914
+ justin currie
1915
+ justin gerard
1916
+ justin sweet
1917
+ justus van gent
1918
+ kaburagi kiyokata
1919
+ kadir nelson
1920
+ kahlo
1921
+ kaigetsudō ando
1922
+ kaii higashiyama
1923
+ kalervo palsa
1924
+ kamisaka sekka
1925
+ kandinsky
1926
+ kanō eitoku
1927
+ kanō hōgai
1928
+ bengal school art
1929
+ kanō motonobu
1930
+ berlin secession
1931
+ kanō sansetsu
1932
+ kanō sanraku
1933
+ kanō tanyū
1934
+ black arts movement
1935
+ kanzan shimomura
1936
+ karel dujardin
1937
+ bertalan karlovszky
1938
+ karel van mander
1939
+ karl bodmer
1940
+ karl bryullov
1941
+ karl hagedorn
1942
+ cloisonnism
1943
+ karl hofer
1944
+ karl kopinski
1945
+ bertram brooker
1946
+ karol bak
1947
+ karolis strautniekas
1948
+ károly brocky
1949
+ károly ferenczy
1950
+ károly kernstok
1951
+ károly kisfaludy
1952
+ károly lotz
1953
+ károly patkó
1954
+ kate beaton
1955
+ kate greenaway
1956
+ käthe kollwitz
1957
+ kathleen scott
1958
+ kati horna
1959
+ katia chausheva
1960
+ katsukawa shunei
1961
+ context art
1962
+ katsukawa shunsen
1963
+ katsukawa shunshō
1964
+ katsushika hokusai
1965
+ betye saar
1966
+ katsuya terada
1967
+ kawai gyokudō
1968
+ kawanabe kyōsai
1969
+ kawase hasui
1970
+ kay nielsen
1971
+ kay sage
1972
+ crystal cubism
1973
+ kazimierz alchimowicz
1974
+ kazimir malevich
1975
+ kees bol
1976
+ kees maks
1977
+ kees scherer
1978
+ kees van dongen
1979
+ keisai eisen
1980
+ keith haring
1981
+ keith henderson
1982
+ keith mallett
1983
+ keith parkinson
1984
+ cynical realism
1985
+ kelly mckernan
1986
+ kelly freas
1987
+ ken danby
1988
+ bikash bhattacharjee
1989
+ ken howard
1990
+ ken kelly
1991
+ bill lewis
1992
+ kelly sueda
1993
+ kenneth noland
1994
+ kentaro miura
1995
+ bill sienkiewicz
1996
+ keos masons
1997
+ danube school
1998
+ kerembeyit
1999
+ kev walker
2000
+ khalil gibran
2001
+ kieran yanner
2002
+ kilian eng
2003
+ kim keever
2004
+ kim tschang yeul
2005
+ billie waters
2006
+ kinuko craft
2007
+ ecological art
2008
+ kishi ganku
2009
+ kitagawa utamaro
2010
+ kitao shigemasa
2011
+ klimt
2012
+ kobayashi kiyochika
2013
+ excessivism
2014
+ kōno bairei
2015
+ blanche hoschedé monet
2016
+ konrad grob
2017
+ konrad klapheck
2018
+ konrad witz
2019
+ konstantin korovin
2020
+ konstantin makovsky
2021
+ konstantin savitsky
2022
+ konstantin somov
2023
+ konstantin vasilyev
2024
+ konstantin westchilov
2025
+ konstantin yuon
2026
+ konstantinas ciurlionis
2027
+ koson ohara
2028
+ krenz cushart
2029
+ kristian zahrtmann
2030
+ kristin nelson
2031
+ feminist art
2032
+ bob singer
2033
+ kun can
2034
+ kuroda seiki
2035
+ bob thompson
2036
+ kurt schwitters
2037
+ kurt wenner
2038
+ kusama
2039
+ kyffin williams
2040
+ kyle lambert
2041
+ bogi fabian
2042
+ ladrönn
2043
+ lajos bruck
2044
+ lajos gulácsy
2045
+ bohumil kubista
2046
+ lajos tihanyi
2047
+ fluxus
2048
+ lam qua
2049
+ lambert doomer
2050
+ lambert jacobsz
2051
+ lan ying
2052
+ lari pittman
2053
+ larry elmore
2054
+ larry fink
2055
+ larry rivers
2056
+ funk art
2057
+ bonnard pierre
2058
+ lasar segall
2059
+ boris vallejo
2060
+ lászló mednyánszky
2061
+ lászló paál
2062
+ laura ford
2063
+ laura knight
2064
+ laura muntz lyall
2065
+ generative art
2066
+ laura wheeler waring
2067
+ laurel burch
2068
+ laurie lipton
2069
+ laurits tuxen
2070
+ lawren harris
2071
+ boris vladimirski
2072
+ geometric abstract art
2073
+ lawrence harris
2074
+ leandro erlich
2075
+ german romanticism
2076
+ leconte stewart
2077
+ lee jeffries
2078
+ lee madgwick
2079
+ leland bell
2080
+ leng mei
2081
+ lennie lee
2082
+ brad holland
2083
+ leo leuppi
2084
+ léon bakst
2085
+ leon kapliński
2086
+ leon kossoff
2087
+ leon kroll
2088
+ leon wyczółkowski
2089
+ leona wood
2090
+ leonaert bramer
2091
+ leonard appelbee
2092
+ heidelberg school
2093
+ leonard long
2094
+ leonard ochtman
2095
+ leonardo da vinci
2096
+ leonid afremov
2097
+ leonid pasternak
2098
+ leonor fini
2099
+ leonora carrington
2100
+ leopold gottlieb
2101
+ leroy neiman
2102
+ les edwards
2103
+ lesser ury
2104
+ lev lvovich kamenev
2105
+ lewis henry meakin
2106
+ li cheng
2107
+ li chevalier
2108
+ li di
2109
+ li kan
2110
+ li keran
2111
+ li shan
2112
+ li shixing
2113
+ li song
2114
+ li tang
2115
+ li tiefu
2116
+ li zai
2117
+ liam wong
2118
+ liang kai
2119
+ brian bolland
2120
+ lichtenstein
2121
+ incoherents
2122
+ lilia alvarado
2123
+ lilla cabot perry
2124
+ lillian bassman
2125
+ brian despain
2126
+ limbourg brothers
2127
+ lin liang
2128
+ brian dunlop
2129
+ linda sutton
2130
+ lionel lindsay
2131
+ lionel walden
2132
+ lisa frank
2133
+ lisa milroy
2134
+ international gothic
2135
+ lisa yuskavage
2136
+ lise deharme
2137
+ liu haisu
2138
+ liu jun
2139
+ liza donnelly
2140
+ lizzy ansingh
2141
+ lodewijk bruckman
2142
+ lois dodd
2143
+ lois mailou jones
2144
+ lois van baarle
2145
+ loish
2146
+ brian thomas
2147
+ lorenzo lotto
2148
+ lorraine fox
2149
+ lotte reiniger
2150
+ louis anquetin
2151
+ louis buvelot
2152
+ louis comfort tiffany
2153
+ louis de caullery
2154
+ louis eilshemius
2155
+ louis faurer
2156
+ bridget bate tichenor
2157
+ louis grell
2158
+ louis hersent
2159
+ louis janmot
2160
+ louis le brocquy
2161
+ louis le nain
2162
+ bridget riley
2163
+ louis marcoussis
2164
+ louis stettner
2165
+ louis valtat
2166
+ louis wain
2167
+ louisa matthíasdóttir
2168
+ louisa puller
2169
+ louise abbéma
2170
+ louise bourgeois
2171
+ louise catherine breslau
2172
+ louise nevelson
2173
+ lovecraft
2174
+ lovis corinth
2175
+ lu guang
2176
+ lu zhi
2177
+ lubin baugin
2178
+ luc tuymans
2179
+ luca della robbia
2180
+ lucas cranach the elder
2181
+ lucas graciano
2182
+ lucas van leyden
2183
+ lucas vorsterman
2184
+ lucian freud
2185
+ lucien pissarro
2186
+ lucio fontana
2187
+ bruce mclean
2188
+ lucy madox brown
2189
+ ludolf bakhuizen
2190
+ ludolf leendertsz de jongh
2191
+ ludovico carracci
2192
+ bruce munro
2193
+ ludwig bemelmans
2194
+ ludwig knaus
2195
+ luděk marold
2196
+ bruce nauman
2197
+ luigi kasimir
2198
+ luis enrique camej
2199
+ luis royo
2200
+ luo mu
2201
+ luo ping
2202
+ lydia field emmet
2203
+ lyle tuttle
2204
+ bruce timm
2205
+ lyonel feininger
2206
+ lyubov popova
2207
+ m c escher
2208
+ ma lin
2209
+ ma quan
2210
+ ma shi
2211
+ ma wan
2212
+ ma yuan
2213
+ bryan organ
2214
+ mab graves
2215
+ mabel rollins harris
2216
+ mac conner
2217
+ maciej kuciara
2218
+ mads berg
2219
+ maeda masao
2220
+ bunny yeager
2221
+ magali villeneuve
2222
+ byeon sangbyeok
2223
+ makoto aida
2224
+ makoto shinkai
2225
+ byron galvez
2226
+ maksymilian gierymski
2227
+ malcolm drummond
2228
+ malcolm morley
2229
+ malczewski
2230
+ malevich
2231
+ malvin gray johnson
2232
+ man ray
2233
+ caesar van everdingen
2234
+ mandy jurgens
2235
+ marc bell
2236
+ marc chagall
2237
+ marc simonetti
2238
+ marcel duchamp
2239
+ marcello bacciarelli
2240
+ marcin zaleski
2241
+ marco mazzoni
2242
+ neoromanticism
2243
+ marek okon
2244
+ margaret boden
2245
+ margaret graeme niven
2246
+ margaret keane
2247
+ margaret macdonald mackintosh
2248
+ marguerite zorach
2249
+ marià fortuny
2250
+ maria sibylla merian
2251
+ marianne north
2252
+ marianne von werefkin
2253
+ marie angel
2254
+ marie bashkirtseff
2255
+ marie bracquemond
2256
+ marie krøyer
2257
+ marie laurencin
2258
+ marilyn bendell
2259
+ marina abramović
2260
+ mario sironi
2261
+ marion wachtel
2262
+ mariotto albertinelli
2263
+ marius borgeaud
2264
+ mark arian
2265
+ mark boyle
2266
+ mark brooks
2267
+ mark english
2268
+ mark gertler
2269
+ mark keathley
2270
+ mark poole
2271
+ mark rothko
2272
+ mark ryden
2273
+ mark tedin
2274
+ mark zug
2275
+ marsden hartley
2276
+ marshall arisman
2277
+ martin deschambault
2278
+ martin johnson heade
2279
+ martin kober
2280
+ martin schoeller
2281
+ martin schongauer
2282
+ martine johanna
2283
+ martinus rørbye
2284
+ martiros saryan
2285
+ paris school
2286
+ maruyama ōkyo
2287
+ mary adshead
2288
+ mary agnes yerkes
2289
+ mary beale
2290
+ mary black
2291
+ mary blair
2292
+ mary callery
2293
+ mary cameron
2294
+ mary cassatt
2295
+ plasticien
2296
+ mary davis
2297
+ mary dignam
2298
+ mary elizabeth price
2299
+ mary grant
2300
+ mary hallock foote
2301
+ mary mccrossan
2302
+ mary moser
2303
+ masamune shirow
2304
+ masolino
2305
+ mathias kollros
2306
+ mathieu le nain
2307
+ mati klarwein
2308
+ matsumura goshun
2309
+ matt cavotta
2310
+ preraphaelitism
2311
+ matt stewart
2312
+ matt groening
2313
+ matthew smith
2314
+ matthias jung
2315
+ matthias stom
2316
+ matthijs maris
2317
+ mattias adolfsson
2318
+ private press
2319
+ maurice boitel
2320
+ maurice braun
2321
+ maurice de vlaminck
2322
+ maurice denis
2323
+ maude kaufman eggemeyer
2324
+ maurice prendergast
2325
+ maurice sendak
2326
+ maurice utrillo
2327
+ maurycy gottlieb
2328
+ max beckmann
2329
+ max buri
2330
+ max dupain
2331
+ max ernst
2332
+ max gubler
2333
+ max klinger
2334
+ max liebermann
2335
+ max pechstein
2336
+ max slevogt
2337
+ max švabinský
2338
+ qajar art
2339
+ max weber
2340
+ maxfield parrish
2341
+ maxim verehin
2342
+ maximilien luce
2343
+ maxwell bates
2344
+ maxwell gordon lightfoot
2345
+ may louise greville cooksey
2346
+ mc escher
2347
+ mckadesinsanity
2348
+ rayonism
2349
+ mead schaeffer
2350
+ mei qing
2351
+ meindert hobbema
2352
+ melchior dhondecoeter
2353
+ melchior lorck
2354
+ melissa benson
2355
+ melozzo da forlì
2356
+ menez
2357
+ meredith dillman
2358
+ mi fu
2359
+ miao fu
2360
+ michael ancher
2361
+ michael andrews
2362
+ michael cheval
2363
+ michael dahl
2364
+ michael flohr
2365
+ michael ford
2366
+ michael garmash
2367
+ michael goldberg
2368
+ michael james smith
2369
+ michael komarck
2370
+ michael leunig
2371
+ michael malm
2372
+ michael sittow
2373
+ michael whelan
2374
+ michaelangelo
2375
+ michal karcz
2376
+ michał karcz
2377
+ michalis oikonomou
2378
+ michel delacroix
2379
+ michelangelo
2380
+ michelangelo buonarotti
2381
+ michelangelo buonarroti
2382
+ michelangelo merisi da caravaggio
2383
+ michiel jansz van mierevelt
2384
+ michiel van musscher
2385
+ mihály munkácsy
2386
+ mihály zichy
2387
+ miho hirano
2388
+ mikalojus konstantinas ciurlionis
2389
+ serial art
2390
+ mike bierek
2391
+ mike deodato
2392
+ mike mignola
2393
+ mike winkelmann
2394
+ mikhail evstafiev
2395
+ mikhail larionov
2396
+ shock art
2397
+ mikhail nesterov
2398
+ mikhail vrubel
2399
+ mikhail yuryevich lermontov
2400
+ miklós barabás
2401
+ mikhail lebedev
2402
+ mildred anne butler
2403
+ miles johnston
2404
+ millard sheets
2405
+ milton avery
2406
+ milton caniff
2407
+ milton glaser
2408
+ mirabello cavalori
2409
+ mitchell johnson
2410
+ miyamoto
2411
+ miyazaki
2412
+ moebius
2413
+ mœbius
2414
+ moïse kisling
2415
+ mondrian
2416
+ monet
2417
+ morgan russell
2418
+ mori sosen
2419
+ mort künstler
2420
+ moses soyer
2421
+ mstislav dobuzhinsky
2422
+ mucha
2423
+ muirhead bone
2424
+ synchromism
2425
+ munch
2426
+ muqi
2427
+ murakami
2428
+ muriel brandt
2429
+ murray tinkelman
2430
+ synthetism
2431
+ mykola burachek
2432
+ myles birket foster
2433
+ n c wyeth
2434
+ nc wyeth
2435
+ nadim karam
2436
+ nadir afonso
2437
+ nagasawa rosetsu
2438
+ nan goldin
2439
+ nancy graves
2440
+ naoko takeuchi
2441
+ naomi okubo
2442
+ natalia goncharova
2443
+ nathan oliveira
2444
+ nathan wyburn
2445
+ nathaniel hone
2446
+ national geographic
2447
+ naza
2448
+ neal adams
2449
+ neil blevins
2450
+ neil boyle
2451
+ neil welliver
2452
+ neil williams
2453
+ nell dorr
2454
+ nelson alexander ross
2455
+ nene thomas
2456
+ nevercrew
2457
+ neysa mcmein
2458
+ ni zan
2459
+ niccolò dell abbate
2460
+ nicholas hilliard
2461
+ nicholas roerich
2462
+ nick gentry
2463
+ nicola samori
2464
+ nicolaes maes
2465
+ nicolaes pieterszoon berchem
2466
+ nicolas de staël
2467
+ nicolas lancret
2468
+ nicolas poussin
2469
+ nicolas toussaint charlet
2470
+ nicoletta ceccoli
2471
+ nikita veprikov
2472
+ niklaus manuel
2473
+ niko henrichon
2474
+ nikolai astrup
2475
+ nikolai ge
2476
+ nikolai yaroshenko
2477
+ nikolaj abraham abildgaard
2478
+ nikolay makovsky
2479
+ nikolay nikanorovich dubovskoy
2480
+ nil gleyen
2481
+ nils von dardel
2482
+ nina hamnett
2483
+ nishikawa sukenobu
2484
+ noah bradley
2485
+ noel counihan
2486
+ noémi ferenczy
2487
+ norah neilson gray
2488
+ noriyoshi ohrai
2489
+ norma bull
2490
+ norman garstin
2491
+ norman hepple
2492
+ norman lewis
2493
+ norman rockwell
2494
+ norman saunders
2495
+ nuno gonçalves
2496
+ okeeffe
2497
+ odd nerdrum
2498
+ odilon redon
2499
+ ogata gekkō
2500
+ ogata kōrin
2501
+ ohara koson
2502
+ okumura masanobu
2503
+ oleg lipchenko
2504
+ oleg oprisco
2505
+ olga boznańska
2506
+ olha darchuk
2507
+ oliver sin
2508
+ olivia de berardinis
2509
+ olivia peguero
2510
+ orazio gentileschi
2511
+ osamu tezuka
2512
+ oskar kokoschka
2513
+ oskar schlemmer
2514
+ osman hamdi bey
2515
+ ossip zadkine
2516
+ oswald achenbach
2517
+ oswald birley
2518
+ oswaldo guayasamín
2519
+ otakar kubín
2520
+ ottó baditz
2521
+ otto dix
2522
+ otto eckmann
2523
+ otto piene
2524
+ otto pilny
2525
+ otto stark
2526
+ pablo carpio
2527
+ pablo munoz gomez
2528
+ pablo picasso
2529
+ pacita abad
2530
+ pál szinyei merse
2531
+ pamphilus
2532
+ pan yuliang
2533
+ paolo uccello
2534
+ paolo veronese
2535
+ parmigianino
2536
+ pascale campion
2537
+ pat adams
2538
+ patrick adam
2539
+ patrick brown
2540
+ patrick ching
2541
+ patrick dougherty
2542
+ patrick hall
2543
+ patrick henry bruce
2544
+ patrick heron
2545
+ patrick nagel
2546
+ patrick nasmyth
2547
+ patrick pietropoli
2548
+ patrick woodroffe
2549
+ paul bird
2550
+ paul bril
2551
+ paul cadmus
2552
+ paul cezanne
2553
+ paul cézanne
2554
+ paul cornoyer
2555
+ paul davis
2556
+ paul delvaux
2557
+ paul émile chabas
2558
+ paul gauguin
2559
+ paul georges
2560
+ paul guigou
2561
+ paul gustav fischer
2562
+ paul gustave fischer
2563
+ paul harvey
2564
+ paul henry
2565
+ paul jacob naftel
2566
+ paul kane
2567
+ paul kelpe
2568
+ paul klee
2569
+ paul lehr
2570
+ paul lohse
2571
+ paul nash
2572
+ paul ranson
2573
+ paul signac
2574
+ paula rego
2575
+ paulus moreelse
2576
+ paulus potter
2577
+ pavel fedotov
2578
+ pavel filonov
2579
+ pearl frush
2580
+ peder severin krøyer
2581
+ pedro álvarez castelló
2582
+ pedro figari
2583
+ peggy angus
2584
+ peggy bacon
2585
+ penleigh boyd
2586
+ penry williams
2587
+ per kirkeby
2588
+ perle fine
2589
+ peter alexander hay
2590
+ peter basch
2591
+ peter birmann
2592
+ peter blume
2593
+ peter brook
2594
+ peter churcher
2595
+ peter de seve
2596
+ peter doig
2597
+ peter elson
2598
+ peter fiore
2599
+ peter gric
2600
+ peter helck
2601
+ peter lanyon
2602
+ peter lely
2603
+ peter lindbergh
2604
+ peter madsen
2605
+ peter max
2606
+ peter michael
2607
+ peter mohrbacher
2608
+ peter paul rubens
2609
+ peter prendergast
2610
+ peter scott
2611
+ peter snow
2612
+ peter wells
2613
+ peter wtewael
2614
+ peter zumthor
2615
+ petrus christus
2616
+ petrus van der velden
2617
+ phil koch
2618
+ philip de lászló
2619
+ philip evergood
2620
+ philip guston
2621
+ philip wilson steer
2622
+ philipp veit
2623
+ philippe druillet
2624
+ philips wouwerman
2625
+ phillip otto runge
2626
+ picasso
2627
+ piero della francesca
2628
+ piero di cosimo
2629
+ pierre adolphe valette
2630
+ pierre auguste cot
2631
+ pierre bonnard
2632
+ pierre brissaud
2633
+ pierre mion
2634
+ pierre pellegrini
2635
+ pierre puvis de chavannes
2636
+ pierre roy
2637
+ pierre soulages
2638
+ pierreauguste renoir
2639
+ piet mondrian
2640
+ pieter aertsen
2641
+ pieter bruegel
2642
+ pieter brueghel the younger
2643
+ pieter claesz
2644
+ pieter codde
2645
+ pieter cornelisz van slingelandt
2646
+ pieter de grebber
2647
+ pieter de hooch
2648
+ pieter de ring
2649
+ pieter huys
2650
+ pieter janssens elinga
2651
+ pieter jansz saenredam
2652
+ pieter lastman
2653
+ pieter mulier ii
2654
+ pieter van anraedt
2655
+ pieter van der werff
2656
+ pieter van laer
2657
+ pietro da cortona
2658
+ pietro longhi
2659
+ pietro lorenzetti
2660
+ pietro perugino
2661
+ pinchus kremegne
2662
+ pinturicchio
2663
+ piranesi
2664
+ pisanello
2665
+ pixar
2666
+ pollock
2667
+ pompeo batoni
2668
+ prince hoare
2669
+ prudence heward
2670
+ pruett carter
2671
+ pu hua
2672
+ puru
2673
+ qi baishi
2674
+ qian du
2675
+ qian gu
2676
+ qian xuan
2677
+ qiu ying
2678
+ quentin blake
2679
+ quentin matsys
2680
+ quint buchholz
2681
+ r b kitaj
2682
+ r r mcian
2683
+ rachel reckitt
2684
+ rachel ruysch
2685
+ rachel whiteread
2686
+ rackstraw downes
2687
+ radi nedelchev
2688
+ rafail levitsky
2689
+ rafal olbinski
2690
+ raja ravi varma
2691
+ ralph albert blakelock
2692
+ ralph burke tyree
2693
+ ralph earl
2694
+ ralph horsley
2695
+ ralph mcquarrie
2696
+ randolph caldecott
2697
+ randolph schwabe
2698
+ randy gallegos
2699
+ randy post
2700
+ randy vargas
2701
+ raoul dufy
2702
+ raphael
2703
+ raphaël collin
2704
+ raphael kirchner
2705
+ raphael lacoste
2706
+ raphael soyer
2707
+ raphaelle peale
2708
+ ravi zupa
2709
+ ray caesar
2710
+ ray crooke
2711
+ ray parker
2712
+ raymond briggs
2713
+ raymond coxon
2714
+ raymond han
2715
+ raymond leech
2716
+ raymond saunders
2717
+ raymond swanland
2718
+ raymond teague cowern
2719
+ rebecca guay
2720
+ relja penezic
2721
+ rembrandt
2722
+ rembrandt peale
2723
+ rembrandt van rijn
2724
+ remedios varo
2725
+ ren hang
2726
+ ren xiong
2727
+ ren xun
2728
+ rené auberjonois
2729
+ rené burri
2730
+ rene magritte
2731
+ rené magritte
2732
+ renoir
2733
+ reynolds beal
2734
+ rhads
2735
+ ric nagualero
2736
+ ricardo bofill
2737
+ richard anuszkiewicz
2738
+ richard avedon
2739
+ richard benning
2740
+ richard carline
2741
+ richard corben
2742
+ richard dadd
2743
+ richard demarco
2744
+ richard diebenkorn
2745
+ richard doyle
2746
+ richard estes
2747
+ richard gerstl
2748
+ richard hamilton
2749
+ richard hess
2750
+ richard mayhew
2751
+ richard parkes bonington
2752
+ richard pionk
2753
+ richard schmid
2754
+ richard wilson
2755
+ richard wright
2756
+ richmond barthé
2757
+ richter
2758
+ rick amor
2759
+ rick griffin
2760
+ ridley scott
2761
+ ridolfo ghirlandaio
2762
+ rihard jakopič
2763
+ rinaldo cuneo
2764
+ rita angus
2765
+ riusuke fukahori
2766
+ riza abbasi
2767
+ rob alexander
2768
+ rob gonsalves
2769
+ rob liefeld
2770
+ robert adamson
2771
+ robert antoine pinchon
2772
+ robert ballagh
2773
+ robert bateman
2774
+ robert bechtle
2775
+ róbert berény
2776
+ robert bevan
2777
+ robert brackman
2778
+ robert brough
2779
+ robert bryden
2780
+ robert campin
2781
+ robert colquhoun
2782
+ robert crumb
2783
+ robert delaunay
2784
+ robert dickerson
2785
+ robert falk
2786
+ robert fawcett
2787
+ robert freebairn
2788
+ robert gavin
2789
+ robert griffier
2790
+ robert henderson blyth
2791
+ robert henri
2792
+ robert jacobsen
2793
+ robert koehler
2794
+ robert lenkiewicz
2795
+ robert macbryde
2796
+ robert maguire
2797
+ robert mapplethorpe
2798
+ robert mccall
2799
+ robert mcginnis
2800
+ robert motherwell
2801
+ robert noble
2802
+ robert peak
2803
+ robert rauschenberg
2804
+ robert reid
2805
+ robert scott lauder
2806
+ robert sivell
2807
+ robert thomas
2808
+ robert walker macbeth
2809
+ robert weaver
2810
+ robert weir allan
2811
+ robert william vonnoh
2812
+ robert zünd
2813
+ roberto ferri
2814
+ roberto parada
2815
+ rockwell kent
2816
+ rodel gonzalez
2817
+ rodney matthews
2818
+ rodolfo amoedo
2819
+ rodolfo escalera
2820
+ rodolfo morales
2821
+ rodolphe wytsman
2822
+ roelant savery
2823
+ roger ballen
2824
+ roger deakins
2825
+ roger dean
2826
+ roger wilson dennis
2827
+ rogier van der weyden
2828
+ rolf armstrong
2829
+ romaine brooks
2830
+ romare bearden
2831
+ ron english
2832
+ ron spears
2833
+ ron spencer
2834
+ ron walotsky
2835
+ ronald davis
2836
+ rory mcewen
2837
+ rosa bonheur
2838
+ rosalie emslie
2839
+ rose maynard barton
2840
+ rosemary allan
2841
+ ross tran
2842
+ rossdraws
2843
+ rowena meeks abdy
2844
+ roy de maistre
2845
+ roy decarava
2846
+ roy lichtenstein
2847
+ roy petley
2848
+ roz chast
2849
+ ruan jia
2850
+ rube goldberg
2851
+ rubens peale
2852
+ rudolf ernst
2853
+ rudolf hausner
2854
+ rudolf koller
2855
+ rudolf schlichter
2856
+ rudolf von alt
2857
+ rudolph belarski
2858
+ rudy siswanto
2859
+ rufino tamayo
2860
+ rupert bunny
2861
+ russell chatham
2862
+ russell dongjun lu
2863
+ russell drysdale
2864
+ russell patterson
2865
+ ruth hollingsworth
2866
+ ruth orkin
2867
+ ruth sanderson
2868
+ ruth simpson
2869
+ ryan barger
2870
+ ryan pancoast
2871
+ ryan yee
2872
+ ryohei hase
2873
+ ryōhei koiso
2874
+ ryoji ikeda
2875
+ sadao watanabe
2876
+ sailor moon
2877
+ saitō kiyoshi
2878
+ sakai hōitsu
2879
+ salomon de bray
2880
+ salomon koninck
2881
+ salomon van ruysdael
2882
+ salvador dali
2883
+ salvador dalí
2884
+ sam black
2885
+ sam bosma
2886
+ sam charles
2887
+ sam spratt
2888
+ samuel colman
2889
+ samuel dirksz van hoogstraten
2890
+ samuel f b morse
2891
+ samuel peploe
2892
+ samuel prout
2893
+ samuel scott
2894
+ samuel shelley
2895
+ samuel silva
2896
+ sándor bortnyik
2897
+ sandra chevrier
2898
+ sandro botticelli
2899
+ sanford robinson gifford
2900
+ santiago caruso
2901
+ santiago rusiñol
2902
+ sarah lucas
2903
+ sarah morris
2904
+ satoshi kon
2905
+ saul steinberg
2906
+ saul tepper
2907
+ scarlett hooft graafland
2908
+ scott gustafson
2909
+ scott listfield
2910
+ scott naismith
2911
+ sean scully
2912
+ seb mckinnon
2913
+ sebastian vrancx
2914
+ sebastiano ricci
2915
+ sengai
2916
+ senior artist
2917
+ senior environment artist
2918
+ serge sudeikin
2919
+ sergio larraín
2920
+ serhii vasylkivsky
2921
+ sesshū tōyō
2922
+ seuss dr
2923
+ shaddy safadi
2924
+ shang xi
2925
+ shao mi
2926
+ shen quan
2927
+ shen zhou
2928
+ sheng mao
2929
+ sheng maoye
2930
+ shibata zeshin
2931
+ shigeru aoki
2932
+ shin saimdang
2933
+ shin yunbok
2934
+ shinji aramaki
2935
+ shitao
2936
+ shukei sesson
2937
+ sidney nolan
2938
+ sidney richard percy
2939
+ siegfried haas
2940
+ sigurd swane
2941
+ silvestro lega
2942
+ silvia dimitrova
2943
+ silvia pelissero
2944
+ simon bisley
2945
+ simon marmion
2946
+ simon stalenhag
2947
+ simon stålenhag
2948
+ simon vouet
2949
+ simone martini
2950
+ sin wi
2951
+ sir alfred munnings
2952
+ sir jacob epstein
2953
+ sir john tenniel
2954
+ sir william orpen
2955
+ sir william russell flint
2956
+ slawomir maniak
2957
+ sofonisba anguissola
2958
+ sohrab sepehri
2959
+ soma orlai petrich
2960
+ song xu
2961
+ sonia delaunay
2962
+ sophie anderson
2963
+ sophie gengembre anderson
2964
+ sophie pemberton
2965
+ sōtarō yasui
2966
+ sparth
2967
+ spencer gore
2968
+ stan galli
2969
+ stan stokes
2970
+ stanhope forbes
2971
+ stanislas lépine
2972
+ stanislav zhukovsky
2973
+ stanisław ignacy witkiewicz
2974
+ stanisław masłowski
2975
+ stanisław wyspiański
2976
+ stanley artgerm
2977
+ stanley spencer
2978
+ stefan lochner
2979
+ stephan martiniere
2980
+ stephan martinière
2981
+ stephen bone
2982
+ stephen greene
2983
+ stephen little
2984
+ stephen pace
2985
+ stevan dohanos
2986
+ steve argyle
2987
+ steve dillon
2988
+ steve hanks
2989
+ steve mccurry
2990
+ steven belledin
2991
+ stokely webster
2992
+ storm thorgerson
2993
+ stuart davis
2994
+ studio ghibli
2995
+ sudip roy
2996
+ sugimura jihei
2997
+ sun long
2998
+ sung choi
2999
+ sunil das
3000
+ susan crile
3001
+ suzanne valadon
3002
+ suzuki harunobu
3003
+ svetlin velinov
3004
+ svetoslav roerich
3005
+ syd barrett
3006
+ syd mead
3007
+ sydney carline
3008
+ sydney prior hall
3009
+ sylvain sarrailh
3010
+ sylvester shchedrin
3011
+ sylvia molloy
3012
+ sylvia sleigh
3013
+ szymon czechowicz
3014
+ t c steele
3015
+ tadao ando
3016
+ taddeo gaddi
3017
+ tadeusz makowski
3018
+ taiyō matsumoto
3019
+ takahashi yuichi
3020
+ takashi murakami
3021
+ takato yamamoto
3022
+ takehisa yumeji
3023
+ takeshi obata
3024
+ takeuchi seihō
3025
+ tamara de lempicka
3026
+ tamara lempicka
3027
+ tang di
3028
+ tang yifen
3029
+ tang yin
3030
+ tani bunchō
3031
+ taro okamoto
3032
+ taro yamamoto
3033
+ tatiana hordiienko
3034
+ tatsuyuki tanaka
3035
+ tawaraya sōtatsu
3036
+ ted degrazia
3037
+ ted nasmith
3038
+ telemaco signorini
3039
+ terese nielsen
3040
+ terry morris
3041
+ terry oakes
3042
+ terry redlin
3043
+ the brothers hildebrandt
3044
+ thechamba
3045
+ theo van doesburg
3046
+ theodor philipsen
3047
+ théodore chassériau
3048
+ theodore earl butler
3049
+ théodore géricault
3050
+ theodore major
3051
+ theodore robinson
3052
+ théodore rousseau
3053
+ théodule ribot
3054
+ thierry bisch
3055
+ thomas baines
3056
+ thomas barker
3057
+ thomas blackshear
3058
+ thomas bock
3059
+ thomas campbell
3060
+ thomas cantrell dugdale
3061
+ thomas carr
3062
+ thomas cole
3063
+ thomas couture
3064
+ thomas crane
3065
+ thomas dalziel
3066
+ thomas de keyser
3067
+ thomas dewing
3068
+ thomas doughty
3069
+ thomas eakins
3070
+ thomas fogarty
3071
+ thomas gainsborough
3072
+ thomas hart benton
3073
+ thomas hill
3074
+ thomas kinkade
3075
+ thomas kluge
3076
+ thomas lawrence
3077
+ thomas mann baynes
3078
+ thomas millie dow
3079
+ thomas moran
3080
+ thomas nast
3081
+ thomas rowlandson
3082
+ thomas scholes
3083
+ thomas stothard
3084
+ thomas struth
3085
+ thomas wijck
3086
+ thornton oakley
3087
+ tim biskup
3088
+ tim doyle
3089
+ tim hildebrandt
3090
+ tim okamura
3091
+ tim white
3092
+ tina blondell
3093
+ tina modotti
3094
+ tintoretto
3095
+ titian
3096
+ titus lunter
3097
+ todd lockwood
3098
+ tom bagshaw
3099
+ tom bonson
3100
+ tom chambers
3101
+ tom lovell
3102
+ tom phillips
3103
+ tom roberts
3104
+ tom scott rsa
3105
+ tom thomson
3106
+ tom wesselmann
3107
+ tom whalen
3108
+ tomasz alen kopera
3109
+ tomasz jedruszek
3110
+ tomek setowski
3111
+ tomer hanuka
3112
+ tomi ungerer
3113
+ tomioka tessai
3114
+ tommaso masaccio
3115
+ tomokazu matsuyama
3116
+ tony diterlizzi
3117
+ tony sart
3118
+ tooth wu
3119
+ torii kiyomasu
3120
+ torii kiyomitsu
3121
+ torii kiyonaga
3122
+ torii kiyonobu i
3123
+ tosa mitsunobu
3124
+ tosa mitsuoki
3125
+ tōshi yoshida
3126
+ toshiko okanoue
3127
+ tove jansson
3128
+ toyen
3129
+ toyohara chikanobu
3130
+ toyohara kunichika
3131
+ tracey emin
3132
+ tracy harris
3133
+ tran nguyen
3134
+ trevor brown
3135
+ tsuchida bakusen
3136
+ tsuchiya koitsu
3137
+ tsuguharu foujita
3138
+ tsukioka yoshitoshi
3139
+ tuomas korpi
3140
+ tyler edlin
3141
+ tyler jacobson
3142
+ uemura shōen
3143
+ ulrika pasch
3144
+ umberto boccioni
3145
+ unichi hiratsuka
3146
+ urakusai nagahide
3147
+ utagawa hirokage
3148
+ utagawa hiroshige ii
3149
+ utagawa kunimasa
3150
+ utagawa kunisada
3151
+ utagawa kunisada ii
3152
+ utagawa kuniyoshi
3153
+ utagawa toyoharu
3154
+ utagawa toyokuni
3155
+ utagawa yoshiiku
3156
+ utagawa yoshitaki
3157
+ utagawa yoshitora
3158
+ utagawa yoshitsuya
3159
+ václav brožík
3160
+ valentin aleksandrovich serov
3161
+ valentine hugo
3162
+ valerie petts
3163
+ van gogh
3164
+ vanessa beecroft
3165
+ vanessa bell
3166
+ vasily andreevich tropinin
3167
+ vasily perov
3168
+ vasily polenov
3169
+ vasily surikov
3170
+ vasily vereshchagin
3171
+ vassily maximov
3172
+ vermeer
3173
+ vicente juan masip
3174
+ victo ngai
3175
+ victor adame minguez
3176
+ victor brauner
3177
+ victor enrich
3178
+ victor meirelles
3179
+ victor mosquera
3180
+ victor nizovtsev
3181
+ victor vasarely
3182
+ victor wang
3183
+ victoria francés
3184
+ viktor madarász
3185
+ viktor oliva
3186
+ viktor vasnetsov
3187
+ vilhelm kyhn
3188
+ vincent di fate
3189
+ vincent evans
3190
+ vincent lefevre
3191
+ vincent proce
3192
+ vincent van gogh
3193
+ vincenzo cabianca
3194
+ vincenzo irolli
3195
+ viola paterson
3196
+ violet oakley
3197
+ virgil finlay
3198
+ virginia lee burton
3199
+ vito dancona
3200
+ vittore carpaccio
3201
+ vivian maier
3202
+ vladimir borovikovsky
3203
+ vladimir kush
3204
+ vladimir makovsky
3205
+ vladimir tatlin
3206
+ vladimir tretchikoff
3207
+ vlaho bukovac
3208
+ volkan baga
3209
+ wadim kashin
3210
+ waldo peirce
3211
+ walenty wańkowicz
3212
+ wally wood
3213
+ walt disney
3214
+ walt reed
3215
+ walter bayes
3216
+ walter beach humphrey
3217
+ walter crane
3218
+ walter emerson baum
3219
+ walter haskell hinton
3220
+ walter humphrey
3221
+ walter leighton clark
3222
+ walter osborne
3223
+ walter sickert
3224
+ walter stuempfig
3225
+ wang duo
3226
+ wang e
3227
+ wang fu
3228
+ wang hui
3229
+ wang jian
3230
+ wang lü
3231
+ wang meng
3232
+ wang mian
3233
+ wang shimin
3234
+ wang shishen
3235
+ wang wei
3236
+ wang wu
3237
+ wang ximeng
3238
+ wang yi
3239
+ wang yuan
3240
+ wang yuanqi
3241
+ wang zhenpeng
3242
+ warhol
3243
+ warren mahy
3244
+ warwick goble
3245
+ washington allston
3246
+ wassily kandinsky
3247
+ wayne barlowe
3248
+ wayne england
3249
+ wayne reynolds
3250
+ wayne thiebaud
3251
+ weiwei
3252
+ wen boren
3253
+ wen jia
3254
+ wen tong
3255
+ wen zhengming
3256
+ wendell minor
3257
+ wendy froud
3258
+ wes anderson
3259
+ wes wilson
3260
+ wesley burt
3261
+ wifredo lam
3262
+ wilhelm bendz
3263
+ wilhelm leibl
3264
+ wilhelm marstrand
3265
+ wilhelm schnarrenberger
3266
+ wilhelm trübner
3267
+ will barnet
3268
+ will eisner
3269
+ will ellis
3270
+ willard metcalf
3271
+ willem claeszoon heda
3272
+ willem cornelisz duyster
3273
+ willem de kooning
3274
+ willem drost
3275
+ willem kalf
3276
+ willem maris
3277
+ willem van aelst
3278
+ willem van der vliet
3279
+ willem van haecht
3280
+ willem van mieris
3281
+ william berra
3282
+ william blake
3283
+ william blake richmond
3284
+ william bliss baker
3285
+ william bonnar
3286
+ william brodie
3287
+ william coldstream
3288
+ william conor
3289
+ william crosbie
3290
+ william crozier
3291
+ william dargie
3292
+ william dobell
3293
+ william dobson
3294
+ william dring
3295
+ william edouard scott
3296
+ william edward west
3297
+ william etty
3298
+ william fettes douglas
3299
+ william forsyth
3300
+ william gear
3301
+ william george gillies
3302
+ william glackens
3303
+ william gropper
3304
+ william harnett
3305
+ william hoare
3306
+ william hogarth
3307
+ william holman hunt
3308
+ william holmes sullivan
3309
+ william home lizars
3310
+ william jacob baer
3311
+ william jennys
3312
+ william john thomson
3313
+ william kentridge
3314
+ william langson lathrop
3315
+ william mactaggart
3316
+ william mcgregor paxton
3317
+ william mctaggart
3318
+ william merritt chase
3319
+ william michael harnett
3320
+ william miller
3321
+ william morris
3322
+ william nicholson
3323
+ william powhida
3324
+ william quiller orchardson
3325
+ william simpson
3326
+ william steig
3327
+ william stott
3328
+ william stout
3329
+ william trost richards
3330
+ william turner
3331
+ william woodward
3332
+ william york macgregor
3333
+ william zorach
3334
+ williamadolphe bouguereau
3335
+ willian murai
3336
+ willie ito
3337
+ willy finch
3338
+ wilson irvine
3339
+ winona nelson
3340
+ winslow homer
3341
+ winsor mccay
3342
+ winston churchill
3343
+ władysław czachórski
3344
+ władysław podkowiński
3345
+ wlop
3346
+ wojciech gerson
3347
+ wojciech korneli stattler
3348
+ wojciech kossak
3349
+ wojciech weiss
3350
+ wolf huber
3351
+ wolf kahn
3352
+ wolfgang letti
3353
+ wolfgang lettl
3354
+ wouter pietersz crabeth
3355
+ wu bin
3356
+ wu changshuo
3357
+ wu guanzhong
3358
+ wu hong
3359
+ wu li
3360
+ wu shixian
3361
+ wu wei
3362
+ wu zhen
3363
+ wu zuoren
3364
+ wylie beckert
3365
+ wyndham lewis
3366
+ xanthus russell smith
3367
+ xi gang
3368
+ xia chang
3369
+ xia gui
3370
+ xia yong
3371
+ xiang shengmo
3372
+ xiao yuncong
3373
+ xie he
3374
+ xie huan
3375
+ xie sun
3376
+ xu beihong
3377
+ xu wei
3378
+ xu xi
3379
+ xuande emperor
3380
+ xul solar
3381
+ yan hui
3382
+ yan liben
3383
+ yanagawa shigenobu
3384
+ yang j
3385
+ yang jin
3386
+ yanjun cheng
3387
+ yasar vurdem
3388
+ yasuo kuniyoshi
3389
+ yasutomo oka
3390
+ yayoi kusama
3391
+ yayou kusama
3392
+ yerkaland
3393
+ yi jaegwan
3394
+ yoann lossel
3395
+ yoji shinkawa
3396
+ yokoyama taikan
3397
+ yosa buson
3398
+ yoshihiko wada
3399
+ yoshio markino
3400
+ yoshitaka amano
3401
+ yoshitoshi mori
3402
+ yousuf karsh
3403
+ yu zhiding
3404
+ yuan jiang
3405
+ yuan yao
3406
+ yue minjun
3407
+ yuko shimizu
3408
+ yun duseo
3409
+ yun shouping
3410
+ yuri ivanovich pimenov
3411
+ yuumei
3412
+ yves klein
3413
+ yves tanguy
3414
+ yvonne jacquette
3415
+ zack snyder
3416
+ zack stella
3417
+ zaha hadid
3418
+ zdzislaw beksinski
3419
+ zdzisław beksiński
3420
+ zeen chin
3421
+ zeng jing
3422
+ zhang han
3423
+ zhang kechun
3424
+ zhang lu
3425
+ zhang shuqi
3426
+ zhang wo
3427
+ zhang xiaogang
3428
+ zhang xuan
3429
+ zhang yan
3430
+ zhang yin
3431
+ zhang zeduan
3432
+ zhang zongcang
3433
+ zhao mengfu
3434
+ zhao yong
3435
+ zhao zuo
3436
+ zheng xie
3437
+ zhichao cai
3438
+ zhou chen
3439
+ zhou fang
3440
+ zhou jichang
3441
+ zhou wenjing
3442
+ zhu da
3443
+ zhu derun
3444
+ zinaida serebriakova
3445
+ zoë mozert
3446
+ zou yigui
3447
+ zou zhe
3448
+ zsolt bodoni
3449
+ zygmunt waliszewski
3450
+ dustin nguyen
3451
+ e simms campbell
3452
+ e william gollings
3453
+ ed emshwiller
3454
+ ed paschke
3455
+ edi rama
3456
+ edmund f ward
3457
+ édouard detaille
3458
+ édouard vuillard
3459
+ eduardo paolozzi
3460
+ edward bailey
3461
+ edward burnejones
3462
+ edward george handel lucas
3463
+ edward hicks
3464
+ edward okuń
3465
+ edward ruscha
3466
+ edward wadsworth
3467
+ edwin dickinson
3468
+ edwin g lucas
3469
+ eglon van der neer
3470
+ eiichiro oda
3471
+ einar hakonarson
3472
+ elbridge ayer burbank
3473
+ ellen gallagher
3474
+ elsa bleda
3475
+ emil orlik
3476
+ emilio grau sala
3477
+ emily mason
3478
+ emma geary
3479
+ ken elias
3480
+ brice marden
CSD/main_sim.py ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ # Copyright (c) Facebook, Inc. and its affiliates.
4
+ # All rights reserved.
5
+
6
+ # This source code is licensed under the license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+
9
+ import argparse
10
+ import builtins
11
+ import os
12
+ import pathlib
13
+ import random
14
+ import sys
15
+ import warnings
16
+
17
+ import numpy as np
18
+ import torch
19
+ import torch.nn as nn
20
+ import torch.nn.parallel
21
+ import torch.backends.cudnn as cudnn
22
+ import torch.distributed as dist
23
+ import torch.optim
24
+ import torch.multiprocessing as mp
25
+ import torch.utils.data
26
+ import torch.utils.data.distributed
27
+ from torchvision import transforms
28
+ import torchvision.models as torchvision_models
29
+ from torchvision.models import VGG16_Weights
30
+
31
+ sys.path.insert(0, str(pathlib.Path(__file__).parent.resolve()))
32
+
33
+ import utils
34
+ from utils import extract_features_pca
35
+ from models import dino_vits, moco_vits
36
+ from data.wikiart import WikiArtD
37
+
38
+
39
+ parser = argparse.ArgumentParser('dynamicDistances-Embedding Generation Module')
40
+ parser.add_argument('--dataset', type=str, required=True, help="Name of the dataset",
41
+ choices=['wikiart'])
42
+
43
+ parser.add_argument('--qsplit', default='query', choices=['query', 'database'], type=str, help="The inferences")
44
+ parser.add_argument('--data-dir', type=str, default=None,
45
+ help='The directory of concerned dataset')
46
+ parser.add_argument('--pt_style', default='csd', type=str)
47
+ parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet50')
48
+
49
+ parser.add_argument('-j', '--workers', default=4, type=int, metavar='N',
50
+ help='number of data loading workers (default: 32)')
51
+ parser.add_argument('-b', '--batch-size', default=64, type=int,
52
+ metavar='N',
53
+ help='mini-batch size (default: 128), this is the total '
54
+ 'batch size of all GPUs on all nodes when '
55
+ 'using Data Parallel or Distributed Data Parallel')
56
+ parser.add_argument('--world-size', default=-1, type=int,
57
+ help='number of nodes for distributed training')
58
+ parser.add_argument('--rank', default=-1, type=int,
59
+ help='node rank for distributed training')
60
+ parser.add_argument('--dist-url', default='tcp://224.66.41.62:23456', type=str,
61
+ help='url used to set up distributed training')
62
+ parser.add_argument('--dist-backend', default='nccl', type=str,
63
+ help='distributed backend')
64
+ parser.add_argument('--seed', default=None, type=int,
65
+ help='seed for initializing training. ')
66
+ parser.add_argument('--gpu', default=None, type=int,
67
+ help='GPU id to use.')
68
+ parser.add_argument('--multiprocessing-distributed', action='store_true',
69
+ help='Use multi-processing distributed training to launch '
70
+ 'N processes per node, which has N GPUs. This is the '
71
+ 'fastest way to use PyTorch for either single node or '
72
+ 'multi node data parallel training')
73
+
74
+ parser.add_argument('--multiscale', default=False, type=utils.bool_flag)
75
+
76
+ # additional configs:
77
+ parser.add_argument('--pretrained', default='', type=str,
78
+ help='path to moco pretrained checkpoint')
79
+ parser.add_argument('--num_loss_chunks', default=1, type=int)
80
+ parser.add_argument('--isvit', action='store_true')
81
+ parser.add_argument('--layer', default=1, type=int, help="layer from end to create descriptors from.")
82
+ parser.add_argument('--feattype', default='normal', type=str, choices=['otprojected', 'weighted', 'concated', 'gram', 'normal'])
83
+ parser.add_argument('--projdim', default=256, type=int)
84
+
85
+ parser.add_argument('-mp', '--model_path', type=str, default=None)
86
+ parser.add_argument('--gram_dims', default=1024, type=int)
87
+ parser.add_argument('--query_count', default=-1, type=int, help='Number of queries to consider for final evaluation. Works only for domainnet')
88
+
89
+ parser.add_argument('--embed_dir', default='./embeddings', type=str, help='Directory to save embeddings')
90
+
91
+ ## Additional config for CSD
92
+ parser.add_argument('--eval_embed', default='head', choices=['head', 'backbone'], help="Which embed to use for eval")
93
+ parser.add_argument('--skip_val', action='store_true')
94
+
95
+
96
+ best_acc1 = 0
97
+
98
+
99
+ def main():
100
+ args = parser.parse_args()
101
+
102
+ if args.seed is not None:
103
+ random.seed(args.seed)
104
+ torch.manual_seed(args.seed)
105
+ cudnn.deterministic = True
106
+ warnings.warn('You have chosen to seed training. '
107
+ 'This will turn on the CUDNN deterministic setting, '
108
+ 'which can slow down your training considerably! '
109
+ 'You may see unexpected behavior when restarting '
110
+ 'from checkpoints.')
111
+ # utils.init_distributed_mode(args)
112
+ if args.gpu is not None:
113
+ warnings.warn('You have chosen a specific GPU. This will completely '
114
+ 'disable data parallelism.')
115
+
116
+ if args.dist_url == "env://" and args.world_size == -1:
117
+ args.world_size = int(os.environ["WORLD_SIZE"])
118
+
119
+ args.distributed = args.world_size > 1 or args.multiprocessing_distributed
120
+
121
+ ngpus_per_node = torch.cuda.device_count()
122
+ if args.multiprocessing_distributed:
123
+ # Since we have ngpus_per_node processes per node, the total world_size
124
+ # needs to be adjusted accordingly
125
+ args.world_size = ngpus_per_node * args.world_size
126
+ # Use torch.multiprocessing.spawn to launch distributed processes: the
127
+ # main_worker process function
128
+ mp.spawn(main_worker, nprocs=ngpus_per_node, args=(ngpus_per_node, args))
129
+ else:
130
+ # Simply call main_worker function
131
+ main_worker(args.gpu, ngpus_per_node, args)
132
+
133
+
134
+ def main_worker(gpu, ngpus_per_node, args):
135
+ global best_acc1
136
+ args.gpu = gpu
137
+
138
+ # suppress printing if not master
139
+ if args.multiprocessing_distributed and args.gpu != 0:
140
+ def print_pass(*args):
141
+ pass
142
+
143
+ builtins.print = print_pass
144
+
145
+ if args.gpu is not None:
146
+ print("Use GPU: {} for training".format(args.gpu))
147
+
148
+ if args.distributed:
149
+ if args.dist_url == "env://" and args.rank == -1:
150
+ args.rank = int(os.environ["RANK"])
151
+ if args.multiprocessing_distributed:
152
+ # For multiprocessing distributed training, rank needs to be the
153
+ # global rank among all the processes
154
+ args.rank = args.rank * ngpus_per_node + gpu
155
+ dist.init_process_group(backend=args.dist_backend, init_method=args.dist_url,
156
+ world_size=args.world_size, rank=args.rank)
157
+ torch.distributed.barrier()
158
+
159
+ # create model
160
+ if args.pt_style == 'dino':
161
+ dinomapping = {
162
+ 'vit_base': 'dino_vitb16',
163
+ 'vit_base8': 'dino_vitb8', # TODO: this mapping is incorrect. Change it later
164
+ }
165
+ if args.arch not in dinomapping:
166
+ raise NotImplementedError('This model type does not exist/supported for DINO')
167
+ model = dino_vits.__dict__[dinomapping[args.arch]](
168
+ pretrained=True
169
+ )
170
+ elif args.pt_style == 'moco':
171
+ if args.arch == 'vit_base':
172
+ model = moco_vits.__dict__[args.arch]()
173
+ pretrained = torch.load('./pretrainedmodels/vit-b-300ep.pth.tar', map_location='cpu')
174
+ state_dict = pretrained['state_dict']
175
+ for k in list(state_dict.keys()):
176
+ # retain only base_encoder up to before the embedding layer
177
+ if k.startswith('module.base_encoder'):
178
+ # remove prefix
179
+ state_dict[k[len("module.base_encoder."):]] = state_dict[k]
180
+ # delete renamed or unused k
181
+ del state_dict[k]
182
+ model.load_state_dict(state_dict, strict=False)
183
+ else:
184
+ raise NotImplementedError('This model type does not exist/supported for MoCo')
185
+ elif args.pt_style == 'clip':
186
+ from models import clip
187
+ clipmapping = {
188
+ 'vit_large': 'ViT-L/14',
189
+ 'vit_base': 'ViT-B/16',
190
+ }
191
+ if args.arch not in clipmapping:
192
+ raise NotImplementedError('This model type does not exist/supported for CLIP')
193
+ model, preprocess = clip.load(clipmapping[args.arch])
194
+ elif args.pt_style == 'vgg':
195
+ model = torchvision_models.vgg16(weights=VGG16_Weights.IMAGENET1K_V1)
196
+ elif args.pt_style == 'sscd':
197
+ if args.arch == 'resnet50':
198
+ model = torch.jit.load("./pretrainedmodels/sscd_disc_mixup.torchscript.pt")
199
+ elif args.arch == 'resnet50_disc':
200
+ model = torch.jit.load("./pretrainedmodels/sscd_disc_large.torchscript.pt")
201
+ else:
202
+ NotImplementedError('This model type does not exist/supported for SSCD')
203
+ elif args.pt_style.startswith('csd'):
204
+ assert args.model_path is not None, "Model path missing for CSD model"
205
+ from CSD.model import CSD_CLIP
206
+ from CSD.utils import has_batchnorms, convert_state_dict
207
+ from CSD.loss_utils import transforms_branch0
208
+
209
+ args.content_proj_head = "default"
210
+ model = CSD_CLIP(args.arch, args.content_proj_head)
211
+ if has_batchnorms(model):
212
+ model = nn.SyncBatchNorm.convert_sync_batchnorm(model)
213
+
214
+ checkpoint = torch.load(args.model_path, map_location="cpu")
215
+ state_dict = convert_state_dict(checkpoint['model_state_dict'])
216
+ msg = model.load_state_dict(state_dict, strict=False)
217
+ print(f"=> loaded checkpoint with msg {msg}")
218
+ preprocess = transforms_branch0
219
+
220
+ if not torch.cuda.is_available():
221
+ print('using CPU, this will be slow')
222
+ elif args.distributed:
223
+ # For multiprocessing distributed, DistributedDataParallel constructor
224
+ # should always set the single device scope, otherwise,
225
+ # DistributedDataParallel will use all available devices.
226
+ if args.gpu is not None:
227
+ torch.cuda.set_device(args.gpu)
228
+ model.cuda(args.gpu)
229
+ # When using a single GPU per process and per
230
+ # DistributedDataParallel, we need to divide the batch size
231
+ # ourselves based on the total number of GPUs we have
232
+ args.batch_size = int(args.batch_size / args.world_size)
233
+ args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node)
234
+ model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu])
235
+ else:
236
+ model.cuda()
237
+ # DistributedDataParallel will divide and allocate batch_size to all
238
+ # available GPUs if device_ids are not set
239
+ model = torch.nn.parallel.DistributedDataParallel(model)
240
+ elif args.gpu is not None:
241
+ torch.cuda.set_device(args.gpu)
242
+ model = model.cuda(args.gpu)
243
+ else:
244
+ # DataParallel will divide and allocate batch_size to all available GPUs
245
+ if args.arch.startswith('alexnet') or args.arch.startswith('vgg'):
246
+ model.features = torch.nn.DataParallel(model.features)
247
+ model.cuda()
248
+ model = torch.nn.DataParallel(model).cuda()
249
+
250
+ cudnn.benchmark = True
251
+
252
+ # Data loading code
253
+ if args.pt_style == 'clip': # and args.arch == 'resnet50':
254
+ ret_transform = preprocess
255
+ elif args.pt_style.startswith('csd'):
256
+ ret_transform = preprocess
257
+ elif args.pt_style in ['dino', 'moco', 'vgg']:
258
+ ret_transform = transforms.Compose([
259
+ transforms.Resize(256),
260
+ transforms.CenterCrop(224),
261
+ transforms.ToTensor(),
262
+ transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
263
+ ])
264
+ else:
265
+ ret_transform = transforms.Compose([
266
+ transforms.Resize(256),
267
+ transforms.CenterCrop(224),
268
+ transforms.ToTensor(),
269
+ transforms.Normalize([0.5], [0.5]),
270
+ ])
271
+
272
+ if args.dataset == 'wikiart':
273
+ dataset_query = WikiArtD(args.data_dir, args.qsplit, ret_transform)
274
+ dataset_values = WikiArtD(args.data_dir, 'database', ret_transform)
275
+ else:
276
+ raise NotImplementedError
277
+
278
+ ## creating dataloader
279
+ if args.distributed:
280
+ sampler = torch.utils.data.distributed.DistributedSampler(dataset_values, shuffle=False)
281
+ qsampler = torch.utils.data.distributed.DistributedSampler(dataset_query, shuffle=False)
282
+ else:
283
+ sampler = None
284
+ qsampler = None
285
+ data_loader_values = torch.utils.data.DataLoader(
286
+ dataset_values,
287
+ sampler=sampler,
288
+ batch_size=args.batch_size,
289
+ num_workers=args.workers,
290
+ pin_memory=True,
291
+ drop_last=False,
292
+ )
293
+ data_loader_query = torch.utils.data.DataLoader(
294
+ dataset_query,
295
+ sampler=qsampler,
296
+ batch_size=args.batch_size if args.feattype != 'gram' else 32,
297
+ num_workers=args.workers,
298
+ pin_memory=True,
299
+ drop_last=False,
300
+ )
301
+ print(f"train: {len(dataset_values)} imgs / query: {len(dataset_query)} imgs")
302
+ model.eval()
303
+
304
+ ############################################################################
305
+ if not args.multiprocessing_distributed:
306
+ utils.init_distributed_mode(args)
307
+ if args.rank == 0: # only rank 0 will work from now on
308
+
309
+ # Step 1: extract features
310
+ os.makedirs(args.embed_dir, exist_ok=True)
311
+ embsavepath = os.path.join(
312
+ args.embed_dir,
313
+ f'{args.pt_style}_{args.arch}_{args.dataset}_{args.feattype}',
314
+ f'{str(args.layer)}')
315
+ if args.feattype == 'gram':
316
+ path1, path2 = embsavepath.split('_gram')
317
+ embsavepath = '_'.join([path1, 'gram', str(args.gram_dims), args.qsplit, path2])
318
+
319
+ if os.path.isfile(os.path.join(embsavepath, 'database/embeddings_0.pkl')) or args.skip_val:
320
+ valexist = True
321
+ else:
322
+ valexist = False
323
+ if args.feattype == 'gram':
324
+ pca_dirs, meanvals = None, None
325
+ query_features, pca_dirs = extract_features_pca(args, model, pca_dirs, args.gram_dims, data_loader_query,
326
+ False, multiscale=args.multiscale)
327
+ if not valexist:
328
+ values_features, _ = extract_features_pca(args, model, pca_dirs, args.gram_dims, data_loader_values,
329
+ False, multiscale=args.multiscale)
330
+
331
+ elif args.pt_style.startswith('csd'):
332
+ from CSD.utils import extract_features
333
+ query_features = extract_features(model, data_loader_query, use_cuda=False, use_fp16=True, eval_embed=args.eval_embed)
334
+
335
+ if not valexist:
336
+ values_features = extract_features(model, data_loader_values, use_cuda=False, use_fp16=True, eval_embed=args.eval_embed)
337
+ else:
338
+ from utils import extract_features
339
+ query_features = extract_features(args, model, data_loader_query, False, multiscale=args.multiscale)
340
+ if not valexist:
341
+ values_features = extract_features(args, model, data_loader_values, False,
342
+ multiscale=args.multiscale)
343
+
344
+ from search.embeddings import save_chunk
345
+ l_query_features = list(np.asarray(query_features.cpu().detach(), dtype=np.float16))
346
+
347
+ save_chunk(l_query_features, dataset_query.namelist, 0, f'{embsavepath}/{args.qsplit}')
348
+ if not valexist:
349
+ l_values_features = list(np.asarray(values_features.cpu().detach(), dtype=np.float16))
350
+ save_chunk(l_values_features, dataset_values.namelist, 0, f'{embsavepath}/database')
351
+
352
+ print(f'Embeddings saved to: {embsavepath}')
353
+
354
+
355
+ if __name__ == '__main__':
356
+ main()
CSD/metrics/__init__.py ADDED
File without changes
CSD/metrics/metrics.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pathlib
2
+ import sys
3
+
4
+ import numpy as np
5
+
6
+ sys.path.insert(0, str(pathlib.Path(__file__).parent.resolve()))
7
+
8
+
9
+ class Metrics(object):
10
+ def __init__(self):
11
+ self.data = None
12
+
13
+ @staticmethod
14
+ def get_recall(preds, gts, topk=5):
15
+ preds = preds[:, :topk]
16
+ preds -= gts[:, None]
17
+ found = np.where(np.amin(np.absolute(preds), axis=1) == 0)[0]
18
+ return found.shape[0] / gts.shape[0]
19
+
20
+ @staticmethod
21
+ def get_mrr(preds, gts, topk=5):
22
+ preds = preds[:, :topk]
23
+ preds -= gts[:, None]
24
+ rows, cols = np.where(preds == 0)
25
+ _, unique_rows = np.unique(rows, return_index=True)
26
+ valid_cols = cols[unique_rows]
27
+ valid_cols += 1
28
+ return np.mean(1/valid_cols)
29
+
30
+ @staticmethod
31
+ def get_map(preds, gts, topk=5):
32
+ preds = preds[:, :topk]
33
+ preds -= gts[:, None]
34
+ rows, cols = np.where(preds == 0)
35
+ _, unique_rows = np.unique(rows, return_index=True)
36
+ row_cols = np.split(cols, unique_rows)[1:]
37
+ row_cols = [np.hstack([x[0], np.diff(x), topk - x[-1]]) for x in row_cols]
38
+ row_cols = [np.pad(x, (0, topk + 1 - x.shape[0]), 'constant', constant_values=(0, 0)) for x in row_cols]
39
+ precision = np.asarray([np.repeat(np.arange(topk + 1), x) / np.arange(1, topk + 1) for x in row_cols])
40
+ return np.sum(np.mean(precision, axis=1)) / preds.shape[0]
41
+ # numpy increasing array according to bins
42
+
43
+ @staticmethod
44
+ def get_recall_bin(preds, topk=5):
45
+ # preds is a binary matrix of size Q x K
46
+ preds = preds[:, :topk]
47
+ found = np.where(np.amax(preds, axis=1) == True)[0]
48
+ return found.shape[0] / preds.shape[0]
49
+
50
+ @staticmethod
51
+ def get_mrr_bin(preds, topk=5):
52
+ # preds is a binary matrix of size Q x K
53
+ preds = preds[:, :topk]
54
+ rows, cols = np.where(preds)
55
+ _, unique_rows = np.unique(rows, return_index=True)
56
+ valid_cols = cols[unique_rows]
57
+ valid_cols += 1
58
+ return np.mean(1/valid_cols)
59
+
60
+ @staticmethod
61
+ def get_map_bin(preds, topk=5):
62
+ # preds is a binary matrix of size Q x K
63
+ preds = preds[:, :topk]
64
+ rows, cols = np.where(preds)
65
+ _, unique_rows = np.unique(rows, return_index=True)
66
+ row_cols = np.split(cols, unique_rows)[1:]
67
+ row_cols = [np.hstack([x[0], np.diff(x), topk - x[-1]]) for x in row_cols]
68
+ row_cols = [np.pad(x, (0, topk + 1 - x.shape[0]), 'constant', constant_values=(0, 0)) for x in row_cols]
69
+ precision = np.asarray([np.repeat(np.arange(topk + 1), x) / np.arange(1, topk + 1) for x in row_cols])
70
+ return np.sum(np.mean(precision, axis=1)) / preds.shape[0]
71
+
72
+ @staticmethod
73
+ def get_per_query_precision_bin(preds):
74
+ return np.sum(preds, axis=1)/preds.shape[1]
CSD/models/clip/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .clip import *
CSD/models/clip/bpe_simple_vocab_16e6.txt.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:924691ac288e54409236115652ad4aa250f48203de50a9e4722a6ecd48d6804a
3
+ size 1356917
CSD/models/clip/clip.py ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import hashlib
2
+ import os
3
+ import urllib
4
+ import warnings
5
+ from typing import Any, Union, List
6
+ from pkg_resources import packaging
7
+
8
+ import torch
9
+ from PIL import Image
10
+ from torchvision.transforms import Compose, Resize, CenterCrop, ToTensor, Normalize
11
+ from tqdm import tqdm
12
+
13
+ from .model import build_model
14
+ from .simple_tokenizer import SimpleTokenizer as _Tokenizer
15
+
16
+ try:
17
+ from torchvision.transforms import InterpolationMode
18
+ BICUBIC = InterpolationMode.BICUBIC
19
+ except ImportError:
20
+ BICUBIC = Image.BICUBIC
21
+
22
+
23
+ if packaging.version.parse(torch.__version__) < packaging.version.parse("1.7.1"):
24
+ warnings.warn("PyTorch version 1.7.1 or higher is recommended")
25
+
26
+
27
+ __all__ = ["available_models", "load", "tokenize"]
28
+ _tokenizer = _Tokenizer()
29
+
30
+ _MODELS = {
31
+ "RN50": "https://openaipublic.azureedge.net/clip/models/afeb0e10f9e5a86da6080e35cf09123aca3b358a0c3e3b6c78a7b63bc04b6762/RN50.pt",
32
+ "RN101": "https://openaipublic.azureedge.net/clip/models/8fa8567bab74a42d41c5915025a8e4538c3bdbe8804a470a72f30b0d94fab599/RN101.pt",
33
+ "RN50x4": "https://openaipublic.azureedge.net/clip/models/7e526bd135e493cef0776de27d5f42653e6b4c8bf9e0f653bb11773263205fdd/RN50x4.pt",
34
+ "RN50x16": "https://openaipublic.azureedge.net/clip/models/52378b407f34354e150460fe41077663dd5b39c54cd0bfd2b27167a4a06ec9aa/RN50x16.pt",
35
+ "RN50x64": "https://openaipublic.azureedge.net/clip/models/be1cfb55d75a9666199fb2206c106743da0f6468c9d327f3e0d0a543a9919d9c/RN50x64.pt",
36
+ "ViT-B/32": "https://openaipublic.azureedge.net/clip/models/40d365715913c9da98579312b702a82c18be219cc2a73407c4526f58eba950af/ViT-B-32.pt",
37
+ "ViT-B/16": "https://openaipublic.azureedge.net/clip/models/5806e77cd80f8b59890b7e101eabd078d9fb84e6937f9e85e4ecb61988df416f/ViT-B-16.pt",
38
+ "ViT-L/14": "https://openaipublic.azureedge.net/clip/models/b8cca3fd41ae0c99ba7e8951adf17d267cdb84cd88be6f7c2e0eca1737a03836/ViT-L-14.pt",
39
+ "ViT-L/14@336px": "https://openaipublic.azureedge.net/clip/models/3035c92b350959924f9f00213499208652fc7ea050643e8b385c2dac08641f02/ViT-L-14-336px.pt",
40
+ }
41
+
42
+
43
+ def _download(url: str, root: str):
44
+ os.makedirs(root, exist_ok=True)
45
+ filename = os.path.basename(url)
46
+
47
+ expected_sha256 = url.split("/")[-2]
48
+ download_target = os.path.join(root, filename)
49
+
50
+ if os.path.exists(download_target) and not os.path.isfile(download_target):
51
+ raise RuntimeError(f"{download_target} exists and is not a regular file")
52
+
53
+ if os.path.isfile(download_target):
54
+ if hashlib.sha256(open(download_target, "rb").read()).hexdigest() == expected_sha256:
55
+ return download_target
56
+ else:
57
+ warnings.warn(f"{download_target} exists, but the SHA256 checksum does not match; re-downloading the file")
58
+
59
+ with urllib.request.urlopen(url) as source, open(download_target, "wb") as output:
60
+ with tqdm(total=int(source.info().get("Content-Length")), ncols=80, unit='iB', unit_scale=True, unit_divisor=1024) as loop:
61
+ while True:
62
+ buffer = source.read(8192)
63
+ if not buffer:
64
+ break
65
+
66
+ output.write(buffer)
67
+ loop.update(len(buffer))
68
+
69
+ if hashlib.sha256(open(download_target, "rb").read()).hexdigest() != expected_sha256:
70
+ raise RuntimeError("Model has been downloaded but the SHA256 checksum does not not match")
71
+
72
+ return download_target
73
+
74
+
75
+ def _convert_image_to_rgb(image):
76
+ return image.convert("RGB")
77
+
78
+
79
+ def _transform(n_px):
80
+ return Compose([
81
+ Resize(n_px, interpolation=BICUBIC),
82
+ CenterCrop(n_px),
83
+ _convert_image_to_rgb,
84
+ ToTensor(),
85
+ Normalize((0.48145466, 0.4578275, 0.40821073), (0.26862954, 0.26130258, 0.27577711)),
86
+ ])
87
+
88
+
89
+ def available_models() -> List[str]:
90
+ """Returns the names of available CLIP models"""
91
+ return list(_MODELS.keys())
92
+
93
+
94
+ def load(name: str, device: Union[str, torch.device] = "cuda" if torch.cuda.is_available() else "cpu", jit: bool = False, download_root: str = None):
95
+ """Load a CLIP model
96
+
97
+ Parameters
98
+ ----------
99
+ name : str
100
+ A model name listed by `clip.available_models()`, or the path to a model checkpoint containing the state_dict
101
+
102
+ device : Union[str, torch.device]
103
+ The device to put the loaded model
104
+
105
+ jit : bool
106
+ Whether to load the optimized JIT model or more hackable non-JIT model (default).
107
+
108
+ download_root: str
109
+ path to download the model files; by default, it uses "~/.cache/clip"
110
+
111
+ Returns
112
+ -------
113
+ model : torch.nn.Module
114
+ The CLIP model
115
+
116
+ preprocess : Callable[[PIL.Image], torch.Tensor]
117
+ A torchvision transform that converts a PIL image into a tensor that the returned model can take as its input
118
+ """
119
+ if name in _MODELS:
120
+ model_path = _download(_MODELS[name], download_root or os.path.expanduser("~/.cache/clip"))
121
+ elif os.path.isfile(name):
122
+ model_path = name
123
+ else:
124
+ raise RuntimeError(f"Model {name} not found; available models = {available_models()}")
125
+
126
+ with open(model_path, 'rb') as opened_file:
127
+ try:
128
+ # loading JIT archive
129
+ model = torch.jit.load(opened_file, map_location=device if jit else "cpu").eval()
130
+ state_dict = None
131
+ except RuntimeError:
132
+ # loading saved state dict
133
+ if jit:
134
+ warnings.warn(f"File {model_path} is not a JIT archive. Loading as a state dict instead")
135
+ jit = False
136
+ state_dict = torch.load(opened_file, map_location="cpu")
137
+
138
+ if not jit:
139
+ model = build_model(state_dict or model.state_dict()).to(device)
140
+ if str(device) == "cpu":
141
+ model.float()
142
+ return model, _transform(model.visual.input_resolution)
143
+
144
+ # patch the device names
145
+ device_holder = torch.jit.trace(lambda: torch.ones([]).to(torch.device(device)), example_inputs=[])
146
+ device_node = [n for n in device_holder.graph.findAllNodes("prim::Constant") if "Device" in repr(n)][-1]
147
+
148
+ def patch_device(module):
149
+ try:
150
+ graphs = [module.graph] if hasattr(module, "graph") else []
151
+ except RuntimeError:
152
+ graphs = []
153
+
154
+ if hasattr(module, "forward1"):
155
+ graphs.append(module.forward1.graph)
156
+
157
+ for graph in graphs:
158
+ for node in graph.findAllNodes("prim::Constant"):
159
+ if "value" in node.attributeNames() and str(node["value"]).startswith("cuda"):
160
+ node.copyAttributes(device_node)
161
+
162
+ model.apply(patch_device)
163
+ patch_device(model.encode_image)
164
+ patch_device(model.encode_text)
165
+
166
+ # patch dtype to float32 on CPU
167
+ if str(device) == "cpu":
168
+ float_holder = torch.jit.trace(lambda: torch.ones([]).float(), example_inputs=[])
169
+ float_input = list(float_holder.graph.findNode("aten::to").inputs())[1]
170
+ float_node = float_input.node()
171
+
172
+ def patch_float(module):
173
+ try:
174
+ graphs = [module.graph] if hasattr(module, "graph") else []
175
+ except RuntimeError:
176
+ graphs = []
177
+
178
+ if hasattr(module, "forward1"):
179
+ graphs.append(module.forward1.graph)
180
+
181
+ for graph in graphs:
182
+ for node in graph.findAllNodes("aten::to"):
183
+ inputs = list(node.inputs())
184
+ for i in [1, 2]: # dtype can be the second or third argument to aten::to()
185
+ if inputs[i].node()["value"] == 5:
186
+ inputs[i].node().copyAttributes(float_node)
187
+
188
+ model.apply(patch_float)
189
+ patch_float(model.encode_image)
190
+ patch_float(model.encode_text)
191
+
192
+ model.float()
193
+
194
+ return model, _transform(model.input_resolution.item())
195
+
196
+
197
+ def tokenize(texts: Union[str, List[str]], context_length: int = 77, truncate: bool = False) -> Union[torch.IntTensor, torch.LongTensor]:
198
+ """
199
+ Returns the tokenized representation of given input string(s)
200
+
201
+ Parameters
202
+ ----------
203
+ texts : Union[str, List[str]]
204
+ An input string or a list of input strings to tokenize
205
+
206
+ context_length : int
207
+ The context length to use; all CLIP models use 77 as the context length
208
+
209
+ truncate: bool
210
+ Whether to truncate the text in case its encoding is longer than the context length
211
+
212
+ Returns
213
+ -------
214
+ A two-dimensional tensor containing the resulting tokens, shape = [number of input strings, context_length].
215
+ We return LongTensor when torch version is <1.8.0, since older index_select requires indices to be long.
216
+ """
217
+ if isinstance(texts, str):
218
+ texts = [texts]
219
+
220
+ sot_token = _tokenizer.encoder["<|startoftext|>"]
221
+ eot_token = _tokenizer.encoder["<|endoftext|>"]
222
+ all_tokens = [[sot_token] + _tokenizer.encode(text) + [eot_token] for text in texts]
223
+ if packaging.version.parse(torch.__version__) < packaging.version.parse("1.8.0"):
224
+ result = torch.zeros(len(all_tokens), context_length, dtype=torch.long)
225
+ else:
226
+ result = torch.zeros(len(all_tokens), context_length, dtype=torch.int)
227
+
228
+ for i, tokens in enumerate(all_tokens):
229
+ if len(tokens) > context_length:
230
+ if truncate:
231
+ tokens = tokens[:context_length]
232
+ tokens[-1] = eot_token
233
+ else:
234
+ raise RuntimeError(f"Input {texts[i]} is too long for context length {context_length}")
235
+ result[i, :len(tokens)] = torch.tensor(tokens)
236
+
237
+ return result
CSD/models/clip/model.py ADDED
@@ -0,0 +1,486 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import OrderedDict
2
+ from typing import Tuple, Union
3
+
4
+ import numpy as np
5
+ import torch
6
+ import torch.nn.functional as F
7
+ from torch import nn
8
+
9
+
10
+ class Bottleneck(nn.Module):
11
+ expansion = 4
12
+
13
+ def __init__(self, inplanes, planes, stride=1):
14
+ super().__init__()
15
+
16
+ # all conv layers have stride 1. an avgpool is performed after the second convolution when stride > 1
17
+ self.conv1 = nn.Conv2d(inplanes, planes, 1, bias=False)
18
+ self.bn1 = nn.BatchNorm2d(planes)
19
+ self.relu1 = nn.ReLU(inplace=True)
20
+
21
+ self.conv2 = nn.Conv2d(planes, planes, 3, padding=1, bias=False)
22
+ self.bn2 = nn.BatchNorm2d(planes)
23
+ self.relu2 = nn.ReLU(inplace=True)
24
+
25
+ self.avgpool = nn.AvgPool2d(stride) if stride > 1 else nn.Identity()
26
+
27
+ self.conv3 = nn.Conv2d(planes, planes * self.expansion, 1, bias=False)
28
+ self.bn3 = nn.BatchNorm2d(planes * self.expansion)
29
+ self.relu3 = nn.ReLU(inplace=True)
30
+
31
+ self.downsample = None
32
+ self.stride = stride
33
+
34
+ if stride > 1 or inplanes != planes * Bottleneck.expansion:
35
+ # downsampling layer is prepended with an avgpool, and the subsequent convolution has stride 1
36
+ self.downsample = nn.Sequential(OrderedDict([
37
+ ("-1", nn.AvgPool2d(stride)),
38
+ ("0", nn.Conv2d(inplanes, planes * self.expansion, 1, stride=1, bias=False)),
39
+ ("1", nn.BatchNorm2d(planes * self.expansion))
40
+ ]))
41
+
42
+ def forward(self, x: torch.Tensor):
43
+ identity = x
44
+
45
+ out = self.relu1(self.bn1(self.conv1(x)))
46
+ out = self.relu2(self.bn2(self.conv2(out)))
47
+ out = self.avgpool(out)
48
+ out = self.bn3(self.conv3(out))
49
+
50
+ if self.downsample is not None:
51
+ identity = self.downsample(x)
52
+
53
+ out += identity
54
+ out = self.relu3(out)
55
+ return out
56
+
57
+
58
+ class AttentionPool2d(nn.Module):
59
+ def __init__(self, spacial_dim: int, embed_dim: int, num_heads: int, output_dim: int = None):
60
+ super().__init__()
61
+ self.positional_embedding = nn.Parameter(torch.randn(spacial_dim ** 2 + 1, embed_dim) / embed_dim ** 0.5)
62
+ self.k_proj = nn.Linear(embed_dim, embed_dim)
63
+ self.q_proj = nn.Linear(embed_dim, embed_dim)
64
+ self.v_proj = nn.Linear(embed_dim, embed_dim)
65
+ self.c_proj = nn.Linear(embed_dim, output_dim or embed_dim)
66
+ self.num_heads = num_heads
67
+
68
+ def forward(self, x):
69
+ x = x.flatten(start_dim=2).permute(2, 0, 1) # NCHW -> (HW)NC
70
+ x = torch.cat([x.mean(dim=0, keepdim=True), x], dim=0) # (HW+1)NC
71
+ x = x + self.positional_embedding[:, None, :].to(x.dtype) # (HW+1)NC
72
+ x, _ = F.multi_head_attention_forward(
73
+ query=x[:1], key=x, value=x,
74
+ embed_dim_to_check=x.shape[-1],
75
+ num_heads=self.num_heads,
76
+ q_proj_weight=self.q_proj.weight,
77
+ k_proj_weight=self.k_proj.weight,
78
+ v_proj_weight=self.v_proj.weight,
79
+ in_proj_weight=None,
80
+ in_proj_bias=torch.cat([self.q_proj.bias, self.k_proj.bias, self.v_proj.bias]),
81
+ bias_k=None,
82
+ bias_v=None,
83
+ add_zero_attn=False,
84
+ dropout_p=0,
85
+ out_proj_weight=self.c_proj.weight,
86
+ out_proj_bias=self.c_proj.bias,
87
+ use_separate_proj_weight=True,
88
+ training=self.training,
89
+ need_weights=False
90
+ )
91
+ return x.squeeze(0)
92
+
93
+
94
+ class ModifiedResNet(nn.Module):
95
+ """
96
+ A ResNet class that is similar to torchvision's but contains the following changes:
97
+ - There are now 3 "stem" convolutions as opposed to 1, with an average pool instead of a max pool.
98
+ - Performs anti-aliasing strided convolutions, where an avgpool is prepended to convolutions with stride > 1
99
+ - The final pooling layer is a QKV attention instead of an average pool
100
+ """
101
+
102
+ def __init__(self, layers, output_dim, heads, input_resolution=224, width=64):
103
+ super().__init__()
104
+ self.output_dim = output_dim
105
+ self.input_resolution = input_resolution
106
+
107
+ # the 3-layer stem
108
+ self.conv1 = nn.Conv2d(3, width // 2, kernel_size=3, stride=2, padding=1, bias=False)
109
+ self.bn1 = nn.BatchNorm2d(width // 2)
110
+ self.relu1 = nn.ReLU(inplace=True)
111
+ self.conv2 = nn.Conv2d(width // 2, width // 2, kernel_size=3, padding=1, bias=False)
112
+ self.bn2 = nn.BatchNorm2d(width // 2)
113
+ self.relu2 = nn.ReLU(inplace=True)
114
+ self.conv3 = nn.Conv2d(width // 2, width, kernel_size=3, padding=1, bias=False)
115
+ self.bn3 = nn.BatchNorm2d(width)
116
+ self.relu3 = nn.ReLU(inplace=True)
117
+ self.avgpool = nn.AvgPool2d(2)
118
+
119
+ # residual layers
120
+ self._inplanes = width # this is a *mutable* variable used during construction
121
+ self.layer1 = self._make_layer(width, layers[0])
122
+ self.layer2 = self._make_layer(width * 2, layers[1], stride=2)
123
+ self.layer3 = self._make_layer(width * 4, layers[2], stride=2)
124
+ self.layer4 = self._make_layer(width * 8, layers[3], stride=2)
125
+
126
+ embed_dim = width * 32 # the ResNet feature dimension
127
+ self.attnpool = AttentionPool2d(input_resolution // 32, embed_dim, heads, output_dim)
128
+
129
+ def _make_layer(self, planes, blocks, stride=1):
130
+ layers = [Bottleneck(self._inplanes, planes, stride)]
131
+
132
+ self._inplanes = planes * Bottleneck.expansion
133
+ for _ in range(1, blocks):
134
+ layers.append(Bottleneck(self._inplanes, planes))
135
+
136
+ return nn.Sequential(*layers)
137
+
138
+ def forward(self, x):
139
+ def stem(x):
140
+ x = self.relu1(self.bn1(self.conv1(x)))
141
+ x = self.relu2(self.bn2(self.conv2(x)))
142
+ x = self.relu3(self.bn3(self.conv3(x)))
143
+ x = self.avgpool(x)
144
+ return x
145
+
146
+ x = x.type(self.conv1.weight.dtype)
147
+ x = stem(x)
148
+ x = self.layer1(x)
149
+ x = self.layer2(x)
150
+ x = self.layer3(x)
151
+ x = self.layer4(x)
152
+ x = self.attnpool(x)
153
+
154
+ return x
155
+ def get_intermediate_layers(self, x):
156
+ def stem(x):
157
+ x = self.relu1(self.bn1(self.conv1(x)))
158
+ x = self.relu2(self.bn2(self.conv2(x)))
159
+ x = self.relu3(self.bn3(self.conv3(x)))
160
+ x = self.avgpool(x)
161
+ return x
162
+
163
+ x = x.type(self.conv1.weight.dtype)
164
+ output = []
165
+ x = stem(x)
166
+ output.append(x)
167
+ x = self.layer1(x)
168
+ output.append(x)
169
+ x = self.layer2(x)
170
+ output.append(x)
171
+ x = self.layer3(x)
172
+ output.append(x)
173
+ x = self.layer4(x)
174
+ output.append(x)
175
+ x = self.attnpool(x)
176
+ output.append(x)
177
+ return output
178
+
179
+ class LayerNorm(nn.LayerNorm):
180
+ """Subclass torch's LayerNorm to handle fp16."""
181
+
182
+ def forward(self, x: torch.Tensor):
183
+ orig_type = x.dtype
184
+ ret = super().forward(x.type(torch.float32))
185
+ return ret.type(orig_type)
186
+
187
+
188
+ class QuickGELU(nn.Module):
189
+ def forward(self, x: torch.Tensor):
190
+ return x * torch.sigmoid(1.702 * x)
191
+
192
+
193
+ class ResidualAttentionBlock(nn.Module):
194
+ def __init__(self, d_model: int, n_head: int, attn_mask: torch.Tensor = None):
195
+ super().__init__()
196
+
197
+ self.attn = nn.MultiheadAttention(d_model, n_head)
198
+ self.ln_1 = LayerNorm(d_model)
199
+ self.mlp = nn.Sequential(OrderedDict([
200
+ ("c_fc", nn.Linear(d_model, d_model * 4)),
201
+ ("gelu", QuickGELU()),
202
+ ("c_proj", nn.Linear(d_model * 4, d_model))
203
+ ]))
204
+ self.ln_2 = LayerNorm(d_model)
205
+ self.attn_mask = attn_mask
206
+
207
+ def attention(self, x: torch.Tensor):
208
+ self.attn_mask = self.attn_mask.to(dtype=x.dtype, device=x.device) if self.attn_mask is not None else None
209
+ return self.attn(x, x, x, need_weights=False, attn_mask=self.attn_mask)[0]
210
+
211
+ def forward(self, x: torch.Tensor):
212
+ x = x + self.attention(self.ln_1(x))
213
+ x = x + self.mlp(self.ln_2(x))
214
+ return x
215
+
216
+
217
+ class Transformer(nn.Module):
218
+ def __init__(self, width: int, layers: int, heads: int, attn_mask: torch.Tensor = None):
219
+ super().__init__()
220
+ self.width = width
221
+ self.layers = layers
222
+ self.resblocks = nn.Sequential(*[ResidualAttentionBlock(width, heads, attn_mask) for _ in range(layers)])
223
+
224
+ def forward(self, x: torch.Tensor):
225
+ return self.resblocks(x)
226
+
227
+ def get_activations(self, x: torch.Tensor):
228
+ output = []
229
+
230
+ for i in range(self.layers):
231
+ # import ipdb; ipdb.set_trace()
232
+ x = self.resblocks[i](x)
233
+ output.append(x.permute(1, 0, 2))
234
+ return output
235
+
236
+
237
+
238
+ class VisionTransformer(nn.Module):
239
+ def __init__(self, input_resolution: int, patch_size: int, width: int, layers: int, heads: int, output_dim: int):
240
+ super().__init__()
241
+ self.input_resolution = input_resolution
242
+ self.output_dim = output_dim
243
+ self.conv1 = nn.Conv2d(in_channels=3, out_channels=width, kernel_size=patch_size, stride=patch_size, bias=False)
244
+
245
+ scale = width ** -0.5
246
+ self.class_embedding = nn.Parameter(scale * torch.randn(width))
247
+ self.positional_embedding = nn.Parameter(scale * torch.randn((input_resolution // patch_size) ** 2 + 1, width))
248
+ self.ln_pre = LayerNorm(width)
249
+
250
+ self.transformer = Transformer(width, layers, heads)
251
+
252
+ self.ln_post = LayerNorm(width)
253
+ self.proj = nn.Parameter(scale * torch.randn(width, output_dim))
254
+
255
+ def forward(self, x: torch.Tensor):
256
+ x = self.conv1(x) # shape = [*, width, grid, grid]
257
+ x = x.reshape(x.shape[0], x.shape[1], -1) # shape = [*, width, grid ** 2]
258
+ x = x.permute(0, 2, 1) # shape = [*, grid ** 2, width]
259
+ x = torch.cat([self.class_embedding.to(x.dtype) + torch.zeros(x.shape[0], 1, x.shape[-1], dtype=x.dtype, device=x.device), x], dim=1) # shape = [*, grid ** 2 + 1, width]
260
+ x = x + self.positional_embedding.to(x.dtype)
261
+ x = self.ln_pre(x)
262
+
263
+ x = x.permute(1, 0, 2) # NLD -> LND
264
+ x = self.transformer(x)
265
+ x = x.permute(1, 0, 2) # LND -> NLD
266
+
267
+ x = self.ln_post(x[:, 0, :])
268
+
269
+ if self.proj is not None:
270
+ x = x @ self.proj
271
+
272
+ return x
273
+
274
+ def get_intermediate_layers(self, x: torch.Tensor):
275
+ x = self.conv1(x) # shape = [*, width, grid, grid]
276
+ x = x.reshape(x.shape[0], x.shape[1], -1) # shape = [*, width, grid ** 2]
277
+ x = x.permute(0, 2, 1) # shape = [*, grid ** 2, width]
278
+ x = torch.cat([self.class_embedding.to(x.dtype) + torch.zeros(x.shape[0], 1, x.shape[-1], dtype=x.dtype, device=x.device), x], dim=1) # shape = [*, grid ** 2 + 1, width]
279
+ x = x + self.positional_embedding.to(x.dtype)
280
+ x = self.ln_pre(x)
281
+
282
+ x = x.permute(1, 0, 2) # NLD -> LND
283
+ # x = self.transformer(x)
284
+ op = self.transformer.get_activations(x)
285
+ # x = x.permute(1, 0, 2) # LND -> NLD
286
+
287
+ # x = self.ln_post(x[:, 0, :])
288
+
289
+ # if self.proj is not None:
290
+ # x = x @ self.proj
291
+ return op
292
+
293
+ class CLIP(nn.Module):
294
+ def __init__(self,
295
+ embed_dim: int,
296
+ # vision
297
+ image_resolution: int,
298
+ vision_layers: Union[Tuple[int, int, int, int], int],
299
+ vision_width: int,
300
+ vision_patch_size: int,
301
+ # text
302
+ context_length: int,
303
+ vocab_size: int,
304
+ transformer_width: int,
305
+ transformer_heads: int,
306
+ transformer_layers: int
307
+ ):
308
+ super().__init__()
309
+
310
+ self.context_length = context_length
311
+
312
+ if isinstance(vision_layers, (tuple, list)):
313
+ vision_heads = vision_width * 32 // 64
314
+ self.visual = ModifiedResNet(
315
+ layers=vision_layers,
316
+ output_dim=embed_dim,
317
+ heads=vision_heads,
318
+ input_resolution=image_resolution,
319
+ width=vision_width
320
+ )
321
+ else:
322
+ vision_heads = vision_width // 64
323
+ self.visual = VisionTransformer(
324
+ input_resolution=image_resolution,
325
+ patch_size=vision_patch_size,
326
+ width=vision_width,
327
+ layers=vision_layers,
328
+ heads=vision_heads,
329
+ output_dim=embed_dim
330
+ )
331
+
332
+ self.transformer = Transformer(
333
+ width=transformer_width,
334
+ layers=transformer_layers,
335
+ heads=transformer_heads,
336
+ attn_mask=self.build_attention_mask()
337
+ )
338
+
339
+ self.vocab_size = vocab_size
340
+ self.token_embedding = nn.Embedding(vocab_size, transformer_width)
341
+ self.positional_embedding = nn.Parameter(torch.empty(self.context_length, transformer_width))
342
+ self.ln_final = LayerNorm(transformer_width)
343
+
344
+ self.text_projection = nn.Parameter(torch.empty(transformer_width, embed_dim))
345
+ self.logit_scale = nn.Parameter(torch.ones([]) * np.log(1 / 0.07))
346
+
347
+ self.initialize_parameters()
348
+
349
+ def initialize_parameters(self):
350
+ nn.init.normal_(self.token_embedding.weight, std=0.02)
351
+ nn.init.normal_(self.positional_embedding, std=0.01)
352
+
353
+ if isinstance(self.visual, ModifiedResNet):
354
+ if self.visual.attnpool is not None:
355
+ std = self.visual.attnpool.c_proj.in_features ** -0.5
356
+ nn.init.normal_(self.visual.attnpool.q_proj.weight, std=std)
357
+ nn.init.normal_(self.visual.attnpool.k_proj.weight, std=std)
358
+ nn.init.normal_(self.visual.attnpool.v_proj.weight, std=std)
359
+ nn.init.normal_(self.visual.attnpool.c_proj.weight, std=std)
360
+
361
+ for resnet_block in [self.visual.layer1, self.visual.layer2, self.visual.layer3, self.visual.layer4]:
362
+ for name, param in resnet_block.named_parameters():
363
+ if name.endswith("bn3.weight"):
364
+ nn.init.zeros_(param)
365
+
366
+ proj_std = (self.transformer.width ** -0.5) * ((2 * self.transformer.layers) ** -0.5)
367
+ attn_std = self.transformer.width ** -0.5
368
+ fc_std = (2 * self.transformer.width) ** -0.5
369
+ for block in self.transformer.resblocks:
370
+ nn.init.normal_(block.attn.in_proj_weight, std=attn_std)
371
+ nn.init.normal_(block.attn.out_proj.weight, std=proj_std)
372
+ nn.init.normal_(block.mlp.c_fc.weight, std=fc_std)
373
+ nn.init.normal_(block.mlp.c_proj.weight, std=proj_std)
374
+
375
+ if self.text_projection is not None:
376
+ nn.init.normal_(self.text_projection, std=self.transformer.width ** -0.5)
377
+
378
+ def build_attention_mask(self):
379
+ # lazily create causal attention mask, with full attention between the vision tokens
380
+ # pytorch uses additive attention mask; fill with -inf
381
+ mask = torch.empty(self.context_length, self.context_length)
382
+ mask.fill_(float("-inf"))
383
+ mask.triu_(1) # zero out the lower diagonal
384
+ return mask
385
+
386
+ @property
387
+ def dtype(self):
388
+ return self.visual.conv1.weight.dtype
389
+
390
+ def encode_image(self, image):
391
+ return self.visual(image.type(self.dtype))
392
+
393
+ def encode_text(self, text):
394
+ x = self.token_embedding(text).type(self.dtype) # [batch_size, n_ctx, d_model]
395
+
396
+ x = x + self.positional_embedding.type(self.dtype)
397
+ x = x.permute(1, 0, 2) # NLD -> LND
398
+ x = self.transformer(x)
399
+ x = x.permute(1, 0, 2) # LND -> NLD
400
+ x = self.ln_final(x).type(self.dtype)
401
+
402
+ # x.shape = [batch_size, n_ctx, transformer.width]
403
+ # take features from the eot embedding (eot_token is the highest number in each sequence)
404
+ x = x[torch.arange(x.shape[0]), text.argmax(dim=-1)] @ self.text_projection
405
+
406
+ return x
407
+
408
+ def forward(self, image, text):
409
+ image_features = self.encode_image(image)
410
+ text_features = self.encode_text(text)
411
+
412
+ # normalized features
413
+ image_features = image_features / image_features.norm(dim=1, keepdim=True)
414
+ text_features = text_features / text_features.norm(dim=1, keepdim=True)
415
+
416
+ # cosine similarity as logits
417
+ logit_scale = self.logit_scale.exp()
418
+ logits_per_image = logit_scale * image_features @ text_features.t()
419
+ logits_per_text = logits_per_image.t()
420
+
421
+ # shape = [global_batch_size, global_batch_size]
422
+ return logits_per_image, logits_per_text
423
+
424
+
425
+ def convert_weights(model: nn.Module):
426
+ """Convert applicable model parameters to fp16"""
427
+
428
+ def _convert_weights_to_fp16(l):
429
+ if isinstance(l, (nn.Conv1d, nn.Conv2d, nn.Linear)):
430
+ l.weight.data = l.weight.data.half()
431
+ if l.bias is not None:
432
+ l.bias.data = l.bias.data.half()
433
+
434
+ if isinstance(l, nn.MultiheadAttention):
435
+ for attr in [*[f"{s}_proj_weight" for s in ["in", "q", "k", "v"]], "in_proj_bias", "bias_k", "bias_v"]:
436
+ tensor = getattr(l, attr)
437
+ if tensor is not None:
438
+ tensor.data = tensor.data.half()
439
+
440
+ for name in ["text_projection", "proj"]:
441
+ if hasattr(l, name):
442
+ attr = getattr(l, name)
443
+ if attr is not None:
444
+ attr.data = attr.data.half()
445
+
446
+ model.apply(_convert_weights_to_fp16)
447
+
448
+
449
+ def build_model(state_dict: dict):
450
+ vit = "visual.proj" in state_dict
451
+
452
+ if vit:
453
+ vision_width = state_dict["visual.conv1.weight"].shape[0]
454
+ vision_layers = len([k for k in state_dict.keys() if k.startswith("visual.") and k.endswith(".attn.in_proj_weight")])
455
+ vision_patch_size = state_dict["visual.conv1.weight"].shape[-1]
456
+ grid_size = round((state_dict["visual.positional_embedding"].shape[0] - 1) ** 0.5)
457
+ image_resolution = vision_patch_size * grid_size
458
+ else:
459
+ counts: list = [len(set(k.split(".")[2] for k in state_dict if k.startswith(f"visual.layer{b}"))) for b in [1, 2, 3, 4]]
460
+ vision_layers = tuple(counts)
461
+ vision_width = state_dict["visual.layer1.0.conv1.weight"].shape[0]
462
+ output_width = round((state_dict["visual.attnpool.positional_embedding"].shape[0] - 1) ** 0.5)
463
+ vision_patch_size = None
464
+ assert output_width ** 2 + 1 == state_dict["visual.attnpool.positional_embedding"].shape[0]
465
+ image_resolution = output_width * 32
466
+
467
+ embed_dim = state_dict["text_projection"].shape[1]
468
+ context_length = state_dict["positional_embedding"].shape[0]
469
+ vocab_size = state_dict["token_embedding.weight"].shape[0]
470
+ transformer_width = state_dict["ln_final.weight"].shape[0]
471
+ transformer_heads = transformer_width // 64
472
+ transformer_layers = len(set(k.split(".")[2] for k in state_dict if k.startswith("transformer.resblocks")))
473
+
474
+ model = CLIP(
475
+ embed_dim,
476
+ image_resolution, vision_layers, vision_width, vision_patch_size,
477
+ context_length, vocab_size, transformer_width, transformer_heads, transformer_layers
478
+ )
479
+
480
+ for key in ["input_resolution", "context_length", "vocab_size"]:
481
+ if key in state_dict:
482
+ del state_dict[key]
483
+
484
+ convert_weights(model)
485
+ model.load_state_dict(state_dict)
486
+ return model.eval()
CSD/models/clip/simple_tokenizer.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gzip
2
+ import html
3
+ import os
4
+ from functools import lru_cache
5
+
6
+ import ftfy
7
+ import regex as re
8
+
9
+
10
+ @lru_cache()
11
+ def default_bpe():
12
+ return os.path.join(os.path.dirname(os.path.abspath(__file__)), "bpe_simple_vocab_16e6.txt.gz")
13
+
14
+
15
+ @lru_cache()
16
+ def bytes_to_unicode():
17
+ """
18
+ Returns list of utf-8 byte and a corresponding list of unicode strings.
19
+ The reversible bpe codes work on unicode strings.
20
+ This means you need a large # of unicode characters in your vocab if you want to avoid UNKs.
21
+ When you're at something like a 10B token dataset you end up needing around 5K for decent coverage.
22
+ This is a signficant percentage of your normal, say, 32K bpe vocab.
23
+ To avoid that, we want lookup tables between utf-8 bytes and unicode strings.
24
+ And avoids mapping to whitespace/control characters the bpe code barfs on.
25
+ """
26
+ bs = list(range(ord("!"), ord("~")+1))+list(range(ord("¡"), ord("¬")+1))+list(range(ord("®"), ord("ÿ")+1))
27
+ cs = bs[:]
28
+ n = 0
29
+ for b in range(2**8):
30
+ if b not in bs:
31
+ bs.append(b)
32
+ cs.append(2**8+n)
33
+ n += 1
34
+ cs = [chr(n) for n in cs]
35
+ return dict(zip(bs, cs))
36
+
37
+
38
+ def get_pairs(word):
39
+ """Return set of symbol pairs in a word.
40
+ Word is represented as tuple of symbols (symbols being variable-length strings).
41
+ """
42
+ pairs = set()
43
+ prev_char = word[0]
44
+ for char in word[1:]:
45
+ pairs.add((prev_char, char))
46
+ prev_char = char
47
+ return pairs
48
+
49
+
50
+ def basic_clean(text):
51
+ text = ftfy.fix_text(text)
52
+ text = html.unescape(html.unescape(text))
53
+ return text.strip()
54
+
55
+
56
+ def whitespace_clean(text):
57
+ text = re.sub(r'\s+', ' ', text)
58
+ text = text.strip()
59
+ return text
60
+
61
+
62
+ class SimpleTokenizer(object):
63
+ def __init__(self, bpe_path: str = default_bpe()):
64
+ self.byte_encoder = bytes_to_unicode()
65
+ self.byte_decoder = {v: k for k, v in self.byte_encoder.items()}
66
+ merges = gzip.open(bpe_path).read().decode("utf-8").split('\n')
67
+ merges = merges[1:49152-256-2+1]
68
+ merges = [tuple(merge.split()) for merge in merges]
69
+ vocab = list(bytes_to_unicode().values())
70
+ vocab = vocab + [v+'</w>' for v in vocab]
71
+ for merge in merges:
72
+ vocab.append(''.join(merge))
73
+ vocab.extend(['<|startoftext|>', '<|endoftext|>'])
74
+ self.encoder = dict(zip(vocab, range(len(vocab))))
75
+ self.decoder = {v: k for k, v in self.encoder.items()}
76
+ self.bpe_ranks = dict(zip(merges, range(len(merges))))
77
+ self.cache = {'<|startoftext|>': '<|startoftext|>', '<|endoftext|>': '<|endoftext|>'}
78
+ self.pat = re.compile(r"""<\|startoftext\|>|<\|endoftext\|>|'s|'t|'re|'ve|'m|'ll|'d|[\p{L}]+|[\p{N}]|[^\s\p{L}\p{N}]+""", re.IGNORECASE)
79
+
80
+ def bpe(self, token):
81
+ if token in self.cache:
82
+ return self.cache[token]
83
+ word = tuple(token[:-1]) + ( token[-1] + '</w>',)
84
+ pairs = get_pairs(word)
85
+
86
+ if not pairs:
87
+ return token+'</w>'
88
+
89
+ while True:
90
+ bigram = min(pairs, key = lambda pair: self.bpe_ranks.get(pair, float('inf')))
91
+ if bigram not in self.bpe_ranks:
92
+ break
93
+ first, second = bigram
94
+ new_word = []
95
+ i = 0
96
+ while i < len(word):
97
+ try:
98
+ j = word.index(first, i)
99
+ new_word.extend(word[i:j])
100
+ i = j
101
+ except:
102
+ new_word.extend(word[i:])
103
+ break
104
+
105
+ if word[i] == first and i < len(word)-1 and word[i+1] == second:
106
+ new_word.append(first+second)
107
+ i += 2
108
+ else:
109
+ new_word.append(word[i])
110
+ i += 1
111
+ new_word = tuple(new_word)
112
+ word = new_word
113
+ if len(word) == 1:
114
+ break
115
+ else:
116
+ pairs = get_pairs(word)
117
+ word = ' '.join(word)
118
+ self.cache[token] = word
119
+ return word
120
+
121
+ def encode(self, text):
122
+ bpe_tokens = []
123
+ text = whitespace_clean(basic_clean(text)).lower()
124
+ for token in re.findall(self.pat, text):
125
+ token = ''.join(self.byte_encoder[b] for b in token.encode('utf-8'))
126
+ bpe_tokens.extend(self.encoder[bpe_token] for bpe_token in self.bpe(token).split(' '))
127
+ return bpe_tokens
128
+
129
+ def decode(self, tokens):
130
+ text = ''.join([self.decoder[token] for token in tokens])
131
+ text = bytearray([self.byte_decoder[c] for c in text]).decode('utf-8', errors="replace").replace('</w>', ' ')
132
+ return text
CSD/models/dino_vits.py ADDED
@@ -0,0 +1,485 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
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
+ Copied from dino transformers and added the global pool layer
16
+ """
17
+ import math
18
+ from functools import partial
19
+ import warnings
20
+
21
+ import torch
22
+ import torch.nn as nn
23
+
24
+
25
+ def _no_grad_trunc_normal_(tensor, mean, std, a, b):
26
+ # Cut & paste from PyTorch official master until it's in a few official releases - RW
27
+ # Method based on https://people.sc.fsu.edu/~jburkardt/presentations/truncated_normal.pdf
28
+ def norm_cdf(x):
29
+ # Computes standard normal cumulative distribution function
30
+ return (1. + math.erf(x / math.sqrt(2.))) / 2.
31
+
32
+ if (mean < a - 2 * std) or (mean > b + 2 * std):
33
+ warnings.warn("mean is more than 2 std from [a, b] in nn.init.trunc_normal_. "
34
+ "The distribution of values may be incorrect.",
35
+ stacklevel=2)
36
+
37
+ with torch.no_grad():
38
+ # Values are generated by using a truncated uniform distribution and
39
+ # then using the inverse CDF for the normal distribution.
40
+ # Get upper and lower cdf values
41
+ l = norm_cdf((a - mean) / std)
42
+ u = norm_cdf((b - mean) / std)
43
+
44
+ # Uniformly fill tensor with values from [l, u], then translate to
45
+ # [2l-1, 2u-1].
46
+ tensor.uniform_(2 * l - 1, 2 * u - 1)
47
+
48
+ # Use inverse cdf transform for normal distribution to get truncated
49
+ # standard normal
50
+ tensor.erfinv_()
51
+
52
+ # Transform to proper mean, std
53
+ tensor.mul_(std * math.sqrt(2.))
54
+ tensor.add_(mean)
55
+
56
+ # Clamp to ensure it's in the proper range
57
+ tensor.clamp_(min=a, max=b)
58
+ return tensor
59
+
60
+
61
+ def trunc_normal_(tensor, mean=0., std=1., a=-2., b=2.):
62
+ # type: (Tensor, float, float, float, float) -> Tensor
63
+ return _no_grad_trunc_normal_(tensor, mean, std, a, b)
64
+
65
+
66
+ def drop_path(x, drop_prob: float = 0., training: bool = False):
67
+ if drop_prob == 0. or not training:
68
+ return x
69
+ keep_prob = 1 - drop_prob
70
+ shape = (x.shape[0],) + (1,) * (x.ndim - 1) # work with diff dim tensors, not just 2D ConvNets
71
+ random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device)
72
+ random_tensor.floor_() # binarize
73
+ output = x.div(keep_prob) * random_tensor
74
+ return output
75
+
76
+
77
+ class DropPath(nn.Module):
78
+ """Drop paths (Stochastic Depth) per sample (when applied in main path of residual blocks).
79
+ """
80
+ def __init__(self, drop_prob=None):
81
+ super(DropPath, self).__init__()
82
+ self.drop_prob = drop_prob
83
+
84
+ def forward(self, x):
85
+ return drop_path(x, self.drop_prob, self.training)
86
+
87
+
88
+ class Mlp(nn.Module):
89
+ def __init__(self, in_features, hidden_features=None, out_features=None, act_layer=nn.GELU, drop=0.):
90
+ super().__init__()
91
+ out_features = out_features or in_features
92
+ hidden_features = hidden_features or in_features
93
+ self.fc1 = nn.Linear(in_features, hidden_features)
94
+ self.act = act_layer()
95
+ self.fc2 = nn.Linear(hidden_features, out_features)
96
+ self.drop = nn.Dropout(drop)
97
+
98
+ def forward(self, x):
99
+ x = self.fc1(x)
100
+ x = self.act(x)
101
+ x = self.drop(x)
102
+ x = self.fc2(x)
103
+ x = self.drop(x)
104
+ return x
105
+
106
+
107
+ class Attention(nn.Module):
108
+ def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):
109
+ super().__init__()
110
+ self.num_heads = num_heads
111
+ head_dim = dim // num_heads
112
+ self.scale = qk_scale or head_dim ** -0.5
113
+
114
+ self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
115
+ self.attn_drop = nn.Dropout(attn_drop)
116
+ self.proj = nn.Linear(dim, dim)
117
+ self.proj_drop = nn.Dropout(proj_drop)
118
+
119
+ def forward(self, x):
120
+ B, N, C = x.shape
121
+ qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
122
+ q, k, v = qkv[0], qkv[1], qkv[2]
123
+
124
+ attn = (q @ k.transpose(-2, -1)) * self.scale
125
+ attn = attn.softmax(dim=-1)
126
+ attn = self.attn_drop(attn)
127
+
128
+ x = (attn @ v).transpose(1, 2).reshape(B, N, C)
129
+ x = self.proj(x)
130
+ x = self.proj_drop(x)
131
+ return x, attn
132
+
133
+
134
+ class Block(nn.Module):
135
+ def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,
136
+ drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm):
137
+ super().__init__()
138
+ self.norm1 = norm_layer(dim)
139
+ self.attn = Attention(
140
+ dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop)
141
+ self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
142
+ self.norm2 = norm_layer(dim)
143
+ mlp_hidden_dim = int(dim * mlp_ratio)
144
+ self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)
145
+
146
+ def forward(self, x, return_attention=False):
147
+ y, attn = self.attn(self.norm1(x))
148
+ if return_attention:
149
+ return attn
150
+ x = x + self.drop_path(y)
151
+ x = x + self.drop_path(self.mlp(self.norm2(x)))
152
+ return x
153
+
154
+
155
+ class PatchEmbed(nn.Module):
156
+ """ Image to Patch Embedding
157
+ """
158
+ def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768):
159
+ super().__init__()
160
+ num_patches = (img_size // patch_size) * (img_size // patch_size)
161
+ self.img_size = img_size
162
+ self.patch_size = patch_size
163
+ self.num_patches = num_patches
164
+
165
+ self.proj = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size)
166
+
167
+ def forward(self, x):
168
+ B, C, H, W = x.shape
169
+ x = self.proj(x).flatten(2).transpose(1, 2)
170
+ return x
171
+
172
+
173
+ class VisionTransformer(nn.Module):
174
+ """ Vision Transformer """
175
+ def __init__(self, img_size=[224], patch_size=16, in_chans=3, num_classes=0, embed_dim=768, depth=12,
176
+ num_heads=12, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop_rate=0., attn_drop_rate=0.,
177
+ drop_path_rate=0., norm_layer=nn.LayerNorm, global_pool='token',**kwargs):
178
+ super().__init__()
179
+ self.num_features = self.embed_dim = embed_dim
180
+
181
+ self.patch_embed = PatchEmbed(
182
+ img_size=img_size[0], patch_size=patch_size, in_chans=in_chans, embed_dim=embed_dim)
183
+ num_patches = self.patch_embed.num_patches
184
+
185
+ self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))
186
+ self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim))
187
+ self.pos_drop = nn.Dropout(p=drop_rate)
188
+
189
+ dpr = [x.item() for x in torch.linspace(0, drop_path_rate, depth)] # stochastic depth decay rule
190
+ self.blocks = nn.ModuleList([
191
+ Block(
192
+ dim=embed_dim, num_heads=num_heads, mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, qk_scale=qk_scale,
193
+ drop=drop_rate, attn_drop=attn_drop_rate, drop_path=dpr[i], norm_layer=norm_layer)
194
+ for i in range(depth)])
195
+ self.norm = norm_layer(embed_dim)
196
+
197
+ # Classifier head
198
+ self.head = nn.Linear(embed_dim, num_classes) if num_classes > 0 else nn.Identity()
199
+
200
+ trunc_normal_(self.pos_embed, std=.02)
201
+ trunc_normal_(self.cls_token, std=.02)
202
+ self.apply(self._init_weights)
203
+
204
+ self.global_pool = global_pool
205
+
206
+ def _init_weights(self, m):
207
+ if isinstance(m, nn.Linear):
208
+ trunc_normal_(m.weight, std=.02)
209
+ if isinstance(m, nn.Linear) and m.bias is not None:
210
+ nn.init.constant_(m.bias, 0)
211
+ elif isinstance(m, nn.LayerNorm):
212
+ nn.init.constant_(m.bias, 0)
213
+ nn.init.constant_(m.weight, 1.0)
214
+
215
+ def interpolate_pos_encoding(self, x, w, h):
216
+ npatch = x.shape[1] - 1
217
+ N = self.pos_embed.shape[1] - 1
218
+ if npatch == N and w == h:
219
+ return self.pos_embed
220
+ class_pos_embed = self.pos_embed[:, 0]
221
+ patch_pos_embed = self.pos_embed[:, 1:]
222
+ dim = x.shape[-1]
223
+ w0 = w // self.patch_embed.patch_size
224
+ h0 = h // self.patch_embed.patch_size
225
+ # we add a small number to avoid floating point error in the interpolation
226
+ # see discussion at https://github.com/facebookresearch/dino/issues/8
227
+ w0, h0 = w0 + 0.1, h0 + 0.1
228
+ patch_pos_embed = nn.functional.interpolate(
229
+ patch_pos_embed.reshape(1, int(math.sqrt(N)), int(math.sqrt(N)), dim).permute(0, 3, 1, 2),
230
+ scale_factor=(w0 / math.sqrt(N), h0 / math.sqrt(N)),
231
+ mode='bicubic',
232
+ )
233
+ assert int(w0) == patch_pos_embed.shape[-2] and int(h0) == patch_pos_embed.shape[-1]
234
+ patch_pos_embed = patch_pos_embed.permute(0, 2, 3, 1).view(1, -1, dim)
235
+ return torch.cat((class_pos_embed.unsqueeze(0), patch_pos_embed), dim=1)
236
+
237
+ def prepare_tokens(self, x):
238
+ B, nc, w, h = x.shape
239
+ x = self.patch_embed(x) # patch linear embedding
240
+
241
+ # add the [CLS] token to the embed patch tokens
242
+ cls_tokens = self.cls_token.expand(B, -1, -1)
243
+ x = torch.cat((cls_tokens, x), dim=1)
244
+
245
+ # add positional encoding to each token
246
+ x = x + self.interpolate_pos_encoding(x, w, h)
247
+
248
+ return self.pos_drop(x)
249
+
250
+ def forward(self, x):
251
+ x = self.prepare_tokens(x)
252
+ for blk in self.blocks:
253
+ x = blk(x)
254
+ x = self.norm(x)
255
+ if self.global_pool == 'token':
256
+ return x[:, 0]
257
+ elif self.global_pool == '':
258
+ return x
259
+
260
+ def get_last_selfattention(self, x):
261
+ x = self.prepare_tokens(x)
262
+ for i, blk in enumerate(self.blocks):
263
+ if i < len(self.blocks) - 1:
264
+ x = blk(x)
265
+ else:
266
+ # return attention of the last block
267
+ return blk(x, return_attention=True)
268
+
269
+ def get_intermediate_layers(self, x, n=1):
270
+ x = self.prepare_tokens(x)
271
+ # we return the output tokens from the `n` last blocks
272
+ output = []
273
+ for i, blk in enumerate(self.blocks):
274
+ x = blk(x)
275
+ if len(self.blocks) - i <= n:
276
+ output.append(self.norm(x))
277
+ return output
278
+
279
+
280
+ def vit_tiny(patch_size=16, **kwargs):
281
+ model = VisionTransformer(
282
+ patch_size=patch_size, embed_dim=192, depth=12, num_heads=3, mlp_ratio=4,
283
+ qkv_bias=True, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
284
+ return model
285
+
286
+
287
+ def vit_small(patch_size=16, **kwargs):
288
+ model = VisionTransformer(
289
+ patch_size=patch_size, embed_dim=384, depth=12, num_heads=6, mlp_ratio=4,
290
+ qkv_bias=True, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
291
+ return model
292
+
293
+
294
+ def vit_base(patch_size=16, **kwargs):
295
+ model = VisionTransformer(
296
+ patch_size=patch_size, embed_dim=768, depth=12, num_heads=12, mlp_ratio=4,
297
+ qkv_bias=True, norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
298
+ return model
299
+
300
+
301
+ class DINOHead(nn.Module):
302
+ def __init__(self, in_dim, out_dim, use_bn=False, norm_last_layer=True, nlayers=3, hidden_dim=2048, bottleneck_dim=256):
303
+ super().__init__()
304
+ nlayers = max(nlayers, 1)
305
+ if nlayers == 1:
306
+ self.mlp = nn.Linear(in_dim, bottleneck_dim)
307
+ else:
308
+ layers = [nn.Linear(in_dim, hidden_dim)]
309
+ if use_bn:
310
+ layers.append(nn.BatchNorm1d(hidden_dim))
311
+ layers.append(nn.GELU())
312
+ for _ in range(nlayers - 2):
313
+ layers.append(nn.Linear(hidden_dim, hidden_dim))
314
+ if use_bn:
315
+ layers.append(nn.BatchNorm1d(hidden_dim))
316
+ layers.append(nn.GELU())
317
+ layers.append(nn.Linear(hidden_dim, bottleneck_dim))
318
+ self.mlp = nn.Sequential(*layers)
319
+ self.apply(self._init_weights)
320
+ self.last_layer = nn.utils.weight_norm(nn.Linear(bottleneck_dim, out_dim, bias=False))
321
+ self.last_layer.weight_g.data.fill_(1)
322
+ if norm_last_layer:
323
+ self.last_layer.weight_g.requires_grad = False
324
+
325
+ def _init_weights(self, m):
326
+ if isinstance(m, nn.Linear):
327
+ trunc_normal_(m.weight, std=.02)
328
+ if isinstance(m, nn.Linear) and m.bias is not None:
329
+ nn.init.constant_(m.bias, 0)
330
+
331
+ def forward(self, x):
332
+ x = self.mlp(x)
333
+ x = nn.functional.normalize(x, dim=-1, p=2)
334
+ x = self.last_layer(x)
335
+ return x
336
+
337
+
338
+ def dino_vits16(pretrained=True, **kwargs):
339
+ """
340
+ ViT-Small/16x16 pre-trained with DINO.
341
+ Achieves 74.5% top-1 accuracy on ImageNet with k-NN classification.
342
+ """
343
+ model = vit_small(patch_size=16, num_classes=0, **kwargs)
344
+ if pretrained:
345
+ state_dict = torch.hub.load_state_dict_from_url(
346
+ url="https://dl.fbaipublicfiles.com/dino/dino_deitsmall16_pretrain/dino_deitsmall16_pretrain.pth",
347
+ map_location="cpu",
348
+ )
349
+ model.load_state_dict(state_dict, strict=True)
350
+ return model
351
+
352
+
353
+ def dino_vits8(pretrained=True, **kwargs):
354
+ """
355
+ ViT-Small/8x8 pre-trained with DINO.
356
+ Achieves 78.3% top-1 accuracy on ImageNet with k-NN classification.
357
+ """
358
+ model = vit_small(patch_size=8, num_classes=0, **kwargs)
359
+ if pretrained:
360
+ state_dict = torch.hub.load_state_dict_from_url(
361
+ url="https://dl.fbaipublicfiles.com/dino/dino_deitsmall8_pretrain/dino_deitsmall8_pretrain.pth",
362
+ map_location="cpu",
363
+ )
364
+ model.load_state_dict(state_dict, strict=True)
365
+ return model
366
+
367
+
368
+ def dino_vitb16(pretrained=True, **kwargs):
369
+ """
370
+ ViT-Base/16x16 pre-trained with DINO.
371
+ Achieves 76.1% top-1 accuracy on ImageNet with k-NN classification.
372
+ """
373
+ model = vit_base(patch_size=16, num_classes=0, **kwargs)
374
+ if pretrained:
375
+ state_dict = torch.hub.load_state_dict_from_url(
376
+ url="https://dl.fbaipublicfiles.com/dino/dino_vitbase16_pretrain/dino_vitbase16_pretrain.pth",
377
+ map_location="cpu",
378
+ )
379
+ model.load_state_dict(state_dict, strict=True)
380
+ return model
381
+
382
+
383
+ def dino_vitb8(pretrained=True, **kwargs):
384
+ """
385
+ ViT-Base/8x8 pre-trained with DINO.
386
+ Achieves 77.4% top-1 accuracy on ImageNet with k-NN classification.
387
+ """
388
+ model = vit_base(patch_size=8, num_classes=0, **kwargs)
389
+ if pretrained:
390
+ state_dict = torch.hub.load_state_dict_from_url(
391
+ url="https://dl.fbaipublicfiles.com/dino/dino_vitbase8_pretrain/dino_vitbase8_pretrain.pth",
392
+ map_location="cpu",
393
+ )
394
+ model.load_state_dict(state_dict, strict=True)
395
+ return model
396
+
397
+ def dino_vitb_cifar10(pretrained=True, **kwargs):
398
+ """
399
+ ViT-Base/16x16 pre-trained with DINO.
400
+ Achieves 76.1% top-1 accuracy on ImageNet with k-NN classification.
401
+ """
402
+ model = vit_base(patch_size=16, num_classes=0, **kwargs)
403
+ if pretrained:
404
+ state_dict = torch.hub.load_state_dict_from_url(
405
+ url="https://dl.fbaipublicfiles.com/dino/cifar100_ViT_B_dino.pth",
406
+ map_location="cpu",
407
+ )
408
+ model.load_state_dict(state_dict, strict=False)
409
+ return model
410
+
411
+
412
+
413
+
414
+ def dino_resnet50(pretrained=True, **kwargs):
415
+ """
416
+ ResNet-50 pre-trained with DINO.
417
+ Achieves 75.3% top-1 accuracy on ImageNet linear evaluation benchmark (requires to train `fc`).
418
+ """
419
+ from torchvision.models.resnet import resnet50
420
+
421
+ model = resnet50(pretrained=False, **kwargs)
422
+ model.fc = torch.nn.Identity()
423
+ if pretrained:
424
+ state_dict = torch.hub.load_state_dict_from_url(
425
+ url="https://dl.fbaipublicfiles.com/dino/dino_resnet50_pretrain/dino_resnet50_pretrain.pth",
426
+ map_location="cpu",
427
+ )
428
+ model.load_state_dict(state_dict, strict=False)
429
+ return model
430
+
431
+
432
+ def dino_xcit_small_12_p16(pretrained=True, **kwargs):
433
+ """
434
+ XCiT-Small-12/16 pre-trained with DINO.
435
+ """
436
+ model = torch.hub.load('facebookresearch/xcit:main', "xcit_small_12_p16", num_classes=0, **kwargs)
437
+ if pretrained:
438
+ state_dict = torch.hub.load_state_dict_from_url(
439
+ url="https://dl.fbaipublicfiles.com/dino/dino_xcit_small_12_p16_pretrain/dino_xcit_small_12_p16_pretrain.pth",
440
+ map_location="cpu",
441
+ )
442
+ model.load_state_dict(state_dict, strict=True)
443
+ return model
444
+
445
+
446
+ def dino_xcit_small_12_p8(pretrained=True, **kwargs):
447
+ """
448
+ XCiT-Small-12/8 pre-trained with DINO.
449
+ """
450
+ model = torch.hub.load('facebookresearch/xcit:main', "xcit_small_12_p8", num_classes=0, **kwargs)
451
+ if pretrained:
452
+ state_dict = torch.hub.load_state_dict_from_url(
453
+ url="https://dl.fbaipublicfiles.com/dino/dino_xcit_small_12_p8_pretrain/dino_xcit_small_12_p8_pretrain.pth",
454
+ map_location="cpu",
455
+ )
456
+ model.load_state_dict(state_dict, strict=True)
457
+ return model
458
+
459
+
460
+ def dino_xcit_medium_24_p16(pretrained=True, **kwargs):
461
+ """
462
+ XCiT-Medium-24/16 pre-trained with DINO.
463
+ """
464
+ model = torch.hub.load('facebookresearch/xcit:main', "xcit_medium_24_p16", num_classes=0, **kwargs)
465
+ if pretrained:
466
+ state_dict = torch.hub.load_state_dict_from_url(
467
+ url="https://dl.fbaipublicfiles.com/dino/dino_xcit_medium_24_p16_pretrain/dino_xcit_medium_24_p16_pretrain.pth",
468
+ map_location="cpu",
469
+ )
470
+ model.load_state_dict(state_dict, strict=True)
471
+ return model
472
+
473
+
474
+ def dino_xcit_medium_24_p8(pretrained=True, **kwargs):
475
+ """
476
+ XCiT-Medium-24/8 pre-trained with DINO.
477
+ """
478
+ model = torch.hub.load('facebookresearch/xcit:main', "xcit_medium_24_p8", num_classes=0, **kwargs)
479
+ if pretrained:
480
+ state_dict = torch.hub.load_state_dict_from_url(
481
+ url="https://dl.fbaipublicfiles.com/dino/dino_xcit_medium_24_p8_pretrain/dino_xcit_medium_24_p8_pretrain.pth",
482
+ map_location="cpu",
483
+ )
484
+ model.load_state_dict(state_dict, strict=True)
485
+ return model
CSD/models/moco_vits.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) Facebook, Inc. and its affiliates.
2
+ # All rights reserved.
3
+
4
+ # This source code is licensed under the license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ import math
8
+ import torch
9
+ import torch.nn as nn
10
+ from functools import partial, reduce
11
+ from operator import mul
12
+
13
+ from timm.models.vision_transformer import VisionTransformer, _cfg
14
+ from timm.models.layers.helpers import to_2tuple
15
+ from timm.models.layers import PatchEmbed
16
+
17
+ __all__ = [
18
+ 'vit_small',
19
+ 'vit_base',
20
+ 'vit_conv_small',
21
+ 'vit_conv_base',
22
+ ]
23
+
24
+
25
+ class VisionTransformerMoCo(VisionTransformer):
26
+ def __init__(self, stop_grad_conv1=False, **kwargs):
27
+ super().__init__(**kwargs)
28
+ # Use fixed 2D sin-cos position embedding
29
+ self.build_2d_sincos_position_embedding()
30
+
31
+ # weight initialization
32
+ for name, m in self.named_modules():
33
+ if isinstance(m, nn.Linear):
34
+ if 'qkv' in name:
35
+ # treat the weights of Q, K, V separately
36
+ val = math.sqrt(6. / float(m.weight.shape[0] // 3 + m.weight.shape[1]))
37
+ nn.init.uniform_(m.weight, -val, val)
38
+ else:
39
+ nn.init.xavier_uniform_(m.weight)
40
+ nn.init.zeros_(m.bias)
41
+ nn.init.normal_(self.cls_token, std=1e-6)
42
+
43
+ if isinstance(self.patch_embed, PatchEmbed):
44
+ # xavier_uniform initialization
45
+ val = math.sqrt(6. / float(3 * reduce(mul, self.patch_embed.patch_size, 1) + self.embed_dim))
46
+ nn.init.uniform_(self.patch_embed.proj.weight, -val, val)
47
+ nn.init.zeros_(self.patch_embed.proj.bias)
48
+
49
+ if stop_grad_conv1:
50
+ self.patch_embed.proj.weight.requires_grad = False
51
+ self.patch_embed.proj.bias.requires_grad = False
52
+
53
+ def build_2d_sincos_position_embedding(self, temperature=10000.):
54
+ h, w = self.patch_embed.grid_size
55
+ grid_w = torch.arange(w, dtype=torch.float32)
56
+ grid_h = torch.arange(h, dtype=torch.float32)
57
+ grid_w, grid_h = torch.meshgrid(grid_w, grid_h)
58
+ assert self.embed_dim % 4 == 0, 'Embed dimension must be divisible by 4 for 2D sin-cos position embedding'
59
+ pos_dim = self.embed_dim // 4
60
+ omega = torch.arange(pos_dim, dtype=torch.float32) / pos_dim
61
+ omega = 1. / (temperature**omega)
62
+ out_w = torch.einsum('m,d->md', [grid_w.flatten(), omega])
63
+ out_h = torch.einsum('m,d->md', [grid_h.flatten(), omega])
64
+ pos_emb = torch.cat([torch.sin(out_w), torch.cos(out_w), torch.sin(out_h), torch.cos(out_h)], dim=1)[None, :, :]
65
+
66
+ # assert self.num_tokens == 1, 'Assuming one and only one token, [cls]'
67
+ pe_token = torch.zeros([1, 1, self.embed_dim], dtype=torch.float32)
68
+ self.pos_embed = nn.Parameter(torch.cat([pe_token, pos_emb], dim=1))
69
+ self.pos_embed.requires_grad = False
70
+
71
+
72
+ class ConvStem(nn.Module):
73
+ """
74
+ ConvStem, from Early Convolutions Help Transformers See Better, Tete et al. https://arxiv.org/abs/2106.14881
75
+ """
76
+ def __init__(self, img_size=224, patch_size=16, in_chans=3, embed_dim=768, norm_layer=None, flatten=True):
77
+ super().__init__()
78
+
79
+ assert patch_size == 16, 'ConvStem only supports patch size of 16'
80
+ assert embed_dim % 8 == 0, 'Embed dimension must be divisible by 8 for ConvStem'
81
+
82
+ img_size = to_2tuple(img_size)
83
+ patch_size = to_2tuple(patch_size)
84
+ self.img_size = img_size
85
+ self.patch_size = patch_size
86
+ self.grid_size = (img_size[0] // patch_size[0], img_size[1] // patch_size[1])
87
+ self.num_patches = self.grid_size[0] * self.grid_size[1]
88
+ self.flatten = flatten
89
+
90
+ # build stem, similar to the design in https://arxiv.org/abs/2106.14881
91
+ stem = []
92
+ input_dim, output_dim = 3, embed_dim // 8
93
+ for l in range(4):
94
+ stem.append(nn.Conv2d(input_dim, output_dim, kernel_size=3, stride=2, padding=1, bias=False))
95
+ stem.append(nn.BatchNorm2d(output_dim))
96
+ stem.append(nn.ReLU(inplace=True))
97
+ input_dim = output_dim
98
+ output_dim *= 2
99
+ stem.append(nn.Conv2d(input_dim, embed_dim, kernel_size=1))
100
+ self.proj = nn.Sequential(*stem)
101
+
102
+ self.norm = norm_layer(embed_dim) if norm_layer else nn.Identity()
103
+
104
+ def forward(self, x):
105
+ B, C, H, W = x.shape
106
+ assert H == self.img_size[0] and W == self.img_size[1], \
107
+ f"Input image size ({H}*{W}) doesn't match model ({self.img_size[0]}*{self.img_size[1]})."
108
+ x = self.proj(x)
109
+ if self.flatten:
110
+ x = x.flatten(2).transpose(1, 2) # BCHW -> BNC
111
+ x = self.norm(x)
112
+ return x
113
+
114
+
115
+ def vit_small(**kwargs):
116
+ model = VisionTransformerMoCo(
117
+ patch_size=16, embed_dim=384, depth=12, num_heads=12, mlp_ratio=4, qkv_bias=True,
118
+ norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
119
+ model.default_cfg = _cfg()
120
+ return model
121
+
122
+ def vit_base(**kwargs):
123
+ model = VisionTransformerMoCo(
124
+ patch_size=16, embed_dim=768, depth=12, num_heads=12, mlp_ratio=4, qkv_bias=True,
125
+ norm_layer=partial(nn.LayerNorm, eps=1e-6), **kwargs)
126
+ model.default_cfg = _cfg()
127
+ return model
128
+
129
+ def vit_conv_small(**kwargs):
130
+ # minus one ViT block
131
+ model = VisionTransformerMoCo(
132
+ patch_size=16, embed_dim=384, depth=11, num_heads=12, mlp_ratio=4, qkv_bias=True,
133
+ norm_layer=partial(nn.LayerNorm, eps=1e-6), embed_layer=ConvStem, **kwargs)
134
+ model.default_cfg = _cfg()
135
+ return model
136
+
137
+ def vit_conv_base(**kwargs):
138
+ # minus one ViT block
139
+ model = VisionTransformerMoCo(
140
+ patch_size=16, embed_dim=768, depth=11, num_heads=12, mlp_ratio=4, qkv_bias=True,
141
+ norm_layer=partial(nn.LayerNorm, eps=1e-6), embed_layer=ConvStem, **kwargs)
142
+ model.default_cfg = _cfg()
143
+ return model
CSD/pretrainedmodels/.gitkeep ADDED
File without changes
CSD/search.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import copy
3
+ import logging
4
+ import logging.handlers as handlers
5
+ import pathlib
6
+ import sys
7
+
8
+ import faiss
9
+ import numpy as np
10
+ import vaex as vx
11
+ import wandb
12
+
13
+ sys.path.insert(0, str(pathlib.Path(__file__).parent.resolve()))
14
+
15
+ from search.embeddings import Embeddings
16
+ from search.faiss_search import FaissIndex
17
+ from metrics import metrics
18
+ from data.wikiart import WikiArt
19
+
20
+ logger = logging.getLogger()
21
+
22
+
23
+ def get_parser():
24
+ parser = argparse.ArgumentParser('dynamicDistances-NN Search Module')
25
+ parser.add_argument('--dataset', default='wikiart', type=str, required=True)
26
+ parser.add_argument('--topk', nargs='+', type=int, default=[5],
27
+ help='Number of NN to consider while calculating recall')
28
+ parser.add_argument('--mode', type=str, required=True, choices=['artist', 'label'],
29
+ help='The type of matching to do')
30
+ parser.add_argument('--method', type=str, default='IP', choices=['IP', 'L2'], help='The method to do NN search')
31
+ parser.add_argument('--emb-dir', type=str, default=None,
32
+ help='The directory where per image embeddings are stored (NOT USED when chunked)')
33
+ parser.add_argument('--query_count', default=-1, type=int,
34
+ help='Number of queries to consider. Works only for domainnet')
35
+ parser.add_argument('--chunked', action='store_true', help='If I should read from chunked directory instead')
36
+ parser.add_argument('--query-chunk-dir', type=str, required=True,
37
+ help='The directory where chunked query embeddings should be saved/are already saved')
38
+ parser.add_argument('--database-chunk-dir', type=str, required=True,
39
+ help='The directory where chunked val embeddings should be saved/are already saved')
40
+ parser.add_argument('--data-dir', type=str, default=None,
41
+ help='The directory of concerned dataset. (HARD CODED LATER)')
42
+ parser.add_argument('--multilabel', action='store_true', help='If the dataset is multilabel')
43
+
44
+ return parser
45
+
46
+
47
+ def get_log_handlers(args):
48
+ # Create handlers
49
+ c_handler = logging.StreamHandler()
50
+ f_handler = handlers.RotatingFileHandler(f'search.log', maxBytes=int(1e6), backupCount=1000)
51
+ c_handler.setLevel(logging.DEBUG)
52
+ f_handler.setLevel(logging.DEBUG)
53
+
54
+ # Create formatters and add it to handlers
55
+ c_format = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
56
+ f_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
57
+ c_handler.setFormatter(c_format)
58
+ f_handler.setFormatter(f_format)
59
+ return c_handler, f_handler
60
+
61
+
62
+ def main():
63
+ parser = get_parser()
64
+ args = parser.parse_args()
65
+
66
+ handlers = get_log_handlers(args)
67
+ logger.addHandler(handlers[0])
68
+ logger.addHandler(handlers[1])
69
+ logger.setLevel(logging.DEBUG)
70
+
71
+ if args.dataset == 'wikiart':
72
+ dataset = WikiArt(args.data_dir)
73
+ else:
74
+ raise NotImplementedError
75
+
76
+ query_embeddings = Embeddings(args.emb_dir, args.query_chunk_dir,
77
+ files=list(map(lambda x: f'{x.split(".")[0]}.npy', dataset.query_images)),
78
+ chunked=args.chunked,
79
+ file_ext='.npy')
80
+ val_embeddings = Embeddings(args.emb_dir, args.database_chunk_dir,
81
+ files=list(map(lambda x: f'{x.split(".")[0]}.npy', dataset.val_images)),
82
+ chunked=args.chunked,
83
+ file_ext='.npy')
84
+
85
+ query_embeddings.filenames = list(query_embeddings.filenames)
86
+ val_embeddings.filenames = list(val_embeddings.filenames)
87
+
88
+ # Filtering the dataset based on the files which actually exist.
89
+ dataset.query_db = dataset.query_db[
90
+ dataset.query_db['name'].isin(query_embeddings.filenames)]
91
+ dataset.val_db = dataset.val_db[
92
+ dataset.val_db['name'].isin(val_embeddings.filenames)]
93
+
94
+ # Using only the embeddings corresponding to images in the datasets
95
+ temp = vx.from_arrays(filename=query_embeddings.filenames, index=np.arange(len(query_embeddings.filenames)))
96
+ dataset.query_db = dataset.query_db.join(temp, left_on='name', right_on='filename', how='left')
97
+ query_embeddings.embeddings = query_embeddings.embeddings[dataset.get_query_col('index')]
98
+ try:
99
+ b, h, w = query_embeddings.embeddings.shape
100
+ query_embeddings.embeddings = query_embeddings.embeddings.reshape(b, 1, h * w)
101
+ except ValueError:
102
+ b, d = query_embeddings.embeddings.shape
103
+ query_embeddings.embeddings = query_embeddings.embeddings.reshape(b, 1, d)
104
+ query_embeddings.filenames = np.asarray(query_embeddings.filenames)[dataset.get_query_col('index')]
105
+
106
+ temp = vx.from_arrays(filename=val_embeddings.filenames, index=np.arange(len(val_embeddings.filenames)))
107
+ dataset.val_db = dataset.val_db.join(temp, left_on='name', right_on='filename', how='left')
108
+ val_embeddings.embeddings = val_embeddings.embeddings[dataset.get_val_col('index')]
109
+ try:
110
+ b, h, w = val_embeddings.embeddings.shape
111
+ val_embeddings.embeddings = val_embeddings.embeddings.reshape(b, 1, h * w)
112
+ except ValueError:
113
+ b, d = val_embeddings.embeddings.shape
114
+ val_embeddings.embeddings = val_embeddings.embeddings.reshape(b, 1, d)
115
+ val_embeddings.filenames = np.asarray(val_embeddings.filenames)[dataset.get_val_col('index')]
116
+
117
+ # Building the faiss index
118
+ embedding_size = query_embeddings.embeddings[0].shape[1]
119
+ if args.method == 'IP':
120
+ method = faiss.IndexFlatIP
121
+ else:
122
+ method = faiss.IndexFlatL2
123
+ search_module = FaissIndex(embedding_size=embedding_size, index_func=method)
124
+ queries = np.asarray(query_embeddings.embeddings).reshape(len(query_embeddings.embeddings), embedding_size)
125
+ database = np.asarray(val_embeddings.embeddings).reshape(len(val_embeddings.embeddings), embedding_size)
126
+ search_module.build_index(database)
127
+
128
+ _, nns_all = search_module.search_nns(queries, max(args.topk))
129
+ if args.multilabel:
130
+ q_labels = dataset.query_db['multilabel'].values
131
+ db_labels = dataset.val_db['multilabel'].values
132
+ nns_all_pred = [q_labels[i] @ db_labels[nns_all[i]].T for i in range(len(nns_all))]
133
+ nns_all_pred = np.array(nns_all_pred)
134
+ else:
135
+ nns_all_pred = nns_all
136
+ classes = np.unique(dataset.get_val_col(args.mode))
137
+ mode_to_index = {classname: i for i, classname in enumerate(classes)}
138
+ try:
139
+ gts = np.asarray(list(map(lambda x: mode_to_index[x], dataset.get_query_col(args.mode).tolist())))
140
+ except KeyError:
141
+ logger.error('Class not found in database. This query list cannot be evaluated')
142
+ return
143
+
144
+ evals = metrics.Metrics()
145
+
146
+ for topk in args.topk:
147
+ logger.info(f'Calculating recall@{topk}')
148
+ nns_all_pred_topk = nns_all_pred[:, :topk]
149
+ if args.multilabel:
150
+ mode_recall = evals.get_recall_bin(copy.deepcopy(nns_all_pred_topk), topk)
151
+ mode_mrr = evals.get_mrr_bin(copy.deepcopy(nns_all_pred_topk), topk)
152
+ mode_map = evals.get_map_bin(copy.deepcopy(nns_all_pred_topk), topk)
153
+ else:
154
+ preds = dataset.get_val_col(args.mode)[nns_all_pred_topk.flatten()].reshape(len(queries), topk)
155
+ preds = np.vectorize(mode_to_index.get)(preds)
156
+ mode_recall = evals.get_recall(copy.deepcopy(preds), gts, topk)
157
+ mode_mrr = evals.get_mrr(copy.deepcopy(preds), gts, topk)
158
+ mode_map = evals.get_map(copy.deepcopy(preds), gts, topk)
159
+ logger.info(f'Recall@{topk}: {mode_recall}')
160
+ logger.info(f'MRR@{topk}: {mode_mrr}')
161
+ logger.info(f'mAP@{topk}: {mode_map}')
162
+
163
+
164
+ if __name__ == '__main__':
165
+ main()
CSD/search/__init__.py ADDED
File without changes
CSD/search/embeddings.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import concurrent.futures as concfut
2
+ import glob
3
+ import os
4
+
5
+ import pickle
6
+ import logging
7
+ import queue
8
+ import os.path as osp
9
+ import threading
10
+ from multiprocessing import Process
11
+ import math
12
+ import numpy as np
13
+
14
+ module_logger = logging.getLogger(__name__)
15
+
16
+
17
+ class Embeddings(object):
18
+ """Class to read embeddings from the disk and store them in memory"""
19
+ def __init__(self, data_dir, chunk_dir, file_ext='.pt', files=None, chunked=False, chunk_size=5000):
20
+ if files is not None:
21
+ self.embedding_files = list(map(lambda x: osp.join(data_dir, x), files))
22
+ else:
23
+ self.embedding_files = glob.glob(f'{data_dir}/*{file_ext}')
24
+ self.embedding_queue = queue.Queue()
25
+ self.embeddings = []
26
+ self.filenames = []
27
+ self.chunk_dir = chunk_dir
28
+ self.chunk_size = chunk_size
29
+ self.chunked = chunked
30
+ if not self.chunked:
31
+ threading.Thread(target=self.__result_consumer, daemon=True).start()
32
+ self.__read_embeddings()
33
+ self.embeddings, self.filenames = self.__remove_missing(self.embeddings, self.filenames)
34
+ else:
35
+ self.__read_embeddings_chunked()
36
+ self.__sort_embeddings()
37
+
38
+ def __result_consumer(self):
39
+ """Consumes the results from the embedding queue and saves them to the disk"""
40
+ processed = 0
41
+ fnf = 0 # FileNotFound
42
+ embedding_chunk = []
43
+ filename_chunk = []
44
+ chunk_cnt = 0
45
+ while True:
46
+ data = self.embedding_queue.get()
47
+ if not isinstance(data, str):
48
+ self.filenames.append(data['filename'])
49
+ if data['embedding'] is not None:
50
+ self.embeddings.append(data['embedding'])
51
+ processed += 1
52
+ if processed % 1000 == 0:
53
+ module_logger.info(f'Read {processed}/{len(self.embedding_files)} embeddings')
54
+ else:
55
+ fnf += 1
56
+ self.embeddings.append(None)
57
+ if len(embedding_chunk) < self.chunk_size:
58
+ embedding_chunk.append(data['embedding'])
59
+ filename_chunk.append(data['filename'])
60
+ else:
61
+ chunk_cnt += 1
62
+ embedding_chunk, filename_chunk = self.__remove_missing(embedding_chunk, filename_chunk)
63
+ Process(target=save_chunk, args=(embedding_chunk, filename_chunk, chunk_cnt, self.chunk_dir),
64
+ daemon=True).start()
65
+ embedding_chunk = []
66
+ filename_chunk = []
67
+ self.embedding_queue.task_done()
68
+ elif data == 'DONE':
69
+ chunk_cnt += 1
70
+ embedding_chunk, filename_chunk = self.__remove_missing(embedding_chunk, filename_chunk)
71
+ save_chunk(embedding_chunk, filename_chunk, chunk_cnt, self.chunk_dir)
72
+ module_logger.info(
73
+ f'Completed reading embeddings. There were {fnf} images for which embeddings were not found')
74
+ self.embedding_queue.task_done()
75
+ break
76
+
77
+ def __sort_embeddings(self):
78
+ """Sort embeddings and filenames by filename"""
79
+ self.filenames = np.asarray(self.filenames)
80
+ sort_order = np.argsort(self.filenames)
81
+ self.embeddings = np.asarray(self.embeddings)[sort_order]
82
+ self.filenames = self.filenames[sort_order]
83
+
84
+ def __load_embedding(self, filename):
85
+ """Loads an embedding from the disk and puts it in the embedding queue"""
86
+ if osp.exists(filename):
87
+ embedding = np.load(filename)
88
+ data = {
89
+ 'embedding': embedding,
90
+ 'filename': filename.split('/')[-1],
91
+ }
92
+ else:
93
+ data = {
94
+ 'filename': filename.split('/')[-1],
95
+ 'embedding': None
96
+ }
97
+ self.embedding_queue.put(data)
98
+
99
+ def __read_embeddings(self):
100
+ """Reads embeddings from the disk"""
101
+ with concfut.ThreadPoolExecutor(max_workers=32) as executor:
102
+ worker = self.__load_embedding
103
+ executor.map(worker, self.embedding_files)
104
+ executor.shutdown(wait=True, cancel_futures=False)
105
+ self.embedding_queue.put('DONE')
106
+ self.embedding_queue.join()
107
+
108
+ def __read_embeddings_chunked(self):
109
+ """Reads embeddings from the disk in chunks"""
110
+ files = os.listdir(self.chunk_dir)
111
+ cnt = 0
112
+ with concfut.ProcessPoolExecutor(max_workers=32) as executor:
113
+ futures = [executor.submit(load_chunk, osp.join(self.chunk_dir, filename)) for filename in files]
114
+ for future in concfut.as_completed(futures):
115
+ result = future.result()
116
+ module_logger.info(f'Consuming {cnt}/{len(files)} chunks')
117
+ self.embeddings.extend(list(map(lambda x: x.squeeze(), result['embeddings'])))
118
+ self.filenames.extend(list(map(lambda x: '.'.join(x.split('/')[-1].split('.')[:-1]), result['filenames'])))
119
+ cnt += 1
120
+ module_logger.info('Finished reading chunks')
121
+
122
+ @staticmethod
123
+ def get_missing(x):
124
+ """Returns the indices of missing embeddings"""
125
+ indices = filter(lambda i_x: i_x[1] is None, enumerate(x))
126
+ res = np.asarray([i for i, x in indices])
127
+ return res
128
+
129
+ def __remove_missing(self, embeddings, filenames):
130
+ """Removes embeddings and filenames for which embeddings were not found"""
131
+ missing_ids = self.get_missing(embeddings)
132
+ embeddings = [ele for idx, ele in enumerate(embeddings) if idx not in missing_ids]
133
+ filenames = [ele for idx, ele in enumerate(filenames) if idx not in missing_ids]
134
+ return embeddings, filenames
135
+
136
+
137
+ def load_chunk(filename):
138
+ """Loads a chunk file containing embeddings and filenames"""
139
+ data = pickle.load(open(filename, 'rb'))
140
+ return data
141
+
142
+
143
+ def save_chunk(embeddings, filenames, count, chunk_dir, chunk_size=50000):
144
+ """Saves a chunk file containing embeddings and filenames. If the number of embeddings is less than chunk_size, it
145
+ saves all embeddings and filenames in one file. Otherwise, it splits the embeddings and filenames into chunks of
146
+ size chunk_size and saves each chunk in a separate file."""
147
+ assert len(embeddings) == len(filenames)
148
+ os.makedirs(chunk_dir, exist_ok=True)
149
+
150
+ if len(embeddings) < chunk_size:
151
+ data = {
152
+ 'embeddings': embeddings,
153
+ 'filenames': filenames,
154
+ }
155
+ pickle.dump(data, open(osp.join(chunk_dir, f'embeddings_{count}.pkl'), 'wb'))
156
+ else:
157
+ # Split into len(embeddings) / 50000 chunks
158
+ for i in range(0, math.ceil(len(embeddings)/chunk_size)):
159
+ data = {
160
+ 'embeddings': embeddings[i*chunk_size: min((i+1)*chunk_size, len(embeddings))],
161
+ 'filenames': filenames[i*chunk_size: min((i+1)*chunk_size, len(embeddings))],
162
+ }
163
+ with open(osp.join(chunk_dir, f'embeddings_{i}.pkl'), 'wb') as f:
164
+ pickle.dump(data, f)
CSD/search/faiss_search.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import faiss
3
+
4
+ module_logger = logging.getLogger(__name__)
5
+
6
+
7
+ class FaissIndex(object):
8
+ def __init__(self, index_func=faiss.IndexFlatIP, embedding_size=512*512):
9
+ self.index = index_func(embedding_size)
10
+ # Enable GPU support
11
+ # self.index_gpu = faiss.index_cpu_to_all_gpus(self.index)
12
+
13
+ def build_index(self, nodes):
14
+ self.index.add(nodes)
15
+ # Enable GPU support
16
+ # self.index_gpu.add(nodes)
17
+
18
+ def search_nns(self, embeddings, n):
19
+ # Enable GPU support
20
+ # return self.index_gpu.search(embeddings, n)
21
+ return self.index.search(embeddings, n)
CSD/utils.py ADDED
@@ -0,0 +1,465 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ '''
2
+ Code elements borrowed from
3
+ https://github.com/clovaai/CutMix-PyTorch/blob/master/train.py
4
+ '''
5
+ import argparse
6
+ import os
7
+ import sys
8
+ from collections import defaultdict, deque
9
+ import time, datetime
10
+
11
+ import faiss
12
+ import numpy as np
13
+ import torch
14
+ import torch.distributed as dist
15
+ import torch.nn as nn
16
+
17
+ from einops import rearrange, reduce
18
+
19
+
20
+ def is_dist_avail_and_initialized():
21
+ if not dist.is_available():
22
+ return False
23
+ if not dist.is_initialized():
24
+ return False
25
+ return True
26
+
27
+
28
+ def bool_flag(s):
29
+ """
30
+ Parse boolean arguments from the command line.
31
+ """
32
+ FALSY_STRINGS = {"off", "false", "0"}
33
+ TRUTHY_STRINGS = {"on", "true", "1"}
34
+ if s.lower() in FALSY_STRINGS:
35
+ return False
36
+ elif s.lower() in TRUTHY_STRINGS:
37
+ return True
38
+ else:
39
+ raise argparse.ArgumentTypeError("invalid value for a boolean flag")
40
+
41
+
42
+ def setup_for_distributed(is_master):
43
+ """
44
+ This function disables printing when not in master process
45
+ """
46
+ import builtins as __builtin__
47
+ builtin_print = __builtin__.print
48
+
49
+ def print(*args, **kwargs):
50
+ force = kwargs.pop('force', False)
51
+ if is_master or force:
52
+ builtin_print(*args, **kwargs)
53
+
54
+ __builtin__.print = print
55
+
56
+
57
+ def init_distributed_mode(args):
58
+ args.distributed = True
59
+ # launched with torch.distributed.launch
60
+ if 'RANK' in os.environ and 'WORLD_SIZE' in os.environ:
61
+ args.rank = int(os.environ["RANK"])
62
+ args.world_size = int(os.environ['WORLD_SIZE'])
63
+ args.gpu = int(os.environ['LOCAL_RANK'])
64
+ # launched with submitit on a slurm cluster
65
+ elif 'SLURM_PROCID' in os.environ:
66
+ args.rank = int(os.environ['SLURM_PROCID'])
67
+ args.gpu = args.rank % torch.cuda.device_count()
68
+ # launched naively with `python main_dino.py`
69
+ # we manually add MASTER_ADDR and MASTER_PORT to env variables
70
+ elif torch.cuda.is_available():
71
+ print('Will run the code on one GPU.')
72
+ args.rank, args.gpu, args.world_size = 0, 0, 1
73
+ os.environ['MASTER_ADDR'] = '127.0.0.1'
74
+ os.environ['MASTER_PORT'] = '29500'
75
+ else:
76
+ print('Does not support training without GPU.')
77
+ sys.exit(1)
78
+
79
+ dist.init_process_group(
80
+ backend="nccl",
81
+ init_method=args.dist_url,
82
+ world_size=args.world_size,
83
+ rank=args.rank,
84
+ )
85
+
86
+ torch.cuda.set_device(args.gpu)
87
+ print('| distributed init (rank {}): {}'.format(
88
+ args.rank, args.dist_url), flush=True)
89
+ dist.barrier()
90
+ setup_for_distributed(args.rank == 0)
91
+
92
+
93
+ class SmoothedValue(object):
94
+ """Track a series of values and provide access to smoothed values over a
95
+ window or the global series average.
96
+ """
97
+
98
+ def __init__(self, window_size=20, fmt=None):
99
+ if fmt is None:
100
+ fmt = "{median:.6f} ({global_avg:.6f})"
101
+ self.deque = deque(maxlen=window_size)
102
+ self.total = 0.0
103
+ self.count = 0
104
+ self.fmt = fmt
105
+
106
+ def update(self, value, n=1):
107
+ self.deque.append(value)
108
+ self.count += n
109
+ self.total += value * n
110
+
111
+ def synchronize_between_processes(self):
112
+ """
113
+ Warning: does not synchronize the deque!
114
+ """
115
+ if not is_dist_avail_and_initialized():
116
+ return
117
+ t = torch.tensor([self.count, self.total], dtype=torch.float64, device='cuda')
118
+ dist.barrier()
119
+ dist.all_reduce(t)
120
+ t = t.tolist()
121
+ self.count = int(t[0])
122
+ self.total = t[1]
123
+
124
+ @property
125
+ def median(self):
126
+ d = torch.tensor(list(self.deque))
127
+ return d.median().item()
128
+
129
+ @property
130
+ def avg(self):
131
+ d = torch.tensor(list(self.deque), dtype=torch.float32)
132
+ return d.mean().item()
133
+
134
+ @property
135
+ def global_avg(self):
136
+ return self.total / self.count
137
+
138
+ @property
139
+ def max(self):
140
+ return max(self.deque)
141
+
142
+ @property
143
+ def value(self):
144
+ return self.deque[-1]
145
+
146
+ def __str__(self):
147
+ return self.fmt.format(
148
+ median=self.median,
149
+ avg=self.avg,
150
+ global_avg=self.global_avg,
151
+ max=self.max,
152
+ value=self.value)
153
+
154
+
155
+ class MetricLogger(object):
156
+ def __init__(self, delimiter="\t"):
157
+ self.meters = defaultdict(SmoothedValue)
158
+ self.delimiter = delimiter
159
+
160
+ def update(self, **kwargs):
161
+ for k, v in kwargs.items():
162
+ if isinstance(v, torch.Tensor):
163
+ v = v.item()
164
+ assert isinstance(v, (float, int))
165
+ self.meters[k].update(v)
166
+
167
+ def __getattr__(self, attr):
168
+ if attr in self.meters:
169
+ return self.meters[attr]
170
+ if attr in self.__dict__:
171
+ return self.__dict__[attr]
172
+ raise AttributeError("'{}' object has no attribute '{}'".format(
173
+ type(self).__name__, attr))
174
+
175
+ def __str__(self):
176
+ loss_str = []
177
+ for name, meter in self.meters.items():
178
+ loss_str.append(
179
+ "{}: {}".format(name, str(meter))
180
+ )
181
+ return self.delimiter.join(loss_str)
182
+
183
+ def synchronize_between_processes(self):
184
+ for meter in self.meters.values():
185
+ meter.synchronize_between_processes()
186
+
187
+ def add_meter(self, name, meter):
188
+ self.meters[name] = meter
189
+
190
+ def log_every(self, iterable, print_freq, header=None):
191
+ i = 0
192
+ if not header:
193
+ header = ''
194
+ start_time = time.time()
195
+ end = time.time()
196
+ iter_time = SmoothedValue(fmt='{avg:.6f}')
197
+ data_time = SmoothedValue(fmt='{avg:.6f}')
198
+ space_fmt = ':' + str(len(str(len(iterable)))) + 'd'
199
+ if torch.cuda.is_available():
200
+ log_msg = self.delimiter.join([
201
+ header,
202
+ '[{0' + space_fmt + '}/{1}]',
203
+ 'eta: {eta}',
204
+ '{meters}',
205
+ 'time: {time}',
206
+ 'data: {data}',
207
+ 'max mem: {memory:.0f}'
208
+ ])
209
+ else:
210
+ log_msg = self.delimiter.join([
211
+ header,
212
+ '[{0' + space_fmt + '}/{1}]',
213
+ 'eta: {eta}',
214
+ '{meters}',
215
+ 'time: {time}',
216
+ 'data: {data}'
217
+ ])
218
+ MB = 1024.0 * 1024.0
219
+ for obj in iterable:
220
+ data_time.update(time.time() - end)
221
+ yield obj
222
+ iter_time.update(time.time() - end)
223
+ if i % print_freq == 0 or i == len(iterable) - 1:
224
+ eta_seconds = iter_time.global_avg * (len(iterable) - i)
225
+ eta_string = str(datetime.timedelta(seconds=int(eta_seconds)))
226
+ if torch.cuda.is_available():
227
+ print(log_msg.format(
228
+ i, len(iterable), eta=eta_string,
229
+ meters=str(self),
230
+ time=str(iter_time), data=str(data_time),
231
+ memory=torch.cuda.max_memory_allocated() / MB))
232
+ else:
233
+ print(log_msg.format(
234
+ i, len(iterable), eta=eta_string,
235
+ meters=str(self),
236
+ time=str(iter_time), data=str(data_time)))
237
+ i += 1
238
+ end = time.time()
239
+ total_time = time.time() - start_time
240
+ total_time_str = str(datetime.timedelta(seconds=int(total_time)))
241
+ print('{} Total time: {} ({:.6f} s / it)'.format(
242
+ header, total_time_str, total_time / len(iterable)))
243
+
244
+
245
+ def multi_scale(samples, model, args):
246
+ v = None
247
+ for s in [1, 1 / 2 ** (1 / 2), 1 / 2]: # we use 3 different scales
248
+ if s == 1:
249
+ inp = samples.clone()
250
+ else:
251
+ inp = torch.nn.functional.interpolate(samples, scale_factor=s, mode='bilinear', align_corners=False)
252
+
253
+ if args.pt_style == 'vicregl':
254
+ feats = model(inp)[-1].clone()
255
+ elif args.pt_style == 'clip':
256
+ feats = model.module.encode_image(samples).to(torch.float32).clone()
257
+ else:
258
+ feats = model(inp).clone()
259
+ feats = torch.squeeze(feats)
260
+ feats = torch.unsqueeze(feats, 0)
261
+ if v is None:
262
+ v = feats
263
+ else:
264
+ v += feats
265
+ v /= 3
266
+ v /= v.norm()
267
+ return v
268
+
269
+
270
+ def patchify(x, size):
271
+ patches = rearrange(x, 'b c (h1 h2) (w1 w2) -> (b h1 w1) c h2 w2', h2=size, w2=size)
272
+ return patches
273
+
274
+
275
+ @torch.no_grad()
276
+ def extract_features(args, model, data_loader, use_cuda=True, multiscale=False):
277
+ metric_logger = MetricLogger(delimiter=" ")
278
+ features = None
279
+ # count = 0
280
+ for samples, index in metric_logger.log_every(data_loader, 100):
281
+ print(f'At the index {index[0]}')
282
+ samples = samples.cuda(non_blocking=True)
283
+ index = index.cuda(non_blocking=True)
284
+ if multiscale:
285
+ feats = multi_scale(samples, model, args)
286
+ else:
287
+
288
+ if args.pt_style == 'dino':
289
+ if args.layer > 1:
290
+ feats = model.module.get_intermediate_layers(samples, args.layer)[0][:, 0, :].clone()
291
+ elif args.layer == -1:
292
+
293
+ allfeats = model.module.get_intermediate_layers(samples, len(model.module.blocks))
294
+ feats = [allfeats[i - 1][:, 0, :] for i in args.multilayer]
295
+ bdim, _ = feats[0].shape
296
+ feats = torch.stack(feats, dim=1).reshape((bdim, -1)).clone()
297
+ else:
298
+ feats = model(samples).clone()
299
+
300
+ elif args.pt_style == 'moco':
301
+ feats = model.module.forward_features(samples)
302
+ feats = feats[:, 0, :].clone()
303
+ elif args.pt_style == 'vgg':
304
+ feats = model.module.features(samples).clone()
305
+ elif args.pt_style in ['clip', 'clip_wikiart']:
306
+ #
307
+ allfeats = model.module.visual.get_intermediate_layers(samples.type(model.module.dtype))
308
+ # else:
309
+ # allfeats = model.get_activations(samples) #[::-1]
310
+ allfeats.reverse()
311
+
312
+ if args.arch == 'resnet50':
313
+ # import ipdb; ipdb.set_trace()
314
+ if args.layer == -1:
315
+ raise Exception('Layer=-1 not allowed with clip resnet')
316
+ elif args.layer == 1:
317
+ feats = allfeats[0].clone()
318
+ else:
319
+ assert len(allfeats) >= args.layer, "Asking for features of layer that doesnt exist"
320
+ feats = reduce(allfeats[args.layer - 1], 'b c h w -> b c', 'mean').clone()
321
+
322
+ else:
323
+ if args.layer == -1:
324
+ feats = [allfeats[i - 1][:, 0, :] for i in args.multilayer]
325
+ bdim, _ = feats[0].shape
326
+ feats = torch.stack(feats, dim=1).reshape((bdim, -1)).clone()
327
+ else:
328
+ assert len(allfeats) >= args.layer
329
+ feats = allfeats[args.layer - 1][:, 0, :].clone()
330
+ else:
331
+ feats = model(samples).clone()
332
+ # init storage feature matrix
333
+ feats = nn.functional.normalize(feats, dim=1, p=2).to(torch.float16)
334
+ if dist.get_rank() == 0 and features is None:
335
+ features = torch.zeros(len(data_loader.dataset), feats.shape[-1], dtype=feats.dtype)
336
+ if use_cuda:
337
+ features = features.cuda(non_blocking=True)
338
+ print(f"Storing features into tensor of shape {features.shape}")
339
+ # get indexes from all processes
340
+ y_all = torch.empty(dist.get_world_size(), index.size(0), dtype=index.dtype, device=index.device)
341
+ y_l = list(y_all.unbind(0))
342
+ y_all_reduce = torch.distributed.all_gather(y_l, index, async_op=True)
343
+ y_all_reduce.wait()
344
+ index_all = torch.cat(y_l)
345
+
346
+ # share features between processes
347
+ feats_all = torch.empty(
348
+ dist.get_world_size(),
349
+ feats.size(0),
350
+ feats.size(1),
351
+ dtype=feats.dtype,
352
+ device=feats.device,
353
+ )
354
+ output_l = list(feats_all.unbind(0))
355
+ output_all_reduce = torch.distributed.all_gather(output_l, feats, async_op=True)
356
+ output_all_reduce.wait()
357
+
358
+ # update storage feature matrix
359
+ if dist.get_rank() == 0:
360
+ if use_cuda:
361
+ features.index_copy_(0, index_all, torch.cat(output_l).cuda())
362
+ else:
363
+ features.index_copy_(0, index_all.cpu(), torch.cat(output_l).cpu())
364
+
365
+ return features
366
+
367
+
368
+ def extract_features_pca(args, model, pca_model, k, data_loader, use_cuda=True, multiscale=False):
369
+ metric_logger = MetricLogger(delimiter=" ")
370
+ features = None
371
+ print('In pca function')
372
+ for samples, index in metric_logger.log_every(data_loader, 100):
373
+ print(f'At the index {index[0]}')
374
+ samples = samples.cuda(non_blocking=True)
375
+ index = index.cuda(non_blocking=True)
376
+
377
+ if multiscale:
378
+ feats = multi_scale(samples, model, args)
379
+ else:
380
+
381
+ if args.pt_style in ['clip', 'clip_wikiart']:
382
+ allfeats = model.module.visual.get_intermediate_layers(samples.type(model.module.dtype))
383
+ allfeats.reverse()
384
+ if args.arch == 'resnet50':
385
+ raise Exception('code not written for this case')
386
+ else:
387
+ temp = allfeats[args.layer - 1]
388
+ temp = torch.nn.functional.normalize(temp, dim=2)
389
+ # Doing gram matrix
390
+ feats = torch.einsum('bij,bik->bjk', temp, temp)
391
+ feats = feats.div(temp.shape[1])
392
+ feats = rearrange(feats, 'b c d -> b (c d)')
393
+ if pca_model is not None:
394
+ feats = feats.cpu().detach().numpy()
395
+ feats = pca_model.apply_py(feats)
396
+ feats = torch.from_numpy(feats).cuda().clone()
397
+ else:
398
+ feats = feats.detach().clone()
399
+ del temp
400
+ del allfeats
401
+ elif args.pt_style == 'vgg':
402
+ temp = model.module.features(samples)
403
+ temp = temp.view(temp.size(0), temp.size(1), -1)
404
+ feats = torch.einsum('bji,bki->bjk', temp, temp)
405
+ feats = feats.div(temp.shape[1])
406
+ feats = rearrange(feats, 'b c d -> b (c d)')
407
+ if pca_model is not None:
408
+ feats = feats.cpu().detach().numpy()
409
+ feats = pca_model.apply_py(feats)
410
+ feats = torch.from_numpy(feats).cuda().clone()
411
+ else:
412
+ feats = feats.detach().clone()
413
+ del temp
414
+ else:
415
+ raise Exception('Code not written for these ptstyles. Come back later.')
416
+
417
+ feats = nn.functional.normalize(feats, dim=1, p=2).to(torch.float16)
418
+ # init storage feature matrix
419
+ if dist.get_rank() == 0 and features is None:
420
+ features = torch.zeros(len(data_loader.dataset), feats.shape[-1], dtype=feats.dtype)
421
+ if use_cuda:
422
+ features = features.cuda(non_blocking=True)
423
+ print(f"Storing features into tensor of shape {features.shape}")
424
+
425
+ # get indexes from all processes
426
+ y_all = torch.empty(dist.get_world_size(), index.size(0), dtype=index.dtype, device=index.device)
427
+ y_l = list(y_all.unbind(0))
428
+ y_all_reduce = torch.distributed.all_gather(y_l, index, async_op=True)
429
+ y_all_reduce.wait()
430
+ index_all = torch.cat(y_l)
431
+
432
+ # share features between processes
433
+ feats_all = torch.empty(
434
+ dist.get_world_size(),
435
+ feats.size(0),
436
+ feats.size(1),
437
+ dtype=feats.dtype,
438
+ device=feats.device,
439
+ )
440
+ output_l = list(feats_all.unbind(0))
441
+ output_all_reduce = torch.distributed.all_gather(output_l, feats, async_op=True)
442
+ output_all_reduce.wait()
443
+
444
+ # update storage feature matrix
445
+ if dist.get_rank() == 0:
446
+ if use_cuda:
447
+ features.index_copy_(0, index_all, torch.cat(output_l))
448
+ else:
449
+ features.index_copy_(0, index_all.cpu(), torch.cat(output_l).cpu())
450
+ if pca_model is None:
451
+ features = features.detach().numpy()
452
+ pca = faiss.PCAMatrix(features.shape[-1], k)
453
+ pca.train(features)
454
+ trans_features = pca.apply_py(features)
455
+ return torch.from_numpy(trans_features), pca
456
+ else:
457
+ return features, None
458
+
459
+
460
+ # saving features into numpy files
461
+ def save_embeddings_numpy(embeddings, filenames, savepath):
462
+ os.makedirs(savepath, exist_ok=True)
463
+ for c, fname in enumerate(filenames):
464
+ np_emb = np.asarray(embeddings[c, :].cpu().detach(), dtype=np.float16)
465
+ np.save(f'{savepath}/{fname}.npy', np_emb)
CSD/wikiart.csv ADDED
The diff for this file is too large to render. See raw diff
 
README.md CHANGED
@@ -1,3 +1,11 @@
1
  ---
2
  license: mit
3
  ---
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: mit
3
  ---
4
+
5
+ ## Measuring Style Similarity in Diffusion Models
6
+
7
+ Cloned from [learn2phoenix/CSD](https://github.com/learn2phoenix/CSD?tab=readme-ov-file).
8
+
9
+ Their model (`csd-vit-l.pth`) downloaded from their [Google Drive](https://drive.google.com/file/d/1FX0xs8p-C7Ob-h5Y4cUhTeOepHzXv_46/view?usp=sharing).
10
+
11
+ The original Git Repo is in the `CSD` folder.
csd-vit-l.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:40e92fad63a361b8136100cd234c42d401ef9b34ff1748234318929ebcc7e7a1
3
+ size 2438228893