├── .gitignore ├── DeepHash ├── __init__.py ├── architecture │ └── __init__.py ├── data_provider │ ├── __init__.py │ ├── image │ │ └── __init__.py │ └── text │ │ └── __init__.py ├── distance │ ├── __init__.py │ ├── npversion.py │ └── tfversion.py ├── evaluation │ ├── __init__.py │ └── load_and_predict.py ├── model │ ├── __init__.py │ ├── dch │ │ ├── .dch.py.swo │ │ ├── __init__.py │ │ ├── dch.py │ │ └── util.py │ ├── dhn │ │ ├── __init__.py │ │ ├── dhn.py │ │ └── util.py │ ├── dqn │ │ ├── __init__.py │ │ ├── dqn.py │ │ └── util.py │ ├── dtq │ │ ├── __init__.py │ │ ├── dtq.py │ │ └── util.py │ ├── dvsq │ │ ├── __init__.py │ │ ├── dvsq.py │ │ └── util.py │ └── plot.py └── util │ └── __init__.py ├── LICENSE ├── README.md ├── __init__.py ├── data ├── cifar10 │ ├── cifar10_wordvec.txt │ ├── database.txt │ ├── test.txt │ └── train.txt ├── coco │ ├── database.txt │ ├── test.txt │ └── train.txt └── nuswide_81 │ ├── database.txt │ ├── images │ ├── nuswide_81_wordvec.txt │ ├── test.txt │ └── train.txt ├── examples ├── __init__.py ├── dch │ └── train_val_script.py ├── dhn │ ├── train_val.sh │ └── train_val_script.py ├── dqn │ ├── train_val.sh │ └── train_val_script.py ├── dtq │ └── train_val_script.py └── dvsq │ ├── train_val.sh │ └── train_val_script.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | 103 | pretrained_model/ 104 | tflog/ 105 | models/ 106 | *.swp 107 | -------------------------------------------------------------------------------- /DeepHash/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thulab/DeepHash/9907613e1b73818985bc585af613a960c8df7d20/DeepHash/__init__.py -------------------------------------------------------------------------------- /DeepHash/architecture/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tensorflow as tf 3 | import numpy as np 4 | 5 | 6 | def img_alexnet_layers(img, batch_size, output_dim, stage, model_weights, with_tanh=True, val_batch_size=32): 7 | deep_param_img = {} 8 | train_layers = [] 9 | train_last_layer = [] 10 | print("loading img model from %s" % model_weights) 11 | net_data = dict(np.load(model_weights, encoding='bytes').item()) 12 | print(list(net_data.keys())) 13 | 14 | # swap(2,1,0), bgr -> rgb 15 | reshaped_image = tf.cast(img, tf.float32)[:, :, :, ::-1] 16 | 17 | height = 227 18 | width = 227 19 | 20 | # Randomly crop a [height, width] section of each image 21 | with tf.name_scope('preprocess'): 22 | def train_fn(): 23 | return tf.stack([tf.random_crop(tf.image.random_flip_left_right(each), [height, width, 3]) 24 | for each in tf.unstack(reshaped_image, batch_size)]) 25 | 26 | def val_fn(): 27 | unstacked = tf.unstack(reshaped_image, val_batch_size) 28 | 29 | def crop(img, x, y): return tf.image.crop_to_bounding_box( 30 | img, x, y, width, height) 31 | 32 | def distort(f, x, y): return tf.stack( 33 | [crop(f(each), x, y) for each in unstacked]) 34 | 35 | def distort_raw(x, y): return distort(lambda x: x, x, y) 36 | 37 | def distort_fliped(x, y): return distort( 38 | tf.image.flip_left_right, x, y) 39 | distorted = tf.concat([distort_fliped(0, 0), distort_fliped(28, 0), 40 | distort_fliped( 41 | 0, 28), distort_fliped(28, 28), 42 | distort_fliped(14, 14), distort_raw(0, 0), 43 | distort_raw(28, 0), distort_raw(0, 28), 44 | distort_raw(28, 28), distort_raw(14, 14)], 0) 45 | 46 | return distorted 47 | distorted = tf.cond(stage > 0, val_fn, train_fn) 48 | 49 | # Zero-mean input 50 | mean = tf.constant([123.68, 116.779, 103.939], dtype=tf.float32, shape=[ 51 | 1, 1, 1, 3], name='img-mean') 52 | distorted = distorted - mean 53 | 54 | # Conv1 55 | # Output 96, kernel 11, stride 4 56 | with tf.name_scope('conv1') as scope: 57 | kernel = tf.Variable(net_data['conv1'][0], name='weights') 58 | conv = tf.nn.conv2d(distorted, kernel, [1, 4, 4, 1], padding='VALID') 59 | biases = tf.Variable(net_data['conv1'][1], name='biases') 60 | out = tf.nn.bias_add(conv, biases) 61 | conv1 = tf.nn.relu(out, name=scope) 62 | deep_param_img['conv1'] = [kernel, biases] 63 | train_layers += [kernel, biases] 64 | 65 | # Pool1 66 | pool1 = tf.nn.max_pool(conv1, 67 | ksize=[1, 3, 3, 1], 68 | strides=[1, 2, 2, 1], 69 | padding='VALID', 70 | name='pool1') 71 | 72 | # LRN1 73 | radius = 2 74 | alpha = 2e-05 75 | beta = 0.75 76 | bias = 1.0 77 | lrn1 = tf.nn.local_response_normalization(pool1, 78 | depth_radius=radius, 79 | alpha=alpha, 80 | beta=beta, 81 | bias=bias) 82 | 83 | # Conv2 84 | # Output 256, pad 2, kernel 5, group 2 85 | with tf.name_scope('conv2') as scope: 86 | kernel = tf.Variable(net_data['conv2'][0], name='weights') 87 | group = 2 88 | 89 | def convolve(i, k): return tf.nn.conv2d( 90 | i, k, [1, 1, 1, 1], padding='SAME') 91 | input_groups = tf.split(lrn1, group, 3) 92 | kernel_groups = tf.split(kernel, group, 3) 93 | output_groups = [convolve(i, k) 94 | for i, k in zip(input_groups, kernel_groups)] 95 | # Concatenate the groups 96 | conv = tf.concat(output_groups, 3) 97 | 98 | biases = tf.Variable(net_data['conv2'][1], name='biases') 99 | out = tf.nn.bias_add(conv, biases) 100 | conv2 = tf.nn.relu(out, name=scope) 101 | deep_param_img['conv2'] = [kernel, biases] 102 | train_layers += [kernel, biases] 103 | 104 | # Pool2 105 | pool2 = tf.nn.max_pool(conv2, 106 | ksize=[1, 3, 3, 1], 107 | strides=[1, 2, 2, 1], 108 | padding='VALID', 109 | name='pool2') 110 | 111 | # LRN2 112 | radius = 2 113 | alpha = 2e-05 114 | beta = 0.75 115 | bias = 1.0 116 | lrn2 = tf.nn.local_response_normalization(pool2, 117 | depth_radius=radius, 118 | alpha=alpha, 119 | beta=beta, 120 | bias=bias) 121 | 122 | # Conv3 123 | # Output 384, pad 1, kernel 3 124 | with tf.name_scope('conv3') as scope: 125 | kernel = tf.Variable(net_data['conv3'][0], name='weights') 126 | conv = tf.nn.conv2d(lrn2, kernel, [1, 1, 1, 1], padding='SAME') 127 | biases = tf.Variable(net_data['conv3'][1], name='biases') 128 | out = tf.nn.bias_add(conv, biases) 129 | conv3 = tf.nn.relu(out, name=scope) 130 | deep_param_img['conv3'] = [kernel, biases] 131 | train_layers += [kernel, biases] 132 | 133 | # Conv4 134 | # Output 384, pad 1, kernel 3, group 2 135 | with tf.name_scope('conv4') as scope: 136 | kernel = tf.Variable(net_data['conv4'][0], name='weights') 137 | group = 2 138 | 139 | def convolve(i, k): return tf.nn.conv2d( 140 | i, k, [1, 1, 1, 1], padding='SAME') 141 | input_groups = tf.split(conv3, group, 3) 142 | kernel_groups = tf.split(kernel, group, 3) 143 | output_groups = [convolve(i, k) 144 | for i, k in zip(input_groups, kernel_groups)] 145 | # Concatenate the groups 146 | conv = tf.concat(output_groups, 3) 147 | biases = tf.Variable(net_data['conv4'][1], name='biases') 148 | out = tf.nn.bias_add(conv, biases) 149 | conv4 = tf.nn.relu(out, name=scope) 150 | deep_param_img['conv4'] = [kernel, biases] 151 | train_layers += [kernel, biases] 152 | 153 | # Conv5 154 | # Output 256, pad 1, kernel 3, group 2 155 | with tf.name_scope('conv5') as scope: 156 | kernel = tf.Variable(net_data['conv5'][0], name='weights') 157 | group = 2 158 | 159 | def convolve(i, k): return tf.nn.conv2d( 160 | i, k, [1, 1, 1, 1], padding='SAME') 161 | input_groups = tf.split(conv4, group, 3) 162 | kernel_groups = tf.split(kernel, group, 3) 163 | output_groups = [convolve(i, k) 164 | for i, k in zip(input_groups, kernel_groups)] 165 | # Concatenate the groups 166 | conv = tf.concat(output_groups, 3) 167 | biases = tf.Variable(net_data['conv5'][1], name='biases') 168 | out = tf.nn.bias_add(conv, biases) 169 | conv5 = tf.nn.relu(out, name=scope) 170 | deep_param_img['conv5'] = [kernel, biases] 171 | train_layers += [kernel, biases] 172 | 173 | # Pool5 174 | pool5 = tf.nn.max_pool(conv5, 175 | ksize=[1, 3, 3, 1], 176 | strides=[1, 2, 2, 1], 177 | padding='VALID', 178 | name='pool5') 179 | 180 | # FC6 181 | # Output 4096 182 | with tf.name_scope('fc6'): 183 | shape = int(np.prod(pool5.get_shape()[1:])) 184 | fc6w = tf.Variable(net_data['fc6'][0], name='weights') 185 | fc6b = tf.Variable(net_data['fc6'][1], name='biases') 186 | pool5_flat = tf.reshape(pool5, [-1, shape]) 187 | fc6l = tf.nn.bias_add(tf.matmul(pool5_flat, fc6w), fc6b) 188 | fc6 = tf.nn.relu(fc6l) 189 | fc6 = tf.cond(stage > 0, lambda: fc6, lambda: tf.nn.dropout(fc6, 0.5)) 190 | fc6o = tf.nn.relu(fc6l) 191 | deep_param_img['fc6'] = [fc6w, fc6b] 192 | train_layers += [fc6w, fc6b] 193 | 194 | # FC7 195 | # Output 4096 196 | with tf.name_scope('fc7'): 197 | fc7w = tf.Variable(net_data['fc7'][0], name='weights') 198 | fc7b = tf.Variable(net_data['fc7'][1], name='biases') 199 | fc7l = tf.nn.bias_add(tf.matmul(fc6, fc7w), fc7b) 200 | fc7 = tf.nn.relu(fc7l) 201 | fc7 = tf.cond(stage > 0, lambda: fc7, lambda: tf.nn.dropout(fc7, 0.5)) 202 | deep_param_img['fc7'] = [fc7w, fc7b] 203 | train_layers += [fc7w, fc7b] 204 | 205 | # FC8 206 | # Output output_dim 207 | with tf.name_scope('fc8'): 208 | # Differ train and val stage by 'fc8' as key 209 | if 'fc8' in net_data: 210 | fc8w = tf.Variable(net_data['fc8'][0], name='weights') 211 | fc8b = tf.Variable(net_data['fc8'][1], name='biases') 212 | else: 213 | fc8w = tf.Variable(tf.random_normal([4096, output_dim], 214 | dtype=tf.float32, 215 | stddev=1e-2), name='weights') 216 | fc8b = tf.Variable(tf.constant(0.0, shape=[output_dim], 217 | dtype=tf.float32), name='biases') 218 | fc8l = tf.nn.bias_add(tf.matmul(fc7, fc8w), fc8b) 219 | if with_tanh: 220 | fc8_t = tf.nn.tanh(fc8l) 221 | else: 222 | fc8_t = fc8l 223 | 224 | def val_fn1(): 225 | concated = tf.concat([tf.expand_dims(i, 0) 226 | for i in tf.split(fc8_t, 10, 0)], 0) 227 | return tf.reduce_mean(concated, 0) 228 | fc8 = tf.cond(stage > 0, val_fn1, lambda: fc8_t) 229 | deep_param_img['fc8'] = [fc8w, fc8b] 230 | train_last_layer += [fc8w, fc8b] 231 | 232 | print("img model loading finished") 233 | # Return outputs 234 | return fc8, deep_param_img, train_layers, train_last_layer 235 | 236 | 237 | def txt_mlp_layers(txt, txt_dim, output_dim, stage, model_weights=None, with_tanh=True): 238 | deep_param_txt = {} 239 | train_layers = [] 240 | train_last_layer = [] 241 | 242 | if model_weights is None: 243 | dir_path = os.path.dirname(os.path.realpath(__file__)) 244 | model_weights = os.path.join( 245 | dir_path, "pretrained_model/reference_pretrain.npy") 246 | 247 | net_data = dict(np.load(model_weights, encoding='bytes').item()) 248 | 249 | # txt_fc1 250 | with tf.name_scope('txt_fc1'): 251 | if 'txt_fc1' not in net_data: 252 | txt_fc1w = tf.Variable(tf.truncated_normal([txt_dim, 4096], 253 | dtype=tf.float32, 254 | stddev=1e-2), name='weights') 255 | txt_fc1b = tf.Variable(tf.constant(0.0, shape=[4096], dtype=tf.float32), 256 | trainable=True, name='biases') 257 | else: 258 | txt_fc1w = tf.Variable(net_data['txt_fc1'][0], name='weights') 259 | txt_fc1b = tf.Variable(net_data['txt_fc1'][1], name='biases') 260 | txt_fc1l = tf.nn.bias_add(tf.matmul(txt, txt_fc1w), txt_fc1b) 261 | 262 | txt_fc1 = tf.cond(stage > 0, lambda: tf.nn.relu( 263 | txt_fc1l), lambda: tf.nn.dropout(tf.nn.relu(txt_fc1l), 0.5)) 264 | 265 | train_layers += [txt_fc1w, txt_fc1b] 266 | deep_param_txt['txt_fc1'] = [txt_fc1w, txt_fc1b] 267 | 268 | # txt_fc2 269 | with tf.name_scope('txt_fc2'): 270 | if 'txt_fc2' not in net_data: 271 | txt_fc2w = tf.Variable(tf.truncated_normal([4096, output_dim], 272 | dtype=tf.float32, 273 | stddev=1e-2), name='weights') 274 | txt_fc2b = tf.Variable(tf.constant(0.0, shape=[output_dim], dtype=tf.float32), 275 | trainable=True, name='biases') 276 | else: 277 | txt_fc2w = tf.Variable(net_data['txt_fc2'][0], name='weights') 278 | txt_fc2b = tf.Variable(net_data['txt_fc2'][1], name='biases') 279 | 280 | txt_fc2l = tf.nn.bias_add(tf.matmul(txt_fc1, txt_fc2w), txt_fc2b) 281 | if with_tanh: 282 | txt_fc2 = tf.nn.tanh(txt_fc2l) 283 | else: 284 | txt_fc2 = txt_fc2l 285 | 286 | train_layers += [txt_fc2w, txt_fc2b] 287 | train_last_layer += [txt_fc2w, txt_fc2b] 288 | deep_param_txt['txt_fc2'] = [txt_fc2w, txt_fc2b] 289 | 290 | # return the output of text layer 291 | return txt_fc2, deep_param_txt, train_layers, train_last_layer 292 | -------------------------------------------------------------------------------- /DeepHash/data_provider/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thulab/DeepHash/9907613e1b73818985bc585af613a960c8df7d20/DeepHash/data_provider/__init__.py -------------------------------------------------------------------------------- /DeepHash/data_provider/image/__init__.py: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # ============================================================================== 15 | 16 | """Routine for decoding the NUS-WIDE binary file format.""" 17 | 18 | import os 19 | import cv2 20 | import numpy as np 21 | 22 | 23 | # Process images of this size. Note that this differs from the original nus-wide 24 | # image size of 224 x 224. If one alters this number, then the entire model 25 | # architecture will change and any model would need to be retrained. 26 | 27 | # Global constants describing the NUS-WIDE data set. 28 | 29 | 30 | class Dataset(object): 31 | def __init__(self, modal, data_root, path, train=True): 32 | self.lines = open(path, 'r').readlines() 33 | self.data_root = data_root 34 | self.n_samples = len(self.lines) 35 | self.train = train 36 | assert modal == 'img' 37 | self.modal = 'img' 38 | self._img = [0] * self.n_samples 39 | self._label = [0] * self.n_samples 40 | self._load = [0] * self.n_samples 41 | self._load_num = 0 42 | self._status = 0 43 | self.data = self.img_data 44 | self.all_data = self.img_all_data 45 | 46 | def get_img(self, i): 47 | path = os.path.join(self.data_root, self.lines[i].strip().split()[0]) 48 | return cv2.resize(cv2.imread(path), (256, 256)) 49 | 50 | def get_label(self, i): 51 | return [int(j) for j in self.lines[i].strip().split()[1:]] 52 | 53 | def img_data(self, indexes): 54 | if self._status: 55 | return (self._img[indexes, :], self._label[indexes, :]) 56 | else: 57 | ret_img = [] 58 | ret_label = [] 59 | for i in indexes: 60 | try: 61 | if self.train: 62 | if not self._load[i]: 63 | self._img[i] = self.get_img(i) 64 | self._label[i] = self.get_label(i) 65 | self._load[i] = 1 66 | self._load_num += 1 67 | ret_img.append(self._img[i]) 68 | ret_label.append(self._label[i]) 69 | else: 70 | self._label[i] = self.get_label(i) 71 | ret_img.append(self.get_img(i)) 72 | ret_label.append(self._label[i]) 73 | except Exception as e: 74 | print('cannot open {}, exception: {}'.format(self.lines[i].strip(), e)) 75 | 76 | if self._load_num == self.n_samples: 77 | self._status = 1 78 | self._img = np.asarray(self._img) 79 | self._label = np.asarray(self._label) 80 | return (np.asarray(ret_img), np.asarray(ret_label)) 81 | 82 | def img_all_data(self): 83 | if self._status: 84 | return (self._img, self._label) 85 | 86 | def get_labels(self): 87 | for i in range(self.n_samples): 88 | if self._label[i] is not list: 89 | self._label[i] = [int(j) 90 | for j in self.lines[i].strip().split()[1:]] 91 | return np.asarray(self._label) 92 | 93 | 94 | def import_train(data_root, img_tr): 95 | ''' 96 | return (img_tr, txt_tr) 97 | ''' 98 | return (Dataset('img', data_root, img_tr, train=True)) 99 | 100 | 101 | def import_validation(data_root, img_te, img_db): 102 | ''' 103 | return (img_te, txt_te, img_db, txt_db) 104 | ''' 105 | return (Dataset('img', data_root, img_te, train=False), 106 | Dataset('img', data_root, img_db, train=False)) 107 | -------------------------------------------------------------------------------- /DeepHash/data_provider/text/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # 6 | # http://www.apache.org/licenses/LICENSE-2.0 7 | # 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | # ============================================================================== 14 | 15 | """Routine for decoding the NUS-WIDE binary file format.""" 16 | 17 | import h5py 18 | import numpy as np 19 | 20 | 21 | # Process images of this size. Note that this differs from the original nus-wide 22 | # image size of 224 x 224. If one alters this number, then the entire model 23 | # architecture will change and any model would need to be retrained. 24 | 25 | # Global constants describing the NUS-WIDE data set. 26 | 27 | class Dataset(object): 28 | def __init__(self, modal, path, train=True): 29 | self.lines = open(path, 'r').readlines() 30 | self.n_samples = len(self.lines) 31 | self.train = train 32 | if modal == 'txt': 33 | self.modal = 'txt' 34 | self._txt = [0] * self.n_samples 35 | self._label = [0] * self.n_samples 36 | self._load = [0] * self.n_samples 37 | self._load_num = 0 38 | self._status = 0 39 | self.data = self.txt_data 40 | self.all_data = self.txt_all_data 41 | 42 | def txt_data(self, index): 43 | if self._status: 44 | return (self._txt[index, :], self._label[index, :]) 45 | else: 46 | ret_txt = [] 47 | ret_label = [] 48 | for i in index: 49 | try: 50 | if self.train: 51 | if not self._load[i]: 52 | self._txt[i] = h5py.File(self.lines[i].split('\n')[0], 'r')["data"][0] 53 | self._label[i] = [int(j) for j in h5py.File(self.lines[i].split('\n')[0], 'r')['label1'][0]] 54 | self._load[i] = 1 55 | self._load_num += 1 56 | ret_txt.append(self._txt[i]) 57 | ret_label.append(self._label[i]) 58 | else: 59 | # self._label[i] = [int(j) for j in h5py.File(self.lines[i].split('\n')[0], 'r')['label1'][0]] 60 | f = h5py.File(self.lines[i].split('\n')[0], 'r') 61 | ret_txt.append(f["data"][0]) 62 | ret_label.append([int(j) for j in f['label1'][0]]) 63 | f.close() 64 | except: 65 | print('cannot open', self.lines[i].split('\n')[0]) 66 | 67 | if self._load_num == self.n_samples: 68 | self._status = 1 69 | self._txt = np.reshape(np.asarray(self._txt), (self.n_samples, len(self._txt[0]))) 70 | self._label = np.asarray(self._label) 71 | return np.reshape(np.asarray(ret_txt), (len(index), -1)), np.asarray(ret_label) 72 | 73 | def txt_all_data(self): 74 | if self._status: 75 | return (self._txt, self._label) 76 | 77 | def get_labels(self): 78 | for i in range(self.n_samples): 79 | if self._label[i] == 0: 80 | if self.modal == 'img': 81 | self._label[i] = [int(j) for j in self.lines[i].strip().split()[1:]] 82 | elif self.modal == 'txt': 83 | f = h5py.File(self.lines[i].split('\n')[0], 'r') 84 | self._label[i] = [int(j) for j in f['label1'][0]] 85 | f.close() 86 | return np.asarray(self._label) 87 | 88 | 89 | def import_train(txt_tr): 90 | return (Dataset('txt', txt_tr, train=True)) 91 | 92 | 93 | def import_validation(txt_te, txt_db): 94 | return (Dataset('txt', txt_te, train=False), 95 | Dataset('txt', txt_db, train=False)) 96 | -------------------------------------------------------------------------------- /DeepHash/distance/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thulab/DeepHash/9907613e1b73818985bc585af613a960c8df7d20/DeepHash/distance/__init__.py -------------------------------------------------------------------------------- /DeepHash/distance/npversion.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import sys 3 | import util 4 | 5 | def norm(x, keepdims=False): 6 | ''' 7 | Param: 8 | x: matrix of shape (n1, n2, ..., nk) 9 | keepdims: Whether keep dims or not 10 | Return: norm of matrix of shape (n1, n2, ..., n_{k-1}) 11 | ''' 12 | return np.sqrt(np.sum(np.square(x), axis=-1, keepdims=keepdims)) 13 | 14 | def normed(x): 15 | ''' 16 | Param: matrix of shape (n1, n2, ..., nk) 17 | Return: normed matrix 18 | ''' 19 | return x / (1e-20 + norm(x, keepdims=True)) 20 | 21 | def euclidean2(x1, x2): 22 | return np.sum(np.square(x1 - x2), axis=-1) 23 | 24 | def euclidean(x1, x2): 25 | return np.sqrt(euclidean2(x1, x2)) 26 | 27 | def averaged_euclidean2(x1, x2): 28 | return np.mean(np.square(x1 - x2), axis=-1) 29 | 30 | def averaged_euclidean(x1, x2): 31 | return np.sqrt(averaged_euclidean2(x1, x2)) 32 | 33 | def normed_euclidean2(x1, x2): 34 | return euclidean2(normed(x1), normed(x2)) 35 | 36 | def inner_product(x1, x2, pair=False): 37 | if pair: 38 | return - np.inner(x1, x2) 39 | else: 40 | return - np.sum(x1 * x2, axis=-1) 41 | 42 | def cosine(x1, x2): 43 | return (1 + inner_product(normed(x1), normed(x2))) / 2 44 | 45 | def distance(x1, x2=None, pair=True, dist_type="euclidean2", ifsign=False): 46 | ''' 47 | Param: 48 | x2: if x2 is None, distance between x1 and x1 will be returned. 49 | pair: if True, for i, j, x1_i, x2_j will be calculated 50 | if False, for i, x1_i, x2_i will be calculated, and it requires the dimension of x1 and x2 is same. 51 | dist_type: distance type, can be euclidean2, normed_euclidean2, inner_product, cosine 52 | ''' 53 | if x2 is None: 54 | x2 = x1 55 | if ifsign: 56 | x1 = util.sign(x1) 57 | x2 = util.sign(x2) 58 | if dist_type == 'inner_product': 59 | return inner_product(x1, x2, pair) 60 | if pair: 61 | x1 = np.expand_dims(x1, 1) 62 | x2 = np.expand_dims(x2, 0) 63 | return getattr(sys.modules[__name__], dist_type)(x1, x2) 64 | 65 | if __name__ == "__main__": 66 | def myAssert(x1, x2): 67 | assert np.mean(x1 - x2) < 1e-8 68 | x1 = 2 * np.array([[1, 1, 1], [1, 1, 0], [1, 0, 1], [0, 1, 1]]) 69 | x2 = 3 * np.eye(3) 70 | myAssert(distance(x1, x2, pair=True, dist_type="euclidean2"), 71 | np.array([[ 9., 9., 9.], 72 | [ 5., 5., 17.], 73 | [ 5., 17., 5.], 74 | [ 17., 5., 5.]]) ) 75 | myAssert(distance(x1, x2, pair=True, dist_type="normed_euclidean2"), 76 | np.array([[ 0.84529946, 0.84529946, 0.84529946], 77 | [ 0.58578644, 0.58578644, 2. ], 78 | [ 0.58578644, 2. , 0.58578644], 79 | [ 2. , 0.58578644, 0.58578644]])) 80 | assert distance(x1, x2, pair=True, dist_type="cosine").shape == (4, 3) 81 | assert distance(x1, x2, pair=True, dist_type="inner_product").shape == (4, 3) 82 | 83 | assert np.all(distance(x1, x1[::-1], pair=False, dist_type="euclidean2") == np.array([4, 8, 8, 4])) 84 | myAssert(distance(x1, x1[::-1], pair=False, dist_type="normed_euclidean2"), np.array([ 0.36700684, 1., 1., 0.36700684])) 85 | myAssert(distance(x1, x1[::-1], pair=False, dist_type="cosine"), np.array([ 0.09175171, 0.25, 0.25, 0.09175171])) 86 | assert np.all(distance(x1, x1[::-1], pair=False, dist_type="inner_product") == np.array([-8, -4, -4, -8])) 87 | -------------------------------------------------------------------------------- /DeepHash/distance/tfversion.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import sys 3 | import numpy as np 4 | 5 | def norm(x, keepdims=False): 6 | ''' 7 | Param: 8 | x: matrix of shape (n1, n2, ..., nk) 9 | keepdims: Whether keep dims or not 10 | Return: norm of matrix of shape (n1, n2, ..., n_{k-1}) 11 | ''' 12 | return tf.sqrt(tf.reduce_sum(tf.square(x), axis=-1, keep_dims=keepdims)) 13 | 14 | def normed(x): 15 | ''' 16 | Param: matrix of shape (n1, n2, ..., nk) 17 | Return: normed matrix 18 | ''' 19 | return x / norm(x, keepdims=True) 20 | 21 | def euclidean2(x1, x2): 22 | return tf.reduce_sum(tf.square(x1 - x2), axis=-1) 23 | 24 | def euclidean(x1, x2): 25 | return tf.sqrt(euclidean2(x1, x2)) 26 | 27 | def averaged_euclidean2(x1, x2): 28 | return tf.reduce_mean(tf.square(x1 - x2), axis=-1) 29 | 30 | def averaged_euclidean(x1, x2): 31 | return tf.sqrt(averaged_euclidean2(x1, x2)) 32 | 33 | def normed_euclidean2(x1, x2): 34 | return euclidean2(normed(x1), normed(x2)) 35 | 36 | def inner_product(x1, x2): 37 | return - tf.reduce_sum(x1 * x2, axis=-1) 38 | 39 | def cosine(x1, x2): 40 | return (1 + inner_product(normed(x1), normed(x2))) / 2 41 | 42 | def distance(x1, x2=None, pair=True, dist_type="euclidean2"): 43 | ''' 44 | Param: 45 | x2: if x2 is None, distance between x1 and x1 will be returned. 46 | pair: if True, for i, j, x1_i, x2_j will be calculated 47 | if False, for i, x1_i, x2_i will be calculated, and it requires the dimension of x1 and x2 is same. 48 | dist_type: distance type, can be euclidean2, normed_euclidean2, inner_product, cosine 49 | ''' 50 | if x2 is None: 51 | x2 = x1 52 | if pair: 53 | x1 = tf.expand_dims(x1, 1) 54 | x2 = tf.expand_dims(x2, 0) 55 | return getattr(sys.modules[__name__], dist_type)(x1, x2) 56 | 57 | if __name__ == "__main__": 58 | sess = tf.InteractiveSession() 59 | def myAssert(x1, x2): 60 | assert np.mean(x1 - x2) < 1e-8 61 | x1 = 2 * np.array([[1, 1, 1], [1, 1, 0], [1, 0, 1], [0, 1, 1]], dtype=float) 62 | x2 = 3 * np.eye(3, dtype=float) 63 | myAssert(distance(x1, x2, pair=True, dist_type="euclidean2").eval(), 64 | np.array([[ 9., 9., 9.], 65 | [ 5., 5., 17.], 66 | [ 5., 17., 5.], 67 | [ 17., 5., 5.]]) ) 68 | myAssert(distance(x1, x2, pair=True, dist_type="normed_euclidean2").eval(), 69 | np.array([[ 0.84529946, 0.84529946, 0.84529946], 70 | [ 0.58578644, 0.58578644, 2. ], 71 | [ 0.58578644, 2. , 0.58578644], 72 | [ 2. , 0.58578644, 0.58578644]])) 73 | assert distance(x1, x2, pair=True, dist_type="cosine").eval().shape == (4, 3) 74 | assert distance(x1, x2, pair=True, dist_type="inner_product").eval().shape == (4, 3) 75 | 76 | assert np.all(distance(x1, x1[::-1], pair=False, dist_type="euclidean2").eval() == np.array([4, 8, 8, 4])) 77 | myAssert(distance(x1, x1[::-1], pair=False, dist_type="normed_euclidean2").eval(), np.array([ 0.36700684, 1., 1., 0.36700684])) 78 | myAssert(distance(x1, x1[::-1], pair=False, dist_type="cosine").eval(), np.array([ 0.09175171, 0.25, 0.25, 0.09175171])) 79 | assert np.all(distance(x1, x1[::-1], pair=False, dist_type="inner_product").eval() == np.array([-8, -4, -4, -8])) 80 | -------------------------------------------------------------------------------- /DeepHash/evaluation/__init__.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from distance.npversion import distance 4 | from util import sign 5 | 6 | 7 | # optimized 8 | def get_mAPs(q_output, q_labels, db_output, db_labels, Rs, dist_type): 9 | dist = distance(q_output, db_output, dist_type=dist_type, pair=True) 10 | unsorted_ids = np.argpartition(dist, Rs - 1)[:, :Rs] 11 | APx = [] 12 | for i in range(dist.shape[0]): 13 | label = q_labels[i, :] 14 | label[label == 0] = -1 15 | idx = unsorted_ids[i, :] 16 | idx = idx[np.argsort(dist[i, :][idx])] 17 | imatch = np.sum(np.equal(db_labels[idx[0: Rs], :], label), 1) > 0 18 | rel = np.sum(imatch) 19 | Lx = np.cumsum(imatch) 20 | Px = Lx.astype(float) / np.arange(1, Rs + 1, 1) 21 | if rel != 0: 22 | APx.append(np.sum(Px * imatch) / rel) 23 | return np.mean(np.array(APx)) 24 | 25 | 26 | def get_mAPs_rerank(q_output, q_labels, db_output, db_labels, Rs, dist_type): 27 | query_output = sign(q_output) 28 | database_output = sign(db_output) 29 | 30 | bit_n = query_output.shape[1] 31 | 32 | ips = np.dot(query_output, database_output.T) 33 | ips = (bit_n - ips) / 2 34 | 35 | mAPX = [] 36 | query_labels = q_labels 37 | database_labels = db_labels 38 | for i in range(ips.shape[0]): 39 | label = query_labels[i, :] 40 | label[label == 0] = -1 41 | 42 | imatch = np.array([]) 43 | for j in range(bit_n): 44 | idx = np.reshape(np.argwhere(np.equal(ips[i, :], j)), (-1)) 45 | all_num = len(idx) 46 | 47 | if all_num != 0: 48 | ips_trad = np.dot(q_output[i, :], db_output[idx[:], :].T) 49 | ids_trad = np.argsort(-ips_trad, axis=0) 50 | db_labels_1 = database_labels[idx[:], :] 51 | 52 | imatch = np.append(imatch, np.sum( 53 | np.equal(db_labels_1[ids_trad, :], label), 1) > 0) 54 | if imatch.shape[0] > Rs: 55 | break 56 | 57 | imatch = imatch[0:Rs] 58 | rel = np.sum(imatch) 59 | Lx = np.cumsum(imatch) 60 | Px = Lx.astype(float) / np.arange(1, Rs + 1, 1) 61 | if rel != 0: 62 | mAPX.append(np.sum(Px * imatch) / rel) 63 | 64 | return np.mean(np.array(mAPX)) 65 | 66 | 67 | class MAPs: 68 | def __init__(self, R): 69 | self.R = R 70 | 71 | def get_mAPs_by_feature(self, database, query, Rs=None, dist_type='inner_product'): 72 | if Rs is None: 73 | Rs = self.R 74 | return get_mAPs(query.output, query.label, database.output, database.label, Rs, dist_type) 75 | 76 | def get_mAPs_after_sign(self, database, query, Rs=None, dist_type='inner_product'): 77 | if Rs is None: 78 | Rs = self.R 79 | q_output = sign(query.output) 80 | db_output = sign(database.output) 81 | return get_mAPs(q_output, query.label, db_output, database.label, Rs, dist_type) 82 | 83 | def get_mAPs_after_sign_with_feature_rerank(self, database, query, Rs=None, dist_type='inner_product'): 84 | if Rs is None: 85 | Rs = self.R 86 | return get_mAPs_rerank(query.output, query.label, database.output, database.label, Rs, dist_type) 87 | 88 | @staticmethod 89 | def get_precision_recall_by_Hamming_Radius(database, query, radius=2): 90 | query_output = sign(query.output) 91 | database_output = sign(database.output) 92 | 93 | bit_n = query_output.shape[1] 94 | 95 | ips = np.dot(query_output, database_output.T) 96 | ips = (bit_n - ips) / 2 97 | ids = np.argsort(ips, 1) 98 | 99 | precX = [] 100 | recX = [] 101 | mAPX = [] 102 | query_labels = query.label 103 | database_labels = database.label 104 | 105 | for i in range(ips.shape[0]): 106 | label = query_labels[i, :] 107 | label[label == 0] = -1 108 | idx = np.reshape(np.argwhere(ips[i, :] <= radius), (-1)) 109 | all_num = len(idx) 110 | 111 | if all_num != 0: 112 | imatch = np.sum(database_labels[idx[:], :] == label, 1) > 0 113 | match_num = np.sum(imatch) 114 | precX.append(np.float(match_num) / all_num) 115 | 116 | all_sim_num = np.sum( 117 | np.sum(database_labels[:, :] == label, 1) > 0) 118 | recX.append(np.float(match_num) / all_sim_num) 119 | 120 | if radius < 10: 121 | ips_trad = np.dot( 122 | query.output[i, :], database.output[ids[i, 0:all_num], :].T) 123 | ids_trad = np.argsort(-ips_trad, axis=0) 124 | db_labels = database_labels[ids[i, 0:all_num], :] 125 | 126 | rel = match_num 127 | imatch = np.sum(db_labels[ids_trad, :] == label, 1) > 0 128 | Lx = np.cumsum(imatch) 129 | Px = Lx.astype(float) / np.arange(1, all_num + 1, 1) 130 | if rel != 0: 131 | mAPX.append(np.sum(Px * imatch) / rel) 132 | else: 133 | mAPX.append(np.float(match_num) / all_num) 134 | 135 | else: 136 | precX.append(np.float(0.0)) 137 | recX.append(np.float(0.0)) 138 | mAPX.append(np.float(0.0)) 139 | 140 | return np.mean(np.array(precX)), np.mean(np.array(recX)), np.mean(np.array(mAPX)) 141 | 142 | @staticmethod 143 | def get_precision_recall_by_Hamming_Radius_All(database, query): 144 | query_output = sign(query.output) 145 | database_output = sign(database.output) 146 | 147 | bit_n = query_output.shape[1] 148 | 149 | ips = np.dot(query_output, database_output.T) 150 | ips = (bit_n - ips) / 2 151 | precX = np.zeros((ips.shape[0], bit_n + 1)) 152 | recX = np.zeros((ips.shape[0], bit_n + 1)) 153 | mAPX = np.zeros((ips.shape[0], bit_n + 1)) 154 | 155 | query_labels = query.label 156 | database_labels = database.label 157 | 158 | ids = np.argsort(ips, 1) 159 | 160 | for i in range(ips.shape[0]): 161 | label = query_labels[i, :] 162 | label[label == 0] = -1 163 | 164 | idx = ids[i, :] 165 | imatch = np.sum(database_labels[idx[:], :] == label, 1) > 0 166 | all_sim_num = np.sum(imatch) 167 | 168 | counts = np.bincount(ips[i, :].astype(np.int64)) 169 | 170 | for r in range(bit_n + 1): 171 | if r >= len(counts): 172 | precX[i, r] = precX[i, r - 1] 173 | recX[i, r] = recX[i, r - 1] 174 | mAPX[i, r] = mAPX[i, r - 1] 175 | continue 176 | 177 | all_num = np.sum(counts[0:r + 1]) 178 | 179 | if all_num != 0: 180 | match_num = np.sum(imatch[0:all_num]) 181 | precX[i, r] = np.float(match_num) / all_num 182 | recX[i, r] = np.float(match_num) / all_sim_num 183 | 184 | rel = match_num 185 | Lx = np.cumsum(imatch[0:all_num]) 186 | Px = Lx.astype(float) / np.arange(1, all_num + 1, 1) 187 | if rel != 0: 188 | mAPX[i, r] = np.sum(Px * imatch[0:all_num]) / rel 189 | return np.mean(np.array(precX), 0), np.mean(np.array(recX), 0), np.mean(np.array(mAPX), 0) 190 | 191 | 192 | class MAPs_CQ: 193 | def __init__(self, C, subspace_num, subcenter_num, R): 194 | self.C = C 195 | self.subspace_num = subspace_num 196 | self.subcenter_num = subcenter_num 197 | self.R = R 198 | 199 | def get_mAPs_SQD(self, database, query, Rs=None, dist_type='inner_product'): 200 | if Rs is None: 201 | Rs = self.R 202 | q_output = np.dot(query.codes, self.C) 203 | db_output = np.dot(database.codes, self.C) 204 | return get_mAPs(q_output, query.label, db_output, database.label, Rs, dist_type) 205 | 206 | def get_mAPs_AQD(self, database, query, Rs=None, dist_type='inner_product'): 207 | if Rs is None: 208 | Rs = self.R 209 | q_output = query.output 210 | db_output = np.dot(database.codes, self.C) 211 | return get_mAPs(q_output, query.label, db_output, database.label, Rs, dist_type) 212 | 213 | def get_mAPs_by_feature(self, database, query, Rs=None, dist_type='inner_product'): 214 | if Rs is None: 215 | Rs = self.R 216 | q_output = query.output 217 | db_output = database.output 218 | return get_mAPs(q_output, query.label, db_output, database.label, Rs, dist_type) 219 | 220 | def get_mAPs_after_sign(self, database, query, Rs=None, dist_type='inner_product'): 221 | if Rs is None: 222 | Rs = self.R 223 | q_output = sign(query.output) 224 | db_output = sign(database.output) 225 | return get_mAPs(q_output, query.label, db_output, database.label, Rs, dist_type) 226 | 227 | 228 | if __name__ == "__main__": 229 | m = MAPs(4) 230 | radius = 2 231 | 232 | class ds: 233 | def __init__(self): 234 | self.output = [] 235 | self.label = [] 236 | database = ds() 237 | query = ds() 238 | 239 | database.output = np.sign(np.random.rand(10000, 64) - 0.5) 240 | database.label = np.sign(np.random.rand(10000, 20) - 0.5) 241 | database.label[database.label < 0] = 0 242 | query.output = np.sign(np.random.rand(1000, 64) - 0.5) 243 | query.label = np.sign(np.random.rand(1000, 20) - 0.5) 244 | query.label[query.label < 0] = 0 245 | 246 | print(m.get_mAPs_after_sign_with_feature_rerank(database, query, 500)) 247 | print(m.get_mAPs_by_feature(database, query, 500)) 248 | prec, rec, maps = m.get_precision_recall_by_Hamming_Radius_All( 249 | database, query) 250 | print(prec) 251 | print(rec) 252 | print(maps) 253 | -------------------------------------------------------------------------------- /DeepHash/evaluation/load_and_predict.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.io as scio 3 | 4 | def pr_curve(params): 5 | database_code = np.array(params['database_code']) 6 | validation_code = np.array(params['validation_code']) 7 | database_labels = np.array(params['database_labels']) 8 | validation_labels = np.array(params['validation_labels']) 9 | 10 | query_num = validation_code.shape[0] 11 | database_num = database_code.shape[0] 12 | 13 | database_code = np.sign(database_code) 14 | database_code[database_code == -1] = 0 15 | database_code = database_code.astype(int) 16 | 17 | validation_code = np.sign(validation_code) 18 | validation_code[validation_code == -1] = 0 19 | validation_code = validation_code.astype(int) 20 | 21 | database_labels.astype(np.int) 22 | validation_labels.astype(np.int) 23 | 24 | WTrue = np.dot(validation_labels, database_labels.T) 25 | WTrue[WTrue >= 1] = 1 26 | WTrue[WTrue < 1] = 0 27 | print(WTrue.shape) 28 | print(np.max(WTrue)) 29 | print(np.min(WTrue)) 30 | 31 | DHat = np.zeros((query_num, database_num)) 32 | 33 | for i in range(query_num): 34 | query = validation_code[i, :] 35 | query_matrix = np.tile(query, (database_num, 1)) 36 | 37 | distance = np.sum(np.absolute(query_matrix - database_code), axis=1) 38 | DHat[i, :] = distance 39 | print(i) 40 | 41 | print(DHat.shape) 42 | print(np.max(DHat)) 43 | print(np.min(DHat)) 44 | 45 | mat_dic = dict( 46 | WTrue=WTrue, 47 | DHat=DHat 48 | ) 49 | scio.savemat('./data/data.mat', mat_dic) 50 | 51 | 52 | def precision_recall(params): 53 | database_code = np.array(params['database_code']) 54 | validation_code = np.array(params['validation_code']) 55 | database_labels = np.array(params['database_labels']) 56 | validation_labels = np.array(params['validation_labels']) 57 | database_code = np.sign(database_code) 58 | validation_code = np.sign(validation_code) 59 | database_labels.astype(np.int) 60 | validation_labels.astype(np.int) 61 | 62 | sim = np.dot(database_code, validation_code.T) 63 | ids = np.argsort(-sim, axis=0) 64 | ones = np.ones((ids.shape[0], ids.shape[1]), dtype=np.int) 65 | print(np.min(ids)) 66 | ids = ids + ones 67 | print(np.min(ids)) 68 | mat_ids = dict( 69 | ids=ids, 70 | LBase=database_labels, 71 | LTest=validation_labels 72 | ) 73 | scio.savemat('./data/data.mat', mat_ids) 74 | 75 | 76 | def hamming_precision(params): 77 | database_code = np.array(params['database_code']) 78 | validation_code = np.array(params['validation_code']) 79 | database_labels = np.array(params['database_labels']) 80 | validation_labels = np.array(params['validation_labels']) 81 | R = params['R'] 82 | query_num = validation_code.shape[0] 83 | database_num = database_code.shape[0] 84 | 85 | database_code = np.sign(database_code) 86 | database_code[database_code == -1] = 0 87 | database_code = database_code.astype(int) 88 | 89 | validation_code = np.sign(validation_code) 90 | validation_code[validation_code == -1] = 0 91 | validation_code = validation_code.astype(int) 92 | 93 | APx = [] 94 | 95 | for i in range(query_num): 96 | query = validation_code[i, :] 97 | query_matrix = np.tile(query, (database_num, 1)) 98 | 99 | label = validation_labels[i, :] 100 | label[label == 0] = -1 101 | label_matrix = np.tile(label, (database_num, 1)) 102 | 103 | distance = np.sum(np.absolute(query_matrix - database_code), axis=1) 104 | similarity = np.sum(database_labels == label_matrix, axis=1) 105 | similarity[similarity > 1] = 1 106 | 107 | total_rel_num = np.sum(distance <= R) 108 | true_positive = np.sum((distance <= R) * similarity) 109 | 110 | print('--------') 111 | print(i) 112 | print(true_positive) 113 | print(total_rel_num) 114 | print('--------') 115 | if total_rel_num != 0: 116 | APx.append(float(true_positive) / total_rel_num) 117 | else: 118 | APx.append(float(0)) 119 | 120 | print(np.sum(np.array(APx) != 0)) 121 | return np.mean(np.array(APx)) 122 | 123 | 124 | def precision_curve(params): 125 | database_code = np.array(params['database_code']) 126 | validation_code = np.array(params['validation_code']) 127 | database_labels = np.array(params['database_labels']) 128 | validation_labels = np.array(params['validation_labels']) 129 | query_num = validation_code.shape[0] 130 | database_code = np.sign(database_code) 131 | validation_code = np.sign(validation_code) 132 | 133 | sim = np.dot(database_code, validation_code.T) 134 | ids = np.argsort(-sim, axis=0) 135 | arr = [] 136 | 137 | for iter in range(10): 138 | R = (iter + 1) * 100 139 | APx = [] 140 | for i in range(query_num): 141 | label = validation_labels[i, :] 142 | label[label == 0] = -1 143 | idx = ids[:, i] 144 | imatch = np.sum(database_labels[idx[0:R], :] == label, axis=1) > 0 145 | relevant_num = np.sum(imatch) 146 | APx.append(float(relevant_num) / R) 147 | arr.append(np.mean(np.array(APx))) 148 | print(arr) 149 | print(arr) 150 | 151 | 152 | def precision(params): 153 | database_code = np.array(params['database_code']) 154 | validation_code = np.array(params['validation_code']) 155 | database_labels = np.array(params['database_labels']) 156 | validation_labels = np.array(params['validation_labels']) 157 | R = params['R'] 158 | query_num = validation_code.shape[0] 159 | database_code = np.sign(database_code) 160 | validation_code = np.sign(validation_code) 161 | 162 | sim = np.dot(database_code, validation_code.T) 163 | ids = np.argsort(-sim, axis=0) 164 | APx = [] 165 | 166 | for i in range(query_num): 167 | label = validation_labels[i, :] 168 | label[label == 0] = -1 169 | idx = ids[:, i] 170 | imatch = np.sum(database_labels[idx[0:R], :] == label, axis=1) > 0 171 | relevant_num = np.sum(imatch) 172 | APx.append(float(relevant_num) / R) 173 | 174 | return np.mean(np.array(APx)) 175 | 176 | 177 | def mean_average_precision(params): 178 | database_code = np.array(params['database_code']) 179 | validation_code = np.array(params['validation_code']) 180 | database_labels = np.array(params['database_labels']) 181 | validation_labels = np.array(params['validation_labels']) 182 | R = params['R'] 183 | query_num = validation_code.shape[0] 184 | database_code = np.sign(database_code) 185 | validation_code = np.sign(validation_code) 186 | 187 | sim = np.dot(database_code, validation_code.T) 188 | ids = np.argsort(-sim, axis=0) 189 | APx = [] 190 | 191 | for i in range(query_num): 192 | label = validation_labels[i, :] 193 | label[label == 0] = -1 194 | idx = ids[:, i] 195 | imatch = np.sum(database_labels[idx[0:R], :] == label, axis=1) > 0 196 | relevant_num = np.sum(imatch) 197 | Lx = np.cumsum(imatch) 198 | Px = Lx.astype(float) / np.arange(1, R+1, 1) 199 | if relevant_num != 0: 200 | APx.append(np.sum(Px * imatch) / relevant_num) 201 | 202 | return np.mean(np.array(APx)) 203 | 204 | 205 | def statistic_prob(params): 206 | database_code = np.array(params['database_code']) 207 | validation_code = np.array(params['validation_code']) 208 | sim = np.dot(database_code, validation_code.T) 209 | query_num = validation_code.shape[0] 210 | database_num = database_code.shape[0] 211 | ones = np.ones((database_num, query_num)) 212 | exp_sim = np.exp(sim) 213 | prob = ones / (1 + 1 / exp_sim) 214 | useless = np.sum(prob >= 0.95) + np.sum(prob <= 0.05) 215 | useful = query_num * database_num - useless 216 | print("useful") 217 | print(useful) 218 | print("useless") 219 | print(useless) 220 | 221 | -------------------------------------------------------------------------------- /DeepHash/model/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thulab/DeepHash/9907613e1b73818985bc585af613a960c8df7d20/DeepHash/model/__init__.py -------------------------------------------------------------------------------- /DeepHash/model/dch/.dch.py.swo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thulab/DeepHash/9907613e1b73818985bc585af613a960c8df7d20/DeepHash/model/dch/.dch.py.swo -------------------------------------------------------------------------------- /DeepHash/model/dch/__init__.py: -------------------------------------------------------------------------------- 1 | from .util import Dataset 2 | from .dch import DCH 3 | 4 | def train(train_img, database_img, query_img, config): 5 | model = DCH(config) 6 | img_database = Dataset(database_img, config.output_dim) 7 | img_query = Dataset(query_img, config.output_dim) 8 | img_train = Dataset(train_img, config.output_dim) 9 | model.train(img_train) 10 | return model.save_file 11 | 12 | def validation(database_img, query_img, config): 13 | model = DCH(config) 14 | img_database = Dataset(database_img, config.output_dim) 15 | img_query = Dataset(query_img, config.output_dim) 16 | return model.validation(img_query, img_database, config.R) 17 | -------------------------------------------------------------------------------- /DeepHash/model/dch/dch.py: -------------------------------------------------------------------------------- 1 | ################################################################################# 2 | # Deep Cauchy Hashing for Hamming Space Retrieval # 3 | # Authors: Yue Cao, Mingsheng Long, Bin Liu, Jianmin Wang # 4 | # Contact: caoyue10@gmail.com # 5 | ################################################################################## 6 | 7 | import os 8 | import shutil 9 | import time 10 | from datetime import datetime 11 | from math import ceil 12 | 13 | import numpy as np 14 | import tensorflow as tf 15 | 16 | import model.plot as plot 17 | from architecture import img_alexnet_layers 18 | from evaluation import MAPs 19 | 20 | 21 | class DCH(object): 22 | def __init__(self, config): 23 | # Initialize setting 24 | print("initializing") 25 | np.set_printoptions(precision=4) 26 | 27 | with tf.name_scope('stage'): 28 | # 0 for training, 1 for validation 29 | self.stage = tf.placeholder_with_default(tf.constant(0), []) 30 | for k, v in vars(config).items(): 31 | setattr(self, k, v) 32 | self.file_name = 'lr_{}_cqlambda_{}_gamma_{}_dataset_{}'.format( 33 | self.lr, 34 | self.q_lambda, 35 | self.gamma, 36 | self.dataset) 37 | self.save_file = os.path.join(self.save_dir, self.file_name + '.npy') 38 | 39 | # Setup session 40 | print("launching session") 41 | configProto = tf.ConfigProto() 42 | configProto.gpu_options.allow_growth = True 43 | configProto.allow_soft_placement = True 44 | self.sess = tf.Session(config=configProto) 45 | 46 | # Create variables and placeholders 47 | self.img = tf.placeholder(tf.float32, [None, 256, 256, 3]) 48 | self.img_label = tf.placeholder(tf.float32, [None, self.label_dim]) 49 | self.img_last_layer, self.deep_param_img, self.train_layers, self.train_last_layer = self.load_model() 50 | 51 | self.global_step = tf.Variable(0, trainable=False) 52 | self.train_op = self.apply_loss_function(self.global_step) 53 | self.sess.run(tf.global_variables_initializer()) 54 | return 55 | 56 | def load_model(self): 57 | if self.img_model == 'alexnet': 58 | img_output = img_alexnet_layers( 59 | self.img, 60 | self.batch_size, 61 | self.output_dim, 62 | self.stage, 63 | self.model_weights, 64 | self.with_tanh, 65 | self.val_batch_size) 66 | else: 67 | raise Exception('cannot use such CNN model as ' + self.img_model) 68 | return img_output 69 | 70 | def save_model(self, model_file=None): 71 | if model_file is None: 72 | model_file = self.save_file 73 | model = {} 74 | for layer in self.deep_param_img: 75 | model[layer] = self.sess.run(self.deep_param_img[layer]) 76 | print("saving model to %s" % model_file) 77 | if os.path.exists(self.save_dir) is False: 78 | os.makedirs(self.save_dir) 79 | 80 | np.save(model_file, np.array(model)) 81 | return 82 | 83 | def cauchy_cross_entropy(self, u, label_u, v=None, label_v=None, gamma=1, normed=True): 84 | 85 | if v is None: 86 | v = u 87 | label_v = label_u 88 | 89 | label_ip = tf.cast( 90 | tf.matmul(label_u, tf.transpose(label_v)), tf.float32) 91 | s = tf.clip_by_value(label_ip, 0.0, 1.0) 92 | 93 | if normed: 94 | ip_1 = tf.matmul(u, tf.transpose(v)) 95 | 96 | def reduce_shaper(t): 97 | return tf.reshape(tf.reduce_sum(t, 1), [tf.shape(t)[0], 1]) 98 | mod_1 = tf.sqrt(tf.matmul(reduce_shaper(tf.square(u)), reduce_shaper( 99 | tf.square(v)) + tf.constant(0.000001), transpose_b=True)) 100 | dist = tf.constant(np.float32(self.output_dim)) / 2.0 * \ 101 | (1.0 - tf.div(ip_1, mod_1) + tf.constant(0.000001)) 102 | else: 103 | r_u = tf.reshape(tf.reduce_sum(u * u, 1), [-1, 1]) 104 | r_v = tf.reshape(tf.reduce_sum(v * v, 1), [-1, 1]) 105 | 106 | dist = r_u - 2 * tf.matmul(u, tf.transpose(v)) + \ 107 | tf.transpose(r_v) + tf.constant(0.001) 108 | 109 | cauchy = gamma / (dist + gamma) 110 | 111 | s_t = tf.multiply(tf.add(s, tf.constant(-0.5)), tf.constant(2.0)) 112 | sum_1 = tf.reduce_sum(s) 113 | sum_all = tf.reduce_sum(tf.abs(s_t)) 114 | balance_param = tf.add( 115 | tf.abs(tf.add(s, tf.constant(-1.0))), tf.multiply(tf.div(sum_all, sum_1), s)) 116 | 117 | mask = tf.equal(tf.eye(tf.shape(u)[0]), tf.constant(0.0)) 118 | 119 | cauchy_mask = tf.boolean_mask(cauchy, mask) 120 | s_mask = tf.boolean_mask(s, mask) 121 | balance_p_mask = tf.boolean_mask(balance_param, mask) 122 | 123 | all_loss = - s_mask * \ 124 | tf.log(cauchy_mask) - (tf.constant(1.0) - s_mask) * \ 125 | tf.log(tf.constant(1.0) - cauchy_mask) 126 | 127 | return tf.reduce_mean(tf.multiply(all_loss, balance_p_mask)) 128 | 129 | def apply_loss_function(self, global_step): 130 | # loss function 131 | self.cos_loss = self.cauchy_cross_entropy(self.img_last_layer, self.img_label, gamma=self.gamma, normed=False) 132 | 133 | self.q_loss_img = tf.reduce_mean(tf.square(tf.subtract(tf.abs(self.img_last_layer), tf.constant(1.0)))) 134 | self.q_loss = self.q_lambda * self.q_loss_img 135 | self.loss = self.cos_loss + self.q_loss 136 | 137 | # Last layer has a 10 times learning rate 138 | lr = tf.train.exponential_decay(self.lr, global_step, self.decay_step, self.decay_factor, staircase=True) 139 | opt = tf.train.MomentumOptimizer(learning_rate=lr, momentum=0.9) 140 | grads_and_vars = opt.compute_gradients(self.loss, self.train_layers+self.train_last_layer) 141 | fcgrad, _ = grads_and_vars[-2] 142 | fbgrad, _ = grads_and_vars[-1] 143 | 144 | self.grads_and_vars = grads_and_vars 145 | tf.summary.scalar('loss', self.loss) 146 | tf.summary.scalar('cos_loss', self.cos_loss) 147 | tf.summary.scalar('q_loss', self.q_loss) 148 | tf.summary.scalar('lr', lr) 149 | self.merged = tf.summary.merge_all() 150 | 151 | if self.finetune_all: 152 | return opt.apply_gradients([(grads_and_vars[0][0], self.train_layers[0]), 153 | (grads_and_vars[1][0]*2, self.train_layers[1]), 154 | (grads_and_vars[2][0], self.train_layers[2]), 155 | (grads_and_vars[3][0]*2, self.train_layers[3]), 156 | (grads_and_vars[4][0], self.train_layers[4]), 157 | (grads_and_vars[5][0]*2, self.train_layers[5]), 158 | (grads_and_vars[6][0], self.train_layers[6]), 159 | (grads_and_vars[7][0]*2, self.train_layers[7]), 160 | (grads_and_vars[8][0], self.train_layers[8]), 161 | (grads_and_vars[9][0]*2, self.train_layers[9]), 162 | (grads_and_vars[10][0], self.train_layers[10]), 163 | (grads_and_vars[11][0]*2, self.train_layers[11]), 164 | (grads_and_vars[12][0], self.train_layers[12]), 165 | (grads_and_vars[13][0]*2, self.train_layers[13]), 166 | (fcgrad*10, self.train_last_layer[0]), 167 | (fbgrad*20, self.train_last_layer[1])], global_step=global_step) 168 | else: 169 | return opt.apply_gradients([(fcgrad*10, self.train_last_layer[0]), 170 | (fbgrad*20, self.train_last_layer[1])], global_step=global_step) 171 | 172 | def train(self, img_dataset): 173 | print("%s #train# start training" % datetime.now()) 174 | 175 | # tensorboard 176 | tflog_path = os.path.join(self.log_dir, self.file_name) 177 | if os.path.exists(tflog_path): 178 | shutil.rmtree(tflog_path) 179 | train_writer = tf.summary.FileWriter(tflog_path, self.sess.graph) 180 | 181 | for train_iter in range(self.iter_num): 182 | images, labels = img_dataset.next_batch(self.batch_size) 183 | start_time = time.time() 184 | 185 | _, loss, cos_loss, output, summary = self.sess.run([self.train_op, self.loss, self.cos_loss, self.img_last_layer, self.merged], 186 | feed_dict={self.img: images, 187 | self.img_label: labels}) 188 | 189 | train_writer.add_summary(summary, train_iter) 190 | 191 | img_dataset.feed_batch_output(self.batch_size, output) 192 | duration = time.time() - start_time 193 | 194 | if train_iter % 100 == 0: 195 | print("%s #train# step %4d, loss = %.4f, cross_entropy loss = %.4f, %.1f sec/batch" 196 | % (datetime.now(), train_iter+1, loss, cos_loss, duration)) 197 | 198 | print("%s #traing# finish training" % datetime.now()) 199 | self.save_model() 200 | print("model saved") 201 | 202 | self.sess.close() 203 | 204 | def validation(self, img_query, img_database, R=100): 205 | print("%s #validation# start validation" % (datetime.now())) 206 | query_batch = int(ceil(img_query.n_samples / float(self.val_batch_size))) 207 | img_query.finish_epoch() 208 | print("%s #validation# totally %d query in %d batches" % (datetime.now(), img_query.n_samples, query_batch)) 209 | for i in range(query_batch): 210 | images, labels = img_query.next_batch(self.val_batch_size) 211 | output, loss = self.sess.run([self.img_last_layer, self.cos_loss], 212 | feed_dict={self.img: images, 213 | self.img_label: labels, 214 | self.stage: 1}) 215 | img_query.feed_batch_output(self.val_batch_size, output) 216 | print('Cosine Loss: %s' % loss) 217 | 218 | database_batch = int(ceil(img_database.n_samples / float(self.val_batch_size))) 219 | img_database.finish_epoch() 220 | print("%s #validation# totally %d database in %d batches" % 221 | (datetime.now(), img_database.n_samples, database_batch)) 222 | for i in range(database_batch): 223 | images, labels = img_database.next_batch(self.val_batch_size) 224 | 225 | output, loss = self.sess.run([self.img_last_layer, self.cos_loss], 226 | feed_dict={self.img: images, 227 | self.img_label: labels, 228 | self.stage: 1}) 229 | img_database.feed_batch_output(self.val_batch_size, output) 230 | if i % 100 == 0: 231 | print('Cosine Loss[%d/%d]: %s' % (i, database_batch, loss)) 232 | 233 | mAPs = MAPs(R) 234 | 235 | self.sess.close() 236 | prec, rec, mmap = mAPs.get_precision_recall_by_Hamming_Radius_All(img_database, img_query) 237 | for i in range(self.output_dim+1): 238 | #prec, rec, mmap = mAPs.get_precision_recall_by_Hamming_Radius(img_database, img_query, i) 239 | plot.plot('prec', prec[i]) 240 | plot.plot('rec', rec[i]) 241 | plot.plot('mAP', mmap[i]) 242 | plot.tick() 243 | print('Results ham dist [%d], prec:%s, rec:%s, mAP:%s' % (i, prec[i], rec[i], mmap[i])) 244 | 245 | result_save_dir = os.path.join(self.save_dir, self.file_name) 246 | if os.path.exists(result_save_dir) is False: 247 | os.makedirs(result_save_dir) 248 | plot.flush(result_save_dir) 249 | 250 | prec, rec, mmap = mAPs.get_precision_recall_by_Hamming_Radius(img_database, img_query, 2) 251 | return { 252 | 'i2i_by_feature': mAPs.get_mAPs_by_feature(img_database, img_query), 253 | 'i2i_after_sign': mAPs.get_mAPs_after_sign(img_database, img_query), 254 | 'i2i_prec_radius_2': prec, 255 | 'i2i_recall_radius_2': rec, 256 | 'i2i_map_radius_2': mmap, 257 | } 258 | -------------------------------------------------------------------------------- /DeepHash/model/dch/util.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class Dataset(object): 4 | def __init__(self, dataset, output_dim): 5 | print ("Initializing Dataset") 6 | self._dataset = dataset 7 | self.n_samples = dataset.n_samples 8 | self._train = dataset.train 9 | self._output = np.zeros((self.n_samples, output_dim), dtype=np.float32) 10 | 11 | self._perm = np.arange(self.n_samples) 12 | np.random.shuffle(self._perm) 13 | self._index_in_epoch = 0 14 | self._epochs_complete = 0 15 | print ("Dataset already") 16 | return 17 | 18 | def next_batch(self, batch_size): 19 | """ 20 | Args: 21 | batch_size 22 | Returns: 23 | [batch_size, (n_inputs)]: next batch images 24 | [batch_size, n_class]: next batch labels 25 | """ 26 | start = self._index_in_epoch 27 | self._index_in_epoch += batch_size 28 | # Another epoch finish 29 | if self._index_in_epoch > self.n_samples: 30 | if self._train: 31 | # Training stage need repeating get batch 32 | self._epochs_complete += 1 33 | # Shuffle the data 34 | np.random.shuffle(self._perm) 35 | # Start next epoch 36 | start = 0 37 | self._index_in_epoch = batch_size 38 | else: 39 | # Validation stage only process once 40 | start = self.n_samples - batch_size 41 | self._index_in_epoch = self.n_samples 42 | end = self._index_in_epoch 43 | 44 | data, label = self._dataset.data(self._perm[start:end]) 45 | return (data, label) 46 | 47 | def feed_batch_output(self, batch_size, output): 48 | """ 49 | Args: 50 | batch_size 51 | [batch_size, n_output] 52 | """ 53 | start = self._index_in_epoch - batch_size 54 | end = self._index_in_epoch 55 | self.output[self._perm[start:end], :] = output 56 | return 57 | 58 | @property 59 | def output(self): 60 | return self._output 61 | 62 | @property 63 | def label(self): 64 | return self._dataset.get_labels() 65 | 66 | def finish_epoch(self): 67 | self._index_in_epoch = 0 68 | np.random.shuffle(self._perm) 69 | 70 | -------------------------------------------------------------------------------- /DeepHash/model/dhn/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thulab/DeepHash/9907613e1b73818985bc585af613a960c8df7d20/DeepHash/model/dhn/__init__.py -------------------------------------------------------------------------------- /DeepHash/model/dhn/dhn.py: -------------------------------------------------------------------------------- 1 | ################################################################################# 2 | # Deep Hashing Network for Efficient Similarity Retrieval # 3 | # Authors: Han Zhu, Mingsheng Long, Jianmin Wang, Yue Cao # 4 | # Contact: caoyue10@gmail.com # 5 | ################################################################################## 6 | 7 | import os 8 | import shutil 9 | import time 10 | from datetime import datetime 11 | from math import ceil 12 | 13 | import numpy as np 14 | import tensorflow as tf 15 | 16 | from architecture import img_alexnet_layers 17 | from evaluation import MAPs 18 | from .util import Dataset 19 | 20 | 21 | class DHN(object): 22 | def __init__(self, config): 23 | # Initialize setting 24 | print("initializing") 25 | np.set_printoptions(precision=4) 26 | self.stage = tf.placeholder_with_default(tf.constant(0), []) 27 | self.device = config['device'] 28 | self.output_dim = config['output_dim'] 29 | self.n_class = config['label_dim'] 30 | self.cq_lambda = config['cq_lambda'] 31 | self.alpha = config['alpha'] 32 | 33 | self.batch_size = config['batch_size'] 34 | self.val_batch_size = config['val_batch_size'] 35 | self.max_iter = config['max_iter'] 36 | self.img_model = config['img_model'] 37 | self.loss_type = config['loss_type'] 38 | self.learning_rate = config['learning_rate'] 39 | self.learning_rate_decay_factor = config['learning_rate_decay_factor'] 40 | self.decay_step = config['decay_step'] 41 | 42 | self.finetune_all = config['finetune_all'] 43 | 44 | self.file_name = 'lr_{}_cqlambda_{}_alpha_{}_dataset_{}'.format( 45 | self.learning_rate, 46 | self.cq_lambda, 47 | self.alpha, 48 | config['dataset']) 49 | self.save_dir = config['save_dir'] 50 | self.save_file = os.path.join( 51 | config['save_dir'], self.file_name + '.npy') 52 | self.log_dir = config['log_dir'] 53 | 54 | # Setup session 55 | print("launching session") 56 | configProto = tf.ConfigProto() 57 | configProto.gpu_options.allow_growth = True 58 | configProto.allow_soft_placement = True 59 | self.sess = tf.Session(config=configProto) 60 | 61 | # Create variables and placeholders 62 | 63 | with tf.device(self.device): 64 | self.img = tf.placeholder(tf.float32, [None, 256, 256, 3]) 65 | self.img_label = tf.placeholder(tf.float32, [None, self.n_class]) 66 | 67 | self.model_weights = config['model_weights'] 68 | self.img_last_layer, self.deep_param_img, self.train_layers, self.train_last_layer = self.load_model() 69 | 70 | self.global_step = tf.Variable(0, trainable=False) 71 | self.train_op = self.apply_loss_function(self.global_step) 72 | self.sess.run(tf.global_variables_initializer()) 73 | return 74 | 75 | def load_model(self): 76 | if self.img_model == 'alexnet': 77 | img_output = img_alexnet_layers( 78 | self.img, self.batch_size, self.output_dim, 79 | self.stage, self.model_weights, val_batch_size=self.val_batch_size) 80 | else: 81 | raise Exception('cannot use such CNN model as ' + self.img_model) 82 | return img_output 83 | 84 | def save_model(self, model_file=None): 85 | if model_file is None: 86 | model_file = self.save_file 87 | model = {} 88 | for layer in self.deep_param_img: 89 | model[layer] = self.sess.run(self.deep_param_img[layer]) 90 | print("saving model to %s" % model_file) 91 | if os.path.exists(self.save_dir) is False: 92 | os.makedirs(self.save_dir) 93 | 94 | np.save(model_file, np.array(model)) 95 | return 96 | 97 | @staticmethod 98 | def cross_entropy(u, label_u, alpha=0.5, normed=False): 99 | 100 | label_ip = tf.cast( 101 | tf.matmul(label_u, tf.transpose(label_u)), tf.float32) 102 | s = tf.clip_by_value(label_ip, 0.0, 1.0) 103 | 104 | # compute balance param 105 | # s_t \in {-1, 1} 106 | s_t = tf.multiply(tf.add(s, tf.constant(-0.5)), tf.constant(2.0)) 107 | sum_1 = tf.reduce_sum(s) 108 | sum_all = tf.reduce_sum(tf.abs(s_t)) 109 | balance_param = tf.add(tf.abs(tf.add(s, tf.constant(-1.0))), 110 | tf.multiply(tf.div(sum_all, sum_1), s)) 111 | 112 | if normed: 113 | # ip = tf.clip_by_value(tf.matmul(u, tf.transpose(u)), -1.5e1, 1.5e1) 114 | ip_1 = tf.matmul(u, tf.transpose(u)) 115 | 116 | def reduce_shaper(t): 117 | return tf.reshape(tf.reduce_sum(t, 1), [tf.shape(t)[0], 1]) 118 | mod_1 = tf.sqrt(tf.matmul(reduce_shaper(tf.square(u)), 119 | reduce_shaper(tf.square(u)), transpose_b=True)) 120 | ip = tf.div(ip_1, mod_1) 121 | else: 122 | ip = tf.clip_by_value(tf.matmul(u, tf.transpose(u)), -1.5e1, 1.5e1) 123 | ones = tf.ones([tf.shape(u)[0], tf.shape(u)[0]]) 124 | return tf.reduce_mean(tf.multiply(tf.log(ones + tf.exp(alpha * ip)) - s * alpha * ip, balance_param)) 125 | 126 | def apply_loss_function(self, global_step): 127 | # loss function 128 | if self.loss_type == 'cross_entropy': 129 | self.cos_loss = self.cross_entropy( 130 | self.img_last_layer, self.img_label, self.alpha) 131 | elif self.loss_type == 'normed_cross_entropy': 132 | self.cos_loss = self.cross_entropy( 133 | self.img_last_layer, self.img_label, self.alpha, True) 134 | 135 | self.q_loss_img = tf.reduce_mean(tf.square(tf.subtract( 136 | tf.abs(self.img_last_layer), tf.constant(1.0)))) 137 | self.q_lambda = tf.Variable(self.cq_lambda, name='cq_lambda') 138 | self.q_loss = tf.multiply(self.q_lambda, self.q_loss_img) 139 | self.loss = self.cos_loss + self.q_loss 140 | 141 | # Last layer has a 10 times learning rate 142 | self.lr = tf.train.exponential_decay( 143 | self.learning_rate, global_step, self.decay_step, self.learning_rate_decay_factor, staircase=True) 144 | opt = tf.train.MomentumOptimizer(learning_rate=self.lr, momentum=0.9) 145 | grads_and_vars = opt.compute_gradients( 146 | self.loss, self.train_layers + self.train_last_layer) 147 | fcgrad, _ = grads_and_vars[-2] 148 | fbgrad, _ = grads_and_vars[-1] 149 | 150 | # for debug 151 | self.grads_and_vars = grads_and_vars 152 | tf.summary.scalar('loss', self.loss) 153 | tf.summary.scalar('cos_loss', self.cos_loss) 154 | tf.summary.scalar('q_loss', self.q_loss) 155 | tf.summary.scalar('lr', self.lr) 156 | self.merged = tf.summary.merge_all() 157 | 158 | if self.finetune_all: 159 | return opt.apply_gradients([(grads_and_vars[0][0], self.train_layers[0]), 160 | (grads_and_vars[1][0]*2, self.train_layers[1]), 161 | (grads_and_vars[2][0], self.train_layers[2]), 162 | (grads_and_vars[3][0]*2, self.train_layers[3]), 163 | (grads_and_vars[4][0], self.train_layers[4]), 164 | (grads_and_vars[5][0]*2, self.train_layers[5]), 165 | (grads_and_vars[6][0], self.train_layers[6]), 166 | (grads_and_vars[7][0]*2, self.train_layers[7]), 167 | (grads_and_vars[8][0], self.train_layers[8]), 168 | (grads_and_vars[9][0]*2, self.train_layers[9]), 169 | (grads_and_vars[10][0], self.train_layers[10]), 170 | (grads_and_vars[11][0]*2, self.train_layers[11]), 171 | (grads_and_vars[12][0], self.train_layers[12]), 172 | (grads_and_vars[13][0]*2, self.train_layers[13]), 173 | (fcgrad*10, self.train_last_layer[0]), 174 | (fbgrad*20, self.train_last_layer[1])], 175 | global_step=global_step) 176 | else: 177 | return opt.apply_gradients([(fcgrad * 10, self.train_last_layer[0]), 178 | (fbgrad * 20, self.train_last_layer[1])], global_step=global_step) 179 | 180 | def train(self, img_dataset): 181 | print("%s #train# start training" % datetime.now()) 182 | 183 | # tensorboard 184 | tflog_path = os.path.join(self.log_dir, self.file_name) 185 | if os.path.exists(tflog_path): 186 | shutil.rmtree(tflog_path) 187 | train_writer = tf.summary.FileWriter(tflog_path, self.sess.graph) 188 | 189 | for train_iter in range(self.max_iter): 190 | images, labels = img_dataset.next_batch(self.batch_size) 191 | start_time = time.time() 192 | 193 | _, loss, cos_loss, output, summary = self.sess.run( 194 | [self.train_op, self.loss, self.cos_loss, self.img_last_layer, self.merged], 195 | feed_dict={self.img: images, 196 | self.img_label: labels}) 197 | train_writer.add_summary(summary, train_iter) 198 | 199 | img_dataset.feed_batch_output(self.batch_size, output) 200 | duration = time.time() - start_time 201 | 202 | if train_iter % 1 == 0: 203 | print("%s #train# step %4d, loss = %.4f, cross_entropy loss = %.4f, %.1f sec/batch" 204 | % (datetime.now(), train_iter + 1, loss, cos_loss, duration)) 205 | 206 | print("%s #traing# finish training" % datetime.now()) 207 | self.save_model() 208 | print("model saved") 209 | 210 | self.sess.close() 211 | 212 | def validation(self, img_query, img_database, R=100): 213 | print("%s #validation# start validation" % (datetime.now())) 214 | query_batch = int(ceil(img_query.n_samples / self.val_batch_size)) 215 | print("%s #validation# totally %d query in %d batches" % (datetime.now(), img_query.n_samples, query_batch)) 216 | for i in range(query_batch): 217 | images, labels = img_query.next_batch(self.val_batch_size) 218 | output, loss = self.sess.run([self.img_last_layer, self.cos_loss], 219 | feed_dict={self.img: images, self.img_label: labels, self.stage: 1}) 220 | img_query.feed_batch_output(self.val_batch_size, output) 221 | print('Cosine Loss: %s' % loss) 222 | 223 | database_batch = int(ceil(img_database.n_samples / self.val_batch_size)) 224 | print("%s #validation# totally %d database in %d batches" % 225 | (datetime.now(), img_database.n_samples, database_batch)) 226 | for i in range(database_batch): 227 | images, labels = img_database.next_batch(self.val_batch_size) 228 | 229 | output, loss = self.sess.run([self.img_last_layer, self.cos_loss], 230 | feed_dict={self.img: images, self.img_label: labels, self.stage: 1}) 231 | img_database.feed_batch_output(self.val_batch_size, output) 232 | # print output[:10, :10] 233 | if i % 100 == 0: 234 | print('Cosine Loss[%d/%d]: %s' % (i, database_batch, loss)) 235 | 236 | mAPs = MAPs(R) 237 | 238 | self.sess.close() 239 | prec, rec, mmap = mAPs.get_precision_recall_by_Hamming_Radius(img_database, img_query, 2) 240 | return { 241 | 'i2i_by_feature': mAPs.get_mAPs_by_feature(img_database, img_query), 242 | 'i2i_after_sign': mAPs.get_mAPs_after_sign(img_database, img_query), 243 | 'i2i_prec_radius_2': prec, 244 | 'i2i_recall_radius_2': rec, 245 | 'i2i_map_radius_2': mmap 246 | } 247 | 248 | 249 | def train(train_img, config): 250 | model = DHN(config) 251 | img_dataset = Dataset(train_img, config['output_dim']) 252 | model.train(img_dataset) 253 | return model.save_file 254 | 255 | 256 | def validation(database_img, query_img, config): 257 | model = DHN(config) 258 | img_database = Dataset(database_img, config['output_dim']) 259 | img_query = Dataset(query_img, config['output_dim']) 260 | return model.validation(img_query, img_database, config['R']) 261 | -------------------------------------------------------------------------------- /DeepHash/model/dhn/util.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class Dataset(object): 4 | def __init__(self, dataset, output_dim): 5 | print ("Initializing Dataset") 6 | self._dataset = dataset 7 | self.n_samples = dataset.n_samples 8 | self._train = dataset.train 9 | self._output = np.zeros((self.n_samples, output_dim), dtype=np.float32) 10 | 11 | self._perm = np.arange(self.n_samples) 12 | np.random.shuffle(self._perm) 13 | self._index_in_epoch = 0 14 | self._epochs_complete = 0 15 | print ("Dataset already") 16 | return 17 | 18 | def next_batch(self, batch_size): 19 | """ 20 | Args: 21 | batch_size 22 | Returns: 23 | [batch_size, (n_inputs)]: next batch images 24 | [batch_size, n_class]: next batch labels 25 | """ 26 | start = self._index_in_epoch 27 | self._index_in_epoch += batch_size 28 | # Another epoch finish 29 | if self._index_in_epoch > self.n_samples: 30 | if self._train: 31 | # Training stage need repeating get batch 32 | self._epochs_complete += 1 33 | # Shuffle the data 34 | np.random.shuffle(self._perm) 35 | # Start next epoch 36 | start = 0 37 | self._index_in_epoch = batch_size 38 | else: 39 | # Validation stage only process once 40 | start = self.n_samples - batch_size 41 | self._index_in_epoch = self.n_samples 42 | end = self._index_in_epoch 43 | 44 | data, label = self._dataset.data(self._perm[start:end]) 45 | return (data, label) 46 | 47 | def feed_batch_output(self, batch_size, output): 48 | start = self._index_in_epoch - batch_size 49 | end = self._index_in_epoch 50 | self.output[self._perm[start:end], :] = output 51 | return 52 | 53 | @property 54 | def output(self): 55 | return self._output 56 | 57 | @property 58 | def label(self): 59 | return self._dataset.get_labels() 60 | 61 | def finish_epoch(self): 62 | self._index_in_epoch = 0 63 | np.random.shuffle(self._perm) 64 | 65 | -------------------------------------------------------------------------------- /DeepHash/model/dqn/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thulab/DeepHash/9907613e1b73818985bc585af613a960c8df7d20/DeepHash/model/dqn/__init__.py -------------------------------------------------------------------------------- /DeepHash/model/dqn/dqn.py: -------------------------------------------------------------------------------- 1 | ################################################################################# 2 | # Deep Quantization Network for Efficient Image Retrieval # 3 | # Authors: Yue Cao, Mingsheng Long, Jianmin Wang, Han Zhu, Qingfu Wen # 4 | # Contact: caoyue10@gmail.com # 5 | ################################################################################## 6 | 7 | import os 8 | import random 9 | import shutil 10 | import time 11 | from datetime import datetime 12 | from math import ceil 13 | 14 | import numpy as np 15 | import tensorflow as tf 16 | from sklearn.cluster import MiniBatchKMeans 17 | 18 | from architecture import img_alexnet_layers 19 | from evaluation import MAPs_CQ 20 | from .util import Dataset 21 | 22 | 23 | class DQN(object): 24 | def __init__(self, config): 25 | # Initialize setting 26 | print("initializing") 27 | np.set_printoptions(precision=4) 28 | self.stage = tf.placeholder_with_default(tf.constant(0), []) 29 | self.device = config['device'] 30 | self.output_dim = config['output_dim'] 31 | self.n_class = config['label_dim'] 32 | 33 | self.subspace_num = config['n_subspace'] 34 | self.subcenter_num = config['n_subcenter'] 35 | self.code_batch_size = config['code_batch_size'] 36 | self.cq_lambda = config['cq_lambda'] 37 | self.max_iter_update_Cb = config['max_iter_update_Cb'] 38 | self.max_iter_update_b = config['max_iter_update_b'] 39 | 40 | self.batch_size = config['batch_size'] 41 | self.val_batch_size = config['val_batch_size'] 42 | self.max_iter = config['max_iter'] 43 | self.img_model = config['img_model'] 44 | self.learning_rate = config['learning_rate'] 45 | self.learning_rate_decay_factor = config['learning_rate_decay_factor'] 46 | self.decay_step = config['decay_step'] 47 | 48 | self.finetune_all = config['finetune_all'] 49 | 50 | self.file_name = 'lr_{}_cqlambda_{}_subspace_num_{}_dataset_{}'.format( 51 | self.learning_rate, 52 | self.cq_lambda, 53 | self.subspace_num, 54 | config['dataset']) 55 | self.save_dir = os.path.join( 56 | config['save_dir'], self.file_name + '.npy') 57 | self.log_dir = config['log_dir'] 58 | 59 | # Setup session 60 | print("launching session") 61 | configProto = tf.ConfigProto() 62 | configProto.gpu_options.allow_growth = True 63 | configProto.allow_soft_placement = True 64 | self.sess = tf.Session(config=configProto) 65 | 66 | # Create variables and placeholders 67 | 68 | with tf.device(self.device): 69 | self.img = tf.placeholder( 70 | tf.float32, [None, 256, 256, 3]) 71 | self.img_label = tf.placeholder( 72 | tf.float32, [None, self.n_class]) 73 | 74 | self.model_weights = config['model_weights'] 75 | self.img_last_layer, self.deep_param_img, self.train_layers, self.train_last_layer = self.load_model() 76 | 77 | self.C = tf.Variable(tf.random_uniform([self.subspace_num * self.subcenter_num, self.output_dim], 78 | minval=-1, maxval=1, dtype=tf.float32, name='centers')) 79 | self.deep_param_img['C'] = self.C 80 | 81 | # Centers shared in different modalities (image & text) 82 | # Binary codes for different modalities (image & text) 83 | self.img_output_all = tf.placeholder( 84 | tf.float32, [None, self.output_dim]) 85 | self.img_b_all = tf.placeholder( 86 | tf.float32, [None, self.subspace_num * self.subcenter_num]) 87 | 88 | self.b_img = tf.placeholder(tf.float32, [None, self.subspace_num * self.subcenter_num]) 89 | self.ICM_m = tf.placeholder(tf.int32, []) 90 | self.ICM_b_m = tf.placeholder(tf.float32, [None, self.subcenter_num]) 91 | self.ICM_b_all = tf.placeholder(tf.float32, [None, self.subcenter_num * self.subspace_num]) 92 | self.ICM_X = tf.placeholder(tf.float32, [self.code_batch_size, self.output_dim]) 93 | self.ICM_C_m = tf.slice(self.C, [self.ICM_m * self.subcenter_num, 0], [self.subcenter_num, self.output_dim]) 94 | self.ICM_X_residual = self.ICM_X - tf.matmul(self.ICM_b_all, self.C) + tf.matmul(self.ICM_b_m, self.ICM_C_m) 95 | ICM_X_expand = tf.expand_dims(self.ICM_X_residual, 1) 96 | ICM_C_m_expand = tf.expand_dims(self.ICM_C_m, 0) 97 | # N*sc*D * D*n 98 | ICM_sum_squares = tf.reduce_sum(tf.square(tf.squeeze( 99 | tf.subtract(ICM_X_expand, ICM_C_m_expand))), reduction_indices=2) 100 | ICM_best_centers = tf.argmin(ICM_sum_squares, 1) 101 | self.ICM_best_centers_one_hot = tf.one_hot( 102 | ICM_best_centers, self.subcenter_num, dtype=tf.float32) 103 | 104 | self.global_step = tf.Variable(0, trainable=False) 105 | self.train_op = self.apply_loss_function(self.global_step) 106 | self.sess.run(tf.global_variables_initializer()) 107 | return 108 | 109 | def load_model(self): 110 | if self.img_model == 'alexnet': 111 | img_output = img_alexnet_layers( 112 | self.img, self.batch_size, self.output_dim, 113 | self.stage, self.model_weights, val_batch_size=self.val_batch_size) 114 | else: 115 | raise Exception('cannot use such CNN model as ' + self.img_model) 116 | return img_output 117 | 118 | def save_model(self, model_file=None): 119 | if model_file is None: 120 | model_file = self.save_dir 121 | model = {} 122 | for layer in self.deep_param_img: 123 | model[layer] = self.sess.run(self.deep_param_img[layer]) 124 | print("saving model to %s" % model_file) 125 | folder = os.path.dirname(model_file) 126 | if os.path.exists(folder) is False: 127 | os.makedirs(folder) 128 | np.save(model_file, np.array(model)) 129 | return 130 | 131 | def save_codes(self, database, query, C, model_file=None): 132 | if model_file is None: 133 | model_file = self.model_weights + "_codes.npy" 134 | model = { 135 | 'db_features': database.output, 136 | 'db_reconstr': np.dot(database.codes, C), 137 | 'db_label': database.label, 138 | 'val_features': query.output, 139 | 'val_reconstr': np.dot(query.codes, C), 140 | 'val_label': query.label, 141 | } 142 | print("saving codes to %s" % model_file) 143 | np.save(model_file, np.array(model)) 144 | return 145 | 146 | def apply_loss_function(self, global_step): 147 | # loss function 148 | 149 | # let sim = {0, 1} to be {-1, 1} 150 | Sim_1 = tf.clip_by_value( 151 | tf.matmul(self.img_label, tf.transpose(self.img_label)), 0.0, 1.0) 152 | Sim_2 = tf.add(Sim_1, tf.constant(-0.5)) 153 | Sim = tf.multiply(Sim_2, tf.constant(2.0)) 154 | 155 | ip_1 = tf.matmul(self.img_last_layer, 156 | self.img_last_layer, transpose_b=True) 157 | 158 | def reduce_shaper(t): 159 | return tf.reshape(tf.reduce_sum(t, 1), [tf.shape(t)[0], 1]) 160 | mod_1 = tf.sqrt(tf.matmul(reduce_shaper(tf.square(self.img_last_layer)), reduce_shaper( 161 | tf.square(self.img_last_layer)), transpose_b=True)) 162 | cos_1 = tf.div(ip_1, mod_1) 163 | self.cos_loss = tf.reduce_mean(tf.square(tf.subtract(Sim, cos_1))) 164 | 165 | self.cq_loss_img = tf.reduce_mean(tf.reduce_sum( 166 | tf.square(tf.subtract(self.img_last_layer, tf.matmul(self.b_img, self.C))), 1)) 167 | self.q_lambda = tf.Variable(self.cq_lambda, name='cq_lambda') 168 | self.cq_loss = tf.multiply(self.q_lambda, self.cq_loss_img) 169 | self.loss = self.cos_loss + self.cq_loss 170 | 171 | # Last layer has a 10 times learning rate 172 | self.lr = tf.train.exponential_decay( 173 | self.learning_rate, global_step, self.decay_step, self.learning_rate_decay_factor, staircase=True) 174 | opt = tf.train.MomentumOptimizer(learning_rate=self.lr, momentum=0.9) 175 | grads_and_vars = opt.compute_gradients( 176 | self.loss, self.train_layers + self.train_last_layer) 177 | fcgrad, _ = grads_and_vars[-2] 178 | fbgrad, _ = grads_and_vars[-1] 179 | 180 | # for debug 181 | self.grads_and_vars = grads_and_vars 182 | tf.summary.scalar('loss', self.loss) 183 | tf.summary.scalar('cos_loss', self.cos_loss) 184 | tf.summary.scalar('cq_loss', self.cq_loss) 185 | tf.summary.scalar('lr', self.lr) 186 | self.merged = tf.summary.merge_all() 187 | 188 | if self.finetune_all: 189 | return opt.apply_gradients([(grads_and_vars[0][0], self.train_layers[0]), 190 | (grads_and_vars[1][0]*2, self.train_layers[1]), 191 | (grads_and_vars[2][0], self.train_layers[2]), 192 | (grads_and_vars[3][0]*2, self.train_layers[3]), 193 | (grads_and_vars[4][0], self.train_layers[4]), 194 | (grads_and_vars[5][0]*2, self.train_layers[5]), 195 | (grads_and_vars[6][0], self.train_layers[6]), 196 | (grads_and_vars[7][0]*2, self.train_layers[7]), 197 | (grads_and_vars[8][0], self.train_layers[8]), 198 | (grads_and_vars[9][0]*2, self.train_layers[9]), 199 | (grads_and_vars[10][0], self.train_layers[10]), 200 | (grads_and_vars[11][0]*2, self.train_layers[11]), 201 | (grads_and_vars[12][0], self.train_layers[12]), 202 | (grads_and_vars[13][0]*2, self.train_layers[13]), 203 | (fcgrad*10, self.train_last_layer[0]), 204 | (fbgrad*20, self.train_last_layer[1])], 205 | global_step=global_step) 206 | else: 207 | return opt.apply_gradients([(fcgrad * 10, self.train_last_layer[0]), 208 | (fbgrad * 20, self.train_last_layer[1])], global_step=global_step) 209 | 210 | def initial_centers(self, img_output): 211 | C_init = np.zeros( 212 | [self.subspace_num * self.subcenter_num, self.output_dim]) 213 | print("#DQN train# initilizing Centers") 214 | all_output = img_output 215 | div = int(self.output_dim / self.subspace_num) 216 | for i in range(self.subspace_num): 217 | kmeans = MiniBatchKMeans(n_clusters=self.subcenter_num).fit( 218 | all_output[:, i * div: (i + 1) * div]) 219 | C_init[i * self.subcenter_num: (i + 1) * self.subcenter_num, i * div: (i + 1) * div] = kmeans.cluster_centers_ 220 | print("step: ", i, " finish") 221 | return C_init 222 | 223 | def update_centers(self, img_dataset): 224 | ''' 225 | Optimize: 226 | self.C = (U * hu^T + V * hv^T) (hu * hu^T + hv * hv^T)^{-1} 227 | self.C^T = (hu * hu^T + hv * hv^T)^{-1} (hu * U^T + hv * V^T) 228 | but all the C need to be replace with C^T : 229 | self.C = (hu * hu^T + hv * hv^T)^{-1} (hu^T * U + hv^T * V) 230 | ''' 231 | old_C_value = self.sess.run(self.C) 232 | 233 | h = self.img_b_all 234 | U = self.img_output_all 235 | smallResidual = tf.constant( 236 | np.eye(self.subcenter_num * self.subspace_num, dtype=np.float32) * 0.001) 237 | Uh = tf.matmul(tf.transpose(h), U) 238 | hh = tf.add(tf.matmul(tf.transpose(h), h), smallResidual) 239 | compute_centers = tf.matmul(tf.matrix_inverse(hh), Uh) 240 | 241 | update_C = self.C.assign(compute_centers) 242 | C_value = self.sess.run(update_C, feed_dict={ 243 | self.img_output_all: img_dataset.output, 244 | self.img_b_all: img_dataset.codes, 245 | }) 246 | 247 | C_sums = np.sum(np.square(C_value), axis=1) 248 | C_zeros_ids = np.where(C_sums < 1e-8) 249 | C_value[C_zeros_ids, :] = old_C_value[C_zeros_ids, :] 250 | self.sess.run(self.C.assign(C_value)) 251 | 252 | def update_codes_ICM(self, output, code): 253 | ''' 254 | Optimize: 255 | min || output - self.C * codes || 256 | min || output - codes * self.C || 257 | args: 258 | output: [n_train, n_output] 259 | self.C: [n_subspace * n_subcenter, n_output] 260 | [C_1, C_2, ... C_M] 261 | codes: [n_train, n_subspace * n_subcenter] 262 | ''' 263 | 264 | code = np.zeros(code.shape) 265 | 266 | for iterate in range(self.max_iter_update_b): 267 | 268 | sub_list = [i for i in range(self.subspace_num)] 269 | random.shuffle(sub_list) 270 | for m in sub_list: 271 | best_centers_one_hot_val = self.sess.run(self.ICM_best_centers_one_hot, feed_dict={ 272 | self.ICM_b_m: code[:, m * self.subcenter_num: (m + 1) * self.subcenter_num], 273 | self.ICM_b_all: code, 274 | self.ICM_m: m, 275 | self.ICM_X: output, 276 | }) 277 | 278 | code[:, m * self.subcenter_num: (m + 1) * 279 | self.subcenter_num] = best_centers_one_hot_val 280 | return code 281 | 282 | def update_codes_batch(self, dataset, batch_size): 283 | ''' 284 | update codes in batch size 285 | ''' 286 | total_batch = int(ceil(dataset.n_samples / batch_size)) 287 | dataset.finish_epoch() 288 | 289 | for i in range(total_batch): 290 | output_val, code_val = dataset.next_batch_output_codes(batch_size) 291 | codes_val = self.update_codes_ICM(output_val, code_val) 292 | dataset.feed_batch_codes(batch_size, codes_val) 293 | 294 | def train(self, img_dataset): 295 | print("%s #train# start training" % datetime.now()) 296 | epoch = 0 297 | epoch_iter = int(ceil(img_dataset.n_samples / self.batch_size)) 298 | 299 | # tensorboard 300 | tflog_path = os.path.join(self.log_dir, self.file_name) 301 | if os.path.exists(tflog_path): 302 | shutil.rmtree(tflog_path) 303 | train_writer = tf.summary.FileWriter(tflog_path, self.sess.graph) 304 | 305 | for train_iter in range(self.max_iter): 306 | images, labels, codes = img_dataset.next_batch(self.batch_size) 307 | start_time = time.time() 308 | 309 | # for epoch 0, q_lambda = 0, for epoch > 0, q_lambda = self.cq_lambda 310 | if epoch <= 1: 311 | assign_lambda = self.q_lambda.assign(epoch * self.cq_lambda) 312 | self.sess.run([assign_lambda]) 313 | 314 | _, loss, output, summary = self.sess.run([self.train_op, self.loss, self.img_last_layer, self.merged], 315 | feed_dict={self.img: images, 316 | self.img_label: labels, 317 | self.b_img: codes}) 318 | 319 | train_writer.add_summary(summary, train_iter) 320 | 321 | img_dataset.feed_batch_output(self.batch_size, output) 322 | duration = time.time() - start_time 323 | 324 | # every epoch: update codes and centers 325 | if train_iter % (2 * epoch_iter) == 0 and train_iter != 0: 326 | epoch = epoch + 1 327 | for i in range(self.max_iter_update_Cb): 328 | self.sess.run(self.C.assign( 329 | self.initial_centers(img_dataset.output))) 330 | self.update_codes_batch(img_dataset, self.code_batch_size) 331 | if train_iter % 50 == 0: 332 | print("%s #train# step %4d, loss = %.4f, %.1f sec/batch" 333 | % (datetime.now(), train_iter + 1, loss, duration)) 334 | 335 | print("%s #traing# finish training" % datetime.now()) 336 | self.save_model() 337 | print("model saved") 338 | 339 | self.sess.close() 340 | 341 | def validation(self, img_query, img_database, R=100): 342 | print("%s #validation# start validation" % (datetime.now())) 343 | query_batch = int(ceil(img_query.n_samples / self.val_batch_size)) 344 | print("%s #validation# totally %d query in %d batches" % 345 | (datetime.now(), img_query.n_samples, query_batch)) 346 | for i in range(query_batch): 347 | images, labels, codes = img_query.next_batch(self.val_batch_size) 348 | output, loss = self.sess.run([self.img_last_layer, self.cos_loss], 349 | feed_dict={self.img: images, self.img_label: labels, self.stage: 1}) 350 | img_query.feed_batch_output(self.val_batch_size, output) 351 | print('Cosine Loss: %s' % loss) 352 | 353 | database_batch = int(ceil(img_database.n_samples / self.val_batch_size)) 354 | print("%s #validation# totally %d database in %d batches" % 355 | (datetime.now(), img_database.n_samples, database_batch)) 356 | for i in range(database_batch): 357 | images, labels, codes = img_database.next_batch(self.val_batch_size) 358 | 359 | output, loss = self.sess.run([self.img_last_layer, self.cos_loss], 360 | feed_dict={self.img: images, self.img_label: labels, self.stage: 1}) 361 | img_database.feed_batch_output(self.val_batch_size, output) 362 | # print output[:10, :10] 363 | if i % 100 == 0: 364 | print('Cosine Loss[%d/%d]: %s' % (i, database_batch, loss)) 365 | 366 | self.update_codes_batch(img_query, self.code_batch_size) 367 | self.update_codes_batch(img_database, self.code_batch_size) 368 | 369 | print("%s #validation# calculating MAP@%d" % (datetime.now(), R)) 370 | C_tmp = self.sess.run(self.C) 371 | # save features and codes 372 | self.save_codes(img_database, img_query, C_tmp) 373 | 374 | mAPs = MAPs_CQ(C_tmp, self.subspace_num, self.subcenter_num, R) 375 | 376 | self.sess.close() 377 | return { 378 | 'i2i_nocq': mAPs.get_mAPs_by_feature(img_database, img_query), 379 | 'i2i_AQD': mAPs.get_mAPs_AQD(img_database, img_query), 380 | 'i2i_SQD': mAPs.get_mAPs_SQD(img_database, img_query) 381 | } 382 | 383 | 384 | def train(train_img, config): 385 | model = DQN(config) 386 | img_dataset = Dataset( 387 | train_img, config['output_dim'], config['n_subspace'] * config['n_subcenter']) 388 | model.train(img_dataset) 389 | return model.save_dir 390 | 391 | 392 | def validation(database_img, query_img, config): 393 | model = DQN(config) 394 | img_database = Dataset( 395 | database_img, config['output_dim'], config['n_subspace'] * config['n_subcenter']) 396 | img_query = Dataset( 397 | query_img, config['output_dim'], config['n_subspace'] * config['n_subcenter']) 398 | return model.validation(img_query, img_database, config['R']) 399 | -------------------------------------------------------------------------------- /DeepHash/model/dqn/util.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class Dataset(object): 4 | def __init__(self, dataset, output_dim, code_dim): 5 | print ("Initializing Dataset") 6 | self._dataset = dataset 7 | self.n_samples = dataset.n_samples 8 | self._train = dataset.train 9 | self._output = np.zeros((self.n_samples, output_dim), dtype=np.float32) 10 | self._codes = np.zeros((self.n_samples, code_dim), dtype=np.float32) 11 | 12 | self._perm = np.arange(self.n_samples) 13 | np.random.shuffle(self._perm) 14 | self._index_in_epoch = 0 15 | self._epochs_complete = 0 16 | print ("Dataset already") 17 | return 18 | 19 | def next_batch(self, batch_size): 20 | """ 21 | Args: 22 | batch_size 23 | Returns: 24 | [batch_size, (n_inputs)]: next batch images 25 | [batch_size, n_class]: next batch labels 26 | """ 27 | start = self._index_in_epoch 28 | self._index_in_epoch += batch_size 29 | # Another epoch finish 30 | if self._index_in_epoch > self.n_samples: 31 | if self._train: 32 | # Training stage need repeating get batch 33 | self._epochs_complete += 1 34 | # Shuffle the data 35 | np.random.shuffle(self._perm) 36 | # Start next epoch 37 | start = 0 38 | self._index_in_epoch = batch_size 39 | else: 40 | # Validation stage only process once 41 | start = self.n_samples - batch_size 42 | self._index_in_epoch = self.n_samples 43 | end = self._index_in_epoch 44 | 45 | data, label = self._dataset.data(self._perm[start:end]) 46 | return (data, label, self.codes[self._perm[start: end], :]) 47 | 48 | def next_batch_output_codes(self, batch_size): 49 | start = self._index_in_epoch 50 | self._index_in_epoch += batch_size 51 | # Another epoch finish 52 | if self._index_in_epoch > self.n_samples: 53 | if self._train: 54 | # Shuffle the data 55 | np.random.shuffle(self._perm) 56 | # Start next epoch 57 | start = 0 58 | self._index_in_epoch = batch_size 59 | else: 60 | # Validation stage only process once 61 | start = self.n_samples - batch_size 62 | self._index_in_epoch = self.n_samples 63 | end = self._index_in_epoch 64 | 65 | return (self.output[self._perm[start: end], :], 66 | self.codes[self._perm[start: end], :]) 67 | 68 | def feed_batch_output(self, batch_size, output): 69 | start = self._index_in_epoch - batch_size 70 | end = self._index_in_epoch 71 | self.output[self._perm[start:end], :] = output 72 | return 73 | 74 | def feed_batch_codes(self, batch_size, codes): 75 | """ 76 | Args: 77 | batch_size 78 | [batch_size, n_output] 79 | """ 80 | start = self._index_in_epoch - batch_size 81 | end = self._index_in_epoch 82 | self.codes[self._perm[start:end], :] = codes 83 | return 84 | 85 | @property 86 | def output(self): 87 | return self._output 88 | 89 | @property 90 | def codes(self): 91 | return self._codes 92 | 93 | @property 94 | def label(self): 95 | return self._dataset.get_labels() 96 | 97 | def finish_epoch(self): 98 | self._index_in_epoch = 0 99 | np.random.shuffle(self._perm) 100 | 101 | -------------------------------------------------------------------------------- /DeepHash/model/dtq/__init__.py: -------------------------------------------------------------------------------- 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) 18 | -------------------------------------------------------------------------------- /DeepHash/model/dtq/dtq.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import shutil 4 | import time 5 | from datetime import datetime 6 | from math import ceil 7 | 8 | import numpy as np 9 | import tensorflow as tf 10 | from sklearn.cluster import MiniBatchKMeans 11 | 12 | from architecture import img_alexnet_layers 13 | from distance.tfversion import distance 14 | from evaluation import MAPs_CQ 15 | 16 | 17 | class DTQ(object): 18 | def __init__(self, config): 19 | # Initialize setting 20 | np.set_printoptions(precision=4) 21 | 22 | with tf.name_scope('stage'): 23 | # 0 for training, 1 for validation 24 | self.stage = tf.placeholder_with_default(tf.constant(0), []) 25 | 26 | self.output_dim = config.output_dim 27 | self.n_class = config.label_dim 28 | 29 | self.subspace_num = config.subspace 30 | self.subcenter_num = config.subcenter 31 | self.code_batch_size = config.code_batch_size 32 | self.cq_lambda = config.cq_lambda 33 | self.max_iter_update_Cb = config.max_iter_update_Cb 34 | self.max_iter_update_b = config.max_iter_update_b 35 | 36 | self.batch_size = 3 * config.batch_size 37 | self.val_batch_size = config.val_batch_size 38 | self.max_epoch = config.epochs 39 | self.img_model = config.img_model 40 | self.with_tanh = config.with_tanh 41 | self.dist_type = config.dist_type 42 | self.learning_rate = config.lr 43 | self.decay_factor = config.decay_factor 44 | self.decay_step = config.decay_step 45 | self.val_freq = config.val_freq 46 | 47 | self.triplet_margin = config.triplet_margin 48 | self.select_strategy = config.select_strategy 49 | self.n_part = config.n_part 50 | self.triplet_thresold = config.triplet_thresold 51 | 52 | self.finetune_all = config.finetune_all 53 | 54 | self.file_name = 'lr_{}_margin_{}_{}_dim_{}_subspace_{}_subcenter_{}_{}_n_part_{}_{}_ds_{}'.format( 55 | self.learning_rate, 56 | self.triplet_margin, 57 | self.select_strategy, 58 | self.output_dim, 59 | self.subspace_num, 60 | self.subcenter_num, 61 | self.dist_type, 62 | self.n_part, 63 | self.triplet_thresold, 64 | config.dataset) 65 | self.save_dir = os.path.join(config.save_dir, self.file_name + '.npy') 66 | self.log_dir = config.log_dir 67 | 68 | # Setup session 69 | config_proto = tf.ConfigProto() 70 | config_proto.gpu_options.allow_growth = True 71 | config_proto.allow_soft_placement = True 72 | self.sess = tf.Session(config=config_proto) 73 | 74 | # Create variables and placeholders 75 | self.img = tf.placeholder(tf.float32, [None, 256, 256, 3]) 76 | self.model_weights = config.model_weights 77 | self.img_last_layer, self.deep_param_img, self.train_layers, self.train_last_layer = self.load_model() 78 | 79 | with tf.name_scope('quantization'): 80 | self.C = tf.Variable(tf.random_uniform( 81 | [self.subspace_num * self.subcenter_num, self.output_dim], 82 | minval=-1, maxval=1, dtype=tf.float32, name='centers')) 83 | self.deep_param_img['C'] = self.C 84 | 85 | self.img_output_all = tf.placeholder(tf.float32, [None, self.output_dim]) 86 | self.img_b_all = tf.placeholder(tf.float32, [None, self.subspace_num * self.subcenter_num]) 87 | 88 | self.b_img = tf.placeholder(tf.float32, [None, self.subspace_num * self.subcenter_num]) 89 | self.ICM_m = tf.placeholder(tf.int32, []) 90 | self.ICM_b_m = tf.placeholder(tf.float32, [None, self.subcenter_num]) 91 | self.ICM_b_all = tf.placeholder(tf.float32, [None, self.subcenter_num * self.subspace_num]) 92 | self.ICM_X = tf.placeholder(tf.float32, [self.code_batch_size, self.output_dim]) 93 | self.ICM_C_m = tf.slice(self.C, [self.ICM_m * self.subcenter_num, 0], [self.subcenter_num, self.output_dim]) 94 | self.ICM_X_residual = self.ICM_X - tf.matmul(self.ICM_b_all, self.C) + tf.matmul(self.ICM_b_m, self.ICM_C_m) 95 | ICM_X_expand = tf.expand_dims(self.ICM_X_residual, 1) 96 | ICM_C_m_expand = tf.expand_dims(self.ICM_C_m, 0) 97 | 98 | ICM_Loss = tf.reduce_sum(tf.square(ICM_X_expand - ICM_C_m_expand), 2) # N * M * D -> N * M 99 | ICM_best_centers = tf.argmin(ICM_Loss, 1) 100 | self.ICM_best_centers_one_hot = tf.one_hot(ICM_best_centers, self.subcenter_num, dtype=tf.float32) 101 | 102 | self.global_step = tf.Variable(0, trainable=False) 103 | self.train_op = self.apply_loss_function(self.global_step) 104 | self.sess.run(tf.global_variables_initializer()) 105 | return 106 | 107 | def load_model(self): 108 | if self.img_model == 'alexnet': 109 | img_output = img_alexnet_layers( 110 | self.img, 111 | self.batch_size, 112 | self.output_dim, 113 | self.stage, 114 | self.model_weights, 115 | self.with_tanh, 116 | self.val_batch_size) 117 | else: 118 | raise Exception('cannot use such CNN model as ' + self.img_model) 119 | return img_output 120 | 121 | def save_codes(self, database, query, C, model_file=None): 122 | if model_file is None: 123 | model_file = self.save_dir + "_codes.npy" 124 | 125 | model = { 126 | 'db_features': database.output, 127 | 'db_reconstr': np.dot(database.codes, C), 128 | 'db_label': database.label, 129 | 'val_features': query.output, 130 | 'val_reconstr': np.dot(query.codes, C), 131 | 'val_label': query.label, 132 | } 133 | print("saving codes to %s" % model_file) 134 | folder = os.path.dirname(model_file) 135 | if os.path.exists(folder) is False: 136 | os.makedirs(folder) 137 | np.save(model_file, np.array(model)) 138 | return 139 | 140 | def save_model(self, model_file=None): 141 | if model_file is None: 142 | model_file = self.save_dir 143 | 144 | model = {} 145 | for layer in self.deep_param_img: 146 | model[layer] = self.sess.run(self.deep_param_img[layer]) 147 | 148 | print("saving model to %s" % model_file) 149 | folder = os.path.dirname(model_file) 150 | if os.path.exists(folder) is False: 151 | os.makedirs(folder) 152 | 153 | np.save(model_file, np.array(model)) 154 | return 155 | 156 | def triplet_loss(self, anchor, pos, neg, margin): 157 | with tf.variable_scope('triplet_loss'): 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) 166 | 167 | return loss 168 | 169 | def quantization_loss(self, z, h): 170 | with tf.name_scope('quantization_loss'): 171 | q_loss = tf.reduce_mean(tf.reduce_sum(tf.square(z - tf.matmul(h, self.C)), -1)) 172 | return q_loss 173 | 174 | def apply_loss_function(self, global_step): 175 | anchor, pos, neg = tf.split(self.img_last_layer, 3, axis=0) 176 | triplet_loss = self.triplet_loss(anchor, pos, neg, self.triplet_margin) 177 | cq_loss = self.quantization_loss(self.img_last_layer, self.b_img) 178 | self.loss = triplet_loss + cq_loss * self.cq_lambda 179 | 180 | self.lr = tf.train.exponential_decay( 181 | self.learning_rate, 182 | global_step, 183 | self.decay_step, 184 | self.decay_factor, 185 | staircase=True) 186 | opt = tf.train.MomentumOptimizer(learning_rate=self.lr, momentum=0.9) 187 | grads_and_vars = opt.compute_gradients(self.loss, self.train_layers+self.train_last_layer) 188 | fcgrad, _ = grads_and_vars[-2] 189 | fbgrad, _ = grads_and_vars[-1] 190 | 191 | tf.summary.scalar('loss', self.loss) 192 | tf.summary.scalar('triplet_loss', triplet_loss) 193 | tf.summary.scalar('cq_loss', cq_loss) 194 | tf.summary.scalar('lr', self.lr) 195 | self.merged = tf.summary.merge_all() 196 | 197 | # Last layer has a 10 times learning rate 198 | if self.finetune_all: 199 | return opt.apply_gradients([(grads_and_vars[0][0], self.train_layers[0]), 200 | (grads_and_vars[1][0]*2, self.train_layers[1]), 201 | (grads_and_vars[2][0], self.train_layers[2]), 202 | (grads_and_vars[3][0]*2, self.train_layers[3]), 203 | (grads_and_vars[4][0], self.train_layers[4]), 204 | (grads_and_vars[5][0]*2, self.train_layers[5]), 205 | (grads_and_vars[6][0], self.train_layers[6]), 206 | (grads_and_vars[7][0]*2, self.train_layers[7]), 207 | (grads_and_vars[8][0], self.train_layers[8]), 208 | (grads_and_vars[9][0]*2, self.train_layers[9]), 209 | (grads_and_vars[10][0], self.train_layers[10]), 210 | (grads_and_vars[11][0]*2, self.train_layers[11]), 211 | (grads_and_vars[12][0], self.train_layers[12]), 212 | (grads_and_vars[13][0]*2, self.train_layers[13]), 213 | (fcgrad*10, self.train_last_layer[0]), 214 | (fbgrad*20, self.train_last_layer[1])], global_step=global_step) 215 | else: 216 | return opt.apply_gradients([(fcgrad*10, self.train_last_layer[0]), 217 | (fbgrad*20, self.train_last_layer[1])], global_step=global_step) 218 | 219 | def initial_centers(self, img_output): 220 | C_init = np.zeros([self.subspace_num * self.subcenter_num, self.output_dim]) 221 | all_output = img_output 222 | for i in range(self.subspace_num): 223 | start = i*int(self.output_dim/self.subspace_num) 224 | end = (i+1)*int(self.output_dim/self.subspace_num) 225 | to_fit = all_output[:, start:end] 226 | kmeans = MiniBatchKMeans(n_clusters=self.subcenter_num).fit(to_fit) 227 | C_init[i * self.subcenter_num: (i + 1) * self.subcenter_num, start:end] = kmeans.cluster_centers_ 228 | return C_init 229 | 230 | def update_centers(self, img_dataset): 231 | ''' 232 | Optimize: 233 | self.C = (U * hu^T + V * hv^T) (hu * hu^T + hv * hv^T)^{-1} 234 | self.C^T = (hu * hu^T + hv * hv^T)^{-1} (hu * U^T + hv * V^T) 235 | but all the C need to be replace with C^T : 236 | self.C = (hu * hu^T + hv * hv^T)^{-1} (hu^T * U + hv^T * V) 237 | ''' 238 | old_C_value = self.sess.run(self.C) 239 | 240 | h = self.img_b_all 241 | U = self.img_output_all 242 | smallResidual = tf.constant(np.eye(self.subcenter_num * self.subspace_num, dtype=np.float32) * 0.001) 243 | Uh = tf.matmul(tf.transpose(h), U) 244 | hh = tf.add(tf.matmul(tf.transpose(h), h), smallResidual) 245 | compute_centers = tf.matmul(tf.matrix_inverse(hh), Uh) 246 | 247 | update_C = self.C.assign(compute_centers) 248 | C_value = self.sess.run(update_C, feed_dict={ 249 | self.img_output_all: img_dataset.output, 250 | self.img_b_all: img_dataset.codes, 251 | }) 252 | 253 | C_sums = np.sum(np.square(C_value), axis=1) 254 | C_zeros_ids = np.where(C_sums < 1e-8) 255 | C_value[C_zeros_ids, :] = old_C_value[C_zeros_ids, :] 256 | self.sess.run(self.C.assign(C_value)) 257 | 258 | def update_codes_ICM(self, output, code): 259 | ''' 260 | Optimize: 261 | min || output - self.C * codes || 262 | min || output - codes * self.C || 263 | args: 264 | output: [n_train, n_output] 265 | self.C: [n_subspace * n_subcenter, n_output] 266 | [C_1, C_2, ... C_M] 267 | codes: [n_train, n_subspace * n_subcenter] 268 | ''' 269 | 270 | code = np.zeros(code.shape) 271 | 272 | for iterate in range(self.max_iter_update_b): 273 | sub_list = list(range(self.subspace_num)) 274 | random.shuffle(sub_list) 275 | for m in sub_list: 276 | best_centers_one_hot_val = self.sess.run(self.ICM_best_centers_one_hot, feed_dict={ 277 | self.ICM_b_m: code[:, m * self.subcenter_num: (m + 1) * self.subcenter_num], 278 | self.ICM_b_all: code, 279 | self.ICM_m: m, 280 | self.ICM_X: output, 281 | }) 282 | 283 | code[:, m * self.subcenter_num: (m + 1) * self.subcenter_num] = best_centers_one_hot_val 284 | return code 285 | 286 | def update_codes_batch(self, dataset, batch_size): 287 | ''' 288 | update codes in batch size 289 | ''' 290 | total_batch = int(ceil(dataset.n_samples / float(batch_size))) 291 | dataset.finish_epoch() 292 | 293 | for i in range(total_batch): 294 | output_val, code_val = dataset.next_batch_output_codes(batch_size) 295 | codes_val = self.update_codes_ICM(output_val, code_val) 296 | dataset.feed_batch_codes(batch_size, codes_val) 297 | 298 | dataset.finish_epoch() 299 | 300 | def update_codes_and_centers(self, img_dataset): 301 | for i in range(self.max_iter_update_Cb): 302 | self.update_codes_batch(img_dataset, self.code_batch_size) 303 | self.update_centers(img_dataset) 304 | 305 | def update_embedding_and_triplets(self, img_dataset): 306 | epoch_iter = int(img_dataset.n_samples / self.batch_size) 307 | for i in range(epoch_iter): 308 | images, labels, codes = img_dataset.next_batch(self.batch_size) 309 | output = self.sess.run(self.img_last_layer, 310 | feed_dict={self.img: images, self.b_img: codes}) 311 | 312 | img_dataset.feed_batch_output(self.batch_size, output) 313 | img_dataset.update_triplets(self.triplet_margin, n_part=self.n_part, select_strategy=self.select_strategy) 314 | 315 | n_triplets = img_dataset.triplets.shape[0] 316 | if n_triplets < self.triplet_thresold and self.n_part > 1: 317 | print('Halve n_part, num_triplets(%s) < triplet thresold(%d)' % (n_triplets, self.triplet_thresold)) 318 | self.n_part = int(self.n_part / 2) 319 | 320 | def train_cq(self, img_dataset, img_query, img_database, R): 321 | print("%s #train# start training" % datetime.now()) 322 | 323 | # tensorboard 324 | tflog_path = os.path.join(self.log_dir, self.file_name) 325 | if os.path.exists(tflog_path): 326 | shutil.rmtree(tflog_path) 327 | train_writer = tf.summary.FileWriter(tflog_path, self.sess.graph) 328 | 329 | print("Get initial embedding and select triplets...") 330 | start_time = time.time() 331 | self.update_embedding_and_triplets(img_dataset) 332 | duration = time.time() - start_time 333 | print('Embedding Done: Time %.3fs' % duration) 334 | 335 | print('Initialize centers and update codes and centers') 336 | self.sess.run(self.C.assign(self.initial_centers(img_dataset.output))) 337 | self.update_codes_and_centers(img_dataset) 338 | 339 | train_iter = 0 340 | for epoch in range(self.max_epoch): 341 | triplet_batch_size = int(self.batch_size / 3) 342 | epoch_iter = int(img_dataset.triplets.shape[0] / triplet_batch_size) 343 | img_dataset.finish_epoch() 344 | for i in range(epoch_iter): 345 | start_time = time.time() 346 | images, labels, codes = img_dataset.next_batch_triplet(triplet_batch_size) 347 | _, output, loss, summary = self.sess.run( 348 | [self.train_op, self.img_last_layer, self.loss, self.merged], 349 | feed_dict={self.img: images, 350 | self.b_img: codes}) 351 | img_dataset.feed_batch_triplet_output(triplet_batch_size, output) 352 | if train_iter < 100 or i % 100 == 0: 353 | print('%s Epoch: [%d/%d][%d/%d]\tTime %.3fs\tLoss %.3f' 354 | % (datetime.now(), epoch, self.max_epoch, i+1, epoch_iter, time.time() - start_time, loss)) 355 | train_writer.add_summary(summary, train_iter) 356 | train_iter += 1 357 | 358 | # every epoch: update embedding, codes and centers 359 | self.update_codes_and_centers(img_dataset) 360 | 361 | # update triplets 362 | self.update_embedding_and_triplets(img_dataset) 363 | # img_dataset.update_triplets(self.triplet_margin, n_part=self.n_part, select_strategy=self.select_strategy) 364 | 365 | val_summary = tf.Summary() 366 | val_summary.value.add(tag='num_triplets', simple_value=img_dataset.triplets.shape[0]) 367 | # validation 368 | if (epoch+1) % self.val_freq == 0 or (epoch+1) == self.max_epoch: 369 | maps = self.validation(img_query, img_database, R) 370 | for key in maps: 371 | print("{}\t{}".format(key, maps[key])) 372 | val_summary.value.add(tag=key, simple_value=maps[key]) 373 | train_writer.add_summary(val_summary, epoch+1) 374 | train_writer.flush() 375 | 376 | print("%s #traing# finish training" % datetime.now()) 377 | self.save_model() 378 | print("model saved") 379 | 380 | self.sess.close() 381 | 382 | def val_forward(self, img_dataset, val_print_freq=100): 383 | batch = int(ceil(img_dataset.n_samples / float(self.val_batch_size))) 384 | img_dataset.finish_epoch() 385 | for i in range(batch): 386 | images, labels, codes = img_dataset.next_batch(self.val_batch_size) 387 | output = self.sess.run([self.img_last_layer], 388 | feed_dict={self.img: images, 389 | self.stage: 1}) 390 | img_dataset.feed_batch_output(self.val_batch_size, output) 391 | if i % val_print_freq == 0: 392 | print("%s #validation# batch %d/%d" % (datetime.now(), i, batch)) 393 | 394 | def validation(self, img_query, img_database, R=100): 395 | print("%s #validation# start validation" % (datetime.now())) 396 | 397 | # Forward to get output 398 | self.val_forward(img_query) 399 | self.val_forward(img_database) 400 | 401 | # Initialize centers 402 | self.sess.run(self.C.assign(self.initial_centers(img_database.output))) 403 | 404 | # Get codes of database && Update centers 405 | self.update_codes_and_centers(img_database) 406 | 407 | # Get codes of query 408 | self.update_codes_batch(img_query, self.code_batch_size) 409 | 410 | # Evaluation 411 | print("%s #validation# calculating MAP@%d" % (datetime.now(), R)) 412 | C_tmp = self.sess.run(self.C) 413 | mAPs = MAPs_CQ(C_tmp, self.subspace_num, self.subcenter_num, R) 414 | self.save_codes(img_database, img_query, C_tmp) 415 | return { 416 | 'map_feature_ip': mAPs.get_mAPs_by_feature(img_database, img_query), 417 | 'map_AQD_ip': mAPs.get_mAPs_AQD(img_database, img_query), 418 | 'map_SQD_ip': mAPs.get_mAPs_SQD(img_database, img_query) 419 | } 420 | 421 | -------------------------------------------------------------------------------- /DeepHash/model/dtq/util.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math 3 | from distance.npversion import distance 4 | 5 | class Dataset(object): 6 | def __init__(self, dataset, output_dim, code_dim): 7 | self._dataset = dataset 8 | self.n_samples = dataset.n_samples 9 | self._train = dataset.train 10 | self._output = np.zeros((self.n_samples, output_dim), dtype=np.float32) 11 | self._codes = np.zeros((self.n_samples, code_dim), dtype=np.float32) 12 | self._triplets = np.array([]) 13 | self._trip_index_in_epoch = 0 14 | self._index_in_epoch = 0 15 | self._epochs_complete = 0 16 | self._perm = np.arange(self.n_samples) 17 | np.random.shuffle(self._perm) 18 | return 19 | 20 | def update_triplets(self, margin, n_part=10, dist_type='euclidean2', select_strategy='margin'): 21 | """ 22 | :param select_strategy: hard, all, margin 23 | :param dist_type: distance type, e.g. euclidean2, cosine 24 | :param margin: triplet margin parameter 25 | :n_part: number of part to split data 26 | """ 27 | n_samples = self.n_samples 28 | np.random.shuffle(self._perm) 29 | embedding = self._output[self._perm[:n_samples]] 30 | labels = self._dataset.get_labels()[self._perm[:n_samples]] 31 | n_samples_per_part = int(math.ceil(n_samples / n_part)) 32 | triplets = [] 33 | for i in range(n_part): 34 | start = n_samples_per_part * i 35 | end = min(n_samples_per_part * (i+1), n_samples) 36 | dist = distance(embedding[start:end], pair=True, dist_type=dist_type) 37 | for idx_anchor in range(0, end - start): 38 | label_anchor = np.copy(labels[idx_anchor+start, :]) 39 | label_anchor[label_anchor==0] = -1 40 | all_pos = np.where(np.any(labels[start:end] == label_anchor, axis=1))[0] 41 | all_neg = np.array(list(set(range(end-start)) - set(all_pos))) 42 | 43 | if select_strategy == 'hard': 44 | idx_pos = all_pos[np.argmax(dist[idx_anchor, all_pos])] 45 | if idx_pos == idx_anchor: 46 | continue 47 | idx_neg = all_neg[np.argmin(dist[idx_anchor, all_neg])] 48 | triplets.append((idx_anchor + start, idx_pos + start, idx_neg + start)) 49 | continue 50 | 51 | for idx_pos in all_pos: 52 | if idx_pos == idx_anchor: 53 | continue 54 | 55 | if select_strategy == 'all': 56 | selected_neg = all_neg 57 | elif select_strategy == 'margin': 58 | selected_neg = all_neg[np.where(dist[idx_anchor, all_neg] - dist[idx_anchor, idx_pos] < margin)[0]] 59 | 60 | if selected_neg.shape[0] > 0: 61 | idx_neg = np.random.choice(selected_neg) 62 | triplets.append((idx_anchor + start, idx_pos + start, idx_neg + start)) 63 | self._triplets = np.array(triplets) 64 | np.random.shuffle(self._triplets) 65 | 66 | # assert 67 | anchor = labels[self._triplets[:, 0]] 68 | mapper = lambda anchor, other: np.any(anchor * (anchor == other), -1) 69 | assert(np.all(mapper(anchor, labels[self._triplets[:, 1]]))) 70 | assert(np.all(np.invert(anchor, labels[self._triplets[:, 2]]))) 71 | return 72 | 73 | def next_batch_triplet(self, batch_size): 74 | """ 75 | Args: 76 | batch_size 77 | Returns: 78 | data, label, codes 79 | """ 80 | start = self._trip_index_in_epoch 81 | self._trip_index_in_epoch += batch_size 82 | if self._trip_index_in_epoch > self.triplets.shape[0]: 83 | start = 0 84 | self._trip_index_in_epoch = batch_size 85 | end = self._trip_index_in_epoch 86 | 87 | # stack index of anchors, positive, negetive to one array 88 | arr = self.triplets[start:end] 89 | idx = self._perm[np.concatenate([arr[:, 0], arr[:, 1], arr[:, 2]], axis=0)] 90 | data, label = self._dataset.data(idx) 91 | 92 | return data, label, self._codes[idx] 93 | 94 | def next_batch(self, batch_size): 95 | """ 96 | Args: 97 | batch_size 98 | Returns: 99 | [batch_size, (n_inputs)]: next batch images, by stacking anchor, positive, negetive 100 | [batch_size, n_class]: next batch labels 101 | """ 102 | start = self._index_in_epoch 103 | self._index_in_epoch += batch_size 104 | if self._index_in_epoch > self.n_samples: 105 | if self._train: 106 | self._epochs_complete += 1 107 | start = 0 108 | self._index_in_epoch = batch_size 109 | else: 110 | # Validation stage only process once 111 | start = self.n_samples - batch_size 112 | self._index_in_epoch = self.n_samples 113 | end = self._index_in_epoch 114 | 115 | data, label = self._dataset.data(self._perm[start:end]) 116 | return (data, label, self._codes[self._perm[start: end], :]) 117 | 118 | def next_batch_output_codes(self, batch_size): 119 | start = self._index_in_epoch 120 | self._index_in_epoch += batch_size 121 | # Another epoch finish 122 | if self._index_in_epoch > self.n_samples: 123 | if self._train: 124 | # Start next epoch 125 | start = 0 126 | self._index_in_epoch = batch_size 127 | else: 128 | # Validation stage only process once 129 | start = self.n_samples - batch_size 130 | self._index_in_epoch = self.n_samples 131 | end = self._index_in_epoch 132 | 133 | return (self._output[self._perm[start: end], :], 134 | self._codes[self._perm[start: end], :]) 135 | 136 | def feed_batch_output(self, batch_size, output): 137 | start = self._index_in_epoch - batch_size 138 | end = self._index_in_epoch 139 | self._output[self._perm[start:end], :] = output 140 | return 141 | 142 | def feed_batch_triplet_output(self, batch_size, triplet_output): 143 | anchor, pos, neg = np.split(triplet_output, 3, axis=0) 144 | start = self._trip_index_in_epoch - batch_size 145 | end = self._trip_index_in_epoch 146 | idx = self._perm[self._triplets[start:end, :]] 147 | self._output[idx[:, 0]] = anchor 148 | self._output[idx[:, 1]] = pos 149 | self._output[idx[:, 2]] = neg 150 | return 151 | 152 | def feed_batch_codes(self, batch_size, codes): 153 | """ 154 | Args: 155 | batch_size 156 | [batch_size, n_output] 157 | """ 158 | start = self._index_in_epoch - batch_size 159 | end = self._index_in_epoch 160 | self._codes[self._perm[start:end], :] = codes 161 | return 162 | 163 | @property 164 | def output(self): 165 | return self._output 166 | 167 | @property 168 | def codes(self): 169 | return self._codes 170 | 171 | @property 172 | def triplets(self): 173 | return self._triplets 174 | 175 | @property 176 | def label(self): 177 | return self._dataset.get_labels() 178 | 179 | def finish_epoch(self): 180 | self._index_in_epoch = 0 181 | -------------------------------------------------------------------------------- /DeepHash/model/dvsq/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thulab/DeepHash/9907613e1b73818985bc585af613a960c8df7d20/DeepHash/model/dvsq/__init__.py -------------------------------------------------------------------------------- /DeepHash/model/dvsq/dvsq.py: -------------------------------------------------------------------------------- 1 | ################################################################################# 2 | # Deep Visual-Semantic Quantization for Efficient Image Retrieval # 3 | # Authors: Yue Cao, Mingsheng Long, Jianmin Wang, Shichen Liu # 4 | # Contact: caoyue10@gmail.com # 5 | ################################################################################## 6 | 7 | import os 8 | import random 9 | import shutil 10 | import time 11 | from datetime import datetime 12 | from math import ceil 13 | 14 | import numpy as np 15 | import tensorflow as tf 16 | from sklearn.cluster import MiniBatchKMeans 17 | 18 | from architecture import img_alexnet_layers 19 | from evaluation import MAPs_CQ 20 | from .util import Dataset 21 | 22 | 23 | class DVSQ(object): 24 | def __init__(self, config): 25 | # Initialize setting 26 | print("initializing") 27 | np.set_printoptions(precision=4) 28 | self.stage = tf.placeholder_with_default(tf.constant(0), []) 29 | self.device = config['device'] 30 | self.output_dim = config['output_dim'] 31 | self.n_class = config['label_dim'] 32 | 33 | self.subspace_num = config['n_subspace'] 34 | self.subcenter_num = config['n_subcenter'] 35 | self.code_batch_size = config['code_batch_size'] 36 | self.cq_lambda = config['cq_lambda'] 37 | self.max_iter_update_Cb = config['max_iter_update_Cb'] 38 | self.max_iter_update_b = config['max_iter_update_b'] 39 | 40 | self.batch_size = config['batch_size'] 41 | self.val_batch_size = config['val_batch_size'] 42 | self.max_iter = config['max_iter'] 43 | self.img_model = config['img_model'] 44 | self.loss_type = config['loss_type'] 45 | self.learning_rate = config['learning_rate'] 46 | self.learning_rate_decay_factor = config['learning_rate_decay_factor'] 47 | self.decay_step = config['decay_step'] 48 | 49 | self.finetune_all = config['finetune_all'] 50 | 51 | self.wordvec_dict = config['wordvec_dict'] 52 | 53 | self.file_name = 'lr_{}_cqlambda_{}_subspace_num_{}_dataset_{}'.format( 54 | self.learning_rate, 55 | self.cq_lambda, 56 | self.subspace_num, 57 | config['dataset']) 58 | self.save_dir = os.path.join( 59 | config['save_dir'], self.file_name + '.npy') 60 | self.log_dir = config['log_dir'] 61 | 62 | # Setup session 63 | print("launching session") 64 | configProto = tf.ConfigProto() 65 | configProto.gpu_options.allow_growth = True 66 | configProto.allow_soft_placement = True 67 | self.sess = tf.Session(config=configProto) 68 | 69 | # Create variables and placeholders 70 | 71 | with tf.device(self.device): 72 | self.img = tf.placeholder(tf.float32, [None, 256, 256, 3]) 73 | self.img_label = tf.placeholder(tf.float32, [None, self.n_class]) 74 | 75 | self.model_weights = config['model_weights'] 76 | self.img_last_layer, self.deep_param_img, self.train_layers, self.train_last_layer = self.load_model() 77 | 78 | # TODO 79 | self.C = tf.Variable(tf.random_uniform([self.subspace_num * self.subcenter_num, self.output_dim], 80 | minval=-1, maxval=1, dtype=tf.float32, name='centers')) 81 | self.deep_param_img['C'] = self.C 82 | 83 | # Centers shared in different modalities (image & text) 84 | # Binary codes for different modalities (image & text) 85 | self.img_output_all = tf.placeholder( 86 | tf.float32, [None, self.output_dim]) 87 | self.img_b_all = tf.placeholder( 88 | tf.float32, [None, self.subspace_num * self.subcenter_num]) 89 | 90 | self.b_img = tf.placeholder( 91 | tf.float32, [None, self.subspace_num * self.subcenter_num]) 92 | self.ICM_m = tf.placeholder(tf.int32, []) 93 | self.ICM_b_m = tf.placeholder( 94 | tf.float32, [None, self.subcenter_num]) 95 | self.ICM_b_all = tf.placeholder( 96 | tf.float32, [None, self.subcenter_num * self.subspace_num]) 97 | self.ICM_X = tf.placeholder( 98 | tf.float32, [self.code_batch_size, self.output_dim]) 99 | self.ICM_C_m = tf.slice( 100 | self.C, [self.ICM_m * self.subcenter_num, 0], [self.subcenter_num, self.output_dim]) 101 | self.ICM_X_residual = tf.add(tf.subtract(self.ICM_X, tf.matmul( 102 | self.ICM_b_all, self.C)), tf.matmul(self.ICM_b_m, self.ICM_C_m)) 103 | ICM_X_expand = tf.expand_dims(self.ICM_X_residual, 1) # N * 1 * D 104 | ICM_C_m_expand = tf.expand_dims(self.ICM_C_m, 0) # 1 * M * D 105 | # N*sc*D * D*n 106 | word_dict = tf.constant(np.loadtxt( 107 | self.wordvec_dict), dtype=tf.float32) 108 | ICM_word_dict = tf.reshape( 109 | tf.matmul( 110 | tf.reshape( 111 | ICM_X_expand - ICM_C_m_expand, 112 | [self.code_batch_size * self.subcenter_num, self.output_dim]), 113 | tf.transpose(word_dict)), 114 | [self.code_batch_size, self.subcenter_num, self.n_class]) 115 | ICM_sum_squares = tf.reduce_sum( 116 | tf.square(ICM_word_dict), reduction_indices=2) 117 | ICM_best_centers = tf.argmin(ICM_sum_squares, 1) 118 | self.ICM_best_centers_one_hot = tf.one_hot( 119 | ICM_best_centers, self.subcenter_num, dtype=tf.float32) 120 | 121 | self.global_step = tf.Variable(0, trainable=False) 122 | self.train_op = self.apply_loss_function(self.global_step) 123 | self.sess.run(tf.global_variables_initializer()) 124 | return 125 | 126 | def load_model(self): 127 | if self.img_model == 'alexnet': 128 | img_output = img_alexnet_layers( 129 | self.img, self.batch_size, self.output_dim, 130 | self.stage, self.model_weights, val_batch_size=self.val_batch_size) 131 | else: 132 | raise Exception('cannot use such CNN model as ' + self.img_model) 133 | return img_output 134 | 135 | def save_model(self, model_file=None): 136 | if model_file is None: 137 | model_file = self.save_dir 138 | model = {} 139 | for layer in self.deep_param_img: 140 | model[layer] = self.sess.run(self.deep_param_img[layer]) 141 | print("saving model to %s" % model_file) 142 | folder = os.path.dirname(model_file) 143 | if os.path.exists(folder) is False: 144 | os.makedirs(folder) 145 | np.save(model_file, np.array(model)) 146 | return 147 | 148 | def save_codes(self, database, query, C, model_file=None): 149 | if model_file is None: 150 | model_file = self.model_weights + "_codes.npy" 151 | model = { 152 | 'db_features': database.output, 153 | 'db_reconstr': np.dot(database.codes, C), 154 | 'db_label': database.label, 155 | 'val_features': query.output, 156 | 'val_reconstr': np.dot(query.codes, C), 157 | 'val_label': query.label, 158 | } 159 | print("saving codes to %s" % model_file) 160 | np.save(model_file, np.array(model)) 161 | return 162 | 163 | def apply_loss_function(self, global_step): 164 | # loss function 165 | if self.loss_type == 'cos_margin_multi_label': 166 | assert self.output_dim == 300 167 | word_dict = tf.constant(np.loadtxt( 168 | self.wordvec_dict), dtype=tf.float32) 169 | margin_param = tf.constant(self.margin_param, dtype=tf.float32) 170 | 171 | # N: batchsize, L: label_dim, D: 300 172 | # img_label: N * L 173 | # word_dic: L * D 174 | # v_label: N * L * D 175 | v_label = tf.multiply(tf.expand_dims( 176 | self.img_label, 2), tf.expand_dims(word_dict, 0)) 177 | # img_last: N * D 178 | # ip_1: N * L 179 | ip_1 = tf.reduce_sum(tf.multiply( 180 | tf.expand_dims(self.img_last_layer, 1), v_label), 2) 181 | # mod_1: N * L 182 | v_label_mod = tf.multiply(tf.expand_dims( 183 | tf.ones([self.batch_size, self.n_class]), 2), tf.expand_dims(word_dict, 0)) 184 | mod_1 = tf.sqrt(tf.multiply(tf.expand_dims(tf.reduce_sum(tf.square( 185 | self.img_last_layer), 1), 1), tf.reduce_sum(tf.square(v_label_mod), 2))) 186 | # cos_1: N * L 187 | cos_1 = tf.div(ip_1, mod_1) 188 | 189 | ip_2 = tf.matmul(self.img_last_layer, word_dict, transpose_b=True) 190 | # multiply ids to inner product 191 | 192 | def reduce_shaper(t): 193 | return tf.reshape(tf.reduce_sum(t, 1), [tf.shape(t)[0], 1]) 194 | mod_2 = tf.sqrt(tf.matmul(reduce_shaper(tf.square( 195 | self.img_last_layer)), reduce_shaper(tf.square(word_dict)), transpose_b=True)) 196 | # cos_2: N * L 197 | cos_2 = tf.div(ip_2, mod_2) 198 | 199 | # cos - cos: N * L * L 200 | cos_cos_1 = tf.subtract(margin_param, tf.subtract( 201 | tf.expand_dims(cos_1, 2), tf.expand_dims(cos_2, 1))) 202 | # we need to let the wrong place be 0 203 | cos_cos = tf.multiply(cos_cos_1, tf.expand_dims(self.img_label, 2)) 204 | 205 | cos_loss = tf.reduce_sum(tf.maximum( 206 | tf.constant(0, dtype=tf.float32), cos_cos)) 207 | self.cos_loss = tf.div(cos_loss, tf.multiply(tf.constant( 208 | self.n_class, dtype=tf.float32), tf.reduce_sum(self.img_label))) 209 | 210 | elif self.loss_type == 'cos_softmargin_multi_label': 211 | assert self.output_dim == 300 212 | word_dict = tf.constant(np.loadtxt( 213 | self.wordvec_dict), dtype=tf.float32) 214 | 215 | # N: batchsize, L: label_dim, D: 300 216 | # img_label: N * L 217 | # word_dic: L * D 218 | # v_label: N * L * D 219 | # img_last: N * D 220 | 221 | ip_2 = tf.matmul(self.img_last_layer, word_dict, transpose_b=True) 222 | # multiply ids to inner product 223 | 224 | def reduce_shaper(t): 225 | return tf.reshape(tf.reduce_sum(t, 1), [tf.shape(t)[0], 1]) 226 | mod_2 = tf.sqrt(tf.matmul(reduce_shaper(tf.square( 227 | self.img_last_layer)), reduce_shaper(tf.square(word_dict)), transpose_b=True)) 228 | # cos_2: N * L 229 | cos_2 = tf.div(ip_2, mod_2) 230 | 231 | # word_dic: L * D 232 | # ip_3: L * L 233 | # compute soft margin 234 | ip_3 = tf.matmul(word_dict, word_dict, transpose_b=True) 235 | # use word_dic to avoid 0 in / 236 | mod_3 = tf.sqrt(tf.matmul(reduce_shaper(tf.square(word_dict)), reduce_shaper( 237 | tf.square(word_dict)), transpose_b=True)) 238 | margin_param = tf.subtract(tf.constant( 239 | 1.0, dtype=tf.float32), tf.div(ip_3, mod_3)) 240 | 241 | # cos - cos: N * L * L 242 | cos_cos_1 = tf.subtract(tf.expand_dims(margin_param, 0), tf.subtract( 243 | tf.expand_dims(cos_2, 2), tf.expand_dims(cos_2, 1))) 244 | # we need to let the wrong place be 0 245 | cos_cos = tf.multiply(cos_cos_1, tf.expand_dims(self.img_label, 2)) 246 | 247 | cos_loss = tf.reduce_sum(tf.maximum( 248 | tf.constant(0, dtype=tf.float32), cos_cos)) 249 | self.cos_loss = tf.div(cos_loss, tf.multiply(tf.constant( 250 | self.n_class, dtype=tf.float32), tf.reduce_sum(self.img_label))) 251 | 252 | self.precq_loss_img = tf.reduce_mean(tf.reduce_sum( 253 | tf.square(tf.subtract(self.img_last_layer, tf.matmul(self.b_img, self.C))), 1)) 254 | word_dict = tf.constant(np.loadtxt( 255 | self.wordvec_dict), dtype=tf.float32) 256 | self.cq_loss_img = tf.reduce_mean(tf.reduce_sum(tf.square(tf.matmul(tf.subtract( 257 | self.img_last_layer, tf.matmul(self.b_img, self.C)), tf.transpose(word_dict))), 1)) 258 | self.q_lambda = tf.Variable(self.cq_lambda, name='cq_lambda') 259 | self.cq_loss = tf.multiply(self.q_lambda, self.cq_loss_img) 260 | self.loss = self.cos_loss + self.cq_loss 261 | 262 | # Last layer has a 10 times learning rate 263 | self.lr = tf.train.exponential_decay( 264 | self.learning_rate, global_step, self.decay_step, self.learning_rate_decay_factor, staircase=True) 265 | opt = tf.train.MomentumOptimizer(learning_rate=self.lr, momentum=0.9) 266 | grads_and_vars = opt.compute_gradients( 267 | self.loss, self.train_layers + self.train_last_layer) 268 | fcgrad, _ = grads_and_vars[-2] 269 | fbgrad, _ = grads_and_vars[-1] 270 | 271 | # for debug 272 | self.grads_and_vars = grads_and_vars 273 | tf.summary.scalar('loss', self.loss) 274 | tf.summary.scalar('cos_loss', self.cos_loss) 275 | tf.summary.scalar('cq_loss', self.cq_loss) 276 | tf.summary.scalar('lr', self.lr) 277 | self.merged = tf.summary.merge_all() 278 | 279 | if self.finetune_all: 280 | return opt.apply_gradients([(grads_and_vars[0][0], self.train_layers[0]), 281 | (grads_and_vars[1][0]*2, self.train_layers[1]), 282 | (grads_and_vars[2][0], self.train_layers[2]), 283 | (grads_and_vars[3][0]*2, self.train_layers[3]), 284 | (grads_and_vars[4][0], self.train_layers[4]), 285 | (grads_and_vars[5][0]*2, self.train_layers[5]), 286 | (grads_and_vars[6][0], self.train_layers[6]), 287 | (grads_and_vars[7][0]*2, self.train_layers[7]), 288 | (grads_and_vars[8][0], self.train_layers[8]), 289 | (grads_and_vars[9][0]*2, self.train_layers[9]), 290 | (grads_and_vars[10][0], self.train_layers[10]), 291 | (grads_and_vars[11][0]*2, self.train_layers[11]), 292 | (grads_and_vars[12][0], self.train_layers[12]), 293 | (grads_and_vars[13][0]*2, self.train_layers[13]), 294 | (fcgrad*10, self.train_last_layer[0]), 295 | (fbgrad*20, self.train_last_layer[1])], global_step=global_step) 296 | else: 297 | return opt.apply_gradients([(fcgrad*10, self.train_last_layer[0]), 298 | (fbgrad*20, self.train_last_layer[1])], global_step=global_step) 299 | 300 | def initial_centers(self, img_output): 301 | C_init = np.zeros( 302 | [self.subspace_num * self.subcenter_num, self.output_dim]) 303 | print("#DVSQ train# initilizing Centers") 304 | all_output = img_output 305 | div = int(self.output_dim / self.subspace_num) 306 | for i in range(self.subspace_num): 307 | kmeans = MiniBatchKMeans(n_clusters=self.subcenter_num).fit( 308 | all_output[:, i * div: (i + 1) * div]) 309 | C_init[i * self.subcenter_num: (i + 1) * self.subcenter_num, i * div: (i + 1) * div] = kmeans.cluster_centers_ 310 | print("step: ", i, " finish") 311 | return C_init 312 | 313 | def update_centers(self, img_dataset): 314 | ''' 315 | Optimize: 316 | self.C = (U * hu^T + V * hv^T) (hu * hu^T + hv * hv^T)^{-1} 317 | self.C^T = (hu * hu^T + hv * hv^T)^{-1} (hu * U^T + hv * V^T) 318 | but all the C need to be replace with C^T : 319 | self.C = (hu * hu^T + hv * hv^T)^{-1} (hu^T * U + hv^T * V) 320 | ''' 321 | old_C_value = self.sess.run(self.C) 322 | 323 | h = self.img_b_all 324 | U = self.img_output_all 325 | smallResidual = tf.constant( 326 | np.eye(self.subcenter_num * self.subspace_num, dtype=np.float32) * 0.001) 327 | Uh = tf.matmul(tf.transpose(h), U) 328 | hh = tf.add(tf.matmul(tf.transpose(h), h), smallResidual) 329 | compute_centers = tf.matmul(tf.matrix_inverse(hh), Uh) 330 | 331 | update_C = self.C.assign(compute_centers) 332 | C_value = self.sess.run(update_C, feed_dict={ 333 | self.img_output_all: img_dataset.output, 334 | self.img_b_all: img_dataset.codes, 335 | }) 336 | 337 | C_sums = np.sum(np.square(C_value), axis=1) 338 | C_zeros_ids = np.where(C_sums < 1e-8) 339 | C_value[C_zeros_ids, :] = old_C_value[C_zeros_ids, :] 340 | self.sess.run(self.C.assign(C_value)) 341 | 342 | def update_codes_ICM(self, output, code): 343 | ''' 344 | Optimize: 345 | min || output - self.C * codes || 346 | min || output - codes * self.C || 347 | args: 348 | output: [n_train, n_output] 349 | self.C: [n_subspace * n_subcenter, n_output] 350 | [C_1, C_2, ... C_M] 351 | codes: [n_train, n_subspace * n_subcenter] 352 | ''' 353 | 354 | code = np.zeros(code.shape) 355 | 356 | for iterate in range(self.max_iter_update_b): 357 | 358 | sub_list = [i for i in range(self.subspace_num)] 359 | random.shuffle(sub_list) 360 | for m in sub_list: 361 | best_centers_one_hot_val = self.sess.run(self.ICM_best_centers_one_hot, feed_dict={ 362 | self.ICM_b_m: code[:, m * self.subcenter_num: (m + 1) * self.subcenter_num], 363 | self.ICM_b_all: code, 364 | self.ICM_m: m, 365 | self.ICM_X: output, 366 | }) 367 | 368 | code[:, m * self.subcenter_num: (m + 1) * 369 | self.subcenter_num] = best_centers_one_hot_val 370 | return code 371 | 372 | def update_codes_batch(self, dataset, batch_size): 373 | ''' 374 | update codes in batch size 375 | ''' 376 | total_batch = int(ceil(dataset.n_samples / (batch_size))) 377 | dataset.finish_epoch() 378 | 379 | for i in range(total_batch): 380 | output_val, code_val = dataset.next_batch_output_codes(batch_size) 381 | codes_val = self.update_codes_ICM(output_val, code_val) 382 | dataset.feed_batch_codes(batch_size, codes_val) 383 | 384 | def train_cq(self, img_dataset): 385 | print("%s #train# start training" % datetime.now()) 386 | epoch = 0 387 | epoch_iter = int(ceil(img_dataset.n_samples / self.batch_size)) 388 | 389 | # tensorboard 390 | tflog_path = os.path.join(self.log_dir, self.file_name) 391 | if os.path.exists(tflog_path): 392 | shutil.rmtree(tflog_path) 393 | train_writer = tf.summary.FileWriter(tflog_path, self.sess.graph) 394 | 395 | for train_iter in range(self.max_iter): 396 | images, labels, codes = img_dataset.next_batch(self.batch_size) 397 | start_time = time.time() 398 | 399 | # for epoch 0, q_lambda = 0, for epoch > 0, q_lambda = self.cq_lambda 400 | if epoch <= 1: 401 | assign_lambda = self.q_lambda.assign(epoch * self.cq_lambda) 402 | self.sess.run([assign_lambda]) 403 | 404 | _, loss, output, summary = self.sess.run([self.train_op, self.loss, self.img_last_layer, self.merged], 405 | feed_dict={self.img: images, 406 | self.img_label: labels, 407 | self.b_img: codes}) 408 | 409 | train_writer.add_summary(summary, train_iter) 410 | 411 | img_dataset.feed_batch_output(self.batch_size, output) 412 | duration = time.time() - start_time 413 | 414 | # every epoch: update codes and centers 415 | if train_iter % (2 * epoch_iter) == 0 and train_iter != 0: 416 | if epoch == 0: 417 | with tf.device(self.device): 418 | for i in range(self.max_iter_update_Cb): 419 | self.sess.run(self.C.assign( 420 | self.initial_centers(img_dataset.output))) 421 | 422 | epoch = epoch + 1 423 | for i in range(self.max_iter_update_Cb): 424 | self.update_codes_batch(img_dataset, self.code_batch_size) 425 | self.update_centers(img_dataset) 426 | if train_iter < 100 or train_iter % 50 == 0: 427 | print("%s #train# step %4d, loss = %.4f, %.1f sec/batch" 428 | % (datetime.now(), train_iter + 1, loss, duration)) 429 | 430 | print("%s #traing# finish training" % datetime.now()) 431 | self.save_model() 432 | print("model saved") 433 | 434 | self.sess.close() 435 | 436 | def validation(self, img_query, img_database, R=100): 437 | print("%s #validation# start validation" % (datetime.now())) 438 | query_batch = int(ceil(img_query.n_samples / (self.val_batch_size))) 439 | print("%s #validation# totally %d query in %d batches" % (datetime.now(), img_query.n_samples, query_batch)) 440 | for i in range(query_batch): 441 | images, labels, codes = img_query.next_batch(self.val_batch_size) 442 | output, loss = self.sess.run([self.img_last_layer, self.cos_loss], 443 | feed_dict={self.img: images, self.img_label: labels, self.stage: 1}) 444 | img_query.feed_batch_output(self.val_batch_size, output) 445 | print('Cosine Loss: %s' % loss) 446 | 447 | database_batch = int(ceil(img_database.n_samples / (self.val_batch_size))) 448 | print("%s #validation# totally %d database in %d batches" % 449 | (datetime.now(), img_database.n_samples, database_batch)) 450 | for i in range(database_batch): 451 | images, labels, codes = img_database.next_batch(self.val_batch_size) 452 | 453 | output, loss = self.sess.run([self.img_last_layer, self.cos_loss], 454 | feed_dict={self.img: images, self.img_label: labels, self.stage: 1}) 455 | img_database.feed_batch_output(self.val_batch_size, output) 456 | # print output[:10, :10] 457 | if i % 100 == 0: 458 | print('Cosine Loss[%d/%d]: %s' % (i, database_batch, loss)) 459 | 460 | self.update_codes_batch(img_query, self.code_batch_size) 461 | self.update_codes_batch(img_database, self.code_batch_size) 462 | 463 | C_tmp = self.sess.run(self.C) 464 | # save features and codes 465 | self.save_codes(img_database, img_query, C_tmp) 466 | 467 | print("%s #validation# calculating MAP@%d" % (datetime.now(), R)) 468 | mAPs = MAPs_CQ(C_tmp, self.subspace_num, self.subcenter_num, R) 469 | 470 | self.sess.close() 471 | return { 472 | 'i2i_nocq': mAPs.get_mAPs_by_feature(img_database, img_query), 473 | 'i2i_AQD': mAPs.get_mAPs_AQD(img_database, img_query), 474 | 'i2i_SQD': mAPs.get_mAPs_SQD(img_database, img_query) 475 | } 476 | 477 | 478 | def train(train_img, config): 479 | model = DVSQ(config) 480 | img_dataset = Dataset(train_img, config['output_dim'], config['n_subspace'] * config['n_subcenter']) 481 | model.train_cq(img_dataset) 482 | return model.save_dir 483 | 484 | 485 | def validation(database_img, query_img, config): 486 | model = DVSQ(config) 487 | img_database = Dataset(database_img, config['output_dim'], config['n_subspace'] * config['n_subcenter']) 488 | img_query = Dataset(query_img, config['output_dim'], config['n_subspace'] * config['n_subcenter']) 489 | return model.validation(img_query, img_database, config['R']) 490 | -------------------------------------------------------------------------------- /DeepHash/model/dvsq/util.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class Dataset(object): 4 | def __init__(self, dataset, output_dim, code_dim): 5 | print ("Initializing Dataset") 6 | self._dataset = dataset 7 | self.n_samples = dataset.n_samples 8 | self._train = dataset.train 9 | self._output = np.zeros((self.n_samples, output_dim), dtype=np.float32) 10 | self._codes = np.zeros((self.n_samples, code_dim), dtype=np.float32) 11 | 12 | self._perm = np.arange(self.n_samples) 13 | np.random.shuffle(self._perm) 14 | self._index_in_epoch = 0 15 | self._epochs_complete = 0 16 | print ("Dataset already") 17 | return 18 | 19 | def next_batch(self, batch_size): 20 | """ 21 | Args: 22 | batch_size 23 | Returns: 24 | [batch_size, (n_inputs)]: next batch images 25 | [batch_size, n_class]: next batch labels 26 | """ 27 | start = self._index_in_epoch 28 | self._index_in_epoch += batch_size 29 | # Another epoch finish 30 | if self._index_in_epoch > self.n_samples: 31 | if self._train: 32 | # Training stage need repeating get batch 33 | self._epochs_complete += 1 34 | # Shuffle the data 35 | np.random.shuffle(self._perm) 36 | # Start next epoch 37 | start = 0 38 | self._index_in_epoch = batch_size 39 | else: 40 | # Validation stage only process once 41 | start = self.n_samples - batch_size 42 | self._index_in_epoch = self.n_samples 43 | end = self._index_in_epoch 44 | 45 | data, label = self._dataset.data(self._perm[start:end]) 46 | return (data, label, self.codes[self._perm[start: end], :]) 47 | 48 | def next_batch_output_codes(self, batch_size): 49 | start = self._index_in_epoch 50 | self._index_in_epoch += batch_size 51 | # Another epoch finish 52 | if self._index_in_epoch > self.n_samples: 53 | if self._train: 54 | # Shuffle the data 55 | np.random.shuffle(self._perm) 56 | # Start next epoch 57 | start = 0 58 | self._index_in_epoch = batch_size 59 | else: 60 | # Validation stage only process once 61 | start = self.n_samples - batch_size 62 | self._index_in_epoch = self.n_samples 63 | end = self._index_in_epoch 64 | 65 | return (self.output[self._perm[start: end], :], 66 | self.codes[self._perm[start: end], :]) 67 | 68 | def feed_batch_output(self, batch_size, output): 69 | start = self._index_in_epoch - batch_size 70 | end = self._index_in_epoch 71 | self.output[self._perm[start:end], :] = output 72 | return 73 | 74 | def feed_batch_codes(self, batch_size, codes): 75 | """ 76 | Args: 77 | batch_size 78 | [batch_size, n_output] 79 | """ 80 | start = self._index_in_epoch - batch_size 81 | end = self._index_in_epoch 82 | self.codes[self._perm[start:end], :] = codes 83 | return 84 | 85 | @property 86 | def output(self): 87 | return self._output 88 | 89 | @property 90 | def codes(self): 91 | return self._codes 92 | 93 | @property 94 | def label(self): 95 | return self._dataset.get_labels() 96 | 97 | def finish_epoch(self): 98 | self._index_in_epoch = 0 99 | np.random.shuffle(self._perm) 100 | 101 | -------------------------------------------------------------------------------- /DeepHash/model/plot.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | import matplotlib 4 | matplotlib.use('Agg') 5 | import matplotlib.pyplot as plt 6 | 7 | import collections 8 | import pickle as pickle 9 | import os 10 | 11 | _since_beginning = collections.defaultdict(lambda: {}) 12 | _since_last_flush = collections.defaultdict(lambda: {}) 13 | 14 | _iter = [0] 15 | def tick(): 16 | _iter[0] += 1 17 | 18 | def plot(name, value): 19 | _since_last_flush[name][_iter[0]] = value 20 | 21 | def flush(path = ""): 22 | prints = [] 23 | 24 | for name, vals in list(_since_last_flush.items()): 25 | prints.append("{}\t{}".format(name, np.mean(list(vals.values())))) 26 | _since_beginning[name].update(vals) 27 | 28 | x_vals = np.sort(list(_since_beginning[name].keys())) 29 | y_vals = [_since_beginning[name][x] for x in x_vals] 30 | 31 | plt.clf() 32 | plt.plot(x_vals, y_vals) 33 | plt.xlabel('iteration') 34 | plt.ylabel(name) 35 | plt.savefig(os.path.join(path, name.replace(' ', '_')+'.jpg')) 36 | 37 | print("iter {}\t{}".format(_iter[0], "\t".join(prints))) 38 | _since_last_flush.clear() 39 | 40 | with open('log.pkl', 'wb') as f: 41 | pickle.dump(dict(_since_beginning), f, pickle.HIGHEST_PROTOCOL) 42 | -------------------------------------------------------------------------------- /DeepHash/util/__init__.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | # return -1 if x < 0, 1 if x > 0, random -1 or 1 if x ==0 4 | def sign(x): 5 | s = np.sign(x) 6 | tmp = s[s == 0] 7 | s[s==0] = np.random.choice([-1, 1], tmp.shape) 8 | return s 9 | 10 | if __name__ == "__main__": 11 | x = np.random.choice([-1, 0, 1], [5, 5]) 12 | print(x) 13 | print((sign(x))) 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 National Engineering Laboratory for Big Data Software 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 | # DeepHash 2 | 3 | DeepHash is a lightweight deep learning to hash library that implements state-of-the-art deep hashing/quantization algorithms. We will implement more representative deep hashing models continuously according to our released [deep hashing paper list](https://github.com/caoyue10/DeepHashingBaselines). Specifically, we welcome other researchers to contribute deep hashing models into this toolkit based on our framework. We will announce the contribution in this project. 4 | 5 | The implemented models include: 6 | 7 | * DQN: [Deep Quantization Network for Efficient Image Retrieval](http://yue-cao.me/doc/deep-quantization-networks-dqn-aaai16.pdf), Yue Cao, Mingsheng Long, Jianmin Wang, Han Zhu, Qingfu Wen, AAAI Conference on Artificial Intelligence (AAAI), 2016 8 | * DHN: [Deep Hashing Network for Efficient Similarity Retrieval](http://ise.thss.tsinghua.edu.cn/~mlong/doc/deep-hashing-network-aaai16.pdf), Han Zhu, Mingsheng Long, Jianmin Wang, Yue Cao, AAAI Conference on Artificial Intelligence (AAAI), 2016 9 | * DVSQ: [Deep Visual-Semantic Quantization for Efficient Image Retrieval](http://yue-cao.me/doc/deep-visual-semantic-quantization-cvpr17.pdf), Yue Cao, Mingsheng Long, Jianmin Wang, Shichen Liu, IEEE Conference on Computer Vision and Pattern Recognition (CVPR), 2017 10 | * DCH: [Deep Cauchy Hashing for Hamming Space Retrieval](http://ise.thss.tsinghua.edu.cn/~mlong/doc/deep-cauchy-hashing-cvpr18.pdf), Yue Cao, Mingsheng Long, Bin Liu, Jianmin Wang, IEEE Conference on Computer Vision and Pattern Recognition (CVPR), 2018 11 | * DTQ: [Deep Triplet Quantization](ise.thss.tsinghua.edu.cn/~mlong/doc/deep-triplet-quantization-acmmm18.pdf), Bin Liu, Yue Cao, Mingsheng Long, Jianmin Wang, Jingdong Wang, ACM Multimedia (ACMMM), 2018 12 | 13 | Note: DTQ and DCH are updated while DQN, DHN, DVSQ maybe outdated, feel free to touch us if you have any questions. We welcome others to contribute! 14 | 15 | ## Requirements 16 | 17 | - Python3: Anaconda is recommended because it already contains a lot of packages: 18 | ``` 19 | conda create -n DeepHash python=3.6 anaconda 20 | source activate DeepHash 21 | ``` 22 | - Other packages: 23 | ``` 24 | conda install -y tensorflow-gpu 25 | conda install -y -c conda-forge opencv 26 | ``` 27 | 28 | To import the pakcages implemented in `./DeepHash`, we need to add the path of `./DeepHash` to environment variables as: 29 | 30 | ```shell 31 | export PYTHONPATH=/path/to/project/DeepHash/DeepHash:$PYTHONPATH 32 | ``` 33 | 34 | ## Data Preparation 35 | In `data/cifar10/train.txt`, we give an example to show how to prepare image training data. In `data/cifar10/test.txt` and `data/cifar10/database.txt`, the list of testing and database images could be processed during predicting procedure. If you want to add other datasets as the input, you need to prepare `train.txt`, `test.txt` and `database.txt` as CIFAR-10 dataset. 36 | 37 | What's more, We have put the whole cifar10 dataset including the images and data list in the [release page](https://github.com/thulab/DeepHash/releases/download/v0.1/cifar10.zip). You can directly download it and unzip to data/cifar10 folder. 38 | 39 | Make sure the tree of `/path/to/project/data/cifar10` looks like this: 40 | 41 | ``` 42 | . 43 | |-- database.txt 44 | |-- test 45 | |-- test.txt 46 | |-- train 47 | `-- train.txt 48 | ``` 49 | 50 | If you need run on NUSWIDE_81 and COCO, we recommend you to follow https://github.com/thuml/HashNet/tree/master/pytorch#datasets to prepare NUSWIDE_81 and COCO images. 51 | 52 | For *DVSQ* model, you also need the *word vector* of the semantic labels. Here we use word2vec model pretrained on GoogleNews Dataset (e.g. https://github.com/mmihaltz/word2vec-GoogleNews-vectors), to extract the word embeddings for the labels of images, e.g. dog, cat and so on. 53 | 54 | ## Get Started 55 | 56 | ### Pre-trained model 57 | 58 | You should manually download the model file of the Imagenet pre-tained AlexNet from [here](https://github.com/thulab/DeepHash/releases/download/v0.1/reference_pretrain.npy.zip) or from release page and unzip it to `/path/to/project/DeepHash/architecture/pretrained_model`. 59 | 60 | Make sure the tree of `/path/to/project/DeepHash/architecture` looks like this: 61 | 62 | ``` 63 | ├── __init__.py 64 | ├── pretrained_model 65 |    └── reference_pretrain.npy 66 | ``` 67 | 68 | ### Training and Testing 69 | 70 | The example of `$method` (DCH and DTQ) can be run like: 71 | 72 | ```shell 73 | cd example/$method/ 74 | python train_val_script.py --gpus "0,1" --data-dir $PWD/../../data --"other parameters descirbe in train_val_script.py" 75 | ``` 76 | 77 | For DVSQ, DQN and DHN, please refer to the `train_val.sh` and `train_val_script.py` in the examples folder. 78 | 79 | ## Citations 80 | If you find *DeepHash* is useful for your research, please consider citing the following papers: 81 | 82 | @InProceedings{cite:AAAI16DQN, 83 | Author = {Yue Cao and Mingsheng Long and Jianmin Wang and Han Zhu and Qingfu Wen}, 84 | Publisher = {AAAI}, 85 | Title = {Deep Quantization Network for Efficient Image Retrieval}, 86 | Year = {2016} 87 | } 88 | 89 | @InProceedings{cite:AAAI16DHN, 90 | Author = {Han Zhu and Mingsheng Long and Jianmin Wang and Yue Cao}, 91 | Publisher = {AAAI}, 92 | Title = {Deep Hashing Network for Efficient Similarity Retrieval}, 93 | Year = {2016} 94 | } 95 | 96 | @InProceedings{cite:CVPR17DVSQ, 97 | Title={Deep visual-semantic quantization for efficient image retrieval}, 98 | Author={Cao, Yue and Long, Mingsheng and Wang, Jianmin and Liu, Shichen}, 99 | Booktitle={CVPR}, 100 | Year={2017} 101 | } 102 | 103 | @InProceedings{cite:CVPR18DCH, 104 | Title={Deep Cauchy Hashing for Hamming Space Retrieval}, 105 | Author={Cao, Yue and Long, Mingsheng and Bin, Liu and Wang, Jianmin}, 106 | Booktitle={CVPR}, 107 | Year={2018} 108 | } 109 | 110 | @article{liu2018deep, 111 | title={Deep triplet quantization}, 112 | author={Liu, Bin and Cao, Yue and Long, Mingsheng and Wang, Jianmin and Wang, Jingdong}, 113 | journal={MM, ACM}, 114 | year={2018} 115 | } 116 | 117 | ## Contacts 118 | Maintainers of this library: 119 | * Yue Cao, Email: caoyue10@gmail.com 120 | * Bin Liu, Email: liubinthss@gmail.com 121 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thulab/DeepHash/9907613e1b73818985bc585af613a960c8df7d20/__init__.py -------------------------------------------------------------------------------- /data/cifar10/test.txt: -------------------------------------------------------------------------------- 1 | train/3_3148.jpg 2 | train/0_4823.jpg 3 | train/2_4819.jpg 4 | train/1_596.jpg 5 | train/4_8747.jpg 6 | train/2_1467.jpg 7 | train/0_871.jpg 8 | train/0_23.jpg 9 | train/3_1837.jpg 10 | train/0_8009.jpg 11 | train/3_6907.jpg 12 | test/999_279.jpg 13 | train/3_1755.jpg 14 | train/2_1964.jpg 15 | train/2_2091.jpg 16 | train/3_7214.jpg 17 | test/999_3344.jpg 18 | train/2_5071.jpg 19 | train/3_4653.jpg 20 | train/2_6744.jpg 21 | test/999_4939.jpg 22 | train/2_9071.jpg 23 | test/999_2527.jpg 24 | train/4_2788.jpg 25 | train/2_5959.jpg 26 | train/1_4544.jpg 27 | train/0_4165.jpg 28 | train/0_8148.jpg 29 | train/2_7629.jpg 30 | train/4_7718.jpg 31 | train/4_5941.jpg 32 | train/4_344.jpg 33 | test/999_9688.jpg 34 | train/1_2257.jpg 35 | train/0_3051.jpg 36 | train/1_2679.jpg 37 | train/4_8499.jpg 38 | train/2_3278.jpg 39 | train/2_1293.jpg 40 | train/2_70.jpg 41 | test/999_1771.jpg 42 | train/1_7634.jpg 43 | train/0_6098.jpg 44 | train/4_6745.jpg 45 | train/0_6453.jpg 46 | train/0_5753.jpg 47 | test/999_762.jpg 48 | train/2_8968.jpg 49 | test/999_4489.jpg 50 | train/0_9389.jpg 51 | train/1_5947.jpg 52 | train/2_2677.jpg 53 | train/0_5235.jpg 54 | train/4_9742.jpg 55 | train/1_9871.jpg 56 | train/0_5618.jpg 57 | train/3_278.jpg 58 | train/2_180.jpg 59 | train/1_6785.jpg 60 | train/4_2727.jpg 61 | train/0_1016.jpg 62 | train/2_1940.jpg 63 | train/2_135.jpg 64 | test/999_2602.jpg 65 | train/2_1059.jpg 66 | train/3_5725.jpg 67 | test/999_9851.jpg 68 | train/4_7591.jpg 69 | train/2_3256.jpg 70 | train/1_1609.jpg 71 | test/999_7776.jpg 72 | train/4_1722.jpg 73 | train/3_7262.jpg 74 | test/999_8605.jpg 75 | train/0_565.jpg 76 | train/1_7486.jpg 77 | train/4_9951.jpg 78 | train/3_1458.jpg 79 | test/999_672.jpg 80 | test/999_545.jpg 81 | train/3_2461.jpg 82 | train/2_7984.jpg 83 | test/999_6730.jpg 84 | train/0_4598.jpg 85 | train/3_6020.jpg 86 | train/2_4279.jpg 87 | train/3_6962.jpg 88 | train/2_5799.jpg 89 | train/3_6794.jpg 90 | test/999_6061.jpg 91 | train/4_8984.jpg 92 | test/999_7997.jpg 93 | test/999_9961.jpg 94 | train/2_2654.jpg 95 | train/4_1354.jpg 96 | train/4_2067.jpg 97 | train/0_1778.jpg 98 | train/2_5779.jpg 99 | train/2_225.jpg 100 | train/3_2050.jpg 101 | test/999_1539.jpg 102 | train/0_1096.jpg 103 | train/0_872.jpg 104 | train/3_9618.jpg 105 | train/2_1794.jpg 106 | train/4_9016.jpg 107 | test/999_3766.jpg 108 | train/2_2127.jpg 109 | train/1_183.jpg 110 | train/4_670.jpg 111 | train/1_8576.jpg 112 | train/4_2289.jpg 113 | train/2_183.jpg 114 | train/4_7945.jpg 115 | train/0_490.jpg 116 | train/2_5769.jpg 117 | train/3_9254.jpg 118 | train/0_1751.jpg 119 | train/4_482.jpg 120 | train/2_8809.jpg 121 | train/1_9509.jpg 122 | train/1_3613.jpg 123 | train/2_6498.jpg 124 | train/0_8024.jpg 125 | train/4_3386.jpg 126 | train/2_8066.jpg 127 | train/2_1876.jpg 128 | test/999_5382.jpg 129 | train/2_4848.jpg 130 | test/999_3938.jpg 131 | train/4_2448.jpg 132 | test/999_8080.jpg 133 | train/1_7424.jpg 134 | train/3_2400.jpg 135 | train/2_2955.jpg 136 | train/4_5785.jpg 137 | train/2_9078.jpg 138 | train/2_8321.jpg 139 | train/1_4554.jpg 140 | train/2_7715.jpg 141 | test/999_6491.jpg 142 | train/2_1244.jpg 143 | train/1_8940.jpg 144 | train/2_6464.jpg 145 | test/999_9352.jpg 146 | test/999_175.jpg 147 | train/1_6411.jpg 148 | test/999_2521.jpg 149 | train/1_3490.jpg 150 | train/4_1396.jpg 151 | test/999_1670.jpg 152 | train/2_131.jpg 153 | train/4_9683.jpg 154 | train/2_1719.jpg 155 | test/999_1581.jpg 156 | train/0_1197.jpg 157 | train/4_1110.jpg 158 | train/1_856.jpg 159 | train/2_410.jpg 160 | train/3_837.jpg 161 | train/1_6886.jpg 162 | train/3_5114.jpg 163 | train/0_8667.jpg 164 | train/0_6952.jpg 165 | test/999_6978.jpg 166 | train/0_1950.jpg 167 | train/4_9251.jpg 168 | train/3_9546.jpg 169 | train/4_8915.jpg 170 | train/1_8534.jpg 171 | test/999_5312.jpg 172 | train/0_3211.jpg 173 | train/3_2356.jpg 174 | train/2_5313.jpg 175 | train/1_3210.jpg 176 | train/0_1525.jpg 177 | train/4_1770.jpg 178 | train/0_7754.jpg 179 | train/0_1450.jpg 180 | train/4_9784.jpg 181 | test/999_6550.jpg 182 | train/0_5215.jpg 183 | test/999_6324.jpg 184 | train/1_2111.jpg 185 | train/1_9533.jpg 186 | train/3_5968.jpg 187 | train/4_3161.jpg 188 | train/4_7720.jpg 189 | train/1_526.jpg 190 | train/0_463.jpg 191 | train/0_7555.jpg 192 | test/999_1089.jpg 193 | train/0_5689.jpg 194 | train/2_4672.jpg 195 | train/3_5254.jpg 196 | train/3_9717.jpg 197 | train/0_2171.jpg 198 | train/1_7873.jpg 199 | train/0_6062.jpg 200 | train/1_5228.jpg 201 | train/3_9002.jpg 202 | train/2_3785.jpg 203 | train/4_1927.jpg 204 | train/4_1174.jpg 205 | train/1_7602.jpg 206 | train/4_6828.jpg 207 | train/4_1505.jpg 208 | train/3_8991.jpg 209 | train/4_1441.jpg 210 | test/999_3866.jpg 211 | train/2_5913.jpg 212 | train/1_3981.jpg 213 | train/0_5499.jpg 214 | train/2_7097.jpg 215 | train/4_5739.jpg 216 | train/1_6252.jpg 217 | train/1_3027.jpg 218 | train/2_8891.jpg 219 | test/999_3364.jpg 220 | train/0_9034.jpg 221 | train/1_8526.jpg 222 | test/999_330.jpg 223 | train/1_9975.jpg 224 | test/999_5349.jpg 225 | train/3_624.jpg 226 | train/0_9594.jpg 227 | test/999_1750.jpg 228 | train/3_8057.jpg 229 | train/0_7605.jpg 230 | train/2_108.jpg 231 | train/2_9446.jpg 232 | test/999_7518.jpg 233 | test/999_8323.jpg 234 | train/2_1606.jpg 235 | test/999_4525.jpg 236 | train/0_7542.jpg 237 | train/4_4241.jpg 238 | train/0_3225.jpg 239 | train/1_2825.jpg 240 | train/2_2944.jpg 241 | train/4_9367.jpg 242 | test/999_4062.jpg 243 | train/1_2155.jpg 244 | train/3_2527.jpg 245 | train/4_8729.jpg 246 | train/1_6030.jpg 247 | train/2_3889.jpg 248 | train/0_2677.jpg 249 | train/4_1765.jpg 250 | train/4_9996.jpg 251 | train/2_4913.jpg 252 | train/2_1983.jpg 253 | train/0_4414.jpg 254 | train/4_6047.jpg 255 | test/999_439.jpg 256 | test/999_921.jpg 257 | test/999_1490.jpg 258 | train/2_7710.jpg 259 | test/999_925.jpg 260 | train/4_3130.jpg 261 | train/1_1838.jpg 262 | train/0_8190.jpg 263 | train/3_9169.jpg 264 | train/4_5666.jpg 265 | test/999_3063.jpg 266 | test/999_8007.jpg 267 | train/4_6851.jpg 268 | train/3_1144.jpg 269 | train/3_9494.jpg 270 | train/4_9010.jpg 271 | train/0_5695.jpg 272 | train/4_5125.jpg 273 | train/3_8652.jpg 274 | train/4_3662.jpg 275 | train/1_5540.jpg 276 | train/4_6705.jpg 277 | test/999_2809.jpg 278 | train/4_5858.jpg 279 | train/0_7091.jpg 280 | train/0_7076.jpg 281 | train/4_7211.jpg 282 | train/2_3835.jpg 283 | train/4_9914.jpg 284 | test/999_1577.jpg 285 | test/999_7931.jpg 286 | train/2_1529.jpg 287 | test/999_6709.jpg 288 | test/999_2526.jpg 289 | test/999_5734.jpg 290 | train/2_3237.jpg 291 | train/2_2999.jpg 292 | train/3_2724.jpg 293 | train/2_1350.jpg 294 | train/0_3596.jpg 295 | train/2_385.jpg 296 | test/999_6355.jpg 297 | train/0_3931.jpg 298 | train/3_6918.jpg 299 | train/1_7281.jpg 300 | train/2_1044.jpg 301 | test/999_4936.jpg 302 | train/4_4992.jpg 303 | train/0_8013.jpg 304 | train/1_8945.jpg 305 | test/999_1994.jpg 306 | train/2_3141.jpg 307 | train/0_2458.jpg 308 | test/999_1350.jpg 309 | train/3_773.jpg 310 | test/999_2732.jpg 311 | train/2_2906.jpg 312 | train/0_9978.jpg 313 | test/999_6420.jpg 314 | test/999_780.jpg 315 | test/999_6779.jpg 316 | train/4_6491.jpg 317 | train/2_6960.jpg 318 | test/999_7210.jpg 319 | test/999_6983.jpg 320 | train/2_7395.jpg 321 | test/999_4434.jpg 322 | train/2_1946.jpg 323 | train/1_648.jpg 324 | test/999_4954.jpg 325 | train/0_3218.jpg 326 | train/4_7450.jpg 327 | test/999_6496.jpg 328 | train/2_8224.jpg 329 | train/1_5726.jpg 330 | train/1_4699.jpg 331 | test/999_4409.jpg 332 | train/2_727.jpg 333 | train/4_4851.jpg 334 | train/4_1805.jpg 335 | train/0_7198.jpg 336 | train/2_45.jpg 337 | train/1_3205.jpg 338 | train/1_3491.jpg 339 | test/999_9451.jpg 340 | test/999_5629.jpg 341 | test/999_9967.jpg 342 | train/3_9331.jpg 343 | train/2_6401.jpg 344 | train/2_1281.jpg 345 | train/3_1046.jpg 346 | train/1_3287.jpg 347 | test/999_9428.jpg 348 | train/2_638.jpg 349 | test/999_1544.jpg 350 | train/1_3899.jpg 351 | train/4_2600.jpg 352 | train/2_2599.jpg 353 | train/0_2349.jpg 354 | train/1_104.jpg 355 | train/4_864.jpg 356 | train/4_6299.jpg 357 | train/0_1607.jpg 358 | test/999_5706.jpg 359 | train/3_3237.jpg 360 | train/1_2520.jpg 361 | train/4_5155.jpg 362 | train/4_6086.jpg 363 | train/4_7197.jpg 364 | train/1_3675.jpg 365 | train/2_9250.jpg 366 | train/4_887.jpg 367 | test/999_4688.jpg 368 | test/999_235.jpg 369 | train/0_3772.jpg 370 | train/1_663.jpg 371 | train/2_5927.jpg 372 | train/2_3969.jpg 373 | train/3_4999.jpg 374 | train/1_5484.jpg 375 | train/1_4380.jpg 376 | train/0_1721.jpg 377 | test/999_5929.jpg 378 | train/3_5581.jpg 379 | train/1_4945.jpg 380 | train/2_8807.jpg 381 | train/3_8544.jpg 382 | train/0_8146.jpg 383 | train/4_2566.jpg 384 | train/4_2429.jpg 385 | train/1_2275.jpg 386 | test/999_421.jpg 387 | train/1_5610.jpg 388 | train/2_3171.jpg 389 | test/999_4326.jpg 390 | train/3_5307.jpg 391 | train/4_6635.jpg 392 | train/4_4098.jpg 393 | train/4_4032.jpg 394 | train/0_7622.jpg 395 | train/0_8157.jpg 396 | train/2_6947.jpg 397 | train/2_9701.jpg 398 | test/999_4347.jpg 399 | test/999_1324.jpg 400 | train/3_2135.jpg 401 | train/1_2014.jpg 402 | test/999_1046.jpg 403 | train/0_8312.jpg 404 | train/3_7401.jpg 405 | train/1_2877.jpg 406 | train/3_4147.jpg 407 | train/3_5499.jpg 408 | train/1_9972.jpg 409 | train/0_9104.jpg 410 | train/2_7082.jpg 411 | train/3_5087.jpg 412 | train/2_9641.jpg 413 | train/4_5349.jpg 414 | test/999_7433.jpg 415 | train/0_1805.jpg 416 | train/0_2769.jpg 417 | train/1_1821.jpg 418 | train/3_7564.jpg 419 | train/3_5246.jpg 420 | train/0_8507.jpg 421 | test/999_9436.jpg 422 | train/2_4621.jpg 423 | train/2_6260.jpg 424 | test/999_9578.jpg 425 | train/3_1748.jpg 426 | train/3_6252.jpg 427 | train/2_7851.jpg 428 | test/999_2462.jpg 429 | train/1_2071.jpg 430 | test/999_8706.jpg 431 | train/1_2691.jpg 432 | train/3_7604.jpg 433 | train/1_3240.jpg 434 | train/0_1237.jpg 435 | train/2_9654.jpg 436 | test/999_9132.jpg 437 | train/1_9929.jpg 438 | train/2_8042.jpg 439 | train/0_1161.jpg 440 | test/999_1576.jpg 441 | train/3_7096.jpg 442 | train/1_1860.jpg 443 | train/1_2119.jpg 444 | train/1_5925.jpg 445 | test/999_3505.jpg 446 | train/3_8923.jpg 447 | train/4_7968.jpg 448 | train/4_7225.jpg 449 | train/1_7282.jpg 450 | train/3_4981.jpg 451 | train/4_7256.jpg 452 | test/999_1195.jpg 453 | train/0_109.jpg 454 | test/999_6973.jpg 455 | train/3_7654.jpg 456 | train/0_1905.jpg 457 | test/999_6336.jpg 458 | train/3_4040.jpg 459 | train/0_5782.jpg 460 | train/1_8566.jpg 461 | test/999_8133.jpg 462 | test/999_9393.jpg 463 | train/3_9258.jpg 464 | test/999_4750.jpg 465 | train/3_123.jpg 466 | train/0_1628.jpg 467 | train/0_4552.jpg 468 | train/3_1383.jpg 469 | train/2_2404.jpg 470 | train/4_7342.jpg 471 | test/999_2396.jpg 472 | train/3_8117.jpg 473 | train/2_446.jpg 474 | train/4_3393.jpg 475 | train/2_5230.jpg 476 | train/1_2827.jpg 477 | train/1_8921.jpg 478 | train/3_8819.jpg 479 | train/4_2994.jpg 480 | train/4_7127.jpg 481 | train/4_8495.jpg 482 | train/1_4360.jpg 483 | train/0_5587.jpg 484 | train/0_5193.jpg 485 | train/4_8845.jpg 486 | train/4_4403.jpg 487 | train/2_4100.jpg 488 | train/4_4949.jpg 489 | test/999_2725.jpg 490 | train/3_9496.jpg 491 | train/4_6735.jpg 492 | train/1_6637.jpg 493 | test/999_6310.jpg 494 | train/0_6738.jpg 495 | train/4_9207.jpg 496 | test/999_1562.jpg 497 | train/3_7072.jpg 498 | train/1_9418.jpg 499 | train/3_2818.jpg 500 | train/3_1519.jpg 501 | train/2_7306.jpg 502 | train/4_3110.jpg 503 | train/2_286.jpg 504 | train/2_8749.jpg 505 | train/1_6859.jpg 506 | train/3_2037.jpg 507 | train/2_4065.jpg 508 | train/4_3820.jpg 509 | train/3_4774.jpg 510 | train/1_657.jpg 511 | train/0_1966.jpg 512 | train/2_3035.jpg 513 | train/2_8885.jpg 514 | train/2_3338.jpg 515 | train/3_2667.jpg 516 | train/4_3315.jpg 517 | train/2_7904.jpg 518 | train/4_7066.jpg 519 | train/3_1301.jpg 520 | train/1_8968.jpg 521 | train/3_7545.jpg 522 | train/3_9283.jpg 523 | test/999_2093.jpg 524 | train/4_1672.jpg 525 | test/999_3223.jpg 526 | train/3_3931.jpg 527 | train/4_9058.jpg 528 | train/3_6740.jpg 529 | train/4_8035.jpg 530 | train/4_2983.jpg 531 | test/999_7488.jpg 532 | test/999_7439.jpg 533 | train/2_7372.jpg 534 | train/2_9632.jpg 535 | train/3_6427.jpg 536 | train/4_150.jpg 537 | train/4_5134.jpg 538 | train/3_6867.jpg 539 | train/1_4175.jpg 540 | train/3_7012.jpg 541 | train/0_5785.jpg 542 | train/4_6286.jpg 543 | train/1_3540.jpg 544 | train/2_6405.jpg 545 | train/0_4726.jpg 546 | train/1_6332.jpg 547 | train/0_3271.jpg 548 | train/0_6029.jpg 549 | train/4_8853.jpg 550 | train/2_8727.jpg 551 | train/1_2898.jpg 552 | test/999_9078.jpg 553 | train/0_6350.jpg 554 | test/999_1482.jpg 555 | train/4_5844.jpg 556 | train/2_8206.jpg 557 | train/3_3530.jpg 558 | train/1_7648.jpg 559 | test/999_8302.jpg 560 | test/999_8984.jpg 561 | train/2_9642.jpg 562 | train/3_6611.jpg 563 | train/1_7429.jpg 564 | test/999_6833.jpg 565 | test/999_2304.jpg 566 | train/3_4792.jpg 567 | train/1_7864.jpg 568 | train/4_9913.jpg 569 | train/0_9367.jpg 570 | test/999_4530.jpg 571 | train/3_1478.jpg 572 | train/3_2382.jpg 573 | train/3_3684.jpg 574 | train/0_4489.jpg 575 | train/4_658.jpg 576 | train/1_6316.jpg 577 | train/4_9093.jpg 578 | train/1_8659.jpg 579 | train/4_9541.jpg 580 | test/999_2420.jpg 581 | train/4_433.jpg 582 | test/999_4051.jpg 583 | test/999_7783.jpg 584 | train/1_4584.jpg 585 | train/3_4590.jpg 586 | train/3_1476.jpg 587 | train/0_4025.jpg 588 | test/999_4443.jpg 589 | train/0_5645.jpg 590 | train/3_1231.jpg 591 | test/999_5513.jpg 592 | train/4_7416.jpg 593 | test/999_2078.jpg 594 | train/1_1349.jpg 595 | train/4_2074.jpg 596 | train/2_675.jpg 597 | train/1_4018.jpg 598 | train/4_8814.jpg 599 | test/999_2356.jpg 600 | train/3_650.jpg 601 | train/2_1245.jpg 602 | train/3_3752.jpg 603 | train/1_1232.jpg 604 | train/1_3688.jpg 605 | train/4_7630.jpg 606 | train/3_1218.jpg 607 | train/1_5683.jpg 608 | train/2_3154.jpg 609 | train/3_4410.jpg 610 | train/3_3400.jpg 611 | train/2_6854.jpg 612 | train/1_5788.jpg 613 | train/2_9309.jpg 614 | test/999_7885.jpg 615 | train/0_4497.jpg 616 | train/0_4818.jpg 617 | train/4_6365.jpg 618 | train/1_1872.jpg 619 | test/999_599.jpg 620 | train/1_5480.jpg 621 | train/3_9850.jpg 622 | train/2_2871.jpg 623 | train/4_3827.jpg 624 | test/999_7351.jpg 625 | train/3_3590.jpg 626 | train/3_6785.jpg 627 | train/0_2888.jpg 628 | train/3_9971.jpg 629 | train/4_3884.jpg 630 | train/1_3549.jpg 631 | test/999_8115.jpg 632 | train/0_3094.jpg 633 | train/4_8899.jpg 634 | train/4_893.jpg 635 | test/999_3165.jpg 636 | train/1_7442.jpg 637 | train/2_7449.jpg 638 | test/999_302.jpg 639 | test/999_5190.jpg 640 | train/3_9247.jpg 641 | train/0_184.jpg 642 | test/999_9269.jpg 643 | train/3_6133.jpg 644 | train/3_4010.jpg 645 | test/999_2079.jpg 646 | train/3_8780.jpg 647 | train/3_5082.jpg 648 | train/4_9584.jpg 649 | train/0_3560.jpg 650 | train/2_2106.jpg 651 | test/999_4640.jpg 652 | train/2_5047.jpg 653 | train/1_4040.jpg 654 | train/2_2330.jpg 655 | train/3_4751.jpg 656 | train/2_6269.jpg 657 | train/3_3934.jpg 658 | train/0_4488.jpg 659 | test/999_3309.jpg 660 | test/999_7910.jpg 661 | train/1_48.jpg 662 | train/4_2939.jpg 663 | test/999_4812.jpg 664 | train/3_322.jpg 665 | train/0_9390.jpg 666 | train/2_2049.jpg 667 | train/4_1292.jpg 668 | train/1_5980.jpg 669 | train/4_4292.jpg 670 | train/3_4640.jpg 671 | train/3_1785.jpg 672 | train/4_3817.jpg 673 | train/2_133.jpg 674 | train/3_3001.jpg 675 | train/2_1418.jpg 676 | train/3_6182.jpg 677 | train/2_2304.jpg 678 | train/0_3933.jpg 679 | train/2_4285.jpg 680 | train/0_6912.jpg 681 | test/999_8498.jpg 682 | test/999_188.jpg 683 | train/3_1900.jpg 684 | train/4_2222.jpg 685 | train/1_3213.jpg 686 | train/0_3872.jpg 687 | train/2_5030.jpg 688 | train/0_9086.jpg 689 | train/1_5666.jpg 690 | train/4_2947.jpg 691 | train/1_2997.jpg 692 | train/4_9679.jpg 693 | train/3_207.jpg 694 | train/0_164.jpg 695 | train/1_9088.jpg 696 | test/999_1110.jpg 697 | test/999_1311.jpg 698 | train/1_8621.jpg 699 | train/3_9487.jpg 700 | train/0_1249.jpg 701 | train/1_3359.jpg 702 | train/0_2982.jpg 703 | train/3_2549.jpg 704 | train/3_8831.jpg 705 | train/4_5030.jpg 706 | train/1_2073.jpg 707 | train/2_7823.jpg 708 | test/999_9532.jpg 709 | train/3_9784.jpg 710 | train/2_9454.jpg 711 | train/1_1387.jpg 712 | train/1_5903.jpg 713 | train/1_3426.jpg 714 | train/4_8333.jpg 715 | train/0_2955.jpg 716 | train/4_3987.jpg 717 | train/2_3579.jpg 718 | train/3_6702.jpg 719 | train/2_7138.jpg 720 | train/2_793.jpg 721 | train/4_4865.jpg 722 | train/3_4571.jpg 723 | test/999_5553.jpg 724 | test/999_3548.jpg 725 | train/4_9762.jpg 726 | train/3_1024.jpg 727 | test/999_8113.jpg 728 | train/4_4490.jpg 729 | train/1_6670.jpg 730 | train/4_1890.jpg 731 | train/1_7870.jpg 732 | train/0_1653.jpg 733 | train/4_1809.jpg 734 | train/0_7221.jpg 735 | train/2_660.jpg 736 | test/999_4226.jpg 737 | train/0_3454.jpg 738 | train/4_9045.jpg 739 | train/0_5085.jpg 740 | test/999_8018.jpg 741 | train/3_3982.jpg 742 | train/4_6845.jpg 743 | train/1_1933.jpg 744 | test/999_8845.jpg 745 | train/4_7771.jpg 746 | train/1_2428.jpg 747 | train/1_8613.jpg 748 | test/999_1394.jpg 749 | test/999_6624.jpg 750 | train/3_284.jpg 751 | test/999_7505.jpg 752 | train/0_3300.jpg 753 | train/2_2603.jpg 754 | test/999_2144.jpg 755 | train/1_9283.jpg 756 | train/0_5337.jpg 757 | train/1_7568.jpg 758 | train/2_4469.jpg 759 | train/4_1402.jpg 760 | test/999_8409.jpg 761 | train/1_1620.jpg 762 | test/999_7414.jpg 763 | train/4_6350.jpg 764 | train/0_6739.jpg 765 | train/1_5869.jpg 766 | train/2_2749.jpg 767 | train/3_1381.jpg 768 | train/2_74.jpg 769 | train/0_8913.jpg 770 | test/999_4896.jpg 771 | train/3_8654.jpg 772 | train/1_1410.jpg 773 | train/2_9910.jpg 774 | train/4_5276.jpg 775 | train/3_4093.jpg 776 | train/0_2294.jpg 777 | train/4_7504.jpg 778 | train/3_410.jpg 779 | train/3_5310.jpg 780 | train/4_9736.jpg 781 | train/4_7184.jpg 782 | train/2_7242.jpg 783 | train/4_2672.jpg 784 | train/2_1573.jpg 785 | train/0_1176.jpg 786 | train/3_6114.jpg 787 | train/2_8792.jpg 788 | train/1_5039.jpg 789 | train/2_6584.jpg 790 | train/0_2184.jpg 791 | train/4_7001.jpg 792 | train/0_3517.jpg 793 | test/999_455.jpg 794 | test/999_3643.jpg 795 | train/1_8769.jpg 796 | test/999_484.jpg 797 | train/4_6691.jpg 798 | train/3_7733.jpg 799 | train/4_1597.jpg 800 | train/1_3633.jpg 801 | train/4_4145.jpg 802 | train/0_9373.jpg 803 | train/1_5084.jpg 804 | train/1_6550.jpg 805 | train/4_7431.jpg 806 | test/999_2038.jpg 807 | train/2_6100.jpg 808 | train/3_4465.jpg 809 | train/2_1024.jpg 810 | train/1_5565.jpg 811 | train/3_661.jpg 812 | train/4_5084.jpg 813 | train/1_2005.jpg 814 | test/999_5309.jpg 815 | test/999_9320.jpg 816 | train/1_3096.jpg 817 | train/2_6938.jpg 818 | train/4_8360.jpg 819 | train/1_7126.jpg 820 | train/1_2168.jpg 821 | train/4_2390.jpg 822 | train/1_7366.jpg 823 | train/4_7191.jpg 824 | train/1_7899.jpg 825 | train/2_6720.jpg 826 | train/3_6205.jpg 827 | train/2_6887.jpg 828 | train/4_135.jpg 829 | train/0_8524.jpg 830 | train/1_5494.jpg 831 | train/3_9866.jpg 832 | train/3_2445.jpg 833 | train/3_7223.jpg 834 | train/2_8291.jpg 835 | train/1_603.jpg 836 | train/2_7029.jpg 837 | test/999_7575.jpg 838 | train/1_8511.jpg 839 | train/3_612.jpg 840 | train/4_9470.jpg 841 | train/2_3856.jpg 842 | train/4_1540.jpg 843 | train/0_5969.jpg 844 | train/3_6164.jpg 845 | train/2_2053.jpg 846 | train/4_4472.jpg 847 | train/2_30.jpg 848 | train/3_9572.jpg 849 | test/999_4795.jpg 850 | train/1_1459.jpg 851 | train/4_7474.jpg 852 | train/2_4148.jpg 853 | train/3_2310.jpg 854 | train/3_4706.jpg 855 | train/2_9497.jpg 856 | train/4_5447.jpg 857 | train/4_8128.jpg 858 | train/3_5601.jpg 859 | train/2_952.jpg 860 | train/0_464.jpg 861 | train/0_3595.jpg 862 | train/3_338.jpg 863 | train/1_1151.jpg 864 | train/3_7891.jpg 865 | test/999_7797.jpg 866 | train/0_2012.jpg 867 | train/1_2187.jpg 868 | train/0_6375.jpg 869 | train/1_2315.jpg 870 | train/1_3513.jpg 871 | train/1_5872.jpg 872 | train/0_6680.jpg 873 | train/2_5299.jpg 874 | train/0_1724.jpg 875 | train/0_6219.jpg 876 | train/1_9868.jpg 877 | train/3_8573.jpg 878 | train/4_2270.jpg 879 | train/3_6302.jpg 880 | train/3_3481.jpg 881 | test/999_4386.jpg 882 | train/1_9735.jpg 883 | train/0_5158.jpg 884 | train/3_6360.jpg 885 | test/999_4290.jpg 886 | train/3_1397.jpg 887 | train/3_400.jpg 888 | train/1_23.jpg 889 | train/1_6526.jpg 890 | train/3_6795.jpg 891 | test/999_1302.jpg 892 | train/1_7191.jpg 893 | train/3_781.jpg 894 | test/999_6555.jpg 895 | train/0_1080.jpg 896 | train/3_632.jpg 897 | test/999_1753.jpg 898 | train/1_5089.jpg 899 | train/4_6296.jpg 900 | train/0_499.jpg 901 | train/0_1907.jpg 902 | test/999_4363.jpg 903 | test/999_6527.jpg 904 | train/0_2271.jpg 905 | train/3_1212.jpg 906 | train/3_3385.jpg 907 | train/0_7451.jpg 908 | train/4_5020.jpg 909 | train/2_4697.jpg 910 | train/2_2500.jpg 911 | train/2_4219.jpg 912 | train/4_2839.jpg 913 | train/0_5418.jpg 914 | train/3_7592.jpg 915 | train/0_4615.jpg 916 | test/999_3594.jpg 917 | train/1_6215.jpg 918 | train/1_4837.jpg 919 | test/999_5612.jpg 920 | train/4_7876.jpg 921 | test/999_3941.jpg 922 | train/1_2278.jpg 923 | train/3_8549.jpg 924 | train/2_8828.jpg 925 | train/4_811.jpg 926 | train/0_8370.jpg 927 | train/1_4290.jpg 928 | train/0_7144.jpg 929 | train/1_7038.jpg 930 | train/3_2465.jpg 931 | train/4_2592.jpg 932 | train/1_7661.jpg 933 | test/999_7942.jpg 934 | test/999_5072.jpg 935 | train/4_7847.jpg 936 | train/3_9959.jpg 937 | train/2_3269.jpg 938 | train/1_3617.jpg 939 | train/0_5542.jpg 940 | train/3_7250.jpg 941 | train/1_7372.jpg 942 | train/0_7559.jpg 943 | train/3_1389.jpg 944 | train/1_6564.jpg 945 | train/4_7478.jpg 946 | train/0_1046.jpg 947 | test/999_9427.jpg 948 | train/3_7945.jpg 949 | train/1_4421.jpg 950 | train/3_4446.jpg 951 | test/999_8495.jpg 952 | train/3_8477.jpg 953 | train/4_5548.jpg 954 | train/2_924.jpg 955 | train/2_2408.jpg 956 | test/999_1019.jpg 957 | train/3_4683.jpg 958 | train/4_917.jpg 959 | test/999_7460.jpg 960 | train/2_9108.jpg 961 | train/4_6322.jpg 962 | train/3_9006.jpg 963 | train/2_8407.jpg 964 | test/999_1579.jpg 965 | test/999_4125.jpg 966 | train/0_3666.jpg 967 | train/4_8748.jpg 968 | train/0_217.jpg 969 | train/1_9777.jpg 970 | test/999_233.jpg 971 | train/2_8456.jpg 972 | train/1_8684.jpg 973 | train/1_1912.jpg 974 | train/0_9463.jpg 975 | test/999_4328.jpg 976 | train/4_4846.jpg 977 | train/3_613.jpg 978 | train/1_3079.jpg 979 | train/4_1537.jpg 980 | test/999_1710.jpg 981 | test/999_3710.jpg 982 | test/999_2981.jpg 983 | train/1_5334.jpg 984 | train/0_694.jpg 985 | train/1_5784.jpg 986 | train/1_5581.jpg 987 | train/2_7430.jpg 988 | train/1_8962.jpg 989 | train/2_6557.jpg 990 | train/4_555.jpg 991 | train/1_8200.jpg 992 | train/1_9062.jpg 993 | train/4_5994.jpg 994 | train/3_1991.jpg 995 | train/2_8210.jpg 996 | train/2_6397.jpg 997 | train/1_2146.jpg 998 | train/0_3543.jpg 999 | train/3_5794.jpg 1000 | train/1_8751.jpg 1001 | -------------------------------------------------------------------------------- /data/nuswide_81/images: -------------------------------------------------------------------------------- 1 | /home/liubin/data/nuswide_81/images -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thulab/DeepHash/9907613e1b73818985bc585af613a960c8df7d20/examples/__init__.py -------------------------------------------------------------------------------- /examples/dch/train_val_script.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | import warnings 4 | import model.dch as model 5 | import data_provider.image as dataset 6 | 7 | from pprint import pprint 8 | 9 | warnings.filterwarnings("ignore", category=DeprecationWarning) 10 | warnings.filterwarnings("ignore", category=FutureWarning) 11 | 12 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' 13 | 14 | parser = argparse.ArgumentParser(description='Triplet Hashing') 15 | parser.add_argument('--lr', '--learning-rate', default=0.005, type=float) 16 | parser.add_argument('--output-dim', default=64, type=int) # 256, 128 17 | parser.add_argument('--gamma', default=20, type=float) 18 | parser.add_argument('--iter-num', default=2000, type=int) 19 | parser.add_argument('--q-lambda', default=0, type=float) 20 | parser.add_argument('--dataset', default='cifar10', type=str) 21 | parser.add_argument('--gpus', default='0', type=str) 22 | parser.add_argument('--log-dir', default='tflog', type=str) 23 | parser.add_argument('-b', '--batch-size', default=128, type=int) 24 | parser.add_argument('-vb', '--val-batch-size', default=16, type=int) 25 | parser.add_argument('--decay-step', default=10000, type=int) 26 | parser.add_argument('--decay-factor', default=0.1, type=float) 27 | 28 | tanh_parser = parser.add_mutually_exclusive_group(required=False) 29 | tanh_parser.add_argument('--with-tanh', dest='with_tanh', action='store_true') 30 | tanh_parser.add_argument('--without-tanh', dest='with_tanh', action='store_false') 31 | parser.set_defaults(with_tanh=True) 32 | 33 | parser.add_argument('--img-model', default='alexnet', type=str) 34 | parser.add_argument('--model-weights', type=str, 35 | default='../../DeepHash/architecture/pretrained_model/reference_pretrain.npy') 36 | parser.add_argument('--finetune-all', default=True, type=bool) 37 | parser.add_argument('--save-dir', default="./models/", type=str) 38 | parser.add_argument('--data-dir', default="~/data/", type=str) 39 | parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true') 40 | 41 | args = parser.parse_args() 42 | 43 | os.environ['CUDA_VISIBLE_DEVICES'] = args.gpus 44 | 45 | label_dims = {'cifar10': 10, 'cub': 200, 'nuswide_81': 81, 'coco': 80} 46 | Rs = {'cifar10': 54000, 'nuswide_81': 5000, 'coco': 5000} 47 | args.R = Rs[args.dataset] 48 | args.label_dim = label_dims[args.dataset] 49 | 50 | args.img_tr = os.path.join(args.data_dir, args.dataset, "train.txt") 51 | args.img_te = os.path.join(args.data_dir, args.dataset, "test.txt") 52 | args.img_db = os.path.join(args.data_dir, args.dataset, "database.txt") 53 | 54 | pprint(vars(args)) 55 | 56 | data_root = os.path.join(args.data_dir, args.dataset) 57 | query_img, database_img = dataset.import_validation(data_root, args.img_te, args.img_db) 58 | 59 | if not args.evaluate: 60 | train_img = dataset.import_train(data_root, args.img_tr) 61 | model_weights = model.train(train_img, database_img, query_img, args) 62 | args.model_weights = model_weights 63 | 64 | maps = model.validation(database_img, query_img, args) 65 | for key in maps: 66 | print(("{}\t{}".format(key, maps[key]))) 67 | 68 | pprint(vars(args)) 69 | -------------------------------------------------------------------------------- /examples/dhn/train_val.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | lr=0.00005 4 | q_lambda=0.0 5 | alpha=10.0 # 0.2 6 | dataset=cifar10 # imagenet # cifar10, nuswide_81, coco 7 | log_dir=tflog 8 | 9 | if [ -z "$1" ]; then 10 | gpu=0 11 | else 12 | gpu=$1 13 | fi 14 | 15 | export TF_CPP_MIN_LOG_LEVEL=3 16 | # lr output iter q_lamb alpha dataset gpu log_dir 17 | CUDA_VISIBLE_DEVICES=$gpu python train_val_script.py $lr 64 2000 $q_lambda $alpha $dataset 0 $log_dir /dir/to/dataset/root/ 18 | -------------------------------------------------------------------------------- /examples/dhn/train_val_script.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.io as sio 3 | import warnings 4 | import data_provider.image as dataset 5 | import model.dhn.dhn as model 6 | import sys 7 | from pprint import pprint 8 | import os 9 | 10 | warnings.filterwarnings("ignore", category=DeprecationWarning) 11 | warnings.filterwarnings("ignore", category=FutureWarning) 12 | 13 | # Define input arguments 14 | lr = float(sys.argv[1]) 15 | output_dim = int(sys.argv[2]) 16 | iter_num = int(sys.argv[3]) 17 | cq_lambda = float(sys.argv[4]) 18 | alpha = float(sys.argv[5]) 19 | _dataset = sys.argv[6] 20 | gpu = sys.argv[7] 21 | log_dir = sys.argv[8] 22 | data_root = sys.argv[9] 23 | 24 | label_dims = {'cifar10': 10, 'cub': 200, 'nuswide_21': 21, 25 | 'nuswide_81': 81, 'coco': 80, 'imagenet': 100, 'cifar10_zero_shot': 10} 26 | Rs = {'cifar10': 54000, 'nuswide_81': 5000, 'coco': 5000, 27 | 'nuswide_21': 5000, 'imagenet': 5000, 'cifar10_zero_shot': 15000} 28 | 29 | config = { 30 | 'device': '/gpu:' + gpu, 31 | 'max_iter': iter_num, 32 | 'batch_size': 256, # TODO 33 | 'val_batch_size': 100, 34 | 'decay_step': 5000, # TODO # Epochs after which learning rate decays. 35 | 'learning_rate_decay_factor': 0.5, # Learning rate decay factor. 36 | 'learning_rate': lr, # Initial learning rate img. 37 | 38 | 'output_dim': output_dim, 39 | 'alpha': alpha, 40 | 41 | 'R': Rs[_dataset], 42 | 'model_weights': '../../core/architecture/single_model/pretrained_model/reference_pretrain.npy', 43 | 44 | 'img_model': 'alexnet', 45 | 'loss_type': 'normed_cross_entropy', # normed_cross_entropy # TODO 46 | 47 | # if only finetune last layer 48 | 'finetune_all': True, 49 | 50 | # CQ params 51 | 'cq_lambda': cq_lambda, 52 | 53 | 'label_dim': label_dims[_dataset], 54 | 'img_tr': "/home/caoyue/data/{}/train.txt".format(_dataset), 55 | 'img_te': "/home/caoyue/data/{}/test.txt".format(_dataset), 56 | 'img_db': "/home/caoyue/data/{}/database.txt".format(_dataset), 57 | 'save_dir': "./models/", 58 | 'log_dir': log_dir, 59 | 'dataset': _dataset 60 | } 61 | 62 | pprint(config) 63 | 64 | train_img = dataset.import_train(data_root, config['img_tr']) 65 | model_weights = model.train(train_img, config) 66 | 67 | config['model_weights'] = model_weights 68 | query_img, database_img = dataset.import_validation(data_root, config['img_te'], config['img_db']) 69 | maps = model.validation(database_img, query_img, config) 70 | for key in maps: 71 | print(("{}: {}".format(key, maps[key]))) 72 | pprint(config) 73 | -------------------------------------------------------------------------------- /examples/dqn/train_val.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | lr=0.002 4 | q_lambda=0.0001 5 | subspace_num=4 6 | dataset=cifar10 # cifar10, nuswide_81 7 | log_dir=tflog 8 | 9 | if [ -z "$1" ]; then 10 | gpu=0 11 | else 12 | gpu=$1 13 | fi 14 | 15 | filename="lr_${lr}_cqlambda_${q_lambda}_subspace_num_${subspace_num}_T_${T}_K_${K}_graph_laplacian_lambda_${gl_lambda}_gl_loss_${gl_loss}_dataset_${dataset}" 16 | model_file="models/${filename}.npy" 17 | export TF_CPP_MIN_LOG_LEVEL=3 18 | # lr output iter q_lamb n_sub dataset gpu log_dir 19 | CUDA_VISIBLE_DEVICES=$gpu python train_val_script.py $lr 300 5000 $q_lambda 4 $dataset 0 $log_dir /dir/to/dataset/root/ 20 | -------------------------------------------------------------------------------- /examples/dqn/train_val_script.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.io as sio 3 | import warnings 4 | import data_provider.image as dataset 5 | import model.dqn.dqn as model 6 | import sys 7 | from pprint import pprint 8 | import os 9 | 10 | warnings.filterwarnings("ignore", category=DeprecationWarning) 11 | warnings.filterwarnings("ignore", category=FutureWarning) 12 | 13 | # Define input arguments 14 | lr = float(sys.argv[1]) 15 | output_dim = int(sys.argv[2]) 16 | iter_num = int(sys.argv[3]) 17 | cq_lambda = float(sys.argv[4]) 18 | subspace_num = int(sys.argv[5]) 19 | _dataset = sys.argv[6] 20 | gpu = sys.argv[7] 21 | log_dir = sys.argv[8] 22 | data_root = sys.argv[9] 23 | 24 | label_dims = {'cifar10': 10, 'cub': 200, 'nuswide_81': 81} 25 | 26 | config = { 27 | 'device': '/gpu:' + gpu, 28 | 'max_iter': iter_num, 29 | 'batch_size': 256, 30 | 'val_batch_size': 100, 31 | 'decay_step': 500, # Epochs after which learning rate decays. 32 | 'learning_rate_decay_factor': 0.5, # Learning rate decay factor. 33 | 'learning_rate': lr, # Initial learning rate img. 34 | 35 | 'output_dim': output_dim, 36 | 37 | 'R': 5, 38 | 'model_weights': '../../DeepHash/architecture/pretrained_model/reference_pretrain.npy', 39 | 40 | 'img_model': 'alexnet', 41 | 42 | # if only finetune last layer 43 | 'finetune_all': True, 44 | 45 | # CQ params 46 | 'max_iter_update_b': 3, 47 | 'max_iter_update_Cb': 1, 48 | 'cq_lambda': cq_lambda, 49 | 'code_batch_size': 500, 50 | 'n_subspace': subspace_num, 51 | 'n_subcenter': 256, 52 | 53 | 'label_dim': label_dims[_dataset], 54 | 'img_tr': "{}/train.txt".format(data_root), 55 | 'img_te': "{}/test.txt".format(data_root), 56 | 'img_db': "{}/database.txt".format(data_root), 57 | 'save_dir': "./models/", 58 | 'log_dir': log_dir, 59 | 'dataset': _dataset 60 | } 61 | 62 | pprint(config) 63 | 64 | train_img = dataset.import_train(data_root, config['img_tr']) 65 | model_weights = model.train(train_img, config) 66 | 67 | config['model_weights'] = model_weights 68 | query_img, database_img = dataset.import_validation(config['img_te'], config['img_db']) 69 | maps = model.validation(data_root, database_img, query_img, config) 70 | 71 | for key in maps: 72 | print(("{}: {}".format(key, maps[key]))) 73 | pprint(config) 74 | -------------------------------------------------------------------------------- /examples/dtq/train_val_script.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.io as sio 3 | import warnings 4 | import data_provider.image as dataset 5 | import model.dtq as model 6 | from pprint import pprint 7 | import os 8 | import argparse 9 | 10 | warnings.filterwarnings("ignore", category = DeprecationWarning) 11 | warnings.filterwarnings("ignore", category = FutureWarning) 12 | os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' 13 | 14 | parser = argparse.ArgumentParser(description='Triplet Hashing', 15 | formatter_class=argparse.ArgumentDefaultsHelpFormatter) 16 | parser.add_argument('--lr', '--learning-rate', default=0.00003, type=float) 17 | parser.add_argument('--triplet-margin', default=30, type=float) 18 | parser.add_argument('--select-strategy', default='margin', choices=['hard', 'all', 'margin']) 19 | parser.add_argument('--output-dim', default=64, type=int) # 256, 128 20 | parser.add_argument('--epochs', default=100, type=int) 21 | parser.add_argument('--cq-lambda', default=0, type=float) 22 | parser.add_argument('--subspace', default=4, type=int) 23 | parser.add_argument('--subcenter', default=256, type=int) 24 | parser.add_argument('--dataset', default='cifar10', type=str, 25 | choices=['cifar10', 'coco', 'nuswide_81']) 26 | parser.add_argument('--gpus', default='0', type=str) 27 | parser.add_argument('--log-dir', default='tflog', type=str) 28 | parser.add_argument('--dist-type', default='euclidean2', type=str, 29 | choices=['euclidean2', 'cosine', 'inner_product', 'euclidean']) 30 | parser.add_argument('-b', '--batch-size', default=128, type=int) 31 | parser.add_argument('-vb', '--val-batch-size', default=16, type=int) 32 | parser.add_argument('--decay-step', default=10000, type=int) 33 | parser.add_argument('--decay-factor', default=0.1, type=int) 34 | 35 | tanh_parser = parser.add_mutually_exclusive_group(required=False) 36 | tanh_parser.add_argument('--with-tanh', dest='with_tanh', action='store_true') 37 | tanh_parser.add_argument('--without-tanh', dest='with_tanh', action='store_false') 38 | parser.set_defaults(with_tanh=True) 39 | 40 | parser.add_argument('--img-model', default='alexnet', type=str) 41 | parser.add_argument('--model-weights', type=str, 42 | default='../../DeepHash/architecture/pretrained_model/reference_pretrain.npy') 43 | parser.add_argument('--finetune-all', default=True, type=bool) 44 | parser.add_argument('--max-iter-update-b', default=3, type=int) 45 | parser.add_argument('--max-iter-update-Cb', default=1, type=int) 46 | parser.add_argument('--code-batch-size', default=500, type=int) 47 | parser.add_argument('--n-part', default=20, type=int) 48 | parser.add_argument('--triplet-thresold', default=64000, type=int) 49 | parser.add_argument('--save-dir', default="./models/", type=str) 50 | parser.add_argument('--data-dir', default="~/data/", type=str) 51 | parser.add_argument('-e', '--evaluate', dest='evaluate', action='store_true') 52 | parser.add_argument('--val-freq', default=1, type=int) 53 | 54 | args = parser.parse_args() 55 | 56 | os.environ['CUDA_VISIBLE_DEVICES'] = args.gpus 57 | 58 | label_dims = {'cifar10': 10, 'nuswide_81': 81, 'coco': 80} 59 | Rs = {'cifar10': 54000, 'nuswide_81': 5000, 'coco': 5000} 60 | args.R = Rs[args.dataset] 61 | args.label_dim = label_dims[args.dataset] 62 | 63 | args.img_tr = os.path.join(args.data_dir, args.dataset, "train.txt") 64 | args.img_te = os.path.join(args.data_dir, args.dataset, "test.txt") 65 | args.img_db = os.path.join(args.data_dir, args.dataset, "database.txt") 66 | 67 | pprint(vars(args)) 68 | 69 | data_root = os.path.join(args.data_dir, args.dataset) 70 | query_img, database_img = dataset.import_validation(data_root, args.img_te, args.img_db) 71 | 72 | if not args.evaluate: 73 | train_img = dataset.import_train(data_root, args.img_tr) 74 | model_weights = model.train(train_img, database_img, query_img, args) 75 | args.model_weights = model_weights 76 | else: 77 | maps = model.validation(database_img, query_img, args) 78 | for key in maps: 79 | print(("{}\t{}".format(key, maps[key]))) 80 | 81 | pprint(vars(args)) 82 | -------------------------------------------------------------------------------- /examples/dvsq/train_val.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | lr=0.02 4 | q_lambda=0.0001 5 | subspace_num=4 6 | dataset=cifar10 # cifar10, nuswide_81 7 | log_dir=tflog 8 | 9 | if [ -z "$1" ]; then 10 | gpu=0 11 | else 12 | gpu=$1 13 | fi 14 | 15 | filename="lr_${lr}_cqlambda_${q_lambda}_subspace_num_${subspace_num}_T_${T}_K_${K}_graph_laplacian_lambda_${gl_lambda}_gl_loss_${gl_loss}_dataset_${dataset}" 16 | model_file="models/${filename}.npy" 17 | export TF_CPP_MIN_LOG_LEVEL=3 18 | python train_val_script.py $lr 300 5000 $q_lambda 4 $dataset $gpu $log_dir /dir/to/dataset/root/ 19 | -------------------------------------------------------------------------------- /examples/dvsq/train_val_script.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.io as sio 3 | import warnings 4 | import data_provider.image as dataset 5 | import model.dvsq.dvsq as model 6 | import sys 7 | from pprint import pprint 8 | import os 9 | 10 | warnings.filterwarnings("ignore", category=DeprecationWarning) 11 | warnings.filterwarnings("ignore", category=FutureWarning) 12 | 13 | # Define input arguments 14 | lr = float(sys.argv[1]) 15 | output_dim = int(sys.argv[2]) 16 | iter_num = int(sys.argv[3]) 17 | cq_lambda = float(sys.argv[4]) 18 | subspace_num = int(sys.argv[5]) 19 | _dataset = sys.argv[6] 20 | gpu = sys.argv[7] 21 | log_dir = sys.argv[8] 22 | data_root = sys.argv[9] 23 | 24 | label_dims = {'cifar10': 10, 'cub': 200, 'nuswide_81': 81, 'coco': 80} 25 | Rs = {'cifar10': 54000, 'nuswide_81': 5000, 'coco': 5000, 'nuswide_21': 5000, 'imagenet': 5000} 26 | 27 | config = { 28 | 'device': '/gpu:' + gpu, 29 | 'max_iter': iter_num, 30 | 'batch_size': 256, 31 | 'val_batch_size': 100, 32 | 'decay_step': 500, # Epochs after which learning rate decays. 33 | 'learning_rate_decay_factor': 0.5, # Learning rate decay factor. 34 | 'learning_rate': lr, # Initial learning rate img. 35 | 36 | 'output_dim': output_dim, 37 | 38 | 'R': Rs[_dataset], 39 | 'model_weights': '../../DeepHash/architecture/pretrained_model/reference_pretrain.npy', 40 | 41 | 'img_model': 'alexnet', 42 | 'loss_type': 'cos_softmargin_multi_label', 43 | 44 | 'margin_param': 0.7, 45 | 'wordvec_dict': "{}/{}_wordvec.txt".format(data_root, _dataset), 46 | 47 | # if only finetune last layer 48 | 'finetune_all': True, 49 | 50 | # CQ params 51 | 'max_iter_update_b': 3, 52 | 'max_iter_update_Cb': 1, 53 | 'cq_lambda': cq_lambda, 54 | 'code_batch_size': 500, 55 | 'n_subspace': subspace_num, 56 | 'n_subcenter': 256, 57 | 58 | 'label_dim': label_dims[_dataset], 59 | 'img_tr': "{}/train.txt".format(data_root), 60 | 'img_te': "{}/test.txt".format(data_root), 61 | 'img_db': "{}/database.txt".format(data_root), 62 | 'save_dir': "./models/", 63 | 'log_dir': log_dir, 64 | 'dataset': _dataset 65 | } 66 | 67 | pprint(config) 68 | 69 | train_img = dataset.import_train(data_root, config['img_tr']) 70 | model_weights = model.train(train_img, config) 71 | 72 | config['model_weights'] = model_weights 73 | query_img, database_img = dataset.import_validation(data_root, config['img_te'], config['img_db']) 74 | maps = model.validation(database_img, query_img, config) 75 | 76 | for key in maps: 77 | print(("{}\t{}".format(key, maps[key]))) 78 | pprint(config) 79 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | h5py 2 | numpy 3 | opencv-python 4 | Pillow 5 | scikit-learn 6 | scipy 7 | tensorflow 8 | --------------------------------------------------------------------------------