Skip to content

Commit b8d2a40

Browse files
committed
update dtq
1 parent dcb86fc commit b8d2a40

7 files changed

Lines changed: 122 additions & 212 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,5 @@ ENV/
102102

103103
pretrained_model/
104104
tflog/
105+
models/
106+
*.swp

core/model/dtq/__init__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from .dtq import DTQ
2+
from .util import Dataset
3+
4+
def train(train_img, database_img, query_img, config):
5+
model = DTQ(config)
6+
img_database = Dataset(database_img, config.output_dim, config.subspace * config.subcenter)
7+
img_query = Dataset(query_img, config.output_dim, config.subspace * config.subcenter)
8+
img_train = Dataset(train_img, config.output_dim, config.subspace * config.subcenter)
9+
model.train_cq(img_train, img_query, img_database, config.R)
10+
return model.save_dir
11+
12+
13+
def validation(database_img, query_img, config):
14+
model = DTQ(config)
15+
img_database = Dataset(database_img, config.output_dim, config.subspace * config.subcenter)
16+
img_query = Dataset(query_img, config.output_dim, config.subspace * config.subcenter)
17+
return model.validation(img_query, img_database, config.R)
Lines changed: 24 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,12 @@
1111

1212
from architecture.single_model import img_alexnet_layers
1313
from distance.tfversion import distance
14-
from evaluation import MAPs_CQ, MAPs
15-
from .util import Dataset
14+
from evaluation import MAPs_CQ
1615

17-
@tf.RegisterGradient("QuantizeGrad")
18-
def quantize_grad(op, grad):
19-
return tf.clip_by_value(tf.identity(grad), -1, 1)
2016

21-
class TripletQuantization(object):
17+
class DTQ(object):
2218
def __init__(self, config):
2319
# Initialize setting
24-
print("initializing")
2520
np.set_printoptions(precision=4)
2621

2722
with tf.name_scope('stage'):
@@ -31,11 +26,10 @@ def __init__(self, config):
3126
self.output_dim = config.output_dim
3227
self.n_class = config.label_dim
3328

34-
self.subspace_num = config.n_subspace
35-
self.subcenter_num = config.n_subcenter
29+
self.subspace_num = config.subspace
30+
self.subcenter_num = config.subcenter
3631
self.code_batch_size = config.code_batch_size
3732
self.cq_lambda = config.cq_lambda
38-
self.q_lambda = config.q_lambda
3933
self.max_iter_update_Cb = config.max_iter_update_Cb
4034
self.max_iter_update_b = config.max_iter_update_b
4135

@@ -72,21 +66,17 @@ def __init__(self, config):
7266
self.log_dir = config.log_dir
7367

7468
# Setup session
75-
print("launching session")
7669
config_proto = tf.ConfigProto()
7770
config_proto.gpu_options.allow_growth = True
7871
config_proto.allow_soft_placement = True
7972
self.sess = tf.Session(config=config_proto)
8073

8174
# Create variables and placeholders
8275
self.img = tf.placeholder(tf.float32, [None, 256, 256, 3])
83-
# TODO useless placeholder
84-
self.img_label = tf.placeholder(tf.float32, [None, self.n_class])
8576
self.model_weights = config.model_weights
8677
self.img_last_layer, self.deep_param_img, self.train_layers, self.train_last_layer = self.load_model()
8778

8879
with tf.name_scope('quantization'):
89-
# C
9080
self.C = tf.Variable(tf.random_uniform(
9181
[self.subspace_num * self.subcenter_num, self.output_dim],
9282
minval=-1, maxval=1, dtype=tf.float32, name='centers'))
@@ -110,9 +100,6 @@ def __init__(self, config):
110100
self.ICM_best_centers_one_hot = tf.one_hot(ICM_best_centers, self.subcenter_num, dtype=tf.float32)
111101

112102
self.global_step = tf.Variable(0, trainable=False)
113-
114-
self.G = tf.get_default_graph()
115-
116103
self.train_op = self.apply_loss_function(self.global_step)
117104
self.sess.run(tf.global_variables_initializer())
118105
return
@@ -153,115 +140,61 @@ def save_codes(self, database, query, C, model_file=None):
153140
def save_model(self, model_file=None):
154141
if model_file is None:
155142
model_file = self.save_dir
143+
156144
model = {}
157145
for layer in self.deep_param_img:
158146
model[layer] = self.sess.run(self.deep_param_img[layer])
147+
159148
print("saving model to %s" % model_file)
160149
folder = os.path.dirname(model_file)
161150
if os.path.exists(folder) is False:
162151
os.makedirs(folder)
152+
163153
np.save(model_file, np.array(model))
164154
return
165155

