Commit 7b29ff1f authored by Manuel Günther's avatar Manuel Günther
Browse files

Finished documentation of algorithms

parent b590fed2
......@@ -15,7 +15,45 @@ import logging
logger = logging.getLogger("bob.bio.base")
class BIC (Algorithm):
"""Computes the Intrapersonal/Extrapersonal classifier using a generic feature type and feature comparison function"""
"""Computes the Intrapersonal/Extrapersonal classifier using a generic feature type and feature comparison function.
In this generic implementation, any distance or similarity vector that results as a comparison of two feature vectors can be used.
Currently two different versions are implemented: One with [MWP98]_ and one without (a generalization of [GW09]_) subspace projection of the features.
The implementation of the BIC training is taken from :ref:`bob.learn.linear <bob.learn.linear>`.
**Parameters:**
comparison_function : function
The function to compare the features in the original feature space.
For a given pair of features, this function is supposed to compute a vector of similarity (or distance) values.
In the easiest case, it just computes the element-wise difference of the feature vectors, but more difficult functions can be applied, and the function might be specialized for the features you put in.
maximum_training_pair_count : int or None
Limit the number of training image pairs to the given value, i.e., to avoid memory issues.
subspace_dimensions : (int, int) or None
A tuple of sizes of the intrapersonal and extrapersonal subspaces.
If given, subspace projection is performed (cf. [MWP98]_) and the subspace projection matrices are truncated to the given sizes.
If omitted, no subspace projection is performed (cf. [GW09]_).
uses_dffs : bool
Only valid, when ``subspace_dimensions`` are specified.
Use the *Distance From Feature Space* (DFFS) (cf. [MWP98]_) during scoring.
Use this flag with care!
read_function : function
A function to read a feature from :py:class:`bob.io.base.HDF5File`.
This function need to be appropriate to read the type of features that you are using.
By default, :py:func:`bob.bio.base.load` is used.
write_function : function
A function to write a feature to :py:class:`bob.io.base.HDF5File`.
This function is used to write the model and need to be appropriate to write the type of features that you are using.
By default, :py:func:`bob.bio.base.save` is used.
kwargs : ``key=value`` pairs
A list of keyword arguments directly passed to the :py:class:`Algorithm` base class constructor.
"""
def __init__(
self,
......@@ -59,17 +97,27 @@ class BIC (Algorithm):
self.M_E = None
def _sqr(self, x):
return x*x
def _trainset_for(self, pairs):
"""Computes the array containing the comparison results for the given set of image pairs."""
return numpy.vstack([self.comparison_function(f1, f2) for (f1, f2) in pairs])
def train_enroller(self, train_features, enroller_file):
"""Trains the IEC Tool, i.e., computes intrapersonal and extrapersonal subspaces"""
"""Trains the BIC by computing intra-personal and extra-personal subspaces.
First, two lists of pairs are computed, which contain intra-personal and extra-personal feature pairs, respectively.
Afterward, the comparison vectors are computed using the ``comparison_function`` specified in the constructor.
Finally, the :py:class:`bob.learn.linear.BICTrainer` is used to train a :py:class:`bob.learn.linear.BICMachine`.
**Parameters:**
train_features : [[object]]
A list of lists of feature vectors, which are used to train the BIC.
Each sub-list contains the features of one client.
enroller_file : str
A writable file, into which the resulting :py:class:`bob.learn.linear.BICMachine` will be written.
"""
# compute intrapersonal and extrapersonal pairs
logger.info(" -> Computing pairs")
......@@ -99,7 +147,15 @@ class BIC (Algorithm):
def load_enroller(self, enroller_file):
"""Reads the intrapersonal and extrapersonal mean and variance values"""
"""Reads the :py:class:`bob.learn.linear.BICMachine` from file.
The :py:attr:`bob.learn.linear.BICMachine.use_DFFS` will be overwritten by the ``use_dffs`` value specified in this class' constructor.
**Parameters:**
enroller_file : str
An existing file, from which the :py:class:`bob.learn.linear.BICMachine` will be read.
"""
self.bic_machine.load(bob.io.base.HDF5File(enroller_file, 'r'))
# to set this should not be required, but just in case
# you re-use a trained enroller file that hat different setup of use_DFFS
......@@ -107,13 +163,38 @@ class BIC (Algorithm):
def enroll(self, enroll_features):
"""Enrolls features by concatenating them"""
"""enroll(enroll_features) -> model
Enrolls the model by storing all given input features.
The features must be writable with the ``write_function`` defined in the constructor.
**Parameters:**
enroll_features : [object]
The list of projected features to enroll the model from.
**Returns:**
model : [object]
The enrolled model (which is identical to the input features).
"""
return enroll_features
def write_model(self, model, model_file):
"""Writes all features of the model into one HDF5 file, using the ``save_function`` specified in the constructor."""
hdf5 = bob.io.base.HDF5File(model_file, "w")
"""Writes all features of the model into one HDF5 file.
To write the features, the ``write_function`` specified in the constructor is employed.
**Parameters:**
model : [object]
The model to write, which is a list of features.
model_file : str or :py:class:`bob.io.base.HDF5File`
The file (open for writing) or a file name to write into.
"""
hdf5 = model_file if isinstance(model_file, bob.io.base.HDF5File) else bob.io.base.HDF5File(model_file, 'w')
for i, f in enumerate(model):
hdf5.create_group("Feature%d" % i)
hdf5.cd("Feature%d" % i)
......@@ -122,7 +203,22 @@ class BIC (Algorithm):
def read_model(self, model_file):
"""Loads all features of the model from the HDF5 file, using the ``load_function`` specified in the constructor."""
"""read_model(model_file) -> model
Reads all features of the model from the given HDF5 file.
To read the features, the ``read_function`` specified in the constructor is employed.
**Parameters:**
model_file : str or :py:class:`bob.io.base.HDF5File`
The file (open for reading) or the name of an existing file to read from.
**Returns:**
model : [object]
The read model, which is a list of features.
"""
hdf5 = bob.io.base.HDF5File(model_file)
i = 0
model = []
......@@ -135,12 +231,45 @@ class BIC (Algorithm):
def read_probe(self, probe_file):
"""Loads the probe feature from file, using the ``load_function`` specified in the constructor."""
"""read_probe(probe_file) -> probe
Reads the probe feature from the given HDF5 file.
To read the feature, the ``read_function`` specified in the constructor is employed.
**Parameters:**
probe_file : str or :py:class:`bob.io.base.HDF5File`
The file (open for reading) or the name of an existing file to read from.
**Returns:**
probe : object
The read probe, which is a feature.
"""
return self.read_function(bob.io.base.HDF5File(probe_file))
def score(self, model, probe):
"""Computes the IEC score for the given model and probe pair"""
"""score(model, probe) -> float
Computes the BIC score between the model and the probe.
First, the ``comparison_function`` is used to create the comparison vectors between all model features and the probe feature.
Then, a BIC score is computed for each comparison vector, and the BIC scores are fused using the :py:func:`model_fusion_function` defined in the :py:class:`Algorithm` base class.
**Parameters:**
model : [object]
The model storing all model features.
probe : object
The probe feature.
**Returns:**
score : float
A fused BIC similarity value between ``model`` and ``probe``.
"""
# compute average score for the models
scores = []
for i in range(len(model)):
......
......@@ -14,11 +14,43 @@ import logging
logger = logging.getLogger("bob.bio.base")
class LDA (Algorithm):
"""Computes linear discriminant analysis"""
"""Computes a linear discriminant analysis (LDA) on the given data, possibly after computing a principal component analysis (PCA).
This algorithm computes a LDA projection (:py:class:`bob.learn.linear.FisherLDATrainer`) on the given training features, projects the features to Fisher space and computes the distance of two projected features in Fisher space.
For example, the Fisher faces algorithm as proposed by [ZKC+98]_ can be run with this class.
Additionally, a PCA projection matrix can be computed beforehand, to reduce the dimensionality of the input vectors.
In that case, the finally stored projection matrix is the combination of the PCA and LDA projection.
**Parameters:**
lda_subspace_dimension : int or ``None``
If specified, the LDA subspace will be truncated to the given number of dimensions.
By default (``None``) it is limited to the number of classes in the training set - 1.
pca_subspace_dimentsion : int or float or ``None``
If specified, a combined PCA + LDA projection matrix will be computed.
If specified as ``int``, defines the number of eigenvectors used in the PCA projection matrix.
If specified as ``float`` (between 0 and 1), the number of eigenvectors is calculated such that the given percentage of variance is kept.
distance_function : function
A function taking two parameters and returns a float.
If ``uses_variances`` is set to ``True``, the function is provided with a third parameter, which is the vector of variances (aka. eigenvalues).
is_distance_function : bool
Set this flag to ``False`` if the given ``distance_function`` computes a similarity value (i.e., higher values are better)
use_variances : bool
If set to ``True``, the ``distance_function`` is provided with a third argument, which is the vector of variances (aka. eigenvalues).
kwargs : ``key=value`` pairs
A list of keyword arguments directly passed to the :py:class:`Algorithm` base class constructor.
"""
def __init__(
self,
lda_subspace_dimension = 0, # if set, the LDA subspace will be truncated to the given number of dimensions; by default it is limited to the number of classes in the training set
lda_subspace_dimension = None, # if set, the LDA subspace will be truncated to the given number of dimensions; by default it is limited to the number of classes in the training set
pca_subspace_dimension = None, # if set, a PCA subspace truncation is performed before applying LDA; might be integral or float
distance_function = scipy.spatial.distance.euclidean,
is_distance_function = True,
......@@ -44,7 +76,7 @@ class LDA (Algorithm):
# copy information
self.pca_subspace = pca_subspace_dimension
self.lda_subspace = lda_subspace_dimension
if self.pca_subspace and isinstance(self.pca_subspace, int) and self.lda_subspace and self.pca_subspace < self.lda_subspace:
if self.pca_subspace is not None and isinstance(self.pca_subspace, int) and self.lda_subspace and self.pca_subspace < self.lda_subspace:
raise ValueError("The LDA subspace is larger than the PCA subspace size. This won't work properly. Please check your setup!")
self.machine = None
......@@ -54,7 +86,7 @@ class LDA (Algorithm):
def _check_feature(self, feature, projected=False):
"""Checks that the features are appropriate"""
"""Checks that the features are appropriate."""
if not isinstance(feature, numpy.ndarray) or feature.ndim != 1 or feature.dtype != numpy.float64:
raise ValueError("The given feature is not appropriate")
index = 1 if projected else 0
......@@ -63,7 +95,7 @@ class LDA (Algorithm):
def _arrange_data(self, training_files):
"""Arranges the data to train the LDA projection matrix"""
"""Arranges the data to train the LDA projection matrix."""
data = []
for client_files in training_files:
# at least two files per client are required!
......@@ -93,7 +125,7 @@ class LDA (Algorithm):
break
self.pca_subspace = index
if self.lda_subspace and self.pca_subspace <= self.lda_subspace:
if self.lda_subspace is not None and self.pca_subspace <= self.lda_subspace:
logger.warn(" ... Extending the PCA subspace dimension from %d to %d", self.pca_subspace, self.lda_subspace + 1)
self.pca_subspace = self.lda_subspace + 1
else:
......@@ -110,7 +142,17 @@ class LDA (Algorithm):
def train_projector(self, training_features, projector_file):
"""Generates the LDA projection matrix from the given features (that are sorted by identity)"""
"""Generates the LDA or PCA+LDA projection matrix from the given features (that are sorted by identity).
**Parameters:**
training_features : [[1D :py:class:`numpy.ndarray`]]
A list of lists of 1D training arrays (vectors) to train the LDA projection matrix with.
Each sub-list contains the features of one client.
projector_file : str
A writable file, into which the LDA or PCA+LDA projection matrix (as a :py:class:`bob.learn.linear.Machine`) and the eigenvalues will be written.
"""
# check data
[self._check_feature(feature) for client_features in training_features for feature in client_features]
......@@ -126,14 +168,14 @@ class LDA (Algorithm):
data = self._perform_pca(pca_machine, data)
logger.info(" -> Training Linear Machine using LDA")
trainer = bob.learn.linear.FisherLDATrainer(strip_to_rank = (self.lda_subspace == 0))
trainer = bob.learn.linear.FisherLDATrainer(strip_to_rank = (self.lda_subspace is None))
self.machine, self.variances = trainer.train(data)
if self.lda_subspace:
if self.lda_subspace is not None:
self.machine.resize(self.machine.shape[0], self.lda_subspace)
self.variances = self.variances.copy()
self.variances.resize(self.lda_subspace)
if self.pca_subspace:
if self.pca_subspace is not None:
# compute combined PCA/LDA projection matrix
combined_matrix = numpy.dot(pca_machine.weights, self.machine.weights)
# set new weight matrix (and new mean vector) of novel machine
......@@ -148,7 +190,13 @@ class LDA (Algorithm):
def load_projector(self, projector_file):
"""Reads the LDA projection matrix from file"""
"""Reads the projection matrix and the eigenvalues from file.
**Parameters:**
projector_file : str
An existing file, from which the PCA or PCA+LDA projection matrix and the eigenvalues are read.
"""
# read LDA projector
hdf5 = bob.io.base.HDF5File(projector_file)
self.variances = hdf5.read("Eigenvalues")
......@@ -157,14 +205,40 @@ class LDA (Algorithm):
def project(self, feature):
"""Projects the data using the stored covariance matrix"""
"""project(feature) -> projected
Projects the given feature into Fisher space.
**Parameters:**
feature : 1D :py:class:`numpy.ndarray`
The 1D feature to be projected.
**Returns:**
projected : 1D :py:class:`numpy.ndarray`
The ``feature`` projected into Fisher space.
"""
self._check_feature(feature)
# Projects the data
return self.machine(feature)
def enroll(self, enroll_features):
"""Enrolls the model by storing all given input vectors"""
"""enroll(enroll_features) -> model
Enrolls the model by storing all given input vectors.
**Parameters:**
enroll_features : [1D :py:class:`numpy.ndarray`]
The list of projected features to enroll the model from.
**Returns:**
model : 2D :py:class:`numpy.ndarray`
The enrolled model.
"""
assert len(enroll_features)
[self._check_feature(feature, True) for feature in enroll_features]
# just store all the features
......@@ -172,7 +246,23 @@ class LDA (Algorithm):
def score(self, model, probe):
"""Computes the distance of the model to the probe using the distance function"""
"""score(model, probe) -> float
Computes the distance of the model to the probe using the distance function specified in the constructor.
**Parameters:**
model : 2D :py:class:`numpy.ndarray`
The model storing all enrollment features.
probe : 1D :py:class:`numpy.ndarray`
The probe feature vector in Fisher space.
**Returns:**
score : float
A similarity value between ``model`` and ``probe``
"""
self._check_feature(probe, True)
# return the negative distance (as a similarity measure)
if len(model.shape) == 2:
......
......@@ -14,10 +14,10 @@ import logging
logger = logging.getLogger("bob.bio.base")
class PCA (Algorithm):
"""Performs PCA on the given data.
"""Performs a principal component analysis (PCA) on the given data.
This algorithm computes a PCA projection (:py:class:`bob.learn.linear.PCATrainer`) on the given training features, projects the features to face space and computes the distance of two projected features in face space.
For eaxmple, the eigenface algorithm as proposed by [TP91]_ can be run with this class.
This algorithm computes a PCA projection (:py:class:`bob.learn.linear.PCATrainer`) on the given training features, projects the features to eigenspace and computes the distance of two projected features in eigenspace.
For example, the eigenface algorithm as proposed by [TP91]_ can be run with this class.
**Parameters:**
......@@ -35,6 +35,8 @@ class PCA (Algorithm):
use_variances : bool
If set to ``True``, the ``distance_function`` is provided with a third argument, which is the vector of variances (aka. eigenvalues).
kwargs : ``key=value`` pairs
A list of keyword arguments directly passed to the :py:class:`Algorithm` base class constructor.
"""
def __init__(
......@@ -190,7 +192,6 @@ class PCA (Algorithm):
score : float
A similarity value between ``model`` and ``probe``
"""
self._check_feature(probe, True)
# return the negative distance (as a similarity measure)
......
......@@ -15,7 +15,11 @@ logger = logging.getLogger("bob.bio.base")
class PLDA (Algorithm):
"""Tool chain for computing PLDA (over PCA-dimensionality reduced) features"""
"""Tool chain for computing PLDA (over PCA-dimensionality reduced) features
.. todo:: Add more documentation for the PLDA constructor, i.e., by explaining the parameters
"""
def __init__(
self,
......@@ -45,7 +49,7 @@ class PLDA (Algorithm):
INIT_SEED = INIT_SEED, # seed for initializing
INIT_F_METHOD = str(INIT_F_METHOD),
INIT_G_METHOD = str(INIT_G_METHOD),
INIT_S_METHOD =str(INIT_S_METHOD),
INIT_S_METHOD = str(INIT_S_METHOD),
multiple_probe_scoring = multiple_probe_scoring,
multiple_model_scoring = None
)
......
......@@ -11,7 +11,7 @@ class FileSelector:
It communicates with the database and provides lists of file names for all steps of the tool chain.
.. todo:: Find a way the this class' methods get correctly documented, instead of the :py:class:`bob.bio.base.Singleton` wrapper class.
.. todo:: Find a way that this class' methods get correctly documented, instead of the :py:class:`bob.bio.base.Singleton` wrapper class.
**Parameters:**
......
......@@ -246,7 +246,7 @@ autodoc_default_flags = ['members', 'inherited-members', 'show-inheritance']
# For inter-documentation mapping:
from bob.extension.utils import link_documentation
intersphinx_mapping = link_documentation(['python', 'numpy', 'bob.bio.face', 'bob.bio.speaker', 'bob.bio.gmm', 'bob.bio.video', 'bob.bio.csu', 'gridtk', 'bob.db.youtube'])
intersphinx_mapping = link_documentation(['python', 'numpy', 'bob.bio.face', 'bob.bio.speaker', 'bob.bio.gmm', 'bob.bio.video', 'bob.bio.csu', 'bob.bio.spear', 'gridtk', 'bob.db.youtube'])
def skip(app, what, name, obj, skip, options):
......
......@@ -185,6 +185,17 @@ These two functions are:
* ``score_for_multiple_probes(self, model, probes)``: By default, the average (or min, max, ...) of the scores for all probes are computed. **Override** this function in case you want different behavior.
Implemented Tools
-----------------
In this base class, only one feature extractor and some recognition algorithms are defined.
However, implementations of the base classes can be found in all of the ``bob.bio`` packages.
Here is a list of implementations:
* :ref:`bob.bio.base <bob.bio.base>` : :ref:`bob.bio.base.implemented`
.. todo:: complete this list, once the other packages are documented as well.
Databases
---------
......
.. _bob.bio.base.implemented:
=================================
Tools implemented in bob.bio.base
=================================
......@@ -16,6 +18,7 @@ Base Classes
bob.bio.base.database.DatabaseZT
bob.bio.base.grid.Grid
Implementations
~~~~~~~~~~~~~~~
......
......@@ -72,6 +72,8 @@ References
.. [ZKC+98] *W. Zhao, A. Krishnaswamy, R. Chellappa, D. Swets and J. Weng*. **Discriminant analysis of principal components for face recognition**, pages 73-85. Springer Verlag Berlin, 1998.
.. [Pri07] *S. J. D. Prince*. **Probabilistic linear discriminant analysis for inferences about identity**. Proceedings of the International Conference on Computer Vision. 2007.
.. [ESM+13] *L. El Shafey, Chris McCool, Roy Wallace and Sébastien Marcel*. **A scalable formulation of probabilistic linear discriminant analysis: applied to face recognition**. IEEE Transactions on Pattern Analysis and Machine Intelligence, 35(7):1788-1794, 7/2013.
.. [MWP98] *B. Moghaddam, W. Wahid and A. Pentland*. **Beyond eigenfaces: probabilistic matching for face recognition**. IEEE International Conference on Automatic Face and Gesture Recognition, pages 30-35. 1998.
.. [GW09] *M. Günther and R.P. Würtz*. **Face detection and recognition using maximum likelihood classifiers on Gabor graphs**. International Journal of Pattern Recognition and Artificial Intelligence, 23(3):433-461, 2009.
ToDo-List
=========
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment