-
Notifications
You must be signed in to change notification settings - Fork 0
/
inference.py
121 lines (94 loc) · 3.79 KB
/
inference.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
from __future__ import print_function
import argparse
from math import log10, ceil
import random, shutil, json
from os.path import join, exists, isfile, realpath, dirname
from os import makedirs, remove, chdir, environ
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.utils.data import DataLoader, SubsetRandomSampler
from torch.utils.data.dataset import Subset
import torchvision.transforms as transforms
from PIL import Image
from datetime import datetime
import torchvision.datasets as datasets
import torchvision.models as models
import h5py
import faiss
from tensorboardX import SummaryWriter
import numpy as np
import netvlad
cuda = torch.cuda.is_available()
device = torch.device("cuda" if cuda else "cpu")
encoder_dim = 512
num_clusters = 64
def test(model, eval_set, epoch=0, write_tboard=False):
# TODO what if features dont fit in memory?
test_data_loader = DataLoader(dataset=eval_set, num_workers=8, batch_size=24,
shuffle=False, pin_memory=cuda)
model.eval()
with torch.no_grad():
print('====> Extracting Features')
pool_size = encoder_dim * num_clusters
dbFeat = np.empty((len(eval_set), pool_size))
for iteration, (input, indices) in enumerate(test_data_loader, 1):
input = input.to(device)
image_encoding = model.encoder(input)
vlad_encoding = model.pool(image_encoding)
dbFeat[indices.detach().numpy(), :] = vlad_encoding.detach().cpu().numpy()
if iteration % 50 == 0 or len(test_data_loader) <= 10:
print("==> Batch ({}/{})".format(iteration,
len(test_data_loader)), flush=True)
del input, image_encoding, vlad_encoding
del test_data_loader
# extracted for both db and query, now split in own sets
# there ara two part when construt the whole dataset
qFeat = dbFeat[eval_set.dbStruct.numDb:].astype('float32')
dbFeat = dbFeat[:eval_set.dbStruct.numDb].astype('float32')
print('====> Building faiss index')
faiss_index = faiss.IndexFlatL2(pool_size)
faiss_index.add(dbFeat)
print('====> Calculating recall @ N')
n_values = [1, 5, 10, 20]
_, predictions = faiss_index.search(qFeat, max(n_values))
# for each query get those within threshold distance
gt = eval_set.getPositives()
correct_at_n = np.zeros(len(n_values))
# TODO can we do this on the matrix in one go?
for qIx, pred in enumerate(predictions):
for i, n in enumerate(n_values):
# if in top N then also in top NN, where NN > N
if np.any(np.in1d(pred[:n], gt[qIx])):
correct_at_n[i:] += 1
break
recall_at_n = correct_at_n / eval_set.dbStruct.numQ
recalls = {} # make dict for output
for i, n in enumerate(n_values):
recalls[n] = recall_at_n[i]
print("====> Recall@{}: {:.4f}".format(n, recall_at_n[i]))
if write_tboard: writer.add_scalar('Val/Recall@' + str(n), recall_at_n[i], epoch)
return recalls
def add_PCA():
pass
def main():
encoder_dim = 512
encoder = models.vgg16(pretrained=False)
# capture only feature part and remove last relu and maxpool
layers = list(encoder.features.children())[:-2]
if pretrained:
# if using pretrained then only train conv5_1, conv5_2, and conv5_3
for l in layers[:-5]:
for p in l.parameters():
p.requires_grad = False
if opt.mode.lower() == 'cluster' and not opt.vladv2:
layers.append(L2Norm())
encoder = nn.Sequential(*layers)
model = nn.Module()
model.add_module('encoder', encoder)
if __name__ == '__main__':
main()