util.py 11.6 KB
Newer Older
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
1
2
3
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
4
# @date: Wed 11 May 2016 09:39:36 CEST
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
5
6
7

import numpy
import tensorflow as tf
8
from tensorflow.python.client import device_lib
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from tensorflow.python.framework import function
import tensorflow.keras.backend as K


def keras_channels_index():
    return -3 if K.image_data_format() == 'channels_first' else -1


@function.Defun(tf.float32, tf.float32)
def norm_grad(x, dy):
    return tf.expand_dims(dy, -1) * (x / (tf.expand_dims(tf.norm(x, ord=2, axis=-1), -1) + 1.0e-19))


@function.Defun(tf.float32, grad_func=norm_grad)
def norm(x):
    return tf.norm(x, ord=2, axis=-1)
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
25

26

Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
27
28
29
30
31
def compute_euclidean_distance(x, y):
    """
    Computes the euclidean distance between two tensorflow variables
    """

32
    with tf.name_scope('euclidean_distance'):
33
34
        # d = tf.sqrt(tf.reduce_sum(tf.square(tf.subtract(x, y)), 1))
        d = norm(tf.subtract(x, y))
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
35
36
        return d

37
38

def load_mnist(perc_train=0.9):
39
    numpy.random.seed(0)
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
40
    import bob.db.mnist
41
    db = bob.db.mnist.Database()
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
42
43
44
45
46
47
    raw_data = db.data()

    # data  = raw_data[0].astype(numpy.float64)
    data = raw_data[0]
    labels = raw_data[1]

48
49
50
51
52
53
    # Shuffling
    total_samples = data.shape[0]
    indexes = numpy.array(range(total_samples))
    numpy.random.shuffle(indexes)

    # Spliting train and validation
54
    n_train = int(perc_train * indexes.shape[0])
55
56
    n_validation = total_samples - n_train

57
    train_data = data[0:n_train, :].astype("float32") * 0.00390625
58
59
    train_labels = labels[0:n_train]

60
61
    validation_data = data[n_train:n_train +
                           n_validation, :].astype("float32") * 0.00390625
62
    validation_labels = labels[n_train:n_train + n_validation]
63
64

    return train_data, train_labels, validation_data, validation_labels
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
65
66


67
68
69
def create_mnist_tfrecord(tfrecords_filename, data, labels, n_samples=6000):
    def _bytes_feature(value):
        return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
70

71
72
    def _int64_feature(value):
        return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
73

74
    writer = tf.python_io.TFRecordWriter(tfrecords_filename)
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
75

76
77
78
    for i in range(n_samples):
        img = data[i]
        img_raw = img.tostring()
79
80
81
82
83
        feature = {
            'data': _bytes_feature(img_raw),
            'label': _int64_feature(labels[i]),
            'key': _bytes_feature(b'-')
        }
84

85
86
87
        example = tf.train.Example(features=tf.train.Features(feature=feature))
        writer.write(example.SerializeToString())
    writer.close()
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
88
89


90
91
def compute_eer(data_train, labels_train, data_validation, labels_validation,
                n_classes):
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
    import bob.measure
    from scipy.spatial.distance import cosine

    # Creating client models
    models = []
    for i in range(n_classes):
        indexes = labels_train == i
        models.append(numpy.mean(data_train[indexes, :], axis=0))

    # Probing
    positive_scores = numpy.zeros(shape=0)
    negative_scores = numpy.zeros(shape=0)

    for i in range(n_classes):
        # Positive scoring
        indexes = labels_validation == i
        positive_data = data_validation[indexes, :]
109
110
111
112
        p = [
            cosine(models[i], positive_data[j])
            for j in range(positive_data.shape[0])
        ]
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
113
114
115
116
117
        positive_scores = numpy.hstack((positive_scores, p))

        # negative scoring
        indexes = labels_validation != i
        negative_data = data_validation[indexes, :]
118
119
120
121
        n = [
            cosine(models[i], negative_data[j])
            for j in range(negative_data.shape[0])
        ]
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
122
123
124
125
126
127
128
129
130
131
132
133
134
        negative_scores = numpy.hstack((negative_scores, n))

    # Computing performance based on EER
    negative_scores = (-1) * negative_scores
    positive_scores = (-1) * positive_scores

    threshold = bob.measure.eer_threshold(negative_scores, positive_scores)
    far, frr = bob.measure.farfrr(negative_scores, positive_scores, threshold)
    eer = (far + frr) / 2.

    return eer


