Replaced some classes to functions #37 . Still need to update some tests

parent ee32fe3c
Pipeline #13123 failed with stages
in 4 minutes and 35 seconds
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
# @date: Tue 09 Aug 2016 16:38 CEST
import logging
import tensorflow as tf
......@@ -10,92 +9,70 @@ logger = logging.getLogger("bob.learn.tensorflow")
slim = tf.contrib.slim
class BaseLoss(object):
"""
Base loss function.
Stupid class. Don't know why I did that.
"""
def __init__(self, loss, operation, name="loss"):
self.loss = loss
self.operation = operation
self.name = name
def __call__(self, graph, label):
return self.operation(self.loss(logits=graph, labels=label), name=self.name)
class MeanSoftMaxLoss(object):
def mean_cross_entropy_loss(logits, labels, add_regularization_losses=True):
"""
Simple CrossEntropy loss.
Basically it wrapps the function tf.nn.sparse_softmax_cross_entropy_with_logits.
**Parameters**
name: Scope name
logits:
labels:
add_regularization_losses: Regulize the loss???
"""
def __init__(self, name="loss", add_regularization_losses=True):
self.name = name
self.add_regularization_losses = add_regularization_losses
with tf.variable_scope('cross_entropy_loss'):
def __call__(self, graph, label):
loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=graph, labels=label), name=self.name)
if self.add_regularization_losses:
logits=logits, labels=labels), name=tf.GraphKeys.LOSSES)
if add_regularization_losses:
regularization_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
return tf.add_n([loss] + regularization_losses, name='total_loss')
return tf.add_n([loss] + regularization_losses, name=tf.GraphKeys.LOSSES)
else:
return loss
class MeanSoftMaxLossCenterLoss(object):
def mean_cross_entropy_center_loss(logits, prelogits, labels, n_classes, alpha=0.9, factor=0.01):
"""
Implementation of the CrossEntropy + Center Loss from the paper
"A Discriminative Feature Learning Approach for Deep Face Recognition"(http://ydwen.github.io/papers/WenECCV16.pdf)
**Parameters**
name: Scope name
logits:
prelogits:
labels:
n_classes: Number of classes of your task
alpha: Alpha factor ((1-alpha)*centers-prelogits)
factor: Weight factor of the center loss
n_classes: Number of classes of your task
"""
def __init__(self, name="loss", alpha=0.9, factor=0.01, n_classes=10):
self.name = name
# Cross entropy
with tf.variable_scope('cross_entropy_loss'):
loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=logits, labels=labels), name=tf.GraphKeys.LOSSES)
self.n_classes = n_classes
self.alpha = alpha
self.factor = factor
# Appending center loss
with tf.variable_scope('center_loss'):
n_features = prelogits.get_shape()[1]
centers = tf.get_variable('centers', [n_classes, n_features], dtype=tf.float32,
initializer=tf.constant_initializer(0), trainable=False)
label = tf.reshape(labels, [-1])
centers_batch = tf.gather(centers, labels)
diff = (1 - alpha) * (centers_batch - prelogits)
centers = tf.scatter_sub(centers, labels, diff)
center_loss = tf.reduce_mean(tf.square(prelogits - centers_batch))
tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, center_loss * factor)
# Adding the regularizers in the loss
with tf.variable_scope('total_loss'):
regularization_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
total_loss = tf.add_n([loss] + regularization_losses, name=tf.GraphKeys.LOSSES)
def __call__(self, logits, prelogits, label):
# Cross entropy
with tf.variable_scope('cross_entropy_loss'):
loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=logits, labels=label), name=self.name)
loss = dict()
loss['loss'] = total_loss
loss['centers'] = centers
# Appending center loss
with tf.variable_scope('center_loss'):
n_features = prelogits.get_shape()[1]
centers = tf.get_variable('centers', [self.n_classes, n_features], dtype=tf.float32,
initializer=tf.constant_initializer(0), trainable=False)
label = tf.reshape(label, [-1])
centers_batch = tf.gather(centers, label)
diff = (1 - self.alpha) * (centers_batch - prelogits)
centers = tf.scatter_sub(centers, label, diff)
center_loss = tf.reduce_mean(tf.square(prelogits - centers_batch))
tf.add_to_collection(tf.GraphKeys.REGULARIZATION_LOSSES, center_loss * self.factor)
# Adding the regularizers in the loss
with tf.variable_scope('total_loss'):
regularization_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
total_loss = tf.add_n([loss] + regularization_losses, name='total_loss')
return total_loss, centers
return loss
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
# @date: Wed 10 Aug 2016 16:38 CEST
import logging
logger = logging.getLogger("bob.learn.tensorflow")
import tensorflow as tf
from .BaseLoss import BaseLoss
from bob.learn.tensorflow.utils import compute_euclidean_distance
class ContrastiveLoss(BaseLoss):
def contrastive_loss(left_embedding, right_embedding, labels, contrastive_margin=1.0):
"""
Compute the contrastive loss as in
......@@ -27,7 +25,7 @@ class ContrastiveLoss(BaseLoss):
right_feature:
Second element of the pair
label:
labels:
Label of the pair (0 or 1)
margin:
......@@ -35,30 +33,25 @@ class ContrastiveLoss(BaseLoss):
"""
def __init__(self, contrastive_margin=1.0):
self.contrastive_margin = contrastive_margin
with tf.name_scope("contrastive_loss"):
labels = tf.to_float(labels)
left_embedding = tf.nn.l2_normalize(left_embedding, 1)
right_embedding = tf.nn.l2_normalize(right_embedding, 1)
def __call__(self, label, left_feature, right_feature):
with tf.name_scope("contrastive_loss"):
label = tf.to_float(label)
left_feature = tf.nn.l2_normalize(left_feature, 1)
right_feature = tf.nn.l2_normalize(right_feature, 1)
one = tf.constant(1.0)
one = tf.constant(1.0)
d = compute_euclidean_distance(left_embedding, right_embedding)
within_class = tf.multiply(one - labels, tf.square(d)) # (1-Y)*(d^2)
max_part = tf.square(tf.maximum(contrastive_margin - d, 0))
between_class = tf.multiply(labels, max_part) # (Y) * max((margin - d)^2, 0)
d = compute_euclidean_distance(left_feature, right_feature)
within_class = tf.multiply(one - label, tf.square(d)) # (1-Y)*(d^2)
max_part = tf.square(tf.maximum(self.contrastive_margin - d, 0))
between_class = tf.multiply(label, max_part) # (Y) * max((margin - d)^2, 0)
loss = 0.5 * (within_class + between_class)
loss = 0.5 * (within_class + between_class)
loss_dict = dict()
loss_dict['loss'] = tf.reduce_mean(loss, name=tf.GraphKeys.LOSSES)
loss_dict['between_class'] = tf.reduce_mean(between_class, name=tf.GraphKeys.LOSSES)
loss_dict['within_class'] = tf.reduce_mean(within_class, name=tf.GraphKeys.LOSSES)
loss_dict = dict()
loss_dict['loss'] = tf.reduce_mean(loss)
loss_dict['between_class'] = tf.reduce_mean(between_class)
loss_dict['within_class'] = tf.reduce_mean(within_class)
return loss_dict
return loss_dict
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
# @date: Wed 10 Aug 2016 16:38 CEST
import logging
logger = logging.getLogger("bob.learn.tensorflow")
import tensorflow as tf
from .BaseLoss import BaseLoss
from bob.learn.tensorflow.utils import compute_euclidean_distance
class TripletAverageLoss(BaseLoss):
"""
Compute the triplet loss as in
Schroff, Florian, Dmitry Kalenichenko, and James Philbin.
"Facenet: A unified embedding for face recognition and clustering."
Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2015.
:math:`L = sum( |f_a - f_p|^2 - |f_a - f_n|^2 + \lambda)`
**Parameters**
left_feature:
First element of the pair
right_feature:
Second element of the pair
label:
Label of the pair (0 or 1)
margin:
Contrastive margin
"""
def __init__(self, margin=0.1):
self.margin = margin
def __call__(self, anchor_embedding, positive_embedding, negative_embedding):
with tf.name_scope("triplet_loss"):
# Normalize
anchor_embedding = tf.nn.l2_normalize(anchor_embedding, 1, 1e-10, name="anchor")
positive_embedding = tf.nn.l2_normalize(positive_embedding, 1, 1e-10, name="positive")
negative_embedding = tf.nn.l2_normalize(negative_embedding, 1, 1e-10, name="negative")
anchor_mean = tf.reduce_mean(anchor_embedding, 0)
d_positive = tf.reduce_sum(tf.square(tf.subtract(anchor_mean, positive_embedding)), 1)
d_negative = tf.reduce_sum(tf.square(tf.subtract(anchor_mean, negative_embedding)), 1)
basic_loss = tf.add(tf.subtract(d_positive, d_negative), self.margin)
loss = tf.reduce_mean(tf.maximum(basic_loss, 0.0), 0)
return loss, tf.reduce_mean(d_negative), tf.reduce_mean(d_positive)
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
# @date: Wed 10 Aug 2016 16:38 CEST
import logging
logger = logging.getLogger("bob.learn.tensorflow")
import tensorflow as tf
from .BaseLoss import BaseLoss
from bob.learn.tensorflow.utils import compute_euclidean_distance
class TripletFisherLoss(BaseLoss):
"""
"""
def __init__(self):
pass
def __call__(self, anchor_embedding, positive_embedding, negative_embedding):
with tf.name_scope("triplet_loss"):
# Normalize
anchor_embedding = tf.nn.l2_normalize(anchor_embedding, 1, 1e-10, name="anchor")
positive_embedding = tf.nn.l2_normalize(positive_embedding, 1, 1e-10, name="positive")
negative_embedding = tf.nn.l2_normalize(negative_embedding, 1, 1e-10, name="negative")
average_class = tf.reduce_mean(anchor_embedding, 0)
average_total = tf.div(tf.add(tf.reduce_mean(anchor_embedding, axis=0),\
tf.reduce_mean(negative_embedding, axis=0)), 2)
length = anchor_embedding.get_shape().as_list()[0]
dim = anchor_embedding.get_shape().as_list()[1]
split_positive = tf.unstack(positive_embedding, num=length, axis=0)
split_negative = tf.unstack(negative_embedding, num=length, axis=0)
Sw = None
Sb = None
for s in zip(split_positive, split_negative):
positive = s[0]
negative = s[1]
buffer_sw = tf.reshape(tf.subtract(positive, average_class), shape=(dim, 1))
buffer_sw = tf.matmul(buffer_sw, tf.reshape(buffer_sw, shape=(1, dim)))
buffer_sb = tf.reshape(tf.subtract(negative, average_total), shape=(dim, 1))
buffer_sb = tf.matmul(buffer_sb, tf.reshape(buffer_sb, shape=(1, dim)))
if Sw is None:
Sw = buffer_sw
Sb = buffer_sb
else:
Sw = tf.add(Sw, buffer_sw)
Sb = tf.add(Sb, buffer_sb)
# Sw = tf.trace(Sw)
# Sb = tf.trace(Sb)
#loss = tf.trace(tf.div(Sb, Sw))
loss = tf.trace(tf.div(Sw, Sb))
return loss, tf.trace(Sb), tf.trace(Sw)
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
# @date: Wed 10 Aug 2016 16:38 CEST
import logging
logger = logging.getLogger("bob.learn.tensorflow")
import tensorflow as tf
from .BaseLoss import BaseLoss
from bob.learn.tensorflow.utils import compute_euclidean_distance
class TripletLoss(BaseLoss):
def triplet_loss(anchor_embedding, positive_embedding, negative_embedding, margin=5.0):
"""
Compute the triplet loss as in
......@@ -37,26 +35,110 @@ class TripletLoss(BaseLoss):
"""
def __init__(self, margin=5.0):
self.margin = margin
with tf.name_scope("triplet_loss"):
# Normalize
anchor_embedding = tf.nn.l2_normalize(anchor_embedding, 1, 1e-10, name="anchor")
positive_embedding = tf.nn.l2_normalize(positive_embedding, 1, 1e-10, name="positive")
negative_embedding = tf.nn.l2_normalize(negative_embedding, 1, 1e-10, name="negative")
d_positive = tf.reduce_sum(tf.square(tf.subtract(anchor_embedding, positive_embedding)), 1)
d_negative = tf.reduce_sum(tf.square(tf.subtract(anchor_embedding, negative_embedding)), 1)
basic_loss = tf.add(tf.subtract(d_positive, d_negative), margin)
loss = tf.reduce_mean(tf.maximum(basic_loss, 0.0), 0, name=tf.GraphKeys.LOSSES)
loss_dict = dict()
loss_dict['loss'] = loss
loss_dict['between_class'] = tf.reduce_mean(d_negative)
loss_dict['within_class'] = tf.reduce_mean(d_positive)
return loss_dict
def triplet_fisher_loss(anchor_embedding, positive_embedding, negative_embedding):
with tf.name_scope("triplet_loss"):
# Normalize
anchor_embedding = tf.nn.l2_normalize(anchor_embedding, 1, 1e-10, name="anchor")
positive_embedding = tf.nn.l2_normalize(positive_embedding, 1, 1e-10, name="positive")
negative_embedding = tf.nn.l2_normalize(negative_embedding, 1, 1e-10, name="negative")
average_class = tf.reduce_mean(anchor_embedding, 0)
average_total = tf.div(tf.add(tf.reduce_mean(anchor_embedding, axis=0),\
tf.reduce_mean(negative_embedding, axis=0)), 2)
length = anchor_embedding.get_shape().as_list()[0]
dim = anchor_embedding.get_shape().as_list()[1]
split_positive = tf.unstack(positive_embedding, num=length, axis=0)
split_negative = tf.unstack(negative_embedding, num=length, axis=0)
Sw = None
Sb = None
for s in zip(split_positive, split_negative):
positive = s[0]
negative = s[1]
buffer_sw = tf.reshape(tf.subtract(positive, average_class), shape=(dim, 1))
buffer_sw = tf.matmul(buffer_sw, tf.reshape(buffer_sw, shape=(1, dim)))
buffer_sb = tf.reshape(tf.subtract(negative, average_total), shape=(dim, 1))
buffer_sb = tf.matmul(buffer_sb, tf.reshape(buffer_sb, shape=(1, dim)))
if Sw is None:
Sw = buffer_sw
Sb = buffer_sb
else:
Sw = tf.add(Sw, buffer_sw)
Sb = tf.add(Sb, buffer_sb)
# Sw = tf.trace(Sw)
# Sb = tf.trace(Sb)
#loss = tf.trace(tf.div(Sb, Sw))
loss = tf.trace(tf.div(Sw, Sb), name=tf.GraphKeys.LOSSES)
return loss, tf.trace(Sb), tf.trace(Sw)
def triplet_average_loss(anchor_embedding, positive_embedding, negative_embedding, margin=5.0):
"""
Compute the triplet loss as in
Schroff, Florian, Dmitry Kalenichenko, and James Philbin.
"Facenet: A unified embedding for face recognition and clustering."
Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2015.
:math:`L = sum( |f_a - f_p|^2 - |f_a - f_n|^2 + \lambda)`
**Parameters**
left_feature:
First element of the pair
right_feature:
Second element of the pair
label:
Label of the pair (0 or 1)
margin:
Contrastive margin
"""
def __call__(self, anchor_embedding, positive_embedding, negative_embedding):
with tf.name_scope("triplet_loss"):
# Normalize
anchor_embedding = tf.nn.l2_normalize(anchor_embedding, 1, 1e-10, name="anchor")
positive_embedding = tf.nn.l2_normalize(positive_embedding, 1, 1e-10, name="positive")
negative_embedding = tf.nn.l2_normalize(negative_embedding, 1, 1e-10, name="negative")
with tf.name_scope("triplet_loss"):
# Normalize
anchor_embedding = tf.nn.l2_normalize(anchor_embedding, 1, 1e-10, name="anchor")
positive_embedding = tf.nn.l2_normalize(positive_embedding, 1, 1e-10, name="positive")
negative_embedding = tf.nn.l2_normalize(negative_embedding, 1, 1e-10, name="negative")
anchor_mean = tf.reduce_mean(anchor_embedding, 0)
d_positive = tf.reduce_sum(tf.square(tf.subtract(anchor_embedding, positive_embedding)), 1)
d_negative = tf.reduce_sum(tf.square(tf.subtract(anchor_embedding, negative_embedding)), 1)
d_positive = tf.reduce_sum(tf.square(tf.subtract(anchor_mean, positive_embedding)), 1)
d_negative = tf.reduce_sum(tf.square(tf.subtract(anchor_mean, negative_embedding)), 1)
basic_loss = tf.add(tf.subtract(d_positive, d_negative), self.margin)
loss = tf.reduce_mean(tf.maximum(basic_loss, 0.0), 0)
basic_loss = tf.add(tf.subtract(d_positive, d_negative), margin)
loss = tf.reduce_mean(tf.maximum(basic_loss, 0.0), 0, name=tf.GraphKeys.LOSSES)
loss_dict = dict()
loss_dict['loss'] = loss
loss_dict['between_class'] = tf.reduce_mean(d_negative)
loss_dict['within_class'] = tf.reduce_mean(d_positive)
return loss, tf.reduce_mean(d_negative), tf.reduce_mean(d_positive)
return loss_dict
from .BaseLoss import BaseLoss, MeanSoftMaxLoss, MeanSoftMaxLossCenterLoss
from .ContrastiveLoss import ContrastiveLoss
from .TripletLoss import TripletLoss
from .TripletAverageLoss import TripletAverageLoss
from .TripletFisherLoss import TripletFisherLoss
from .NegLogLoss import NegLogLoss
from .BaseLoss import mean_cross_entropy_loss, mean_cross_entropy_center_loss
from .ContrastiveLoss import contrastive_loss
from .TripletLoss import triplet_loss, triplet_average_loss, triplet_fisher_loss
#from .NegLogLoss import NegLogLoss
# gets sphinx autodoc done right - don't remove it
......@@ -21,13 +19,9 @@ def __appropriate__(*args):
for obj in args: obj.__module__ = __name__
__appropriate__(
BaseLoss,
ContrastiveLoss,
TripletLoss,
TripletFisherLoss,
TripletAverageLoss,
NegLogLoss,
MeanSoftMaxLoss
mean_cross_entropy_loss, mean_cross_entropy_center_loss,
contrastive_loss,
triplet_loss, triplet_average_loss, triplet_fisher_loss
)
__all__ = [_ for _ in dir() if not _.startswith('_')]
......
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
# @date: Wed 11 May 2016 09:39:36 CEST
import tensorflow as tf
from .utils import append_logits
def chopra(inputs, conv1_kernel_size=[7, 7],
conv1_output=15,
class Chopra(object):
pooling1_size=[2, 2],
conv2_kernel_size=[6, 6],
conv2_output=45,
pooling2_size=[4, 3],
fc1_output=250,
seed=10,
reuse=False,):
"""Class that creates the architecture presented in the paper:
Chopra, Sumit, Raia Hadsell, and Yann LeCun. "Learning a similarity metric discriminatively, with application to
......@@ -49,79 +58,41 @@ class Chopra(object):
fc1_output:
n_classes: If None, no Fully COnnected layer with class output will be created
seed:
"""
def __init__(self,
conv1_kernel_size=[7, 7],
conv1_output=15,
pooling1_size=[2, 2],
conv2_kernel_size=[6, 6],
conv2_output=45,
pooling2_size=[4, 3],
fc1_output=250,
n_classes=None,
seed=10):
self.conv1_kernel_size = conv1_kernel_size
self.conv1_output = conv1_output
self.pooling1_size = pooling1_size
self.conv2_output = conv2_output
self.conv2_kernel_size = conv2_kernel_size
self.pooling2_size = pooling2_size
self.fc1_output = fc1_output
self.seed = seed
self.n_classes = n_classes
def __call__(self, inputs, reuse=False, end_point='logits'):
slim = tf.contrib.slim
end_points = dict()
initializer = tf.contrib.layers.xavier_initializer(uniform=False, dtype=tf.float32, seed=self.seed)
graph = slim.conv2d(inputs, self.conv1_output, self.conv1_kernel_size, activation_fn=tf.nn.relu,
stride=1,
weights_initializer=initializer,
scope='conv1',
reuse=reuse)
end_points['conv1'] = graph
graph = slim.max_pool2d(graph, self.pooling1_size, scope='pool1')
end_points['pool1'] = graph
graph = slim.conv2d(graph, self.conv2_output, self.conv2_kernel_size, activation_fn=tf.nn.relu,
stride=1,
weights_initializer=initializer,
scope='conv2', reuse=reuse)
end_points['conv2'] = graph
graph = slim.max_pool2d(graph, self.pooling2_size, scope='pool2')
end_points['pool2'] = graph
graph = slim.flatten(graph, scope='flatten1')
end_points['flatten1'] = graph
graph = slim.fully_connected(graph, self.fc1_output,
weights_initializer=initializer,
activation_fn=None,
scope='fc1',
reuse=reuse)
end_points['fc1'] = graph
if self.n_classes is not None:
# Appending the logits layer
graph = append_logits(graph, self.n_classes, reuse)
end_points['logits'] = graph
return end_points[end_point]
slim = tf.contrib.slim
end_points = dict()
initializer = tf.contrib.layers.xavier_initializer(uniform=False, dtype=tf.float32, seed=seed)
graph = slim.conv2d(inputs, conv1_output, conv1_kernel_size, activation_fn=tf.nn.relu,
stride=1,
weights_initializer=initializer,
scope='conv1',
reuse=reuse)
end_points['conv1'] = graph
graph = slim.max_pool2d(graph, pooling1_size, scope='pool1')
end_points['pool1'] = graph
graph = slim.conv2d(graph, conv2_output, conv2_kernel_size, activation_fn=tf.nn.relu,
stride=1,
weights_initializer=initializer,
scope='conv2', reuse=reuse)
end_points['conv2'] = graph
graph = slim.max_pool2d(graph, pooling2_size, scope='pool2')
end_points['pool2'] = graph
graph = slim.flatten(graph, scope='flatten1')
end_points['flatten1'] = graph
graph = slim.fully_connected(graph, fc1_output,
weights_initializer=initializer,
activation_fn=None,
scope='fc1',
reuse=reuse)
end_points['fc1'] = graph
return graph, end_points
from .Chopra import Chopra
from .Chopra import chopra
from .LightCNN9 import LightCNN9
from .LightCNN29 import LightCNN29
from .Dummy import Dummy
......
......@@ -6,12 +6,9 @@ import tensorflow as tf
slim = tf.contrib.slim
def append_logits(graph, n_classes, reuse):
graph = slim.fully_connected(graph, n_classes, activation_fn=None,
weights_initializer=tf.truncated_normal_initializer(stddev=0.1),
weights_regularizer=slim.l2_regularizer(0.1),
def append_logits(graph, n_classes, reuse=False, l2_regularizer=0.001, weights_std=0.1):
return slim.fully_connected(graph, n_classes, activation_fn=None,
weights_initializer=tf.truncated_normal_initializer(stddev=weights_std),
weights_regularizer=slim.l2_regularizer(l2_regularizer),
scope