Commit 578f27a2 authored by Tiago de Freitas Pereira's avatar Tiago de Freitas Pereira
Browse files

Merge branch 'updates' into 'master'

Updates

See merge request !17
parents d8b85d54 929fc8f8
Pipeline #13011 passed with stages
in 14 minutes and 26 seconds
......@@ -190,17 +190,21 @@ class Base(object):
bob.ip.base.scale(copy, dst)
dst = numpy.reshape(dst, self.input_shape[1:4])
else:
# dst = numpy.resize(data, self.bob_shape) # Scaling with numpy, because bob is c,w,d instead of w,h,c
dst = numpy.zeros(shape=self.bob_shape)
#dst = numpy.resize(data, self.bob_shape) # Scaling with numpy, because bob is c,w,d instead of w,h,c
#dst = numpy.zeros(shape=(data.shape[0], data.shape[1], 3))
#dst[:, :, 0] = data[:, :, 0]
#dst[:, :, 1] = data[:, :, 0]
#dst[:, :, 2] = data[:, :, 0]
# TODO: LAME SOLUTION
if data.shape[0] != 3: # GRAY SCALE IMAGES IN A RGB DATABASE
step_data = numpy.zeros(shape=(3, data.shape[0], data.shape[1]))
step_data[0, ...] = data[:, :]
step_data[1, ...] = data[:, :]
step_data[2, ...] = data[:, :]
data = step_data
#if data.shape[0] != 3: # GRAY SCALE IMAGES IN A RGB DATABASE
# step_data = numpy.zeros(shape=(3, data.shape[0], data.shape[1]))
#step_data = numpy.zeros(shape=(3, data.shape[0], data.shape[1]))
#step_data[0, ...] = data[:, :, 0]
#step_data[1, ...] = data[:, :, 0]
#step_data[2, ...] = data[:, :, 0]
#data = step_data
dst = numpy.zeros(shape=(self.bob_shape))
bob.ip.base.scale(data, dst)
return dst
......
#!/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 numpy
import tensorflow as tf
......@@ -11,10 +10,22 @@ from bob.learn.tensorflow.datashuffler.Normalizer import Linear
class TFRecord(object):
"""
Generic datashuffler that wraps the batching using tfrecords.
**Parameters**
filename_queue: Tensorflow producer
input_shape: Shape of the input in the tfrecord
input_dtype: Type of the raw data saved in the tf record
batch_size: Size of the batch
seed: Seed
prefetch_capacity: Capacity of the bucket for prefetching
prefetch_threads: Number of threads in the prefetching
"""
def __init__(self,filename_queue,
input_shape=[None, 28, 28, 1],
input_dtype="float32",
input_dtype=tf.float32,
batch_size=32,
seed=10,
prefetch_capacity=50,
......@@ -75,7 +86,7 @@ class TFRecord(object):
features = tf.parse_single_example(serialized_example, features=feature)
# Convert the image data from string back to the numbers
image = tf.decode_raw(features['train/data'], tf.float32)
image = tf.decode_raw(features['train/data'], self.input_dtype)
# Cast label data into int32
label = tf.cast(features['train/label'], tf.int64)
......@@ -94,17 +105,5 @@ class TFRecord(object):
def get_batch(self):
"""
Shuffle the Memory dataset and get a random batch.
** Returns **
data:
Selected samples
labels:
Correspondent labels
"""
pass
#!/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 numpy
import tensorflow as tf
import bob.ip.base
import numpy
from bob.learn.tensorflow.datashuffler.Normalizer import Linear
from .TFRecord import TFRecord
class TFRecordImage(TFRecord):
"""
Datashuffler that wraps the batching using tfrecords.
This shuffler is more suitable for image datasets, because it does image data augmentation operations.
**Parameters**
filename_queue: Tensorflow producer
input_shape: Shape of the input in the tfrecord
output_shape: Desired output shape after the data augmentation
input_dtype: Type of the raw data saved in the tf record
batch_size: Size of the batch
seed: Seed
prefetch_capacity: Capacity of the bucket for prefetching
prefetch_threads: Number of threads in the prefetching
shuffle: Shuffled the batch
normalization: zero mean and unit std
random_flip:
random_crop:
gray_scale: Convert the output to gray scale
"""
def __init__(self,filename_queue,
input_shape=[None, 28, 28, 1],
output_shape=[None, 28, 28, 1],
input_dtype=tf.uint8,
batch_size=32,
seed=10,
prefetch_capacity=50,
prefetch_threads=5,
shuffle=True,
normalization=False,
random_flip=True,
random_crop=True,
gray_scale=False
):
# Setting the seed for the pseudo random number generator
self.seed = seed
numpy.random.seed(seed)
self.input_dtype = input_dtype
# TODO: Check if the bacth size is higher than the input data
self.batch_size = batch_size
# Preparing the inputs
self.filename_queue = filename_queue
self.input_shape = tuple(input_shape)
self.output_shape = output_shape
# Prefetch variables
self.prefetch = True
self.prefetch_capacity = prefetch_capacity
self.prefetch_threads = prefetch_threads
self.data_ph = None
self.label_ph = None
self.shuffle = shuffle
self.normalization = normalization
self.random_crop = random_crop
self.gray_scale = gray_scale
def __call__(self, element, from_queue=False):
"""
Return the necessary placeholder
"""
if not element in ["data", "label"]:
raise ValueError("Value '{0}' invalid. Options available are {1}".format(element, self.placeholder_options))
# If None, create the placeholders from scratch
if self.data_ph is None:
self.create_placeholders()
if element == "data":
return self.data_ph
else:
return self.label_ph
def create_placeholders(self):
feature = {'train/data': tf.FixedLenFeature([], tf.string),
'train/label': tf.FixedLenFeature([], tf.int64)}
# Define a reader and read the next record
reader = tf.TFRecordReader()
_, serialized_example = reader.read(self.filename_queue)
# Decode the record read by the reader
features = tf.parse_single_example(serialized_example, features=feature)
# Convert the image data from string back to the numbers
image = tf.decode_raw(features['train/data'], self.input_dtype)
#image = tf.decode_raw(features['train/data'], tf.uint8)
# Cast label data into int32
label = tf.cast(features['train/label'], tf.int64)
# Reshape image data into the original shape
image = tf.reshape(image, self.input_shape[1:])
# Casting to float32
image = tf.cast(image, tf.float32)
if self.gray_scale:
image = tf.image.rgb_to_grayscale(image, name="rgb_to_gray")
self.output_shape[3] = 1
if self.random_crop:
image = tf.image.resize_image_with_crop_or_pad(image, self.output_shape[1], self.output_shape[2])
# normalizing data
if self.normalization:
image = tf.image.per_image_standardization(image)
image.set_shape(tuple(self.output_shape[1:]))
if self.shuffle:
data_ph, label_ph = tf.train.shuffle_batch([image, label], batch_size=self.batch_size,
capacity=self.prefetch_capacity, num_threads=self.prefetch_threads,
min_after_dequeue=1, name="shuffle_batch")
else:
data_ph, label_ph = tf.train.batch([image, label], batch_size=self.batch_size,
capacity=self.prefetch_capacity, num_threads=self.prefetch_threads, name="batch")
self.data_ph = data_ph
self.label_ph = label_ph
......@@ -22,6 +22,7 @@ from .Normalizer import ScaleFactor, MeanOffset, Linear
from .DiskAudio import DiskAudio
from .TFRecord import TFRecord
from .TFRecordImage import TFRecordImage
# gets sphinx autodoc done right - don't remove it
def __appropriate__(*args):
......@@ -55,5 +56,7 @@ __appropriate__(
ImageAugmentation,
ScaleFactor, MeanOffset, Linear,
DiskAudio,
TFRecord,
TFRecordImage
)
__all__ = [_ for _ in dir() if not _.startswith('_')]
......@@ -13,8 +13,7 @@ slim = tf.contrib.slim
class BaseLoss(object):
"""
Base loss function.
One exam
Stupid class. Don't know why I did that.
"""
def __init__(self, loss, operation, name="loss"):
......@@ -28,23 +27,75 @@ class BaseLoss(object):
class MeanSoftMaxLoss(object):
"""
Mean softmax loss. Basically it wrapps the function tf.nn.sparse_softmax_cross_entropy_with_logits.
Simple CrossEntropy loss.
Basically it wrapps the function tf.nn.sparse_softmax_cross_entropy_with_logits.
**Parameters**
name: Scope name
add_regularization_losses: Regulize the loss???
"""
def __init__(self, name="loss"):
"""
Constructor
**Parameters**
def __init__(self, name="loss", add_regularization_losses=True):
self.name = name
self.add_regularization_losses = add_regularization_losses
name:
Scope name
"""
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:
regularization_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)
return tf.add_n([loss] + regularization_losses, name='total_loss')
else:
return loss
class MeanSoftMaxLossCenterLoss(object):
"""
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
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
def __call__(self, graph, label):
self.n_classes = n_classes
self.alpha = alpha
self.factor = factor
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)
# 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)
return tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
logits=graph, labels=label), name=self.name)
# 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
from .BaseLoss import BaseLoss, MeanSoftMaxLoss
from .BaseLoss import BaseLoss, MeanSoftMaxLoss, MeanSoftMaxLossCenterLoss
from .ContrastiveLoss import ContrastiveLoss
from .TripletLoss import TripletLoss
from .TripletAverageLoss import TripletAverageLoss
......
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains the definition of the Inception Resnet V1 architecture.
As described in http://arxiv.org/abs/1602.07261.
Inception-v4, Inception-ResNet and the Impact of Residual Connections
on Learning
Christian Szegedy, Sergey Ioffe, Vincent Vanhoucke, Alex Alemi
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
import tensorflow.contrib.slim as slim
# Inception-Renset-A
def block35(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
"""Builds the 35x35 resnet block."""
with tf.variable_scope(scope, 'Block35', [net], reuse=reuse):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 32, 1, scope='Conv2d_1x1')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, 32, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, 32, 3, scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
tower_conv2_0 = slim.conv2d(net, 32, 1, scope='Conv2d_0a_1x1')
tower_conv2_1 = slim.conv2d(tower_conv2_0, 32, 3, scope='Conv2d_0b_3x3')
tower_conv2_2 = slim.conv2d(tower_conv2_1, 32, 3, scope='Conv2d_0c_3x3')
mixed = tf.concat([tower_conv, tower_conv1_1, tower_conv2_2], 3)
up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,
activation_fn=None, scope='Conv2d_1x1')
net += scale * up
if activation_fn:
net = activation_fn(net)
return net
# Inception-Renset-B
def block17(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
"""Builds the 17x17 resnet block."""
with tf.variable_scope(scope, 'Block17', [net], reuse=reuse):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 128, 1, scope='Conv2d_1x1')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, 128, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, 128, [1, 7],
scope='Conv2d_0b_1x7')
tower_conv1_2 = slim.conv2d(tower_conv1_1, 128, [7, 1],
scope='Conv2d_0c_7x1')
mixed = tf.concat([tower_conv, tower_conv1_2], 3)
up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,
activation_fn=None, scope='Conv2d_1x1')
net += scale * up
if activation_fn:
net = activation_fn(net)
return net
# Inception-Resnet-C
def block8(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
"""Builds the 8x8 resnet block."""
with tf.variable_scope(scope, 'Block8', [net], reuse=reuse):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 192, 1, scope='Conv2d_1x1')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, 192, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, 192, [1, 3],
scope='Conv2d_0b_1x3')
tower_conv1_2 = slim.conv2d(tower_conv1_1, 192, [3, 1],
scope='Conv2d_0c_3x1')
mixed = tf.concat([tower_conv, tower_conv1_2], 3)
up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,
activation_fn=None, scope='Conv2d_1x1')
net += scale * up
if activation_fn:
net = activation_fn(net)
return net
def reduction_a(net, k, l, m, n):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, n, 3, stride=2, padding='VALID',
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, k, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, l, 3,
scope='Conv2d_0b_3x3')
tower_conv1_2 = slim.conv2d(tower_conv1_1, m, 3,
stride=2, padding='VALID',
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_2'):
tower_pool = slim.max_pool2d(net, 3, stride=2, padding='VALID',
scope='MaxPool_1a_3x3')
net = tf.concat([tower_conv, tower_conv1_2, tower_pool], 3)
return net
def reduction_b(net):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
tower_conv_1 = slim.conv2d(tower_conv, 384, 3, stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
tower_conv1 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1, 256, 3, stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_2'):
tower_conv2 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
tower_conv2_1 = slim.conv2d(tower_conv2, 256, 3,
scope='Conv2d_0b_3x3')
tower_conv2_2 = slim.conv2d(tower_conv2_1, 256, 3, stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_3'):
tower_pool = slim.max_pool2d(net, 3, stride=2, padding='VALID',
scope='MaxPool_1a_3x3')
net = tf.concat([tower_conv_1, tower_conv1_1,
tower_conv2_2, tower_pool], 3)
return net
def inference(images, keep_probability, phase_train=True,
bottleneck_layer_size=128, weight_decay=0.0, reuse=None):
batch_norm_params = {
# Decay for the moving averages.
'decay': 0.995,
# epsilon to prevent 0s in variance.
'epsilon': 0.001,
# force in-place updates of mean and variance estimates
'updates_collections': None,
# Moving averages ends up in the trainable variables collection
'variables_collections': [ tf.GraphKeys.TRAINABLE_VARIABLES ],
}
with slim.arg_scope([slim.conv2d, slim.fully_connected],
weights_initializer=tf.truncated_normal_initializer(stddev=0.1),
weights_regularizer=slim.l2_regularizer(weight_decay),
normalizer_fn=slim.batch_norm,
normalizer_params=batch_norm_params):
return inception_resnet_v1(images, is_training=phase_train,
dropout_keep_prob=keep_probability, bottleneck_layer_size=bottleneck_layer_size, reuse=reuse)
def inception_resnet_v1(inputs, is_training=True,
dropout_keep_prob=0.8,
bottleneck_layer_size=128,
reuse=None,
scope='InceptionResnetV1'):
"""
Creates the Inception Resnet V1 model.
**Parameters**
inputs:
a 4-D tensor of size [batch_size, height, width, 3].
num_classes:
number of predicted classes.
is_training:
whether is training or not.
dropout_keep_prob:
the fraction to keep before final layer.
reuse:
whether or not the network and its variables should be reused. To be able to reuse 'scope' must be given.
scope:
Optional variable_scope.
"""
end_points = {}
with tf.variable_scope(scope, 'InceptionResnetV1', [inputs], reuse=reuse):
with slim.arg_scope([slim.batch_norm, slim.dropout],
is_training=is_training):
with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
stride=1, padding='SAME'):
# 149 x 149 x 32
net = slim.conv2d(inputs, 32, 3, stride=2, padding='VALID',
scope='Conv2d_1a_3x3')
end_points['Conv2d_1a_3x3'] = net
# 147 x 147 x 32
net = slim.conv2d(net, 32, 3, padding='VALID',
scope='Conv2d_2a_3x3')
end_points['Conv2d_2a_3x3'] = net
# 147 x 147 x 64
net = slim.conv2d(net, 64, 3, scope='Conv2d_2b_3x3')
end_points['Conv2d_2b_3x3'] = net
# 73 x 73 x 64
net = slim.max_pool2d(net, 3, stride=2, padding='VALID',
scope='MaxPool_3a_3x3')
end_points['MaxPool_3a_3x3'] = net
# 73 x 73 x 80
net = slim.conv2d(net, 80, 1, padding='VALID',
scope='Conv2d_3b_1x1')
end_points['Conv2d_3b_1x1'] = net
# 71 x 71 x 192
net = slim.conv2d(net, 192, 3, padding='VALID',
scope='Conv2d_4a_3x3')
end_points['Conv2d_4a_3x3'] = net
# 35 x 35 x 256
net = slim.conv2d(net, 256, 3, stride=2, padding='VALID',
scope='Conv2d_4b_3x3')
end_points['Conv2d_4b_3x3'] = net
# 5 x Inception-resnet-A
net = slim.repeat(net, 5, block35, scale=0.17)
end_points['Mixed_5a'] = net
# Reduction-A
with tf.variable_scope('Mixed_6a'):
net = reduction_a(net, 192, 192, 256, 384)
end_points['Mixed_6a'] = net
# 10 x Inception-Resnet-B
net = slim.repeat(net, 10, block17, scale=0.10)
end_points['Mixed_6b'] = net