135
136
def compute_accuracy(data_train, labels_train, data_validation,
                     labels_validation, n_classes):
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
137
138
139
140
141
142
143
144
145
146
147
148
    from scipy.spatial.distance import cosine

    # Creating client models
    models = []
    for i in range(n_classes):
        indexes = labels_train == i
        models.append(numpy.mean(data_train[indexes, :], axis=0))

    # Probing
    tp = 0
    for i in range(data_validation.shape[0]):

149
        d = data_validation[i, :]
Tiago de Freitas Pereira's avatar
Scratch  
Tiago de Freitas Pereira committed
150
151
152
153
154
155
156
157
158
        l = labels_validation[i]

        scores = [cosine(m, d) for m in models]
        predict = numpy.argmax(scores)

        if predict == l:
            tp += 1

    return (float(tp) / data_validation.shape[0]) * 100
159
160


Tiago de Freitas Pereira's avatar
Tiago de Freitas Pereira committed
161
162
163
164
165
def debug_embbeding(image, architecture, embbeding_dim=2, feature_layer="fc3"):
    """
    """
    import tensorflow as tf
    from bob.learn.tensorflow.utils.session import Session
166
167
168

    session = Session.instance(new=False).session
    inference_graph = architecture.compute_graph(
169
170
        architecture.inference_placeholder,
        feature_layer=feature_layer,
171
        training=False)
Tiago de Freitas Pereira's avatar
Tiago de Freitas Pereira committed
172
173
174

    embeddings = numpy.zeros(shape=(image.shape[0], embbeding_dim))
    for i in range(image.shape[0]):
175
        feed_dict = {
176
177
            architecture.inference_placeholder: image[i:i + 1, :, :, :]
        }
178
179
180
        embedding = session.run(
            [tf.nn.l2_normalize(inference_graph, 1, 1e-10)],
            feed_dict=feed_dict)[0]
Tiago de Freitas Pereira's avatar
Tiago de Freitas Pereira committed
181
182
183
184
        embedding = numpy.reshape(embedding, numpy.prod(embedding.shape[1:]))
        embeddings[i] = embedding

    return embeddings
185
186


187
def pdist(A):
188
189
    """
    Compute a pairwise euclidean distance in the same fashion
190
    as in scipy.spation.distance.pdist
191
    """
192
    with tf.variable_scope('Pairwisedistance'):
193
194
        ones_1 = tf.reshape(
            tf.cast(tf.ones_like(A), tf.float32)[:, 0], [1, -1])
195
        p1 = tf.matmul(
196
            tf.expand_dims(tf.reduce_sum(tf.square(A), 1), 1), ones_1)
197

198
199
        ones_2 = tf.reshape(
            tf.cast(tf.ones_like(A), tf.float32)[:, 0], [-1, 1])
200
201
202
203
204
        p2 = tf.transpose(
            tf.matmul(
                tf.reshape(tf.reduce_sum(tf.square(A), 1), shape=[-1, 1]),
                ones_2,
                transpose_b=True))
205
206
207
208

        return tf.sqrt(tf.add(p1, p2) - 2 * tf.matmul(A, A, transpose_b=True))


209
def predict_using_tensors(embedding, labels, num=None):
210
    """
211
212
    Compute the predictions through exhaustive comparisons between
    embeddings using tensors
213
214
    """

215
216
    # Fitting the main diagonal with infs (removing comparisons with the same
    # sample)
217
    inf = tf.cast(tf.ones_like(labels), tf.float32) * numpy.inf
218

219
    distances = pdist(embedding)
220
221
    distances = tf.matrix_set_diag(distances, inf)
    indexes = tf.argmin(distances, axis=1)
222
223
224
225
226
    return [labels[i] for i in tf.unstack(indexes, num=num)]


def compute_embedding_accuracy_tensors(embedding, labels, num=None):
    """
227
    Compute the accuracy in a closed-set
228

229
230
231
232
233
234
235
    **Parameters**

    embeddings: `tf.Tensor`
      Set of embeddings

    labels: `tf.Tensor`
      Correspondent labels
236
237
    """

238
239
    # Fitting the main diagonal with infs (removing comparisons with the same
    # sample)
240
    predictions = predict_using_tensors(embedding, labels, num=num)
241
    matching = [
242
        tf.equal(p, l) for p, l in zip(
243
244
            tf.unstack(predictions, num=num), tf.unstack(labels, num=num))
    ]
245

246
    return tf.reduce_sum(tf.cast(matching, tf.uint8)) / len(predictions)
247
248


249
250
def compute_embedding_accuracy(embedding, labels):
    """
251
    Compute the accuracy in a closed-set
252

253
254
255
256
257
258
259
    **Parameters**

    embeddings: :any:`numpy.array`
      Set of embeddings

    labels: :any:`numpy.array`
      Correspondent labels
260
261
    """