166-
167-
def quantize(self, x):
168-
with self.G.gradient_override_map({"Sign": "QuantizeGrad"}):
169-
return tf.sign(x)
170-
171156
def triplet_loss(self, anchor, pos, neg, margin):
172-
173157
with tf.variable_scope('triplet_loss'):
174-
if 'sign' in self.select_strategy:
175-
# first version
176-
#anchor_sign = tf.stop_gradient(tf.sign(anchor))
177-
#pos_sign = tf.stop_gradient(tf.sign(pos))
178-
#neg_sign = tf.stop_gradient(tf.sign(neg))
179-
180-
#a_pos_dist = distance(anchor, pos_sign, pair=False, dist_type=self.dist_type)
181-
#a_neg_dist = distance(anchor, neg_sign, pair=False, dist_type=self.dist_type)
182-
#p_pos_dist = distance(anchor_sign, pos, pair=False, dist_type=self.dist_type)
183-
#p_neg_dist = distance(anchor_sign, neg_sign, pair=False, dist_type=self.dist_type)
184-
#n_pos_dist = distance(anchor_sign, pos_sign, pair=False, dist_type=self.dist_type)
185-
#n_neg_dist = distance(anchor_sign, neg, pair=False, dist_type=self.dist_type)
186-
187-
#basic_loss_a = tf.maximum(a_pos_dist - a_neg_dist + margin, 0.0)
188-
#basic_loss_p = tf.maximum(p_pos_dist - p_neg_dist + margin, 0.0)
189-
#basic_loss_n = tf.maximum(n_pos_dist - n_neg_dist + margin, 0.0)
190-
191-
#loss = tf.reduce_mean(basic_loss_a+basic_loss_p+basic_loss_n, 0)/3
192-
193-
#tf.summary.histogram('a_pos_dist', a_pos_dist)
194-
#tf.summary.histogram('a_neg_dist', a_neg_dist)
195-
#tf.summary.histogram('a_pos_dist - a_neg_dist', a_pos_dist - a_neg_dist)
196-
197-
# binarynet version
198-
199-
anchor_sign = self.quantize(anchor)
200-
pos_sign = self.quantize(pos)
201-
neg_sign = self.quantize(neg)
202-
203-
pos_dist = distance(anchor_sign, pos_sign, pair=False, dist_type=self.dist_type)
204-
neg_dist = distance(anchor_sign, neg_sign, pair=False, dist_type=self.dist_type)
205-
basic_loss = tf.maximum(pos_dist - neg_dist + margin, 0.0)
206-
207-
pos_dist_1 = distance(anchor, pos, pair=False, dist_type=self.dist_type)
208-
neg_dist_1 = distance(anchor, neg, pair=False, dist_type=self.dist_type)
209-
basic_loss_1 = tf.maximum(pos_dist_1 - neg_dist_1 + margin, 0.0)
210-
211-
loss = (tf.reduce_mean(basic_loss, 0) + tf.reduce_mean(basic_loss_1, 0)) / 2
212-
213-
tf.summary.histogram('pos_dist', pos_dist)
214-
tf.summary.histogram('neg_dist', neg_dist)
215-
tf.summary.histogram('pos_dist - neg_dist', pos_dist - neg_dist)
216-
else:
217-
pos_dist = distance(anchor, pos, pair=False, dist_type=self.dist_type)
218-
neg_dist = distance(anchor, neg, pair=False, dist_type=self.dist_type)
219-
basic_loss = tf.maximum(pos_dist - neg_dist + margin, 0.0)
220-
loss = tf.reduce_mean(basic_loss, 0)
221-
222-
tf.summary.histogram('pos_dist', pos_dist)
223-
tf.summary.histogram('neg_dist', neg_dist)
224-
tf.summary.histogram('pos_dist - neg_dist', pos_dist - neg_dist)
158+
pos_dist = distance(anchor, pos, pair=False, dist_type=self.dist_type)
159+
neg_dist = distance(anchor, neg, pair=False, dist_type=self.dist_type)
160+
basic_loss = tf.maximum(pos_dist - neg_dist + margin, 0.0)
161+
loss = tf.reduce_mean(basic_loss, 0)
162+
163+
tf.summary.histogram('pos_dist', pos_dist)
164+
tf.summary.histogram('neg_dist', neg_dist)
165+
tf.summary.histogram('pos_dist - neg_dist', pos_dist - neg_dist)
225166

226167
return loss
227168

