├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── SimCLRv1.ipynb ├── cluster.py ├── generate_prediction_pytorch.py ├── generate_prediction_pytorch_supervised.py ├── generate_prediction_tf.py ├── generate_super.sh ├── plots.ipynb ├── requirements.txt ├── torch_utils.py └── visual_utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | .hypothesis/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | .static_storage/ 58 | .media/ 59 | local_settings.py 60 | 61 | # Flask stuff: 62 | instance/ 63 | .webassets-cache 64 | 65 | # Scrapy stuff: 66 | .scrapy 67 | 68 | # Sphinx documentation 69 | docs/_build/ 70 | 71 | # PyBuilder 72 | target/ 73 | 74 | # Jupyter Notebook 75 | .ipynb_checkpoints 76 | 77 | # pyenv 78 | .python-version 79 | 80 | # celery beat schedule file 81 | celerybeat-schedule 82 | 83 | # SageMath parsed files 84 | *.sage.py 85 | 86 | # Environments 87 | .env 88 | .venv 89 | env/ 90 | venv/ 91 | ENV/ 92 | env.bak/ 93 | venv.bak/ 94 | 95 | # Spyder project settings 96 | .spyderproject 97 | .spyproject 98 | 99 | # Rope project settings 100 | .ropeproject 101 | 102 | # mkdocs documentation 103 | /site 104 | 105 | # mypy 106 | .mypy_cache/ 107 | 108 | .idea/ 109 | data/ 110 | results/ 111 | checkpoints/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "PyContrast"] 2 | path = PyContrast 3 | url = https://github.com/HobbitLong/PyContrast.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Evgenii Zheltonozhskii 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Self-Supervised Learning for Large-Scale Unsupervised Image Clustering 2 | [![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/self-supervised-learning-for-large-scale/unsupervised-image-classification-on)](https://paperswithcode.com/sota/unsupervised-image-classification-on?p=self-supervised-learning-for-large-scale) 3 | [![PWC](https://img.shields.io/endpoint.svg?url=https://paperswithcode.com/badge/self-supervised-learning-for-large-scale/unsupervised-image-classification-on-imagenet)](https://paperswithcode.com/sota/unsupervised-image-classification-on-imagenet?p=self-supervised-learning-for-large-scale) 4 | 5 | This is code to run experiments for paper ["Self-Supervised Learning for Large-Scale Unsupervised Image Clustering"](https://arxiv.org/abs/2008.10312). 6 | 7 | # Running the code 8 | For part of the models, you'll need to download the chekpoints manually: 9 | - SimCLR models: https://github.com/google-research/simclr 10 | - MoCo and InfoMin models: https://github.com/HobbitLong/PyContrast/blob/master/pycontrast/docs/MODEL_ZOO.md 11 | - SwAV models: https://github.com/facebookresearch/swav 12 | 13 | and put them in chekpoint folder. 14 | 15 | For SimCLRv2, BigBiGAN as well as supervised models checkpoints are downloaded automatically. 16 | 17 | ## Download the code and install dependencies 18 | Remember to clone the submodules by running 19 | ``` 20 | git clone --recurse-submodules https://github.com/Randl/kmeans_selfsuper.git 21 | ``` 22 | during cloning the repo, or, if you forgot to do it, by running 23 | ``` 24 | git submodule update --init --recursive 25 | ``` 26 | in the repo folder. 27 | 28 | You'll need to install dependencies, by running 29 | ``` 30 | pip install -r requirements.txt 31 | ``` 32 | ## Generating features 33 | For SimCLRv2 and BigBiGAN run 34 | ``` 35 | python3 generate_prediction_tf.py --model resnet152_simclr2 36 | python3 generate_prediction_tf.py --model resnet50_simclr2 37 | python3 generate_prediction_tf.py --model resnet152x3_simclr2 38 | python3 generate_prediction_tf.py --model resnet50_bigbigan 39 | python3 generate_prediction_tf.py --model revnet50x4_bigbigan 40 | ``` 41 | For InfoMin, MoCo v2 and SwAV, run 42 | ``` 43 | python3 generate_prediction_pytorch.py --model resnext152_infomin 44 | python3 generate_prediction_pytorch.py --model resnet50_infomin 45 | python3 generate_prediction_pytorch.py --model resnet50_mocov2 46 | python3 generate_prediction_pytorch.py --model resnet50_swav 47 | ``` 48 | Finally, for supervised models, run 49 | ``` 50 | python3 generate_prediction_pytorch_supervised.py --model tf_efficientnet_l2_ns_475 51 | python3 generate_prediction_pytorch_supervised.py --model gluon_resnet152_v1s 52 | python3 generate_prediction_pytorch_supervised.py --model ig_resnext101_32x48d 53 | ``` 54 | You'll need large amount of RAM since the script keeps features in memory. It was tested on machine with 128 GB RAM. 55 | ## Running clustering 56 | To run clustering, you need to run 57 | ``` 58 | python3 cluster.py --model resnet50_infomin 59 | ``` 60 | where the model name should fit the name in generating part. For overclustering, e.g., 1.25 times more clusters 61 | than classes, run 62 | ``` 63 | python3 cluster.py --model resnet152_simclr2 --over 1.25 64 | ``` 65 | For using smaller dimensions of features, e.g., 512, run 66 | ``` 67 | python3 cluster.py --model resnet152_simclr2 --n-components 512 68 | ``` 69 | # Citing the paper 70 | If you found the paper or the code useful, please cite it. You can use following bibtex entry: 71 | ``` 72 | @article{zheltonozhskii2020unsupervised, 73 | title = {Self-Supervised Learning for Large-Scale Unsupervised Image Clustering}, 74 | author = {Zheltonozhskii, Evgenii and Baskin, Chaim and Bronstein, Alex M. and Mendelson, Avi}, 75 | journal = {NeurIPS Self-Supervised Learning Workshop}, 76 | year = {2020}, 77 | month = aug, 78 | url = {https://arxiv.org/abs/2008.10312}, 79 | code = {https://github.com/Randl/kmeans_selfsuper}, 80 | arxiv = {2008.10312}, 81 | } 82 | ``` 83 | -------------------------------------------------------------------------------- /cluster.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import gc 3 | import os 4 | import time 5 | 6 | import numpy as np 7 | import sklearn 8 | from scipy.optimize import linear_sum_assignment 9 | from sklearn import cluster 10 | from sklearn.datasets import make_blobs 11 | from sklearn.decomposition import IncrementalPCA 12 | from sklearn.model_selection import train_test_split 13 | from sklearn.utils import shuffle 14 | from tqdm import trange, tqdm 15 | 16 | from torch_utils import get_loaders_objectnet 17 | 18 | np.set_printoptions(threshold=np.inf) 19 | 20 | model_names = set(filename.split('.')[0].replace('_pca', '') for filename in os.listdir('./results')) 21 | 22 | parser = argparse.ArgumentParser(description='IM') 23 | parser.add_argument('--model', dest='model', type=str, default='resnext152_infomin', 24 | help='Model: one of' + ', '.join(model_names)) 25 | parser.add_argument('--over', type=float, default=1., help='Mutiplier for number of clusters') 26 | parser.add_argument('--n-components', type=int, default=None, help='Number of components for PCA') 27 | args = parser.parse_args() 28 | print(args) 29 | 30 | n_classes = 1000 31 | n_clusters = int(args.over * n_classes) 32 | n_classes_objectnet = 313 33 | n_clusters_objectnet = int(args.over * n_classes_objectnet) 34 | train_size = 12811 # 67 35 | val_size = 500 # 00 36 | 37 | epochs = 60 38 | 39 | n_features = 2048 40 | batch_size = max(2048, int(2 ** np.ceil(np.log2(n_clusters)))) 41 | 42 | 43 | def get_cost_matrix(y_pred, y, nc=1000): 44 | C = np.zeros((nc, y.max() + 1)) 45 | for pred, label in zip(y_pred, y): 46 | C[pred, label] += 1 47 | return C 48 | 49 | 50 | def get_cost_matrix_objectnet(y_pred, y, objectnet_to_imagenet): 51 | C = np.zeros((n_clusters, y.max() + 1)) 52 | ny, nyp = [], [] 53 | for pred, label in zip(y_pred, y): 54 | if len(objectnet_to_imagenet[label]) > 0: 55 | C[pred, label] += 1 56 | ny.append(label) 57 | nyp.append(pred) 58 | return C, np.array(nyp), np.array(ny) 59 | 60 | 61 | def get_best_clusters(C, k=3): 62 | Cpart = C / (C.sum(axis=1, keepdims=True) + 1e-5) 63 | Cpart[C.sum(axis=1) < 10, :] = 0 64 | # print('as', np.argsort(Cpart, axis=None)[::-1]) 65 | ind = np.unravel_index(np.argsort(Cpart, axis=None)[::-1], Cpart.shape)[0] # indices of good clusters 66 | _, idx = np.unique(ind, return_index=True) 67 | cluster_idx = ind[np.sort(idx)] # unique indices of good clusters 68 | accs = Cpart.max(axis=1)[cluster_idx] 69 | good_clusters = cluster_idx[:k] 70 | print('Best clusters accuracy: {}'.format(Cpart[good_clusters].max(axis=1))) 71 | print('Best clusters classes: {}'.format(Cpart[good_clusters].argmax(axis=1))) 72 | return good_clusters 73 | 74 | 75 | def get_worst_clusters(C, k=3): 76 | Cpart = C / (C.sum(axis=1, keepdims=True) + 1e-5) 77 | Cstd = Cpart.std(axis=1) 78 | Cstd[C.sum(axis=1) < 10] = 1000 79 | cluster_idx = np.argsort(Cstd) # low std -- closer to uniform 80 | return cluster_idx[:k] 81 | 82 | 83 | def print_cluster(ci, y_pred, text): 84 | idx = np.where(y_pred == ci)[0] 85 | print('{}: {}'.format(text, idx)) 86 | 87 | 88 | def assign_classes_hungarian(C): 89 | row_ind, col_ind = linear_sum_assignment(C, maximize=True) 90 | ri, ci = np.arange(C.shape[0]), np.zeros(C.shape[0]) 91 | ci[row_ind] = col_ind 92 | 93 | # for overclustering, rest is assigned to best matching class 94 | mask = np.ones(C.shape[0], dtype=bool) 95 | mask[row_ind] = False 96 | ci[mask] = C[mask, :].argmax(1) 97 | return ri.astype(int), ci.astype(int) 98 | 99 | 100 | def assign_classes_majority(C): 101 | col_ind = C.argmax(1) 102 | row_ind = np.arange(C.shape[0]) 103 | 104 | # best matching class for every cluster 105 | mask = np.ones(C.shape[0], dtype=bool) 106 | mask[row_ind] = False 107 | 108 | return row_ind.astype(int), col_ind.astype(int) 109 | 110 | 111 | def imagenet_assignment_to_objectnet(row_ind, col_ind, imagenet_to_objectnet): 112 | nri, nci = [], [] 113 | for i, (ri, ci) in enumerate(zip(row_ind, col_ind)): 114 | if imagenet_to_objectnet[ci] > 0: 115 | nri.append(ri) 116 | nci.append(imagenet_to_objectnet[ci]) 117 | return np.array(nri), np.array(nci) 118 | 119 | 120 | def accuracy_from_assignment(C, row_ind, col_ind, set_size=None): 121 | if set_size is None: 122 | set_size = C.sum() 123 | cnt = C[row_ind, col_ind].sum() 124 | return cnt / set_size 125 | 126 | 127 | def batches(l, n): 128 | for i in range(0, len(l), n): 129 | yield l[i:i + n] 130 | 131 | 132 | def print_metrics(message, y_pred, y_true, train_lin_assignment, train_maj_assignment, val_lin_assignment=None, 133 | val_maj_assignment=None, objectnet=False, imagenet_to_objectnet=None, objectnet_to_imagenet=None): 134 | if objectnet: 135 | C, y_pred, y_true = get_cost_matrix_objectnet(y_pred, y_true, objectnet_to_imagenet) 136 | train_lin_assignment = imagenet_assignment_to_objectnet(*train_lin_assignment, imagenet_to_objectnet) 137 | train_maj_assignment = imagenet_assignment_to_objectnet(*train_maj_assignment, imagenet_to_objectnet) 138 | else: 139 | C = get_cost_matrix(y_pred, y_true, n_clusters) 140 | 141 | # for r,c in zip(*train_lin_assignment): 142 | # print(r,c) 143 | acc_tr_lin = accuracy_from_assignment(C, *train_lin_assignment) 144 | acc_tr_maj = accuracy_from_assignment(C, *train_maj_assignment) 145 | if val_lin_assignment is not None: 146 | acc_va_lin = accuracy_from_assignment(C, *val_lin_assignment) 147 | acc_va_maj = accuracy_from_assignment(C, *val_maj_assignment) 148 | else: 149 | acc_va_lin, acc_va_maj = 0, 0 150 | 151 | # confusion_mat(C, *train_lin_assignment, name=args.model) 152 | 153 | ari = sklearn.metrics.adjusted_rand_score(y_true, y_pred) 154 | v_measure = sklearn.metrics.v_measure_score(y_true, y_pred) 155 | ami = sklearn.metrics.adjusted_mutual_info_score(y_true, y_pred) 156 | fm = sklearn.metrics.fowlkes_mallows_score(y_true, y_pred) 157 | 158 | print("{}: ARI {:.5e}\tV {:.5e}\tAMI {:.5e}\tFM {:.5e}".format(message, ari, v_measure, ami, fm)) 159 | print("{}: ACC TR L {:.5e}\tACC TR M {:.5e}\t" 160 | "ACC VA L {:.5e}\tACC VA M {:.5e}".format(message, acc_tr_lin, acc_tr_maj, acc_va_lin, acc_va_maj)) 161 | 162 | if message == 'ont': 163 | ri, ci = train_lin_assignment 164 | both = np.zeros(len(ci), dtype=bool) 165 | y = [s for s in objectnet_to_imagenet if len(objectnet_to_imagenet[s]) > 0] 166 | for i in range(len(ci)): 167 | if ci[i] in y: 168 | both[i] = 1 169 | 170 | acc_both = accuracy_from_assignment(C, ri[both], ci[both], C[:, ci[both]].sum()) 171 | acc_obj = accuracy_from_assignment(C, ri[~both], ci[~both], C[:, ci[~both]].sum()) 172 | print("{}: ACC both {:.5e}\tACC obj {:.5e}".format(message, acc_both, acc_obj)) 173 | 174 | best = get_best_clusters(C, k=3) 175 | worst = get_worst_clusters(C, k=3) 176 | return best, worst 177 | 178 | 179 | def train_pca(X_train): 180 | bs = max(4096, X_train.shape[1] * 2) 181 | transformer = IncrementalPCA(batch_size=bs) # 182 | for i, batch in enumerate(tqdm(batches(X_train, bs), total=len(X_train) // bs + 1)): 183 | transformer = transformer.partial_fit(batch) 184 | # break 185 | print(transformer.explained_variance_ratio_.cumsum()) 186 | return transformer 187 | 188 | 189 | def cluster_data(X_train, y_train, X_test, y_test, X_test2, y_test2, imagenet_to_objectnet, objectnet_to_imagenet): 190 | minib_k_means = cluster.MiniBatchKMeans(n_clusters=n_clusters, batch_size=batch_size, max_no_improvement=None) 191 | 192 | # TODO: save to csv 193 | for e in trange(epochs): 194 | X_train, y_train = shuffle(X_train, y_train) 195 | for batch in batches(X_train, batch_size): 196 | minib_k_means = minib_k_means.partial_fit(batch) 197 | 198 | pred = minib_k_means.predict(X_train) 199 | C_train = get_cost_matrix(pred, y_train, n_clusters) 200 | 201 | y_pred = minib_k_means.predict(X_test) 202 | C_val = get_cost_matrix(y_pred, y_test, n_clusters) 203 | 204 | y_pred2 = minib_k_means.predict(X_test2) 205 | C_val2, _, _ = get_cost_matrix_objectnet(y_pred2, y_test2, objectnet_to_imagenet) 206 | 207 | best_im, worst_im = print_metrics('val', y_pred, y_test, assign_classes_hungarian(C_train), 208 | assign_classes_majority(C_train), assign_classes_hungarian(C_val), 209 | assign_classes_majority(C_val)) 210 | best_obj, worst_obj = print_metrics('on', y_pred2, y_test2, assign_classes_hungarian(C_train), 211 | assign_classes_majority(C_train), assign_classes_hungarian(C_val2), 212 | assign_classes_majority(C_val2), objectnet=True, 213 | imagenet_to_objectnet=imagenet_to_objectnet, 214 | objectnet_to_imagenet=objectnet_to_imagenet) 215 | 216 | for i, cli in enumerate(best_im): 217 | print_cluster(cli, y_pred, 'best imagenet cluster #{}, imagenet index:'.format(i)) 218 | print_cluster(cli, y_pred2, 'best imagenet cluster #{}, objectnet index:'.format(i)) 219 | for i, cli in enumerate(worst_im): 220 | print_cluster(cli, y_pred, 'worst imagenet cluster #{}, imagenet index:'.format(i)) 221 | print_cluster(cli, y_pred2, 'worst imagenet cluster #{}, objectnet index:'.format(i)) 222 | if False: 223 | for i, cli in enumerate(best_obj): 224 | print_cluster(cli, y_pred, 'best objectnet cluster #{}, imagenet index:'.format(i)) 225 | print_cluster(cli, y_pred2, 'best objectnet cluster #{}, objectnet index:'.format(i)) 226 | for i, cli in enumerate(worst_obj): 227 | print_cluster(cli, y_pred, 'worst objectnet cluster #{}, imagenet index:'.format(i)) 228 | print_cluster(cli, y_pred2, 'worst objectnet cluster #{}, objectnet index:'.format(i)) 229 | 230 | 231 | def cluster_training_data(X_train, y_train, objectnet_to_imagenet): 232 | minib_k_means = cluster.MiniBatchKMeans(n_clusters=n_clusters_objectnet, batch_size=batch_size, 233 | max_no_improvement=None) 234 | 235 | for e in trange(epochs): 236 | X_train, y_train = shuffle(X_train, y_train) 237 | for batch in batches(X_train, batch_size): 238 | minib_k_means = minib_k_means.partial_fit(batch) 239 | 240 | pred = minib_k_means.predict(X_train) 241 | C_train = get_cost_matrix(pred, y_train, nc=n_clusters_objectnet) 242 | 243 | print_metrics('ont', pred, y_train, assign_classes_hungarian(C_train), assign_classes_majority(C_train), 244 | objectnet_to_imagenet=objectnet_to_imagenet) 245 | 246 | 247 | def transform_pca(X, transformer): 248 | n = max(4096, X.shape[1] * 2) 249 | for i in trange(0, len(X), n): 250 | X[i:i + n] = transformer.transform(X[i:i + n]) 251 | # break 252 | return X 253 | 254 | 255 | generate = False 256 | if generate: 257 | pass 258 | else: 259 | filename = 'results/' + args.model + '_pca.npz' 260 | if not os.path.exists(filename): 261 | 262 | t0 = time.time() 263 | path = 'results/' + args.model + '.npz' 264 | data = np.load(path) 265 | X_train, y_train, X_test, y_test, X_test2, y_test2 = data['train_embs'], data['train_labs'], data['val_embs'], \ 266 | data['val_labs'], data['obj_embs'], data['obj_labs'] 267 | t1 = time.time() 268 | print(path) 269 | print('Loading time: {:.6f}'.format(t1 - t0)) 270 | 271 | if len(y_train.shape) > 1: 272 | y_train, y_test, y_test2 = y_train.argmax(1), y_test.argmax(1), y_test2.argmax(1) 273 | X_train, y_train, X_test, y_test, X_test2, y_test2 = X_train.squeeze(), y_train.squeeze(), X_test.squeeze(), y_test.squeeze(), X_test2.squeeze(), y_test2.squeeze() 274 | transformer = train_pca(X_train) 275 | X_train, X_test = transform_pca(X_train, transformer), transform_pca(X_test, transformer) 276 | gc.collect() 277 | np.savez(filename, train_embs=X_train, train_labs=y_train, val_embs=X_test, val_labs=y_test, obj_embs=X_test2, 278 | obj_labs=y_test2, PCA=transformer) 279 | else: 280 | t0 = time.time() 281 | data = np.load(filename) 282 | print(filename) 283 | X_train, y_train, X_test, y_test, X_test2, y_test2 = data['train_embs'], data['train_labs'], data['val_embs'], \ 284 | data['val_labs'], data['obj_embs'], data['obj_labs'] 285 | # print(y_test2.shape, y_test2, y_test2.max()) 286 | if len(y_test2.shape) > 1: 287 | y_test2 = y_test2.argmax(1) 288 | t1 = time.time() 289 | print('Loading time: {:.6f}'.format(t1 - t0)) 290 | if args.n_components is not None: 291 | X_train, X_test, X_test2 = X_train[:, :args.n_components], X_test[:, :args.n_components], X_test2[:, 292 | :args.n_components] 293 | 294 | objectnet_path = '/home/chaimb/objectnet-1.0' 295 | imagenet_path = '/home/chaimb/ILSVRC/Data/CLS-LOC' 296 | val_loader, imagenet_to_objectnet, objectnet_to_imagenet, objectnet_both, imagenet_both = get_loaders_objectnet( 297 | objectnet_path, imagenet_path, 16, 224, 8, 1, 0) 298 | cluster_data(X_train, y_train, X_test, y_test, X_test2, y_test2, imagenet_to_objectnet, objectnet_to_imagenet) 299 | cluster_training_data(X_test2, y_test2, objectnet_to_imagenet) 300 | -------------------------------------------------------------------------------- /generate_prediction_pytorch.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | from types import SimpleNamespace 4 | 5 | import numpy as np 6 | import torch 7 | from torch import nn 8 | from tqdm import tqdm 9 | 10 | from PyContrast.pycontrast.networks.build_backbone import build_model 11 | from torch_utils import get_loaders_imagenet, get_loaders_objectnet 12 | 13 | device, dtype = 'cuda:0', torch.float32 14 | 15 | 16 | def get_model(model='resnet50_infomin'): 17 | if model == 'resnet50_infomin': 18 | args = SimpleNamespace() 19 | 20 | args.jigsaw = True 21 | args.arch, args.head, args.feat_dim = 'resnet50', 'mlp', 128 22 | args.mem = 'moco' 23 | args.modal = 'RGB' 24 | model, _ = build_model(args) 25 | cp = torch.load('checkpoints/InfoMin_800.pth') 26 | 27 | sd = cp['model'] 28 | new_sd = {} 29 | for entry in sd: 30 | new_sd[entry.replace('module.', '')] = sd[entry] 31 | model.load_state_dict(new_sd, strict=False) # no head, don't need linear model 32 | 33 | model = model.to(device=device) 34 | return model 35 | elif model == 'resnext152_infomin': 36 | args = SimpleNamespace() 37 | 38 | args.jigsaw = True 39 | args.arch, args.head, args.feat_dim = 'resnext152v1', 'mlp', 128 40 | args.mem = 'moco' 41 | args.modal = 'RGB' 42 | model, _ = build_model(args) 43 | cp = torch.load('checkpoints/InfoMin_resnext152v1_e200.pth') 44 | 45 | sd = cp['model'] 46 | new_sd = {} 47 | for entry in sd: 48 | new_sd[entry.replace('module.', '')] = sd[entry] 49 | model.load_state_dict(new_sd, strict=False) # no head, don't need linear model 50 | 51 | model = model.to(device=device) 52 | return model 53 | elif model == 'resnet50_mocov2': 54 | args = SimpleNamespace() 55 | 56 | args.jigsaw = False 57 | args.arch, args.head, args.feat_dim = 'resnet50', 'linear', 2048 58 | args.mem = 'moco' 59 | args.modal = 'RGB' 60 | model, _ = build_model(args) 61 | cp = torch.load('checkpoints/MoCov2.pth') 62 | 63 | sd = cp['model'] 64 | new_sd = {} 65 | for entry in sd: 66 | new_sd[entry.replace('module.', '')] = sd[entry] 67 | model.load_state_dict(new_sd, strict=False) # no head, don't need linear model 68 | 69 | model = model.to(device=device) 70 | return model 71 | elif model == 'resnet50_swav': 72 | model = torch.hub.load('facebookresearch/swav', 'resnet50') 73 | modules = list(model.children())[:-1] 74 | model = nn.Sequential(*modules) 75 | model = model.to(device=device) 76 | return model 77 | else: 78 | raise ValueError('Wrong model') 79 | 80 | 81 | def eval_swav(model, loader): 82 | reses = [] 83 | labs = [] 84 | 85 | for batch_idx, (data, target) in enumerate(tqdm(loader)): 86 | data, target = data.to(device=device, dtype=dtype), target.to(device=device) 87 | 88 | output = model.forward(data) 89 | reses.append(output.detach().cpu().numpy()) 90 | labs.append(target.detach().cpu().numpy()) 91 | 92 | rss = np.concatenate(reses, axis=0) 93 | lbs = np.concatenate(labs, axis=0) 94 | return rss, lbs 95 | 96 | 97 | def eval(model, loader, kwargs): 98 | reses = [] 99 | labs = [] 100 | 101 | for batch_idx, (data, target) in enumerate(tqdm(loader)): 102 | data, target = data.to(device=device, dtype=dtype), target.to(device=device) 103 | 104 | output = model.forward(data, mode=2) 105 | reses.append(output.detach().cpu().numpy()) 106 | labs.append(target.detach().cpu().numpy()) 107 | 108 | rss = np.concatenate(reses, axis=0) 109 | lbs = np.concatenate(labs, axis=0) 110 | return rss, lbs 111 | 112 | 113 | imagenet_path = '/home/vista/Datasets/ILSVRC/Data/CLS-LOC' 114 | imagenet_path = '/home/chaimb/ILSVRC/Data/CLS-LOC' 115 | objectnet_path = '/home/chaimb/objectnet-1.0' 116 | 117 | 118 | def eval_and_save(model='resnet50_infomin'): 119 | mdl = get_model(model) 120 | bs = 32 if model in ['resnet50_infomin'] else 16 121 | train_loader, val_loader = get_loaders_imagenet(imagenet_path, bs, bs, 224, 8, 1, 0) 122 | obj_loader, _, _, _, _ = get_loaders_objectnet(objectnet_path, imagenet_path, bs, 224, 8, 1, 0) 123 | eval_f = eval_swav if 'swav' in model else eval 124 | train_embs, train_labs = eval_f(mdl, train_loader) 125 | val_embs, val_labs = eval_f(mdl, val_loader) 126 | obj_embs, obj_labs = eval_f(mdl, obj_loader) 127 | os.makedirs('./results', exist_ok=True) 128 | np.savez(os.path.join('./results', model + '.npz'), train_embs=train_embs, train_labs=train_labs, val_embs=val_embs, 129 | val_labs=val_labs, obj_embs=obj_embs, obj_labs=obj_labs) 130 | 131 | 132 | models = ['resnet50_infomin', 'resnext152_infomin', 'resnet50_mocov2', 'resnet50_swav'] 133 | parser = argparse.ArgumentParser(description='IM') 134 | parser.add_argument('--model', dest='model', type=str, default='resnext152_infomin', 135 | help='Model: one of ' + ', '.join(models)) 136 | args = parser.parse_args() 137 | 138 | eval_and_save(args.model) 139 | -------------------------------------------------------------------------------- /generate_prediction_pytorch_supervised.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | from types import SimpleNamespace 4 | 5 | import numpy as np 6 | import torch 7 | from tqdm import tqdm 8 | import torch.nn.functional as F 9 | from PyContrast.pycontrast.networks.build_backbone import build_model 10 | from torch_utils import get_loaders_imagenet, get_loaders_objectnet 11 | 12 | device, dtype = 'cuda:0', torch.float32 13 | gh = 'rwightman/pytorch-image-models' 14 | 15 | def get_model(model='resnet50_infomin'): 16 | if model == 'resnet50_infomin': 17 | args = SimpleNamespace() 18 | 19 | args.jigsaw = True 20 | args.arch, args.head, args.feat_dim = 'resnet50', 'mlp', 128 21 | args.mem = 'moco' 22 | args.modal = 'RGB' 23 | model, _ = build_model(args) 24 | cp = torch.load('checkpoints/InfoMin_800.pth') 25 | 26 | sd = cp['model'] 27 | new_sd = {} 28 | for entry in sd: 29 | new_sd[entry.replace('module.', '')] = sd[entry] 30 | model.load_state_dict(new_sd, strict=False) # no head, don't need linear model 31 | 32 | model = model.to(device=device) 33 | return model 34 | elif model == 'resnext152_infomin': 35 | args = SimpleNamespace() 36 | 37 | args.jigsaw = True 38 | args.arch, args.head, args.feat_dim = 'resnext152v1', 'mlp', 128 39 | args.mem = 'moco' 40 | args.modal = 'RGB' 41 | model, _ = build_model(args) 42 | cp = torch.load('checkpoints/InfoMin_resnext152v1_e200.pth') 43 | 44 | sd = cp['model'] 45 | new_sd = {} 46 | for entry in sd: 47 | new_sd[entry.replace('module.', '')] = sd[entry] 48 | model.load_state_dict(new_sd, strict=False) # no head, don't need linear model 49 | 50 | model = model.to(device=device) 51 | return model 52 | elif model == 'resnet50_mocov2': 53 | args = SimpleNamespace() 54 | 55 | args.jigsaw = False 56 | args.arch, args.head, args.feat_dim = 'resnet50', 'linear', 2048 57 | args.mem = 'moco' 58 | args.modal = 'RGB' 59 | model, _ = build_model(args) 60 | cp = torch.load('checkpoints/MoCov2.pth') 61 | 62 | sd = cp['model'] 63 | new_sd = {} 64 | for entry in sd: 65 | new_sd[entry.replace('module.', '')] = sd[entry] 66 | model.load_state_dict(new_sd, strict=False) # no head, don't need linear model 67 | 68 | model = model.to(device=device) 69 | return model 70 | else: 71 | raise ValueError('Wrong model') 72 | 73 | 74 | def eval(model, loader): 75 | reses = [] 76 | labs = [] 77 | with torch.no_grad(): 78 | for batch_idx, (data, target) in enumerate(tqdm(loader)): 79 | data, target = data.to(device=device, dtype=dtype), target.to(device=device) 80 | 81 | output = model.forward_features(data) 82 | output = F.adaptive_avg_pool2d(output, output_size=(1,1)).view(output.shape[0], -1) 83 | reses.append(output.detach().cpu().numpy()) 84 | labs.append(target.detach().cpu().numpy()) 85 | 86 | rss = np.concatenate(reses, axis=0) 87 | lbs = np.concatenate(labs, axis=0) 88 | return rss, lbs 89 | 90 | 91 | imagenet_path = '/home/vista/Datasets/ILSVRC/Data/CLS-LOC' 92 | imagenet_path = '/home/chaimb/ILSVRC/Data/CLS-LOC' 93 | objectnet_path = '/home/chaimb/objectnet-1.0' 94 | 95 | bss = {'tf_efficientnet_l2_ns_475': 8, 'gluon_resnet152_v1s': 16, 'ig_resnext101_32x48d': 16} 96 | def eval_and_save(model='resnet50_infomin', dim=224): 97 | mdl = torch.hub.load(gh, model, pretrained=True).cuda() 98 | bs = 16 99 | train_loader, val_loader = get_loaders_imagenet(imagenet_path, bs, bs, dim, 8, 1, 0) 100 | obj_loader, _, _, _, _ = get_loaders_objectnet(objectnet_path, imagenet_path, bs, dim, 8, 1, 0) 101 | train_embs, train_labs = eval(mdl, train_loader) 102 | val_embs, val_labs = eval(mdl, val_loader) 103 | obj_embs, obj_labs = eval(mdl, obj_loader) 104 | os.makedirs('./results', exist_ok=True) 105 | np.savez(os.path.join('./results', model + '_super.npz'), train_embs=train_embs, train_labs=train_labs, val_embs=val_embs, 106 | val_labs=val_labs, obj_embs=obj_embs, obj_labs=obj_labs) 107 | 108 | 109 | models = torch.hub.list(gh) 110 | # models to run: 111 | # tf_efficientnet_l2_ns_475 112 | # gluon_resnet152_v1s 113 | # ig_resnext101_32x48d 114 | parser = argparse.ArgumentParser(description='IM') 115 | parser.add_argument('--model', dest='model', type=str, default='resnext152_infomin', 116 | help='Model: one of ' + ', '.join(models)) 117 | args = parser.parse_args() 118 | 119 | dims = {'tf_efficientnet_l2_ns_475': 475, 'gluon_resnet152_v1s': 224, 'ig_resnext101_32x48d': 224} 120 | eval_and_save(args.model, dim=dims[args.model]) 121 | -------------------------------------------------------------------------------- /generate_prediction_tf.py: -------------------------------------------------------------------------------- 1 | #%% 2 | import argparse 3 | import json 4 | import os 5 | import pathlib 6 | import zipfile 7 | from functools import partial 8 | 9 | import matplotlib.pyplot as plt 10 | import numpy as np 11 | import requests 12 | import tensorflow as tf 13 | import tensorflow_hub as hub 14 | from tqdm import tqdm, trange 15 | 16 | imagenet_path = '/home/vista/Datasets/ILSVRC/Data/CLS-LOC' 17 | imagenet_path = '/home/chaimb/ILSVRC/Data/CLS-LOC' 18 | objectnet_path = '/home/chaimb/objectnet-1.0' 19 | 20 | 21 | #%% 22 | 23 | def download_file(url, filename=False, verbose=False): 24 | """ 25 | Download file with progressbar 26 | 27 | Usage: 28 | download_file('http://web4host.net/5MB.zip') 29 | """ 30 | if not filename: 31 | local_filename = os.path.join(".", url.split('/')[-1]) 32 | else: 33 | local_filename = filename 34 | 35 | response = requests.get(url, stream=True) 36 | 37 | with open(filename, "wb") as handle: 38 | for data in tqdm(response.iter_content()): 39 | handle.write(data) 40 | return 41 | 42 | 43 | #%% 44 | 45 | # test 46 | IMAGE_SHAPE = (224, 224) 47 | train_dir = pathlib.Path(os.path.join(imagenet_path, 'train')) 48 | val_dir = pathlib.Path(os.path.join(imagenet_path, 'val')) 49 | object_dir = pathlib.Path(os.path.join(objectnet_path, 'images')) 50 | 51 | #%% 52 | 53 | assert val_dir.exists() 54 | assert train_dir.exists() 55 | assert object_dir.exists() 56 | 57 | #%% 58 | 59 | CLASS_NAMES = np.array([item.name for item in train_dir.glob('*') if item.name != "LICENSE.txt"]) 60 | CLASS_NAMES_OBJ = np.array([item.name for item in object_dir.glob('*') if item.name != "LICENSE.txt"]) 61 | 62 | #%% 63 | 64 | 65 | map_url = 'https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json' 66 | response = json.loads(requests.get(map_url).text) 67 | name_map = {} 68 | name_to_num = {} 69 | for r in response: 70 | name_map[response[r][0]] = response[r][1] 71 | name_to_num[response[r][1]] = response[r][0] 72 | 73 | 74 | #%% 75 | 76 | 77 | def show_batch(image_batch, label_batch): 78 | plt.figure(figsize=(10, 10)) 79 | for n in range(25): 80 | ax = plt.subplot(5, 5, n + 1) 81 | plt.imshow(image_batch[n]) 82 | plt.title(name_map[CLASS_NAMES[label_batch[n] == 1][0].title().lower()]) 83 | plt.axis('off') 84 | 85 | 86 | #%% 87 | 88 | def get_label(file_path): 89 | # convert the path to a list of path components 90 | parts = tf.strings.split(file_path, os.path.sep) 91 | # The second to last is the class-directory 92 | return parts[-2] == CLASS_NAMES 93 | 94 | 95 | def get_label_objectnet(file_path): 96 | # convert the path to a list of path components 97 | parts = tf.strings.split(file_path, os.path.sep) 98 | # The second to last is the class-directory 99 | return parts[-2] == CLASS_NAMES_OBJ 100 | 101 | 102 | def crop_center_and_resize(img, size, scale=0.875): 103 | s = tf.shape(img) 104 | w, h = s[0], s[1] 105 | c = tf.maximum(w, h) 106 | wn, hn = h / c * scale, w / c * scale 107 | result = tf.image.crop_and_resize(tf.expand_dims(img, 0), 108 | [[(1 - wn) / 2, (1 - hn) / 2, wn, hn]], 109 | [0], [size, size]) 110 | return tf.squeeze(result, 0) 111 | 112 | 113 | def decode_img(img, IMG_HEIGHT=224, IMG_WIDTH=224, pm1=False, crop=True): 114 | # convert the compressed string to a 3D uint8 tensor 115 | img = tf.image.decode_jpeg(img, channels=3) 116 | # Use `convert_image_dtype` to convert to floats in the [0,1] range. 117 | if pm1: 118 | img = tf.cast(img, tf.float32) / (255. / 2.) - 1 119 | else: 120 | img = tf.image.convert_image_dtype(img, tf.float32) 121 | if IMG_HEIGHT == 256: 122 | SIZE = 292 123 | else: 124 | SIZE = 256 125 | # resize the image to the desired size. 126 | if crop: 127 | return crop_center_and_resize(img, IMG_HEIGHT) 128 | else: 129 | return tf.image.resize_with_pad(img, IMG_HEIGHT, IMG_HEIGHT) 130 | 131 | 132 | def process_path(file_path, bbg=False, label_function=get_label): 133 | label = label_function(file_path) 134 | # load the raw data from the file as a string 135 | img = tf.io.read_file(file_path) 136 | if bbg: 137 | img = decode_img(img, 256, 256, True) 138 | else: 139 | img = decode_img(img) 140 | return img, label 141 | 142 | 143 | def prepare_for_eval(ds, batch_size): 144 | ds = ds.batch(batch_size) 145 | 146 | # `prefetch` lets the dataset fetch batches in the background while the model 147 | # is training. 148 | ds = ds.prefetch(buffer_size=640) 149 | 150 | return ds 151 | 152 | 153 | #%% 154 | 155 | 156 | def get_datasets(bbg=False): 157 | BATCH_SIZE = 32 158 | process = partial(process_path, bbg=bbg, label_function=get_label) 159 | process_obj = partial(process_path, bbg=bbg, label_function=get_label_objectnet) 160 | 161 | list_ds = tf.data.Dataset.list_files(str(train_dir / '*/*'), shuffle=False) 162 | # Set `num_parallel_calls` so multiple images are loaded/processed in parallel. 163 | labeled_ds = list_ds.map(process, num_parallel_calls=8) 164 | 165 | train_ds = prepare_for_eval(labeled_ds, BATCH_SIZE) 166 | 167 | list_val_ds = tf.data.Dataset.list_files(str(val_dir / '*/*'), shuffle=False) 168 | # Set `num_parallel_calls` so multiple images are loaded/processed in parallel. 169 | labeled_val_ds = list_val_ds.map(process, num_parallel_calls=8) 170 | 171 | val_ds = prepare_for_eval(labeled_val_ds, BATCH_SIZE) 172 | 173 | list_obj_ds = tf.data.Dataset.list_files(str(object_dir / '*/*'), shuffle=False) 174 | # Set `num_parallel_calls` so multiple images are loaded/processed in parallel. 175 | labeled_obj_ds = list_obj_ds.map(process_obj, num_parallel_calls=8) 176 | 177 | obj_ds = prepare_for_eval(labeled_obj_ds, BATCH_SIZE) 178 | return train_ds, val_ds, obj_ds 179 | 180 | 181 | #%% 182 | def get_resnet50x4_simclr(): 183 | resnet50x4_url = "https://storage.cloud.google.com/simclr-gcs/checkpoints/ResNet50_1x.zip" 184 | 185 | os.makedirs('./checkpoints', exist_ok=True) 186 | 187 | resnet50x4_path = './checkpoints/checkpoints_ResNet50_4x' 188 | # download_file(resnet50_url,resnet50_path+'.zip') 189 | with zipfile.ZipFile(resnet50x4_path + '.zip', "r") as zip_ref: 190 | zip_ref.extractall('./checkpoints') 191 | 192 | resnet50x4_path = './checkpoints/ResNet50_4x' 193 | resnet50x4 = tf.keras.Sequential([ 194 | hub.KerasLayer(os.path.join(resnet50x4_path, 'hub')) 195 | ]) 196 | 197 | return resnet50x4 198 | 199 | 200 | #%% 201 | def get_resnet50_simclr(): 202 | resnet50_url = "https://storage.cloud.google.com/simclr-gcs/checkpoints/ResNet50_1x.zip" 203 | 204 | os.makedirs('./checkpoints', exist_ok=True) 205 | 206 | resnet50_path = './checkpoints/ResNet50_1x' 207 | # download_file(resnet50_url,resnet50_path+'.zip') 208 | with zipfile.ZipFile(resnet50_path + '.zip', "r") as zip_ref: 209 | zip_ref.extractall('./checkpoints') 210 | 211 | resnet50 = tf.keras.Sequential([ 212 | hub.KerasLayer(os.path.join(resnet50_path, 'hub')) 213 | ]) 214 | 215 | return resnet50 216 | 217 | 218 | #%% 219 | def get_resnet152x3_simclrv2(): 220 | module_path = 'gs://simclr-checkpoints/simclrv2/pretrained/r152_3x_sk1/hub/' # r152_3x_sk1 221 | resnet152x3 = tf.keras.Sequential([ 222 | hub.KerasLayer(module_path) 223 | ]) 224 | return resnet152x3 225 | 226 | 227 | def get_resnet50_simclrv2(): 228 | module_path = 'gs://simclr-checkpoints/simclrv2/pretrained/r50_1x_sk0/hub/' # r152_3x_sk1 229 | resnet152x3 = tf.keras.Sequential([ 230 | hub.KerasLayer(module_path) 231 | ]) 232 | return resnet152x3 233 | 234 | 235 | def get_resnet152_simclrv2(): 236 | module_path = 'gs://simclr-checkpoints/simclrv2/pretrained/r152_1x_sk1/hub/' # r152_3x_sk1 237 | resnet152x3 = tf.keras.Sequential([ 238 | hub.KerasLayer(module_path) 239 | ]) 240 | return resnet152x3 241 | 242 | 243 | #%% 244 | def get_revnet50x4_bigbigan(): 245 | module_path = 'https://tfhub.dev/deepmind/bigbigan-revnet50x4/1' # RevNet-50 x4 246 | revnet50x4 = tf.keras.Sequential([ 247 | hub.KerasLayer(module_path, signature='encode') 248 | ]) 249 | 250 | return revnet50x4 251 | 252 | 253 | def get_resnet50_bigbigan(): 254 | module_path = 'https://tfhub.dev/deepmind/bigbigan-resnet50/1' # ResNet-50 255 | resnet50 = tf.keras.Sequential([ 256 | hub.KerasLayer(module_path, signature='encode') 257 | ]) 258 | 259 | return resnet50 260 | 261 | 262 | #%% 263 | models = ['resnet50_simclr', 'resnet50x4_simclr', 'revnet50x4_bigbigan', 'resnet50_simclr2', 'resnet152_simclr2', 264 | 'resnet152x3_simclr2'] 265 | 266 | 267 | def get_model(model='resnet50_simclr'): 268 | if model == 'resnet50_simclr': 269 | return get_resnet50_simclr() 270 | elif model == 'resnet50x4_simclr': 271 | return get_resnet50x4_simclr() 272 | elif model == 'revnet50x4_bigbigan': 273 | return get_revnet50x4_bigbigan() 274 | elif model == 'resnet50_bigbigan': 275 | return get_resnet50_bigbigan() 276 | elif model == 'resnet50_simclr2': 277 | return get_resnet50_simclrv2() 278 | elif model == 'resnet152_simclr2': 279 | return get_resnet152_simclrv2() 280 | elif model == 'resnet152x3_simclr2': 281 | return get_resnet152x3_simclrv2() 282 | else: 283 | raise ValueError('Wrong model') 284 | 285 | 286 | #%% 287 | 288 | def eval(model, ds): 289 | dit = iter(ds) 290 | reses = [] 291 | labs = [] 292 | num_elements = tf.data.experimental.cardinality(ds).numpy() 293 | for ind in trange(num_elements): 294 | x, y = next(dit) 295 | result = model.predict_on_batch(x) # , training=False 296 | reses.append(result) 297 | labs.append(y) 298 | rss = np.concatenate(reses, axis=0) 299 | lbs = np.concatenate(labs, axis=0) 300 | return rss, lbs 301 | 302 | 303 | #%% 304 | 305 | parser = argparse.ArgumentParser(description='IM') 306 | parser.add_argument('--model', dest='model', type=str, default='resnet50_simclr2', 307 | help='Model: one of ' + ', '.join(models)) 308 | args = parser.parse_args() 309 | 310 | model = args.model 311 | #%% 312 | train_ds, val_ds, obj_ds = get_datasets(bbg=model in ['revnet50x4_bigbigan']) 313 | image_batch, label_batch = next(iter(train_ds)) 314 | show_batch(image_batch.numpy(), label_batch.numpy()) 315 | 316 | #%% 317 | 318 | num_elements = tf.data.experimental.cardinality(train_ds).numpy() 319 | print(num_elements) 320 | num_elements = tf.data.experimental.cardinality(val_ds).numpy() 321 | print(num_elements) 322 | num_elements = tf.data.experimental.cardinality(obj_ds).numpy() 323 | print(num_elements) 324 | 325 | 326 | #%% 327 | def eval_and_save(model='resnet50_simclr'): 328 | mdl = get_model(model) 329 | train_embs, train_labs = eval(mdl, train_ds) 330 | val_embs, val_labs = eval(mdl, val_ds) 331 | obj_embs, obj_labs = eval(mdl, obj_ds) 332 | os.makedirs('./results', exist_ok=True) 333 | np.savez(os.path.join('./results', model + '.npz'), train_embs=train_embs, train_labs=train_labs, val_embs=val_embs, 334 | val_labs=val_labs, obj_embs=obj_embs, obj_labs=obj_labs) 335 | 336 | 337 | eval_and_save(model) 338 | -------------------------------------------------------------------------------- /generate_super.sh: -------------------------------------------------------------------------------- 1 | python3 generate_prediction_pytorch_supervised.py --model tf_efficientnet_l2_ns_475 2 | python3 generate_prediction_pytorch_supervised.py --model gluon_resnet152_v1s 3 | python3 generate_prediction_pytorch_supervised.py --model ig_resnext101_32x48d 4 | -------------------------------------------------------------------------------- /plots.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np\n", 10 | "import matplotlib.pyplot as plt\n", 11 | "import os\n", 12 | "import csv\n", 13 | "from matplotlib.ticker import ScalarFormatter\n", 14 | "\n", 15 | "import statsmodels.api as sm" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 2, 21 | "metadata": { 22 | "pycharm": { 23 | "name": "#%%\n" 24 | } 25 | }, 26 | "outputs": [], 27 | "source": [ 28 | "# setup\n", 29 | "SMALL_SIZE = 10\n", 30 | "MEDIUM_SIZE = 18\n", 31 | "BIG_SIZE = 20\n", 32 | "BIGGER_SIZE = 25\n", 33 | "\n", 34 | "plt.rc('font', size=BIGGER_SIZE) # controls default text sizes\n", 35 | "plt.rc('axes', titlesize=BIGGER_SIZE) # fontsize of the axes title\n", 36 | "plt.rc('xtick', labelsize=BIGGER_SIZE) # fontsize of the tick labels\n", 37 | "plt.rc('ytick', labelsize=BIGGER_SIZE) # fontsize of the tick labels\n", 38 | "plt.rc('legend', fontsize=BIG_SIZE) # legend fontsize\n", 39 | "plt.rc('figure', titlesize=BIG_SIZE) # fontsize of the figure title\n", 40 | "plt.rc('text', usetex=True)\n", 41 | "plt.rcParams['axes.axisbelow'] = True\n", 42 | "'''cm=plt.get_cmap('CMRmap')\n", 43 | "NUM_COLORS = len(all_papers)+1\n", 44 | "colors = [cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS)][::-1]'''\n", 45 | "# https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors/\n", 46 | "colors = [(230, 25, 75), (60, 180, 75), (255, 225, 25), (0, 130, 200), (245, 130, 48), (145, 30, 180),\n", 47 | " (70, 240, 240), (240, 50, 230), (210, 245, 60), (250, 190, 190), (0, 128, 128),\n", 48 | " (230, 190, 255), (170, 110, 40), (255, 250, 200), (128, 0, 0), (170, 255, 195), (128, 128, 0),\n", 49 | " (255, 215, 180), (0, 0, 128), (128, 128, 128), (0, 0, 0)]\n", 50 | "colors = [[x[0] / 255., x[1] / 255., x[2] / 255.] for x in colors]\n", 51 | "\n", 52 | "# Draw the plots without marker\n", 53 | "markers = ['s', 'D', 'h', '>', 'o', 'p', '*', 'x', '+']\n" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 3, 59 | "metadata": { 60 | "pycharm": { 61 | "name": "#%%\n" 62 | } 63 | }, 64 | "outputs": [ 65 | { 66 | "name": "stdout", 67 | "output_type": "stream", 68 | "text": [ 69 | "42.784733362438146 26.125135091428362\n" 70 | ] 71 | } 72 | ], 73 | "source": [ 74 | "#Data\n", 75 | "pca_dim = np.array([16,32,64,128,256,512,1024,2048,])\n", 76 | "pca_res_acc = np.array([[7.626,8.038,8.002],\n", 77 | "[10.530,10.820,10.566],\n", 78 | "[15.144,14.778,15.106],\n", 79 | "[19.778,20.222,20.006],\n", 80 | "[26.876,27.136,26.818],\n", 81 | "[33.258,33.496,33.196],\n", 82 | "[37.356,38.950,38.222],\n", 83 | "[39.096,38.044,38.088]])\n", 84 | "pca_res_acc_mean, pca_res_acc_std = pca_res_acc.mean(axis=1), pca_res_acc.std(axis=1)\n", 85 | "pca_res_ari = np.array([[3.908, 4.071, 3.936],[5.781, 5.784, 5.749],[8.421, 8.301, 8.481],[12.146, 12.010, 12.039],[16.794, 16.855, 16.503],[21.359, 21.302, 21.271],[23.187, 23.071, 23.897],[23.061, 22.192, 22.566]])\n", 86 | "\n", 87 | "pca_res_ari_mean, pca_res_ari_std = pca_res_ari.mean(axis=1), pca_res_ari.std(axis=1)\n", 88 | "\n", 89 | "print((pca_res_acc_mean+pca_res_acc_std).max()*1.1, (pca_res_ari_mean+pca_res_ari_std).max()*1.1)" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 4, 95 | "metadata": { 96 | "pycharm": { 97 | "name": "#%%\n" 98 | } 99 | }, 100 | "outputs": [ 101 | { 102 | "data": { 103 | "image/png": "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\n", 104 | "text/plain": [ 105 | "
" 106 | ] 107 | }, 108 | "metadata": {}, 109 | "output_type": "display_data" 110 | } 111 | ], 112 | "source": [ 113 | "fig, ax1 = plt.subplots(figsize=(9, 5))\n", 114 | "\n", 115 | "\n", 116 | "color = 'tab:red'\n", 117 | "ax1.set_xlabel('PCA dimensions')\n", 118 | "ax1.set_ylabel('Top-1 accuracy, \\%', color=colors[0])\n", 119 | "\n", 120 | "ax1.plot(pca_dim,pca_res_acc_mean,color=colors[0],label='Accuracy') \n", 121 | "ax1.fill_between(pca_dim, pca_res_acc_mean+pca_res_acc_std, pca_res_acc_mean-pca_res_acc_std,\n", 122 | " color=colors[0], alpha=.25)\n", 123 | "ax1.tick_params(axis='y', labelcolor=colors[0])\n", 124 | "\n", 125 | "ax1.set_ylim(0,(pca_res_acc_mean+pca_res_acc_std).max()*1.1)\n", 126 | "ax1.grid()\n", 127 | "\n", 128 | "\n", 129 | "ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis\n", 130 | "\n", 131 | "\n", 132 | "ax2.set_ylabel('Adjusted Rand index, \\%', color=colors[1])\n", 133 | "\n", 134 | "ax2.plot(pca_dim,pca_res_ari_mean,color=colors[1],label='Adjusted Rand index') \n", 135 | "ax2.fill_between(pca_dim, pca_res_ari_mean+pca_res_ari_std, pca_res_ari_mean-pca_res_ari_std,\n", 136 | " color=colors[1], alpha=.25)\n", 137 | "ax2.tick_params(axis='y', labelcolor=colors[1])\n", 138 | "\n", 139 | "#plt.legend()\n", 140 | "plt.xlim(16,2048)\n", 141 | "plt.xscale('log', basex=2)\n", 142 | "ax2.set_ylim(0,(pca_res_ari_mean+pca_res_ari_std).max()*1.1)\n", 143 | "ax1.xaxis.set_major_formatter(ScalarFormatter())\n", 144 | "#ax2.set_yticks(np.linspace(ax2.get_yticks()[0], ax2.get_yticks()[-1], len(ax1.get_yticks())))\n", 145 | "# plt.xlabel('')\n", 146 | "# plt.ylabel('')\n", 147 | "fig.tight_layout()\n", 148 | "plt.savefig('pca_ablation.pdf')\n", 149 | "plt.show()" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 5, 155 | "metadata": {}, 156 | "outputs": [], 157 | "source": [ 158 | "over_cnt = np.array([1,1.25,1.5,1.75,2,2.5,3,4,5])\n", 159 | "over_acc = np.array([[38.838,38.222,39.962],\n", 160 | "[43.836,43.360,44.104],\n", 161 | "[46.160,46.146,46.152],\n", 162 | "[47.364,46.820,47.614],\n", 163 | "[48.418,48.384,48.304],\n", 164 | "[50.122,49.998,49.960],\n", 165 | "[51.020,50.976,50.862],\n", 166 | "[52.282,52.352,52.508],\n", 167 | "[53.472,53.234,53.6440]])\n", 168 | "over_acc_mean, over_acc_std = over_acc.mean(axis=1), over_acc.std(axis=1)\n", 169 | "over_ari = np.array([[22.283,22.338,23.092],\n", 170 | "[23.767,23.738,23.982],\n", 171 | "[24.955,24.796,24.566],\n", 172 | "[24.516,24.629,24.463],\n", 173 | "[24.118,24.588,24.624],\n", 174 | "[23.062,22.903,22.654],\n", 175 | "[22.072,21.447,21.500],\n", 176 | "[19.276,18.899,18.980],\n", 177 | "[17.162,16.673,17.0846]])\n", 178 | "over_ari_mean, over_ari_std = over_ari.mean(axis=1), over_ari.std(axis=1)\n", 179 | "cl_basic=1000" 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": 6, 185 | "metadata": {}, 186 | "outputs": [ 187 | { 188 | "data": { 189 | "image/png": "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\n", 190 | "text/plain": [ 191 | "
" 192 | ] 193 | }, 194 | "metadata": {}, 195 | "output_type": "display_data" 196 | } 197 | ], 198 | "source": [ 199 | "fig, ax1 = plt.subplots(figsize=(9, 5))\n", 200 | "\n", 201 | "\n", 202 | "color = 'tab:red'\n", 203 | "ax1.set_xlabel('Number of clusters')\n", 204 | "ax1.set_ylabel('Top-1 accuracy, \\%', color=colors[0])\n", 205 | "\n", 206 | "ax1.plot(over_cnt*cl_basic,over_acc_mean,color=colors[0],label='Accuracy') \n", 207 | "ax1.fill_between(over_cnt*cl_basic, over_acc_mean+over_acc_std, over_acc_mean-over_acc_std,\n", 208 | " color=colors[0], alpha=.25)\n", 209 | "ax1.tick_params(axis='y', labelcolor=colors[0])\n", 210 | "\n", 211 | "ax1.set_ylim(0,(over_acc_mean+over_acc_std).max()*1.1)\n", 212 | "ax1.grid()\n", 213 | "\n", 214 | "\n", 215 | "ax2 = ax1.twinx() # instantiate a second axes that shares the same x-axis\n", 216 | "\n", 217 | "\n", 218 | "ax2.set_ylabel('Adjusted Rand index, \\%', color=colors[1])\n", 219 | "\n", 220 | "ax2.plot(over_cnt*cl_basic,over_ari_mean,color=colors[1],label='Adjusted Rand index') \n", 221 | "ax2.fill_between(over_cnt*cl_basic, over_ari_mean+over_ari_std, over_ari_mean-over_ari_std,\n", 222 | " color=colors[1], alpha=.25)\n", 223 | "ax2.tick_params(axis='y', labelcolor=colors[1])\n", 224 | "\n", 225 | "#plt.legend()\n", 226 | "plt.xlim(1000,5000)\n", 227 | "ax2.set_ylim(0,(over_ari_mean+over_ari_std).max()*1.1)\n", 228 | "ax1.xaxis.set_major_formatter(ScalarFormatter())\n", 229 | "#ax2.set_yticks(np.linspace(ax2.get_yticks()[0], ax2.get_yticks()[-1], len(ax1.get_yticks())))\n", 230 | "# plt.xlabel('')\n", 231 | "# plt.ylabel('')\n", 232 | "fig.tight_layout()\n", 233 | "plt.savefig('over_ablation.pdf')\n", 234 | "plt.show()" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 7, 240 | "metadata": {}, 241 | "outputs": [], 242 | "source": [ 243 | "lin_acc = np.array([71.1, 73.0,71.7, 61.3, 75.2, 77.2])\n", 244 | "k_means_acc = np.array([23.09, 33.17, 22.40, 3, 38.6,39.07])\n", 245 | "ari = np.array([11.99, 14.71,10.97,1.01, 22.15, 22.80])\n", 246 | "\n", 247 | "lin_acc2 = np.array([75.3, 79.8])\n", 248 | "k_means_acc2 = np.array([15.04, 31.15 ])\n", 249 | "ari2 = np.array([7.72, 13.84 ])\n", 250 | "\n", 251 | "k_means_acc_all = np.concatenate((k_means_acc,k_means_acc2))\n", 252 | "ari_all = np.concatenate((ari,ari2))\n", 253 | "\n", 254 | "k_means_acc3 = np.array([39.9])\n", 255 | "ari3 = np.array([27.5])" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": 8, 261 | "metadata": {}, 262 | "outputs": [ 263 | { 264 | "name": "stdout", 265 | "output_type": "stream", 266 | "text": [ 267 | " OLS Regression Results \n", 268 | "==============================================================================\n", 269 | "Dep. Variable: y R-squared: 0.947\n", 270 | "Model: OLS Adj. R-squared: 0.934\n", 271 | "Method: Least Squares F-statistic: 72.14\n", 272 | "Date: Mon, 17 Aug 2020 Prob (F-statistic): 0.00105\n", 273 | "Time: 18:12:39 Log-Likelihood: -14.804\n", 274 | "No. Observations: 6 AIC: 33.61\n", 275 | "Df Residuals: 4 BIC: 33.19\n", 276 | "Df Model: 1 \n", 277 | "Covariance Type: nonrobust \n", 278 | "==============================================================================\n", 279 | " coef std err t P>|t| [0.025 0.975]\n", 280 | "------------------------------------------------------------------------------\n", 281 | "const -145.4009 20.296 -7.164 0.002 -201.753 -89.049\n", 282 | "x1 2.4022 0.283 8.493 0.001 1.617 3.187\n", 283 | "==============================================================================\n", 284 | "Omnibus: nan Durbin-Watson: 2.943\n", 285 | "Prob(Omnibus): nan Jarque-Bera (JB): 0.504\n", 286 | "Skew: -0.200 Prob(JB): 0.777\n", 287 | "Kurtosis: 1.638 Cond. No. 1.02e+03\n", 288 | "==============================================================================\n", 289 | "\n", 290 | "Warnings:\n", 291 | "[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.\n", 292 | "[2] The condition number is large, 1.02e+03. This might indicate that there are\n", 293 | "strong multicollinearity or other numerical problems.\n", 294 | "0.9474621291204218\n" 295 | ] 296 | }, 297 | { 298 | "name": "stderr", 299 | "output_type": "stream", 300 | "text": [ 301 | "/usr/local/lib/python3.6/dist-packages/statsmodels/stats/stattools.py:71: ValueWarning: omni_normtest is not valid with less than 8 observations; 6 samples were given.\n", 302 | " \"samples were given.\" % int(n), ValueWarning)\n" 303 | ] 304 | } 305 | ], 306 | "source": [ 307 | "# fit1\n", 308 | "X1 = sm.add_constant(lin_acc)\n", 309 | "mod1_ols = sm.OLS(k_means_acc, X1)\n", 310 | "res1_ols = mod1_ols.fit()\n", 311 | "print(res1_ols.summary())\n", 312 | "print(res1_ols.rsquared)\n", 313 | "\n", 314 | "\n", 315 | "intercept1, slope1 = res1_ols.params\n", 316 | "\n", 317 | "\n", 318 | "x1 = np.linspace(0.,100., 10000)\n", 319 | "y1 = slope1*x1 + intercept1\n" 320 | ] 321 | }, 322 | { 323 | "cell_type": "code", 324 | "execution_count": 9, 325 | "metadata": {}, 326 | "outputs": [ 327 | { 328 | "name": "stdout", 329 | "output_type": "stream", 330 | "text": [ 331 | " OLS Regression Results \n", 332 | "==============================================================================\n", 333 | "Dep. Variable: y R-squared: 0.941\n", 334 | "Model: OLS Adj. R-squared: 0.932\n", 335 | "Method: Least Squares F-statistic: 96.32\n", 336 | "Date: Mon, 17 Aug 2020 Prob (F-statistic): 6.45e-05\n", 337 | "Time: 18:12:39 Log-Likelihood: -15.233\n", 338 | "No. Observations: 8 AIC: 34.47\n", 339 | "Df Residuals: 6 BIC: 34.62\n", 340 | "Df Model: 1 \n", 341 | "Covariance Type: nonrobust \n", 342 | "==============================================================================\n", 343 | " coef std err t P>|t| [0.025 0.975]\n", 344 | "------------------------------------------------------------------------------\n", 345 | "const -1.2599 1.611 -0.782 0.464 -5.202 2.682\n", 346 | "x1 0.5609 0.057 9.814 0.000 0.421 0.701\n", 347 | "==============================================================================\n", 348 | "Omnibus: 0.757 Durbin-Watson: 1.295\n", 349 | "Prob(Omnibus): 0.685 Jarque-Bera (JB): 0.627\n", 350 | "Skew: -0.464 Prob(JB): 0.731\n", 351 | "Kurtosis: 1.989 Cond. No. 68.5\n", 352 | "==============================================================================\n", 353 | "\n", 354 | "Warnings:\n", 355 | "[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.\n", 356 | "0.9413583437048022\n" 357 | ] 358 | }, 359 | { 360 | "name": "stderr", 361 | "output_type": "stream", 362 | "text": [ 363 | "/usr/local/lib/python3.6/dist-packages/scipy/stats/stats.py:1535: UserWarning: kurtosistest only valid for n>=20 ... continuing anyway, n=8\n", 364 | " \"anyway, n=%i\" % int(n))\n" 365 | ] 366 | } 367 | ], 368 | "source": [ 369 | "# fit2\n", 370 | "X2 = sm.add_constant(k_means_acc_all)\n", 371 | "mod2_ols = sm.OLS(ari_all, X2)\n", 372 | "res2_ols = mod2_ols.fit()\n", 373 | "print(res2_ols.summary())\n", 374 | "print(res2_ols.rsquared)\n", 375 | "\n", 376 | "\n", 377 | "intercept2, slope2 = res2_ols.params\n", 378 | "\n", 379 | "\n", 380 | "x2 = np.linspace(0.,100., 10000)\n", 381 | "y2 = slope2*x2 + intercept2\n" 382 | ] 383 | }, 384 | { 385 | "cell_type": "code", 386 | "execution_count": 10, 387 | "metadata": {}, 388 | "outputs": [ 389 | { 390 | "data": { 391 | "image/png": "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\n", 392 | "text/plain": [ 393 | "
" 394 | ] 395 | }, 396 | "metadata": { 397 | "needs_background": "light" 398 | }, 399 | "output_type": "display_data" 400 | } 401 | ], 402 | "source": [ 403 | "\n", 404 | "\n", 405 | "# plot\n", 406 | "fig = plt.figure(figsize=(9, 5))\n", 407 | "\n", 408 | "\n", 409 | "plt.scatter(lin_acc,k_means_acc,color=colors[0], marker='o', edgecolors='white', s=125, zorder=2) \n", 410 | "plt.scatter(lin_acc2,k_means_acc2,color=colors[1], marker='o', edgecolors='white', s=125, zorder=2) \n", 411 | " \n", 412 | "plt.plot(x1,y1,linestyle='dashed',color=colors[0],label='Linear fit', zorder=1) \n", 413 | "plt.legend()\n", 414 | "plt.grid()\n", 415 | "plt.xlabel('Linear evaluation accuracy, \\%', fontsize=BIGGER_SIZE)\n", 416 | "plt.ylabel('k-means accuracy, \\%', fontsize=BIGGER_SIZE)\n", 417 | "plt.xlim(0.,100.)\n", 418 | "plt.ylim(0,100.)\n", 419 | "fig.tight_layout()\n", 420 | "\n", 421 | "plt.legend()\n", 422 | "\n", 423 | "plt.savefig('lin_vs_uns.pdf')\n", 424 | "plt.show()" 425 | ] 426 | }, 427 | { 428 | "cell_type": "code", 429 | "execution_count": 11, 430 | "metadata": {}, 431 | "outputs": [ 432 | { 433 | "data": { 434 | "image/png": "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\n", 435 | "text/plain": [ 436 | "
" 437 | ] 438 | }, 439 | "metadata": { 440 | "needs_background": "light" 441 | }, 442 | "output_type": "display_data" 443 | } 444 | ], 445 | "source": [ 446 | "# plot\n", 447 | "fig = plt.figure(figsize=(9, 5))\n", 448 | "\n", 449 | "\n", 450 | "plt.scatter(k_means_acc_all,ari_all,color=colors[0], marker='o', edgecolors='white', s=125, zorder=2, label='Self-supervised methods') \n", 451 | "plt.scatter(k_means_acc3,ari3,color=colors[2], marker='o', edgecolors='white', s=125, zorder=2, label='SCAN') \n", 452 | " \n", 453 | "plt.plot(x2,y2,linestyle='dashed',color=colors[0],label='Linear fit', zorder=1) \n", 454 | "plt.legend()\n", 455 | "plt.grid()\n", 456 | "plt.xlabel('Unsupervised accuracy, \\%', fontsize=BIGGER_SIZE)\n", 457 | "plt.ylabel('ARI, \\%', fontsize=BIGGER_SIZE)\n", 458 | "plt.xlim(0.,100.)\n", 459 | "plt.ylim(0,100.)\n", 460 | "fig.tight_layout()\n", 461 | "\n", 462 | "plt.legend()\n", 463 | "\n", 464 | "plt.savefig('uns_vs_ari.pdf')\n", 465 | "plt.show()" 466 | ] 467 | }, 468 | { 469 | "cell_type": "code", 470 | "execution_count": null, 471 | "metadata": {}, 472 | "outputs": [], 473 | "source": [] 474 | } 475 | ], 476 | "metadata": { 477 | "kernelspec": { 478 | "display_name": "Python 3", 479 | "language": "python", 480 | "name": "python3" 481 | }, 482 | "language_info": { 483 | "codemirror_mode": { 484 | "name": "ipython", 485 | "version": 3 486 | }, 487 | "file_extension": ".py", 488 | "mimetype": "text/x-python", 489 | "name": "python", 490 | "nbconvert_exporter": "python", 491 | "pygments_lexer": "ipython3", 492 | "version": "3.6.9" 493 | } 494 | }, 495 | "nbformat": 4, 496 | "nbformat_minor": 1 497 | } 498 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | scipy>=1.4,<1.5 2 | numpy 3 | scikit-learn 4 | tqdm 5 | tensorflow>=2.2,<2.3 6 | tensorflow_hub>=0.8,<0.9 7 | tensorflow-estimator>=2.2,<2.3 8 | tensorflow_datasets 9 | tensorboard_logger 10 | torch>=1.5,<1.6 11 | torchvision -------------------------------------------------------------------------------- /torch_utils.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | import requests 5 | import torch 6 | from torch.utils.data import DistributedSampler 7 | from torchvision import datasets 8 | from torchvision.transforms import transforms 9 | 10 | __imagenet_stats = {'mean': [0.485, 0.456, 0.406], 11 | 'std': [0.229, 0.224, 0.225]} 12 | 13 | 14 | def woof_preproccess(input_size, normalize=__imagenet_stats): 15 | return transforms.Compose([ 16 | transforms.RandomResizedCrop(input_size, scale=(0.35, 1.)), 17 | transforms.RandomHorizontalFlip(), 18 | transforms.ToTensor(), 19 | transforms.Normalize(**normalize) 20 | ]) 21 | 22 | 23 | def inception_preproccess(input_size, normalize=__imagenet_stats): 24 | return transforms.Compose([ 25 | transforms.RandomResizedCrop(input_size), 26 | transforms.RandomHorizontalFlip(), 27 | transforms.ToTensor(), 28 | transforms.Normalize(**normalize) 29 | ]) 30 | 31 | 32 | def scale_crop(input_size, scale_size=None, normalize=__imagenet_stats): 33 | t_list = [ 34 | transforms.CenterCrop(input_size), 35 | transforms.ToTensor(), 36 | transforms.Normalize(**normalize), 37 | ] 38 | if scale_size != input_size: 39 | t_list = [transforms.Resize(scale_size)] + t_list 40 | 41 | return transforms.Compose(t_list) 42 | 43 | 44 | def get_transform_imagenet(augment=True, input_size=224): 45 | normalize = __imagenet_stats 46 | scale_size = int(input_size / 0.875) 47 | if augment: 48 | return woof_preproccess(input_size=input_size, normalize=normalize) 49 | else: 50 | return scale_crop(input_size=input_size, scale_size=scale_size, normalize=normalize) 51 | 52 | 53 | def get_loaders_imagenet(dataroot, val_batch_size, train_batch_size, input_size, workers, num_nodes, local_rank): 54 | # TODO: pin-memory currently broken for distributed 55 | pin_memory = False 56 | # TODO: datasets.ImageNet 57 | val_data = datasets.ImageFolder(root=os.path.join(dataroot, 'val'), 58 | transform=get_transform_imagenet(False, input_size)) 59 | val_sampler = DistributedSampler(val_data, num_nodes, local_rank) 60 | val_loader = torch.utils.data.DataLoader(val_data, batch_size=val_batch_size, sampler=val_sampler, 61 | num_workers=workers, pin_memory=pin_memory) 62 | 63 | train_data = datasets.ImageFolder(root=os.path.join(dataroot, 'train'), 64 | transform=get_transform_imagenet(input_size=input_size)) 65 | train_sampler = DistributedSampler(train_data, num_nodes, local_rank) 66 | train_loader = torch.utils.data.DataLoader(train_data, batch_size=train_batch_size, sampler=train_sampler, 67 | num_workers=workers, pin_memory=pin_memory) 68 | return train_loader, val_loader 69 | 70 | 71 | def get_loaders_objectnet(dataroot, imagenet_dataroot, val_batch_size, input_size, workers, num_nodes, local_rank): 72 | # TODO: pin-memory currently broken for distributed 73 | pin_memory = False 74 | # TODO: datasets.ImageNet 75 | val_data_im = datasets.ImageFolder(root=os.path.join(imagenet_dataroot, 'val'), 76 | transform=get_transform_imagenet(False, input_size)) 77 | # TODO: datasets.ImageNet 78 | val_data = datasets.ImageFolder(root=os.path.join(dataroot, 'images'), 79 | transform=get_transform_imagenet(False, input_size)) 80 | val_sampler = DistributedSampler(val_data, num_nodes, local_rank) 81 | val_loader = torch.utils.data.DataLoader(val_data, batch_size=val_batch_size, sampler=val_sampler, 82 | num_workers=workers, pin_memory=pin_memory) 83 | imagenet_to_objectnet, objectnet_to_imagenet, objectnet_both, imagenet_both = objectnet_imagenet_mappings(dataroot, 84 | val_data, 85 | val_data_im) 86 | return val_loader, imagenet_to_objectnet, objectnet_to_imagenet, objectnet_both, imagenet_both 87 | 88 | 89 | def objectnet_imagenet_mappings(dataroot, object_data, imagenet_data): 90 | import numpy as np 91 | mappings = os.path.join(dataroot, 'mappings') 92 | object_to_imagenet = json.load(open(os.path.join(mappings, 'objectnet_to_imagenet_1k.json'))) 93 | folder_to_object = json.load(open(os.path.join(mappings, 'folder_to_objectnet_label.json'))) 94 | map_url = 'https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json' 95 | response = json.loads(requests.get(map_url).text) 96 | name_map = {} 97 | name_to_syn = {} 98 | name_to_num = {} 99 | for r in response: 100 | name_map[response[r][0]] = response[r][1] 101 | name_to_syn[response[r][1]] = response[r][0] 102 | # print(response[r][1].replace('_',' ')) 103 | name_to_num[response[r][1].replace('_', ' ')] = imagenet_data.class_to_idx[response[r][0]] 104 | 105 | imagenet_to_name = [] 106 | imagenet_to_objectnet = - np.ones(1000, dtype=int) 107 | objectnet_to_imagenet = {} 108 | 109 | name_to_imagenet = {} 110 | for i, cl in enumerate(open(os.path.join(mappings, 'imagenet_to_label_2012_v2'))): 111 | cl = cl.strip() 112 | imagenet_to_name.append(cl) 113 | name_to_imagenet[cl] = i 114 | 115 | cnt_both, cnt = 0, 0 116 | objectnet_both = [] 117 | imagenet_both = [] 118 | for cl in object_data.class_to_idx: 119 | obj = folder_to_object[cl] 120 | if obj in object_to_imagenet: 121 | imagenet_classes = [s.strip() for s in object_to_imagenet[obj].split(';')] 122 | pt_classes = [name_to_num[ic.split(',')[0].strip()] for ic in imagenet_classes] 123 | objectnet_to_imagenet[object_data.class_to_idx[cl]] = pt_classes 124 | cnt_both += 1 125 | objectnet_both.append(object_data.class_to_idx[cl]) 126 | for icl in pt_classes: 127 | imagenet_both.append(icl) 128 | imagenet_to_objectnet[icl] = object_data.class_to_idx[cl] 129 | else: 130 | objectnet_to_imagenet[object_data.class_to_idx[cl]] = [] 131 | cnt += 1 132 | 133 | return imagenet_to_objectnet, objectnet_to_imagenet, objectnet_both, imagenet_both 134 | -------------------------------------------------------------------------------- /visual_utils.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | 3 | 4 | def confusion_mat(C, row_ind, col_ind, name=''): 5 | conf_mat = C[row_ind][:, col_ind] 6 | 7 | fig = plt.figure(figsize=(9, 7)) 8 | im = plt.imshow(conf_mat) 9 | 10 | plt.title("Confusion matrix") 11 | fig.tight_layout() 12 | plt.savefig(name + '_conf.pdf') 13 | --------------------------------------------------------------------------------