262
    from scipy.spatial.distance import pdist, squareform
263

264
    distances = squareform(pdist(embedding))
265

266
267
    n_samples = embedding.shape[0]

268
269
    # Fitting the main diagonal with infs (removing comparisons with the same
    # sample)
270
    numpy.fill_diagonal(distances, numpy.inf)
271

272
    indexes = distances.argmin(axis=1)
273

274
275
    # Computing the argmin excluding comparisons with the same samples
    # Basically, we are excluding the main diagonal
276
277

    #valid_indexes = distances[distances>0].reshape(n_samples, n_samples-1).argmin(axis=1)
278
279

    # Getting the original positions of the indexes in the 1-axis
280
    #corrected_indexes = [ i if i<j else i+1 for i, j in zip(valid_indexes, range(n_samples))]
281

282
283
284
    matching = [
        labels[i] == labels[j] for i, j in zip(range(n_samples), indexes)
    ]
285
286
    accuracy = sum(matching) / float(n_samples)

287
    return accuracy
Tiago de Freitas Pereira's avatar
Tiago de Freitas Pereira committed
288

289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307

def get_available_gpus():
    """Returns the number of GPU devices that are available.

    Returns
    -------
    [str]
        The names of available GPU devices.
    """
    local_device_protos = device_lib.list_local_devices()
    return [x.name for x in local_device_protos if x.device_type == 'GPU']


def to_channels_last(image):
    """Converts the image to channel_last format. This is the same format as in
    matplotlib, skimage, and etc.

    Parameters
    ----------
308
    image : `tf.Tensor`
309
310
311
312
313
        At least a 3 dimensional image. If the dimension is more than 3, the
        last 3 dimensions are assumed to be [C, H, W].

    Returns
    -------
314
    image : `tf.Tensor`
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
        The image in [..., H, W, C] format.

    Raises
    ------
    ValueError
        If dim of image is less than 3.
    """
    ndim = len(image.shape)
    if ndim < 3:
        raise ValueError("The image needs to be at least 3 dimensional but it "
                         "was {}".format(ndim))
    axis_order = [1, 2, 0]
    shift = ndim - 3
    axis_order = list(range(ndim - 3)) + [n + shift for n in axis_order]
    return tf.transpose(image, axis_order)


def to_channels_first(image):
    """Converts the image to channel_first format. This is the same format as
    in bob.io.image and bob.io.video.

    Parameters
    ----------
338
    image : `tf.Tensor`
339
340
341
342
343
        At least a 3 dimensional image. If the dimension is more than 3, the
        last 3 dimensions are assumed to be [H, W, C].

    Returns
    -------
344
    image : `tf.Tensor`
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
        The image in [..., C, H, W] format.

    Raises
    ------
    ValueError
        If dim of image is less than 3.
    """
    ndim = len(image.shape)
    if ndim < 3:
        raise ValueError("The image needs to be at least 3 dimensional but it "
                         "was {}".format(ndim))
    axis_order = [2, 0, 1]
    shift = ndim - 3
    axis_order = list(range(ndim - 3)) + [n + shift for n in axis_order]
    return tf.transpose(image, axis_order)


to_skimage = to_matplotlib = to_channels_last
to_bob = to_channels_first
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394


def bytes2human(n, format='%(value).1f %(symbol)s', symbols='customary'):
    """Convert n bytes into a human readable string based on format.
    From: https://code.activestate.com/recipes/578019-bytes-to-human-human-to-
    bytes-converter/
    Author: Giampaolo Rodola' <g.rodola [AT] gmail [DOT] com>
    License: MIT
    symbols can be either "customary", "customary_ext", "iec" or "iec_ext",
    see: http://goo.gl/kTQMs
    """
    SYMBOLS = {
        'customary': ('B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'),
        'customary_ext': ('byte', 'kilo', 'mega', 'giga', 'tera', 'peta',
                          'exa', 'zetta', 'iotta'),
        'iec': ('Bi', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'),
        'iec_ext': ('byte', 'kibi', 'mebi', 'gibi', 'tebi', 'pebi', 'exbi',
                    'zebi', 'yobi'),
    }
    n = int(n)
    if n < 0:
        raise ValueError("n < 0")
    symbols = SYMBOLS[symbols]
    prefix = {}
    for i, s in enumerate(symbols[1:]):
        prefix[s] = 1 << (i + 1) * 10
    for symbol in reversed(symbols[1:]):
        if n >= prefix[symbol]:
            value = float(n) / prefix[symbol]
            return format % locals()
    return format % dict(symbol=symbols[0], value=n)