228-
def c_quantization_loss(self, z, h):
229-
with tf.name_scope('c_quantization_loss'):
230-
q_loss = tf.reduce_mean(tf.reduce_sum(z - tf.matmul(h, self.C), -1))
231-
return q_loss
232-
233-
def quantization_loss(self, z):
169+
def quantization_loss(self, z, h):
234170
with tf.name_scope('quantization_loss'):
235-
q_loss = tf.reduce_mean(1.0 - tf.abs(z))
171+
q_loss = tf.reduce_mean(tf.reduce_sum(z - tf.matmul(h, self.C), -1))
236172
return q_loss
237173

238174
def apply_loss_function(self, global_step):
239175
anchor, pos, neg = tf.split(self.img_last_layer, 3, axis=0)
240176
triplet_loss = self.triplet_loss(anchor, pos, neg, self.triplet_margin)
241-
cq_loss = self.c_quantization_loss(self.img_last_layer, self.b_img)
242-
q_loss = self.quantization_loss(self.img_last_layer)
243-
self.loss = triplet_loss + cq_loss * self.cq_lambda + q_loss * self.q_lambda
177+
cq_loss = self.quantization_loss(self.img_last_layer, self.b_img)
178+
self.loss = triplet_loss + cq_loss * self.cq_lambda
244179

245-
# Last layer has a 10 times learning rate
246180
self.lr = tf.train.exponential_decay(
247181
self.learning_rate,
248182
global_step,
249183
self.decay_step,
250184
self.decay_factor,
251185
staircase=True)
252186
opt = tf.train.MomentumOptimizer(learning_rate=self.lr, momentum=0.9)
253-
254187
grads_and_vars = opt.compute_gradients(self.loss, self.train_layers+self.train_last_layer)
255188
fcgrad, _ = grads_and_vars[-2]
256189
fbgrad, _ = grads_and_vars[-1]
257190

258191
tf.summary.scalar('loss', self.loss)
259192
tf.summary.scalar('triplet_loss', triplet_loss)
260193
tf.summary.scalar('cq_loss', cq_loss)
261-
tf.summary.scalar('q_loss', q_loss)
262194
tf.summary.scalar('lr', self.lr)
263195
self.merged = tf.summary.merge_all()
264196

