-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.py
154 lines (120 loc) · 5.27 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
#author:zhaochao time:2021/5/18
import torch as t
import torch.nn.functional as F
import numpy as np
import random
import torch.nn as nn
def CORAL(source, target):
d = source.data.shape[1]
# source covariance
xm = t.mean(source, 1, keepdim=True) - source
xc = t.matmul(t.transpose(xm, 0, 1), xm)
# target covariance
xmt = t.mean(target, 1, keepdim=True) - target
xct = t.matmul(t.transpose(xmt, 0, 1), xmt)
# frobenius norm between source and target
loss = t.mean(t.mul((xc - xct), (xc - xct)))
loss = loss/(4*d*4)
return loss
class TripletLoss(nn.Module):
'''
Compute normal triplet loss or soft margin triplet loss given triplets
'''
def __init__(self, margin = None):
super(TripletLoss, self).__init__()
self.margin = margin
if self.margin is None: # use soft-margin
self.Loss = nn.SoftMarginLoss()
else:
self.Loss = nn.TripletMarginLoss(margin = margin, p = 2)
def forward(self, anchor, pos, neg):
if self.margin is None:
num_samples = anchor.shape[0]
y = t.ones((num_samples, 1)).view(-1)
if anchor.is_cuda: y = y.cuda()
ap_dist = t.norm(anchor - pos, 2, dim = 1).view(-1)
an_dist = t.norm(anchor - neg, 2, dim = 1).view(-1)
loss = self.Loss(an_dist - ap_dist, y)
else:
loss = self.Loss(anchor, pos, neg)
return loss
def pdist_torch(emb1, emb2):
'''
compute the eucilidean distance matrix between embeddings1 and embeddings2
using gpu
'''
m, n = emb1.shape[0], emb2.shape[0]
emb1_pow = t.pow(emb1, 2).sum(dim = 1, keepdim = True).expand(m, n)
emb2_pow = t.pow(emb2, 2).sum(dim = 1, keepdim = True).expand(n, m).t()
dist_mtx = emb1_pow + emb2_pow
dist_mtx = dist_mtx.addmm_(1, -2, emb1, emb2.t())
dist_mtx = dist_mtx.clamp(min = 1e-12).sqrt()
return dist_mtx
class BatchHardTripletSelector(object):
'''
a selector to generate hard batch embeddings from the embedded batch
'''
def __init__(self, *args, **kwargs):
super(BatchHardTripletSelector, self).__init__()
def __call__(self, embeds, labels):
dist_mtx = pdist_torch(embeds, embeds).detach().cpu().numpy()# 计算距离
labels = labels.contiguous().cpu().numpy().reshape((-1, 1))
num = labels.shape[0]
dia_inds = np.diag_indices(num)#返回对角线索引
lb_eqs = labels == labels.T
lb_eqs[dia_inds] = False
dist_same = dist_mtx.copy()
dist_same[lb_eqs == False] = -np.inf
pos_idxs = np.argmax(dist_same, axis = 1)
dist_diff = dist_mtx.copy()
lb_eqs[dia_inds] = True
dist_diff[lb_eqs == True] = np.inf
neg_idxs = np.argmin(dist_diff, axis = 1)
pos = embeds[pos_idxs].contiguous().view(num, -1)
neg = embeds[neg_idxs].contiguous().view(num, -1)
return embeds, pos, neg
def setup_seed(seed):
np.random.seed(seed)
random.seed(seed)
t.manual_seed(seed) # cpu
t.cuda.manual_seed_all(seed) # 并行gpu
t.backends.cudnn.deterministic = True # cpu/gpu结果一致
t.backends.cudnn.benchmark = True # 训练集变化不大时使训练加速
def CrossEntropyLoss(label, predict_prob, class_level_weight=None, instance_level_weight=None, epsilon=1e-12):
N, C = label.size()
N_, C_ = predict_prob.size()
assert N == N_ and C == C_, 'fatal error: dimension mismatch!'
if class_level_weight is None:
class_level_weight = 1.0
else:
if len(class_level_weight.size()) == 1:
class_level_weight = class_level_weight.view(1, class_level_weight.size(0))
assert class_level_weight.size(1) == C, 'fatal error: dimension mismatch!'
if instance_level_weight is None:
instance_level_weight = 1.0
else:
if len(instance_level_weight.size()) == 1:
instance_level_weight = instance_level_weight.view(instance_level_weight.size(0), 1)
assert instance_level_weight.size(0) == N, 'fatal error: dimension mismatch!'
ce = -label * t.log(predict_prob + epsilon)
return t.sum(instance_level_weight * ce * class_level_weight) / float(N)
def EntropyLoss(predict_prob, class_level_weight=None, instance_level_weight=None, epsilon=1e-20):
N, C = predict_prob.size()
if class_level_weight is None:
class_level_weight = 1.0
else:
if len(class_level_weight.size()) == 1:
class_level_weight = class_level_weight.view(1, class_level_weight.size(0))
assert class_level_weight.size(1) == C, 'fatal error: dimension mismatch!'
if instance_level_weight is None:
instance_level_weight = 1.0
else:
if len(instance_level_weight.size()) == 1:
instance_level_weight = instance_level_weight.view(instance_level_weight.size(0), 1)
assert instance_level_weight.size(0) == N, 'fatal error: dimension mismatch!'
mask = predict_prob.ge(0.000001) # 逐元素比较
mask_out = t.masked_select(predict_prob, mask)#
entropy =-mask_out * t.log(mask_out)
#
return t.sum(instance_level_weight * entropy * class_level_weight) / float(N)
#