Unit tests

parent d44b8012
......@@ -11,6 +11,8 @@ import bob.measure
from tensorflow.core.framework import summary_pb2
from scipy.spatial.distance import cosine
from bob.learn.tensorflow.datashuffler import Memory, Disk
class ExperimentAnalizer:
"""
......@@ -55,35 +57,44 @@ class ExperimentAnalizer:
self.network = network
self.session = session
# Getting the base class. Recipe extracted from
# http://stackoverflow.com/questions/5516263/creating-an-object-from-a-base-class-object-in-python/5516330#5516330
if isinstance(data_shuffler, Memory):
base_data_shuffler = object.__new__(Memory)
base_data_shuffler.__dict__ = data_shuffler.__dict__.copy()
else:
base_data_shuffler = object.__new__(Disk)
base_data_shuffler.__dict__ = data_shuffler.__dict__.copy()
# Extracting features for enrollment
enroll_data, enroll_labels = self.data_shuffler.get_batch()
enroll_data, enroll_labels = base_data_shuffler.get_batch()
enroll_features = self.network(enroll_data, session=self.session)
del enroll_data
# Extracting features for probing
probe_data, probe_labels = self.data_shuffler.get_batch()
probe_data, probe_labels = base_data_shuffler.get_batch()
probe_features = self.network(probe_data, session=self.session)
del probe_data
# Creating models
models = []
for i in range(len(self.data_shuffler.possible_labels)):
for i in range(len(base_data_shuffler.possible_labels)):
indexes_model = numpy.where(enroll_labels == self.data_shuffler.possible_labels[i])[0]
models.append(numpy.mean(enroll_features[indexes_model, :], axis=0))
# Probing
positive_scores = numpy.zeros(shape=0)
negative_scores = numpy.zeros(shape=0)
for i in range(len(self.data_shuffler.possible_labels)):
for i in range(len(base_data_shuffler.possible_labels)):
#for i in self.data_shuffler.possible_labels:
# Positive scoring
indexes = probe_labels == self.data_shuffler.possible_labels[i]
indexes = probe_labels == base_data_shuffler.possible_labels[i]
positive_data = probe_features[indexes, :]
p = [cosine(models[i], positive_data[j]) for j in range(positive_data.shape[0])]
positive_scores = numpy.hstack((positive_scores, p))
# negative scoring
indexes = probe_labels != self.data_shuffler.possible_labels[i]
indexes = probe_labels != base_data_shuffler.possible_labels[i]
negative_data = probe_features[indexes, :]
n = [cosine(models[i], negative_data[j]) for j in range(negative_data.shape[0])]
negative_scores = numpy.hstack((negative_scores, n))
......
......@@ -80,7 +80,7 @@ class Disk(Base):
for i in range(self.batch_size):
file_name = self.data[indexes[i]]
data = self.load_from_file(file_name, self.shape)
data = self.load_from_file(file_name)
selected_data[i, ...] = data
if self.scale:
......
......@@ -68,8 +68,8 @@ class SiameseDisk(Siamese, Disk):
genuine = True
for i in range(self.shape[0]):
file_name, file_name_p = self.get_genuine_or_not(self.data, self.labels, genuine=genuine)
data[i, ...] = self.load_from_file(str(file_name), self.shape)
data_p[i, ...] = self.load_from_file(str(file_name_p), self.shape)
data[i, ...] = self.load_from_file(str(file_name))
data_p[i, ...] = self.load_from_file(str(file_name_p))
labels_siamese[i] = not genuine
genuine = not genuine
......
......@@ -71,9 +71,9 @@ class TripletDisk(Triplet, Disk):
for i in range(self.shape[0]):
file_name_a, file_name_p, file_name_n = self.get_one_triplet(self.data, self.labels)
data_a[i, ...] = self.load_from_file(str(file_name_a), self.shape)
data_p[i, ...] = self.load_from_file(str(file_name_p), self.shape)
data_n[i, ...] = self.load_from_file(str(file_name_n), self.shape)
data_a[i, ...] = self.load_from_file(str(file_name_a))
data_p[i, ...] = self.load_from_file(str(file_name_p))
data_n[i, ...] = self.load_from_file(str(file_name_n))
if self.scale:
data_a *= self.scale_value
......
......@@ -30,10 +30,19 @@ class Constant(Initialization):
def __call__(self, shape, name):
initializer = tf.constant(self.constant_value, shape=shape)
try:
with tf.variable_scope(name):
if self.use_gpu:
with tf.device("/gpu:0"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
else:
with tf.device("/cpu"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
except ValueError:
with tf.variable_scope(name, reuse=True):
if self.use_gpu:
with tf.device("/gpu:0"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
else:
with tf.device("/cpu"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
......@@ -36,6 +36,8 @@ class Gaussian(Initialization):
stddev=self.std,
seed=self.seed)
try:
with tf.variable_scope(name):
if self.use_gpu:
with tf.device("/gpu:0"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
......@@ -43,4 +45,12 @@ class Gaussian(Initialization):
with tf.device("/cpu"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
except ValueError:
with tf.variable_scope(name, reuse=True):
if self.use_gpu:
with tf.device("/gpu:0"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
else:
with tf.device("/cpu"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
......@@ -38,11 +38,20 @@ class SimplerXavier(Initialization):
initializer = tf.truncated_normal(shape, stddev=stddev, seed=self.seed)
try:
with tf.variable_scope(name):
if self.use_gpu:
with tf.device("/gpu:0"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
else:
with tf.device("/cpu"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
except ValueError:
with tf.variable_scope(name, reuse=True):
if self.use_gpu:
with tf.device("/gpu:0"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
else:
with tf.device("/cpu"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
......@@ -39,11 +39,20 @@ class Xavier(Initialization):
initializer = tf.truncated_normal(shape, stddev=stddev, seed=self.seed)
try:
with tf.variable_scope(name):
if self.use_gpu:
with tf.device("/gpu:0"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
else:
with tf.device("/cpu"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
except ValueError:
with tf.variable_scope(name, reuse=True):
if self.use_gpu:
with tf.device("/gpu:0"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
else:
with tf.device("/cpu"):
return tf.get_variable(name, initializer=initializer, dtype=tf.float32)
......@@ -60,13 +60,13 @@ class MLP(SequenceNetwork):
for i in range(len(hidden_layers)):
l = hidden_layers[i]
self.add(FullyConnected(name="fc{0}".format(i),
self.add(FullyConnected(name="mlp_fc{0}".format(i),
output_dim=l,
activation=hidden_activation,
weights_initialization=weights_initialization,
bias_initialization=bias_initialization))
self.add(FullyConnected(name="fc_output",
self.add(FullyConnected(name="mlp_fc_output",
output_dim=output_shape,
activation=output_activation,
weights_initialization=weights_initialization,
......
......@@ -118,71 +118,6 @@ class SequenceNetwork(six.with_metaclass(abc.ABCMeta, object)):
return variables
def save(self, hdf5, step=None):
"""Save the state of the network in HDF5 format
**Parameters**
hdf5: An opened :py:class:`bob.io.base.HDF5File`
step: The current training step. If not `None`, will create a HDF5 group with the current step.
"""
# Directory that stores the tensorflow variables
hdf5.create_group('/tensor_flow')
hdf5.cd('/tensor_flow')
if step is not None:
group_name = '/step_{0}'.format(step)
hdf5.create_group(group_name)
hdf5.cd(group_name)
# Iterating the variables of the model
for v in self.dump_variables().keys():
hdf5.set(v, self.dump_variables()[v].eval())
hdf5.cd('..')
if step is not None:
hdf5.cd('..')
hdf5.set('input_divide', self.input_divide)
hdf5.set('input_subtract', self.input_subtract)
def load(self, hdf5, shape, session=None):
"""Load the network
**Parameters**
hdf5: The saved network in the :py:class:`bob.io.base.HDF5File` format
shape: Input shape of the network
session: tensorflow `session <https://www.tensorflow.org/versions/r0.11/api_docs/python/client.html#Session>`_
"""
if session is None:
session = tf.Session()
# Loading the normalization parameters
self.input_divide = hdf5.read('input_divide')
self.input_subtract = hdf5.read('input_subtract')
# Loading variables
place_holder = tf.placeholder(tf.float32, shape=shape, name="load")
self.compute_graph(place_holder)
tf.initialize_all_variables().run(session=session)
hdf5.cd('/tensor_flow')
for k in self.sequence_net:
# TODO: IT IS NOT SMART TESTING ALONG THIS PAGE
if not isinstance(self.sequence_net[k], MaxPooling):
#self.sequence_net[k].W.assign(hdf5.read(self.sequence_net[k].W.name))
self.sequence_net[k].W.assign(hdf5.read(self.sequence_net[k].W.name)).eval(session=session)
session.run(self.sequence_net[k].W)
self.sequence_net[k].b.assign(hdf5.read(self.sequence_net[k].b.name)).eval(session=session)
session.run(self.sequence_net[k].b)
def variable_summaries(self, var, name):
"""Attach a lot of summaries to a Tensor."""
with tf.name_scope('summaries'):
......@@ -248,40 +183,113 @@ class SequenceNetwork(six.with_metaclass(abc.ABCMeta, object)):
# self.saver = tf.train.Saver(variables)
#self.saver.restore(session, path)
def save(self, hdf5, step=None):
"""
Save the state of the network in HDF5 format
**Parameters**
hdf5: An opened :py:class:`bob.io.base.HDF5File`
step: The current training step. If not `None`, will create a HDF5 group with the current step.
"""
def save(self, session, path, step=None):
if self.saver is None:
variables = self.dump_variables()
variables['mean'] = tf.Variable(10.0)
#import ipdb; ipdb.set_trace()
def create_groups(path):
split_path = path.split("/")
for i in range(0, len(split_path)-1):
p = split_path[i]
hdf5.create_group(p)
tf.initialize_all_variables().run()
self.saver = tf.train.Saver(variables)
# Directory that stores the tensorflow variables
hdf5.create_group('/tensor_flow')
hdf5.cd('/tensor_flow')
if step is None:
return self.saver.save(session, os.path.join(path, "model.ckpt"))
else:
return self.saver.save(session, os.path.join(path, "model" + str(step) + ".ckpt"))
if step is not None:
group_name = '/step_{0}'.format(step)
hdf5.create_group(group_name)
hdf5.cd(group_name)
# Iterating the variables of the model
for v in self.dump_variables().keys():
create_groups(v)
hdf5.set(v, self.dump_variables()[v].eval())
hdf5.cd('..')
if step is not None:
hdf5.cd('..')
def load(self, path, shape, session=None):
hdf5.set('input_divide', self.input_divide)
hdf5.set('input_subtract', self.input_subtract)
def load(self, hdf5, shape, session=None):
"""
Load the network
**Parameters**
hdf5: The saved network in the :py:class:`bob.io.base.HDF5File` format
shape: Input shape of the network
session: tensorflow `session <https://www.tensorflow.org/versions/r0.11/api_docs/python/client.html#Session>`_
"""
if session is None:
session = tf.Session()
# Loading the normalization parameters
self.input_divide = hdf5.read('input_divide')
self.input_subtract = hdf5.read('input_subtract')
# Loading variables
place_holder = tf.placeholder(tf.float32, shape=shape, name="load")
self.compute_graph(place_holder)
tf.initialize_all_variables().run(session=session)
hdf5.cd('/tensor_flow')
for k in self.sequence_net:
# TODO: IT IS NOT SMART TESTING ALONG THIS PAGE
if not isinstance(self.sequence_net[k], MaxPooling):
#self.sequence_net[k].W.assign(hdf5.read(self.sequence_net[k].W.name))
self.sequence_net[k].W.assign(hdf5.read(self.sequence_net[k].W.name)).eval(session=session)
session.run(self.sequence_net[k].W)
self.sequence_net[k].b.assign(hdf5.read(self.sequence_net[k].b.name)).eval(session=session)
session.run(self.sequence_net[k].b)
"""
def save(self, session, path, step=None):
if self.saver is None:
variables = self.dump_variables()
variables['input_divide'] = self.input_divide
variables['input_subtract'] = self.input_subtract
self.saver = tf.train.Saver(variables)
#variables = self.dump_variables()
#variables['mean'] = tf.Variable(10.0)
#import ipdb; ipdb.set_trace()
#tf.initialize_all_variables().run()
self.saver = tf.train.Saver(session)
if step is None:
return self.saver.save(session, path)
else:
return self.saver.save(session, path)
def load(self, path, session=None):
if session is None:
session = tf.Session()
#tf.initialize_all_variables().run(session=session)
# Loading variables
#place_holder = tf.placeholder(tf.float32, shape=shape, name="load")
#self.compute_graph(place_holder)
#tf.initialize_all_variables().run(session=session)
#if self.saver is None:
#variables = self.dump_variables()
#variables['input_divide'] = self.input_divide
#variables['input_subtract'] = self.input_subtract
#self.saver = tf.train.Saver(variables)
self.saver.restore(session, path)
"""
\ No newline at end of file
......@@ -22,12 +22,13 @@ from docopt import docopt
import tensorflow as tf
from .. import util
SEED = 10
from bob.learn.tensorflow.data import MemoryDataShuffler, TextDataShuffler
from bob.learn.tensorflow.datashuffler import SiameseMemory
from bob.learn.tensorflow.network import Lenet, MLP, LenetDropout, VGG, Chopra, Dummy
from bob.learn.tensorflow.trainers import SiameseTrainer
from bob.learn.tensorflow.loss import ContrastiveLoss
import numpy
def main():
args = docopt(__doc__, version='Mnist training with TensorFlow')
......@@ -39,105 +40,40 @@ def main():
perc_train = 0.9
# Loading data
mnist = True
if mnist:
train_data, train_labels, validation_data, validation_labels = \
util.load_mnist(data_dir="./src/bob.db.mnist/bob/db/mnist/")
train_data = numpy.reshape(train_data, (train_data.shape[0], 28, 28, 1))
validation_data = numpy.reshape(validation_data, (validation_data.shape[0], 28, 28, 1))
train_data_shuffler = MemoryDataShuffler(train_data, train_labels,
train_data_shuffler = SiameseMemory(train_data, train_labels,
input_shape=[28, 28, 1],
scale=True,
batch_size=BATCH_SIZE)
validation_data_shuffler = MemoryDataShuffler(validation_data, validation_labels,
validation_data_shuffler = SiameseMemory(validation_data, validation_labels,
input_shape=[28, 28, 1],
scale=True,
batch_size=VALIDATION_BATCH_SIZE)
else:
import bob.db.mobio
db_mobio = bob.db.mobio.Database()
import bob.db.casia_webface
db_casia = bob.db.casia_webface.Database()
# Preparing train set
train_objects = db_casia.objects(groups="world")
#train_objects = db.objects(groups="world")
train_labels = [int(o.client_id) for o in train_objects]
directory = "/idiap/resource/database/CASIA-WebFace/CASIA-WebFace"
train_file_names = [o.make_path(
directory=directory,
extension="")
for o in train_objects]
#import ipdb;
#ipdb.set_trace();
#train_file_names = [o.make_path(
# directory="/idiap/group/biometric/databases/orl",
# extension=".pgm")
# for o in train_objects]
train_data_shuffler = TextDataShuffler(train_file_names, train_labels,
input_shape=[250, 250, 3],
batch_size=BATCH_SIZE)
#train_data_shuffler = TextDataShuffler(train_file_names, train_labels,
# input_shape=[56, 46, 1],
# batch_size=BATCH_SIZE)
# Preparing train set
directory = "/idiap/temp/tpereira/DEEP_FACE/CASIA/preprocessed"
validation_objects = db_mobio.objects(protocol="male", groups="dev")
validation_labels = [o.client_id for o in validation_objects]
#validation_file_names = [o.make_path(
# directory="/idiap/group/biometric/databases/orl",
# extension=".pgm")
# for o in validation_objects]
validation_file_names = [o.make_path(
directory=directory,
extension=".hdf5")
for o in validation_objects]
validation_data_shuffler = TextDataShuffler(validation_file_names, validation_labels,
input_shape=[250, 250, 3],
batch_size=VALIDATION_BATCH_SIZE)
#validation_data_shuffler = TextDataShuffler(validation_file_names, validation_labels,
# input_shape=[56, 46, 1],
# batch_size=VALIDATION_BATCH_SIZE)
# Preparing the architecture
n_classes = len(train_data_shuffler.possible_labels)
#n_classes = 50
cnn = True
if cnn:
# LENET PAPER CHOPRA
architecture = Chopra(seed=SEED, fc1_output=n_classes)
#architecture = Lenet(default_feature_layer="fc2", n_classes=n_classes, conv1_output=8, conv2_output=16,use_gpu=USE_GPU)
#architecture = VGG(n_classes=n_classes, use_gpu=USE_GPU)
#architecture = Dummy(seed=SEED)
#architecture = LenetDropout(default_feature_layer="fc2", n_classes=n_classes, conv1_output=4, conv2_output=8, use_gpu=USE_GPU)
loss = ContrastiveLoss(contrastive_margin=4.)
optimizer = tf.train.GradientDescentOptimizer(0.000001)
#optimizer = tf.train.GradientDescentOptimizer(0.000001)
trainer = SiameseTrainer(architecture=architecture,
loss=loss,
iterations=ITERATIONS,
snapshot=VALIDATION_TEST,
optimizer=optimizer,
prefetch=True,
prefetch=False,
temp_dir="./LOGS/siamese-cnn-prefetch")
#import ipdb; ipdb.set_trace();
trainer.train(train_data_shuffler, validation_data_shuffler)
#trainer.train(train_data_shuffler)
else:
mlp = MLP(n_classes, hidden_layers=[15, 20])
......
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# @author: Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
# @date: Thu 13 Oct 2016 13:35 CEST
import numpy
from bob.learn.tensorflow.datashuffler import Memory, SiameseMemory, TripletMemory, Disk, SiameseDisk, TripletDisk
from bob.learn.tensorflow.network import Chopra, MLP
from bob.learn.tensorflow.loss import BaseLoss, ContrastiveLoss, TripletLoss
from bob.learn.tensorflow.trainers import Trainer, SiameseTrainer, TripletTrainer
# from ..analyzers import ExperimentAnalizer, SoftmaxAnalizer
from bob.learn.tensorflow.util import load_mnist
import tensorflow as tf
import bob.io.base
import os
import shutil
from scipy.spatial.distance import cosine
import bob.measure
"""
Some unit tests for the datashuffler
"""
batch_size = 16
validation_batch_size = 400
iterations = 50
seed = 10
def dummy_experiment(data_s, architecture, session):
"""
Create a dummy experiment and return the EER
"""
data_shuffler = object.__new__(Memory)
data_shuffler.__dict__ = data_s.__dict__.copy()
# Extracting features for enrollment
enroll_data, enroll_labels = data_shuffler.get_batch()
enroll_features = architecture(enroll_data, session=session)
del enroll_data
# Extracting features for probing
probe_data, probe_labels = data_shuffler.get_batch()
probe_features = architecture(probe_data, session=session)
del probe_data
# Creating models
models = []
for i in range(len(data_shuffler.possible_labels)):
indexes_model = numpy.where(enroll_labels == data_shuffler.possible_labels[i])[0]
models.append(numpy.mean(enroll_features[indexes_model, :], axis=0))
# Probing
positive_scores = numpy.zeros(shape=0)
negative_scores = numpy.zeros(shape=0)
for i in range(len(data_shuffler.possible_labels)):
# Positive scoring
indexes = probe_labels == data_shuffler.possible_labels[i]
positive_data = probe_features[indexes, :]
p = [cosine(models[i], positive_data[j]) for j in range(positive_data.shape[0])]
positive_scores = numpy.hstack((positive_scores, p))
# negative scoring
indexes = probe_labels != data_shuffler.possible_labels[i]
negative_data = probe_features[indexes, :]
n = [cosine(models[i], negative_data[j]) for j in range(negative_data.shape[0])]
negative_scores = numpy.hstack((negative_scores, n))
threshold = bob.measure.eer_threshold((-1) * negative_scores, (-1) * positive_scores)
far, frr = bob.measure.farfrr((-1) * negative_scores, (-1) * positive_scores, threshold)
return (far + frr) / 2.
def test_cnn_trainer():
train_data, train_labels, validation_data, validation_labels = load_mnist()
train_data = numpy.reshape(train_data, (train_data.shape[0], 28, 28, 1))
validation_data = numpy.reshape(validation_data, (validation_data.shape[0], 28, 28, 1))
# Creating datashufflers
train_data_shuffler = Memory(train_data, train_labels,
input_shape=[28, 28, 1],
batch_size=batch_size)
with tf.Session() as session:
directory = "./temp/cnn"
# Preparing the architecture
architecture = Chopra(seed=seed, fc1_output=10)
# Loss for the softmax
loss = BaseLoss(tf.nn.sparse_softmax_cross_entropy_with_logits, tf.reduce_mean)
# One graph trainer
trainer = Trainer(architecture=architecture,
loss=loss,
iterations=iterations,
analizer=None,
prefetch=False,
temp_dir=directory)
trainer.train(train_data_shuffler)
# Testing
validation_shape = [400, 28, 28, 1]
chopra = Chopra(seed=seed, fc1_output=10)
chopra.load(bob.io.base.HDF5File(os.path.join(directory, "model.hdf5")),
shape=validation_shape, session=session)
validation_data_shuffler = Memory(validation_data, validation_labels,
input_shape=[28, 28, 1],
batch_size=validation_batch_size)
[data, labels] = validation_data_shuffler.get_batch()
predictions = chopra(data, session=session)
accuracy = 100. * numpy.sum(numpy.argmax(predictions, 1) == labels) / predictions.shape[0]
# At least 80% of accuracy
assert accuracy > 80.
shutil.rmtree(directory)
def test_siamesecnn_trainer():
train_data, train_labels, validation_data, validation_labels = load_mnist()
train_data = numpy.reshape(train_data, (train_data.shape[0], 28, 28, 1))
validation_data = numpy.reshape(validation_data, (validation_data.shape[0], 28, 28, 1))
# Creating datashufflers
train_data_shuffler = SiameseMemory(train_data, train_labels,
input_shape=[28, 28, 1],
batch_size=batch_size)
validation_data_shuffler = SiameseMemory(validation_data, validation_labels,
input_shape=[28, 28, 1],
batch_size=validation_batch_size)
with tf.Session() as session:
directory = "./temp/siamesecnn"
# Preparing the architecture
architecture = Chopra(seed=seed, fc1_output=10)
# Loss for the Siamese
loss = ContrastiveLoss(contrastive_margin=4.)
# One graph trainer
trainer = SiameseTrainer(architecture=architecture,
loss=loss,
iterations=iterations,
prefetch=False,
analizer=None,
temp_dir=directory)