197+
# Last layer has a 10 times learning rate
265198
if self.finetune_all:
266199
return opt.apply_gradients([(grads_and_vars[0][0], self.train_layers[0]),
267200
(grads_and_vars[1][0]*2, self.train_layers[1]),
@@ -285,7 +218,6 @@ def apply_loss_function(self, global_step):
285218

286219
def initial_centers(self, img_output):
287220
C_init = np.zeros([self.subspace_num * self.subcenter_num, self.output_dim])
288-
print("#TripletQuantization train# initilizing Centers")
289221
all_output = img_output
290222
for i in range(self.subspace_num):
291223
start = i*int(self.output_dim/self.subspace_num)
@@ -375,7 +307,7 @@ def update_embedding_and_triplets(self, img_dataset):
375307
for i in range(epoch_iter):
376308
images, labels, codes = img_dataset.next_batch(self.batch_size)
377309
output = self.sess.run(self.img_last_layer,
378-
feed_dict={self.img: images, self.img_label: labels, self.b_img: codes})
310+
feed_dict={self.img: images, self.b_img: codes})
379311

380312
img_dataset.feed_batch_output(self.batch_size, output)
381313
img_dataset.update_triplets(self.triplet_margin, n_part=self.n_part, select_strategy=self.select_strategy)
@@ -415,7 +347,6 @@ def train_cq(self, img_dataset, img_query, img_database, R):
415347
_, output, loss, summary = self.sess.run(
416348
[self.train_op, self.img_last_layer, self.loss, self.merged],
417349
feed_dict={self.img: images,
418-
self.img_label: labels,
419350
self.b_img: codes})
420351
img_dataset.feed_batch_triplet_output(triplet_batch_size, output)
421352
if train_iter < 100 or i % 100 == 0:
@@ -455,7 +386,6 @@ def val_forward(self, img_dataset, val_print_freq=100):
455386
images, labels, codes = img_dataset.next_batch(self.val_batch_size)
456387
output = self.sess.run([self.img_last_layer],
457388
feed_dict={self.img: images,
458-
self.img_label: labels,
459389
self.stage: 1})
460390
img_dataset.feed_batch_output(self.val_batch_size, output)
461391
if i % val_print_freq == 0:
@@ -480,32 +410,11 @@ def validation(self, img_query, img_database, R=100):
480410
# Evaluation
481411
print("%s #validation# calculating MAP@%d" % (datetime.now(), R))
482412
C_tmp = self.sess.run(self.C)
483-
413+
mAPs = MAPs_CQ(C_tmp, self.subspace_num, self.subcenter_num, R)
484414
self.save_codes(img_database, img_query, C_tmp)
485-
486-
mAPs = MAPs(R)
487-
prec, rec, mmap = mAPs.get_precision_recall_by_Hamming_Radius(img_database, img_query, 2)
488-
489415
return {
490416
'map_feature_ip': mAPs.get_mAPs_by_feature(img_database, img_query),
491-
'map_sign_ip': mAPs.get_mAPs_after_sign(img_database, img_query),
492-
'prec_radius_2': prec,
493-
'recall_radius_2': rec,
494-
'map_radius_2': mmap
417+
'map_AQD_ip': mAPs.get_mAPs_AQD(img_database, img_query),
418+
'map_SQD_ip': mAPs.get_mAPs_SQD(img_database, img_query)
495419
}
496420

497-
498-
def train(train_img, database_img, query_img, config):
499-
model = TripletQuantization(config) # 0 for train, 1 for val
500-
img_database = Dataset(database_img, config.output_dim, config.n_subspace * config.n_subcenter)
501-
img_query = Dataset(query_img, config.output_dim, config.n_subspace * config.n_subcenter)
502-
img_train = Dataset(train_img, config.output_dim, config.n_subspace * config.n_subcenter)
503-
model.train_cq(img_train, img_query, img_database, config.R)
504-
return model.save_dir
505-
506-
507-
def validation(database_img, query_img, config):
508-
model = TripletQuantization(config) # 0 for train, 1 for val
509-
img_database = Dataset(database_img, config.output_dim, config.n_subspace * config.n_subcenter)
510-
img_query = Dataset(query_img, config.output_dim, config.n_subspace * config.n_subcenter)
511-
return model.validation(img_query, img_database, config.R)
Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,6 @@ def update_triplets(self, margin, n_part=10, dist_type='euclidean2', select_stra
2424
:param margin: triplet margin parameter
2525
:n_part: number of part to split data
2626
"""
27-
ifsign = False
28-
if 'sign-' in select_strategy:
29-
ifsign = True
30-
select_strategy = select_strategy.replace("sign-", "")
31-
3227
n_samples = self.n_samples
3328
np.random.shuffle(self._perm)
3429
embedding = self._output[self._perm[:n_samples]]
@@ -38,7 +33,7 @@ def update_triplets(self, margin, n_part=10, dist_type='euclidean2', select_stra
3833
for i in range(n_part):
3934
start = n_samples_per_part * i
4035
end = min(n_samples_per_part * (i+1), n_samples)
41-
dist = distance(embedding[start:end], pair=True, dist_type=dist_type, ifsign=ifsign)
36+
dist = distance(embedding[start:end], pair=True, dist_type=dist_type)
4237
for idx_anchor in range(0, end - start):
4338
label_anchor = np.copy(labels[idx_anchor+start, :])
4439
label_anchor[label_anchor==0] = -1
@@ -57,24 +52,13 @@ def update_triplets(self, margin, n_part=10, dist_type='euclidean2', select_stra
5752
if idx_pos == idx_anchor:
5853
continue
5954

60-
if select_strategy == 'all' or select_strategy == 'prob':
55+
if select_strategy == 'all':
6156
selected_neg = all_neg
6257
elif select_strategy == 'margin':
6358
selected_neg = all_neg[np.where(dist[idx_anchor, all_neg] - dist[idx_anchor, idx_pos] < margin)[0]]
64-
elif select_strategy == 'hardneg':
65-
idx_neg = all_neg[np.argmin(dist[idx_anchor, all_neg])]
66-
selected_neg = np.array([])
67-
if (dist[idx_anchor, idx_neg] - dist[idx_anchor, idx_pos] < margin):
68-
selected_neg = np.array([idx_neg])
69-
#selected_neg = all_neg[np.where(dist[idx_anchor, all_neg] - dist[idx_anchor, idx_pos] < margin)[0]]
7059

7160
if selected_neg.shape[0] > 0:
72-
if select_strategy == 'prob':
73-
prob = np.maximum(margin - dist[idx_anchor, all_neg] + dist[idx_anchor, idx_pos], 0)
74-
prob = prob / np.sum(prob)
75-
idx_neg = np.random.choice(selected_neg, p=prob)
76-
else:
77-
idx_neg = np.random.choice(selected_neg)
61+
idx_neg = np.random.choice(selected_neg)
7862
triplets.append((idx_anchor + start, idx_pos + start, idx_neg + start))
7963
self._triplets = np.array(triplets)
8064
np.random.shuffle(self._triplets)

core/model/triplet_hash/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)