forked from cvai-roig-lab/duality-diagram-similarity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.py
320 lines (267 loc) · 11.1 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# -*- coding: utf-8 -*-
"""
Created on Mon Aug 10 19:45:42 2020
@author: kshitij
"""
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.metrics.pairwise import laplacian_kernel
from sklearn.metrics.pairwise import euclidean_distances
from sklearn.preprocessing import StandardScaler
def get_similarity_from_rdms(x,y,dist,feature_norm,debiased=True,centered=True):
"""
Parameters
----------
x : numpy matrix with dimensions n x p
task 1 features (n = number of images, p = feature dimensions)
y : numpy matrix with dimensions n x p
task 1 features (n = number of images, p = feature dimensions)
dist : string
distance function to compute dissimilarity matrices
feature_norm : string
feature normalization type
debiased : bool, optional
set True to perform unbiased centering
centered : bool, optional
set True to perform unbiased centering
Returns
-------
DDS: float
DDS between task1 and task2
"""
if feature_norm == 'None':
x = x
y = y
elif feature_norm == 'centering':
x = (x - np.mean(x,axis = 0, keepdims=True))
y = (y - np.mean(y,axis = 0, keepdims=True))
elif feature_norm == 'znorm':
x = StandardScaler().fit_transform(x)
y = StandardScaler().fit_transform(y)
elif feature_norm == 'group_norm':
x = np.reshape(x,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
y = np.reshape(y,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
x = group_norm(x,group_size=2)
y = group_norm(y,group_size=2)
elif feature_norm == 'instance_norm':
x = np.reshape(x,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
y = np.reshape(y,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
x = group_norm(x,group_size=8)
y = group_norm(y,group_size=8)
elif feature_norm == 'layer_norm':
x = np.reshape(x,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
y = np.reshape(y,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
x = group_norm(x,group_size=1)
y = group_norm(y,group_size=1)
elif feature_norm == 'batch_norm':
x = np.reshape(x,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
y = np.reshape(y,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
x = batch_norm(x)
y = batch_norm(y)
return cka(rdm(x,dist),rdm(y,dist),debiased=debiased,centered=centered)
def get_similarity(x,y,kernel,feature_norm,debiased=True,centered=True):
"""
Parameters
----------
x : numpy matrix with dimensions n x p
task 1 features (n = number of images, p = feature dimensions)
y : numpy matrix with dimensions n x p
task 1 features (n = number of images, p = feature dimensions)
kernel : string
kernel function to compute similarity matrices
feature_norm : string
feature normalization type
debiased : bool, optional
set True to perform unbiased centering
centered : bool, optional
set True to perform unbiased centering
Returns
-------
DDS: float
DDS between task1 and task2
"""
if feature_norm == 'None':
x = x
y = y
elif feature_norm == 'centering':
x = (x - np.mean(x,axis=0))
y = (y - np.mean(y,axis=0))
elif feature_norm == 'znorm':
x = StandardScaler().fit_transform(x)
y = StandardScaler().fit_transform(y)
elif feature_norm == 'group_norm':
x = np.reshape(x,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
y = np.reshape(y,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
x = group_norm(x,group_size=2)
y = group_norm(y,group_size=2)
elif feature_norm == 'instance_norm':
x = np.reshape(x,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
y = np.reshape(y,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
x = group_norm(x,group_size=8)
y = group_norm(y,group_size=8)
elif feature_norm == 'layer_norm':
x = np.reshape(x,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
y = np.reshape(y,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
x = group_norm(x,group_size=1)
y = group_norm(y,group_size=1)
elif feature_norm == 'batch_norm':
x = np.reshape(x,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
y = np.reshape(y,(-1,16,16,8)) # reshaping features back to n x h x w x c format from flattened features
x = batch_norm(x)
y = batch_norm(y)
if kernel == 'linear':
return cka(gram_linear(x),gram_linear(y),debiased=debiased,centered=centered)
elif kernel == 'rbf':
return cka(gram_rbf(x, 0.5),gram_rbf(y, 0.5),debiased=debiased,centered=centered)
elif kernel == 'lap':
return cka(gram_laplacian_scipy(x),gram_laplacian_scipy(y),debiased=debiased,centered=centered)
def group_norm(x,group_size=2):
"""
Parameters
----------
x : numpy matrix with dimensions n x h x w x c
features (n = number of images, h = height, w = width, c = channel dimensions)
group_size : int, optional
group size for group norm. The default is 2.
group size (G) = channel_dim (C) for instance normalization
group size (G) = 1 for layer normalization
Returns
-------
normalized_x : numpy matrix with dimensions n x h*w*c
normalized features
"""
eps = 1e-9
N, H, W, C = x.shape
#print("The shape of features are ",N, H, W, C)
G = group_size
x = np.reshape(x, (N, H, W,G, C // G ))
mean = np.mean(x,axis = (1, 2, 4), keepdims=True)
var = np.var(x,axis = (1, 2, 4), keepdims=True)
x = (x - mean) / np.sqrt(var + eps)
normalized_x = np.reshape(x, (N, C*H*W))
return normalized_x
def batch_norm(x):
"""
Parameters
----------
x : numpy matrix with dimensions n x h x w x c
task 1 features (n = number of images, h = height, w = width, c = channel dimensions)
Returns
-------
normalized_x : numpy matrix with dimensions n x h*w*c
normalized features
"""
eps = 1e-9
N, H, W, C = x.shape
#print("The shape of features are ",N, H, W, C)
mean = np.mean(x,axis = (0, 1, 2), keepdims=True)
var = np.var(x,axis = (0, 1, 2), keepdims=True)
x = (x - mean) / np.sqrt(var + eps)
normalized_x = np.reshape(x, (N, C*H*W))
return normalized_x
def rdm(activations_value,dist):
"""
Parameters
----------
activations_value : numpy matrix with dimensions n x p
task 1 features (n = number of images, p = feature dimensions)
dist : string
distance function to compute dissimilarity matrix
Returns
-------
RDM : numpy matrix with dimensions n x n
dissimilarity matrices
"""
if dist == 'pearson':
RDM = 1-np.corrcoef(activations_value)
elif dist == 'euclidean':
RDM = euclidean_distances(activations_value)
elif dist == 'cosine':
RDM = 1- cosine_similarity(activations_value)
return RDM
def gram_linear(x):
"""Compute Gram (kernel) matrix for a linear kernel.
Args:
x: A num_examples x num_features matrix of features.
Returns:
A num_examples x num_examples Gram matrix of examples.
P.S. Function from Kornblith et al., ICML 2019
"""
return x.dot(x.T)
def gram_laplacian_scipy(x):
"""Compute Gram (kernel) matrix for a laplacian kernel.
Args:
x: A num_examples x num_features matrix of features.
Returns:
A num_examples x num_examples Gram matrix of examples.
"""
K = laplacian_kernel(x)
return K
def gram_rbf(x, threshold=1.0):
"""Compute Gram (kernel) matrix for an RBF kernel.
Args:
x: A num_examples x num_features matrix of features.
threshold: Fraction of median Euclidean distance to use as RBF kernel
bandwidth. (This is the heuristic we use in the paper. There are other
possible ways to set the bandwidth; we didn't try them.)
Returns:
A num_examples x num_examples Gram matrix of examples.
P.S. Function from Kornblith et al., ICML 2019
"""
dot_products = x.dot(x.T)
sq_norms = np.diag(dot_products)
sq_distances = -2 * dot_products + sq_norms[:, None] + sq_norms[None, :]
sq_median_distance = np.median(sq_distances)
return np.exp(-sq_distances / (2 * threshold ** 2 * sq_median_distance))
def center_gram(gram, unbiased=False):
"""Center a symmetric Gram matrix.
This is equvialent to centering the (possibly infinite-dimensional) features
induced by the kernel before computing the Gram matrix.
Args:
gram: A num_examples x num_examples symmetric matrix.
unbiased: Whether to adjust the Gram matrix in order to compute an unbiased
estimate of HSIC. Note that this estimator may be negative.
Returns:
A symmetric matrix with centered columns and rows.
P.S. Function from Kornblith et al., ICML 2019
"""
if not np.allclose(gram, gram.T):
raise ValueError('Input must be a symmetric matrix.')
gram = gram.copy()
if unbiased:
# This formulation of the U-statistic, from Szekely, G. J., & Rizzo, M.
# L. (2014). Partial distance correlation with methods for dissimilarities.
# The Annals of Statistics, 42(6), 2382-2412, seems to be more numerically
# stable than the alternative from Song et al. (2007).
n = gram.shape[0]
np.fill_diagonal(gram, 0)
means = np.sum(gram, 0, dtype=np.float64) / (n - 2)
means -= np.sum(means) / (2 * (n - 1))
gram -= means[:, None]
gram -= means[None, :]
np.fill_diagonal(gram, 0)
else:
means = np.mean(gram, 0, dtype=np.float64)
means -= np.mean(means) / 2
gram -= means[:, None]
gram -= means[None, :]
return gram
def cka(gram_x, gram_y, debiased=False,centered=True):
"""Compute CKA.
Args:
gram_x: A num_examples x num_examples Gram matrix.
gram_y: A num_examples x num_examples Gram matrix.
debiased: Use unbiased estimator of HSIC. CKA may still be biased.
Returns:
The value of CKA between X and Y.
P.S. Function from Kornblith et al., ICML 2019
"""
if centered:
gram_x = center_gram(gram_x, unbiased=debiased)
gram_y = center_gram(gram_y, unbiased=debiased)
# Note: To obtain HSIC, this should be divided by (n-1)**2 (biased variant) or
# n*(n-3) (unbiased variant), but this cancels for CKA.
scaled_hsic = gram_x.ravel().dot(gram_y.ravel())
normalization_x = np.linalg.norm(gram_x)
normalization_y = np.linalg.norm(gram_y)
return scaled_hsic / (normalization_x * normalization_y)