From 1462fb0733ea83ff822c6c3f1aeb6f88623d7222 Mon Sep 17 00:00:00 2001 From: Andre Anjos <andre.anjos@idiap.ch> Date: Wed, 15 Jan 2014 11:57:33 +0100 Subject: [PATCH] Specialize this package to only contain Activation functors --- MANIFEST.in | 1 - README.rst | 14 +- buildout.cfg | 6 +- doc/guide.rst | 719 ------------------ doc/index.rst | 13 +- doc/py_api.rst | 4 +- setup.py | 39 +- xbob/learn/__init__.py | 2 + xbob/learn/activation/__init__.py | 2 + .../activation}/activation.cpp | 141 ++-- xbob/{ => learn/activation}/cleanup.h | 0 .../activation/identity.cpp} | 24 +- .../include/xbob.learn.activation/api.h | 292 +++++++ .../include/xbob.learn.activation/config.h | 14 + .../activation/linear.cpp} | 35 +- .../activation/logistic.cpp} | 25 +- xbob/learn/activation/main.cpp | 146 ++++ .../activation/mult_tanh.cpp} | 40 +- xbob/learn/activation/tanh.cpp | 99 +++ .../activation/test.py} | 135 +++- xbob/machine/__init__.py | 21 - xbob/machine/__linear__.py | 39 - xbob/machine/__mlp__.py | 48 -- xbob/machine/bic.cc | 127 ---- xbob/machine/cleanup.h | 37 - xbob/machine/externals.cpp | 70 -- xbob/machine/gabor.cc | 252 ------ xbob/machine/gaussian.cc | 88 --- xbob/machine/gmm.cc | 295 ------- xbob/machine/include/xbob.machine/api.h | 352 --------- xbob/machine/include/xbob.machine/config.h | 14 - xbob/machine/ivector.cc | 116 --- xbob/machine/jfa.cc | 240 ------ xbob/machine/kmeans.cc | 125 --- xbob/machine/linear.cpp | 646 ---------------- xbob/machine/linearscoring.cc | 148 ---- xbob/machine/machine.cc | 39 - xbob/machine/main.cpp | 159 ---- xbob/machine/mlp.cc | 252 ------ xbob/machine/plda.cc | 177 ----- xbob/machine/roll.cc | 106 --- xbob/machine/svm.cc | 284 ------- xbob/machine/tanh_activation.cpp | 99 --- xbob/machine/test_gaussian.py | 90 --- xbob/machine/test_gmm.py | 219 ------ xbob/machine/test_ivector.py | 156 ---- xbob/machine/test_jfa.py | 374 --------- xbob/machine/test_kmeans.py | 75 -- xbob/machine/test_linear.py | 225 ------ xbob/machine/test_linearscoring.py | 128 ---- xbob/machine/test_mlp.py | 277 ------- xbob/machine/test_mlp_machine.py | 98 --- xbob/machine/test_plda.py | 561 -------------- xbob/machine/test_roll.py | 44 -- xbob/machine/test_svm.py | 284 ------- xbob/machine/test_utils.py | 94 --- xbob/machine/test_wiener.py | 109 --- xbob/machine/test_ztnorm.py | 126 --- xbob/machine/version.cc | 42 - xbob/machine/wiener.cc | 85 --- xbob/machine/ztnorm.cc | 154 ---- 61 files changed, 818 insertions(+), 7808 deletions(-) delete mode 100644 doc/guide.rst create mode 100644 xbob/learn/__init__.py create mode 100644 xbob/learn/activation/__init__.py rename xbob/{machine => learn/activation}/activation.cpp (75%) rename xbob/{ => learn/activation}/cleanup.h (100%) rename xbob/{machine/identity_activation.cpp => learn/activation/identity.cpp} (85%) create mode 100644 xbob/learn/activation/include/xbob.learn.activation/api.h create mode 100644 xbob/learn/activation/include/xbob.learn.activation/config.h rename xbob/{machine/linear_activation.cpp => learn/activation/linear.cpp} (81%) rename xbob/{machine/logistic_activation.cpp => learn/activation/logistic.cpp} (84%) create mode 100644 xbob/learn/activation/main.cpp rename xbob/{machine/mult_tanh_activation.cpp => learn/activation/mult_tanh.cpp} (76%) create mode 100644 xbob/learn/activation/tanh.cpp rename xbob/{machine/test_activation.py => learn/activation/test.py} (53%) delete mode 100644 xbob/machine/__init__.py delete mode 100644 xbob/machine/__linear__.py delete mode 100644 xbob/machine/__mlp__.py delete mode 100644 xbob/machine/bic.cc delete mode 100644 xbob/machine/cleanup.h delete mode 100644 xbob/machine/externals.cpp delete mode 100644 xbob/machine/gabor.cc delete mode 100644 xbob/machine/gaussian.cc delete mode 100644 xbob/machine/gmm.cc delete mode 100644 xbob/machine/include/xbob.machine/api.h delete mode 100644 xbob/machine/include/xbob.machine/config.h delete mode 100644 xbob/machine/ivector.cc delete mode 100644 xbob/machine/jfa.cc delete mode 100644 xbob/machine/kmeans.cc delete mode 100644 xbob/machine/linear.cpp delete mode 100644 xbob/machine/linearscoring.cc delete mode 100644 xbob/machine/machine.cc delete mode 100644 xbob/machine/main.cpp delete mode 100644 xbob/machine/mlp.cc delete mode 100644 xbob/machine/plda.cc delete mode 100644 xbob/machine/roll.cc delete mode 100644 xbob/machine/svm.cc delete mode 100644 xbob/machine/tanh_activation.cpp delete mode 100644 xbob/machine/test_gaussian.py delete mode 100644 xbob/machine/test_gmm.py delete mode 100644 xbob/machine/test_ivector.py delete mode 100644 xbob/machine/test_jfa.py delete mode 100644 xbob/machine/test_kmeans.py delete mode 100644 xbob/machine/test_linear.py delete mode 100644 xbob/machine/test_linearscoring.py delete mode 100644 xbob/machine/test_mlp.py delete mode 100644 xbob/machine/test_mlp_machine.py delete mode 100644 xbob/machine/test_plda.py delete mode 100644 xbob/machine/test_roll.py delete mode 100644 xbob/machine/test_svm.py delete mode 100644 xbob/machine/test_utils.py delete mode 100644 xbob/machine/test_wiener.py delete mode 100644 xbob/machine/test_ztnorm.py delete mode 100644 xbob/machine/version.cc delete mode 100644 xbob/machine/wiener.cc delete mode 100644 xbob/machine/ztnorm.cc diff --git a/MANIFEST.in b/MANIFEST.in index 9de54f2..09ed020 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,3 @@ include LICENSE README.rst bootstrap.py buildout.cfg recursive-include doc conf.py *.rst recursive-include xbob *.cpp *.h -recursive-include xbob/machine/data *.* diff --git a/README.rst b/README.rst index 4f078f6..edd867c 100644 --- a/README.rst +++ b/README.rst @@ -2,12 +2,12 @@ .. Andre Anjos <andre.anjos@idiap.ch> .. Fri 13 Dec 2013 12:35:22 CET -================================= - Python bindings for bob.machine -================================= +========================================== + Python bindings for bob.learn.activation +========================================== -This package contains a set of Pythonic bindings for Bob's machine packages and -functionality. +This package contains a set of Pythonic bindings for Bob's machine Activation +functors. Installation ------------ @@ -31,7 +31,7 @@ Testing You can run a set of tests using the nose test runner:: - $ nosetests -sv xbob.machine + $ nosetests -sv xbob.learn.activation .. warning:: @@ -48,7 +48,7 @@ You can run our documentation tests using sphinx itself:: You can test overall test coverage with:: - $ nosetests --with-coverage --cover-package=xbob.machine + $ nosetests --with-coverage --cover-package=xbob.learn.activation The ``coverage`` egg must be installed for this to work properly. diff --git a/buildout.cfg b/buildout.cfg index 5877743..0bbc70e 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -3,8 +3,8 @@ ; Mon 16 Apr 08:29:18 2012 CEST [buildout] -parts = xbob.blitz xbob.io xbob.machine scripts -eggs = xbob.machine +parts = xbob.blitz xbob.io xbob.learn.activation scripts +eggs = xbob.learn.activation ipdb extensions = mr.developer auto-checkout = * @@ -26,7 +26,7 @@ recipe = xbob.buildout:develop setup = src/xbob.io eggs = xbob.blitz xbob.buildout xbob.extension -[xbob.machine] +[xbob.learn.activation] recipe = xbob.buildout:develop eggs = xbob.blitz xbob.io diff --git a/doc/guide.rst b/doc/guide.rst deleted file mode 100644 index 79c1551..0000000 --- a/doc/guide.rst +++ /dev/null @@ -1,719 +0,0 @@ -.. vim: set fileencoding=utf-8 : -.. Laurent El Shafey <Laurent.El-Shafey@idiap.ch> -.. Wed Mar 14 12:31:35 2012 +0100 -.. modified by Elie Khoury <elie.khoury@idiap.ch> -.. Mon May 06 15:50:20 2013 +0100 -.. -.. Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -********** - Machines -********** - -Machines are one of the core components of |project|. They represent -statistical models or other functions defined by parameters that can be learnt -or set by using :doc:`TutorialsTrainer`. Two examples of machines are -multi-layer perceptrons (MLPs) and Gaussian mixture models (GMMs). The -operation you normally expect from a machine is to be able to feed a feature -vector and extract the machine response or output for that input vector. It -works, in many ways, similarly to signal processing blocks. Different types of -machines will give you a different type of output. In this tutorial we examine -a few of the machines available in |project| and how to make use of them. Let's -start with the simplest of the machines: a -:py:class:`bob.machine.LinearMachine`. - -.. testsetup:: * - - import numpy - import bob - import tempfile - import os - - current_directory = os.path.realpath(os.curdir) - temp_dir = tempfile.mkdtemp(prefix='bob_doctest_') - os.chdir(temp_dir) - -Linear machine -============== - -This machine executes the simple operation :math:`y = \mathbf{W} x`, where -:math:`y` is the output vector, :math:`x` is the input vector and :math:`W` is -a matrix (2D array) stored in the machine. The input vector :math:`x` should be -composed of double-precision floating-point elements. The output will also be -in double-precision. Here is how to use a -:py:class:`bob.machine.LinearMachine`: - -.. doctest:: - - >>> W = numpy.array([[0.5, 0.5], [1.0, 1.0]], 'float64') - >>> W - array([[ 0.5, 0.5], - [ 1. , 1. ]]) - >>> machine = bob.machine.LinearMachine(W) - >>> machine.shape - (2, 2) - >>> x = numpy.array([0.3, 0.4], 'float64') - >>> y = machine(x) - >>> y - array([ 0.55, 0.55]) - -As was shown in the above example, the way to pass data through a machine is to -call its ``()`` operator. - -The first thing to notice about machines is that they can be stored and -retrieved in HDF5 files (for more details in manipulating HDF5 files, please -consult :doc:`TutorialsIO`). To save the before metioned machine to a file, -just use the machine's ``save`` command. Because several machines can be stored -on the same :py:class:`bob.io.HDF5File`, we let the user open the file and set -it up before the machine can write to it: - -.. doctest:: - - >>> myh5_file = bob.io.HDF5File('linear.hdf5', 'w') - >>> #do other operations on myh5_file to set it up, optionally - >>> machine.save(myh5_file) - >>> del myh5_file #close - -You can load the machine again in a similar way: - -.. doctest:: - - >>> myh5_file = bob.io.HDF5File('linear.hdf5') - >>> reloaded = bob.machine.LinearMachine(myh5_file) - >>> numpy.array_equal(machine.weights, reloaded.weights) - True - -The shape of a ``LinearMachine`` (see -:py:attr:`bob.machine.LinearMachine.shape`) indicates the size of the input -vector that is expected by this machine and the size of the output vector it -produces, in a tuple format like ``(input_size, output_size)``: - -.. doctest:: - - >>> machine.shape - (2, 2) - -A :py:class:`bob.machine.LinearMachine`` also supports pre-setting -normalization vectors that are applied to every input :math:`x`. You can set a -subtraction factor and a division factor, so that the actual input :math:`x'` -that is fed to the matrix :math:`W` is :math:`x' = (x - s) ./ d`. The variables -:math:`s` and :math:`d` are vectors that have to have the same size as the -input vector :math:`x`. The operator :math:`./` indicates an element-wise -division. By default, :math:`s := 0.0` and :math:`d := 1.0`. - -.. doctest:: - - >>> machine.input_subtract - array([ 0., 0.]) - >>> machine.input_divide - array([ 1., 1.]) - -To set a new value for :math:`s` or :math:`d` just assign the desired machine property: - -.. doctest:: - - >>> machine.input_subtract = numpy.array([0.5, 0.8]) - >>> machine.input_divide = numpy.array([2.0, 4.0]) - >>> y = machine(x) - >>> y - array([-0.15, -0.15]) - -.. note:: - - In the event you save a machine that has the subtraction and/or a division - factor set, the vectors are saved and restored automatically w/o user - intervention. - -You will find interesting ways to train a :py:class:`bob.machine.LinearMachine` -so they can do something useful for you at :doc:`TutorialsTrainer`. - -Neural networks: multi-layer perceptrons (MLP) -============================================== - -A `multi-layer perceptron -<http://en.wikipedia.org/wiki/Multilayer_perceptron>`_ (MLP) is a neural -network architecture that has some well-defined characteristics such as a -feed-forward structure. You can create a new MLP using one of the trainers -described at :doc:`TutorialsTrainer`. In this tutorial, we show only how to use -an MLP. To instantiate a new (uninitialized) :py:class:`bob.machine.MLP` pass -a shape descriptor as a :py:func:`tuple`. The shape parameter should contain -the input size as the first parameter and the output size as the last -parameter. The parameters in between define the number of neurons in the -hidden layers of the MLP. For example ``(3, 3, 1)`` defines an MLP with 3 -inputs, 1 single hidden layer with 3 neurons and 1 output, whereas a shape like -``(10, 5, 3, 2)`` defines an MLP with 10 inputs, 5 neurons in the first hidden -layer, 3 neurons in the second hidden layer and 2 outputs. Here is an example: - -.. doctest:: - - >>> mlp = bob.machine.MLP((3, 3, 2, 1)) - -As it is, the network is uninitialized. For the sake of demonstrating how to -use MLPs, let's set the weight and biases manually (we would normally use a -trainer for this): - -.. doctest:: - - >>> input_to_hidden0 = numpy.ones((3,3), 'float64') - >>> input_to_hidden0 - array([[ 1., 1., 1.], - [ 1., 1., 1.], - [ 1., 1., 1.]]) - >>> hidden0_to_hidden1 = 0.5*numpy.ones((3,2), 'float64') - >>> hidden0_to_hidden1 - array([[ 0.5, 0.5], - [ 0.5, 0.5], - [ 0.5, 0.5]]) - >>> hidden1_to_output = numpy.array([0.3, 0.2], 'float64').reshape(2,1) - >>> hidden1_to_output - array([[ 0.3], - [ 0.2]]) - >>> bias_hidden0 = numpy.array([-0.2, -0.3, -0.1], 'float64') - >>> bias_hidden0 - array([-0.2, -0.3, -0.1]) - >>> bias_hidden1 = numpy.array([-0.7, 0.2], 'float64') - >>> bias_hidden1 - array([-0.7, 0.2]) - >>> bias_output = numpy.array([0.5], 'float64') - >>> bias_output - array([ 0.5]) - >>> mlp.weights = (input_to_hidden0, hidden0_to_hidden1, hidden1_to_output) - >>> mlp.biases = (bias_hidden0, bias_hidden1, bias_output) - -At this point, a few things should be noted: - -1. Weights should **always** be 2D arrays, even if they are connecting 1 neuron - to many (or many to 1). You can use the NumPy_ ``reshape()`` array method - for this purpose as shown above -2. Biases should **always** be 1D arrays. -3. By default, MLPs use the :py:class:bob.machine.HyperbolicTangentActivation` - as activation function. There are currently 4 other activation functions - available in |project|: - - * The identity function: :py:class:`bob.machine.IdentityActivation`; - * The sigmoid function (also known as the `logistic function <http://mathworld.wolfram.com/SigmoidFunction.html>`_ function): :py:class:`bob.machine.LogisticActivation`; - * A scaled version of the hyperbolic tangent function: :py:class:`bob.machine.MultipliedHyperbolicTangentActivation`; and - * A scaled version of the identity activation: :py:class:`bob.machine.LinearActivation` - -Let's try changing all of the activation functions to a simpler one, just for -this example: - -.. doctest:: - - >>> mlp.hidden_activation = bob.machine.IdentityActivation() - >>> mlp.output_activation = bob.machine.IdentityActivation() - -Once the network weights and biases are set, we can feed forward an example -through this machine. This is done using the ``()`` operator, like for a -:py:class:`bob.machine.LinearMachine`: - -.. doctest:: - - >>> mlp(numpy.array([0.1, -0.1, 0.2], 'float64')) - array([ 0.33]) - -Support vector machines -======================= - -.. ifconfig:: not has_libsvm - - .. warning:: - - LIBSVM was not found when this documentation has been generated. - - -Support for Suuport Vecotor Machines (SVMs) is provided through the -:py:class:`bob.machine.SupportVector` machine in |project|. This is in fact a -bridge to `LIBSVM`_. The functionality of this bridge includes loading and -saving SVM data files and machine models, which you can produce or download -following the instructions found on `LIBSVM`_'s home page. |project| bindings -to `LIBSVM`_ do not allow you to explicitly set the machine's internal values. -You must use the associated trainer as explained in :doc:`TutorialsTrainer` to -generate a valid :py:class:`bob.machine.SupportVector`. Once you have followed -the instructions at :doc:`TutorialsTrainer`, you can come back to this page and -follow the remaining instructions here. - -.. note:: - - Our current ``svm`` object was trained with the file called `heart_scale`, - distributed with `LIBSVM`_ and `available here - <http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary/heart_scale>`_. - This dataset proposes a binary classification problem (i.e., 2 classes of - features to be discriminated). The number of features is 13. - -Our extensions to `LIBSVM`_ also allows you to feed data through a -:py:class:`bob.machine.SupportVector` using :py:class:`numpy.ndarray` objects -and collect results in that format. For the following lines, we assume you have -available a :py:class:`bob.machine.SupportVector` named ``svm``. (For this -example, the variable ``svm`` was generated from the ``heart_scale`` dataset -using the application ``svm-train`` with default parameters). - - -.. ifconfig:: has_libsvm - - .. testsetup:: svm - - import os - import bob - import numpy - - def F(m, f): - from pkg_resources import resource_filename - return resource_filename('bob.%s.test' % m, os.path.join('data', f)) - - heart_model = F('machine', 'heart.svmmodel') - - svm = bob.machine.SupportVector(heart_model) - - -.. ifconfig:: has_libsvm - - .. doctest:: svm - - >>> svm.shape - (13, 1) - - -.. ifconfig:: not has_libsvm - - .. code-block:: python - - >>> svm.shape - (13, 1) - - -To run a single example through the SVM, just use the ``()`` operator like -before: - - -.. ifconfig:: has_libsvm - - .. doctest:: svm - - >> svm(numpy.ones((13,), 'float64')) - 1 - >> svm(numpy.ones((10,13), 'float64')) - (1, 1, 1, 1, 1, 1, 1, 1, 1, 1) - -.. ifconfig:: not has_libsvm - - .. code-block:: python - - >> svm(numpy.ones((13,), 'float64')) - 1 - >> svm(numpy.ones((10,13), 'float64')) - (1, 1, 1, 1, 1, 1, 1, 1, 1, 1) - - -Visit the documentation for :py:class:`bob.machine.SupportVector` to find more -information about these bindings and methods you can call on such a machine. -Visit the documentation for :py:class:`bob.machine.SVMFile` for information on -loading `LIBSVM`_ data files direction into python and producing -:py:class:`numpy.ndarray` objects. - -Below is a quick example: Suppose the variable ``f`` contains an object of -type :py:class:`bob.machine.SVMFile`. Then, you could read data (and labels) -from the file like this: - -.. ifconfig:: has_libsvm - - .. testsetup:: svmfile - - import os - import numpy - import bob - - def F(m, f): - from pkg_resources import resource_filename - return resource_filename('bob.%s.test' % m, os.path.join('data', f)) - - heart_data = F('machine', 'heart.svmdata') - - f = bob.machine.SVMFile(heart_data) - - heart_model = F('machine', 'heart.svmmodel') - - svm = bob.machine.SupportVector(heart_model) - - -.. ifconfig:: has_libsvm - - .. doctest:: svmfile - - >>> labels, data = f.read_all() - >>> data = numpy.vstack(data) #creates a single 2D array - -.. ifconfig:: not has_libsvm - - .. code-block:: python - - >>> labels, data = f.read_all() - >>> data = numpy.vstack(data) #creates a single 2D array - - -Then you can throw the data into the ``svm`` machine you trained earlier like -this: - -.. ifconfig:: has_libsvm - - .. doctest:: svmfile - - >>> predicted_labels = svm(data) - -.. ifconfig:: not has_libsvm - - .. code-block:: python - - >>> predicted_labels = svm(data) - - -As a final note, if you decide to use our `LIBSVM`_ bindings for your -publication, be sure to also cite: - -.. code-block:: latex - - @article{CC01a, - author = {Chang, Chih-Chung and Lin, Chih-Jen}, - title = {{LIBSVM}: A library for support vector machines}, - journal = {ACM Transactions on Intelligent Systems and Technology}, - volume = {2}, - issue = {3}, - year = {2011}, - pages = {27:1--27:27}, - note = {Software available at \url{http://www.csie.ntu.edu.tw/~cjlin/libsvm}} - } - - -K-means machines -================ - -`k-means <http://en.wikipedia.org/wiki/K-means_clustering>`_ is a clustering -method which aims to partition a set of observations into :math:`k` clusters. -The `training` procedure is described in :doc:`TutorialsTrainer`. Otherwise, -it is possible to define a :py:class:`bob.io.KMeansMachine` as follows. - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> machine = bob.machine.KMeansMachine(2,3) # Two clusters with a feature dimensionality of 3 - >>> machine.means = numpy.array([[1,0,0],[0,0,1]], 'float64') # Defines the two clusters - -Then, given some input data, it is possible to determine to which cluster the -data is the closest as well as the min distance. - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> sample = numpy.array([2,1,-2], 'float64') - >>> print(machine.get_closest_mean(sample)) # Returns the index of the closest mean and the distance to it at the power of 2 - (0, 6.0) - - -Gaussian machines -================= - -The :py:class:`bob.machine.Gaussian` represents a `multivariate diagonal -Gaussian (or normal) distribution -<http://en.wikipedia.org/wiki/Multivariate_normal_distribution>`_. In this -context, a *diagonal* Gaussian refers to the covariance matrix of the -distribution being diagonal. When the covariance matrix is diagonal, each -variable in the distribution is independent of the others. - -Objects of this class are normally used as building blocks for more complex -:py:class:`bob.machine.GMMMachine` or GMM objects, but can also be used -individually. Here is how to create one multivariate diagonal Gaussian -distribution: - -.. doctest:: - - >>> g = bob.machine.Gaussian(2) #bi-variate diagonal normal distribution - >>> g.mean = numpy.array([0.3, 0.7], 'float64') - >>> g.mean - array([ 0.3, 0.7]) - >>> g.variance = numpy.array([0.2, 0.1], 'float64') - >>> g.variance - array([ 0.2, 0.1]) - -Once the :py:class:`bob.machine.Gaussian` has been set, you can use it to -estimate the log-likelihood of an input feature vector with a matching -number of dimensions: - -.. doctest:: - - >>> log_likelihood = g(numpy.array([0.4, 0.4], 'float64')) - -As with other machines you can save and re-load machines of this type using -:py:meth:`bob.machine.Gaussian.save` and the class constructor respectively. - -Gaussian mixture models -======================= - -The :py:class:`bob.machine.GMMMachine` represents a Gaussian `mixture model -<http://en.wikipedia.org/wiki/Mixture_model>`_ (GMM), which consists of a -mixture of weighted :py:class:`bob.machine.Gaussian`\s. - -.. doctest:: - - >>> gmm = bob.machine.GMMMachine(2,3) # Mixture of two diagonal Gaussian of dimension 3 - -By default, the diagonal Gaussian distributions of the GMM are initialized with -zero mean and unit variance, and the weights are identical. This can be updated -using the :py:attr:`bob.machine.GMMMachine.means`, -:py:attr:`bob.machine.GMMMachine.variances` or -:py:attr:`bob.machine.GMMMachine.weights`. - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> gmm.weights = numpy.array([0.4, 0.6], 'float64') - >>> gmm.means = numpy.array([[1, 6, 2], [4, 3, 2]], 'float64') - >>> gmm.variances = numpy.array([[1, 2, 1], [2, 1, 2]], 'float64') - >>> gmm.means - array([[ 1., 6., 2.], - [ 4., 3., 2.]]) - -Once the :py:class:`bob.machine.GMMMachine` has been set, you can use it to -estimate the log-likelihood of an input feature vector with a matching -number of dimensions: - -.. doctest:: - - >>> log_likelihood = gmm(numpy.array([5.1, 4.7, -4.9], 'float64')) - -As with other machines you can save and re-load machines of this type using -:py:meth:`bob.machine.GMMMachine.save` and the class constructor respectively. - - -Gaussian mixture models Statistics -================================== - -The :py:class:`bob.machine.GMMStats` is a container for the sufficient -statistics of a GMM distribution. - -Given a GMM, the sufficient statistics of a sample can be computed as -follows: - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> gs = bob.machine.GMMStats(2,3) - >>> sample = numpy.array([0.5, 4.5, 1.5]) - >>> gmm.acc_statistics(sample, gs) - >>> print(gs) # doctest: +SKIP - -Then, the sufficient statistics can be accessed (or set as below), by considering the -following attributes. - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> gs = bob.machine.GMMStats(2,3) - >>> log_likelihood = -3. # log-likelihood of the accumulated samples - >>> T = 1 # Number of samples used to accumulate statistics - >>> n = numpy.array([0.4, 0.6], 'float64') # zeroth order stats - >>> sumpx = numpy.array([[1., 2., 3.], [4., 5., 6.]], 'float64') # first order stats - >>> sumpxx = numpy.array([[10., 20., 30.], [40., 50., 60.]], 'float64') # second order stats - >>> gs.log_likelihood = log_likelihood - >>> gs.t = T - >>> gs.n = n - >>> gs.sum_px = sumpx - >>> gs.sum_pxx = sumpxx - - -Joint Factor Analysis -===================== - -Joint Factor Analysis (JFA) [1]_ [2]_ is a session variability modelling -technique built on top of the Gaussian mixture modelling approach. It utilises -a within-class subspace :math:`U`, a between-class subspace :math:`V`, and a -subspace for the residuals :math:`D` to capture and suppress a significant -portion of between-class variation. - -An instance of :py:class:`bob.machine.JFABase` carries information about the -matrices :math:`U`, :math:`V` and :math:`D`, which can be shared between -several classes. In contrast, after the enrolment phase, an instance of -:py:class:`bob.machine.JFAMachine` carries class-specific information about the -latent variables :math:`y` and :math:`z`. - -An instance of :py:class:`bob.machine.JFABase` can be initialized as follows, -given an existing GMM: - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> jfa_base = bob.machine.JFABase(gmm,2,2) # dimensions of U and V are both equal to 2 - >>> U = numpy.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]], 'float64') - >>> V = numpy.array([[6, 5], [4, 3], [2, 1], [1, 2], [3, 4], [5, 6]], 'float64') - >>> d = numpy.array([0, 1, 0, 1, 0, 1], 'float64') - >>> jfa_base.u = U - >>> jfa_base.v = V - >>> jfa_base.d = d - -Next, this :py:class:`bob.machine.JFABase` can be shared by several instances -of :py:class:`bob.machine.JFAMachine`, the initialization being as follows: - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> m = bob.machine.JFAMachine(jfa_base) - >>> m.y = numpy.array([1,2], 'float64') - >>> m.z = numpy.array([3,4,1,2,0,1], 'float64') - - -Once the :py:class:`bob.machine.JFAMachine` has been configured for a specific -class, the log-likelihood (score) that an input sample belongs to the enrolled -class, can be estimated, by first computing the GMM sufficient statistics of -this input sample, and then calling the -:py:meth:`bob.machine.JFAMachine:forward` on the sufficient statistics. - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> gs = bob.machine.GMMStats(2,3) - >>> gmm.acc_statistics(sample, gs) - >>> score = m.forward(gs) - -As with other machines you can save and re-load machines of this type using -:py:meth:`bob.machine.JFAMachine.save` and the class constructor respectively. - - -Inter-Session Variability -========================= - -Similarly to Joint Factor Analysis, Inter-Session Variability (ISV) modelling -[3]_ [2]_ is another session variability modelling technique built on top of -the Gaussian mixture modelling approach. It utilises a within-class subspace -:math:`U` and a subspace for the residuals :math:`D` to capture and suppress a -significant portion of between-class variation. The main difference compared to -JFA is the absence of the between-class subspace :math:`V`. - -Similarly to JFA, an instance of :py:class:`bob.machine.JFABase` carries -information about the matrices :math:`U` and :math:`D`, which can be shared -between several classes, whereas an instance of -:py:class:`bob.machine.JFAMachine` carries class-specific information about the -latent variable :math:`z`. - -An instance of :py:class:`bob.machine.ISVBase` can be initialized as follows, -given an existing GMM: - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> isv_base = bob.machine.ISVBase(gmm,2) # dimension of U is equal to 2 - >>> isv_base.u = U - >>> isv_base.d = d - -Next, this :py:class:`bob.machine.ISVBase` can be shared by several instances of -:py:class:`bob.machine.ISVMachine`, the initialization being as follows: - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> m = bob.machine.ISVMachine(isv_base) - >>> m.z = numpy.array([3,4,1,2,0,1], 'float64') - -Once the :py:class:`bob.machine.ISVMachine` has been configured for a specific -class, the log-likelihood (score) that an input sample belongs to the enrolled -class, can be estimated, by first computing the GMM sufficient statistics of -this input sample, and then calling the -:py:meth:`bob.machine.ISVMachine:forward` on the sufficient statistics. - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> gs = bob.machine.GMMStats(2,3) - >>> gmm.acc_statistics(sample, gs) - >>> score = m.forward(gs) - -As with other machines you can save and re-load machines of this type using -:py:meth:`bob.machine.ISVMachine.save` and the class constructor respectively. - - -Total Variability (i-vectors) -============================= - -Total Variability (TV) modelling [4]_ is a front-end initially introduced for -speaker recognition, which aims at describing samples by vectors of low -dimensionality called ``i-vectors``. The model consists of a subspace :math:`T` -and a residual diagonal covariance matrix :math:`\Sigma`, that are then used -to extract i-vectors, and is built upon the GMM approach. - -An instance of the class :py:class:`bob.machine.IVectorMachine` carries -information about these two matrices. This can be initialized as follows: - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> m = bob.machine.IVectorMachine(gmm, 2) - >>> m.t = numpy.array([[1.,2],[4,1],[0,3],[5,8],[7,10],[11,1]]) - >>> m.sigma = numpy.array([1.,2.,1.,3.,2.,4.]) - - -Once the :py:class:`bob.machine.IVectorMachine` has been set, the extraction -of an i-vector :math:`w_ij` can be done in two steps, by first extracting -the GMM sufficient statistics, and then estimating the i-vector: - -.. doctest:: - :options: +NORMALIZE_WHITESPACE - - >>> gs = bob.machine.GMMStats(2,3) - >>> gmm.acc_statistics(sample, gs) - >>> w_ij = m.forward(gs) - -As with other machines you can save and re-load machines of this type using -:py:meth:`bob.machine.IVectorMachine.save` and the class constructor respectively. - - -Probabilistic Linear Discriminant Analysis (PLDA) -================================================= - -Probabilistic Linear Discriminant Analysis [5]_ [6]_ is a probabilistic model -that incorporates components describing both between-class and within-class -variations. Given a mean :math:`\mu`, between-class and within-class subspaces -:math:`F` and :math:`G` and residual noise :math:`\epsilon` with zero mean and -diagonal covariance matrix :math:`\Sigma`, the model assumes that a sample -:math:`x_{i,j}` is generated by the following process: - -.. math:: - - x_{i,j} = \mu + F h_{i} + G w_{i,j} + \epsilon_{i,j} - -Information about a PLDA model (:math:`\mu`, :math:`F`, :math:`G` and -:math:`\Sigma`) are carried out by an instance of the class -:py:class:`bob.machine.PLDABase`. - -.. doctest:: - - >>> ### This creates a PLDABase container for input feature of dimensionality 3, - >>> ### and with subspaces F and G of rank 1 and 2 respectively. - >>> pldabase = bob.machine.PLDABase(3,1,2) - -Class-specific information (usually from enrollment samples) are contained in -an instance of :py:class:`bob.machine.PLDAMachine`, that must be attached to a -given :py:class:`bob.machine.PLDABase`. Once done, log-likelihood computations -can be performed. - -.. doctest:: - - >>> plda = bob.machine.PLDAMachine(pldabase) - >>> samples = numpy.array([[3.5,-3.4,102], [4.5,-4.3,56]], dtype=numpy.float64) - >>> loglike = plda.compute_log_likelihood(samples) - - -.. testcleanup:: * - - import shutil - os.chdir(current_directory) - shutil.rmtree(temp_dir) - -.. Place here your external references - -.. _numpy: http://numpy.scipy.org -.. _libsvm: http://www.csie.ntu.edu.tw/~cjlin/libsvm/ - -.. [1] http://dx.doi.org/10.1109/TASL.2006.881693 -.. [2] http://publications.idiap.ch/index.php/publications/show/2606 -.. [3] http://dx.doi.org/10.1016/j.csl.2007.05.003 -.. [4] http://dx.doi.org/10.1109/TASL.2010.2064307 -.. [5] http://dx.doi.org/10.1109/ICCV.2007.4409052 -.. [6] http://doi.ieeecomputersociety.org/10.1109/TPAMI.2013.38 diff --git a/doc/index.rst b/doc/index.rst index 12d5da1..51d9eee 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -4,13 +4,13 @@ .. .. Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland -============== - Bob Machines -============== +========================= + Bob Activation Functors +========================= -This module contains base functionality from Bob bound to Python, available in -the C++ counter-part ``bob::machine``. It includes machines from our Machine -Learning core. +This module contains some functionality from Bob bound to Python, available in +the C++ counter-part ``bob::machine``. It includes Activation functors from the +Machine Learning core. Reference --------- @@ -18,7 +18,6 @@ Reference .. toctree:: :maxdepth: 2 - guide py_api c_cpp_api diff --git a/doc/py_api.rst b/doc/py_api.rst index 53590a1..40eff59 100644 --- a/doc/py_api.rst +++ b/doc/py_api.rst @@ -7,8 +7,8 @@ ============ This section includes information for using the pure Python API of -``xbob.machine``. +``xbob.learn.activation``. -.. automodule:: xbob.machine +.. automodule:: xbob.learn.activation diff --git a/setup.py b/setup.py index 55dc65f..b07399d 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ import xbob.io import os package_dir = os.path.dirname(os.path.realpath(__file__)) -package_dir = os.path.join(package_dir, 'xbob', 'machine', 'include') +package_dir = os.path.join(package_dir, 'xbob', 'learn', 'activation', 'include') include_dirs = [package_dir, xbob.io.get_include()] packages = ['bob-machine >= 1.3'] @@ -18,10 +18,10 @@ version = '2.0.0a0' setup( - name='xbob.machine', + name='xbob.learn.activation', version=version, - description='Bindings for bob.machine', - url='http://github.com/anjos/xbob.machine', + description='Bindings for bob.machine\'s Activation functors', + url='http://github.com/anjos/xbob.learn.activation', license='BSD', author='Andre Anjos', author_email='andre.anjos@idiap.ch', @@ -39,27 +39,19 @@ setup( namespace_packages=[ "xbob", + "xbob.learn", ], ext_modules = [ - Extension("xbob.machine._externals", + Extension("xbob.learn.activation._library", [ - "xbob/machine/externals.cpp", - ], - packages = packages, - include_dirs = include_dirs, - version = version, - ), - Extension("xbob.machine._library", - [ - "xbob/machine/activation.cpp", - "xbob/machine/identity_activation.cpp", - "xbob/machine/linear_activation.cpp", - "xbob/machine/logistic_activation.cpp", - "xbob/machine/tanh_activation.cpp", - "xbob/machine/mult_tanh_activation.cpp", - "xbob/machine/linear.cpp", - "xbob/machine/main.cpp", + "xbob/learn/activation/activation.cpp", + "xbob/learn/activation/identity.cpp", + "xbob/learn/activation/linear.cpp", + "xbob/learn/activation/logistic.cpp", + "xbob/learn/activation/tanh.cpp", + "xbob/learn/activation/mult_tanh.cpp", + "xbob/learn/activation/main.cpp", ], packages = packages, include_dirs = include_dirs, @@ -67,11 +59,6 @@ setup( ), ], - entry_points={ - 'console_scripts': [ - ], - }, - classifiers = [ 'Development Status :: 3 - Alpha', 'Intended Audience :: Developers', diff --git a/xbob/learn/__init__.py b/xbob/learn/__init__.py new file mode 100644 index 0000000..60381ea --- /dev/null +++ b/xbob/learn/__init__.py @@ -0,0 +1,2 @@ +#see http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages +__import__('pkg_resources').declare_namespace(__name__) diff --git a/xbob/learn/activation/__init__.py b/xbob/learn/activation/__init__.py new file mode 100644 index 0000000..907b5a4 --- /dev/null +++ b/xbob/learn/activation/__init__.py @@ -0,0 +1,2 @@ +from ._library import * +from ._library import __version__, __api_version__ diff --git a/xbob/machine/activation.cpp b/xbob/learn/activation/activation.cpp similarity index 75% rename from xbob/machine/activation.cpp rename to xbob/learn/activation/activation.cpp index 1b2f856..df0b413 100644 --- a/xbob/machine/activation.cpp +++ b/xbob/learn/activation/activation.cpp @@ -7,9 +7,9 @@ * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland */ -#define XBOB_MACHINE_MODULE +#define XBOB_LEARN_ACTIVATION_MODULE #include "cleanup.h" -#include <xbob.machine/api.h> +#include <xbob.learn.activation/api.h> #include <xbob.io/api.h> #include <xbob.blitz/cppapi.h> #include <bob/machine/Activation.h> @@ -24,7 +24,7 @@ PyDoc_STRVAR(s_activation_str, XBOB_EXT_MODULE_PREFIX ".Activation"); PyDoc_STRVAR(s_activation_doc, -"Base class for activation functions (actually, *functors*).\n\ +"Base class for activation functors.\n\ \n\ .. warning::\n\ \n\ @@ -43,7 +43,8 @@ PyDoc_STRVAR(s_activation_doc, \n\ "); -static int PyBobMachineActivation_init(PyBobMachineActivationObject* self, PyObject*, PyObject*) { +static int PyBobLearnActivation_init(PyBobLearnActivationObject* self, + PyObject*, PyObject*) { PyErr_Format(PyExc_NotImplementedError, "cannot initialize object of base type `%s' - use one of the inherited classes", s_activation_str); return -1; @@ -98,7 +99,7 @@ static int apply(boost::function<double (double)> function, } -static PyObject* PyBobMachineActivation_call1(PyBobMachineActivationObject* o, +static PyObject* PyBobLearnActivation_call1(PyBobLearnActivationObject* o, double (bob::machine::Activation::*method) (double) const, PyObject* args, PyObject* kwds) { @@ -162,7 +163,7 @@ static PyObject* PyBobMachineActivation_call1(PyBobMachineActivationObject* o, } -static PyObject* PyBobMachineActivation_call2(PyBobMachineActivationObject* o, +static PyObject* PyBobLearnActivation_call2(PyBobLearnActivationObject* o, double (bob::machine::Activation::*method) (double) const, PyObject* args, PyObject* kwds) { @@ -248,7 +249,7 @@ error otherwise.\n\ \n\ "); -static PyObject* PyBobMachineActivation_call(PyBobMachineActivationObject* o, +static PyObject* PyBobLearnActivation_call(PyBobLearnActivationObject* o, PyObject* args, PyObject* kwds) { Py_ssize_t nargs = args?PyTuple_Size(args):0 + kwds?PyDict_Size(kwds):0; @@ -256,12 +257,12 @@ static PyObject* PyBobMachineActivation_call(PyBobMachineActivationObject* o, switch (nargs) { case 1: - return PyBobMachineActivation_call1 + return PyBobLearnActivation_call1 (o, &bob::machine::Activation::f, args, kwds); break; case 2: - return PyBobMachineActivation_call2 + return PyBobLearnActivation_call2 (o, &bob::machine::Activation::f, args, kwds); break; @@ -300,7 +301,7 @@ error otherwise.\n\ \n\ "); -static PyObject* PyBobMachineActivation_f_prime(PyBobMachineActivationObject* o, +static PyObject* PyBobLearnActivation_f_prime(PyBobLearnActivationObject* o, PyObject* args, PyObject* kwds) { Py_ssize_t nargs = args?PyTuple_Size(args):0 + kwds?PyDict_Size(kwds):0; @@ -308,12 +309,12 @@ static PyObject* PyBobMachineActivation_f_prime(PyBobMachineActivationObject* o, switch (nargs) { case 1: - return PyBobMachineActivation_call1 + return PyBobLearnActivation_call1 (o, &bob::machine::Activation::f_prime, args, kwds); break; case 2: - return PyBobMachineActivation_call2 + return PyBobLearnActivation_call2 (o, &bob::machine::Activation::f_prime, args, kwds); break; @@ -352,7 +353,7 @@ error otherwise.\n\ \n\ "); -static PyObject* PyBobMachineActivation_f_prime_from_f(PyBobMachineActivationObject* o, +static PyObject* PyBobLearnActivation_f_prime_from_f(PyBobLearnActivationObject* o, PyObject* args, PyObject* kwds) { Py_ssize_t nargs = args?PyTuple_Size(args):0 + kwds?PyDict_Size(kwds):0; @@ -360,12 +361,12 @@ static PyObject* PyBobMachineActivation_f_prime_from_f(PyBobMachineActivationObj switch (nargs) { case 1: - return PyBobMachineActivation_call1 + return PyBobLearnActivation_call1 (o, &bob::machine::Activation::f_prime_from_f, args, kwds); break; case 2: - return PyBobMachineActivation_call2 + return PyBobLearnActivation_call2 (o, &bob::machine::Activation::f_prime_from_f, args, kwds); break; @@ -388,7 +389,7 @@ in connection with the Activation registry.\n\ \n\ "); -static PyObject* PyBobMachineActivation_UniqueIdentifier (PyBobMachineActivationObject* o) { +static PyObject* PyBobLearnActivation_UniqueIdentifier (PyBobLearnActivationObject* o) { return Py_BuildValue("s", o->base->unique_identifier().c_str()); } @@ -400,7 +401,7 @@ Loads itself from a :py:class:`xbob.io.HDF5File`\n\ \n\ "); -static PyObject* PyBobMachineActivation_Load(PyBobMachineActivationObject* o, +static PyObject* PyBobLearnActivation_Load(PyBobLearnActivationObject* o, PyObject* f) { if (!PyBobIoHDF5File_Check(f)) { @@ -434,7 +435,7 @@ Loads itself from a :py:class:`xbob.io.HDF5File`\n\ \n\ "); -static PyObject* PyBobMachineActivation_Save(PyBobMachineActivationObject* o, +static PyObject* PyBobLearnActivation_Save(PyBobLearnActivationObject* o, PyObject* f) { if (!PyBobIoHDF5File_Check(f)) { @@ -460,59 +461,59 @@ static PyObject* PyBobMachineActivation_Save(PyBobMachineActivationObject* o, Py_RETURN_NONE; } -static PyMethodDef PyBobMachineActivation_methods[] = { +static PyMethodDef PyBobLearnActivation_methods[] = { { s_call_str, - (PyCFunction)PyBobMachineActivation_call, + (PyCFunction)PyBobLearnActivation_call, METH_VARARGS|METH_KEYWORDS, s_call_doc }, { s_f_prime_str, - (PyCFunction)PyBobMachineActivation_f_prime, + (PyCFunction)PyBobLearnActivation_f_prime, METH_VARARGS|METH_KEYWORDS, s_f_prime_doc }, { s_f_prime_from_f_str, - (PyCFunction)PyBobMachineActivation_f_prime_from_f, + (PyCFunction)PyBobLearnActivation_f_prime_from_f, METH_VARARGS|METH_KEYWORDS, s_f_prime_from_f_doc }, { s_unique_id_str, - (PyCFunction)PyBobMachineActivation_UniqueIdentifier, + (PyCFunction)PyBobLearnActivation_UniqueIdentifier, METH_NOARGS, s_unique_id_doc }, { s_load_str, - (PyCFunction)PyBobMachineActivation_Load, + (PyCFunction)PyBobLearnActivation_Load, METH_O, s_load_doc }, { s_save_str, - (PyCFunction)PyBobMachineActivation_Save, + (PyCFunction)PyBobLearnActivation_Save, METH_O, s_save_doc }, {0} /* Sentinel */ }; -int PyBobMachineActivation_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobMachineActivation_Type)); +int PyBobLearnActivation_Check(PyObject* o) { + return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnActivation_Type)); } -static PyObject* PyBobMachineActivation_RichCompare (PyBobMachineActivationObject* self, PyObject* other, int op) { +static PyObject* PyBobLearnActivation_RichCompare (PyBobLearnActivationObject* self, PyObject* other, int op) { - if (!PyBobMachineActivation_Check(other)) { + if (!PyBobLearnActivation_Check(other)) { PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", s_activation_str, other->ob_type->tp_name); return 0; } - auto other_ = reinterpret_cast<PyBobMachineActivationObject*>(other); + auto other_ = reinterpret_cast<PyBobLearnActivationObject*>(other); switch (op) { case Py_EQ: @@ -530,48 +531,48 @@ static PyObject* PyBobMachineActivation_RichCompare (PyBobMachineActivationObjec } -static PyObject* PyBobMachineActivation_Str (PyBobMachineActivationObject* o) { +static PyObject* PyBobLearnActivation_Str (PyBobLearnActivationObject* o) { return Py_BuildValue("s", o->base->str().c_str()); } -PyTypeObject PyBobMachineActivation_Type = { +PyTypeObject PyBobLearnActivation_Type = { PyObject_HEAD_INIT(0) - 0, /* ob_size */ - s_activation_str, /* tp_name */ - sizeof(PyBobMachineActivationObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - (ternaryfunc)PyBobMachineActivation_call, /* tp_call */ - (reprfunc)PyBobMachineActivation_Str, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - s_activation_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)PyBobMachineActivation_RichCompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PyBobMachineActivation_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)PyBobMachineActivation_init, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ + 0, /* ob_size */ + s_activation_str, /* tp_name */ + sizeof(PyBobLearnActivationObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)PyBobLearnActivation_call, /* tp_call */ + (reprfunc)PyBobLearnActivation_Str, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + s_activation_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)PyBobLearnActivation_RichCompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PyBobLearnActivation_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PyBobLearnActivation_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ }; diff --git a/xbob/cleanup.h b/xbob/learn/activation/cleanup.h similarity index 100% rename from xbob/cleanup.h rename to xbob/learn/activation/cleanup.h diff --git a/xbob/machine/identity_activation.cpp b/xbob/learn/activation/identity.cpp similarity index 85% rename from xbob/machine/identity_activation.cpp rename to xbob/learn/activation/identity.cpp index c21f748..32072b0 100644 --- a/xbob/machine/identity_activation.cpp +++ b/xbob/learn/activation/identity.cpp @@ -5,21 +5,21 @@ * @brief Implementation of the Identity Activation function */ -#define XBOB_MACHINE_MODULE -#include <xbob.machine/api.h> +#define XBOB_LEARN_ACTIVATION_MODULE +#include <xbob.learn.activation/api.h> PyDoc_STRVAR(s_identityactivation_str, - XBOB_EXT_MODULE_PREFIX ".IdentityActivation"); + XBOB_EXT_MODULE_PREFIX ".Identity"); PyDoc_STRVAR(s_identityactivation_doc, -"IdentityActivation() -> new IdentityActivation\n\ +"Identity() -> new Identity activation functor\n\ \n\ Computes :math:`f(z) = z` as activation function.\n\ \n\ "); -static int PyBobMachineIdentityActivation_init -(PyBobMachineIdentityActivationObject* self, PyObject* args, PyObject* kwds) { +static int PyBobLearnIdentityActivation_init +(PyBobLearnIdentityActivationObject* self, PyObject* args, PyObject* kwds) { /* Parses input arguments in a single shot */ static const char* const_kwlist[] = {0}; @@ -45,8 +45,8 @@ static int PyBobMachineIdentityActivation_init } -static void PyBobMachineIdentityActivation_delete -(PyBobMachineIdentityActivationObject* self) { +static void PyBobLearnIdentityActivation_delete +(PyBobLearnIdentityActivationObject* self) { delete self->base; self->parent.base = 0; @@ -55,13 +55,13 @@ static void PyBobMachineIdentityActivation_delete } -PyTypeObject PyBobMachineIdentityActivation_Type = { +PyTypeObject PyBobLearnIdentityActivation_Type = { PyObject_HEAD_INIT(0) 0, /*ob_size*/ s_identityactivation_str, /*tp_name*/ - sizeof(PyBobMachineIdentityActivationObject), /*tp_basicsize*/ + sizeof(PyBobLearnIdentityActivationObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ - (destructor)PyBobMachineIdentityActivation_delete, /*tp_dealloc*/ + (destructor)PyBobLearnIdentityActivation_delete, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -92,7 +92,7 @@ PyTypeObject PyBobMachineIdentityActivation_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)PyBobMachineIdentityActivation_init, /* tp_init */ + (initproc)PyBobLearnIdentityActivation_init, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ }; diff --git a/xbob/learn/activation/include/xbob.learn.activation/api.h b/xbob/learn/activation/include/xbob.learn.activation/api.h new file mode 100644 index 0000000..aed9d14 --- /dev/null +++ b/xbob/learn/activation/include/xbob.learn.activation/api.h @@ -0,0 +1,292 @@ +/** + * @author Andre Anjos <andre.anjos@idiap.ch> + * @date Wed 15 Jan 2014 10:15:21 CET + * + * @brief C/C++ Python API for activation functors in bob::machine + */ + +#ifndef XBOB_LEARN_ACTIVATION_H +#define XBOB_LEARN_ACTIVATION_H + +#include <Python.h> +#include <xbob.learn.activation/config.h> +#include <bob/machine/Activation.h> +#include <bob/machine/LinearMachine.h> + +#define XBOB_LEARN_ACTIVATION_MODULE_PREFIX xbob.learn.activation +#define XBOB_LEARN_ACTIVATION_MODULE_NAME _library + +/******************* + * C API functions * + *******************/ + +/************** + * Versioning * + **************/ + +#define PyXbobLearnActivation_APIVersion_NUM 0 +#define PyXbobLearnActivation_APIVersion_TYPE int + +/************************************************* + * Bindings for xbob.learn.activation.Activation * + *************************************************/ + +typedef struct { + PyObject_HEAD + bob::machine::Activation* base; +} PyBobLearnActivationObject; + +#define PyBobLearnActivation_Type_NUM 1 +#define PyBobLearnActivation_Type_TYPE PyTypeObject + +#define PyBobLearnActivation_Check_NUM 2 +#define PyBobLearnActivation_Check_RET int +#define PyBobLearnActivation_Check_PROTO (PyObject* o) + +/*********************************************** + * Bindings for xbob.learn.activation.Identity * + ***********************************************/ + +typedef struct { + PyBobLearnActivationObject parent; + bob::machine::IdentityActivation* base; +} PyBobLearnIdentityActivationObject; + +#define PyBobLearnIdentityActivation_Type_NUM 3 +#define PyBobLearnIdentityActivation_Type_TYPE PyTypeObject + +/********************************************* + * Bindings for xbob.learn.activation.Linear * + *********************************************/ + +typedef struct { + PyBobLearnActivationObject parent; + bob::machine::LinearActivation* base; +} PyBobLearnLinearActivationObject; + +#define PyBobLearnLinearActivation_Type_NUM 4 +#define PyBobLearnLinearActivation_Type_TYPE PyTypeObject + +/*********************************************** + * Bindings for xbob.learn.activation.Logistic * + ***********************************************/ + +typedef struct { + PyBobLearnActivationObject parent; + bob::machine::LogisticActivation* base; +} PyBobLearnLogisticActivationObject; + +#define PyBobLearnLogisticActivation_Type_NUM 5 +#define PyBobLearnLogisticActivation_Type_TYPE PyTypeObject + +/******************************************************** + * Bindings for xbob.learn.activation.HyperbolicTangent * + ********************************************************/ + +typedef struct { + PyBobLearnActivationObject parent; + bob::machine::HyperbolicTangentActivation* base; +} PyBobLearnHyperbolicTangentActivationObject; + +#define PyBobLearnHyperbolicTangentActivation_Type_NUM 6 +#define PyBobLearnHyperbolicTangentActivation_Type_TYPE PyTypeObject + +/****************************************************************** + * Bindings for xbob.learn.activation.MultipliedHyperbolicTangent * + ******************************************************************/ + +typedef struct { + PyBobLearnActivationObject parent; + bob::machine::MultipliedHyperbolicTangentActivation* base; +} PyBobLearnMultipliedHyperbolicTangentActivationObject; + +#define PyBobLearnMultipliedHyperbolicTangentActivation_Type_NUM 7 +#define PyBobLearnMultipliedHyperbolicTangentActivation_Type_TYPE PyTypeObject + +/* Total number of C API pointers */ +#define PyXbobLearnActivation_API_pointers 8 + +#ifdef XBOB_LEARN_ACTIVATION_MODULE + + /* This section is used when compiling `xbob.learn.activation' itself */ + + /************** + * Versioning * + **************/ + + extern int PyXbobLearnActivation_APIVersion; + + /************************************************* + * Bindings for xbob.learn.activation.Activation * + *************************************************/ + + extern PyBobLearnActivation_Type_TYPE PyBobLearnActivation_Type; + + PyBobLearnActivation_Check_RET PyBobLearnActivation_Check PyBobLearnActivation_Check_PROTO; + + /*********************************************** + * Bindings for xbob.learn.activation.Identity * + ***********************************************/ + + extern PyBobLearnIdentityActivation_Type_TYPE PyBobLearnIdentityActivation_Type; + + /********************************************* + * Bindings for xbob.learn.activation.Linear * + *********************************************/ + + extern PyBobLearnLinearActivation_Type_TYPE PyBobLearnLinearActivation_Type; + + /*********************************************** + * Bindings for xbob.learn.activation.Logistic * + ***********************************************/ + + extern PyBobLearnLogisticActivation_Type_TYPE PyBobLearnLogisticActivation_Type; + + /******************************************************** + * Bindings for xbob.learn.activation.HyperbolicTangent * + ********************************************************/ + + extern PyBobLearnHyperbolicTangentActivation_Type_TYPE PyBobLearnHyperbolicTangentActivation_Type; + + /****************************************************************** + * Bindings for xbob.learn.activation.MultipliedHyperbolicTangent * + ******************************************************************/ + + extern PyBobLearnMultipliedHyperbolicTangentActivation_Type_TYPE PyBobLearnMultipliedHyperbolicTangentActivation_Type; + +#else + + /* This section is used in modules that use `xbob.learn.activation's' C-API */ + +/************************************************************************ + * Macros to avoid symbol collision and allow for separate compilation. * + * We pig-back on symbols already defined for NumPy and apply the same * + * set of rules here, creating our own API symbol names. * + ************************************************************************/ + +# if defined(PY_ARRAY_UNIQUE_SYMBOL) +# define XBOB_LEARN_ACTIVATION_MAKE_API_NAME_INNER(a) XBOB_LEARN_ACTIVATION_ ## a +# define XBOB_LEARN_ACTIVATION_MAKE_API_NAME(a) XBOB_LEARN_ACTIVATION_MAKE_API_NAME_INNER(a) +# define PyXbobLearnActivation_API XBOB_LEARN_ACTIVATION_MAKE_API_NAME(PY_ARRAY_UNIQUE_SYMBOL) +# endif + +# if defined(NO_IMPORT_ARRAY) + extern void **PyXbobLearnActivation_API; +# else +# if defined(PY_ARRAY_UNIQUE_SYMBOL) + void **PyXbobLearnActivation_API; +# else + static void **PyXbobLearnActivation_API=NULL; +# endif +# endif + + /************** + * Versioning * + **************/ + +# define PyXbobLearnActivation_APIVersion (*(PyXbobLearnActivation_APIVersion_TYPE *)PyXbobLearnActivation_API[PyXbobLearnActivation_APIVersion_NUM]) + + /************************************************* + * Bindings for xbob.learn.activation.Activation * + *************************************************/ + +# define PyBobLearnActivation_Type (*(PyBobLearnActivation_Type_TYPE *)PyXbobLearnActivation_API[PyBobLearnActivation_Type_NUM]) + +# define PyBobLearnActivation_Check (*(PyBobLearnActivation_Check_RET (*)PyBobLearnActivation_Check_PROTO) PyXbobLearnActivation_API[PyBobLearnActivation_Check_NUM]) + + /*********************************************** + * Bindings for xbob.learn.activation.Identity * + ***********************************************/ + +# define PyBobLearnIdentityActivation_Type (*(PyBobLearnIdentityActivation_Type_TYPE *)PyXbobLearnActivation_API[PyBobLearnIdentityActivation_Type_NUM]) + + /********************************************* + * Bindings for xbob.learn.activation.Linear * + *********************************************/ + +# define PyBobLearnLinearActivation_Type (*(PyBobLearnLinearActivation_Type_TYPE *)PyXbobLearnActivation_API[PyBobLearnLinearActivation_Type_NUM]) + + /*********************************************** + * Bindings for xbob.learn.activation.Logistic * + ***********************************************/ + +# define PyBobLearnLogisticActivation_Type (*(PyBobLearnLogisticActivation_Type_TYPE *)PyXbobLearnActivation_API[PyBobLearnLogisticActivation_Type_NUM]) + + /******************************************************** + * Bindings for xbob.learn.activation.HyperbolicTangent * + ********************************************************/ + +# define PyBobLearnHyperbolicTangentActivation_Type (*(PyBobLearnHyperbolicTangentActivation_Type_TYPE *)PyXbobLearnActivation_API[PyBobLearnHyperbolicTangentActivation_Type_NUM]) + + /****************************************************************** + * Bindings for xbob.learn.activation.MultipliedHyperbolicTangent * + ******************************************************************/ + +# define PyBobLearnMultipliedHyperbolicTangentActivation_Type (*(PyBobLearnMultipliedHyperbolicTangentActivation_Type_TYPE *)PyXbobLearnActivation_API[PyBobLearnMultipliedHyperbolicTangentActivation_Type_NUM]) + +# if !defined(NO_IMPORT_ARRAY) + + /** + * Returns -1 on error, 0 on success. PyCapsule_Import will set an exception + * if there's an error. + */ + static int import_xbob_io(void) { + + PyObject *c_api_object; + PyObject *module; + + module = PyImport_ImportModule(BOOST_PP_STRINGIZE(XBOB_LEARN_ACTIVATION_MODULE_PREFIX) "." BOOST_PP_STRINGIZE(XBOB_LEARN_ACTIVATION_MODULE_NAME)); + + if (module == NULL) return -1; + + c_api_object = PyObject_GetAttrString(module, "_C_API"); + + if (c_api_object == NULL) { + Py_DECREF(module); + return -1; + } + +# if PY_VERSION_HEX >= 0x02070000 + if (PyCapsule_CheckExact(c_api_object)) { + PyXbobLearnActivation_API = (void **)PyCapsule_GetPointer(c_api_object, + PyCapsule_GetName(c_api_object)); + } +# else + if (PyCObject_Check(c_api_object)) { + XbobLearnActivation_API = (void **)PyCObject_AsVoidPtr(c_api_object); + } +# endif + + Py_DECREF(c_api_object); + Py_DECREF(module); + + if (!XbobLearnActivation_API) { + PyErr_Format(PyExc_ImportError, +# if PY_VERSION_HEX >= 0x02070000 + "cannot find C/C++ API capsule at `%s.%s._C_API'", +# else + "cannot find C/C++ API cobject at `%s.%s._C_API'", +# endif + BOOST_PP_STRINGIZE(XBOB_LEARN_ACTIVATION_MODULE_PREFIX), + BOOST_PP_STRINGIZE(XBOB_LEARN_ACTIVATION_MODULE_NAME)); + return -1; + } + + /* Checks that the imported version matches the compiled version */ + int imported_version = *(int*)PyXbobLearnActivation_API[PyXbobLearnActivation_APIVersion_NUM]; + + if (XBOB_LEARN_ACTIVATION_API_VERSION != imported_version) { + PyErr_Format(PyExc_ImportError, "%s.%s import error: you compiled against API version 0x%04x, but are now importing an API with version 0x%04x which is not compatible - check your Python runtime environment for errors", BOOST_PP_STRINGIZE(XBOB_LEARN_ACTIVATION_MODULE_PREFIX), BOOST_PP_STRINGIZE(XBOB_LEARN_ACTIVATION_MODULE_NAME), XBOB_LEARN_ACTIVATION_API_VERSION, imported_version); + return -1; + } + + /* If you get to this point, all is good */ + return 0; + + } + +# endif //!defined(NO_IMPORT_ARRAY) + +#endif /* XBOB_LEARN_ACTIVATION_MODULE */ + +#endif /* XBOB_LEARN_ACTIVATION_H */ diff --git a/xbob/learn/activation/include/xbob.learn.activation/config.h b/xbob/learn/activation/include/xbob.learn.activation/config.h new file mode 100644 index 0000000..3b643aa --- /dev/null +++ b/xbob/learn/activation/include/xbob.learn.activation/config.h @@ -0,0 +1,14 @@ +/** + * @author Andre Anjos <andre.anjos@idiap.ch> + * @date Fri 13 Dec 2013 11:50:29 CET + * + * @brief General directives for all modules in xbob.learn.activation + */ + +#ifndef XBOB_LEARN_ACTIVATION_CONFIG_H +#define XBOB_LEARN_ACTIVATION_CONFIG_H + +/* Macros that define versions and important names */ +#define XBOB_LEARN_ACTIVATION_API_VERSION 0x0200 + +#endif /* XBOB_LEARN_ACTIVATION_CONFIG_H */ diff --git a/xbob/machine/linear_activation.cpp b/xbob/learn/activation/linear.cpp similarity index 81% rename from xbob/machine/linear_activation.cpp rename to xbob/learn/activation/linear.cpp index 10c74cc..491ebd6 100644 --- a/xbob/machine/linear_activation.cpp +++ b/xbob/learn/activation/linear.cpp @@ -5,14 +5,13 @@ * @brief Implementation of the Linear Activation function */ -#define XBOB_MACHINE_MODULE -#include <xbob.machine/api.h> +#define XBOB_LEARN_ACTIVATION_MODULE +#include <xbob.learn.activation/api.h> -PyDoc_STRVAR(s_linearactivation_str, - XBOB_EXT_MODULE_PREFIX ".LinearActivation"); +PyDoc_STRVAR(s_linearactivation_str, XBOB_EXT_MODULE_PREFIX ".Linear"); PyDoc_STRVAR(s_linearactivation_doc, -"LinearActivation([C=1.0]) -> new LinearActivation\n\ +"Linear([C=1.0]) -> new linear activation functor\n\ \n\ Computes :math:`f(z) = C \\cdot z` as activation function.\n\ \n\ @@ -22,8 +21,8 @@ set constant to the default value (1.0). In such a case,\n\ prefer to use the more efficient :py:class:`IdentityActivation`.\n\ "); -static int PyBobMachineLinearActivation_init -(PyBobMachineLinearActivationObject* self, PyObject* args, PyObject* kwds) { +static int PyBobLearnLinearActivation_init +(PyBobLearnLinearActivationObject* self, PyObject* args, PyObject* kwds) { /* Parses input arguments in a single shot */ static const char* const_kwlist[] = {"C", 0}; @@ -51,8 +50,8 @@ static int PyBobMachineLinearActivation_init } -static void PyBobMachineLinearActivation_delete -(PyBobMachineLinearActivationObject* self) { +static void PyBobLearnLinearActivation_delete +(PyBobLearnLinearActivationObject* self) { delete self->base; self->parent.base = 0; @@ -66,17 +65,17 @@ PyDoc_STRVAR(s_C_doc, "The multiplication factor for the linear function (read-only)" ); -static PyObject* PyBobMachineLinearActivation_C -(PyBobMachineLinearActivationObject* self) { +static PyObject* PyBobLearnLinearActivation_C +(PyBobLearnLinearActivationObject* self) { return Py_BuildValue("d", self->base->C()); } -static PyGetSetDef PyBobMachineLinearActivation_getseters[] = { +static PyGetSetDef PyBobLearnLinearActivation_getseters[] = { { s_C_str, - (getter)PyBobMachineLinearActivation_C, + (getter)PyBobLearnLinearActivation_C, 0, s_C_doc, 0 @@ -84,13 +83,13 @@ static PyGetSetDef PyBobMachineLinearActivation_getseters[] = { {0} /* Sentinel */ }; -PyTypeObject PyBobMachineLinearActivation_Type = { +PyTypeObject PyBobLearnLinearActivation_Type = { PyObject_HEAD_INIT(0) 0, /*ob_size*/ s_linearactivation_str, /*tp_name*/ - sizeof(PyBobMachineLinearActivationObject), /*tp_basicsize*/ + sizeof(PyBobLearnLinearActivationObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ - (destructor)PyBobMachineLinearActivation_delete, /*tp_dealloc*/ + (destructor)PyBobLearnLinearActivation_delete, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -115,13 +114,13 @@ PyTypeObject PyBobMachineLinearActivation_Type = { 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ - PyBobMachineLinearActivation_getseters, /* tp_getset */ + PyBobLearnLinearActivation_getseters, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)PyBobMachineLinearActivation_init, /* tp_init */ + (initproc)PyBobLearnLinearActivation_init, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ }; diff --git a/xbob/machine/logistic_activation.cpp b/xbob/learn/activation/logistic.cpp similarity index 84% rename from xbob/machine/logistic_activation.cpp rename to xbob/learn/activation/logistic.cpp index 079af69..34c2233 100644 --- a/xbob/machine/logistic_activation.cpp +++ b/xbob/learn/activation/logistic.cpp @@ -5,21 +5,20 @@ * @brief Implementation of the Logistic Activation function */ -#define XBOB_MACHINE_MODULE -#include <xbob.machine/api.h> +#define XBOB_LEARN_ACTIVATION_MODULE +#include <xbob.learn.activation/api.h> -PyDoc_STRVAR(s_logisticactivation_str, - XBOB_EXT_MODULE_PREFIX ".LogisticActivation"); +PyDoc_STRVAR(s_logisticactivation_str, XBOB_EXT_MODULE_PREFIX ".Logistic"); PyDoc_STRVAR(s_logisticactivation_doc, -"LogisticActivation() -> new LogisticActivation\n\ +"Logistic() -> new Logistic activation functor\n\ \n\ Computes :math:`f(z) = 1/(1+ e^{-z})` as activation function.\n\ \n\ "); -static int PyBobMachineLogisticActivation_init -(PyBobMachineLogisticActivationObject* self, PyObject* args, PyObject* kwds) { +static int PyBobLearnLogisticActivation_init +(PyBobLearnLogisticActivationObject* self, PyObject* args, PyObject* kwds) { /* Parses input arguments in a single shot */ static const char* const_kwlist[] = {0}; @@ -45,8 +44,8 @@ static int PyBobMachineLogisticActivation_init } -static void PyBobMachineLogisticActivation_delete -(PyBobMachineLogisticActivationObject* self) { +static void PyBobLearnLogisticActivation_delete +(PyBobLearnLogisticActivationObject* self) { delete self->base; self->parent.base = 0; @@ -55,13 +54,13 @@ static void PyBobMachineLogisticActivation_delete } -PyTypeObject PyBobMachineLogisticActivation_Type = { +PyTypeObject PyBobLearnLogisticActivation_Type = { PyObject_HEAD_INIT(0) 0, /*ob_size*/ s_logisticactivation_str, /*tp_name*/ - sizeof(PyBobMachineLogisticActivationObject), /*tp_basicsize*/ + sizeof(PyBobLearnLogisticActivationObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ - (destructor)PyBobMachineLogisticActivation_delete, /*tp_dealloc*/ + (destructor)PyBobLearnLogisticActivation_delete, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -92,7 +91,7 @@ PyTypeObject PyBobMachineLogisticActivation_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)PyBobMachineLogisticActivation_init, /* tp_init */ + (initproc)PyBobLearnLogisticActivation_init, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ }; diff --git a/xbob/learn/activation/main.cpp b/xbob/learn/activation/main.cpp new file mode 100644 index 0000000..0532309 --- /dev/null +++ b/xbob/learn/activation/main.cpp @@ -0,0 +1,146 @@ +/** + * @author Andre Anjos <andre.anjos@idiap.ch> + * @date Fri 13 Dec 2013 12:35:59 CET + * + * @brief Bindings to activation functors + */ + +#define XBOB_LEARN_ACTIVATION_MODULE +#include <xbob.learn.activation/api.h> + +#ifdef NO_IMPORT_ARRAY +#undef NO_IMPORT_ARRAY +#endif +#include <xbob.blitz/capi.h> +#include <xbob.io/api.h> + +static PyMethodDef library_methods[] = { + {0} /* Sentinel */ +}; + +PyDoc_STRVAR(library_docstr, "classes for activation functors"); + +int PyXbobLearnActivation_APIVersion = XBOB_LEARN_ACTIVATION_API_VERSION; + +PyMODINIT_FUNC XBOB_EXT_ENTRY_NAME (void) { + + PyBobLearnActivation_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&PyBobLearnActivation_Type) < 0) return; + + PyBobLearnIdentityActivation_Type.tp_base = &PyBobLearnActivation_Type; + if (PyType_Ready(&PyBobLearnIdentityActivation_Type) < 0) return; + + PyBobLearnLinearActivation_Type.tp_base = &PyBobLearnActivation_Type; + if (PyType_Ready(&PyBobLearnLinearActivation_Type) < 0) return; + + PyBobLearnLogisticActivation_Type.tp_base = &PyBobLearnActivation_Type; + if (PyType_Ready(&PyBobLearnLogisticActivation_Type) < 0) return; + + PyBobLearnHyperbolicTangentActivation_Type.tp_base = + &PyBobLearnActivation_Type; + if (PyType_Ready(&PyBobLearnHyperbolicTangentActivation_Type) < 0) return; + + PyBobLearnMultipliedHyperbolicTangentActivation_Type.tp_base = + &PyBobLearnActivation_Type; + if (PyType_Ready(&PyBobLearnMultipliedHyperbolicTangentActivation_Type) < 0) + return; + + PyObject* m = Py_InitModule3(XBOB_EXT_MODULE_NAME, library_methods, library_docstr); + + /* register some constants */ + PyModule_AddIntConstant(m, "__api_version__", + XBOB_LEARN_ACTIVATION_API_VERSION); + PyModule_AddStringConstant(m, "__version__", XBOB_EXT_MODULE_VERSION); + + /* register the types to python */ + Py_INCREF(&PyBobLearnActivation_Type); + PyModule_AddObject(m, "Activation", (PyObject *)&PyBobLearnActivation_Type); + + Py_INCREF(&PyBobLearnIdentityActivation_Type); + PyModule_AddObject(m, "Identity", (PyObject *)&PyBobLearnIdentityActivation_Type); + + Py_INCREF(&PyBobLearnLinearActivation_Type); + PyModule_AddObject(m, "Linear", (PyObject *)&PyBobLearnLinearActivation_Type); + + Py_INCREF(&PyBobLearnLogisticActivation_Type); + PyModule_AddObject(m, "Logistic", (PyObject *)&PyBobLearnLogisticActivation_Type); + + Py_INCREF(&PyBobLearnHyperbolicTangentActivation_Type); + PyModule_AddObject(m, "HyperbolicTangent", (PyObject *)&PyBobLearnHyperbolicTangentActivation_Type); + + Py_INCREF(&PyBobLearnMultipliedHyperbolicTangentActivation_Type); + PyModule_AddObject(m, "MultipliedHyperbolicTangent", (PyObject *)&PyBobLearnMultipliedHyperbolicTangentActivation_Type); + + static void* PyXbobLearnActivation_API[PyXbobLearnActivation_API_pointers]; + + /* exhaustive list of C APIs */ + + /************** + * Versioning * + **************/ + + PyXbobLearnActivation_API[PyXbobLearnActivation_APIVersion_NUM] = (void *)&PyXbobLearnActivation_APIVersion; + + /************************************************* + * Bindings for xbob.learn.activation.Activation * + *************************************************/ + + PyXbobLearnActivation_API[PyBobLearnActivation_Type_NUM] = (void *)&PyBobLearnActivation_Type; + + PyXbobLearnActivation_API[PyBobLearnActivation_Check_NUM] = (void *)&PyBobLearnActivation_Check; + + /*********************************************** + * Bindings for xbob.learn.activation.Identity * + ***********************************************/ + + PyXbobLearnActivation_API[PyBobLearnIdentityActivation_Type_NUM] = (void *)&PyBobLearnIdentityActivation_Type; + + /********************************************* + * Bindings for xbob.learn.activation.Linear * + *********************************************/ + + PyXbobLearnActivation_API[PyBobLearnLinearActivation_Type_NUM] = (void *)&PyBobLearnLinearActivation_Type; + + /*********************************************** + * Bindings for xbob.learn.activation.Logistic * + ***********************************************/ + + PyXbobLearnActivation_API[PyBobLearnLogisticActivation_Type_NUM] = (void *)&PyBobLearnLogisticActivation_Type; + + /******************************************************** + * Bindings for xbob.learn.activation.HyperbolicTangent * + ********************************************************/ + + PyXbobLearnActivation_API[PyBobLearnHyperbolicTangentActivation_Type_NUM] = (void *)&PyBobLearnHyperbolicTangentActivation_Type; + + /****************************************************************** + * Bindings for xbob.learn.activation.MultipliedHyperbolicTangent * + ******************************************************************/ + + PyXbobLearnActivation_API[PyBobLearnMultipliedHyperbolicTangentActivation_Type_NUM] = (void *)&PyBobLearnMultipliedHyperbolicTangentActivation_Type; + +#if PY_VERSION_HEX >= 0x02070000 + + /* defines the PyCapsule */ + + PyObject* c_api_object = PyCapsule_New((void *)PyXbobLearnActivation_API, + XBOB_EXT_MODULE_PREFIX "." XBOB_EXT_MODULE_NAME "._C_API", 0); + +#else + + PyObject* c_api_object = PyCObject_FromVoidPtr((void *)PyXbobLearnActivation_API, 0); + +#endif + + if (c_api_object) PyModule_AddObject(m, "_C_API", c_api_object); + + /* imports the NumPy C-API */ + import_array(); + + /* imports xbob.blitz C-API */ + import_xbob_blitz(); + + /* imports xbob.io C-API */ + import_xbob_io(); + +} diff --git a/xbob/machine/mult_tanh_activation.cpp b/xbob/learn/activation/mult_tanh.cpp similarity index 76% rename from xbob/machine/mult_tanh_activation.cpp rename to xbob/learn/activation/mult_tanh.cpp index ff917af..72038bb 100644 --- a/xbob/machine/mult_tanh_activation.cpp +++ b/xbob/learn/activation/mult_tanh.cpp @@ -5,14 +5,14 @@ * @brief Implementation of the MultipliedHyperbolicTangent Activation function */ -#define XBOB_MACHINE_MODULE -#include <xbob.machine/api.h> +#define XBOB_LEARN_ACTIVATION_MODULE +#include <xbob.learn.activation/api.h> PyDoc_STRVAR(s_multtanhactivation_str, - XBOB_EXT_MODULE_PREFIX ".MultipliedHyperbolicTangentActivation"); + XBOB_EXT_MODULE_PREFIX ".MultipliedHyperbolicTangent"); PyDoc_STRVAR(s_multtanhactivation_doc, -"MultipliedHyperbolicTangentActivation([C=1.0, [M=1.0]]) -> new MultipliedHyperbolicTangentActivation\n\ +"MultipliedHyperbolicTangentActivation([C=1.0, [M=1.0]]) -> new multiplied hyperbolic tangent functor\n\ \n\ Computes :math:`f(z) = C \\cdot \\tanh(Mz)` as activation\n\ function.\n\ @@ -24,8 +24,8 @@ such a case, prefer to use the more efficient\n\ :py:class:`bob.machine.HyperbolicTangentActivation`.\n\ "); -static int PyBobMachineMultipliedHyperbolicTangentActivation_init -(PyBobMachineMultipliedHyperbolicTangentActivationObject* self, PyObject* args, PyObject* kwds) { +static int PyBobLearnMultipliedHyperbolicTangentActivation_init +(PyBobLearnMultipliedHyperbolicTangentActivationObject* self, PyObject* args, PyObject* kwds) { /* Parses input arguments in a single shot */ static const char* const_kwlist[] = {"C", "M", 0}; @@ -55,8 +55,8 @@ static int PyBobMachineMultipliedHyperbolicTangentActivation_init } -static void PyBobMachineMultipliedHyperbolicTangentActivation_delete -(PyBobMachineMultipliedHyperbolicTangentActivationObject* self) { +static void PyBobLearnMultipliedHyperbolicTangentActivation_delete +(PyBobLearnMultipliedHyperbolicTangentActivationObject* self) { delete self->base; self->parent.base = 0; @@ -71,8 +71,8 @@ PyDoc_STRVAR(s_C_doc, tangent function (read-only).\n\ "); -static PyObject* PyBobMachineMultipliedHyperbolicTangentActivation_C -(PyBobMachineMultipliedHyperbolicTangentActivationObject* self) { +static PyObject* PyBobLearnMultipliedHyperbolicTangentActivation_C +(PyBobLearnMultipliedHyperbolicTangentActivationObject* self) { return Py_BuildValue("d", self->base->C()); @@ -85,24 +85,24 @@ tangent function (read-only).\n\ " ); -static PyObject* PyBobMachineMultipliedHyperbolicTangentActivation_M -(PyBobMachineMultipliedHyperbolicTangentActivationObject* self) { +static PyObject* PyBobLearnMultipliedHyperbolicTangentActivation_M +(PyBobLearnMultipliedHyperbolicTangentActivationObject* self) { return Py_BuildValue("d", self->base->M()); } -static PyGetSetDef PyBobMachineMultipliedHyperbolicTangentActivation_getseters[] = { +static PyGetSetDef PyBobLearnMultipliedHyperbolicTangentActivation_getseters[] = { { s_C_str, - (getter)PyBobMachineMultipliedHyperbolicTangentActivation_C, + (getter)PyBobLearnMultipliedHyperbolicTangentActivation_C, 0, s_C_doc, 0 }, { s_M_str, - (getter)PyBobMachineMultipliedHyperbolicTangentActivation_M, + (getter)PyBobLearnMultipliedHyperbolicTangentActivation_M, 0, s_M_doc, 0 @@ -110,13 +110,13 @@ static PyGetSetDef PyBobMachineMultipliedHyperbolicTangentActivation_getseters[] {0} /* Sentinel */ }; -PyTypeObject PyBobMachineMultipliedHyperbolicTangentActivation_Type = { +PyTypeObject PyBobLearnMultipliedHyperbolicTangentActivation_Type = { PyObject_HEAD_INIT(0) 0, /*ob_size*/ s_multtanhactivation_str, /*tp_name*/ - sizeof(PyBobMachineMultipliedHyperbolicTangentActivationObject), /*tp_basicsize*/ + sizeof(PyBobLearnMultipliedHyperbolicTangentActivationObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ - (destructor)PyBobMachineMultipliedHyperbolicTangentActivation_delete, /*tp_dealloc*/ + (destructor)PyBobLearnMultipliedHyperbolicTangentActivation_delete, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ @@ -141,13 +141,13 @@ PyTypeObject PyBobMachineMultipliedHyperbolicTangentActivation_Type = { 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ - PyBobMachineMultipliedHyperbolicTangentActivation_getseters, /* tp_getset */ + PyBobLearnMultipliedHyperbolicTangentActivation_getseters, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)PyBobMachineMultipliedHyperbolicTangentActivation_init, /* tp_init */ + (initproc)PyBobLearnMultipliedHyperbolicTangentActivation_init, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ }; diff --git a/xbob/learn/activation/tanh.cpp b/xbob/learn/activation/tanh.cpp new file mode 100644 index 0000000..d310a7a --- /dev/null +++ b/xbob/learn/activation/tanh.cpp @@ -0,0 +1,99 @@ +/** + * @author Andre Anjos <andre.anjos@idiap.ch> + * @date Mon 13 Jan 2014 17:25:32 CET + * + * @brief Implementation of the HyperbolicTangent Activation function + */ + +#define XBOB_LEARN_ACTIVATION_MODULE +#include <xbob.learn.activation/api.h> + +PyDoc_STRVAR(s_hyperbolictangentactivation_str, + XBOB_EXT_MODULE_PREFIX ".HyperbolicTangentActivation"); + +PyDoc_STRVAR(s_hyperbolictangentactivation_doc, +"HyperbolicTangentActivation() -> new HyperbolicTangentActivation\n\ +\n\ +Computes :math:`f(z) = \\tanh(z)` as activation function.\n\ +\n\ +"); + +static int PyBobLearnHyperbolicTangentActivation_init +(PyBobLearnHyperbolicTangentActivationObject* self, + PyObject* args, PyObject* kwds) { + + /* Parses input arguments in a single shot */ + static const char* const_kwlist[] = {0}; + static char** kwlist = const_cast<char**>(const_kwlist); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) return -1; + + try { + self->base = new bob::machine::HyperbolicTangentActivation(); + } + catch (std::exception& ex) { + PyErr_SetString(PyExc_RuntimeError, ex.what()); + } + catch (...) { + PyErr_Format(PyExc_RuntimeError, "cannot create new object of type `%s' - unknown exception thrown", s_hyperbolictangentactivation_str); + } + + self->parent.base = self->base; + + if (PyErr_Occurred()) return -1; + + return 0; + +} + +static void PyBobLearnHyperbolicTangentActivation_delete +(PyBobLearnHyperbolicTangentActivationObject* self) { + + delete self->base; + self->parent.base = 0; + self->base = 0; + self->parent.ob_type->tp_free((PyObject*)self); + +} + +PyTypeObject PyBobLearnHyperbolicTangentActivation_Type = { + PyObject_HEAD_INIT(0) + 0, /*ob_size*/ + s_hyperbolictangentactivation_str, /*tp_name*/ + sizeof(PyBobLearnHyperbolicTangentActivationObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)PyBobLearnHyperbolicTangentActivation_delete, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + s_hyperbolictangentactivation_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PyBobLearnHyperbolicTangentActivation_init,/* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; diff --git a/xbob/machine/test_activation.py b/xbob/learn/activation/test.py similarity index 53% rename from xbob/machine/test_activation.py rename to xbob/learn/activation/test.py index af0b773..6b3ea42 100644 --- a/xbob/machine/test_activation.py +++ b/xbob/learn/activation/test.py @@ -9,146 +9,211 @@ import numpy import math -from . import IdentityActivation, \ - LinearActivation, \ - HyperbolicTangentActivation, \ - MultipliedHyperbolicTangentActivation, \ - LogisticActivation +from . import Identity, Linear, Logistic, HyperbolicTangent, \ + MultipliedHyperbolicTangent -from .test_utils import estimate_gradient +def estimate_gradient(f, x, epsilon=1e-4, args=()): + """Estimates the gradient for a given callable f + + Suppose you have a function :math:`f'(x)` that purportedly computes + :math`\frac{\partial f(x)}{\partial x}`. You'd like to check if :math:`f'(x)` + is outputting correct derivative values. You can then use this function to + estimate the gradient around a point and compare it to the output of + :math:`f'(x)`. The estimation can have a precision of up to a few decimal + houses. + + Imagine a random value for :math:`x`, called :math:`x_t` (for test). Now + imagine you modify one of the elements in :math:`x_t` so that + :math:`x_{t+\epsilon}` has that element added with a small (positive) value + :math:`\epsilon` and :math:`x_{t-\epsilon}` has the same value subtracted. + + In this case, one can use a truncated Taylor expansion of the derivative + to calculate the approximate supposed value: + + .. math:: + f'(x_t) \sim \frac{f(x_{t+\epsilon}) - f(x_{t-\epsilon})}{2\epsilon} + + The degree to which these two values should approximate each other will + depend on the details of :math:`f(x)`. But assuming :math:`\epsilon = + 10^{-4}`, you’ll usually find that the left- and right-hand sides of the + above will agree to at least 4 significant digits (and often many more). + + Keyword arguments: + + f + The function which you'd like to have the gradient estimated for. + + x + The input to ``f``. This must be the first parameter ``f`` receives. If + that is not the case, you must write a wrapper around ``f`` so it does the + parameter inversion and provide that wrapper instead. + + If f expects a multi-dimensional array, than this entry should be a + :py:class:`numpy.ndarray` with as many dimensions as required for f. + + precision + The epsilon step + + args (optional) + Extra arguments (a tuple) to ``f`` + + This function returns the estimated value for :math:`f'(x)` given ``x``. + + .. note:: + + Gradient estimation is a powerful tool for testing if a function is + correctly computing the derivative of another function, but can be quite + slow. It therefore is not a good replacement for writing specific code that + can compute the derivative of ``f``. + """ + epsilon = 1e-4 + + if isinstance(x, numpy.ndarray): + + retval = numpy.ndarray(x.shape, dtype=x.dtype) + for k in range(x.size): + xt_plus = x.copy() + xt_plus.flat[k] += epsilon + xt_minus = x.copy() + xt_minus.flat[k] -= epsilon + retval.flat[k] = (f(xt_plus,*args) - f(xt_minus,*args)) / (2*epsilon) + return retval + + else: # x is scalar + return (f(x+epsilon, *args) - f(x-epsilon, *args)) / (2*epsilon) def is_close(x, y, eps=1e-10): return (abs(x - y) < eps) def test_identity(): - op = IdentityActivation() + op = Identity() x = numpy.random.rand(10) #10 random numbers between 0 and 1 # go for an exact match for k in x: - assert is_close(op.f(k), k), 'IdentityActivation does not perform identity %g != %g' % (op.f(k), k) + assert is_close(op.f(k), k), 'Identity does not perform identity %g != %g' % (op.f(k), k) def test_identity_derivative(): - op = IdentityActivation() + op = Identity() x = numpy.random.rand(10) #10 random numbers between 0 and 1 # go for an exact match for k in x: - assert is_close(op.f_prime(k), 1.), 'IdentityActivation derivative is not equal to 1.: %g != 1.' % (op.f_prime(k),) + assert is_close(op.f_prime(k), 1.), 'Identity derivative is not equal to 1.: %g != 1.' % (op.f_prime(k),) # tries to estimate the gradient and check for k in x: absdiff = abs(op.f_prime(k)-estimate_gradient(op.f,k)) - assert absdiff < 1e-4, 'IdentityActivation derivative and estimation do not match to 10^-4: |%g-%g| = %g' % (op.f_prime(k), estimate_gradient(op.f,k), absdiff) + assert absdiff < 1e-4, 'Identity derivative and estimation do not match to 10^-4: |%g-%g| = %g' % (op.f_prime(k), estimate_gradient(op.f,k), absdiff) def test_linear(): C = numpy.random.rand() - op = LinearActivation(C) + op = Linear(C) x = numpy.random.rand(10) #10 random numbers between 0 and 1 # go for an exact match for k in x: - assert is_close(op.f(k), (C*k)), 'LinearActivation does not match expected value: %g != %g' % (op.f(k), C*k) + assert is_close(op.f(k), (C*k)), 'Linear does not match expected value: %g != %g' % (op.f(k), C*k) def test_linear_derivative(): C = numpy.random.rand() - op = LinearActivation(C) + op = Linear(C) x = numpy.random.rand(10) #10 random numbers between 0 and 1 # go for an exact match for k in x: - assert is_close(op.f_prime(k), C), 'LinearActivation derivative does not match expected value: %g != %g' % (op.f_prime(k), k) + assert is_close(op.f_prime(k), C), 'Linear derivative does not match expected value: %g != %g' % (op.f_prime(k), k) # tries to estimate the gradient and check for k in x: absdiff = abs(op.f_prime(k)-estimate_gradient(op.f,k)) - assert absdiff < 1e-4, 'IdentityActivation derivative and estimation do not match to 10^-4: |%g-%g| = %g' % (op.f_prime(k), estimate_gradient(op.f,k), absdiff) + assert absdiff < 1e-4, 'Identity derivative and estimation do not match to 10^-4: |%g-%g| = %g' % (op.f_prime(k), estimate_gradient(op.f,k), absdiff) def test_hyperbolic_tangent(): - op = HyperbolicTangentActivation() + op = HyperbolicTangent() x = numpy.random.rand(10) #10 random numbers between 0 and 1 # go for an exact match for k in x: - assert is_close(op.f(k), math.tanh(k)), 'HyperbolicTangentActivation does not match expected value: %g != %g' % (op.f(k), math.tanh(k)) + assert is_close(op.f(k), math.tanh(k)), 'HyperbolicTangent does not match expected value: %g != %g' % (op.f(k), math.tanh(k)) def test_hyperbolic_tangent_derivative(): - op = HyperbolicTangentActivation() + op = HyperbolicTangent() x = numpy.random.rand(10) #10 random numbers between 0 and 1 # go for an exact match for k in x: precise = 1 - op.f(k)**2 - assert is_close(op.f_prime(k), precise), 'HyperbolicTangentActivation derivative does not match expected value: %g != %g' % (op.f_prime(k), precise) + assert is_close(op.f_prime(k), precise), 'HyperbolicTangent derivative does not match expected value: %g != %g' % (op.f_prime(k), precise) # tries to estimate the gradient and check for k in x: absdiff = abs(op.f_prime(k)-estimate_gradient(op.f,k)) - assert absdiff < 1e-4, 'HyperbolicTangentActivation derivative and estimation do not match to 10^-4: |%g-%g| = %g' % (op.f_prime(k), estimate_gradient(op.f,k), absdiff) + assert absdiff < 1e-4, 'HyperbolicTangent derivative and estimation do not match to 10^-4: |%g-%g| = %g' % (op.f_prime(k), estimate_gradient(op.f,k), absdiff) def test_logistic(): - op = LogisticActivation() + op = Logistic() x = numpy.random.rand(10) #10 random numbers between 0 and 1 # go for an exact match for k in x: precise = 1. / (1. + math.exp(-k)) - assert is_close(op.f(k), precise), 'LogisticActivation does not match expected value: %g != %g' % (op.f(k), precise) + assert is_close(op.f(k), precise), 'Logistic does not match expected value: %g != %g' % (op.f(k), precise) def test_logistic_derivative(): - op = LogisticActivation() + op = Logistic() x = numpy.random.rand(10) #10 random numbers between 0 and 1 # go for an exact match for k in x: precise = op.f(k) * (1 - op.f(k)) - assert is_close(op.f_prime(k), precise), 'LogisticActivation derivative does not match expected value: %g != %g' % (op.f_prime(k), precise) + assert is_close(op.f_prime(k), precise), 'Logistic derivative does not match expected value: %g != %g' % (op.f_prime(k), precise) # tries to estimate the gradient and check for k in x: absdiff = abs(op.f_prime(k)-estimate_gradient(op.f,k)) - assert absdiff < 1e-4, 'LogisticActivation derivative and estimation do not match to 10^-4: |%g-%g| = %g' % (op.f_prime(k), estimate_gradient(op.f,k), absdiff) + assert absdiff < 1e-4, 'Logistic derivative and estimation do not match to 10^-4: |%g-%g| = %g' % (op.f_prime(k), estimate_gradient(op.f,k), absdiff) def test_multiplied_tanh(): C = numpy.random.rand() M = numpy.random.rand() - op = MultipliedHyperbolicTangentActivation(C, M) + op = MultipliedHyperbolicTangent(C, M) x = numpy.random.rand(10) #10 random numbers between 0 and 1 # go for an exact match for k in x: - assert is_close(op.f(k), C*math.tanh(M*k)), 'MultipliedHyperbolicTangentActivation does not match expected value: %g != %g' % (op.f(k), C*math.tanh(M*k)) + assert is_close(op.f(k), C*math.tanh(M*k)), 'MultipliedHyperbolicTangent does not match expected value: %g != %g' % (op.f(k), C*math.tanh(M*k)) def test_multiplied_tanh_derivative(): C = numpy.random.rand() M = numpy.random.rand() - op = MultipliedHyperbolicTangentActivation(C, M) + op = MultipliedHyperbolicTangent(C, M) x = numpy.random.rand(10) #10 random numbers between 0 and 1 # go for an exact match for k in x: precise = C*M*(1-math.pow(math.tanh(M*k),2)) - assert is_close(op.f_prime(k),precise), 'MultipliedHyperbolicTangentActivation derivative does not match expected value: %g != %g' % (op.f_prime(k), precise) + assert is_close(op.f_prime(k),precise), 'MultipliedHyperbolicTangent derivative does not match expected value: %g != %g' % (op.f_prime(k), precise) # tries to estimate the gradient and check for k in x: absdiff = abs(op.f_prime(k)-estimate_gradient(op.f,k)) - assert absdiff < 1e-4, 'MultipliedHyperbolicTangentActivation derivative and estimation do not match to 10^-4: |%g-%g| = %g' % (op.f_prime(k), estimate_gradient(op.f,k), absdiff) + assert absdiff < 1e-4, 'MultipliedHyperbolicTangent derivative and estimation do not match to 10^-4: |%g-%g| = %g' % (op.f_prime(k), estimate_gradient(op.f,k), absdiff) def test_1d_ndarray(): C = numpy.random.rand() - op = LinearActivation(C) + op = Linear(C) X = numpy.random.rand(10) #10 random numbers between 0 and 1 Y = op(X) @@ -176,7 +241,7 @@ def test_1d_ndarray(): def test_2d_ndarray(): C = numpy.random.rand() - op = LinearActivation(C) + op = Linear(C) X = numpy.random.rand(4, 4) Y = op(X) @@ -204,7 +269,7 @@ def test_2d_ndarray(): def test_3d_ndarray(): C = numpy.random.rand() - op = LinearActivation(C) + op = Linear(C) X = numpy.random.rand(3, 3, 3) Y = op(X) @@ -232,7 +297,7 @@ def test_3d_ndarray(): def test_4d_ndarray(): C = numpy.random.rand() - op = LinearActivation(C) + op = Linear(C) X = numpy.random.rand(2, 2, 2, 2) Y = op(X) diff --git a/xbob/machine/__init__.py b/xbob/machine/__init__.py deleted file mode 100644 index ead6eb6..0000000 --- a/xbob/machine/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -from ._library import * -from ._library import __version__, __api_version__ -from . import _externals - -#from . import __linear__ -#from . import __mlp__ - -def ztnorm_same_value(vect_a, vect_b): - """Computes the matrix of boolean D for the ZT-norm, which indicates where - the client ids of the T-Norm models and Z-Norm samples match. - - vect_a An (ordered) list of client_id corresponding to the T-Norm models - vect_b An (ordered) list of client_id corresponding to the Z-Norm impostor samples - """ - from .. import core - import numpy as np - sameMatrix = np.ndarray((len(vect_a), len(vect_b)), 'bool') - for j in range(len(vect_a)): - for i in range(len(vect_b)): - sameMatrix[j, i] = (vect_a[j] == vect_b[i]) - return sameMatrix diff --git a/xbob/machine/__linear__.py b/xbob/machine/__linear__.py deleted file mode 100644 index e0d0f41..0000000 --- a/xbob/machine/__linear__.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Andre Anjos <andre.dos.anjos@gmail.com> -# Mon 24 Jun 11:03:59 2013 - -"""LinearMachine additions -""" - -from . import LinearMachine, IdentityActivation - -def linearmachine_repr(self): - """A funky way to display a bob Linear Machine""" - if self.activation == IdentityActivation(): - return '<LinearMachine %s@%s>' % (self.weights.dtype, self.weights.shape) - else: - return '<LinearMachine %s@%s [act: %s]>' % (self.weights.dtype, self.weights.shape, self.activation) -LinearMachine.__repr__ = linearmachine_repr -del linearmachine_repr - -def linearmachine_str(self): - """A funky way to print a bob Linear Machine""" - act = "" - if self.activation != IdentityActivation(): - act = " [act: %s]" % self.activation - sub = "" - if not (self.input_subtract == 0.0).all(): - sub = "\n subtract: %s" % self.input_subtract - div = "" - if not (self.input_divide == 1.0).all(): - div = "\n divide: %s" % self.input_divide - bias = "" - if not (self.biases == 0.0).all(): - bias = "\n bias: %s" % self.biases - shape = self.weights.shape - return 'LinearMachine (%s) %d inputs, %d outputs%s%s%s%s\n %s' % \ - (self.weights.dtype, shape[0], shape[1], act, sub, div, - bias, self.weights) -LinearMachine.__str__ = linearmachine_str -del linearmachine_str diff --git a/xbob/machine/__mlp__.py b/xbob/machine/__mlp__.py deleted file mode 100644 index b34ff17..0000000 --- a/xbob/machine/__mlp__.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Andre Anjos <andre.dos.anjos@gmail.com> -# Mon 24 Jun 11:01:07 2013 - -"""MLP additions -""" - -from . import MLP - -def mlp_repr(self): - """A funky way to display a bob MLP""" - bias = False - for i, k in enumerate(self.biases): - if not (k == 0.0).all(): bias = True - if self.hidden_activation != self.output_activation: - return '<MLP %s@%s [bias: %s][act: {hidden}%s | {output}%s]>' % (self.weights[0].dtype, self.shape, str(bias).lower(), self.hidden_activation, self.output_activation) - else: - return '<MLP %s@%s [bias: %s][act: %s]>' % (self.weights[0].dtype, self.shape, str(bias).lower(), self.hidden_activation) -MLP.__repr__ = mlp_repr -del mlp_repr - -def mlp_str(self): - """A funky way to print a bob MLP""" - if self.hidden_activation != self.output_activation: - act = "[act: {hidden}%s | {output}%s]" % (self.hidden_activation, self.output_activation) - else: - act = "[act: %s]" % self.hidden_activation - sub = "" - if not (self.input_subtract == 0.0).all(): - sub = "\n subtract: %s" % self.input_subtract - div = "" - if not (self.input_divide == 1.0).all(): - div = "\n divide: %s" % self.input_divide - has_bias = False - bias = "" - for i, k in enumerate(self.biases): - if not (k == 0.0).all(): - has_bias = True - bias += "\n bias[%d]:\n %s" % (i, k) - weight = "" - for i, k in enumerate(self.weights): - weight += "\n weight[%d]:\n %s" % (i, k) - return 'MLP %s@%s [bias: %s]%s%s%s%s%s' % \ - (self.weights[0].dtype, self.shape, str(has_bias).lower(), - act, sub, div, bias, weight) -MLP.__str__ = mlp_str -del mlp_str diff --git a/xbob/machine/bic.cc b/xbob/machine/bic.cc deleted file mode 100644 index 33281ec..0000000 --- a/xbob/machine/bic.cc +++ /dev/null @@ -1,127 +0,0 @@ -/** - * @file machine/python/bic.cc - * @date Wed Jun 6 10:29:09 CEST 2012 - * @author Manuel Guenther <Manuel.Guenther@idiap.ch> - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob/python/ndarray.h> -#include <boost/python.hpp> -#include <bob/machine/BICMachine.h> -#include <bob/io/HDF5File.h> -#include <bob/python/exception.h> - - -static double bic_call_(const bob::machine::BICMachine& machine, bob::python::const_ndarray input){ - double o; - machine.forward_(input.bz<double,1>(), o); - return o; -} - -static double bic_call(const bob::machine::BICMachine& machine, bob::python::const_ndarray input){ - double o; - machine.forward(input.bz<double,1>(), o); - return o; -} - -void bind_machine_bic(){ - - // bind BICMachine - boost::python::class_<bob::machine::BICMachine, boost::shared_ptr<bob::machine::BICMachine> > ( - "BICMachine", - "This machine is designed to classify image differences to be either intrapersonal or extrapersonal. " - "There are two possible implementations of the BIC:\n" - "\n" - "* 'The Bayesian Intrapersonal/Extrapersonal Classifier' from Teixeira [1]_. " - " A full projection of the data is performed. No prior for the classes has to be selected.\n" - "* 'Face Detection and Recognition using Maximum Likelihood Classifiers on Gabor Graphs' from Guenther and Wuertz [2]_." - " Only mean and variance of the difference vectors are calculated. There is no subspace truncation and no priors.\n" - "\n" - "What kind of machine is used is dependent on the way, this class is trained via the BICTrainer.\n" - "\n" - ".. [1] Marcio Luis Teixeira. The Bayesian intrapersonal/extrapersonal classifier. Colorado State University, 2003.\n" - ".. [2] Manuel Guenther and Rolf P. Wuertz. Face detection and recognition using maximum likelihood classifiers on Gabor graphs. International Journal of Pattern Recognition and Artificial Intelligence, 23(3):433-461, 2009.", - boost::python::init<bool>( - (boost::python::arg("self"), boost::python::arg("use_dffs") = false), - "Initializes an empty BICMachine. The optional boolean parameter specifies whether to use the DFFS in the BIC implementation. \n\n.. warning :: Use this flag with care, the default value 'False' is usually the best choice!" - ) - ) - - .def( - boost::python::init<const bob::machine::BICMachine&>( - (boost::python::arg("self"), boost::python::arg("other")), - "Constructs one BICMachine from another one by doing a deep copy." - ) - ) - - .def( - boost::python::self == boost::python::self - ) - - .def( - "is_similar_to", - &bob::machine::BICMachine::is_similar_to, - (boost::python::arg("self"), boost::python::arg("other"), boost::python::arg("r_epsilon") = 1e-5, boost::python::arg("a_epsilon") = 1e-8), - "Compares this BICMachine with the 'other' one to be approximately the same." - ) - - .def( - "load", - &bob::machine::BICMachine::load, - (boost::python::arg("self"), boost::python::arg("file")), - "Loads the configuration parameters from an hdf5 file." - ) - - .def( - "save", - &bob::machine::BICMachine::save, - (boost::python::arg("self"), boost::python::arg("file")), - "Saves the configuration parameters to an hdf5 file." - ) - - .def( - "__call__", - &bic_call, - ( - boost::python::arg("self"), - boost::python::arg("input") - ), - "Computes the BIC or IEC score for the given input vector, which results of a comparison of two (facial) images. " - "The resulting value is returned as a single float value. " - "The score itself is the log-likelihood score of the given input vector belonging to the intrapersonal class. " - "No sanity checks of input and output are performed." - ) - - .def( - "forward_", - &bic_call_, - ( - boost::python::arg("self"), - boost::python::arg("input") - ), - "Computes the BIC or IEC score for the given input vector, which results of a comparison of two (facial) images. " - "The score itself is the log-likelihood score of the given input vector belonging to the intrapersonal class. " - "No sanity checks of input are performed." - ) - - .def( - "forward", - &bic_call, - ( - boost::python::arg("self"), - boost::python::arg("input") - ), - "Computes the BIC or IEC score for the given input vector, which results of a comparison of two (facial) images. " - "The score itself is the log-likelihood score of the given input vector belonging to the intrapersonal class. " - "Sanity checks of input shape are performed." - ) - - .add_property( - "use_dffs", - // cast overloaded function with the same name to its type... - static_cast<bool (bob::machine::BICMachine::*)() const>(&bob::machine::BICMachine::use_DFFS), - static_cast<void (bob::machine::BICMachine::*)(bool)>(&bob::machine::BICMachine::use_DFFS), - "Should the Distance From Feature Space (DFFS) measure be added during scoring? \n\n.. warning :: Only set this flag to True if the number of intrapersonal and extrapersonal training pairs is approximately equal. Otherwise, weird thing may happen!" - ); -} diff --git a/xbob/machine/cleanup.h b/xbob/machine/cleanup.h deleted file mode 100644 index d6f0011..0000000 --- a/xbob/machine/cleanup.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Wed 11 Dec 08:42:53 2013 - * - * @brief Some C++ tricks to make our life dealing with Python references a bit - * easier - */ - -#include <Python.h> -#include <memory> - -/** - * Calls Py_DECREF(x) on the input object x. Usage pattern: - * - * PyObject* x = ... // builds x with a new python reference - * auto protected_x = make_safe(x); - * - * After this point, no need to worry about DECREF'ing x anymore. - * You can still use `x' inside your code, or protected_x.get(). - */ -template <typename T> std::shared_ptr<T> make_safe(T* o) { - return std::shared_ptr<T>(o, [&](T* p){Py_DECREF(p);}); -} - -/** - * Calls Py_XDECREF(x) on the input object x. Usage pattern: - * - * PyObject* x = ... // builds x with a new python reference, x may be NULL - * auto protected_x = make_xsafe(x); - * - * After this point, no need to worry about XDECREF'ing x anymore. - * You can still use `x' inside your code, or protected_x.get(). Note - * `x' may be NULL with this method. - */ -template <typename T> std::shared_ptr<T> make_xsafe(T* o) { - return std::shared_ptr<T>(o, [&](T* p){Py_XDECREF(p);}); -} diff --git a/xbob/machine/externals.cpp b/xbob/machine/externals.cpp deleted file mode 100644 index bf8380b..0000000 --- a/xbob/machine/externals.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Thu 7 Nov 13:50:16 2013 - * - * @brief Binds configuration information available from bob - */ - -#include <Python.h> -#include "cleanup.h" - -#define XBOB_MACHINE_MODULE -#include <xbob.machine/config.h> -#include <bob/config.h> -#include <boost/format.hpp> - -#if WITH_LIBSVM -#include <svm.h> -#endif - -static PyObject* get_libsvm_version() { -#if WITH_LIBSVM - boost::format s("%d.%d.%d"); - s % (LIBSVM_VERSION / 100); - s % ((LIBSVM_VERSION % 100) / 10); - s % (LIBSVM_VERSION % 10); - return Py_BuildValue("s", s.str().c_str()); -#else - return Py_BuildValue("s", "unavailable"); -#endif -} - -static PyObject* build_version_dictionary() { - - PyObject* retval = PyDict_New(); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - PyObject* version_string = get_libsvm_version(); - if (!version_string) return 0; - auto version_string_ = make_safe(version_string); - - int status = PyDict_SetItemString(retval, "libsvm", version_string); - if (status == 0) return 0; - - Py_INCREF(retval); - return retval; - -} - -static PyMethodDef module_methods[] = { - {0} /* Sentinel */ -}; - -PyDoc_STRVAR(module_docstr, -"Information about software used to compile the C++ Bob API" -); - -PyMODINIT_FUNC XBOB_EXT_ENTRY_NAME (void) { - - PyObject* m = Py_InitModule3(XBOB_EXT_MODULE_NAME, module_methods, module_docstr); - - /* register some constants */ - PyModule_AddIntConstant(m, "__api_version__", XBOB_MACHINE_API_VERSION); - PyModule_AddStringConstant(m, "__version__", XBOB_EXT_MODULE_VERSION); - - PyObject* dict = build_version_dictionary(); - if (!dict) return; - PyModule_AddObject(m, "versions", dict); - -} diff --git a/xbob/machine/gabor.cc b/xbob/machine/gabor.cc deleted file mode 100644 index bc6b202..0000000 --- a/xbob/machine/gabor.cc +++ /dev/null @@ -1,252 +0,0 @@ -/** - * @file machine/python/gabor.cc - * @date 2012-03-05 - * @author Manuel Guenther <Manuel.Guenther@idiap.ch> - * - * @brief Bindings for the GaborGraphMachine and several GaborJetSimilarities - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - - -#include <boost/python.hpp> -#include <bob/python/ndarray.h> - -#include <bob/ip/GaborWaveletTransform.h> -#include <bob/machine/GaborGraphMachine.h> -#include <bob/machine/GaborJetSimilarities.h> - -static void bob_extract(bob::machine::GaborGraphMachine& self, bob::python::const_ndarray input_jet_image, bob::python::ndarray output_graph){ - if (output_graph.type().nd == 2){ - blitz::Array<double,2> graph = output_graph.bz<double,2>(); - self.extract(input_jet_image.bz<double,3>(), graph); - } else if (output_graph.type().nd == 3){ - blitz::Array<double,3> graph = output_graph.bz<double,3>(); - self.extract(input_jet_image.bz<double,4>(), graph); - } else { - PYTHON_ERROR(RuntimeError, "parameter `output_graph' should be 2 or 3 dimensional, but you passed a " SIZE_T_FMT " dimensional array.", output_graph.type().nd); - } -} - -static bob::python::ndarray bob_extract2(bob::machine::GaborGraphMachine& self, bob::python::const_ndarray input_jet_image){ - if (input_jet_image.type().nd == 3){ - const blitz::Array<double,3> jet_image = input_jet_image.bz<double,3>(); - bob::python::ndarray output_graph(bob::core::array::t_float64, self.numberOfNodes(), jet_image.shape()[2]); - blitz::Array<double,2> graph = output_graph.bz<double,2>(); - self.extract(jet_image, graph); - return output_graph; - } else if (input_jet_image.type().nd == 4){ - const blitz::Array<double,4> jet_image = input_jet_image.bz<double,4>(); - bob::python::ndarray output_graph(bob::core::array::t_float64, self.numberOfNodes(), jet_image.shape()[2], jet_image.shape()[3]); - blitz::Array<double,3> graph = output_graph.bz<double,3>(); - self.extract(jet_image, graph); - return output_graph; - } else { - PYTHON_ERROR(RuntimeError, "parameter `input_jet_image' should be 3 or 4 dimensional, but you passed a " SIZE_T_FMT " dimensional array.", input_jet_image.type().nd); - } -} - -static void bob_average(bob::machine::GaborGraphMachine& self, bob::python::const_ndarray many_graph_jets, bob::python::ndarray averaged_graph_jets){ - blitz::Array<double,3> graph = averaged_graph_jets.bz<double,3>(); - self.average(many_graph_jets.bz<double,4>(), graph); -} - -static double bob_similarity(bob::machine::GaborGraphMachine& self, bob::python::const_ndarray model_graph, bob::python::ndarray probe_graph, const bob::machine::GaborJetSimilarity& similarity_function){ - switch (probe_graph.type().nd){ - case 2:{ // Gabor graph including jets without phases - blitz::Array<double,2> probe = probe_graph.bz<double,2>(); - switch (model_graph.type().nd){ - case 2:{ - return self.similarity(model_graph.bz<double,2>(), probe, similarity_function); - } - case 3:{ - return self.similarity(model_graph.bz<double,3>(), probe, similarity_function); - } - default: - PYTHON_ERROR(RuntimeError, "parameter `model_graph' should be 2 or 3 dimensional (because `probe_graph' is 2D), but you passed a " SIZE_T_FMT " dimensional array.", model_graph.type().nd); - } - } - - case 3:{ // Gabor graph including jets with phases - blitz::Array<double,3> probe = probe_graph.bz<double,3>(); - switch (model_graph.type().nd){ - case 3:{ - return self.similarity(model_graph.bz<double,3>(), probe, similarity_function); - } - case 4:{ - return self.similarity(model_graph.bz<double,4>(), probe, similarity_function); - } - default: - PYTHON_ERROR(RuntimeError, "parameter `model_graph' should be 3 or 4 dimensional (because `probe_graph' is 3D), but you passed a " SIZE_T_FMT " dimensional array.", model_graph.type().nd); - } - } - - default: // unknown graph shape - PYTHON_ERROR(RuntimeError, "parameter `probe_graph' should be 2 or 3 dimensional, but you passed a " SIZE_T_FMT " dimensional array.", probe_graph.type().nd); - } -} - -static double bob_jet_sim(const bob::machine::GaborJetSimilarity& self, bob::python::const_ndarray jet1, bob::python::const_ndarray jet2){ - switch (jet1.type().nd){ - case 1:{ - return self(jet1.bz<double,1>(), jet2.bz<double,1>()); - } - case 2:{ - return self(jet1.bz<double,2>(), jet2.bz<double,2>()); - } - default: - PYTHON_ERROR(RuntimeError, "parameter `jet1' should be 1 or 2 dimensional, but you passed a " SIZE_T_FMT " dimensional array.", jet1.type().nd); - } -} - -void bind_machine_gabor(){ - ///////////////////////////////////////////////////////////////////////////////////////// - //////////////// Gabor jet similarities - boost::python::class_<bob::machine::GaborJetSimilarity, boost::noncopyable >( - "GaborJetSimilarity", - "This is the pure virtual base class for all Gabor jet similarities.", - boost::python::no_init - ) - - .def( - boost::python::init<bob::machine::GaborJetSimilarity::SimilarityType, const bob::ip::GaborWaveletTransform&>( - ( - boost::python::arg("self"), - boost::python::arg("type"), - boost::python::arg("gwt") = bob::ip::GaborWaveletTransform() - ), - "Generates a Gabor jet similarity measure of the given type. The parameters of the given transform are used for disparity-like similarity functions only." - ) - ) - - .def( - "save", - &bob::machine::GaborJetSimilarity::save, - (boost::python::arg("self"), boost::python::arg("config")), - "Saves the parameterization of this Gabor jet similarity function to HDF5 file." - ) - - .def( - "load", - &bob::machine::GaborJetSimilarity::load, - (boost::python::arg("self"), boost::python::arg("config")), - "Loads the parameterization of this Gabor jet similarity function from HDF5 file." - ) - - .def( - "disparity", - &bob::machine::GaborJetSimilarity::disparity, - (boost::python::arg("self")), - "Returns the disparity computed by the latest call. Only valid for disparity-like similarity function types." - ) - - .def( - "__call__", - &bob_jet_sim, - (boost::python::arg("self"), boost::python::arg("jet1"), boost::python::arg("jet2")), - "Computes the similarity between the given Gabor jets." - ); - - boost::python::enum_<bob::machine::GaborJetSimilarity::SimilarityType>("gabor_jet_similarity_type") - .value("SCALAR_PRODUCT", bob::machine::GaborJetSimilarity::SCALAR_PRODUCT) - .value("CANBERRA", bob::machine::GaborJetSimilarity::CANBERRA) - .value("DISPARITY", bob::machine::GaborJetSimilarity::DISPARITY) - .value("PHASE_DIFF", bob::machine::GaborJetSimilarity::PHASE_DIFF) - .value("PHASE_DIFF_PLUS_CANBERRA", bob::machine::GaborJetSimilarity::PHASE_DIFF_PLUS_CANBERRA) - .export_values(); - - ///////////////////////////////////////////////////////////////////////////////////////// - //////////////// Gabor graph machine - boost::python::class_<bob::machine::GaborGraphMachine, boost::shared_ptr<bob::machine::GaborGraphMachine> >( - "GaborGraphMachine", - "This class implements functionality dealing with Gabor graphs, Gabor graph comparison and Gabor graph averaging.", - boost::python::no_init - ) - - .def( - boost::python::init<>( - boost::python::arg("self"), - "Generates an empty Grid graph extractor. This extractor should only be used to compute average graphs or to compare two graphs!" - ) - ) - - .def( - boost::python::init<const bob::machine::GaborGraphMachine&>( - (boost::python::arg("self"), boost::python::arg("other")), - "Constructs a GaborGraphMachine from the one by doing a deep copy." - ) - ) - - .def( - boost::python::self == boost::python::self - ) - - .def( - boost::python::init<blitz::TinyVector<int,2>, blitz::TinyVector<int,2>, int, int, int, int>( - (boost::python::arg("self"), boost::python::arg("lefteye"), boost::python::arg("righteye"), boost::python::arg("between")=3, boost::python::arg("along")=2, boost::python::arg("above")=4, boost::python::arg("below")=6), - "Generates a Grid graph extractor with nodes put according to the given eye positions, and the given number of nodes between, along, above, and below the eyes." - ) - ) - - .def( - boost::python::init<blitz::TinyVector<int,2>, blitz::TinyVector<int,2>, blitz::TinyVector<int,2> >( - (boost::python::arg("self"), boost::python::arg("first"), boost::python::arg("last"), boost::python::arg("step")), - "Generates a Grid graph extractor with nodes put between the given first and last position in the desired step size." - ) - ) - - .def( - "save", - &bob::machine::GaborGraphMachine::save, - (boost::python::arg("self"), boost::python::arg("config")), - "Saves the parameterization of this Gabor graph extractor to HDF5 file." - ) - - .def( - "load", - &bob::machine::GaborGraphMachine::load, - (boost::python::arg("self"), boost::python::arg("config")), - "Loads the parameterization of this Gabor graph extractor from HDF5 file." - ) - - .add_property( - "number_of_nodes", - &bob::machine::GaborGraphMachine::numberOfNodes, - "The number of nodes of the graph." - ) - - .add_property( - "nodes", - &bob::machine::GaborGraphMachine::nodes, - "The node positions of the graph." - ) - - .def( - "__call__", - &bob_extract, - (boost::python::arg("self"), boost::python::arg("jet_image"), boost::python::arg("graph_jets")), - "Extracts the Gabor jets at the desired locations from the given Gabor jet image" - ) - - .def( - "__call__", - &bob_extract2, - (boost::python::arg("self"), boost::python::arg("jet_image")), - "Extracts and returns the Gabor jets at the desired locations from the given Gabor jet image" - ) - - .def( - "average", - &bob_average, - (boost::python::arg("self"), boost::python::arg("many_graph_jets"), boost::python::arg("averaged_graph_jets")), - "Averages the given list of Gabor graphs into one Gabor graph" - ) - - .def( - "similarity", - &bob_similarity, - (boost::python::arg("self"), boost::python::arg("model_graph_jets"), boost::python::arg("probe_graph_jets"), boost::python::arg("jet_similarity_function")), - "Computes the similarity between the given probe graph and the gallery, which might be a single graph or a collection of graphs" - ); - -} diff --git a/xbob/machine/gaussian.cc b/xbob/machine/gaussian.cc deleted file mode 100644 index baa3aba..0000000 --- a/xbob/machine/gaussian.cc +++ /dev/null @@ -1,88 +0,0 @@ -/** - * @file machine/python/gaussian.cc - * @date Tue Jul 26 15:11:33 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/python.hpp> -#include <bob/python/ndarray.h> -#include <bob/machine/Gaussian.h> - - -using namespace boost::python; - -static void py_setMean(bob::machine::Gaussian& machine, - bob::python::const_ndarray mean) -{ - machine.setMean(mean.bz<double,1>()); -} - -static void py_setVariance(bob::machine::Gaussian& machine, - bob::python::const_ndarray variance) -{ - machine.setVariance(variance.bz<double,1>()); -} - -static void py_setVarianceThresholds(bob::machine::Gaussian& machine, - bob::python::const_ndarray varianceThresholds) -{ - machine.setVarianceThresholds(varianceThresholds.bz<double,1>()); -} - -static tuple get_shape(const bob::machine::Gaussian& m) -{ - return make_tuple(m.getNInputs()); -} - -static void set_shape(bob::machine::Gaussian& m, - const blitz::TinyVector<int,1>& s) -{ - m.resize(s(0)); -} - -static double py_logLikelihood(const bob::machine::Gaussian& machine, - bob::python::const_ndarray input) -{ - double output; - machine.forward(input.bz<double,1>(), output); - return output; -} - -static double py_logLikelihood_(const bob::machine::Gaussian& machine, - bob::python::const_ndarray input) -{ - double output; - machine.forward_(input.bz<double,1>(), output); - return output; -} - -void bind_machine_gaussian() -{ - class_<bob::machine::Gaussian, boost::shared_ptr<bob::machine::Gaussian>, bases<bob::machine::Machine<blitz::Array<double,1>, double> > >("Gaussian", - "This class implements a multivariate diagonal Gaussian distribution.", init<>(arg("self"))) - .def(init<const size_t>((arg("self"), arg("n_inputs")))) - .def(init<bob::machine::Gaussian&>((arg("self"), arg("other")))) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")))) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::Gaussian::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this Gaussian with the 'other' one to be approximately the same.") - .add_property("dim_d", &bob::machine::Gaussian::getNInputs, &bob::machine::Gaussian::setNInputs, - "Dimensionality of the input feature space") - .add_property("mean", make_function(&bob::machine::Gaussian::getMean, return_value_policy<copy_const_reference>()), &py_setMean, "Mean of the Gaussian") - .add_property("variance", make_function(&bob::machine::Gaussian::getVariance, return_value_policy<copy_const_reference>()), &py_setVariance, "The diagonal of the (diagonal) covariance matrix") - .add_property("variance_thresholds", make_function(&bob::machine::Gaussian::getVarianceThresholds, return_value_policy<copy_const_reference>()), &py_setVarianceThresholds, - "The variance flooring thresholds, i.e. the minimum allowed value of variance in each dimension. " - "The variance will be set to this value if an attempt is made to set it to a smaller value.") - .add_property("shape", &get_shape, &set_shape, "A tuple that represents the dimensionality of the Gaussian ``(dim_d,)``.") - .def("set_variance_thresholds", (void (bob::machine::Gaussian::*)(const double))&bob::machine::Gaussian::setVarianceThresholds, (arg("self"), arg("var_thd")), - "Set the variance flooring thresholds equal to the given threshold for all the dimensions.") - .def("resize", &bob::machine::Gaussian::resize, (arg("self"), arg("dim_d")), "Set the input dimensionality, reset the mean to zero and the variance to one.") - .def("log_likelihood", &py_logLikelihood, (arg("self"), arg("sample")), "Output the log likelihood of the sample, x. The input size is checked.") - .def("log_likelihood_", &py_logLikelihood_, (arg("self"), arg("sample")), "Output the log likelihood of the sample, x. The input size is NOT checked.") - .def("save", &bob::machine::Gaussian::save, (arg("self"), arg("config")), "Save to a Configuration") - .def("load", &bob::machine::Gaussian::load, (arg("self"), arg("config")),"Load from a Configuration") - .def(self_ns::str(self_ns::self)) - ; -} diff --git a/xbob/machine/gmm.cc b/xbob/machine/gmm.cc deleted file mode 100644 index fc2a9cf..0000000 --- a/xbob/machine/gmm.cc +++ /dev/null @@ -1,295 +0,0 @@ -/** - * @file machine/python/gmm.cc - * @date Tue Jul 26 15:11:33 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ -#include <boost/python.hpp> -#include <bob/python/ndarray.h> -#include <boost/concept_check.hpp> -#include <bob/machine/GMMStats.h> -#include <bob/machine/GMMMachine.h> -#include <blitz/array.h> - - -using namespace boost::python; - -static object py_gmmstats_getN(bob::machine::GMMStats& s) -{ - bob::python::ndarray n(bob::core::array::t_float64, s.n.extent(0)); - blitz::Array<double,1> n_ = n.bz<double,1>(); - n_ = s.n; - return n.self(); -} - -static void py_gmmstats_setN(bob::machine::GMMStats& s, - bob::python::const_ndarray n) -{ - s.n = n.bz<double,1>(); -} - -static object py_gmmstats_getSumpx(bob::machine::GMMStats& s) -{ - bob::python::ndarray sumpx(bob::core::array::t_float64, s.sumPx.extent(0), - s.sumPx.extent(1)); - blitz::Array<double,2> sumpx_ = sumpx.bz<double,2>(); - sumpx_ = s.sumPx; - return sumpx.self(); -} - -static void py_gmmstats_setSumpx(bob::machine::GMMStats& s, - bob::python::const_ndarray sumpx) -{ - s.sumPx = sumpx.bz<double,2>(); -} - -static object py_gmmstats_getSumpxx(bob::machine::GMMStats& s) -{ - bob::python::ndarray sumpxx(bob::core::array::t_float64, s.sumPxx.extent(0), - s.sumPxx.extent(1)); - blitz::Array<double,2> sumpxx_ = sumpxx.bz<double,2>(); - sumpxx_ = s.sumPxx; - return sumpxx.self(); -} - -static void py_gmmstats_setSumpxx(bob::machine::GMMStats& s, - bob::python::const_ndarray sumpxx) -{ - s.sumPxx = sumpxx.bz<double,2>(); -} - - -static void py_gmmmachine_setWeights(bob::machine::GMMMachine& machine, - bob::python::const_ndarray weights) -{ - machine.setWeights(weights.bz<double,1>()); -} - -static object py_gmmmachine_getMeans(const bob::machine::GMMMachine& machine) -{ - bob::python::ndarray means(bob::core::array::t_float64, - machine.getNGaussians(), machine.getNInputs()); - blitz::Array<double,2> means_ = means.bz<double,2>(); - machine.getMeans(means_); - return means.self(); -} - -static void py_gmmmachine_setMeans(bob::machine::GMMMachine& machine, - bob::python::const_ndarray means) -{ - machine.setMeans(means.bz<double,2>()); -} - -static void py_gmmmachine_setMeanSupervector(bob::machine::GMMMachine& machine, - bob::python::const_ndarray vec) -{ - machine.setMeanSupervector(vec.bz<double,1>()); -} - -static object py_gmmmachine_getVariances(const bob::machine::GMMMachine& machine) -{ - bob::python::ndarray variances(bob::core::array::t_float64, - machine.getNGaussians(), machine.getNInputs()); - blitz::Array<double,2> variances_ = variances.bz<double,2>(); - machine.getVariances(variances_); - return variances.self(); -} - -static void py_gmmmachine_setVariances(bob::machine::GMMMachine& machine, - bob::python::const_ndarray variances) -{ - machine.setVariances(variances.bz<double,2>()); -} - -static void py_gmmmachine_setVarianceSupervector(bob::machine::GMMMachine& machine, - bob::python::const_ndarray vec) -{ - machine.setVarianceSupervector(vec.bz<double,1>()); -} - -static object py_gmmmachine_getVarianceThresholds(const bob::machine::GMMMachine& machine) -{ - bob::python::ndarray varianceThresholds(bob::core::array::t_float64, - machine.getNGaussians(), machine.getNInputs()); - blitz::Array<double,2> varianceThresholds_ = varianceThresholds.bz<double,2>(); - machine.getVarianceThresholds(varianceThresholds_); - return varianceThresholds.self(); -} - -static void py_gmmmachine_setVarianceThresholds(bob::machine::GMMMachine& machine, - bob::python::const_ndarray varianceThresholds) -{ - machine.setVarianceThresholds(varianceThresholds.bz<double,2>()); -} - -static void py_gmmmachine_setVarianceThresholdsOther(bob::machine::GMMMachine& machine, - object o) -{ - extract<int> int_check(o); - extract<double> float_check(o); - if(int_check.check()) { //is int - machine.setVarianceThresholds(int_check()); - } - else if(float_check.check()) { //is float - machine.setVarianceThresholds(float_check()); - } - else { - //try hard-core extraction - throws TypeError, if not possible - extract<bob::python::const_ndarray> array_check(o); - if (!array_check.check()) - PYTHON_ERROR(TypeError, "Cannot extract an array from this Python object"); - bob::python::const_ndarray ar = array_check(); - machine.setVarianceThresholds(ar.bz<double,1>()); - } -} - -static tuple py_gmmmachine_get_shape(const bob::machine::GMMMachine& m) -{ - return make_tuple(m.getNGaussians(), m.getNInputs()); -} - -static void py_gmmmachine_set_shape(bob::machine::GMMMachine& m, - const blitz::TinyVector<int,2>& s) -{ - m.resize(s(0), s(1)); -} - -static double py_gmmmachine_loglikelihoodA(const bob::machine::GMMMachine& machine, - bob::python::const_ndarray x, bob::python::ndarray ll) -{ - blitz::Array<double,1> ll_ = ll.bz<double,1>(); - return machine.logLikelihood(x.bz<double,1>(), ll_); -} - -static double py_gmmmachine_loglikelihoodA_(const bob::machine::GMMMachine& machine, - bob::python::const_ndarray x, bob::python::ndarray ll) -{ - blitz::Array<double,1> ll_ = ll.bz<double,1>(); - return machine.logLikelihood_(x.bz<double,1>(), ll_); -} - -static double py_gmmmachine_loglikelihoodB(const bob::machine::GMMMachine& machine, - bob::python::const_ndarray x) -{ - return machine.logLikelihood(x.bz<double,1>()); -} - -static double py_gmmmachine_loglikelihoodB_(const bob::machine::GMMMachine& machine, - bob::python::const_ndarray x) -{ - return machine.logLikelihood_(x.bz<double,1>()); -} - -static void py_gmmmachine_accStatistics(const bob::machine::GMMMachine& machine, - bob::python::const_ndarray x, bob::machine::GMMStats& gs) -{ - const bob::core::array::typeinfo& info = x.type(); - switch(info.nd) { - case 1: - machine.accStatistics(x.bz<double,1>(), gs); - break; - case 2: - machine.accStatistics(x.bz<double,2>(), gs); - break; - default: - PYTHON_ERROR(TypeError, "cannot accStatistics of arrays with " SIZE_T_FMT " dimensions (only with 1 or 2 dimensions).", info.nd); - } -} - -static void py_gmmmachine_accStatistics_(const bob::machine::GMMMachine& machine, - bob::python::const_ndarray x, bob::machine::GMMStats& gs) -{ - const bob::core::array::typeinfo& info = x.type(); - switch(info.nd) { - case 1: - machine.accStatistics_(x.bz<double,1>(), gs); - break; - case 2: - machine.accStatistics_(x.bz<double,2>(), gs); - break; - default: - PYTHON_ERROR(TypeError, "cannot accStatistics of arrays with " SIZE_T_FMT " dimensions (only with 1 or 2 dimensions).", info.nd); - } -} - -void bind_machine_gmm() -{ - class_<bob::machine::GMMStats, boost::shared_ptr<bob::machine::GMMStats> >("GMMStats", - "A container for GMM statistics.\n" - "With respect to Reynolds, \"Speaker Verification Using Adapted " - "Gaussian Mixture Models\", DSP, 2000:\n" - "Eq (8) is n(i)\n" - "Eq (9) is sumPx(i) / n(i)\n" - "Eq (10) is sumPxx(i) / n(i)\n", - init<>(arg("self"))) - .def(init<const size_t, const size_t>((arg("self"), arg("n_gaussians"), arg("n_inputs")))) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")))) - .def(init<bob::machine::GMMStats&>((arg("self"), arg("other")), "Creates a GMMStats from another GMMStats, using the copy constructor.")) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::GMMStats::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this GMMStats with the 'other' one to be approximately the same.") - .def_readwrite("log_likelihood", &bob::machine::GMMStats::log_likelihood, "The accumulated log likelihood of all samples") - .def_readwrite("t", &bob::machine::GMMStats::T, "The accumulated number of samples") - .add_property("n", &py_gmmstats_getN, &py_gmmstats_setN, "For each Gaussian, the accumulated sum of responsibilities, i.e. the sum of P(gaussian_i|x)") - .add_property("sum_px", &py_gmmstats_getSumpx, &py_gmmstats_setSumpx, "For each Gaussian, the accumulated sum of responsibility times the sample ") - .add_property("sum_pxx", &py_gmmstats_getSumpxx, &py_gmmstats_setSumpxx, "For each Gaussian, the accumulated sum of responsibility times the sample squared") - .def("resize", &bob::machine::GMMStats::resize, (arg("self"), arg("n_gaussians"), arg("n_inputs")), - " Allocates space for the statistics and resets to zero.") - .def("init", &bob::machine::GMMStats::init, (arg("self")), "Resets statistics to zero.") - .def("save", &bob::machine::GMMStats::save, (arg("self"), arg("config")), "Save to a Configuration") - .def("load", &bob::machine::GMMStats::load, (arg("self"), arg("config")), "Load from a Configuration") - .def(self_ns::str(self_ns::self)) - .def(self_ns::self += self_ns::self) - ; - - class_<bob::machine::GMMMachine, boost::shared_ptr<bob::machine::GMMMachine>, bases<bob::machine::Machine<blitz::Array<double,1>, double> > >("GMMMachine", - "This class implements a multivariate diagonal Gaussian distribution.\n" - "See Section 2.3.9 of Bishop, \"Pattern recognition and machine learning\", 2006", - init<>(arg("self"))) - .def(init<const size_t, const size_t>((arg("self"), arg("n_gaussians"), arg("n_inputs")))) - .def(init<bob::machine::GMMMachine&>((arg("self"), arg("other")), "Creates a GMMMachine from another GMMMachine, using the copy constructor.")) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")))) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::GMMMachine::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this GMMMachine with the 'other' one to be approximately the same.") - .add_property("dim_d", &bob::machine::GMMMachine::getNInputs, &bob::machine::GMMMachine::setNInputs, "The feature dimensionality D") - .add_property("dim_c", &bob::machine::GMMMachine::getNGaussians, "The number of Gaussian components C") - .add_property("weights", make_function(&bob::machine::GMMMachine::getWeights, return_value_policy<copy_const_reference>()), &py_gmmmachine_setWeights, "The weights (also known as \"mixing coefficients\")") - .add_property("means", &py_gmmmachine_getMeans, &py_gmmmachine_setMeans, "The means of the gaussians") - .add_property("mean_supervector", make_function((const blitz::Array<double,1>& (bob::machine::GMMMachine::*)(void) const)&bob::machine::GMMMachine::getMeanSupervector, return_value_policy<copy_const_reference>()), &py_gmmmachine_setMeanSupervector, - "The mean supervector of the GMMMachine " - "(concatenation of the mean vectors of each Gaussian of the GMMMachine") - .add_property("variances", &py_gmmmachine_getVariances, &py_gmmmachine_setVariances, "The (diagonal) variances of the Gaussians") - .add_property("variance_supervector", make_function((const blitz::Array<double,1>& (bob::machine::GMMMachine::*)(void) const)&bob::machine::GMMMachine::getVarianceSupervector, return_value_policy<copy_const_reference>()), &py_gmmmachine_setVarianceSupervector, - "The variance supervector of the GMMMachine " - "(concatenation of the variance vectors of each Gaussian of the GMMMachine") - .add_property("variance_thresholds", &py_gmmmachine_getVarianceThresholds, &py_gmmmachine_setVarianceThresholds, - "The variance flooring thresholds for each Gaussian in each dimension") - .add_property("shape", &py_gmmmachine_get_shape, &py_gmmmachine_set_shape, "A tuple that represents the dimensionality of the GMMMachine ``(n_gaussians, n_inputs)``.") - .def("resize", &bob::machine::GMMMachine::resize, (arg("self"), arg("n_gaussians"), arg("n_inputs")), - "Reset the input dimensionality, and the number of Gaussian components.\n" - "Initialises the weights to uniform distribution.") - .def("set_variance_thresholds", &py_gmmmachine_setVarianceThresholdsOther, (arg("self"), arg("variance_threshold")), - "Set the variance flooring thresholds in each dimension to the same vector for all Gaussian components if the argument is a 1D numpy arrray, and equal for all Gaussian components and dimensions if the parameter is a scalar.") - .def("update_gaussian", &bob::machine::GMMMachine::updateGaussian, (arg("self"), arg("i")), - "Get the specified Gaussian component. An exception is thrown if i is out of range.") - - .def("log_likelihood", &py_gmmmachine_loglikelihoodA, args("self", "x", "log_weighted_gaussian_likelihoods"), - "Output the log likelihood of the sample, x, i.e. log(p(x|bob::machine::GMMMachine)). Inputs are checked.") - .def("log_likelihood_", &py_gmmmachine_loglikelihoodA_, args("self", "x", "log_weighted_gaussian_likelihoods"), - "Output the log likelihood of the sample, x, i.e. log(p(x|bob::machine::GMMMachine)). Inputs are NOT checked.") - .def("log_likelihood", &py_gmmmachine_loglikelihoodB, args("self", "x"), - " Output the log likelihood of the sample, x, i.e. log(p(x|GMM)). Inputs are checked.") - .def("log_likelihood_", &py_gmmmachine_loglikelihoodB_, args("self", "x"), - " Output the log likelihood of the sample, x, i.e. log(p(x|GMM)). Inputs are checked.") - .def("acc_statistics", &py_gmmmachine_accStatistics, args("self", "x", "stats"), - "Accumulate the GMM statistics for this sample(s). Inputs are checked.") - .def("acc_statistics_", &py_gmmmachine_accStatistics_, args("self", "x", "stats"), - "Accumulate the GMM statistics for this sample(s). Inputs are NOT checked.") - .def("load", &bob::machine::GMMMachine::load, (arg("self"), arg("config")), "Load from a Configuration") - .def("save", &bob::machine::GMMMachine::save, (arg("self"), arg("config")), "Save to a Configuration") - .def(self_ns::str(self_ns::self)) - ; - -} diff --git a/xbob/machine/include/xbob.machine/api.h b/xbob/machine/include/xbob.machine/api.h deleted file mode 100644 index 576fcdf..0000000 --- a/xbob/machine/include/xbob.machine/api.h +++ /dev/null @@ -1,352 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Tue 5 Nov 12:22:48 2013 - * - * @brief C/C++ API for bob::machine - */ - -#ifndef XBOB_MACHINE_H -#define XBOB_MACHINE_H - -#include <Python.h> -#include <xbob.machine/config.h> -#include <bob/machine/Activation.h> -#include <bob/machine/LinearMachine.h> - -#define XBOB_MACHINE_MODULE_PREFIX xbob.machine -#define XBOB_MACHINE_MODULE_NAME _library - -/******************* - * C API functions * - *******************/ - -/************** - * Versioning * - **************/ - -#define PyXbobMachine_APIVersion_NUM 0 -#define PyXbobMachine_APIVersion_TYPE int - -/**************************************** - * Bindings for xbob.machine.Activation * - ****************************************/ - -/* Type definition for PyBobMachineActivationObject */ -typedef struct { - PyObject_HEAD - - /* Type-specific fields go here. */ - bob::machine::Activation* base; - -} PyBobMachineActivationObject; - -#define PyBobMachineActivation_Type_NUM 1 -#define PyBobMachineActivation_Type_TYPE PyTypeObject - -#define PyBobMachineActivation_Check_NUM 2 -#define PyBobMachineActivation_Check_RET int -#define PyBobMachineActivation_Check_PROTO (PyObject* o) - -/************************************************ - * Bindings for xbob.machine.IdentityActivation * - ************************************************/ - -/* Type definition for PyBobMachineIdentityActivationObject */ -typedef struct { - PyBobMachineActivationObject parent; - - /* Type-specific fields go here. */ - bob::machine::IdentityActivation* base; - -} PyBobMachineIdentityActivationObject; - -#define PyBobMachineIdentityActivation_Type_NUM 3 -#define PyBobMachineIdentityActivation_Type_TYPE PyTypeObject - -/********************************************** - * Bindings for xbob.machine.LinearActivation * - **********************************************/ - -/* Type definition for PyBobMachineLinearActivationObject */ -typedef struct { - PyBobMachineActivationObject parent; - - /* Type-specific fields go here. */ - bob::machine::LinearActivation* base; - -} PyBobMachineLinearActivationObject; - -#define PyBobMachineLinearActivation_Type_NUM 4 -#define PyBobMachineLinearActivation_Type_TYPE PyTypeObject - -/************************************************ - * Bindings for xbob.machine.LogisticActivation * - ************************************************/ - -/* Type definition for PyBobMachineLogisticActivationObject */ -typedef struct { - PyBobMachineActivationObject parent; - - /* Type-specific fields go here. */ - bob::machine::LogisticActivation* base; - -} PyBobMachineLogisticActivationObject; - -#define PyBobMachineLogisticActivation_Type_NUM 5 -#define PyBobMachineLogisticActivation_Type_TYPE PyTypeObject - -/********************************************************* - * Bindings for xbob.machine.HyperbolicTangentActivation * - *********************************************************/ - -/* Type definition for PyBobMachineHyperbolicTangentActivationObject */ -typedef struct { - PyBobMachineActivationObject parent; - - /* Type-specific fields go here. */ - bob::machine::HyperbolicTangentActivation* base; - -} PyBobMachineHyperbolicTangentActivationObject; - -#define PyBobMachineHyperbolicTangentActivation_Type_NUM 6 -#define PyBobMachineHyperbolicTangentActivation_Type_TYPE PyTypeObject - -/******************************************************************* - * Bindings for xbob.machine.MultipliedHyperbolicTangentActivation * - *******************************************************************/ - -/* Type definition: PyBobMachineMultipliedHyperbolicTangentActivationObject */ -typedef struct { - PyBobMachineActivationObject parent; - - /* Type-specific fields go here. */ - bob::machine::MultipliedHyperbolicTangentActivation* base; - -} PyBobMachineMultipliedHyperbolicTangentActivationObject; - -#define PyBobMachineMultipliedHyperbolicTangentActivation_Type_NUM 7 -#define PyBobMachineMultipliedHyperbolicTangentActivation_Type_TYPE PyTypeObject - -/******************************************* - * Bindings for xbob.machine.LinearMachine * - *******************************************/ - -/* Type definition: PyBobMachineLinear */ -typedef struct { - PyObject_HEAD - - /* Type-specific fields go here. */ - bob::machine::LinearMachine* machine; - -} PyBobMachineLinearObject; - -#define PyBobMachineLinear_Type_NUM 8 -#define PyBobMachineLinear_Type_TYPE PyTypeObject - -#define PyBobMachineLinear_Check_NUM 9 -#define PyBobMachineLinear_Check_RET int -#define PyBobMachineLinear_Check_PROTO (PyObject* o) - -/* Total number of C API pointers */ -#define PyXbobMachine_API_pointers 10 - -#ifdef XBOB_MACHINE_MODULE - - /* This section is used when compiling `xbob.machine' itself */ - - /************** - * Versioning * - **************/ - - extern int PyXbobMachine_APIVersion; - - /**************************************** - * Bindings for xbob.machine.Activation * - ****************************************/ - - extern PyBobMachineActivation_Type_TYPE PyBobMachineActivation_Type; - - PyBobMachineActivation_Check_RET PyBobMachineActivation_Check PyBobMachineActivation_Check_PROTO; - - /************************************************ - * Bindings for xbob.machine.IdentityActivation * - ************************************************/ - - extern PyBobMachineIdentityActivation_Type_TYPE PyBobMachineIdentityActivation_Type; - - /********************************************** - * Bindings for xbob.machine.LinearActivation * - **********************************************/ - - extern PyBobMachineLinearActivation_Type_TYPE PyBobMachineLinearActivation_Type; - - /************************************************ - * Bindings for xbob.machine.LogisticActivation * - ************************************************/ - - extern PyBobMachineLogisticActivation_Type_TYPE PyBobMachineLogisticActivation_Type; - - /********************************************************* - * Bindings for xbob.machine.HyperbolicTangentActivation * - *********************************************************/ - - extern PyBobMachineHyperbolicTangentActivation_Type_TYPE PyBobMachineHyperbolicTangentActivation_Type; - - /******************************************************************* - * Bindings for xbob.machine.MultipliedHyperbolicTangentActivation * - *******************************************************************/ - - extern PyBobMachineMultipliedHyperbolicTangentActivation_Type_TYPE PyBobMachineMultipliedHyperbolicTangentActivation_Type; - - /************************************ - * Bindings for xbob.machine.Linear * - ************************************/ - - extern PyBobMachineLinear_Type_TYPE PyBobMachineLinear_Type; - - PyBobMachineLinear_Check_RET PyBobMachineLinear_Check PyBobMachineLinear_Check_PROTO; - -#else - - /* This section is used in modules that use `blitz.array's' C-API */ - -/************************************************************************ - * Macros to avoid symbol collision and allow for separate compilation. * - * We pig-back on symbols already defined for NumPy and apply the same * - * set of rules here, creating our own API symbol names. * - ************************************************************************/ - -# if defined(PY_ARRAY_UNIQUE_SYMBOL) -# define XBOB_MACHINE_MAKE_API_NAME_INNER(a) XBOB_MACHINE_ ## a -# define XBOB_MACHINE_MAKE_API_NAME(a) XBOB_MACHINE_MAKE_API_NAME_INNER(a) -# define PyXbobMachine_API XBOB_MACHINE_MAKE_API_NAME(PY_ARRAY_UNIQUE_SYMBOL) -# endif - -# if defined(NO_IMPORT_ARRAY) - extern void **PyXbobMachine_API; -# else -# if defined(PY_ARRAY_UNIQUE_SYMBOL) - void **PyXbobMachine_API; -# else - static void **PyXbobMachine_API=NULL; -# endif -# endif - - /************** - * Versioning * - **************/ - -# define PyXbobMachine_APIVersion (*(PyXbobMachine_APIVersion_TYPE *)PyXbobMachine_API[PyXbobMachine_APIVersion_NUM]) - - /**************************************** - * Bindings for xbob.machine.Activation * - ****************************************/ - -# define PyBobMachineActivation_Type (*(PyBobMachineActivation_Type_TYPE *)PyXbobMachine_API[PyBobMachineActivation_Type_NUM]) - -# define PyBobMachineActivation_Check (*(PyBobMachineActivation_Check_RET (*)PyBobMachineActivation_Check_PROTO) PyXbobMachine_API[PyBobMachineActivation_Check_NUM]) - - /************************************************ - * Bindings for xbob.machine.IdentityActivation * - ************************************************/ - -# define PyBobMachineIdentityActivation_Type (*(PyBobMachineIdentityActivation_Type_TYPE *)PyXbobMachine_API[PyBobMachineIdentityActivation_Type_NUM]) - - /********************************************** - * Bindings for xbob.machine.LinearActivation * - **********************************************/ - -# define PyBobMachineLinearActivation_Type (*(PyBobMachineLinearActivation_Type_TYPE *)PyXbobMachine_API[PyBobMachineLinearActivation_Type_NUM]) - - /************************************************ - * Bindings for xbob.machine.LogisticActivation * - ************************************************/ - -# define PyBobMachineLogisticActivation_Type (*(PyBobMachineLogisticActivation_Type_TYPE *)PyXbobMachine_API[PyBobMachineLogisticActivation_Type_NUM]) - - /********************************************************* - * Bindings for xbob.machine.HyperbolicTangentActivation * - *********************************************************/ - -# define PyBobMachineHyperbolicTangentActivation_Type (*(PyBobMachineHyperbolicTangentActivation_Type_TYPE *)PyXbobMachine_API[PyBobMachineHyperbolicTangentActivation_Type_NUM]) - - /******************************************************************* - * Bindings for xbob.machine.MultipliedHyperbolicTangentActivation * - *******************************************************************/ - -# define PyBobMachineMultipliedHyperbolicTangentActivation_Type (*(PyBobMachineMultipliedHyperbolicTangentActivation_Type_TYPE *)PyXbobMachine_API[PyBobMachineMultipliedHyperbolicTangentActivation_Type_NUM]) - - /************************************ - * Bindings for xbob.machine.Linear * - ************************************/ - -# define PyBobMachineLinear_Type (*(PyBobMachineLinear_Type_TYPE *)PyXbobMachine_API[PyBobMachineLinear_Type_NUM]) - -# define PyBobMachineLinear_Check (*(PyBobMachineLinear_Check_RET (*)PyBobMachineLinear_Check_PROTO) PyXbobMachine_API[PyBobMachineLinear_Check_NUM]) - -# if !defined(NO_IMPORT_ARRAY) - - /** - * Returns -1 on error, 0 on success. PyCapsule_Import will set an exception - * if there's an error. - */ - static int import_xbob_io(void) { - - PyObject *c_api_object; - PyObject *module; - - module = PyImport_ImportModule(BOOST_PP_STRINGIZE(XBOB_MACHINE_MODULE_PREFIX) "." BOOST_PP_STRINGIZE(XBOB_MACHINE_MODULE_NAME)); - - if (module == NULL) return -1; - - c_api_object = PyObject_GetAttrString(module, "_C_API"); - - if (c_api_object == NULL) { - Py_DECREF(module); - return -1; - } - -# if PY_VERSION_HEX >= 0x02070000 - if (PyCapsule_CheckExact(c_api_object)) { - PyXbobMachine_API = (void **)PyCapsule_GetPointer(c_api_object, - PyCapsule_GetName(c_api_object)); - } -# else - if (PyCObject_Check(c_api_object)) { - XbobMachine_API = (void **)PyCObject_AsVoidPtr(c_api_object); - } -# endif - - Py_DECREF(c_api_object); - Py_DECREF(module); - - if (!XbobMachine_API) { - PyErr_Format(PyExc_ImportError, -# if PY_VERSION_HEX >= 0x02070000 - "cannot find C/C++ API capsule at `%s.%s._C_API'", -# else - "cannot find C/C++ API cobject at `%s.%s._C_API'", -# endif - BOOST_PP_STRINGIZE(XBOB_MACHINE_MODULE_PREFIX), - BOOST_PP_STRINGIZE(XBOB_MACHINE_MODULE_NAME)); - return -1; - } - - /* Checks that the imported version matches the compiled version */ - int imported_version = *(int*)PyXbobMachine_API[PyXbobMachine_APIVersion_NUM]; - - if (XBOB_MACHINE_API_VERSION != imported_version) { - PyErr_Format(PyExc_ImportError, "%s.%s import error: you compiled against API version 0x%04x, but are now importing an API with version 0x%04x which is not compatible - check your Python runtime environment for errors", BOOST_PP_STRINGIZE(XBOB_MACHINE_MODULE_PREFIX), BOOST_PP_STRINGIZE(XBOB_MACHINE_MODULE_NAME), XBOB_MACHINE_API_VERSION, imported_version); - return -1; - } - - /* If you get to this point, all is good */ - return 0; - - } - -# endif //!defined(NO_IMPORT_ARRAY) - -#endif /* XBOB_MACHINE_MODULE */ - -#endif /* XBOB_MACHINE_H */ diff --git a/xbob/machine/include/xbob.machine/config.h b/xbob/machine/include/xbob.machine/config.h deleted file mode 100644 index 633ed57..0000000 --- a/xbob/machine/include/xbob.machine/config.h +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Fri 13 Dec 2013 11:50:29 CET - * - * @brief General directives for all modules in xbob.machine - */ - -#ifndef XBOB_MACHINE_CONFIG_H -#define XBOB_MACHINE_CONFIG_H - -/* Macros that define versions and important names */ -#define XBOB_MACHINE_API_VERSION 0x0200 - -#endif /* XBOB_MACHINE_CONFIG_H */ diff --git a/xbob/machine/ivector.cc b/xbob/machine/ivector.cc deleted file mode 100644 index 1cd318b..0000000 --- a/xbob/machine/ivector.cc +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @file machine/python/ivector.cc - * @date Sun Mar 31 18:07:00 2013 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/python.hpp> -#include <bob/python/ndarray.h> -#include <boost/shared_ptr.hpp> -#include <bob/python/exception.h> -#include <bob/machine/IVectorMachine.h> - -using namespace boost::python; - -static void py_iv_setT(bob::machine::IVectorMachine& machine, - bob::python::const_ndarray T) -{ - machine.setT(T.bz<double,2>()); -} - -static void py_iv_setSigma(bob::machine::IVectorMachine& machine, - bob::python::const_ndarray sigma) -{ - machine.setSigma(sigma.bz<double,1>()); -} - -static void py_computeIdTtSigmaInvT1(const bob::machine::IVectorMachine& machine, - const bob::machine::GMMStats& gs, bob::python::ndarray output) -{ - blitz::Array<double,2> output_ = output.bz<double,2>(); - machine.computeIdTtSigmaInvT(gs, output_); -} - -static object py_computeIdTtSigmaInvT2(const bob::machine::IVectorMachine& machine, - const bob::machine::GMMStats& gs) -{ - bob::python::ndarray output(bob::core::array::t_float64, machine.getDimRt(), machine.getDimRt()); - blitz::Array<double,2> output_ = output.bz<double,2>(); - machine.computeIdTtSigmaInvT(gs, output_); - return output.self(); -} - -static void py_computeTtSigmaInvFnorm1(const bob::machine::IVectorMachine& machine, - const bob::machine::GMMStats& gs, bob::python::ndarray output) -{ - blitz::Array<double,1> output_ = output.bz<double,1>(); - machine.computeTtSigmaInvFnorm(gs, output_); -} - -static object py_computeTtSigmaInvFnorm2(const bob::machine::IVectorMachine& machine, - const bob::machine::GMMStats& gs) -{ - bob::python::ndarray output(bob::core::array::t_float64, machine.getDimRt()); - blitz::Array<double,1> output_ = output.bz<double,1>(); - machine.computeTtSigmaInvFnorm(gs, output_); - return output.self(); -} - -static void py_iv_forward1(const bob::machine::IVectorMachine& machine, - const bob::machine::GMMStats& gs, bob::python::ndarray ivector) -{ - blitz::Array<double,1> ivector_ = ivector.bz<double,1>(); - machine.forward(gs, ivector_); -} - -static void py_iv_forward1_(const bob::machine::IVectorMachine& machine, - const bob::machine::GMMStats& gs, bob::python::ndarray ivector) -{ - blitz::Array<double,1> ivector_ = ivector.bz<double,1>(); - machine.forward_(gs, ivector_); -} - -static object py_iv_forward2(const bob::machine::IVectorMachine& machine, - const bob::machine::GMMStats& gs) -{ - bob::python::ndarray ivector(bob::core::array::t_float64, machine.getDimRt()); - blitz::Array<double,1> ivector_ = ivector.bz<double,1>(); - machine.forward(gs, ivector_); - return ivector.self(); -} - - -void bind_machine_ivector() -{ - // TODO: reuse binding from generic machine - class_<bob::machine::IVectorMachine, boost::shared_ptr<bob::machine::IVectorMachine> >("IVectorMachine", "An IVectorMachine to extract i-vector.\n\nReferences:\n[1] 'Front End Factor Analysis for Speaker Verification', N. Dehak, P. Kenny, R. Dehak, P. Dumouchel, P. Ouellet, IEEE Transactions on Audio, Speech and Language Processing, 2010, vol. 19, issue 4, pp. 788-798", init<boost::shared_ptr<bob::machine::GMMMachine>, optional<const size_t, const size_t> >((arg("self"), arg("ubm"), arg("rt")=1, arg("variance_threshold")=1e-10), "Builds a new IVectorMachine.")) - .def(init<>((arg("self")), "Constructs a new empty IVectorMachine.")) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")), "Constructs a new IVectorMachine from a configuration file.")) - .def(init<const bob::machine::IVectorMachine&>((arg("self"), arg("machine")), "Copy constructs an IVectorMachine")) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::IVectorMachine::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this IVectorMachine with the 'other' one to be approximately the same.") - .def("load", &bob::machine::IVectorMachine::load, (arg("self"), arg("config")), "Loads the configuration parameters from a configuration file.") - .def("save", &bob::machine::IVectorMachine::save, (arg("self"), arg("config")), "Saves the configuration parameters to a configuration file.") - .def("resize", &bob::machine::IVectorMachine::resize, (arg("self"), arg("rt")), "Reset the dimensionality of the Total Variability subspace T.") - .add_property("ubm", &bob::machine::IVectorMachine::getUbm, &bob::machine::IVectorMachine::setUbm, "The UBM GMM attached to this Joint Factor Analysis model") - .add_property("t", make_function(&bob::machine::IVectorMachine::getT, return_value_policy<copy_const_reference>()), &py_iv_setT, "The subspace T (Total Variability matrix)") - .add_property("sigma", make_function(&bob::machine::IVectorMachine::getSigma, return_value_policy<copy_const_reference>()), &py_iv_setSigma, "The residual matrix of the model sigma") - .add_property("variance_threshold", &bob::machine::IVectorMachine::getVarianceThreshold, &bob::machine::IVectorMachine::setVarianceThreshold, "Threshold for the variance contained in sigma") - .add_property("dim_c", &bob::machine::IVectorMachine::getDimC, "The number of Gaussian components") - .add_property("dim_d", &bob::machine::IVectorMachine::getDimD, "The dimensionality of the feature space") - .add_property("dim_cd", &bob::machine::IVectorMachine::getDimCD, "The dimensionality of the supervector space") - .add_property("dim_rt", &bob::machine::IVectorMachine::getDimRt, "The dimensionality of the Total Variability subspace (rank of T)") - .def("__compute_Id_TtSigmaInvT__", &py_computeIdTtSigmaInvT1, (arg("self"), arg("gmmstats"), arg("output")), "Computes (Id + sum_{c=1}^{C} N_{i,j,c} T^{T} Sigma_{c}^{-1} T)") - .def("__compute_Id_TtSigmaInvT__", &py_computeIdTtSigmaInvT2, (arg("self"), arg("gmmstats")), "Computes (Id + sum_{c=1}^{C} N_{i,j,c} T^{T} Sigma_{c}^{-1} T)") - .def("__compute_TtSigmaInvFnorm__", &py_computeTtSigmaInvFnorm1, (arg("self"), arg("gmmstats"), arg("output")), "Computes T^{T} Sigma^{-1} sum_{c=1}^{C} (F_c - N_c mean(c))") - .def("__compute_TtSigmaInvFnorm__", &py_computeTtSigmaInvFnorm2, (arg("self"), arg("gmmstats")), "Computes T^{T} Sigma^{-1} sum_{c=1}^{C} (F_c - N_c mean(c))") - .def("__call__", &py_iv_forward1_, (arg("self"), arg("gmmstats"), arg("ivector")), "Executes the machine on the GMMStats, and updates the ivector array. NO CHECK is performed.") - .def("__call__", &py_iv_forward2, (arg("self"), arg("gmmstats")), "Executes the machine on the GMMStats. The ivector is allocated an returned.") - .def("forward", &py_iv_forward1, (arg("self"), arg("gmmstats"), arg("ivector")), "Executes the machine on the GMMStats, and updates the ivector array.") - .def("forward_", &py_iv_forward1_, (arg("self"), arg("gmmstats"), arg("ivector")), "Executes the machine on the GMMStats, and updates the ivector array. NO CHECK is performed.") - .def("forward", &py_iv_forward2, (arg("self"), arg("gmmstats")), "Executes the machine on the GMMStats. The ivector is allocated an returned.") - ; -} diff --git a/xbob/machine/jfa.cc b/xbob/machine/jfa.cc deleted file mode 100644 index 5348a43..0000000 --- a/xbob/machine/jfa.cc +++ /dev/null @@ -1,240 +0,0 @@ -/** - * @file machine/python/jfa.cc - * @date Sat Jul 23 21:41:15 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Python bindings for the FA-related machines - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/python.hpp> -#include <bob/python/ndarray.h> -#include <boost/shared_ptr.hpp> -#include <bob/machine/JFAMachine.h> -#include <bob/machine/GMMMachine.h> - -using namespace boost::python; - -static void py_jfa_setU(bob::machine::JFABase& machine, - bob::python::const_ndarray U) -{ - machine.setU(U.bz<double,2>()); -} - -static void py_jfa_setV(bob::machine::JFABase& machine, - bob::python::const_ndarray V) -{ - machine.setV(V.bz<double,2>()); -} - -static void py_jfa_setD(bob::machine::JFABase& machine, - bob::python::const_ndarray D) -{ - machine.setD(D.bz<double,1>()); -} - -static void py_jfa_setY(bob::machine::JFAMachine& machine, bob::python::const_ndarray Y) { - const blitz::Array<double,1>& Y_ = Y.bz<double,1>(); - machine.setY(Y_); -} - -static void py_jfa_setZ(bob::machine::JFAMachine& machine, bob::python::const_ndarray Z) { - const blitz::Array<double,1> Z_ = Z.bz<double,1>(); - machine.setZ(Z_); -} - -static void py_jfa_estimateX(bob::machine::JFAMachine& machine, - const bob::machine::GMMStats& gmm_stats, bob::python::ndarray x) -{ - blitz::Array<double,1> x_ = x.bz<double,1>(); - machine.estimateX(gmm_stats, x_); -} - -static void py_jfa_estimateUx(bob::machine::JFAMachine& machine, - const bob::machine::GMMStats& gmm_stats, bob::python::ndarray ux) -{ - blitz::Array<double,1> ux_ = ux.bz<double,1>(); - machine.estimateUx(gmm_stats, ux_); -} - -static double py_jfa_forwardUx(bob::machine::JFAMachine& machine, - const bob::machine::GMMStats& gmm_stats, bob::python::const_ndarray ux) -{ - double score; - machine.forward(gmm_stats, ux.bz<double,1>(), score); - return score; -} - - -static void py_isv_setU(bob::machine::ISVBase& machine, - bob::python::const_ndarray U) -{ - machine.setU(U.bz<double,2>()); -} - -static void py_isv_setD(bob::machine::ISVBase& machine, - bob::python::const_ndarray D) -{ - machine.setD(D.bz<double,1>()); -} - -static void py_isv_setZ(bob::machine::ISVMachine& machine, bob::python::const_ndarray Z) { - machine.setZ(Z.bz<double,1>()); -} - -static void py_isv_estimateX(bob::machine::ISVMachine& machine, - const bob::machine::GMMStats& gmm_stats, bob::python::ndarray x) -{ - blitz::Array<double,1> x_ = x.bz<double,1>(); - machine.estimateX(gmm_stats, x_); -} - -static void py_isv_estimateUx(bob::machine::ISVMachine& machine, - const bob::machine::GMMStats& gmm_stats, bob::python::ndarray ux) -{ - blitz::Array<double,1> ux_ = ux.bz<double,1>(); - machine.estimateUx(gmm_stats, ux_); -} - -static double py_isv_forwardUx(bob::machine::ISVMachine& machine, - const bob::machine::GMMStats& gmm_stats, bob::python::const_ndarray ux) -{ - double score; - machine.forward(gmm_stats, ux.bz<double,1>(), score); - return score; -} - - -static double py_gen1_forward(const bob::machine::Machine<bob::machine::GMMStats, double>& m, - const bob::machine::GMMStats& stats) -{ - double output; - m.forward(stats, output); - return output; -} - -static double py_gen1_forward_(const bob::machine::Machine<bob::machine::GMMStats, double>& m, - const bob::machine::GMMStats& stats) -{ - double output; - m.forward_(stats, output); - return output; -} - -static void py_gen2b_forward(const bob::machine::Machine<bob::machine::GMMStats, blitz::Array<double,1> >& m, - const bob::machine::GMMStats& stats, bob::python::const_ndarray output) -{ - blitz::Array<double,1> output_ = output.bz<double,1>(); - m.forward(stats, output_); -} - -static void py_gen2b_forward_(const bob::machine::Machine<bob::machine::GMMStats, blitz::Array<double,1> >& m, - const bob::machine::GMMStats& stats, bob::python::const_ndarray output) -{ - blitz::Array<double,1> output_ = output.bz<double,1>(); - m.forward_(stats, output_); -} - - -void bind_machine_jfa() -{ - class_<bob::machine::Machine<bob::machine::GMMStats, double>, boost::noncopyable>("MachineGMMStatsScalarBase", - "Root class for all Machine<bob::machine::GMMStats, double>", no_init) - .def("__call__", &py_gen1_forward_, (arg("self"), arg("input")), "Executes the machine on the GMMStats, and returns the (scalar) output. NO CHECK is performed.") - .def("forward", &py_gen1_forward, (arg("self"), arg("input")), "Executes the machine on the GMMStats, and returns the (scalar) output.") - .def("forward_", &py_gen1_forward_, (arg("self"), arg("input")), "Executes the machine on the GMMStats, and returns the (scalar) output. NO CHECK is performed.") - ; - - class_<bob::machine::Machine<bob::machine::GMMStats, blitz::Array<double,1> >, boost::noncopyable>("MachineGMMStatsA1DBase", - "Root class for all Machine<bob::machine::GMMStats, blitz::Array<double,1>", no_init) - .def("__call__", &py_gen2b_forward_, (arg("self"), arg("input"), arg("output")), "Executes the machine on the GMMStats, and returns the (scalar) output. NO CHECK is performed.") - .def("forward", &py_gen2b_forward, (arg("self"), arg("input"), arg("output")), "Executes the machine on the GMMStats, and returns the (scalar) output.") - .def("forward_", &py_gen2b_forward_, (arg("self"), arg("input"), arg("output")), "Executes the machine on the GMMStats, and returns the (scalar) output. NO CHECK is performed.") - ; - - - class_<bob::machine::JFABase, boost::shared_ptr<bob::machine::JFABase>, bases<bob::machine::Machine<bob::machine::GMMStats, double> > >("JFABase", "A JFABase instance can be seen as a container for U, V and D when performing Joint Factor Analysis (JFA).\n\nReferences:\n[1] 'Explicit Modelling of Session Variability for Speaker Verification', R. Vogt, S. Sridharan, Computer Speech & Language, 2008, vol. 22, no. 1, pp. 17-38\n[2] 'Session Variability Modelling for Face Authentication', C. McCool, R. Wallace, M. McLaren, L. El Shafey, S. Marcel, IET Biometrics, 2013", init<const boost::shared_ptr<bob::machine::GMMMachine>, optional<const size_t, const size_t> >((arg("self"), arg("ubm"), arg("ru")=1, arg("rv")=1), "Builds a new JFABase.")) - .def(init<>((arg("self")), "Constructs a 1x1 JFABase instance. You have to set a UBM GMM and resize the U, V and D subspaces afterwards.")) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")), "Constructs a new JFABaseMachine from a configuration file.")) - .def(init<const bob::machine::JFABase&>((arg("self"), arg("machine")), "Copy constructs a JFABase")) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::JFABase::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this JFABase with the 'other' one to be approximately the same.") - .def("load", &bob::machine::JFABase::load, (arg("self"), arg("config")), "Loads the configuration parameters from a configuration file.") - .def("save", &bob::machine::JFABase::save, (arg("self"), arg("config")), "Saves the configuration parameters to a configuration file.") - .def("resize", &bob::machine::JFABase::resize, (arg("self"), arg("ru"), arg("rv")), "Reset the dimensionality of the subspaces U and V.") - .add_property("ubm", &bob::machine::JFABase::getUbm, &bob::machine::JFABase::setUbm, "The UBM GMM attached to this Joint Factor Analysis model") - .add_property("u", make_function(&bob::machine::JFABase::getU, return_value_policy<copy_const_reference>()), &py_jfa_setU, "The subspace U for within-class variations") - .add_property("v", make_function(&bob::machine::JFABase::getV, return_value_policy<copy_const_reference>()), &py_jfa_setV, "The subspace V for between-class variations") - .add_property("d", make_function(&bob::machine::JFABase::getD, return_value_policy<copy_const_reference>()), &py_jfa_setD, "The subspace D for residual variations") - .add_property("dim_c", &bob::machine::JFABase::getDimC, "The number of Gaussian components") - .add_property("dim_d", &bob::machine::JFABase::getDimD, "The dimensionality of the feature space") - .add_property("dim_cd", &bob::machine::JFABase::getDimCD, "The dimensionality of the supervector space") - .add_property("dim_ru", &bob::machine::JFABase::getDimRu, "The dimensionality of the within-class variations subspace (rank of U)") - .add_property("dim_rv", &bob::machine::JFABase::getDimRv, "The dimensionality of the between-class variations subspace (rank of V)") - ; - - class_<bob::machine::JFAMachine, boost::shared_ptr<bob::machine::JFAMachine>, bases<bob::machine::Machine<bob::machine::GMMStats, double> > >("JFAMachine", "A JFAMachine. An attached JFABase should be provided for Joint Factor Analysis. The JFAMachine carries information about the speaker factors y and z, whereas a JFABase carries information about the matrices U, V and D.\n\nReferences:\n[1] 'Explicit Modelling of Session Variability for Speaker Verification', R. Vogt, S. Sridharan, Computer Speech & Language, 2008, vol. 22, no. 1, pp. 17-38\n[2] 'Session Variability Modelling for Face Authentication', C. McCool, R. Wallace, M. McLaren, L. El Shafey, S. Marcel, IET Biometrics, 2013", init<const boost::shared_ptr<bob::machine::JFABase> >((arg("self"), arg("jfa_base")), "Builds a new JFAMachine.")) - .def(init<>((arg("self")), "Constructs a 1x1 JFAMachine instance. You have to set a JFABase afterwards.")) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")), "Constructs a new JFAMachine from a configuration file.")) - .def(init<const bob::machine::JFAMachine&>((arg("self"), arg("machine")), "Copy constructs a JFAMachine")) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::JFAMachine::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this JFABase with the 'other' one to be approximately the same.") - .def("load", &bob::machine::JFAMachine::load, (arg("self"), arg("config")), "Loads the configuration parameters from a configuration file.") - .def("save", &bob::machine::JFAMachine::save, (arg("self"), arg("config")), "Saves the configuration parameters to a configuration file.") - .def("estimate_x", &py_jfa_estimateX, (arg("self"), arg("stats"), arg("x")), "Estimates the session offset x (LPT assumption) given GMM statistics.") - .def("estimate_ux", &py_jfa_estimateUx, (arg("self"), arg("stats"), arg("ux")), "Estimates Ux (LPT assumption) given GMM statistics.") - .def("forward_ux", &py_jfa_forwardUx, (arg("self"), arg("stats"), arg("ux")), "Processes the GMM statistics and Ux to return a score.") - .add_property("jfa_base", &bob::machine::JFAMachine::getJFABase, &bob::machine::JFAMachine::setJFABase, "The JFABase attached to this machine") - .add_property("__x__", make_function(&bob::machine::JFAMachine::getX, return_value_policy<copy_const_reference>()), "The latent variable x (last one computed). This is a feature provided for convenience, but this attribute is not 'part' of the machine. The session latent variable x is indeed not class-specific, but depends on the sample considered. Furthermore, it is not saved into the machine or used when comparing machines.") - .add_property("y", make_function(&bob::machine::JFAMachine::getY, return_value_policy<copy_const_reference>()), &py_jfa_setY, "The latent variable y of this machine") - .add_property("z", make_function(&bob::machine::JFAMachine::getZ, return_value_policy<copy_const_reference>()), &py_jfa_setZ, "The latent variable z of this machine") - .add_property("dim_c", &bob::machine::JFAMachine::getDimC, "The number of Gaussian components") - .add_property("dim_d", &bob::machine::JFAMachine::getDimD, "The dimensionality of the feature space") - .add_property("dim_cd", &bob::machine::JFAMachine::getDimCD, "The dimensionality of the supervector space") - .add_property("dim_ru", &bob::machine::JFAMachine::getDimRu, "The dimensionality of the within-class variations subspace (rank of U)") - .add_property("dim_rv", &bob::machine::JFAMachine::getDimRv, "The dimensionality of the between-class variations subspace (rank of V)") - ; - - class_<bob::machine::ISVBase, boost::shared_ptr<bob::machine::ISVBase>, bases<bob::machine::Machine<bob::machine::GMMStats, double> > >("ISVBase", "An ISVBase instance can be seen as a container for U and D when performing Joint Factor Analysis (ISV). \n\nReferences:\n[1] 'Explicit Modelling of Session Variability for Speaker Verification', R. Vogt, S. Sridharan, Computer Speech & Language, 2008, vol. 22, no. 1, pp. 17-38\n[2] 'Session Variability Modelling for Face Authentication', C. McCool, R. Wallace, M. McLaren, L. El Shafey, S. Marcel, IET Biometrics, 2013", init<const boost::shared_ptr<bob::machine::GMMMachine>, optional<const size_t> >((arg("self"), arg("ubm"), arg("ru")=1), "Builds a new ISVBase.")) - .def(init<>((arg("self")), "Constructs a 1 ISVBase instance. You have to set a UBM GMM and resize the U and D subspaces afterwards.")) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")), "Constructs a new ISVBaseMachine from a configuration file.")) - .def(init<const bob::machine::ISVBase&>((arg("self"), arg("machine")), "Copy constructs an ISVBase")) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::ISVBase::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this ISVBase with the 'other' one to be approximately the same.") - .def("load", &bob::machine::ISVBase::load, (arg("self"), arg("config")), "Loads the configuration parameters from a configuration file.") - .def("save", &bob::machine::ISVBase::save, (arg("self"), arg("config")), "Saves the configuration parameters to a configuration file.") - .def("resize", &bob::machine::ISVBase::resize, (arg("self"), arg("ru")), "Reset the dimensionality of the subspaces U.") - .add_property("ubm", &bob::machine::ISVBase::getUbm, &bob::machine::ISVBase::setUbm, "The UBM GMM attached to this Joint Factor Analysis model") - .add_property("u", make_function(&bob::machine::ISVBase::getU, return_value_policy<copy_const_reference>()), &py_isv_setU, "The subspace U for within-class variations") - .add_property("d", make_function(&bob::machine::ISVBase::getD, return_value_policy<copy_const_reference>()), &py_isv_setD, "The subspace D for residual variations") - .add_property("dim_c", &bob::machine::ISVBase::getDimC, "The number of Gaussian components") - .add_property("dim_d", &bob::machine::ISVBase::getDimD, "The dimensionality of the feature space") - .add_property("dim_cd", &bob::machine::ISVBase::getDimCD, "The dimensionality of the supervector space") - .add_property("dim_ru", &bob::machine::ISVBase::getDimRu, "The dimensionality of the within-class variations subspace (rank of U)") - ; - - class_<bob::machine::ISVMachine, boost::shared_ptr<bob::machine::ISVMachine>, bases<bob::machine::Machine<bob::machine::GMMStats, double> > >("ISVMachine", "An ISVMachine. An attached ISVBase should be provided for Inter-session Variability Modelling. The ISVMachine carries information about the speaker factors z, whereas a ISVBase carries information about the matrices U and D. \n\nReferences:\n[1] 'Explicit Modelling of Session Variability for Speaker Verification', R. Vogt, S. Sridharan, Computer Speech & Language, 2008, vol. 22, no. 1, pp. 17-38\n[2] 'Session Variability Modelling for Face Authentication', C. McCool, R. Wallace, M. McLaren, L. El Shafey, S. Marcel, IET Biometrics, 2013", init<const boost::shared_ptr<bob::machine::ISVBase> >((arg("self"), arg("isv_base")), "Builds a new ISVMachine.")) - .def(init<>((arg("self")), "Constructs a 1 ISVMachine instance. You have to set a ISVBase afterwards.")) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")), "Constructs a new ISVMachine from a configuration file.")) - .def(init<const bob::machine::ISVMachine&>((arg("self"), arg("machine")), "Copy constructs an ISVMachine")) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::ISVMachine::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this ISVBase with the 'other' one to be approximately the same.") - .def("load", &bob::machine::ISVMachine::load, (arg("self"), arg("config")), "Loads the configuration parameters from a configuration file.") - .def("save", &bob::machine::ISVMachine::save, (arg("self"), arg("config")), "Saves the configuration parameters to a configuration file.") - .def("estimate_x", &py_isv_estimateX, (arg("self"), arg("stats"), arg("x")), "Estimates the session offset x (LPT assumption) given GMM statistics.") - .def("estimate_ux", &py_isv_estimateUx, (arg("self"), arg("stats"), arg("ux")), "Estimates Ux (LPT assumption) given GMM statistics.") - .def("forward_ux", &py_isv_forwardUx, (arg("self"), arg("stats"), arg("ux")), "Processes the GMM statistics and Ux to return a score.") - .add_property("isv_base", &bob::machine::ISVMachine::getISVBase, &bob::machine::ISVMachine::setISVBase, "The ISVBase attached to this machine") - .add_property("__x__", make_function(&bob::machine::ISVMachine::getX, return_value_policy<copy_const_reference>()), "The latent variable x (last one computed). This is a feature provided for convenience, but this attribute is not 'part' of the machine. The session latent variable x is indeed not class-specific, but depends on the sample considered. Furthermore, it is not saved into the machine or used when comparing machines.") - .add_property("z", make_function(&bob::machine::ISVMachine::getZ, return_value_policy<copy_const_reference>()), &py_isv_setZ, "The latent variable z of this machine") - .add_property("dim_c", &bob::machine::ISVMachine::getDimC, "The number of Gaussian components") - .add_property("dim_d", &bob::machine::ISVMachine::getDimD, "The dimensionality of the feature space") - .add_property("dim_cd", &bob::machine::ISVMachine::getDimCD, "The dimensionality of the supervector space") - .add_property("dim_ru", &bob::machine::ISVMachine::getDimRu, "The dimensionality of the within-class variations subspace (rank of U)") - ; -} diff --git a/xbob/machine/kmeans.cc b/xbob/machine/kmeans.cc deleted file mode 100644 index 8162201..0000000 --- a/xbob/machine/kmeans.cc +++ /dev/null @@ -1,125 +0,0 @@ -/** - * @file machine/python/kmeans.cc - * @date Tue Jul 26 15:11:33 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ -#include <boost/python.hpp> -#include <boost/concept_check.hpp> -#include <bob/machine/KMeansMachine.h> - -#include <bob/python/ndarray.h> - -using namespace boost::python; - -static tuple py_getVariancesAndWeightsForEachCluster(const bob::machine::KMeansMachine& machine, bob::python::const_ndarray ar) { - size_t n_means = machine.getNMeans(); - size_t n_inputs = machine.getNInputs(); - bob::python::ndarray variances(bob::core::array::t_float64, n_means, n_inputs); - bob::python::ndarray weights(bob::core::array::t_float64, n_means); - blitz::Array<double,2> variances_ = variances.bz<double,2>(); - blitz::Array<double,1> weights_ = weights.bz<double,1>(); - machine.getVariancesAndWeightsForEachCluster(ar.bz<double,2>(), variances_, weights_); - return boost::python::make_tuple(variances.self(), weights.self()); -} - -static void py_getVariancesAndWeightsForEachClusterInit(const bob::machine::KMeansMachine& machine, bob::python::ndarray variances, bob::python::ndarray weights) { - blitz::Array<double,2> variances_ = variances.bz<double,2>(); - blitz::Array<double,1> weights_ = weights.bz<double,1>(); - machine.getVariancesAndWeightsForEachClusterInit(variances_, weights_); -} - -static void py_getVariancesAndWeightsForEachClusterAcc(const bob::machine::KMeansMachine& machine, bob::python::const_ndarray ar, bob::python::ndarray variances, bob::python::ndarray weights) { - blitz::Array<double,2> variances_ = variances.bz<double,2>(); - blitz::Array<double,1> weights_ = weights.bz<double,1>(); - machine.getVariancesAndWeightsForEachClusterAcc(ar.bz<double,2>(), variances_, weights_); -} - -static void py_getVariancesAndWeightsForEachClusterFin(const bob::machine::KMeansMachine& machine, bob::python::ndarray variances, bob::python::ndarray weights) { - blitz::Array<double,2> variances_ = variances.bz<double,2>(); - blitz::Array<double,1> weights_ = weights.bz<double,1>(); - machine.getVariancesAndWeightsForEachClusterFin(variances_, weights_); -} - -static object py_getMean(const bob::machine::KMeansMachine& kMeansMachine, const size_t i) { - bob::python::ndarray mean(bob::core::array::t_float64, kMeansMachine.getNInputs()); - blitz::Array<double,1> mean_ = mean.bz<double,1>(); - kMeansMachine.getMean(i, mean_); - return mean.self(); -} - -static void py_setMean(bob::machine::KMeansMachine& machine, const size_t i, bob::python::const_ndarray mean) { - machine.setMean(i, mean.bz<double,1>()); -} - -static void py_setMeans(bob::machine::KMeansMachine& machine, bob::python::const_ndarray means) { - machine.setMeans(means.bz<double,2>()); -} - -static double py_getDistanceFromMean(const bob::machine::KMeansMachine& machine, bob::python::const_ndarray x, const size_t i) -{ - return machine.getDistanceFromMean(x.bz<double,1>(), i); -} - -static tuple py_getClosestMean(const bob::machine::KMeansMachine& machine, bob::python::const_ndarray x) -{ - size_t closest_mean; - double min_distance; - machine.getClosestMean(x.bz<double,1>(), closest_mean, min_distance); - return boost::python::make_tuple(closest_mean, min_distance); -} - -static double py_getMinDistance(const bob::machine::KMeansMachine& machine, bob::python::const_ndarray input) -{ - return machine.getMinDistance(input.bz<double,1>()); -} - -static void py_setCacheMeans(bob::machine::KMeansMachine& machine, bob::python::const_ndarray cache_means) { - machine.setCacheMeans(cache_means.bz<double,2>()); -} - -void bind_machine_kmeans() -{ - class_<bob::machine::KMeansMachine, boost::shared_ptr<bob::machine::KMeansMachine>, - bases<bob::machine::Machine<blitz::Array<double,1>, double> > >("KMeansMachine", - "This class implements a k-means classifier.\n" - "See Section 9.1 of Bishop, \"Pattern recognition and machine learning\", 2006", - init<>((arg("self")))) - .def(init<const size_t, const size_t>((arg("self"), arg("n_means"), arg("n_inputs")))) - .def(init<bob::machine::KMeansMachine&>((arg("self"), arg("other")))) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")))) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::KMeansMachine::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this KMeansMachine with the 'other' one to be approximately the same.") - .add_property("means", make_function(&bob::machine::KMeansMachine::getMeans, return_value_policy<copy_const_reference>()), &py_setMeans, "The mean vectors") - .add_property("__cache_means__", make_function(&bob::machine::KMeansMachine::getCacheMeans, return_value_policy<copy_const_reference>()), &py_setCacheMeans, "The cache mean vectors. This should only be used when parallelizing the get_variances_and_weights_for_each_cluster() method") - .add_property("dim_d", &bob::machine::KMeansMachine::getNInputs, "Number of inputs") - .add_property("dim_c", &bob::machine::KMeansMachine::getNMeans, "Number of means (k)") - .def("resize", &bob::machine::KMeansMachine::resize, (arg("self"), arg("n_means"), arg("n_inputs")), "Resize the number of means and inputs") - .def("get_mean", &py_getMean, (arg("self"), arg("i")), "Get the i'th mean") - .def("set_mean", &py_setMean, (arg("self"), arg("i"), arg("mean")), "Set the i'th mean") - .def("get_distance_from_mean", &py_getDistanceFromMean, (arg("self"), arg("x"), arg("i")), - "Return the power of two of the square Euclidean distance of the sample, x, to the i'th mean") - .def("get_closest_mean", &py_getClosestMean, (arg("self"), arg("x")), - "Calculate the index of the mean that is closest (in terms of square Euclidean distance) to the data sample, x") - .def("get_min_distance", &py_getMinDistance, (arg("self"), arg("input")), - "Output the minimum square Euclidean distance between the input and one of the means") - .def("get_variances_and_weights_for_each_cluster", &py_getVariancesAndWeightsForEachCluster, (arg("self"), arg("data")), - "For each mean, find the subset of the samples that is closest to that mean, and calculate\n" - "1) the variance of that subset (the cluster variance)\n" - "2) the proportion of the samples represented by that subset (the cluster weight)") - .def("__get_variances_and_weights_for_each_cluster_init__", &py_getVariancesAndWeightsForEachClusterInit, (arg("self"), arg("variances"), arg("weights")), - "For the parallel version of get_variances_and_weights_for_each_cluster()\n" - "Initialization step") - .def("__get_variances_and_weights_for_each_cluster_acc__", &py_getVariancesAndWeightsForEachClusterAcc, (arg("self"), arg("data"), arg("variances"), arg("weights")), - "For the parallel version of get_variances_and_weights_for_each_cluster()\n" - "Accumulation step") - .def("__get_variances_and_weights_for_each_cluster_fin__", &py_getVariancesAndWeightsForEachClusterFin, (arg("self"), arg("variances"), arg("weights")), - "For the parallel version of get_variances_and_weights_for_each_cluster()\n" - "Finalization step") - .def("load", &bob::machine::KMeansMachine::load, (arg("self"), arg("config")), "Load from a Configuration") - .def("save", &bob::machine::KMeansMachine::save, (arg("self"), arg("config")), "Save to a Configuration") - .def(self_ns::str(self_ns::self)) - ; -} diff --git a/xbob/machine/linear.cpp b/xbob/machine/linear.cpp deleted file mode 100644 index c1378ae..0000000 --- a/xbob/machine/linear.cpp +++ /dev/null @@ -1,646 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Tue 14 Jan 2014 14:26:09 CET - * - * @brief Bindings for a LinearMachine - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#define XBOB_MACHINE_MODULE -#include "cleanup.h" -#include <xbob.io/api.h> -#include <xbob.machine/api.h> -#include <xbob.blitz/cppapi.h> -#include <structmember.h> - -/********************************************** - * Implementation of LinearMachine base class * - **********************************************/ - -PyDoc_STRVAR(s_linear_str, XBOB_EXT_MODULE_PREFIX ".LinearMachine"); - -PyDoc_STRVAR(s_linear_doc, -"LinearMachine([input_size=0, [output_size=0]])\n\ -LinearMachine(weights)\n\ -LinearMachine(config)\n\ -LinearMachine(other)\n\ -\n\ -A linear classifier. See C. M. Bishop, 'Pattern Recognition\n\ -and Machine Learning', chapter 4 for more details. The basic\n\ -matrix operation performed for projecting the input to the\n\ -output is: :math:`o = w \\times i` (with :math:`w` being the\n\ -vector of machine weights and :math:`i` the input data vector).\n\ -The weights matrix is therefore organized column-wise. In this\n\ -scheme, each column of the weights matrix can be interpreted\n\ -as vector to which the input is projected. The number of\n\ -columns of the weights matrix determines the number of outputs\n\ -this linear machine will have. The number of rows, the number\n\ -of allowed inputs it can process.\n\ -\n\ -Input and output is always performed on 1D arrays with 64-bit\n\ -floating point numbers.\n\ -\n\ -A linear machine can be constructed in different ways. In the\n\ -first form, the user specifies optional input and output vector\n\ -sizes. The machine is remains **uninitialized**. With the second\n\ -form, the user passes a 2D array with 64-bit floats containing\n\ -weight matrix to be used by the new machine. In the third form\n\ -the user passes a pre-opened HDF5 file pointing to the machine\n\ -information to be loaded in memory. Finally, in the last form\n\ -(copy constructor), the user passes another\n\ -:py:class:`LinearMachine` that will be fully copied.\n\ -"); - -static int PyBobMachineLinear_init_sizes(PyBobMachineLinearObject* self, - PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - static const char* const_kwlist[] = {"input_size", "output_size", 0}; - static char** kwlist = const_cast<char**>(const_kwlist); - - Py_ssize_t input_size = 0; - Py_ssize_t output_size = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|nn", kwlist, - &input_size, &output_size)) return -1; - - try { - self->machine = new bob::machine::LinearMachine(input_size, output_size); - } - catch (std::exception& ex) { - PyErr_SetString(PyExc_RuntimeError, ex.what()); - } - catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot create new object of type `%s' - unknown exception thrown", s_linear_str); - } - - return 0; - -} - -static int PyBobMachineLinear_init_weights(PyBobMachineLinearObject* self, - PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - static const char* const_kwlist[] = {"weights", 0}; - static char** kwlist = const_cast<char**>(const_kwlist); - - PyBlitzArrayObject* weights = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, - &PyBlitzArray_Converter, &weights)) return -1; - auto weights_ = make_safe(weights); - - if (weights->type_num != NPY_FLOAT64 || weights->ndim != 2) { - PyErr_SetString(PyExc_TypeError, "LinearMachine only supports 64-bit floats 2D arrays for property array `weights'"); - return -1; - } - - try { - self->machine = new bob::machine::LinearMachine - (*PyBlitzArrayCxx_AsBlitz<double,2>(weights)); - } - catch (std::exception& ex) { - PyErr_SetString(PyExc_RuntimeError, ex.what()); - } - catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot create new object of type `%s' - unknown exception thrown", s_linear_str); - } - - return 0; - -} - -static int PyBobMachineLinear_init_hdf5(PyBobMachineLinearObject* self, - PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - static const char* const_kwlist[] = {"config", 0}; - static char** kwlist = const_cast<char**>(const_kwlist); - - PyObject* config = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, - &config)) return -1; - - if (!PyBobIoHDF5File_Check(config)) { - PyErr_Format(PyExc_TypeError, "initialization with HDF5 files requires an object of type `HDF5File' for input, not `%s'", config->ob_type->tp_name); - return -1; - } - - auto h5f = reinterpret_cast<PyBobIoHDF5FileObject*>(config); - - try { - self->machine = new bob::machine::LinearMachine(*(h5f->f)); - } - catch (std::exception& ex) { - PyErr_SetString(PyExc_RuntimeError, ex.what()); - } - catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot create new object of type `%s' - unknown exception thrown", s_linear_str); - } - - return 0; - -} - -static int PyBobMachineLinear_init_copy(PyBobMachineLinearObject* self, - PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - static const char* const_kwlist[] = {"other", 0}; - static char** kwlist = const_cast<char**>(const_kwlist); - - PyObject* other = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, - &other)) return -1; - - if (!PyBobMachineLinear_Check(other)) { - PyErr_Format(PyExc_TypeError, "copy construction requires an object of type `%s' for input, not `%s'", self->ob_type->tp_name, other->ob_type->tp_name); - return -1; - } - - auto copy = reinterpret_cast<PyBobMachineLinearObject*>(other); - - try { - self->machine = new bob::machine::LinearMachine(*(copy->machine)); - } - catch (std::exception& ex) { - PyErr_SetString(PyExc_RuntimeError, ex.what()); - } - catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot create new object of type `%s' - unknown exception thrown", s_linear_str); - } - - return 0; - -} - -static int PyBobMachineLinear_init(PyBobMachineLinearObject* self, - PyObject* args, PyObject* kwds) { - - Py_ssize_t nargs = args?PyTuple_Size(args):0 + kwds?PyDict_Size(kwds):0; - - switch (nargs) { - - case 0: //default initializer - case 2: //two sizes - return PyBobMachineLinear_init_sizes(self, args, kwds); - - case 1: - - { - - PyObject* arg = 0; ///< borrowed (don't delete) - if (PyTuple_Size(args)) arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwds); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - if (PyBobIoHDF5File_Check(arg)) { - return PyBobMachineLinear_init_hdf5(self, args, kwds); - } - - if (PyBlitzArray_Check(arg) || PyArray_Check(arg)) { - return PyBobMachineLinear_init_weights(self, args, kwds); - } - - if (PyNumber_Check(arg)) { - return PyBobMachineLinear_init_sizes(self, args, kwds); - } - - if (PyBobMachineActivation_Check(arg)) { - return PyBobMachineLinear_init_copy(self, args, kwds); - } - - PyErr_Format(PyExc_TypeError, "cannot initialize `%s' with `%s' (see help)", s_linear_str, arg->ob_type->tp_name); - - } - - break; - - default: - - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires 0, 1 or 2 arguments, but you provided %" PY_FORMAT_SIZE_T "d (see help)", s_linear_str, nargs); - - } - - return -1; - -} - -static void PyBobMachineLinear_delete (PyBobMachineLinearObject* self) { - - delete self->machine; - self->ob_type->tp_free((PyObject*)self); - -} - -int PyBobMachineLinear_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobMachineLinear_Type)); -} - -static PyObject* PyBobMachineLinear_RichCompare (PyBobMachineLinearObject* self, PyObject* other, int op) { - - if (!PyBobMachineLinear_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", - s_linear_str, other->ob_type->tp_name); - return 0; - } - - auto other_ = reinterpret_cast<PyBobMachineLinearObject*>(other); - - switch (op) { - case Py_EQ: - if (self->machine->operator==(*other_->machine)) Py_RETURN_TRUE; - Py_RETURN_FALSE; - break; - case Py_NE: - if (self->machine->operator!=(*other_->machine)) Py_RETURN_TRUE; - Py_RETURN_FALSE; - break; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - -} - -static PyMethodDef PyBobMachineLinear_methods[] = { - {0} /* Sentinel */ -}; - -/** - .add_property("activation", &bob::machine::LinearMachine::getActivation, &bob::machine::LinearMachine::setActivation, "The activation function - by default, the identity function. The output provided by the activation function is passed, unchanged, to the user.") -**/ - -PyDoc_STRVAR(s_weights_str, "weights"); -PyDoc_STRVAR(s_weights_doc, -"Weight matrix to which the input is projected to. The output\n\ -of the project is fed subject to bias and activation before\n\ -being output.\n\ -"); - -static PyObject* PyBobMachineLinear_getWeights -(PyBobMachineLinearObject* self, void* /*closure*/) { - return PyBlitzArray_NUMPY_WRAP(PyBlitzArrayCxx_NewFromConstArray(self->machine->getWeights())); -} - -static int PyBobMachineLinear_setWeights (PyBobMachineLinearObject* self, - PyObject* o, void* /*closure*/) { - - PyBlitzArrayObject* weights = 0; - if (!PyBlitzArray_Converter(o, &weights)) return -1; - auto weights_ = make_safe(weights); - - if (weights->type_num != NPY_FLOAT64 || weights->ndim != 2) { - PyErr_SetString(PyExc_TypeError, "LinearMachine only supports 64-bit floats 2D arrays for property array `weights'"); - return -1; - } - - try { - self->machine->setWeights(*PyBlitzArrayCxx_AsBlitz<double,2>(weights)); - } - catch (std::exception& ex) { - PyErr_SetString(PyExc_RuntimeError, ex.what()); - return -1; - } - catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot reset `weights' of %s: unknown exception caught", s_linear_str); - return -1; - } - - return 0; - -} - -PyDoc_STRVAR(s_biases_str, "biases"); -PyDoc_STRVAR(s_biases_doc, -"Bias to the output units of this linear machine, to be added\n\ -to the output before activation.\n\ -"); - -static PyObject* PyBobMachineLinear_getBiases -(PyBobMachineLinearObject* self, void* /*closure*/) { - return PyBlitzArray_NUMPY_WRAP(PyBlitzArrayCxx_NewFromConstArray(self->machine->getBiases())); -} - -static int PyBobMachineLinear_setBiases (PyBobMachineLinearObject* self, - PyObject* o, void* /*closure*/) { - - PyBlitzArrayObject* biases = 0; - if (!PyBlitzArray_Converter(o, &biases)) return -1; - auto biases_ = make_safe(biases); - - if (biases->type_num != NPY_FLOAT64 || biases->ndim != 1) { - PyErr_SetString(PyExc_TypeError, "LinearMachine only supports 64-bit floats 1D arrays for property array `biases'"); - return -1; - } - - try { - self->machine->setBiases(*PyBlitzArrayCxx_AsBlitz<double,1>(biases)); - } - catch (std::exception& ex) { - PyErr_SetString(PyExc_RuntimeError, ex.what()); - return -1; - } - catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot reset `biases' of %s: unknown exception caught", s_linear_str); - return -1; - } - - return 0; - -} - -PyDoc_STRVAR(s_input_subtract_str, "input_subtract"); -PyDoc_STRVAR(s_input_subtract_doc, -"Input subtraction factor, before feeding data through the\n\ -weight matrix W. The subtraction is the first applied\n\ -operation in the processing chain - by default, it is set to\n\ -0.0.\n\ -"); - -static PyObject* PyBobMachineLinear_getInputSubtraction -(PyBobMachineLinearObject* self, void* /*closure*/) { - return PyBlitzArray_NUMPY_WRAP(PyBlitzArrayCxx_NewFromConstArray(self->machine->getInputSubtraction())); -} - -static int PyBobMachineLinear_setInputSubtraction -(PyBobMachineLinearObject* self, PyObject* o, void* /*closure*/) { - - PyBlitzArrayObject* input_subtract = 0; - if (!PyBlitzArray_Converter(o, &input_subtract)) return -1; - auto input_subtract_ = make_safe(input_subtract); - - if (input_subtract->type_num != NPY_FLOAT64 || input_subtract->ndim != 1) { - PyErr_SetString(PyExc_TypeError, "LinearMachine only supports 64-bit floats 1D arrays for property array `input_subtract'"); - return -1; - } - - try { - self->machine->setInputSubtraction(*PyBlitzArrayCxx_AsBlitz<double,1>(input_subtract)); - } - catch (std::exception& ex) { - PyErr_SetString(PyExc_RuntimeError, ex.what()); - return -1; - } - catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot reset `input_subtract' of %s: unknown exception caught", s_linear_str); - return -1; - } - - return 0; - -} - -PyDoc_STRVAR(s_input_divide_str, "input_divide"); -PyDoc_STRVAR(s_input_divide_doc, -"Input division factor, before feeding data through the\n\ -weight matrix W. The division is applied just after\n\ -subtraction - by default, it is set to 1.0.\n\ -"); - -static PyObject* PyBobMachineLinear_getInputDivision -(PyBobMachineLinearObject* self, void* /*closure*/) { - return PyBlitzArray_NUMPY_WRAP(PyBlitzArrayCxx_NewFromConstArray(self->machine->getInputDivision())); -} - -static int PyBobMachineLinear_setInputDivision (PyBobMachineLinearObject* self, - PyObject* o, void* /*closure*/) { - - PyBlitzArrayObject* input_divide = 0; - if (!PyBlitzArray_Converter(o, &input_divide)) return -1; - auto input_divide_ = make_safe(input_divide); - - if (input_divide->type_num != NPY_FLOAT64 || input_divide->ndim != 1) { - PyErr_SetString(PyExc_TypeError, "LinearMachine only supports 64-bit floats 1D arrays for property array `input_divide'"); - return -1; - } - - try { - self->machine->setInputDivision(*PyBlitzArrayCxx_AsBlitz<double,1>(input_divide)); - } - catch (std::exception& ex) { - PyErr_SetString(PyExc_RuntimeError, ex.what()); - return -1; - } - catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot reset `input_divide' of %s: unknown exception caught", s_linear_str); - return -1; - } - - return 0; - -} - -PyDoc_STRVAR(s_shape_str, "shape"); -PyDoc_STRVAR(s_shape_doc, -"A tuple that represents the size of the input vector\n\ -followed by the size of the output vector in the format\n\ -``(input, output)``.\n\ -"); - -static PyObject* PyBobMachineLinear_getShape -(PyBobMachineLinearObject* self, void* /*closure*/) { - return Py_BuildValue("(nn)", self->machine->inputSize(), - self->machine->outputSize()); -} - -static int PyBobMachineLinear_setShape (PyBobMachineLinearObject* self, - PyObject* o, void* /*closure*/) { - - if (!PySequence_Check(o)) { - PyErr_Format(PyExc_TypeError, "LinearMachine shape can only be set using tuples (or sequences), not `%s'", o->ob_type->tp_name); - return -1; - } - - PyObject* shape = PySequence_Tuple(o); - auto shape_ = make_safe(shape); - - if (PyTuple_GET_SIZE(shape) != 2) { - PyErr_Format(PyExc_RuntimeError, "LinearMachine shape can only be set using 2-position tuples (or sequences), not an %" PY_FORMAT_SIZE_T "d-position sequence", PyTuple_GET_SIZE(shape)); - return -1; - } - - Py_ssize_t in = PyNumber_AsSsize_t(PyTuple_GET_ITEM(shape, 0), PyExc_OverflowError); - if (PyErr_Occurred()) return -1; - Py_ssize_t out = PyNumber_AsSsize_t(PyTuple_GET_ITEM(shape, 1), PyExc_OverflowError); - if (PyErr_Occurred()) return -1; - - try { - self->machine->resize(in, out); - } - catch (std::exception& ex) { - PyErr_SetString(PyExc_RuntimeError, ex.what()); - return -1; - } - catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot reset `shape' of %s: unknown exception caught", s_linear_str); - return -1; - } - - return 0; - -} - -static PyGetSetDef PyBobMachineLinear_getseters[] = { - { - s_weights_str, - (getter)PyBobMachineLinear_getWeights, - (setter)PyBobMachineLinear_setWeights, - s_weights_doc, - 0 - }, - { - s_biases_str, - (getter)PyBobMachineLinear_getBiases, - (setter)PyBobMachineLinear_setBiases, - s_biases_doc, - 0 - }, - { - s_input_subtract_str, - (getter)PyBobMachineLinear_getInputSubtraction, - (setter)PyBobMachineLinear_setInputSubtraction, - s_input_subtract_doc, - 0 - }, - { - s_input_divide_str, - (getter)PyBobMachineLinear_getInputDivision, - (setter)PyBobMachineLinear_setInputDivision, - s_input_divide_doc, - 0 - }, - { - s_shape_str, - (getter)PyBobMachineLinear_getShape, - (setter)PyBobMachineLinear_setShape, - s_shape_doc, - 0 - }, - {0} /* Sentinel */ -}; - -PyTypeObject PyBobMachineLinear_Type = { - PyObject_HEAD_INIT(0) - 0, /* ob_size */ - s_linear_str, /* tp_name */ - sizeof(PyBobMachineLinearObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)PyBobMachineLinear_delete, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, //(ternaryfunc)PyBobMachineLinear_call, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - s_linear_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)PyBobMachineLinear_RichCompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PyBobMachineLinear_methods, /* tp_methods */ - 0, /* tp_members */ - PyBobMachineLinear_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)PyBobMachineLinear_init, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - -/****** -static object forward(const bob::machine::LinearMachine& m, - bob::python::const_ndarray input) -{ - const bob::core::array::typeinfo& info = input.type(); - - switch(info.nd) { - case 1: - { - bob::python::ndarray output(bob::core::array::t_float64, m.outputSize()); - blitz::Array<double,1> output_ = output.bz<double,1>(); - m.forward(input.bz<double,1>(), output_); - return output.self(); - } - case 2: - { - bob::python::ndarray output(bob::core::array::t_float64, info.shape[0], m.outputSize()); - blitz::Array<double,2> input_ = input.bz<double,2>(); - blitz::Array<double,2> output_ = output.bz<double,2>(); - blitz::Range all = blitz::Range::all(); - for (size_t k=0; k<info.shape[0]; ++k) { - blitz::Array<double,1> i_ = input_(k,all); - blitz::Array<double,1> o_ = output_(k,all); - m.forward(i_, o_); - } - return output.self(); - } - default: - PYTHON_ERROR(TypeError, "cannot forward arrays with " SIZE_T_FMT " dimensions (only with 1 or 2 dimensions).", info.nd); - } -} - -static void forward2(const bob::machine::LinearMachine& m, - bob::python::const_ndarray input, bob::python::ndarray output) -{ - const bob::core::array::typeinfo& info = input.type(); - - switch(info.nd) { - case 1: - { - blitz::Array<double,1> output_ = output.bz<double,1>(); - m.forward(input.bz<double,1>(), output_); - } - break; - case 2: - { - blitz::Array<double,2> input_ = input.bz<double,2>(); - blitz::Array<double,2> output_ = output.bz<double,2>(); - blitz::Range all = blitz::Range::all(); - for (size_t k=0; k<info.shape[0]; ++k) { - blitz::Array<double,1> i_ = input_(k,all); - blitz::Array<double,1> o_ = output_(k,all); - m.forward(i_, o_); - } - } - break; - default: - PYTHON_ERROR(TypeError, "cannot forward arrays with " SIZE_T_FMT " dimensions (only with 1 or 2 dimensions).", info.nd); - } -} -***/ - -/*** -void bind_machine_linear() { - .def("is_similar_to", &bob::machine::LinearMachine::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this LinearMachine with the 'other' one to be approximately the same.") - .def("load", &bob::machine::LinearMachine::load, (arg("self"), arg("config")), "Loads the weights and biases from a configuration file. Both weights and biases have their dimensionalities checked between each other for consistency.") - .def("save", &bob::machine::LinearMachine::save, (arg("self"), arg("config")), "Saves the weights and biases to a configuration file.") - .def("resize", &bob::machine::LinearMachine::resize, (arg("self"), arg("input"), arg("output")), "Resizes the machine. If either the input or output increases in size, the weights and other factors should be considered uninitialized. If the size is preserved or reduced, already initialized values will not be changed.\n\nTip: Use this method to force data compression. All will work out given most relevant factors to be preserved are organized on the top of the weight matrix. In this way, reducing the system size will supress less relevant projections.") - .def("__call__", &forward2, (arg("self"), arg("input"), arg("output")), "Projects the input to the weights and biases and saves results on the output") - .def("forward", &forward2, (arg("self"), arg("input"), arg("output")), "Projects the input to the weights and biases and saves results on the output") - .def("__call__", &forward, (arg("self"), arg("input")), "Projects the input to the weights and biases and returns the output. This method implies in copying out the output data and is, therefore, less efficient as its counterpart that sets the output given as parameter. If you have to do a tight loop, consider using that variant instead of this one.") - .def("forward", &forward, (arg("self"), arg("input")), "Projects the input to the weights and biases and returns the output. This method implies in copying out the output data and is, therefore, less efficient as its counterpart that sets the output given as parameter. If you have to do a tight loop, consider using that variant instead of this one.") - ; -} -***/ diff --git a/xbob/machine/linearscoring.cc b/xbob/machine/linearscoring.cc deleted file mode 100644 index 759dcf9..0000000 --- a/xbob/machine/linearscoring.cc +++ /dev/null @@ -1,148 +0,0 @@ -/** - * @file machine/python/linearscoring.cc - * @date Wed Jul 13 16:00:04 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ -#include <boost/python.hpp> -#include <bob/python/ndarray.h> -#include <boost/shared_ptr.hpp> -#include <bob/machine/LinearScoring.h> -#include <boost/python/stl_iterator.hpp> -#include <vector> - - -using namespace boost::python; - -static void convertGMMMeanList(object models, std::vector<blitz::Array<double,1> >& models_c) { - stl_input_iterator<bob::python::const_ndarray> dbegin(models), dend; - std::vector<bob::python::const_ndarray> vmodels(dbegin, dend); - - for(std::vector<bob::python::const_ndarray>::iterator it=vmodels.begin(); - it!=vmodels.end(); ++it) - models_c.push_back(it->bz<double,1>()); -} - -static void convertGMMStatsList(object test_stats, std::vector<boost::shared_ptr<const bob::machine::GMMStats> >& test_stats_c) { - stl_input_iterator<boost::shared_ptr<bob::machine::GMMStats> > dbegin(test_stats), dend; - test_stats_c.assign(dbegin, dend); -} - -static void convertChannelOffsetList(object test_channelOffset, std::vector<blitz::Array<double,1> >& test_channelOffset_c) { - stl_input_iterator<bob::python::const_ndarray> dbegin(test_channelOffset), dend; - std::vector<bob::python::const_ndarray> vtest_channelOffset(dbegin, dend); - - for(std::vector<bob::python::const_ndarray>::iterator it=vtest_channelOffset.begin(); - it!=vtest_channelOffset.end(); ++it) - test_channelOffset_c.push_back(it->bz<double,1>()); -} - -static void convertGMMMachineList(object models, std::vector<boost::shared_ptr<const bob::machine::GMMMachine> >& models_c) { - stl_input_iterator<boost::shared_ptr<bob::machine::GMMMachine> > dbegin(models), dend; - models_c.assign(dbegin, dend); -} - -static object linearScoring1(object models, - bob::python::const_ndarray ubm_mean, bob::python::const_ndarray ubm_variance, - object test_stats, object test_channelOffset = list(), // Empty list - bool frame_length_normalisation = false) -{ - blitz::Array<double,1> ubm_mean_ = ubm_mean.bz<double,1>(); - blitz::Array<double,1> ubm_variance_ = ubm_variance.bz<double,1>(); - - std::vector<blitz::Array<double,1> > models_c; - convertGMMMeanList(models, models_c); - - std::vector<boost::shared_ptr<const bob::machine::GMMStats> > test_stats_c; - convertGMMStatsList(test_stats, test_stats_c); - - bob::python::ndarray ret(bob::core::array::t_float64, models_c.size(), test_stats_c.size()); - blitz::Array<double,2> ret_ = ret.bz<double,2>(); - if (test_channelOffset.ptr() == Py_None || len(test_channelOffset) == 0) { //list is empty - bob::machine::linearScoring(models_c, ubm_mean_, ubm_variance_, test_stats_c, frame_length_normalisation, ret_); - } - else { - std::vector<blitz::Array<double,1> > test_channelOffset_c; - convertChannelOffsetList(test_channelOffset, test_channelOffset_c); - bob::machine::linearScoring(models_c, ubm_mean_, ubm_variance_, test_stats_c, test_channelOffset_c, frame_length_normalisation, ret_); - } - - return ret.self(); -} - -static object linearScoring2(object models, - bob::machine::GMMMachine& ubm, - object test_stats, object test_channelOffset = list(), // Empty list - bool frame_length_normalisation = false) -{ - std::vector<boost::shared_ptr<const bob::machine::GMMMachine> > models_c; - convertGMMMachineList(models, models_c); - - std::vector<boost::shared_ptr<const bob::machine::GMMStats> > test_stats_c; - convertGMMStatsList(test_stats, test_stats_c); - - bob::python::ndarray ret(bob::core::array::t_float64, models_c.size(), test_stats_c.size()); - blitz::Array<double,2> ret_ = ret.bz<double,2>(); - if (test_channelOffset.ptr() == Py_None || len(test_channelOffset) == 0) { //list is empty - bob::machine::linearScoring(models_c, ubm, test_stats_c, frame_length_normalisation, ret_); - } - else { - std::vector<blitz::Array<double,1> > test_channelOffset_c; - convertChannelOffsetList(test_channelOffset, test_channelOffset_c); - bob::machine::linearScoring(models_c, ubm, test_stats_c, test_channelOffset_c, frame_length_normalisation, ret_); - } - - return ret.self(); -} - -static double linearScoring3(bob::python::const_ndarray model, - bob::python::const_ndarray ubm_mean, bob::python::const_ndarray ubm_var, - const bob::machine::GMMStats& test_stats, bob::python::const_ndarray test_channelOffset, - const bool frame_length_normalisation = false) -{ - return bob::machine::linearScoring(model.bz<double,1>(), ubm_mean.bz<double,1>(), - ubm_var.bz<double,1>(), test_stats, test_channelOffset.bz<double,1>(), frame_length_normalisation); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(linearScoring1_overloads, linearScoring1, 4, 6) -BOOST_PYTHON_FUNCTION_OVERLOADS(linearScoring2_overloads, linearScoring2, 3, 5) -BOOST_PYTHON_FUNCTION_OVERLOADS(linearScoring3_overloads, linearScoring3, 5, 6) - -void bind_machine_linear_scoring() { - def("linear_scoring", linearScoring1, linearScoring1_overloads(args("models", "ubm_mean", "ubm_variance", "test_stats", "test_channelOffset", "frame_length_normalisation"), - "Compute a matrix of scores using linear scoring.\n" - "Return a 2D matrix of scores, scores[m, s] is the score for model m against statistics s\n" - "\n" - "Warning Each GMM must have the same size.\n" - "\n" - "models -- list of mean supervectors for the client models\n" - "ubm_mean -- mean supervector for the world model\n" - "ubm_variance -- variance supervector for the world model\n" - "test_stats -- list of accumulate statistics for each test trial\n" - "test_channelOffset -- \n" - "frame_length_normlisation -- perform a normalisation by the number of feature vectors\n" - )); - def("linear_scoring", linearScoring2, linearScoring2_overloads(args("models", "ubm", "test_stats", "test_channel_offset", "frame_length_normalisation"), - "Compute a matrix of scores using linear scoring.\n" - "Return a 2D matrix of scores, scores[m, s] is the score for model m against statistics s\n" - "\n" - "Warning Each GMM must have the same size.\n" - "\n" - "models -- list of client models\n" - "ubm -- world model\n" - "test_stats -- list of accumulate statistics for each test trial\n" - "test_channel_offset -- \n" - "frame_length_normlisation -- perform a normalisation by the number of feature vectors\n" - )); - def("linear_scoring", linearScoring3, linearScoring3_overloads(args("model", "ubm_mean", "ubm_variance", "test_stats", "test_channelOffset", "frame_length_normalisation"), - "Compute a score using linear scoring.\n" - "\n" - "model -- mean supervectors for the client model\n" - "ubm_mean -- mean supervector for the world model\n" - "ubm_variance -- variance supervector for the world model\n" - "test_stats -- accumulate statistics for each test trial\n" - "test_channelOffset -- \n" - "frame_length_normlisation -- perform a normalisation by the number of feature vectors\n" - )); -} diff --git a/xbob/machine/machine.cc b/xbob/machine/machine.cc deleted file mode 100644 index 330d145..0000000 --- a/xbob/machine/machine.cc +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file machine/python/machine.cc - * @date Tue Jul 26 15:11:33 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ -#include <boost/python.hpp> -#include <boost/concept_check.hpp> -#include <blitz/array.h> -#include <bob/machine/Machine.h> - -#include <bob/python/ndarray.h> - -using namespace boost::python; - -static double forward(const bob::machine::Machine<blitz::Array<double,1>, double>& m, - bob::python::const_ndarray input) { - double output; - m.forward(input.bz<double,1>(), output); - return output; -} - -static double forward_(const bob::machine::Machine<blitz::Array<double,1>, double>& m, - bob::python::const_ndarray input) { - double output; - m.forward_(input.bz<double,1>(), output); - return output; -} - -void bind_machine_base() -{ - class_<bob::machine::Machine<blitz::Array<double,1>, double>, boost::noncopyable>("MachineDoubleBase", - "Root class for all Machine<blitz::Array<double,1>, double>", no_init) - .def("__call__", &forward_, (arg("self"), arg("input")), "Executes the machine on the given 1D numpy array of float64, and returns the output. NO CHECK is performed.") - .def("forward", &forward, (arg("self"), arg("input")), "Executes the machine on the given 1D numpy array of float64, and returns the output.") - .def("forward_", &forward_, (arg("self"), arg("input")), "Executes the machine on the given 1D numpy array of float64, and returns the output. NO CHECK is performed.") - ; -} diff --git a/xbob/machine/main.cpp b/xbob/machine/main.cpp deleted file mode 100644 index 7c0784b..0000000 --- a/xbob/machine/main.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Fri 13 Dec 2013 12:35:59 CET - * - * @brief Bindings to bob::machine - */ - -#define XBOB_MACHINE_MODULE -#include <xbob.machine/api.h> - -#ifdef NO_IMPORT_ARRAY -#undef NO_IMPORT_ARRAY -#endif -#include <xbob.blitz/capi.h> -#include <xbob.io/api.h> - -static PyMethodDef library_methods[] = { - {0} /* Sentinel */ -}; - -PyDoc_STRVAR(library_docstr, "bob::machine classes and methods"); - -int PyXbobMachine_APIVersion = XBOB_MACHINE_API_VERSION; - -PyMODINIT_FUNC XBOB_EXT_ENTRY_NAME (void) { - - PyBobMachineActivation_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyBobMachineActivation_Type) < 0) return; - - PyBobMachineIdentityActivation_Type.tp_base = &PyBobMachineActivation_Type; - if (PyType_Ready(&PyBobMachineIdentityActivation_Type) < 0) return; - - PyBobMachineLinearActivation_Type.tp_base = &PyBobMachineActivation_Type; - if (PyType_Ready(&PyBobMachineLinearActivation_Type) < 0) return; - - PyBobMachineLogisticActivation_Type.tp_base = &PyBobMachineActivation_Type; - if (PyType_Ready(&PyBobMachineLogisticActivation_Type) < 0) return; - - PyBobMachineHyperbolicTangentActivation_Type.tp_base = - &PyBobMachineActivation_Type; - if (PyType_Ready(&PyBobMachineHyperbolicTangentActivation_Type) < 0) return; - - PyBobMachineMultipliedHyperbolicTangentActivation_Type.tp_base = - &PyBobMachineActivation_Type; - if (PyType_Ready(&PyBobMachineMultipliedHyperbolicTangentActivation_Type) < 0) - return; - - PyBobMachineLinear_Type.tp_new = PyType_GenericNew; - if (PyType_Ready(&PyBobMachineLinear_Type) < 0) return; - - PyObject* m = Py_InitModule3(XBOB_EXT_MODULE_NAME, library_methods, library_docstr); - - /* register some constants */ - PyModule_AddIntConstant(m, "__api_version__", XBOB_MACHINE_API_VERSION); - PyModule_AddStringConstant(m, "__version__", XBOB_EXT_MODULE_VERSION); - - /* register the types to python */ - Py_INCREF(&PyBobMachineActivation_Type); - PyModule_AddObject(m, "Activation", (PyObject *)&PyBobMachineActivation_Type); - - Py_INCREF(&PyBobMachineIdentityActivation_Type); - PyModule_AddObject(m, "IdentityActivation", (PyObject *)&PyBobMachineIdentityActivation_Type); - - Py_INCREF(&PyBobMachineLinearActivation_Type); - PyModule_AddObject(m, "LinearActivation", (PyObject *)&PyBobMachineLinearActivation_Type); - - Py_INCREF(&PyBobMachineLogisticActivation_Type); - PyModule_AddObject(m, "LogisticActivation", (PyObject *)&PyBobMachineLogisticActivation_Type); - - Py_INCREF(&PyBobMachineHyperbolicTangentActivation_Type); - PyModule_AddObject(m, "HyperbolicTangentActivation", (PyObject *)&PyBobMachineHyperbolicTangentActivation_Type); - - Py_INCREF(&PyBobMachineMultipliedHyperbolicTangentActivation_Type); - PyModule_AddObject(m, "MultipliedHyperbolicTangentActivation", (PyObject *)&PyBobMachineMultipliedHyperbolicTangentActivation_Type); - - Py_INCREF(&PyBobMachineLinear_Type); - PyModule_AddObject(m, "LinearMachine", (PyObject *)&PyBobMachineLinear_Type); - - static void* PyXbobMachine_API[PyXbobMachine_API_pointers]; - - /* exhaustive list of C APIs */ - - /************** - * Versioning * - **************/ - - PyXbobMachine_API[PyXbobMachine_APIVersion_NUM] = (void *)&PyXbobMachine_APIVersion; - - /**************************************** - * Bindings for xbob.machine.Activation * - ****************************************/ - - PyXbobMachine_API[PyBobMachineActivation_Type_NUM] = (void *)&PyBobMachineActivation_Type; - - PyXbobMachine_API[PyBobMachineActivation_Check_NUM] = (void *)&PyBobMachineActivation_Check; - - /************************************************ - * Bindings for xbob.machine.IdentityActivation * - ************************************************/ - - PyXbobMachine_API[PyBobMachineIdentityActivation_Type_NUM] = (void *)&PyBobMachineIdentityActivation_Type; - - /********************************************** - * Bindings for xbob.machine.LinearActivation * - **********************************************/ - - PyXbobMachine_API[PyBobMachineLinearActivation_Type_NUM] = (void *)&PyBobMachineLinearActivation_Type; - - /************************************************ - * Bindings for xbob.machine.LogisticActivation * - ************************************************/ - - PyXbobMachine_API[PyBobMachineLogisticActivation_Type_NUM] = (void *)&PyBobMachineLogisticActivation_Type; - - /********************************************************* - * Bindings for xbob.machine.HyperbolicTangentActivation * - *********************************************************/ - - PyXbobMachine_API[PyBobMachineHyperbolicTangentActivation_Type_NUM] = (void *)&PyBobMachineHyperbolicTangentActivation_Type; - - /******************************************************************* - * Bindings for xbob.machine.MultipliedHyperbolicTangentActivation * - *******************************************************************/ - - PyXbobMachine_API[PyBobMachineMultipliedHyperbolicTangentActivation_Type_NUM] = (void *)&PyBobMachineMultipliedHyperbolicTangentActivation_Type; - - /************************************ - * Bindings for xbob.machine.Linear * - ************************************/ - - PyXbobMachine_API[PyBobMachineLinear_Type_NUM] = (void *)&PyBobMachineLinear_Type; - - PyXbobMachine_API[PyBobMachineLinear_Check_NUM] = (void *)&PyBobMachineLinear_Check; - -#if PY_VERSION_HEX >= 0x02070000 - - /* defines the PyCapsule */ - - PyObject* c_api_object = PyCapsule_New((void *)PyXbobMachine_API, - XBOB_EXT_MODULE_PREFIX "." XBOB_EXT_MODULE_NAME "._C_API", 0); - -#else - - PyObject* c_api_object = PyCObject_FromVoidPtr((void *)PyXbobMachine_API, 0); - -#endif - - if (c_api_object) PyModule_AddObject(m, "_C_API", c_api_object); - - /* imports the NumPy C-API */ - import_array(); - - /* imports xbob.blitz C-API */ - import_xbob_blitz(); - - /* imports xbob.io C-API */ - import_xbob_io(); - -} diff --git a/xbob/machine/mlp.cc b/xbob/machine/mlp.cc deleted file mode 100644 index 278276f..0000000 --- a/xbob/machine/mlp.cc +++ /dev/null @@ -1,252 +0,0 @@ -/** - * @file machine/python/mlp.cc - * @date Thu Jul 7 16:49:35 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief Python bindings to MLPs - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob/python/ndarray.h> -#include <boost/make_shared.hpp> -#include <boost/python/stl_iterator.hpp> -#include <bob/machine/MLP.h> - -using namespace boost::python; - -static tuple get_shape(const bob::machine::MLP& m) { - list retval; - retval.append(m.inputSize()); - const std::vector<blitz::Array<double,1> >& bias = m.getBiases(); - for (size_t i=0; i<bias.size(); ++i) retval.append(bias[i].extent(0)); - return tuple(retval); -} - -static void set_shape(bob::machine::MLP& m, object shape) { - stl_input_iterator<size_t> begin(shape), end; - std::vector<size_t> vshape(begin, end); - m.resize(vshape); -} - -static object forward1(bob::machine::MLP& m, bob::python::const_ndarray input) { - - const bob::core::array::typeinfo& info = input.type(); - - switch(info.nd) { - case 1: - { - bob::python::ndarray output(bob::core::array::t_float64, m.outputSize()); - blitz::Array<double,1> output_ = output.bz<double,1>(); - m.forward(input.bz<double,1>(), output_); - return output.self(); - } - break; - case 2: - { - bob::python::ndarray output(bob::core::array::t_float64, input.type().shape[0],m.outputSize()); - blitz::Array<double,2> output_ = output.bz<double,2>(); - m.forward(input.bz<double,2>(), output_); - return output.self(); - } - break; - default: - PYTHON_ERROR(TypeError, "cannot forward arrays of dimensionality " SIZE_T_FMT ". Only 1D and 2D arrays are supported.", info.nd); - } -} - -static void forward2(bob::machine::MLP& m, bob::python::const_ndarray input, - bob::python::ndarray output) { - const bob::core::array::typeinfo& info = input.type(); - - switch(info.nd) { - case 1: - { - blitz::Array<double,1> output_ = output.bz<double,1>(); - m.forward(input.bz<double,1>(), output_); - } - break; - case 2: - { - blitz::Array<double,2> output_ = output.bz<double,2>(); - m.forward(input.bz<double,2>(), output_); - } - break; - default: - PYTHON_ERROR(TypeError, "cannot forward arrays of dimensionality " SIZE_T_FMT ". Only 1D and 2D arrays are supported.", info.nd); - } -} - -static void forward2_(bob::machine::MLP& m, bob::python::const_ndarray input, - bob::python::ndarray output) { - const bob::core::array::typeinfo& info = input.type(); - - switch(info.nd) { - case 1: - { - blitz::Array<double,1> output_ = output.bz<double,1>(); - m.forward_(input.bz<double,1>(), output_); - } - break; - case 2: - { - blitz::Array<double,2> output_ = output.bz<double,2>(); - m.forward_(input.bz<double,2>(), output_); - } - break; - default: - PYTHON_ERROR(TypeError, "cannot forward arrays of dimensionality " SIZE_T_FMT ". Only 1D and 2D arrays are supported.", info.nd); - } -} - -static void set_input_sub(bob::machine::MLP& m, object o) { - extract<int> int_check(o); - extract<double> float_check(o); - if (int_check.check()) { //is int - m.setInputSubtraction(int_check()); - } - else if (float_check.check()) { //is float - m.setInputSubtraction(float_check()); - } - else { - //try hard-core extraction - throws TypeError, if not possible - extract<bob::python::const_ndarray> array_check(o); - if (!array_check.check()) - PYTHON_ERROR(TypeError, "Cannot extract an array from this Python object"); - bob::python::const_ndarray ar = array_check(); - m.setInputSubtraction(ar.bz<double,1>()); - } -} - -static void set_input_div(bob::machine::MLP& m, object o) { - extract<int> int_check(o); - extract<double> float_check(o); - if (int_check.check()) { //is int - m.setInputDivision(int_check()); - } - else if (float_check.check()) { //is float - m.setInputDivision(float_check()); - } - else { - //try hard-core extraction - throws TypeError, if not possible - extract<bob::python::const_ndarray> array_check(o); - if (!array_check.check()) - PYTHON_ERROR(TypeError, "Cannot extract an array from this Python object"); - bob::python::const_ndarray ar = array_check(); - m.setInputDivision(ar.bz<double,1>()); - } -} - -static tuple get_weight(bob::machine::MLP& m) { - list retval; - for (std::vector<blitz::Array<double,2> >::const_iterator - it = m.getWeights().begin(); it != m.getWeights().end(); ++it) { - retval.append(*it); - } - return tuple(retval); -} - -static void set_weight(bob::machine::MLP& m, object o) { - extract<int> int_check(o); - extract<double> float_check(o); - if (int_check.check()) { //is int - m.setWeights(int_check()); - } - else if (float_check.check()) { //is float - m.setWeights(float_check()); - } - else { - //try hard-core extraction - throws TypeError, if not possible - stl_input_iterator<bob::python::const_ndarray> begin(o), end; - std::vector<bob::python::const_ndarray> ndata(begin, end); - std::vector<blitz::Array<double,2> > vdata; - for(std::vector<bob::python::const_ndarray>::iterator it=ndata.begin(); - it!=ndata.end(); ++it) - vdata.push_back(it->bz<double,2>()); - m.setWeights(vdata); - } -} - -static tuple get_bias(const bob::machine::MLP& m) { - list retval; - for (std::vector<blitz::Array<double,1> >::const_iterator - it = m.getBiases().begin(); it != m.getBiases().end(); ++it) { - retval.append(*it); - } - return tuple(retval); -} - -static void set_bias(bob::machine::MLP& m, object o) { - extract<int> int_check(o); - extract<double> float_check(o); - if (int_check.check()) { //is int - m.setBiases(int_check()); - } - else if (float_check.check()) { //is float - m.setBiases(float_check()); - } - else { - //try hard-core extraction - throws TypeError, if not possible - stl_input_iterator<bob::python::const_ndarray> begin(o), end; - std::vector<bob::python::const_ndarray> ndata(begin, end); - std::vector<blitz::Array<double,1> > vdata; - for(std::vector<bob::python::const_ndarray>::iterator it=ndata.begin(); - it!=ndata.end(); ++it) - vdata.push_back(it->bz<double,1>()); - m.setBiases(vdata); - } -} - -static void random0(bob::machine::MLP& M) { - M.randomize(); -} - -static void random1(bob::machine::MLP& M, - double lower_bound, double upper_bound) { - M.randomize(lower_bound, upper_bound); -} - -static void random2(bob::machine::MLP& M, boost::mt19937& rng) { - M.randomize(rng); -} - -static void random3(bob::machine::MLP& M, - boost::mt19937& rng, double lower_bound, double upper_bound) { - M.randomize(rng, lower_bound, upper_bound); -} - -static boost::shared_ptr<bob::machine::MLP> mlp_from_shape(object shape) { - stl_input_iterator<size_t> begin(shape), end; - std::vector<size_t> vshape(begin, end); - return boost::make_shared<bob::machine::MLP>(vshape); -} - -void bind_machine_mlp() { - class_<bob::machine::MLP, boost::shared_ptr<bob::machine::MLP> >("MLP", "An MLP object is a representation of a Multi-Layer Perceptron. This implementation is feed-forward and fully-connected. The implementation allows setting of input normalization values and a global activation function. References to fully-connected feed-forward networks: Bishop's Pattern Recognition and Machine Learning, Chapter 5. Figure 5.1 shows what we mean.\n\nMLPs normally are multi-layered systems, with 1 or more hidden layers. As a special case, this implementation also supports connecting the input directly to the output by means of a single weight matrix. This is equivalent of a LinearMachine, with the advantage it can be trained by MLP trainers.", no_init) - .def(init<const bob::machine::MLP&>((arg("self"), arg("other")), "Initializes a **new** MLP copying data from another instance")) - .def("__init__", make_constructor(&mlp_from_shape, default_call_policies(), (arg("shape"))), "Builds a new MLP with a shape containing the number of inputs (first element), number of outputs (last element) and the number of neurons in each hidden layer (elements between the first and last element of given tuple). The default activation function will be set to hyperbolic tangent.") - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")), "Constructs a new MLP from a configuration file. Both weights and biases have their dimensionalities checked between each other for consistency.")) - .def(init<const bob::machine::MLP&>((arg("self"), arg("machine")), "Copy constructs an MLP machine")) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::MLP::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this MLP with the 'other' one to be approximately the same.") - .def("load", &bob::machine::MLP::load, (arg("self"), arg("config")), "Loads the weights, biases and other configuration parameter sfrom a configuration file.") - .def("save", &bob::machine::MLP::save, (arg("self"), arg("config")), "Saves the weights and biases to a configuration file.") - .add_property("input_subtract", make_function(&bob::machine::MLP::getInputSubtraction, return_value_policy<copy_const_reference>()), &set_input_sub, "Input subtraction factor, before feeding data through the MLP. The subtraction is the first applied operation in the processing chain - by default, it is set to 0.0.") - .add_property("input_divide", make_function(&bob::machine::MLP::getInputDivision, return_value_policy<copy_const_reference>()), &set_input_div, "Input division factor, before feeding data through the MLP. The division is applied just after subtraction - by default, it is set to 1.0") - .add_property("weights", &get_weight, &set_weight, "A set of weights for the synapses connecting each layer in the MLP. This is represented by a standard tuple containing the weights as 2D numpy.ndarray's of double-precision floating-point elements. Each of the ndarrays has the number of rows equals to the input received by that layer and the number of columns equals to the output fed to the next layer.") - .add_property("biases", &get_bias, &set_bias, "A set of biases for each layer in the MLP. This is represented by a standard tuple containing the biases as 1D numpy.ndarray's of double-precision floating-point elements. Each of the ndarrays has the number of elements equals to the number of neurons in the respective layer. Note that, by definition, the input layer is not subject to biasing. If you need biasing on the input layer, use the input_subtract and input_divide attributes of this MLP.") - .add_property("hidden_activation", &bob::machine::MLP::getHiddenActivation, &bob::machine::MLP::setHiddenActivation, "The activation function (for all hidden layers) - by default, the hyperbolic tangent function. The output provided by the activation function is passed, unchanged, to the user.") - .add_property("output_activation", &bob::machine::MLP::getOutputActivation, &bob::machine::MLP::setOutputActivation, "The output activation function (only for the last output layer) - by default, the hyperbolic tangent function. The output provided by the activation function is passed, unchanged, to the user.") - .add_property("shape", &get_shape, &set_shape, "A tuple that represents the size of the input vector followed by the number of neurons in each hidden layer of the MLP and, finally, terminated by the size of the output vector in the format ``(input, hidden0, hidden1, ..., hiddenN, output)``. If you set this attribute, the network is automatically resized and should be considered uninitialized.") - .def("__call__", &forward2, (arg("self"), arg("input"), arg("output")), "Projects the input to the weights and biases and saves results on the output. You can either pass an input with 1 or 2 dimensions. If 2D, it is the same as running the 1D case many times considering as input to be every row in the input matrix.") - .def("forward", &forward2, (arg("self"), arg("input"), arg("output")), "Projects the input to the weights and biases and saves results on the output. You can either pass an input with 1 or 2 dimensions. If 2D, it is the same as running the 1D case many times considering as input to be every row in the input matrix.") - .def("forward_", &forward2_, (arg("self"), arg("input"), arg("output")), "Projects the input to the weights and biases and saves results on the output. You can either pass an input with 1 or 2 dimensions. If 2D, it is the same as running the 1D case many times considering as input to be every row in the input matrix.") - .def("__call__", &forward1, (arg("self"), arg("input")), "Projects the input to the weights and biases and returns the output. This method implies in copying out the output data and is, therefore, less efficient as its counterpart that sets the output given as parameter. If you have to do a tight loop, consider using that variant instead of this one. You can either pass an input with 1 or 2 dimensions. If 2D, it is the same as running the 1D case many times considering as input to be every row in the input matrix.") - .def("forward", &forward1, (arg("self"), arg("input")), "Projects the input to the weights and biases and returns the output. This method implies in copying out the output data and is, therefore, less efficient as its counterpart that sets the output given as parameter. If you have to do a tight loop, consider using that variant instead of this one. You can either pass an input with 1 or 2 dimensions. If 2D, it is the same as running the 1D case many times considering as input to be every row in the input matrix.") - .def("randomize", &random0, (arg("self")), "Sets all weights and biases of this MLP, with random values between [-0.1, 0.1) as advised in textbooks.\n\nValues are drawn using boost::uniform_real class. The seed is picked using a time-based algorithm. Different calls spaced of at least 1 microsecond (machine clock) will be seeded differently. Values are taken from the range [lower_bound, upper_bound) according to the boost::random documentation.") - .def("randomize", &random1, (arg("self"), arg("lower_bound"), arg("upper_bound")), "Sets all weights and biases of this MLP, with random values between [lower_bound, upper_bound).\n\nValues are drawn using boost::uniform_real class. The seed is picked using a time-based algorithm. Different calls spaced of at least 1 microsecond (machine clock) will be seeded differently. Values are taken from the range [lower_bound, upper_bound) according to the boost::random documentation.") - .def("randomize", &random2, (arg("self"), arg("rng")), "Sets all weights and biases of this MLP, with random values between [-0.1, 0.1) as advised in textbooks.\n\nValues are drawn using boost::uniform_real class. You should pass the generator in this variant. You can seed it the way it pleases you. Values are taken from the range [lower_bound, upper_bound) according to the boost::random documentation.") - .def("randomize", &random3, (arg("self"), arg("rng"), arg("lower_bound"), arg("upper_bound")), "Sets all weights and biases of this MLP, with random values between [lower_bound, upper_bound).\n\nValues are drawn using boost::uniform_real class. In this variant you can pass your own random number generate as well as the limits from where the random numbers will be chosen from. Values are taken from the range [lower_bound, upper_bound) according to the boost::random documentation.") - ; -} diff --git a/xbob/machine/plda.cc b/xbob/machine/plda.cc deleted file mode 100644 index 888d824..0000000 --- a/xbob/machine/plda.cc +++ /dev/null @@ -1,177 +0,0 @@ -/** - * @file machine/python/plda.cc - * @date Fri Oct 14 18:07:56 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Python bindings for the PLDABase/PLDAMachine - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob/python/ndarray.h> -#include <boost/shared_ptr.hpp> -#include <bob/python/exception.h> -#include <bob/machine/PLDAMachine.h> - -using namespace boost::python; - -static void py_set_dim_d(bob::machine::PLDABase& machine, const size_t dim_d) -{ - machine.resize(dim_d, machine.getDimF(), machine.getDimG()); -} -static void py_set_dim_f(bob::machine::PLDABase& machine, const size_t dim_f) -{ - machine.resize(machine.getDimD(), dim_f, machine.getDimG()); -} -static void py_set_dim_g(bob::machine::PLDABase& machine, const size_t dim_g) -{ - machine.resize(machine.getDimD(), machine.getDimF(), dim_g); -} - -// Set methods that uses blitz::Arrays -static void py_set_mu(bob::machine::PLDABase& machine, - bob::python::const_ndarray mu) -{ - machine.setMu(mu.bz<double,1>()); -} - -static void py_set_f(bob::machine::PLDABase& machine, - bob::python::const_ndarray f) -{ - machine.setF(f.bz<double,2>()); -} - -static void py_set_g(bob::machine::PLDABase& machine, - bob::python::const_ndarray g) -{ - machine.setG(g.bz<double,2>()); -} - -static void py_set_sigma(bob::machine::PLDABase& machine, - bob::python::const_ndarray sigma) -{ - machine.setSigma(sigma.bz<double,1>()); -} - - -static double computeLogLikelihood(bob::machine::PLDAMachine& plda, - bob::python::const_ndarray samples, bool with_enrolled_samples=true) -{ - const bob::core::array::typeinfo& info = samples.type(); - switch (info.nd) { - case 1: - return plda.computeLogLikelihood(samples.bz<double,1>(), with_enrolled_samples); - case 2: - return plda.computeLogLikelihood(samples.bz<double,2>(), with_enrolled_samples); - default: - PYTHON_ERROR(TypeError, "PLDA log-likelihood computation does not accept input array with '" SIZE_T_FMT "' dimensions (only 1D or 2D arrays)", info.nd); - } -} - -static double plda_forward_sample(bob::machine::PLDAMachine& m, - bob::python::const_ndarray samples) -{ - const bob::core::array::typeinfo& info = samples.type(); - switch (info.nd) { - case 1: - { - double score; - // Calls the forward function - m.forward(samples.bz<double,1>(), score); - return score; - } - case 2: - { - double score; - // Calls the forward function - m.forward(samples.bz<double,2>(), score); - return score; - } - default: - PYTHON_ERROR(TypeError, "PLDA forwarding does not accept input array with '" SIZE_T_FMT "' dimensions (only 1D or 2D arrays)", info.nd); - } -} - -static double py_log_likelihood_point_estimate(bob::machine::PLDABase& plda, - bob::python::const_ndarray xij, bob::python::const_ndarray hi, - bob::python::const_ndarray wij) -{ - return plda.computeLogLikelihoodPointEstimate(xij.bz<double,1>(), - hi.bz<double,1>(), wij.bz<double,1>()); -} - -BOOST_PYTHON_FUNCTION_OVERLOADS(computeLogLikelihood_overloads, computeLogLikelihood, 2, 3) - -void bind_machine_plda() -{ - class_<bob::machine::PLDABase, boost::shared_ptr<bob::machine::PLDABase> >("PLDABase", "A PLDABase can be seen as a container for the subspaces F, G, the diagonal covariance matrix sigma (stored as a 1D array) and the mean vector mu when performing Probabilistic Linear Discriminant Analysis (PLDA). PLDA is a probabilistic model that incorporates components describing both between-class and within-class variations. A PLDABase can be shared between several PLDAMachine that contains class-specific information (information about the enrolment samples).\n\nReferences:\n1. 'A Scalable Formulation of Probabilistic Linear Discriminant Analysis: Applied to Face Recognition', Laurent El Shafey, Chris McCool, Roy Wallace, Sebastien Marcel, TPAMI'2013\n2. 'Probabilistic Linear Discriminant Analysis for Inference About Identity', Prince and Elder, ICCV'2007.\n3. 'Probabilistic Models for Inference about Identity', Li, Fu, Mohammed, Elder and Prince, TPAMI'2012.", init<const size_t, const size_t, const size_t, optional<const double> >((arg("self"), arg("dim_d"), arg("dim_f"), arg("dim_g"), arg("variance_flooring")=0.), "Builds a new PLDABase. dim_d is the dimensionality of the input features, dim_f is the dimensionality of the F subspace and dim_g the dimensionality of the G subspace. The variance flooring threshold is the minimum value that the variance sigma can reach, as this diagonal matrix is inverted.")) - .def(init<>((arg("self")), "Constructs a new empty PLDABase.")) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")), "Constructs a new PLDABase from a configuration file.")) - .def(init<const bob::machine::PLDABase&>((arg("self"), arg("machine")), "Copy constructs a PLDABase")) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::PLDABase::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this PLDABase with the 'other' one to be approximately the same.") - .def("load", &bob::machine::PLDABase::load, (arg("self"), arg("config")), "Loads the configuration parameters from a configuration file.") - .def("save", &bob::machine::PLDABase::save, (arg("self"), arg("config")), "Saves the configuration parameters to a configuration file.") - .add_property("dim_d", &bob::machine::PLDABase::getDimD, &py_set_dim_d, "Dimensionality of the input feature vectors") - .add_property("dim_f", &bob::machine::PLDABase::getDimF, &py_set_dim_f, "Dimensionality of the F subspace/matrix of the PLDA model") - .add_property("dim_g", &bob::machine::PLDABase::getDimG, &py_set_dim_g, "Dimensionality of the G subspace/matrix of the PLDA model") - .add_property("mu", make_function(&bob::machine::PLDABase::getMu, return_value_policy<copy_const_reference>()), &py_set_mu, "The mean vector mu of the PLDA model") - .add_property("f", make_function(&bob::machine::PLDABase::getF, return_value_policy<copy_const_reference>()), &py_set_f, "The subspace/matrix F of the PLDA model") - .add_property("g", make_function(&bob::machine::PLDABase::getG, return_value_policy<copy_const_reference>()), &py_set_g, "The subspace/matrix G of the PLDA model") - .add_property("sigma", make_function(&bob::machine::PLDABase::getSigma, return_value_policy<copy_const_reference>()), &py_set_sigma, "The diagonal covariance matrix (represented by a 1D numpy array) sigma of the PLDA model") - .add_property("variance_threshold", &bob::machine::PLDABase::getVarianceThreshold, &bob::machine::PLDABase::setVarianceThreshold, - "The variance flooring threshold, i.e. the minimum allowed value of variance (sigma) in each dimension. " - "The variance sigma will be set to this value if an attempt is made to set it to a smaller value.") - .def("resize", &bob::machine::PLDABase::resize, (arg("self"), arg("dim_d"), arg("dim_f"), arg("dim_g")), "Resizes the dimensionality of the PLDA model. Paramaters mu, F, G and sigma are reinitialized.") - .def("has_gamma", &bob::machine::PLDABase::hasGamma, (arg("self"), arg("a")), "Tells if the gamma matrix for the given number of samples has already been computed. (gamma = inverse(I+a.F^T.beta.F), please check the documentation/source code for more details.") - .def("compute_gamma", &bob::machine::PLDABase::computeGamma, (arg("self"), arg("a"), arg("gamma")), "Computes the gamma matrix for the given number of samples. (gamma = inverse(I+a.F^T.beta.F), please check the documentation/source code for more details.") - .def("get_add_gamma", make_function(&bob::machine::PLDABase::getAddGamma, return_value_policy<copy_const_reference>(), (arg("self"), arg("a"))), "Computes the gamma matrix for the given number of samples. (gamma = inverse(I+a.F^T.beta.F), please check the documentation/source code for more details.") - .def("get_gamma", make_function(&bob::machine::PLDABase::getGamma, return_value_policy<copy_const_reference>(), (arg("self"), arg("a"))), "Returns the gamma matrix for the given number of samples if it has already been put in cache. Throws an exception otherwise. (gamma = inverse(I+a.F^T.beta.F), please check the documentation/source code for more details.") - .def("has_log_like_const_term", &bob::machine::PLDABase::hasLogLikeConstTerm, (arg("self"), arg("a")), "Tells if the log likelihood constant term for the given number of samples has already been computed.") - .def("compute_log_like_const_term", (double (bob::machine::PLDABase::*)(const size_t, const blitz::Array<double,2>&) const)&bob::machine::PLDABase::computeLogLikeConstTerm, (arg("self"), arg("a"), arg("gamma")), "Computes the log likelihood constant term for the given number of samples.") - .def("get_add_log_like_const_term", &bob::machine::PLDABase::getAddLogLikeConstTerm, (arg("self"), arg("a")), "Computes the log likelihood constant term for the given number of samples, and adds it to the machine (as well as gamma), if it does not already exist.") - .def("get_log_like_const_term", &bob::machine::PLDABase::getLogLikeConstTerm, (arg("self"), arg("a")), "Returns the log likelihood constant term for the given number of samples if it has already been put in cache. Throws an exception otherwise.") - .def("clear_maps", &bob::machine::PLDABase::clearMaps, (arg("self")), "Clear the maps containing the gamma's as well as the log likelihood constant term for few number of samples. These maps are used to make likelihood computations faster.") - .def("compute_log_likelihood_point_estimate", &py_log_likelihood_point_estimate, (arg("self"), arg("xij"), arg("hi"), arg("wij")), "Computes the log-likelihood of a sample given the latent variables hi and wij (point estimate rather than Bayesian-like full integration).") - .def(self_ns::str(self_ns::self)) - .add_property("__isigma__", make_function(&bob::machine::PLDABase::getISigma, return_value_policy<copy_const_reference>()), "sigma^{-1} matrix stored in cache") - .add_property("__alpha__", make_function(&bob::machine::PLDABase::getAlpha, return_value_policy<copy_const_reference>()), "alpha matrix stored in cache") - .add_property("__beta__", make_function(&bob::machine::PLDABase::getBeta, return_value_policy<copy_const_reference>()), "beta matrix stored in cache") - .add_property("__ft_beta__", make_function(&bob::machine::PLDABase::getFtBeta, return_value_policy<copy_const_reference>()), "F^T.beta matrix stored in cache") - .add_property("__gt_i_sigma__", make_function(&bob::machine::PLDABase::getGtISigma, return_value_policy<copy_const_reference>()), "G^T.sigma^{-1} matrix stored in cache") - .add_property("__logdet_alpha__", &bob::machine::PLDABase::getLogDetAlpha, "Logarithm of the determinant of the alpha matrix stored in cache.") - .add_property("__logdet_sigma__", &bob::machine::PLDABase::getLogDetSigma, "Logarithm of the determinant of the sigma matrix stored in cache.") - .def("__precompute__", &bob::machine::PLDABase::precompute, (arg("self")), "Precomputes useful values such as alpha and beta.") - .def("__precompute_log_like__", &bob::machine::PLDABase::precomputeLogLike, (arg("self")), "Precomputes useful values for log-likelihood computations.") - ; - - class_<bob::machine::PLDAMachine, boost::shared_ptr<bob::machine::PLDAMachine> >("PLDAMachine", "A PLDAMachine contains class-specific information (from the enrolment samples) when performing Probabilistic Linear Discriminant Analysis (PLDA). It should be attached to a PLDABase that contains information such as the subspaces F and G.\n\nReferences:\n1. 'A Scalable Formulation of Probabilistic Linear Discriminant Analysis: Applied to Face Recognition', Laurent El Shafey, Chris McCool, Roy Wallace, Sebastien Marcel, TPAMI'2013\n2. 'Probabilistic Linear Discriminant Analysis for Inference About Identity', Prince and Elder, ICCV'2007.\n3. 'Probabilistic Models for Inference about Identity', Li, Fu, Mohammed, Elder and Prince, TPAMI'2012.", init<boost::shared_ptr<bob::machine::PLDABase> >((arg("self"), arg("plda_base")), "Builds a new PLDAMachine. An attached PLDABase should be provided, that can be shared by several PLDAMachine.")) - .def(init<>((arg("self")), "Constructs a new empty (invalid) PLDAMachine. A PLDABase should then be set using the 'plda_base' attribute of this object.")) - .def(init<bob::io::HDF5File&, boost::shared_ptr<bob::machine::PLDABase> >((arg("self"), arg("config"), arg("plda_base")), "Constructs a new PLDAMachine from a configuration file (and a PLDABase object).")) - .def(init<const bob::machine::PLDAMachine&>((arg("self"), arg("machine")), "Copy constructs a PLDAMachine")) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::PLDAMachine::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this PLDAMachine with the 'other' one to be approximately the same.") - .def("load", &bob::machine::PLDAMachine::load, (arg("self"), arg("config")), "Loads the configuration parameters from a configuration file. The PLDABase will not be loaded, and has to be set manually using the 'plda_base' attribute.") - .def("save", &bob::machine::PLDAMachine::save, (arg("self"), arg("config")), "Saves the configuration parameters to a configuration file. The PLDABase will not be saved, and has to be saved separately, as it can be shared by several PLDAMachines.") - .add_property("plda_base", &bob::machine::PLDAMachine::getPLDABase, &bob::machine::PLDAMachine::setPLDABase) - .add_property("dim_d", &bob::machine::PLDAMachine::getDimD, "Dimensionality of the input feature vectors") - .add_property("dim_f", &bob::machine::PLDAMachine::getDimF, "Dimensionality of the F subspace/matrix of the PLDA model") - .add_property("dim_g", &bob::machine::PLDAMachine::getDimG, "Dimensionality of the G subspace/matrix of the PLDA model") - .add_property("n_samples", &bob::machine::PLDAMachine::getNSamples, &bob::machine::PLDAMachine::setNSamples, "Number of enrolled samples") - .add_property("w_sum_xit_beta_xi", &bob::machine::PLDAMachine::getWSumXitBetaXi, &bob::machine::PLDAMachine::setWSumXitBetaXi) - .add_property("weighted_sum", make_function(&bob::machine::PLDAMachine::getWeightedSum, return_value_policy<copy_const_reference>()), &bob::machine::PLDAMachine::setWeightedSum) - .add_property("log_likelihood", &bob::machine::PLDAMachine::getLogLikelihood, &bob::machine::PLDAMachine::setLogLikelihood) - .def("has_gamma", &bob::machine::PLDAMachine::hasGamma, (arg("self"), arg("a")), "Tells if the gamma matrix for the given number of samples has already been computed. (gamma = inverse(I+a.F^T.beta.F), please check the documentation/source code for more details.") - .def("get_add_gamma", make_function(&bob::machine::PLDAMachine::getAddGamma, return_value_policy<copy_const_reference>(), (arg("self"), arg("a"))), "Computes the gamma matrix for the given number of samples. (gamma = inverse(I+a.F^T.beta.F), please check the documentation/source code for more details.") - .def("get_gamma", make_function(&bob::machine::PLDAMachine::getGamma, return_value_policy<copy_const_reference>(), (arg("self"), arg("a"))), "Returns the gamma matrix for the given number of samples if it has already been put in cache. Throws an exception otherwise. (gamma = inverse(I+a.F^T.beta.F), please check the documentation/source code for more details.") - .def("has_log_like_const_term", &bob::machine::PLDAMachine::hasLogLikeConstTerm, (arg("self"), arg("a")), "Tells if the log likelihood constant term for the given number of samples has already been computed.") - .def("get_add_log_like_const_term", &bob::machine::PLDAMachine::getAddLogLikeConstTerm, (arg("self"), arg("a")), "Computes the log likelihood constant term for the given number of samples, and adds it to the machine (as well as gamma), if it does not already exist.") - .def("get_log_like_const_term", &bob::machine::PLDAMachine::getLogLikeConstTerm, (arg("self"), arg("a")), "Returns the log likelihood constant term for the given number of samples if it has already been put in cache. Throws an exception otherwise.") - .def("clear_maps", &bob::machine::PLDAMachine::clearMaps, (arg("self")), "Clears the maps containing the gamma's as well as the log likelihood constant term for few number of samples. These maps are used to make likelihood computations faster.") - .def("compute_log_likelihood", &computeLogLikelihood, computeLogLikelihood_overloads((arg("self"), arg("sample"), arg("use_enrolled_samples")=true), "Computes the log-likelihood considering only the probe sample(s) or jointly the probe sample(s) and the enrolled samples.")) - .def("__call__", &plda_forward_sample, (arg("self"), arg("sample")), "Processes a sample and returns a log-likelihood ratio score.") - .def("forward", &plda_forward_sample, (arg("self"), arg("sample")), "Processes a sample and returns a log-likelihood ratio score.") - ; -} diff --git a/xbob/machine/roll.cc b/xbob/machine/roll.cc deleted file mode 100644 index bf213f5..0000000 --- a/xbob/machine/roll.cc +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @file machine/python/roll.cc - * @date Tue Jun 25 19:09:50 CEST 2013 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob/python/ndarray.h> -#include <vector> -#include <bob/machine/roll.h> -#include <boost/python/stl_iterator.hpp> - -using namespace boost::python; - -static object unroll0(const bob::machine::MLP& m) -{ - bob::python::ndarray vec(bob::core::array::t_float64, - bob::machine::detail::getNbParameters(m)); - blitz::Array<double,1> vec_ = vec.bz<double,1>(); - bob::machine::unroll(m, vec_); - return vec.self(); -} - -static void unroll1(const bob::machine::MLP& m, bob::python::ndarray vec) -{ - blitz::Array<double,1> vec_ = vec.bz<double,1>(); - bob::machine::unroll(m, vec_); -} - -static void unroll2(object w, object b, bob::python::ndarray vec) -{ - stl_input_iterator<bob::python::const_ndarray> wbegin(w), wend; - std::vector<bob::python::const_ndarray> wv(wbegin, wend); - std::vector<blitz::Array<double,2> > w_; - for(std::vector<bob::python::const_ndarray>::iterator it=wv.begin(); - it!=wv.end(); ++it) - w_.push_back(it->bz<double,2>()); - - stl_input_iterator<bob::python::const_ndarray> bbegin(b), bend; - std::vector<bob::python::const_ndarray> bv(bbegin, bend); - std::vector<blitz::Array<double,1> > b_; - for(std::vector<bob::python::const_ndarray>::iterator it=bv.begin(); - it!=bv.end(); ++it) - b_.push_back(it->bz<double,1>()); - - blitz::Array<double,1> vec_ = vec.bz<double,1>(); - bob::machine::unroll(w_, b_, vec_); -} - -static object unroll3(object w, object b) -{ - stl_input_iterator<bob::python::const_ndarray> wbegin(w), wend; - std::vector<bob::python::const_ndarray> wv(wbegin, wend); - std::vector<blitz::Array<double,2> > w_; - for(std::vector<bob::python::const_ndarray>::iterator it=wv.begin(); - it!=wv.end(); ++it) - w_.push_back(it->bz<double,2>()); - - stl_input_iterator<bob::python::const_ndarray> bbegin(b), bend; - std::vector<bob::python::const_ndarray> bv(bbegin, bend); - std::vector<blitz::Array<double,1> > b_; - for(std::vector<bob::python::const_ndarray>::iterator it=bv.begin(); - it!=bv.end(); ++it) - b_.push_back(it->bz<double,1>()); - - bob::python::ndarray vec(bob::core::array::t_float64, - bob::machine::detail::getNbParameters(w_, b_)); - blitz::Array<double,1> vec_ = vec.bz<double,1>(); - bob::machine::unroll(w_, b_, vec_); - return vec.self(); -} - -static void roll1(bob::machine::MLP& m, bob::python::const_ndarray vec) -{ - bob::machine::roll(m, vec.bz<double,1>()); -} - -static void roll2(object w, object b, bob::python::const_ndarray vec) -{ - stl_input_iterator<bob::python::ndarray> wbegin(w), wend; - std::vector<bob::python::ndarray> wv(wbegin, wend); - std::vector<blitz::Array<double,2> > w_; - for(std::vector<bob::python::ndarray>::iterator it=wv.begin(); - it!=wv.end(); ++it) - w_.push_back(it->bz<double,2>()); - - stl_input_iterator<bob::python::ndarray> bbegin(b), bend; - std::vector<bob::python::ndarray> bv(bbegin, bend); - std::vector<blitz::Array<double,1> > b_; - for(std::vector<bob::python::ndarray>::iterator it=bv.begin(); - it!=bv.end(); ++it) - b_.push_back(it->bz<double,1>()); - - bob::machine::roll(w_, b_, vec.bz<double,1>()); -} - -void bind_machine_roll() { - def("unroll", &unroll0, (arg("MLP")), "Unroll the parameters of an MLP into a single 1D numpy array"); - def("unroll", &unroll3, (arg("weights"), arg("biases")), "Unroll the parameters (weights and biases) into a single 1D numpy array."); - def("unroll", &unroll1, (arg("MLP"), arg("vec")), "Unroll the parameters of an MLP into the 1D numpy array 'vec'. 'vec' should be allocated with the correct size."); - def("unroll", &unroll2, (arg("weights"), arg("biases"), arg("vec")), "Unroll the parameters (weights and biases) into the 1D numpy array 'vec'. 'vec' should be allocated with the correct size."); - - def("roll", &roll1, (arg("MLP"), arg("vec")), "Roll the 1D numpy array 'vec' into the parameters (weights and biases) of the MLP."); - def("roll", &roll2, (arg("weights"), arg("biases"), arg("vec")), "Roll the 1D numpy array 'vec' into the parameters (weights and biases)"); -} diff --git a/xbob/machine/svm.cc b/xbob/machine/svm.cc deleted file mode 100644 index 2cf3756..0000000 --- a/xbob/machine/svm.cc +++ /dev/null @@ -1,284 +0,0 @@ -/** - * @file machine/python/svm.cc - * @date Sat Dec 17 14:41:56 2011 +0100 - * @author AndreÌ Anjos <andre.dos.anjos@gmail.com> - * - * @brief Bindings to our C++ SVM infrastructure. - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob/python/ndarray.h> -#include <bob/machine/SVM.h> - -using namespace boost::python; - -static tuple get_shape(const bob::machine::SupportVector& m) { - return make_tuple(m.inputSize(), m.outputSize()); -} - -static object predict_class(const bob::machine::SupportVector& m, - bob::python::const_ndarray input) { - return object(m.predictClass(input.bz<double,1>())); -} - -static object predict_class_(const bob::machine::SupportVector& m, - bob::python::const_ndarray input) { - return object(m.predictClass_(input.bz<double,1>())); -} - -static object predict_class_n(const bob::machine::SupportVector& m, - bob::python::const_ndarray input) { - blitz::Array<double,2> i_ = input.bz<double,2>(); - if ((size_t)i_.extent(1) < m.inputSize()) { - PYTHON_ERROR(RuntimeError, "Input array should have **at least** " SIZE_T_FMT " columns, but you have given me one with %d instead", m.inputSize(), i_.extent(1)); - } - blitz::Range all = blitz::Range::all(); - list retval; - for (int k=0; k<i_.extent(0); ++k) { - blitz::Array<double,1> tmp = i_(k,all); - retval.append(m.predictClass_(tmp)); - } - return tuple(retval); -} - -static object svm_call(const bob::machine::SupportVector& m, - bob::python::const_ndarray input) { - switch (input.type().nd) { - case 1: - return predict_class(m, input); - case 2: - return predict_class_n(m, input); - default: - PYTHON_ERROR(RuntimeError, "Input array should be 1D or 2D. You passed an array with " SIZE_T_FMT " dimensions instead", input.type().nd); - } -} - -static int predict_class_and_scores(const bob::machine::SupportVector& m, - bob::python::const_ndarray input, bob::python::ndarray scores) { - blitz::Array<double,1> scores_ = scores.bz<double,1>(); - return m.predictClassAndScores(input.bz<double,1>(), scores_); -} - -static int predict_class_and_scores_(const bob::machine::SupportVector& m, - bob::python::const_ndarray input, bob::python::ndarray scores) { - blitz::Array<double,1> scores_ = scores.bz<double,1>(); - return m.predictClassAndScores_(input.bz<double,1>(), scores_); -} - -static tuple predict_class_and_scores2(const bob::machine::SupportVector& m, - bob::python::const_ndarray input) { - size_t size = m.outputSize() < 2 ? 1 : (m.outputSize()*(m.outputSize()-1))/2; - bob::python::ndarray scores(bob::core::array::t_float64, size); - blitz::Array<double,1> scores_ = scores.bz<double,1>(); - int c = m.predictClassAndScores(input.bz<double,1>(), scores_); - return make_tuple(c, scores.self()); -} - -static object predict_class_and_scores_n(const bob::machine::SupportVector& m, - bob::python::const_ndarray input) { - blitz::Array<double,2> i_ = input.bz<double,2>(); - if ((size_t)i_.extent(1) < m.inputSize()) { - PYTHON_ERROR(RuntimeError, "Input array should have **at least** " SIZE_T_FMT " columns, but you have given me one with %d instead", m.inputSize(), i_.extent(1)); - } - size_t size = m.outputSize() < 2 ? 1 : (m.outputSize()*(m.outputSize()-1))/2; - blitz::Range all = blitz::Range::all(); - list classes, scores; - for (int k=0; k<i_.extent(0); ++k) { - blitz::Array<double,1> tmp = i_(k,all); - bob::python::ndarray s(bob::core::array::t_float64, size); - blitz::Array<double,1> s_ = s.bz<double,1>(); - classes.append(m.predictClassAndScores_(tmp, s_)); - scores.append(s.self()); - } - return make_tuple(tuple(classes), tuple(scores)); -} - -static int predict_class_and_probs(const bob::machine::SupportVector& m, - bob::python::const_ndarray input, bob::python::ndarray probs) { - blitz::Array<double,1> probs_ = probs.bz<double,1>(); - return m.predictClassAndProbabilities(input.bz<double,1>(), probs_); -} - -static int predict_class_and_probs_(const bob::machine::SupportVector& m, - bob::python::const_ndarray input, bob::python::ndarray probs) { - blitz::Array<double,1> probs_ = probs.bz<double,1>(); - return m.predictClassAndProbabilities_(input.bz<double,1>(), probs_); -} - -static tuple predict_class_and_probs2(const bob::machine::SupportVector& m, - bob::python::const_ndarray input) { - bob::python::ndarray probs(bob::core::array::t_float64, m.outputSize()); - blitz::Array<double,1> probs_ = probs.bz<double,1>(); - int c = m.predictClassAndProbabilities(input.bz<double,1>(), probs_); - return make_tuple(c, probs.self()); -} - -static object predict_class_and_probs_n(const bob::machine::SupportVector& m, - bob::python::const_ndarray input) { - blitz::Array<double,2> i_ = input.bz<double,2>(); - if ((size_t)i_.extent(1) < m.inputSize()) { - PYTHON_ERROR(RuntimeError, "Input array should have **at least** " SIZE_T_FMT " columns, but you have given me one with %d instead", m.inputSize(), i_.extent(1)); - } - if (!m.supportsProbability()) { - PYTHON_ERROR(RuntimeError, "this SVM does not support probabilities"); - } - blitz::Range all = blitz::Range::all(); - list classes, probs; - for (int k=0; k<i_.extent(0); ++k) { - blitz::Array<double,1> tmp = i_(k,all); - bob::python::ndarray s(bob::core::array::t_float64, m.numberOfClasses()); - blitz::Array<double,1> s_ = s.bz<double,1>(); - classes.append(m.predictClassAndProbabilities_(tmp, s_)); - probs.append(s.self()); - } - return make_tuple(tuple(classes), tuple(probs)); -} - -static tuple labels(const bob::machine::SupportVector& m) { - list retval; - for (size_t k=0; k<m.numberOfClasses(); ++k) retval.append(m.classLabel(k)); - return tuple(retval); -} - -static object svmfile_read(bob::machine::SVMFile& f) { - if (!f.good()) return object(); //None - bob::python::ndarray values(bob::core::array::t_float64, f.shape()); - blitz::Array<double,1> values_ = values.bz<double,1>(); - int label; - if (!f.read_(label, values_)) return object(); //None - return make_tuple(label, values.self()); -} - -static tuple svmfile_read_all(bob::machine::SVMFile& f) { - list labels; - list values; - while (f.good()) { - object data = svmfile_read(f); - if (!TPY_ISNONE(data)) { - labels.append(data[0]); - values.append(data[1]); - } - } - return make_tuple(tuple(labels), tuple(values)); -} - -static object svmfile_read2(bob::machine::SVMFile& f, bob::python::ndarray values) { - if (!f.good()) return object(); //None - blitz::Array<double,1> values_ = values.bz<double,1>(); - int label; - if (!f.read(label, values_)) return object(); //None - return object(label); -} - -static object svmfile_read2_(bob::machine::SVMFile& f, bob::python::ndarray values) { - if (!f.good()) return object(); //None - blitz::Array<double,1> values_ = values.bz<double,1>(); - int label; - if (!f.read_(label, values_)) return object(); //None - return object(label); -} - -static tuple svmfile_shape(bob::machine::SVMFile& f) { - return make_tuple(f.shape()); -} - -static void set_input_sub(bob::machine::SupportVector& m, object o) { - extract<int> int_check(o); - extract<double> float_check(o); - if (int_check.check()) { //is int - m.setInputSubtraction(int_check()); - } - else if (float_check.check()) { //is float - m.setInputSubtraction(float_check()); - } - else { - //try hard-core extraction - throws TypeError, if not possible - extract<bob::python::const_ndarray> array_check(o); - if (!array_check.check()) - PYTHON_ERROR(TypeError, "Cannot extract an array from this Python object"); - bob::python::const_ndarray ar = array_check(); - m.setInputSubtraction(ar.bz<double,1>()); - } -} - -static void set_input_div(bob::machine::SupportVector& m, object o) { - extract<int> int_check(o); - extract<double> float_check(o); - if (int_check.check()) { //is int - m.setInputDivision(int_check()); - } - else if (float_check.check()) { //is float - m.setInputDivision(float_check()); - } - else { - //try hard-core extraction - throws TypeError, if not possible - extract<bob::python::const_ndarray> array_check(o); - if (!array_check.check()) - PYTHON_ERROR(TypeError, "Cannot extract an array from this Python object"); - bob::python::const_ndarray ar = array_check(); - m.setInputDivision(ar.bz<double,1>()); - } -} - -void bind_machine_svm() { - - class_<bob::machine::SVMFile, boost::shared_ptr<bob::machine::SVMFile>, boost::noncopyable>("SVMFile", "Loads a given libsvm data file. The data file format, as defined on the library README is like this:\n\n <label> <index1>:<value1> <index2>:<value2> ...\n .\n .\n .\n\nThe labels are integer values, so are the indexes, starting from '1' (and not from zero as a C-programmer would expect. The values are floating point.\n\nZero values are suppressed - libsvm uses a sparse format.\n\nThis class is made available to you so you can input original libsvm files and convert them to another representation better supported. You cannot, from this object, save data or extend the current set.", init<const char*>((arg("self"), arg("filename")), "Intializes an SVM file with the path to an existing file. The file is scanned entirely so to compute the sample size.")) - .add_property("shape", &svmfile_shape, "The size of each sample in the file, as tuple with a single entry") - .add_property("__len__", &bob::machine::SVMFile::samples, "The size of each sample in the file, as tuple with a single entry") - .add_property("filename", make_function(&bob::machine::SVMFile::filename, return_value_policy<copy_const_reference>()), "The name of the file being read") - .def("reset", &bob::machine::SVMFile::reset, (arg("self")), "Resets the current file so it starts reading from the begin once more") - .def("read", &svmfile_read, (arg("self")), "Reads a single line from the file and returns a tuple containing the label and a numpy array of float64 elements. The numpy array has a shape as defined by the 'shape' property of this file. If the file has finished, returns None instead.") - .def("read", &svmfile_read2, (arg("self"), arg("values")), "Reads a single line from the file, but in this variant you should pass the numpy array where the results of the readout will be stored. The array should have a shape that is identical to what is returned by the 'shape' property of this file or an error will be raised. Returns the label for the entry. If the file is finished, returns None instead.") - .def("read_", &svmfile_read2_, (arg("self"), arg("values")), "Reads a single line from the file and stores the contents of the line in the input array. Does not check the array shape. Returns the label for the entry. If the file is finished, returns None instead.") - .def("read_all", &svmfile_read_all, (arg("self")), "Reads all remaining entries in the file. Returns a tuple containing (label, values) tuples for each entry in the file, in order of appearance.") - .def("good", &bob::machine::SVMFile::good, (arg("self")), "Returns if the file is in a good state for readout. That means it has neither the eof, fail or bad bits set.") - .def("fail", &bob::machine::SVMFile::fail, (arg("self")), "Tells if the file has the fail or bad bit set") - .def("eof", &bob::machine::SVMFile::eof, (arg("self")), "Tells if the file has the eof bit set") - ; - - enum_<bob::machine::SupportVector::svm_t>("svm_type") - .value("C_SVC", bob::machine::SupportVector::C_SVC) - .value("NU_SVC", bob::machine::SupportVector::NU_SVC) - .value("ONE_CLASS", bob::machine::SupportVector::ONE_CLASS) - .value("EPSILON_SVR", bob::machine::SupportVector::EPSILON_SVR) - .value("NU_SVR", bob::machine::SupportVector::NU_SVR) - ; - - enum_<bob::machine::SupportVector::kernel_t>("svm_kernel_type") - .value("LINEAR", bob::machine::SupportVector::LINEAR) - .value("POLY", bob::machine::SupportVector::POLY) - .value("RBF", bob::machine::SupportVector::RBF) - .value("SIGMOID", bob::machine::SupportVector::SIGMOID) - .value("PRECOMPUTED", bob::machine::SupportVector::PRECOMPUTED) - ; - - class_<bob::machine::SupportVector, boost::shared_ptr<bob::machine::SupportVector>, boost::noncopyable>("SupportVector", "This class can load and run an SVM generated by libsvm. Libsvm is a simple, easy-to-use, and efficient software for SVM classification and regression. It solves C-SVM classification, nu-SVM classification, one-class-SVM, epsilon-SVM regression, and nu-SVM regression. It also provides an automatic model selection tool for C-SVM classification. More information about libsvm can be found on its `website <http://www.csie.ntu.edu.tw/~cjlin/libsvm/>`_. In particular, this class covers most of the functionality provided by the command-line utility svm-predict.", no_init) - .def(init<const char*>((arg("self"), arg("filename")), "Builds a new Support Vector Machine from a libsvm model file\n\nWhen you load using the libsvm model loader, note that the scaling parameters will be set to defaults (subtraction of 0.0 and division by 1.0). If you need scaling to be applied, set it individually using the appropriate methods bellow.")) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")), "Builds a new Support Vector Machine from an HDF5 file containing the configuration for this machine. Scaling parameters are also loaded from the file. Using this constructor assures a 100% state recovery from previous sessions.")) - .add_property("input_subtract", make_function(&bob::machine::SupportVector::getInputSubtraction, return_value_policy<copy_const_reference>()), &set_input_sub) - .add_property("input_divide", make_function(&bob::machine::SupportVector::getInputDivision, return_value_policy<copy_const_reference>()), &set_input_div) - .add_property("shape", &get_shape, "Expected input and output sizes. Note the output size is always 1.") - .add_property("labels", &labels, "The labels this machine will output.") - .add_property("svm_type", &bob::machine::SupportVector::machineType, "The type of SVM machine contained") - .add_property("kernel_type", &bob::machine::SupportVector::kernelType, "The type of kernel used by the support vectors in this machine") - .add_property("degree", &bob::machine::SupportVector::polynomialDegree, "The polinomial degree, only valid if the kernel is polynomial") - .add_property("gamma", &bob::machine::SupportVector::gamma, "The gamma parameter for polynomial, RBF (gaussian) or sigmoidal kernels") - .add_property("coef0", &bob::machine::SupportVector::coefficient0, "The coefficient 0 for polynomial or sigmoidal kernels") - .add_property("probability", &bob::machine::SupportVector::supportsProbability, "true if this machine supports probability outputs") - .def("predict_class", &predict_class, (arg("self"), arg("input")), "Returns the predicted class given a certain input. Checks the input data for size conformity. If the size is wrong, an exception is raised.") - .def("predict_class_", &predict_class_, (arg("self"), arg("input")), "Returns the predicted class given a certain input. Does not check the input data and is, therefore, a little bit faster.") - .def("predict_classes", &predict_class_n, (arg("self"), arg("input")), "Returns the predicted class given a certain input. Checks the input data for size conformity. If the size is wrong, an exception is raised. This variant accepts as input a 2D array with samples arranged in lines. The array can have as many lines as you want, but the number of columns should match the expected machine input size.") - .def("__call__", &svm_call, (arg("self"), arg("input")), "Returns the predicted class(es) given a certain input. Checks the input data for size conformity. If the size is wrong, an exception is raised. The input may be either a 1D or a 2D numpy ndarray object of double-precision floating-point numbers. If the array is 1D, a single answer is returned (the class of the input vector). If the array is 2D, then the number of columns in such array must match the input size. In this case, the SupportVector object will return 1 prediction for every row at the input array.") - .def("predict_class_and_scores", &predict_class_and_scores2, (arg("self"), arg("input")), "Returns the predicted class and output scores as a tuple, in this order. Checks the input and output arrays for size conformity. In particular, the size of the output array should be, if ``o`` is the number of classes the machine can treat, :math:`o*(o-1)/2`. The order, as the ``libsvm`` README points out, is label[0] vs label[1], ..., label[0] vs. label[o-1], label[1] vs. label[2], ... label[o-2] vs label[o-1]. Note that when :math:`o = 1`, this function does not give any decision value. If the size is wrong, an exception is raised.") - .def("predict_class_and_scores", &predict_class_and_scores, (arg("self"), arg("input"), arg("scores")), "Returns the predicted class given a certain input. Returns the scores for each class in the second argument. Checks the input and output arrays for size conformity. In particular, the size of the output array should be, if ``o`` is the number of classes the machine can treat, :math:`o*(o-1)/2`. The order, as the ``libsvm`` README points out, is label[0] vs label[1], ..., label[0] vs. label[o-1], label[1] vs. label[2], ... label[o-2] vs label[o-1]. Note that when :math:`o = 1`, this function does not give any decision value. If the size is wrong, an exception is raised.") - .def("predict_class_and_scores_", &predict_class_and_scores_, (arg("self"), arg("input"), arg("scores")), "Returns the predicted class given a certain input. Returns the scores for each class in the second argument. Checks the input and output arrays for size conformity. Does not check the input data and is, therefore, a little bit faster.") - .def("predict_classes_and_scores", &predict_class_and_scores_n, (arg("self"), arg("input")), "Returns the predicted class and output scores as a tuple, in this order. Checks the input array for size conformity. In particular, the size of the output array should be, if ``o`` is the number of classes the machine can treat, :math:`o*(o-1)/2`. The order, as the ``libsvm`` README points out, is label[0] vs label[1], ..., label[0] vs. label[o-1], label[1] vs. label[2], ... label[o-2] vs label[o-1]. Note that when :math:`o = 1`, this function does not give any decision value. If the size is wrong, an exception is raised. This variant takes a single 2D double array as input. The samples should be organized row-wise.") - .def("predict_class_and_probabilities", &predict_class_and_probs2, (arg("self"), arg("input")), "Returns the predicted class and probabilities in a tuple (on that order) given a certain input. The current machine has to support probabilities, otherwise an exception is raised. Checks the input array for size conformity. If the size is wrong, an exception is raised.") - .def("predict_class_and_probabilities", &predict_class_and_probs, (arg("self"), arg("input"), arg("probabilities")), "Returns the predicted class given a certain input. If the model supports it, returns the probabilities for each class in the second argument, otherwise raises an exception. Checks the input and output arrays for size conformity. If the size is wrong, an exception is raised.") - .def("predict_class_and_probabilities_", &predict_class_and_probs_, (arg("self"), arg("input"), arg("probabilities")), "Returns the predicted class given a certain input. This version will not run any checks, so you must be sure to pass the correct input to the classifier.") - .def("predict_classes_and_probabilities", &predict_class_and_probs_n, (arg("self"), arg("input")), "Returns the predicted class and output probabilities for each possible class as a tuple, in this order. Checks the input array for size conformity. If the size is wrong, an exception is raised. This variant takes a single 2D double array as input. The samples should be organized row-wise.") - .def("save", (void (bob::machine::SupportVector::*)(const std::string&) const)&bob::machine::SupportVector::save, (arg("self"), arg("filename")), "Saves the currently loaded model to an output file. Overwrites the file, if necessary") - .def("save", (void (bob::machine::SupportVector::*)(bob::io::HDF5File&) const)&bob::machine::SupportVector::save, (arg("self"), arg("config")), "Saves the whole machine into a configuration file. This allows for a single instruction parameter loading, which includes both the model and the scaling parameters.") - ; -} diff --git a/xbob/machine/tanh_activation.cpp b/xbob/machine/tanh_activation.cpp deleted file mode 100644 index f121057..0000000 --- a/xbob/machine/tanh_activation.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Mon 13 Jan 2014 17:25:32 CET - * - * @brief Implementation of the HyperbolicTangent Activation function - */ - -#define XBOB_MACHINE_MODULE -#include <xbob.machine/api.h> - -PyDoc_STRVAR(s_hyperbolictangentactivation_str, - XBOB_EXT_MODULE_PREFIX ".HyperbolicTangentActivation"); - -PyDoc_STRVAR(s_hyperbolictangentactivation_doc, -"HyperbolicTangentActivation() -> new HyperbolicTangentActivation\n\ -\n\ -Computes :math:`f(z) = \\tanh(z)` as activation function.\n\ -\n\ -"); - -static int PyBobMachineHyperbolicTangentActivation_init -(PyBobMachineHyperbolicTangentActivationObject* self, - PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - static const char* const_kwlist[] = {0}; - static char** kwlist = const_cast<char**>(const_kwlist); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) return -1; - - try { - self->base = new bob::machine::HyperbolicTangentActivation(); - } - catch (std::exception& ex) { - PyErr_SetString(PyExc_RuntimeError, ex.what()); - } - catch (...) { - PyErr_Format(PyExc_RuntimeError, "cannot create new object of type `%s' - unknown exception thrown", s_hyperbolictangentactivation_str); - } - - self->parent.base = self->base; - - if (PyErr_Occurred()) return -1; - - return 0; - -} - -static void PyBobMachineHyperbolicTangentActivation_delete -(PyBobMachineHyperbolicTangentActivationObject* self) { - - delete self->base; - self->parent.base = 0; - self->base = 0; - self->parent.ob_type->tp_free((PyObject*)self); - -} - -PyTypeObject PyBobMachineHyperbolicTangentActivation_Type = { - PyObject_HEAD_INIT(0) - 0, /*ob_size*/ - s_hyperbolictangentactivation_str, /*tp_name*/ - sizeof(PyBobMachineHyperbolicTangentActivationObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)PyBobMachineHyperbolicTangentActivation_delete, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - s_hyperbolictangentactivation_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)PyBobMachineHyperbolicTangentActivation_init, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; diff --git a/xbob/machine/test_gaussian.py b/xbob/machine/test_gaussian.py deleted file mode 100644 index c4b8cc7..0000000 --- a/xbob/machine/test_gaussian.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Laurent El Shafey <Laurent.El-Shafey@idiap.ch> -# Thu Feb 16 16:54:45 2012 +0200 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Tests the Gaussian machine -""" - -import os, sys -import unittest -import bob -import numpy -import tempfile - -def equals(x, y, epsilon): - return (abs(x - y) < epsilon) - -class GaussianMachineTest(unittest.TestCase): - """Performs various Gaussian machine tests.""" - - def test01_GaussianNormal(self): - # Test the likelihood computation of a simple normal Gaussian - gaussian = bob.machine.Gaussian(2) - # By default, initialized with zero mean and unit variance - logLH = gaussian.log_likelihood(numpy.array([0.4, 0.2], 'float64')) - self.assertTrue( equals(logLH, -1.93787706641, 1e-10)) - - def test02_GaussianMachine(self): - # Test a GaussianMachine more thoroughly - - # Initializes a Gaussian with zero mean and unit variance - g = bob.machine.Gaussian(3) - self.assertTrue( (g.mean == 0.0).all() ) - self.assertTrue( (g.variance == 1.0).all() ) - self.assertTrue( g.dim_d == 3 ) - - # Set and check mean, variance, variance thresholds - mean = numpy.array([0, 1, 2], 'float64') - variance = numpy.array([3, 2, 1], 'float64') - g.mean = mean - g.variance = variance - g.set_variance_thresholds(0.0005) - self.assertTrue( (g.mean == mean).all() ) - self.assertTrue( (g.variance == variance).all() ) - self.assertTrue( (g.variance_thresholds == 0.0005).all() ) - - # Save and read from file - filename = str(tempfile.mkstemp(".hdf5")[1]) - g.save(bob.io.HDF5File(filename, 'w')) - g_loaded = bob.machine.Gaussian(bob.io.HDF5File(filename)) - self.assertTrue( g == g_loaded ) - self.assertFalse( g != g_loaded ) - self.assertTrue(g.is_similar_to(g_loaded)) - # Make them different - g_loaded.set_variance_thresholds(0.001) - self.assertFalse( g == g_loaded ) - self.assertTrue( g != g_loaded ) - - # Check likelihood computation - sample1 = numpy.array([0, 1, 2], 'float64') - sample2 = numpy.array([1, 2, 3], 'float64') - sample3 = numpy.array([2, 3, 4], 'float64') - ref1 = -3.652695334228046 - ref2 = -4.569362000894712 - ref3 = -7.319362000894712 - eps = 1e-10 - self.assertTrue( equals(g.log_likelihood(sample1), ref1, eps) ) - self.assertTrue( equals(g.forward(sample1), ref1, eps) ) - self.assertTrue( equals(g.log_likelihood(sample2), ref2, eps) ) - self.assertTrue( equals(g.forward(sample2), ref2, eps) ) - self.assertTrue( equals(g.log_likelihood(sample3), ref3, eps) ) - self.assertTrue( equals(g.forward(sample3), ref3, eps) ) - - # Check resize and assignment - g.shape = (6,) - self.assertTrue( g.shape == (6,) ) - g.resize(5) - self.assertTrue( g.dim_d == 5 ) - g2 = bob.machine.Gaussian() - g2 = g - self.assertTrue( g == g2 ) - self.assertFalse( g != g2 ) - g3 = bob.machine.Gaussian(g) - self.assertTrue( g == g3 ) - self.assertFalse( g != g3 ) - - # Clean-up - os.unlink(filename) diff --git a/xbob/machine/test_gmm.py b/xbob/machine/test_gmm.py deleted file mode 100644 index a951723..0000000 --- a/xbob/machine/test_gmm.py +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Laurent El Shafey <Laurent.El-Shafey@idiap.ch> -# Thu Feb 16 17:57:10 2012 +0200 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Tests the GMM machine and the GMMStats container -""" - -import os, sys -import unittest -import bob -import numpy -import tempfile -import pkg_resources - -def F(f): - """Returns the test file on the "data" subdirectory""" - return pkg_resources.resource_filename(__name__, os.path.join('data', f)) - -class GMMMachineTest(unittest.TestCase): - """Performs various GMM machine-related tests.""" - - def test01_GMMStats(self): - # Test a GMMStats - - # Initializes a GMMStats - gs = bob.machine.GMMStats(2,3) - log_likelihood = -3. - T = 57 - n = numpy.array([4.37, 5.31], 'float64') - sumpx = numpy.array([[1., 2., 3.], [4., 5., 6.]], 'float64') - sumpxx = numpy.array([[10., 20., 30.], [40., 50., 60.]], 'float64') - gs.log_likelihood = log_likelihood - gs.t = T - gs.n = n - gs.sum_px = sumpx - gs.sum_pxx = sumpxx - self.assertTrue( gs.log_likelihood == log_likelihood ) - self.assertTrue( gs.t == T ) - self.assertTrue( (gs.n == n).all() ) - self.assertTrue( (gs.sum_px == sumpx).all() ) - self.assertTrue( (gs.sum_pxx == sumpxx).all() ) - - # Saves and reads from file - filename = str(tempfile.mkstemp(".hdf5")[1]) - gs.save(bob.io.HDF5File(filename, 'w')) - gs_loaded = bob.machine.GMMStats(bob.io.HDF5File(filename)) - self.assertTrue( gs == gs_loaded ) - self.assertFalse( gs != gs_loaded ) - self.assertTrue( gs.is_similar_to(gs_loaded) ) - # Makes them different - gs_loaded.t = 58 - self.assertFalse( gs == gs_loaded ) - self.assertTrue( gs != gs_loaded ) - self.assertFalse( gs.is_similar_to(gs_loaded) ) - # Accumulates from another GMMStats - gs2 = bob.machine.GMMStats(2,3) - gs2.log_likelihood = log_likelihood - gs2.t = T - gs2.n = n - gs2.sum_px = sumpx - gs2.sum_pxx = sumpxx - gs2 += gs - eps = 1e-8 - self.assertTrue( gs2.log_likelihood == 2*log_likelihood ) - self.assertTrue( gs2.t == 2*T ) - self.assertTrue( numpy.allclose(gs2.n, 2*n, eps) ) - self.assertTrue( numpy.allclose(gs2.sum_px, 2*sumpx, eps) ) - self.assertTrue( numpy.allclose(gs2.sum_pxx, 2*sumpxx, eps) ) - - # Reinit and checks for zeros - gs_loaded.init() - self.assertTrue( gs_loaded.log_likelihood == 0 ) - self.assertTrue( gs_loaded.t == 0 ) - self.assertTrue( (gs_loaded.n == 0).all() ) - self.assertTrue( (gs_loaded.sum_px == 0).all() ) - self.assertTrue( (gs_loaded.sum_pxx == 0).all() ) - # Resize and checks size - gs_loaded.resize(4,5) - self.assertTrue( gs_loaded.sum_px.shape[0] == 4) - self.assertTrue( gs_loaded.sum_px.shape[1] == 5) - - # Clean-up - os.unlink(filename) - - def test02_GMMMachine(self): - # Test a GMMMachine basic features - - weights = numpy.array([0.5, 0.5], 'float64') - weights2 = numpy.array([0.6, 0.4], 'float64') - means = numpy.array([[3, 70, 0], [4, 72, 0]], 'float64') - means2 = numpy.array([[3, 7, 0], [4, 72, 0]], 'float64') - variances = numpy.array([[1, 10, 1], [2, 5, 2]], 'float64') - variances2 = numpy.array([[10, 10, 1], [2, 5, 2]], 'float64') - varianceThresholds = numpy.array([[0, 0, 0], [0, 0, 0]], 'float64') - varianceThresholds2 = numpy.array([[0.0005, 0.0005, 0.0005], [0, 0, 0]], 'float64') - - # Initializes a GMMMachine - gmm = bob.machine.GMMMachine(2,3) - # Sets the weights, means, variances and varianceThresholds and - # Checks correctness - gmm.weights = weights - gmm.means = means - gmm.variances = variances - gmm.varianceThresholds = varianceThresholds - self.assertTrue( gmm.dim_c == 2 ) - self.assertTrue( gmm.dim_d == 3 ) - self.assertTrue( (gmm.weights == weights).all() ) - self.assertTrue( (gmm.means == means).all() ) - self.assertTrue( (gmm.variances == variances).all() ) - self.assertTrue( (gmm.variance_thresholds == varianceThresholds).all() ) - - # Checks supervector-like accesses - self.assertTrue( (gmm.mean_supervector == means.reshape(means.size)).all() ) - self.assertTrue( (gmm.variance_supervector == variances.reshape(variances.size)).all() ) - newMeans = numpy.array([[3, 70, 2], [4, 72, 2]], 'float64') - newVariances = numpy.array([[1, 1, 1], [2, 2, 2]], 'float64') - gmm.mean_supervector = newMeans.reshape(newMeans.size) - gmm.variance_supervector = newVariances.reshape(newVariances.size) - self.assertTrue( (gmm.mean_supervector == newMeans.reshape(newMeans.size)).all() ) - self.assertTrue( (gmm.variance_supervector == newVariances.reshape(newVariances.size)).all() ) - - # Checks particular varianceThresholds-related methods - varianceThresholds1D = numpy.array([0.3, 1, 0.5], 'float64') - gmm.set_variance_thresholds(varianceThresholds1D) - self.assertTrue( (gmm.variance_thresholds[0,:] == varianceThresholds1D).all() ) - self.assertTrue( (gmm.variance_thresholds[1,:] == varianceThresholds1D).all() ) - gmm.set_variance_thresholds(0.005) - self.assertTrue( (gmm.variance_thresholds == 0.005).all() ) - - # Checks Gaussians access - self.assertTrue( (gmm.update_gaussian(0).mean == newMeans[0,:]).all() ) - self.assertTrue( (gmm.update_gaussian(1).mean == newMeans[1,:]).all() ) - self.assertTrue( (gmm.update_gaussian(0).variance == newVariances[0,:]).all() ) - self.assertTrue( (gmm.update_gaussian(1).variance == newVariances[1,:]).all() ) - - # Checks resize - gmm.shape = (5,6) - self.assertTrue( gmm.shape == (5,6) ) - gmm.resize(4,5) - self.assertTrue( gmm.dim_c == 4 ) - self.assertTrue( gmm.dim_d == 5 ) - - # Checks comparison - gmm2 = bob.machine.GMMMachine(gmm) - gmm3 = bob.machine.GMMMachine(2,3) - gmm3.weights = weights2 - gmm3.means = means - gmm3.variances = variances - gmm3.varianceThresholds = varianceThresholds - gmm4 = bob.machine.GMMMachine(2,3) - gmm4.weights = weights - gmm4.means = means2 - gmm4.variances = variances - gmm4.varianceThresholds = varianceThresholds - gmm5 = bob.machine.GMMMachine(2,3) - gmm5.weights = weights - gmm5.means = means - gmm5.variances = variances2 - gmm5.varianceThresholds = varianceThresholds - gmm6 = bob.machine.GMMMachine(2,3) - gmm6.weights = weights - gmm6.means = means - gmm6.variances = variances - gmm6.varianceThresholds = varianceThresholds2 - - self.assertTrue( gmm == gmm2) - self.assertFalse( gmm != gmm2) - self.assertTrue( gmm.is_similar_to(gmm2) ) - self.assertTrue( gmm != gmm3) - self.assertFalse( gmm == gmm3) - self.assertFalse( gmm.is_similar_to(gmm3) ) - self.assertTrue( gmm != gmm4) - self.assertFalse( gmm == gmm4) - self.assertFalse( gmm.is_similar_to(gmm4) ) - self.assertTrue( gmm != gmm5) - self.assertFalse( gmm == gmm5) - self.assertFalse( gmm.is_similar_to(gmm5) ) - self.assertTrue( gmm != gmm6) - self.assertFalse( gmm == gmm6) - self.assertFalse( gmm.is_similar_to(gmm6) ) - - def test03_GMMMachine(self): - # Test a GMMMachine (statistics) - - arrayset = bob.io.load(F("faithful.torch3_f64.hdf5")) - gmm = bob.machine.GMMMachine(2, 2) - gmm.weights = numpy.array([0.5, 0.5], 'float64') - gmm.means = numpy.array([[3, 70], [4, 72]], 'float64') - gmm.variances = numpy.array([[1, 10], [2, 5]], 'float64') - gmm.variance_thresholds = numpy.array([[0, 0], [0, 0]], 'float64') - - stats = bob.machine.GMMStats(2, 2) - gmm.acc_statistics(arrayset, stats) - - stats_ref = bob.machine.GMMStats(bob.io.HDF5File(F("stats.hdf5"))) - - self.assertTrue(stats.t == stats_ref.t) - self.assertTrue( numpy.allclose(stats.n, stats_ref.n, atol=1e-10) ) - #self.assertTrue( numpy.array_equal(stats.sumPx, stats_ref.sumPx) ) - #Note AA: precision error above - self.assertTrue ( numpy.allclose(stats.sum_px, stats_ref.sum_px, atol=1e-10) ) - self.assertTrue( numpy.allclose(stats.sum_pxx, stats_ref.sum_pxx, atol=1e-10) ) - - def test04_GMMMachine(self): - # Test a GMMMachine (log-likelihood computation) - - data = bob.io.load(F('data.hdf5')) - gmm = bob.machine.GMMMachine(2, 50) - gmm.weights = bob.io.load(F('weights.hdf5')) - gmm.means = bob.io.load(F('means.hdf5')) - gmm.variances = bob.io.load(F('variances.hdf5')) - - # Compare the log-likelihood with the one obtained using Chris Matlab - # implementation - matlab_ll_ref = -2.361583051672024e+02 - self.assertTrue( abs(gmm(data) - matlab_ll_ref) < 1e-10) diff --git a/xbob/machine/test_ivector.py b/xbob/machine/test_ivector.py deleted file mode 100644 index eaa6506..0000000 --- a/xbob/machine/test_ivector.py +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Laurent El Shafey <Laurent.El-Shafey@idiap.ch> -# Mon Apr 2 11:19:00 2013 +0200 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - - -"""Tests the I-Vector machine -""" - -import unittest -import bob, numpy, numpy.linalg, numpy.random - - -### Test class inspired by an implementation of Chris McCool -### Chris McCool (chris.mccool@nicta.com.au) -class IVectorMachinePy(): - """An IVector extractor""" - - def __init__(self, ubm=None, dim_t=1): - # Our state - self.m_ubm = ubm - self.m_dim_t = dim_t - # Resize the matrices T and sigma - self.resize() - # Precompute - self.precompute() - - def resize(self): - if self.m_ubm: - dim_cd = self.m_ubm.dim_c * self.m_ubm.dim_d - self.m_t = numpy.random.randn(dim_cd, self.m_dim_t) - self.m_sigma = numpy.random.randn(dim_cd) - - def precompute(self): - if self.m_ubm and not (self.m_t == None) and not (self.m_sigma == None): - dim_c = self.m_ubm.dim_c - dim_d = self.m_ubm.dim_d - self.m_cache_TtSigmaInv = {} - self.m_cache_TtSigmaInvT = {} - for c in range(dim_c): - start = c*dim_d - end = (c+1)*dim_d - Tc = self.m_t[start:end,:] - self.m_cache_TtSigmaInv[c] = Tc.transpose() / self.m_sigma[start:end] - self.m_cache_TtSigmaInvT[c] = numpy.dot(self.m_cache_TtSigmaInv[c], Tc); - - def set_ubm(self, ubm): - self.m_ubm = ubm - # Precompute - self.precompute() - - def get_ubm(self): - return self.m_ubm - - def set_t(self, t): - # @warning: no dimensions check - self.m_t = t - # Precompute - self.precompute() - - def get_t(self): - return self.m_t - - def set_sigma(self, sigma): - # @warning: no dimensions check - self.m_sigma = sigma - # Precompute - self.precompute() - - def get_sigma(self): - return self.m_sigma - - - def _get_TtSigmaInv_Fnorm(self, N, F): - # Initialization - dim_c = self.m_ubm.dim_c - dim_d = self.m_ubm.dim_d - mean_supervector = self.m_ubm.mean_supervector - TtSigmaInv_Fnorm = numpy.zeros(shape=(self.m_dim_t,), dtype=numpy.float64) - - # Loop over each Gaussian component - dim_c = self.m_ubm.dim_c - for c in range(dim_c): - start = c*dim_d - end = (c+1)*dim_d - Fnorm = F[c,:] - N[c] * mean_supervector[start:end] - TtSigmaInv_Fnorm = TtSigmaInv_Fnorm + numpy.dot(self.m_cache_TtSigmaInv[c], Fnorm) - return TtSigmaInv_Fnorm - - def _get_I_TtSigmaInvNT(self, N): - # Initialization - dim_c = self.m_ubm.dim_c - dim_d = self.m_ubm.dim_d - - TtSigmaInvNT = numpy.eye(self.m_dim_t, dtype=numpy.float64) - for c in range(dim_c): - TtSigmaInvNT = TtSigmaInvNT + self.m_cache_TtSigmaInvT[c] * N[c] - - return TtSigmaInvNT - - def forward(self, gmmstats): - if self.m_ubm and not (self.m_t == None) and not (self.m_sigma == None): - N = gmmstats.n - F = gmmstats.sum_px - - TtSigmaInv_Fnorm = self._get_TtSigmaInv_Fnorm(N, F) - TtSigmaInvNT = self._get_I_TtSigmaInvNT(N) - - return numpy.linalg.solve(TtSigmaInvNT, TtSigmaInv_Fnorm) - - - -class IVectorTests(unittest.TestCase): - - def test01_machine(self): - # Ubm - ubm = bob.machine.GMMMachine(2,3) - ubm.weights = numpy.array([0.4,0.6]) - ubm.means = numpy.array([[1.,7,4],[4,5,3]]) - ubm.variances = numpy.array([[0.5,1.,1.5],[1.,1.5,2.]]) - - # Defines GMMStats - gs = bob.machine.GMMStats(2,3) - log_likelihood = -3. - T = 1 - n = numpy.array([0.4, 0.6], numpy.float64) - sumpx = numpy.array([[1., 2., 3.], [2., 4., 3.]], numpy.float64) - sumpxx = numpy.array([[10., 20., 30.], [40., 50., 60.]], numpy.float64) - gs.log_likelihood = log_likelihood - gs.t = T - gs.n = n - gs.sum_px = sumpx - gs.sum_pxx = sumpxx - - # IVector (Python) - m = IVectorMachinePy(ubm, 2) - t = numpy.array([[1.,2],[4,1],[0,3],[5,8],[7,10],[11,1]]) - m.set_t(t) - sigma = numpy.array([1.,2.,1.,3.,2.,4.]) - m.set_sigma(sigma) - - wij_ref = numpy.array([-0.04213415, 0.21463343]) # Reference from original Chris implementation - wij = m.forward(gs) - self.assertTrue(numpy.allclose(wij_ref, wij, 1e-5)) - - # IVector (C++) - mc = bob.machine.IVectorMachine(ubm, 2) - mc.t = t - mc.sigma = sigma - - wij_ref = numpy.array([-0.04213415, 0.21463343]) # Reference from original Chris implementation - wij = mc.forward(gs) - self.assertTrue(numpy.allclose(wij_ref, wij, 1e-5)) - diff --git a/xbob/machine/test_jfa.py b/xbob/machine/test_jfa.py deleted file mode 100644 index a71579c..0000000 --- a/xbob/machine/test_jfa.py +++ /dev/null @@ -1,374 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Laurent El Shafey <Laurent.El-Shafey@idiap.ch> -# Wed Feb 15 23:24:35 2012 +0200 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Tests on the JFA-based machines -""" - -import os, sys -import unittest -import math -import bob -import numpy, numpy.linalg -import tempfile - -def estimate_x(dim_c, dim_d, mean, sigma, U, N, F): - # Compute helper values - UtSigmaInv = {} - UtSigmaInvU = {} - dim_ru = U.shape[1] - for c in range(dim_c): - start = c*dim_d - end = (c+1)*dim_d - Uc = U[start:end,:] - UtSigmaInv[c] = Uc.transpose() / sigma[start:end] - UtSigmaInvU[c] = numpy.dot(UtSigmaInv[c], Uc); - - # I + (U^{T} \Sigma^-1 N U) - I_UtSigmaInvNU = numpy.eye(dim_ru, dtype=numpy.float64) - for c in range(dim_c): - I_UtSigmaInvNU = I_UtSigmaInvNU + UtSigmaInvU[c] * N[c] - - # U^{T} \Sigma^-1 F - UtSigmaInv_Fnorm = numpy.zeros((dim_ru,), numpy.float64) - for c in range(dim_c): - start = c*dim_d - end = (c+1)*dim_d - Fnorm = F[c,:] - N[c] * mean[start:end] - UtSigmaInv_Fnorm = UtSigmaInv_Fnorm + numpy.dot(UtSigmaInv[c], Fnorm) - - return numpy.linalg.solve(I_UtSigmaInvNU, UtSigmaInv_Fnorm) - -def estimate_ux(dim_c, dim_d, mean, sigma, U, N, F): - return numpy.dot(U, estimate_x(dim_c, dim_d, mean, sigma, U, N, F)) - - -class FATest(unittest.TestCase): - """Performs various FA tests.""" - - def test01_JFABase(self): - - # Creates a UBM - weights = numpy.array([0.4, 0.6], 'float64') - means = numpy.array([[1, 6, 2], [4, 3, 2]], 'float64') - variances = numpy.array([[1, 2, 1], [2, 1, 2]], 'float64') - ubm = bob.machine.GMMMachine(2,3) - ubm.weights = weights - ubm.means = means - ubm.variances = variances - - # Creates a JFABase - U = numpy.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]], 'float64') - V = numpy.array([[6, 5], [4, 3], [2, 1], [1, 2], [3, 4], [5, 6]], 'float64') - d = numpy.array([0, 1, 0, 1, 0, 1], 'float64') - m = bob.machine.JFABase(ubm) - self.assertTrue( m.dim_ru == 1) - self.assertTrue( m.dim_rv == 1) - - # Checks for correctness - m.resize(2,2) - m.u = U - m.v = V - m.d = d - self.assertTrue( (m.u == U).all() ) - self.assertTrue( (m.v == V).all() ) - self.assertTrue( (m.d == d).all() ) - self.assertTrue( m.dim_c == 2) - self.assertTrue( m.dim_d == 3) - self.assertTrue( m.dim_cd == 6) - self.assertTrue( m.dim_ru == 2) - self.assertTrue( m.dim_rv == 2) - - # Saves and loads - filename = str(tempfile.mkstemp(".hdf5")[1]) - m.save(bob.io.HDF5File(filename, 'w')) - m_loaded = bob.machine.JFABase(bob.io.HDF5File(filename)) - m_loaded.ubm = ubm - self.assertTrue( m == m_loaded ) - self.assertFalse( m != m_loaded ) - self.assertTrue( m.is_similar_to(m_loaded) ) - - # Copy constructor - mc = bob.machine.JFABase(m) - self.assertTrue( m == mc ) - - # Variant - mv = bob.machine.JFABase() - # Checks for correctness - mv.ubm = ubm - mv.resize(2,2) - mv.u = U - mv.v = V - mv.d = d - self.assertTrue( (m.u == U).all() ) - self.assertTrue( (m.v == V).all() ) - self.assertTrue( (m.d == d).all() ) - self.assertTrue( m.dim_c == 2) - self.assertTrue( m.dim_d == 3) - self.assertTrue( m.dim_cd == 6) - self.assertTrue( m.dim_ru == 2) - self.assertTrue( m.dim_rv == 2) - - # Clean-up - os.unlink(filename) - - def test02_ISVBase(self): - - # Creates a UBM - weights = numpy.array([0.4, 0.6], 'float64') - means = numpy.array([[1, 6, 2], [4, 3, 2]], 'float64') - variances = numpy.array([[1, 2, 1], [2, 1, 2]], 'float64') - ubm = bob.machine.GMMMachine(2,3) - ubm.weights = weights - ubm.means = means - ubm.variances = variances - - # Creates a ISVBase - U = numpy.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]], 'float64') - d = numpy.array([0, 1, 0, 1, 0, 1], 'float64') - m = bob.machine.ISVBase(ubm) - self.assertTrue( m.dim_ru == 1) - - # Checks for correctness - m.resize(2) - m.u = U - m.d = d - self.assertTrue( (m.u == U).all() ) - self.assertTrue( (m.d == d).all() ) - self.assertTrue( m.dim_c == 2) - self.assertTrue( m.dim_d == 3) - self.assertTrue( m.dim_cd == 6) - self.assertTrue( m.dim_ru == 2) - - # Saves and loads - filename = str(tempfile.mkstemp(".hdf5")[1]) - m.save(bob.io.HDF5File(filename, 'w')) - m_loaded = bob.machine.ISVBase(bob.io.HDF5File(filename)) - m_loaded.ubm = ubm - self.assertTrue( m == m_loaded ) - self.assertFalse( m != m_loaded ) - self.assertTrue( m.is_similar_to(m_loaded) ) - - # Copy constructor - mc = bob.machine.ISVBase(m) - self.assertTrue( m == mc ) - - # Variant - mv = bob.machine.ISVBase() - # Checks for correctness - mv.ubm = ubm - mv.resize(2) - mv.u = U - mv.d = d - self.assertTrue( (m.u == U).all() ) - self.assertTrue( (m.d == d).all() ) - self.assertTrue( m.dim_c == 2) - self.assertTrue( m.dim_d == 3) - self.assertTrue( m.dim_cd == 6) - self.assertTrue( m.dim_ru == 2) - - # Clean-up - os.unlink(filename) - - def test03_JFAMachine(self): - - # Creates a UBM - weights = numpy.array([0.4, 0.6], 'float64') - means = numpy.array([[1, 6, 2], [4, 3, 2]], 'float64') - variances = numpy.array([[1, 2, 1], [2, 1, 2]], 'float64') - ubm = bob.machine.GMMMachine(2,3) - ubm.weights = weights - ubm.means = means - ubm.variances = variances - - # Creates a JFABase - U = numpy.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]], 'float64') - V = numpy.array([[6, 5], [4, 3], [2, 1], [1, 2], [3, 4], [5, 6]], 'float64') - d = numpy.array([0, 1, 0, 1, 0, 1], 'float64') - base = bob.machine.JFABase(ubm,2,2) - base.u = U - base.v = V - base.d = d - - # Creates a JFAMachine - y = numpy.array([1,2], 'float64') - z = numpy.array([3,4,1,2,0,1], 'float64') - m = bob.machine.JFAMachine(base) - m.y = y - m.z = z - self.assertTrue( m.dim_c == 2) - self.assertTrue( m.dim_d == 3) - self.assertTrue( m.dim_cd == 6) - self.assertTrue( m.dim_ru == 2) - self.assertTrue( m.dim_rv == 2) - self.assertTrue( (m.y == y).all() ) - self.assertTrue( (m.z == z).all() ) - - # Saves and loads - filename = str(tempfile.mkstemp(".hdf5")[1]) - m.save(bob.io.HDF5File(filename, 'w')) - m_loaded = bob.machine.JFAMachine(bob.io.HDF5File(filename)) - m_loaded.jfa_base = base - self.assertTrue( m == m_loaded ) - self.assertFalse( m != m_loaded ) - self.assertTrue(m.is_similar_to(m_loaded)) - - # Copy constructor - mc = bob.machine.JFAMachine(m) - self.assertTrue( m == mc ) - - # Variant - mv = bob.machine.JFAMachine() - # Checks for correctness - mv.jfa_base = base - m.y = y - m.z = z - self.assertTrue( m.dim_c == 2) - self.assertTrue( m.dim_d == 3) - self.assertTrue( m.dim_cd == 6) - self.assertTrue( m.dim_ru == 2) - self.assertTrue( m.dim_rv == 2) - self.assertTrue( (m.y == y).all() ) - self.assertTrue( (m.z == z).all() ) - - # Defines GMMStats - gs = bob.machine.GMMStats(2,3) - log_likelihood = -3. - T = 1 - n = numpy.array([0.4, 0.6], 'float64') - sumpx = numpy.array([[1., 2., 3.], [4., 5., 6.]], 'float64') - sumpxx = numpy.array([[10., 20., 30.], [40., 50., 60.]], 'float64') - gs.log_likelihood = log_likelihood - gs.t = T - gs.n = n - gs.sum_px = sumpx - gs.sum_pxx = sumpxx - - # Forward GMMStats and check estimated value of the x speaker factor - eps = 1e-10 - x_ref = numpy.array([0.291042849767692, 0.310273618998444], 'float64') - score_ref = -2.111577181208289 - score = m.forward(gs) - self.assertTrue( numpy.allclose(m.__x__, x_ref, eps) ) - self.assertTrue( abs(score_ref-score) < eps ) - - # x and Ux - x = numpy.ndarray((2,), numpy.float64) - m.estimate_x(gs, x) - x_py = estimate_x(m.dim_c, m.dim_d, ubm.mean_supervector, ubm.variance_supervector, U, n, sumpx) - self.assertTrue( numpy.allclose(x, x_py, eps)) - - ux = numpy.ndarray((6,), numpy.float64) - m.estimate_ux(gs, ux) - ux_py = estimate_ux(m.dim_c, m.dim_d, ubm.mean_supervector, ubm.variance_supervector, U, n, sumpx) - self.assertTrue( numpy.allclose(ux, ux_py, eps)) - self.assertTrue( numpy.allclose(m.__x__, x, eps) ) - - score = m.forward_ux(gs, ux) - self.assertTrue( abs(score_ref-score) < eps ) - - # Clean-up - os.unlink(filename) - - def test04_ISVMachine(self): - - # Creates a UBM - weights = numpy.array([0.4, 0.6], 'float64') - means = numpy.array([[1, 6, 2], [4, 3, 2]], 'float64') - variances = numpy.array([[1, 2, 1], [2, 1, 2]], 'float64') - ubm = bob.machine.GMMMachine(2,3) - ubm.weights = weights - ubm.means = means - ubm.variances = variances - - # Creates a JFABaseMachine - U = numpy.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]], 'float64') - V = numpy.array([[0], [0], [0], [0], [0], [0]], 'float64') - d = numpy.array([0, 1, 0, 1, 0, 1], 'float64') - base = bob.machine.ISVBase(ubm,2) - base.u = U - base.v = V - base.d = d - - # Creates a JFAMachine - z = numpy.array([3,4,1,2,0,1], 'float64') - m = bob.machine.ISVMachine(base) - m.z = z - self.assertTrue( m.dim_c == 2) - self.assertTrue( m.dim_d == 3) - self.assertTrue( m.dim_cd == 6) - self.assertTrue( m.dim_ru == 2) - self.assertTrue( (m.z == z).all() ) - - # Saves and loads - filename = str(tempfile.mkstemp(".hdf5")[1]) - m.save(bob.io.HDF5File(filename, 'w')) - m_loaded = bob.machine.ISVMachine(bob.io.HDF5File(filename)) - m_loaded.isv_base = base - self.assertTrue( m == m_loaded ) - self.assertFalse( m != m_loaded ) - self.assertTrue(m.is_similar_to(m_loaded)) - - # Copy constructor - mc = bob.machine.ISVMachine(m) - self.assertTrue( m == mc ) - - # Variant - mv = bob.machine.ISVMachine() - # Checks for correctness - mv.isv_base = base - m.z = z - self.assertTrue( m.dim_c == 2) - self.assertTrue( m.dim_d == 3) - self.assertTrue( m.dim_cd == 6) - self.assertTrue( m.dim_ru == 2) - self.assertTrue( (m.z == z).all() ) - - # Defines GMMStats - gs = bob.machine.GMMStats(2,3) - log_likelihood = -3. - T = 1 - n = numpy.array([0.4, 0.6], 'float64') - sumpx = numpy.array([[1., 2., 3.], [4., 5., 6.]], 'float64') - sumpxx = numpy.array([[10., 20., 30.], [40., 50., 60.]], 'float64') - gs.log_likelihood = log_likelihood - gs.t = T - gs.n = n - gs.sum_px = sumpx - gs.sum_pxx = sumpxx - - # Forward GMMStats and check estimated value of the x speaker factor - eps = 1e-10 - x_ref = numpy.array([0.291042849767692, 0.310273618998444], 'float64') - score_ref = -3.280498193082100 - - score = m.forward(gs) - self.assertTrue( numpy.allclose(m.__x__, x_ref, eps) ) - self.assertTrue( abs(score_ref-score) < eps ) - - # Check using alternate forward() method - Ux = numpy.ndarray(shape=(m.dim_cd,), dtype=numpy.float64) - m.estimate_ux(gs, Ux) - score = m.forward_ux(gs, Ux) - self.assertTrue( abs(score_ref-score) < eps ) - - # x and Ux - x = numpy.ndarray((2,), numpy.float64) - m.estimate_x(gs, x) - x_py = estimate_x(m.dim_c, m.dim_d, ubm.mean_supervector, ubm.variance_supervector, U, n, sumpx) - self.assertTrue( numpy.allclose(x, x_py, eps)) - - ux = numpy.ndarray((6,), numpy.float64) - m.estimate_ux(gs, ux) - ux_py = estimate_ux(m.dim_c, m.dim_d, ubm.mean_supervector, ubm.variance_supervector, U, n, sumpx) - self.assertTrue( numpy.allclose(ux, ux_py, eps)) - self.assertTrue( numpy.allclose(m.__x__, x, eps) ) - - score = m.forward_ux(gs, ux) - self.assertTrue( abs(score_ref-score) < eps ) - - # Clean-up - os.unlink(filename) diff --git a/xbob/machine/test_kmeans.py b/xbob/machine/test_kmeans.py deleted file mode 100644 index f65f208..0000000 --- a/xbob/machine/test_kmeans.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Laurent El Shafey <Laurent.El-Shafey@idiap.ch> -# Thu Feb 16 17:57:10 2012 +0200 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Tests the KMeans machine -""" - -import os, sys -import unittest -import bob -import numpy, math -import tempfile - -def equals(x, y, epsilon): - return (abs(x - y) < epsilon) - -class KMeansMachineTest(unittest.TestCase): - """Performs various KMeans machine-related tests.""" - - def test01_KMeansMachine(self): - # Test a KMeansMachine - - means = numpy.array([[3, 70, 0], [4, 72, 0]], 'float64') - mean = numpy.array([3,70,1], 'float64') - - # Initializes a KMeansMachine - km = bob.machine.KMeansMachine(2,3) - km.means = means - self.assertTrue( km.dim_c == 2 ) - self.assertTrue( km.dim_d == 3 ) - - # Sets and gets - self.assertTrue( (km.means == means).all() ) - self.assertTrue( (km.get_mean(0) == means[0,:]).all() ) - self.assertTrue( (km.get_mean(1) == means[1,:]).all() ) - km.set_mean(0, mean) - self.assertTrue( (km.get_mean(0) == mean).all() ) - - # Distance and closest mean - eps = 1e-10 - self.assertTrue( equals( km.get_distance_from_mean(mean, 0), 0, eps) ) - self.assertTrue( equals( km.get_distance_from_mean(mean, 1), 6, eps) ) - (index, dist) = km.get_closest_mean(mean) - self.assertTrue( index == 0) - self.assertTrue( equals( dist, 0, eps) ) - self.assertTrue( equals( km.get_min_distance(mean), 0, eps) ) - - # Loads and saves - filename = str(tempfile.mkstemp(".hdf5")[1]) - km.save(bob.io.HDF5File(filename, 'w')) - km_loaded = bob.machine.KMeansMachine(bob.io.HDF5File(filename)) - self.assertTrue( km == km_loaded ) - - # Resize - km.resize(4,5) - self.assertTrue( km.dim_c == 4 ) - self.assertTrue( km.dim_d == 5 ) - - # Copy constructor and comparison operators - km.resize(2,3) - km2 = bob.machine.KMeansMachine(km) - self.assertTrue( km2 == km) - self.assertFalse( km2 != km) - self.assertTrue( km2.is_similar_to(km) ) - means2 = numpy.array([[3, 70, 0], [4, 72, 2]], 'float64') - km2.means = means2 - self.assertFalse( km2 == km) - self.assertTrue( km2 != km) - self.assertFalse( km2.is_similar_to(km) ) - - # Clean-up - os.unlink(filename) diff --git a/xbob/machine/test_linear.py b/xbob/machine/test_linear.py deleted file mode 100644 index 52ef2e6..0000000 --- a/xbob/machine/test_linear.py +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Andre Anjos <andre.anjos@idiap.ch> -# Tue May 31 16:55:10 2011 +0200 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Tests on the LinearMachine infrastructure. -""" - -import os, sys -import nose.tools -import math -from . import LinearMachine, HyperbolicTangentActivation, IdentityActivation -import numpy -import pkg_resources -from xbob.io import HDF5File - -def F(f): - """Returns the test file on the "data" subdirectory""" - return pkg_resources.resource_filename(__name__, os.path.join('data', f)) - -MACHINE = F('linear-test.hdf5') - -def test_initialization(): - - # Two inputs and 1 output - m = LinearMachine(2,1) - assert (m.weights == 0.0).all() - nose.tools.eq_( m.weights.shape, (2,1) ) - assert (m.biases == 0.0).all() - nose.tools.eq_( m.biases.shape, (1,) ) - - # Start by providing the data - w = numpy.array([[0.4, 0.1], [0.4, 0.2], [0.2, 0.7]], 'float64') - m = LinearMachine(w) - b = numpy.array([0.3, -3.0], 'float64') - isub = numpy.array([0., 0.5, 0.5], 'float64') - idiv = numpy.array([0.5, 1.0, 1.0], 'float64') - m.input_subtract = isub - m.input_divide = idiv - m.biases = b - m.activation = HyperbolicTangentActivation() - - assert (m.input_subtract == isub).all() - assert (m.input_divide == idiv).all() - assert (m.weights == w).all() - assert (m.biases == b). all() - nose.tools.eq_(m.hidden_activation, - HyperbolicTangentActivation()) - # Save to file - # c = HDF5File("bla.hdf5", 'w') - # m.save(c) - - # Start by reading data from a file - c = HDF5File(MACHINE) - m = LinearMachine(c) - assert (m.weights == w).all() - assert (m.biases == b). all() - - # Makes sure we cannot stuff incompatible data - w = numpy.array([[0.4, 0.4, 0.2], [0.1, 0.2, 0.7]], 'float64') - m = LinearMachine(w) - b = numpy.array([0.3, -3.0, 2.7, -18, 52], 'float64') #wrong - nose.tools.assert_raises(RuntimeError, setattr, m, 'biases', b) - nose.tools.assert_raises(RuntimeError, setattr, m, 'input_subtract', b) - nose.tools.assert_raises(RuntimeError, setattr, m, 'input_divide', b) - -def test_correctness(): - - # Tests the correctness of a linear machine - c = HDF5File(MACHINE) - m = LinearMachine(c) - - def presumed(ivalue): - """Calculates, by hand, the presumed output given the input""" - - # These are the supposed preloaded values from the file "MACHINE" - isub = numpy.array([0., 0.5, 0.5], 'float64') - idiv = numpy.array([0.5, 1.0, 1.0], 'float64') - w = numpy.array([[0.4, 0.4, 0.2], [0.1, 0.2, 0.7]], 'float64') - b = numpy.array([0.3, -3.0], 'float64') - act = math.tanh - - return numpy.array([ act((w[i,:]*((ivalue-isub)/idiv)).sum() + b[i]) for i in range(w.shape[0]) ], 'float64') - - testing = [ - [1,1,1], - [0.5,0.2,200], - [-27,35.77,0], - [12,0,0], - ] - - # 1D case - maxerr = numpy.ndarray((2,), 'float64') - maxerr.fill(1e-10) - for k in testing: - input = numpy.array(k, 'float64') - assert (abs(presumed(input) - m(input)) < maxerr).all() - - # 2D case - output = m(testing) - for i, k in enumerate(testing): - input = numpy.array(k, 'float64') - assert (abs(presumed(input) - output[i,:]) < maxerr).all() - -def test_user_allocation(): - - # Tests the correctness of a linear machine - c = HDF5File(MACHINE) - m = LinearMachine(c) - - def presumed(ivalue): - """Calculates, by hand, the presumed output given the input""" - - # These are the supposed preloaded values from the file "MACHINE" - isub = numpy.array([0., 0.5, 0.5], 'float64') - idiv = numpy.array([0.5, 1.0, 1.0], 'float64') - w = numpy.array([[0.4, 0.4, 0.2], [0.1, 0.2, 0.7]], 'float64') - b = numpy.array([0.3, -3.0], 'float64') - act = math.tanh - - return numpy.array([ act((w[i,:]*((ivalue-isub)/idiv)).sum() + b[i]) for i in range(w.shape[0]) ], 'float64') - - testing = [ - [1,1,1], - [0.5,0.2,200], - [-27,35.77,0], - [12,0,0], - ] - - # 1D case - maxerr = numpy.ndarray((2,), 'float64') - maxerr.fill(1e-10) - output = numpy.ndarray((2,), 'float64') - for k in testing: - input = numpy.array(k, 'float64') - m(input, output) - assert (abs(presumed(input) - output) < maxerr).all() - - # 2D case - output = numpy.ndarray((len(testing), 2), 'float64') - m(testing, output) - for i, k in enumerate(testing): - input = numpy.array(k, 'float64') - assert (abs(presumed(input) - output[i,:]) < maxerr).all() - -def test_comparisons(): - - # Start by creating the data - w1 = numpy.array([[0.4, 0.1], [0.4, 0.2], [0.2, 0.7]], 'float64') - w2 = numpy.array([[0.4, 1.1], [0.4, 0.2], [0.2, 0.7]], 'float64') - b1 = numpy.array([0.3, -3.0], 'float64') - b2 = numpy.array([0.3, 3.0], 'float64') - isub1 = numpy.array([0., 0.5, 0.5], 'float64') - isub2 = numpy.array([0.5, 0.5, 0.5], 'float64') - idiv1 = numpy.array([0.5, 1.0, 1.0], 'float64') - idiv2 = numpy.array([1.5, 1.0, 1.0], 'float64') - - # Creates LinearMachine's - m1 = LinearMachine(w1) - m1.input_subtract = isub1 - m1.input_divide = idiv1 - m1.biases = b1 - m1.activation = HyperbolicTangentActivation() - - m1b = LinearMachine(m1) - m1c = LinearMachine(w1) - m1c.input_subtract = isub1 - m1c.input_divide = idiv1 - m1c.biases = b1 - m1c.activation = HyperbolicTangentActivation() - - m2 = LinearMachine(w2) - m2.input_subtract = isub1 - m2.input_divide = idiv1 - m2.biases = b1 - m2.activation = HyperbolicTangentActivation() - - m3 = LinearMachine(w1) - m3.input_subtract = isub2 - m3.input_divide = idiv1 - m3.biases = b1 - m3.activation = HyperbolicTangentActivation() - - m4 = LinearMachine(w1) - m4.input_subtract = isub1 - m4.input_divide = idiv2 - m4.biases = b1 - m4.activation = HyperbolicTangentActivation() - - m5 = LinearMachine(w1) - m5.input_subtract = isub1 - m5.input_divide = idiv1 - m5.biases = b2 - m5.activation = HyperbolicTangentActivation() - - m6 = LinearMachine(w1) - m6.input_subtract = isub1 - m6.input_divide = idiv1 - m6.biases = b1 - m6.activation = IdentityActivation() - - # Compares them using the overloaded operators == and != - assert m1 == m1b - assert not m1 != m1b - assert m1.is_similar_to(m1b) - assert m1 == m1c - assert not m1 != m1c - assert m1.is_similar_to(m1c) - assert not m1 == m2 - assert m1 != m2 - assert not m1.is_similar_to(m2) - assert not m1 == m3 - assert m1 != m3 - assert not m1.is_similar_to(m3) - assert not m1 == m4 - assert m1 != m4 - assert not m1.is_similar_to(m4) - assert not m1 == m5 - assert m1 != m5 - assert not m1.is_similar_to(m5) - assert not m1 == m6 - assert m1 != m6 - assert not m1.is_similar_to(m6) diff --git a/xbob/machine/test_linearscoring.py b/xbob/machine/test_linearscoring.py deleted file mode 100644 index e72a5ef..0000000 --- a/xbob/machine/test_linearscoring.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Francois Moulin <Francois.Moulin@idiap.ch> -# Wed Jul 13 16:00:04 2011 +0200 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Tests on the LinearScoring function -""" - -import os, sys -import unittest -import bob -import numpy - -class LinearScoringTest(unittest.TestCase): - """Performs various LinearScoring tests.""" - - def test01_LinearScoring(self): - ubm = bob.machine.GMMMachine(2, 2) - ubm.weights = numpy.array([0.5, 0.5], 'float64') - ubm.means = numpy.array([[3, 70], [4, 72]], 'float64') - ubm.variances = numpy.array([[1, 10], [2, 5]], 'float64') - ubm.variance_thresholds = numpy.array([[0, 0], [0, 0]], 'float64') - - model1 = bob.machine.GMMMachine(2, 2) - model1.weights = numpy.array([0.5, 0.5], 'float64') - model1.means = numpy.array([[1, 2], [3, 4]], 'float64') - model1.variances = numpy.array([[9, 10], [11, 12]], 'float64') - model1.variance_thresholds = numpy.array([[0, 0], [0, 0]], 'float64') - - model2 = bob.machine.GMMMachine(2, 2) - model2.weights = numpy.array([0.5, 0.5], 'float64') - model2.means = numpy.array([[5, 6], [7, 8]], 'float64') - model2.variances = numpy.array([[13, 14], [15, 16]], 'float64') - model2.variance_thresholds = numpy.array([[0, 0], [0, 0]], 'float64') - - stats1 = bob.machine.GMMStats(2, 2) - stats1.sum_px = numpy.array([[1, 2], [3, 4]], 'float64') - stats1.n = numpy.array([1, 2], 'float64') - stats1.t = 1+2 - - stats2 = bob.machine.GMMStats(2, 2) - stats2.sum_px = numpy.array([[5, 6], [7, 8]], 'float64') - stats2.n = numpy.array([3, 4], 'float64') - stats2.t = 3+4 - - stats3 = bob.machine.GMMStats(2, 2) - stats3.sum_px = numpy.array([[5, 6], [7, 3]], 'float64') - stats3.n = numpy.array([3, 4], 'float64') - stats3.t = 3+4 - - test_channeloffset = [numpy.array([9, 8, 7, 6], 'float64'), numpy.array([5, 4, 3, 2], 'float64'), numpy.array([1, 0, 1, 2], 'float64')] - - # Reference scores (from Idiap internal matlab implementation) - ref_scores_00 = numpy.array([[2372.9, 5207.7, 5275.7], [2215.7, 4868.1, 4932.1]], 'float64') - ref_scores_01 = numpy.array( [[790.9666666666667, 743.9571428571428, 753.6714285714285], [738.5666666666667, 695.4428571428572, 704.5857142857144]], 'float64') - ref_scores_10 = numpy.array([[2615.5, 5434.1, 5392.5], [2381.5, 4999.3, 5022.5]], 'float64') - ref_scores_11 = numpy.array([[871.8333333333332, 776.3000000000001, 770.3571428571427], [793.8333333333333, 714.1857142857143, 717.5000000000000]], 'float64') - - - # 1/ Use GMMMachines - # 1/a/ Without test_channelOffset, without frame-length normalisation - scores = bob.machine.linear_scoring([model1, model2], ubm, [stats1, stats2, stats3]) - self.assertTrue((abs(scores - ref_scores_00) < 1e-7).all()) - - # 1/b/ Without test_channelOffset, with frame-length normalisation - scores = bob.machine.linear_scoring([model1, model2], ubm, [stats1, stats2, stats3], [], True) - self.assertTrue((abs(scores - ref_scores_01) < 1e-7).all()) - scores = bob.machine.linear_scoring([model1, model2], ubm, [stats1, stats2, stats3], (), True) - self.assertTrue((abs(scores - ref_scores_01) < 1e-7).all()) - scores = bob.machine.linear_scoring([model1, model2], ubm, [stats1, stats2, stats3], None, True) - self.assertTrue((abs(scores - ref_scores_01) < 1e-7).all()) - - # 1/c/ With test_channelOffset, without frame-length normalisation - scores = bob.machine.linear_scoring([model1, model2], ubm, [stats1, stats2, stats3], test_channeloffset) - self.assertTrue((abs(scores - ref_scores_10) < 1e-7).all()) - - # 1/d/ With test_channelOffset, with frame-length normalisation - scores = bob.machine.linear_scoring([model1, model2], ubm, [stats1, stats2, stats3], test_channeloffset, True) - self.assertTrue((abs(scores - ref_scores_11) < 1e-7).all()) - - - # 2/ Use mean/variance supervectors - # 2/a/ Without test_channelOffset, without frame-length normalisation - scores = bob.machine.linear_scoring([model1.mean_supervector, model2.mean_supervector], ubm.mean_supervector, ubm.variance_supervector, [stats1, stats2, stats3]) - self.assertTrue((abs(scores - ref_scores_00) < 1e-7).all()) - - # 2/b/ Without test_channelOffset, with frame-length normalisation - scores = bob.machine.linear_scoring([model1.mean_supervector, model2.mean_supervector], ubm.mean_supervector, ubm.variance_supervector, [stats1, stats2, stats3], [], True) - self.assertTrue((abs(scores - ref_scores_01) < 1e-7).all()) - - # 2/c/ With test_channelOffset, without frame-length normalisation - scores = bob.machine.linear_scoring([model1.mean_supervector, model2.mean_supervector], ubm.mean_supervector, ubm.variance_supervector, [stats1, stats2, stats3], test_channeloffset) - self.assertTrue((abs(scores - ref_scores_10) < 1e-7).all()) - - # 2/d/ With test_channelOffset, with frame-length normalisation - scores = bob.machine.linear_scoring([model1.mean_supervector, model2.mean_supervector], ubm.mean_supervector, ubm.variance_supervector, [stats1, stats2, stats3], test_channeloffset, True) - self.assertTrue((abs(scores - ref_scores_11) < 1e-7).all()) - - # 3/ Using single model/sample - # 3/a/ without frame-length normalisation - score = bob.machine.linear_scoring(model1.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats1, test_channeloffset[0]) - self.assertTrue(abs(score - ref_scores_10[0,0]) < 1e-7) - score = bob.machine.linear_scoring(model1.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats2, test_channeloffset[1]) - self.assertTrue(abs(score - ref_scores_10[0,1]) < 1e-7) - score = bob.machine.linear_scoring(model1.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats3, test_channeloffset[2]) - self.assertTrue(abs(score - ref_scores_10[0,2]) < 1e-7) - score = bob.machine.linear_scoring(model2.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats1, test_channeloffset[0]) - self.assertTrue(abs(score - ref_scores_10[1,0]) < 1e-7) - score = bob.machine.linear_scoring(model2.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats2, test_channeloffset[1]) - self.assertTrue(abs(score - ref_scores_10[1,1]) < 1e-7) - score = bob.machine.linear_scoring(model2.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats3, test_channeloffset[2]) - self.assertTrue(abs(score - ref_scores_10[1,2]) < 1e-7) - - # 3/b/ without frame-length normalisation - score = bob.machine.linear_scoring(model1.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats1, test_channeloffset[0], True) - self.assertTrue(abs(score - ref_scores_11[0,0]) < 1e-7) - score = bob.machine.linear_scoring(model1.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats2, test_channeloffset[1], True) - self.assertTrue(abs(score - ref_scores_11[0,1]) < 1e-7) - score = bob.machine.linear_scoring(model1.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats3, test_channeloffset[2], True) - self.assertTrue(abs(score - ref_scores_11[0,2]) < 1e-7) - score = bob.machine.linear_scoring(model2.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats1, test_channeloffset[0], True) - self.assertTrue(abs(score - ref_scores_11[1,0]) < 1e-7) - score = bob.machine.linear_scoring(model2.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats2, test_channeloffset[1], True) - self.assertTrue(abs(score - ref_scores_11[1,1]) < 1e-7) - score = bob.machine.linear_scoring(model2.mean_supervector, ubm.mean_supervector, ubm.variance_supervector, stats3, test_channeloffset[2], True) - self.assertTrue(abs(score - ref_scores_11[1,2]) < 1e-7) diff --git a/xbob/machine/test_mlp.py b/xbob/machine/test_mlp.py deleted file mode 100644 index 9c73efa..0000000 --- a/xbob/machine/test_mlp.py +++ /dev/null @@ -1,277 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Andre Anjos <andre.anjos@idiap.ch> -# Thu 13 Jun 2013 16:58:21 CEST -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Tests on the MLP infrastructure. -""" - -import numpy -import nose.tools -from .. import MLP, HyperbolicTangentActivation, LogisticActivation -from . import test_mlp_machine as pymlp -from ... import io -from ...test import utils as test_utils - -def test_2in_1out(): - - m = MLP((2,1)) - assert m.shape == (2,1) - assert m.input_divide.shape == (2,) - assert m.input_subtract.shape == (2,) - assert len(m.weights) == 1 - assert m.weights[0].shape == (2,1) - assert numpy.allclose(m.weights[0], 0., rtol=1e-10, atol=1e-15) - assert len(m.biases) == 1 - assert m.biases[0].shape == (1,) - assert m.biases[0] == 0. - assert m.hidden_activation == HyperbolicTangentActivation() - assert m.output_activation == HyperbolicTangentActivation() - - # calculate and match - weights = [numpy.random.rand(2,1)] - biases = [numpy.random.rand(1)] - - m.weights = weights - m.biases = biases - - pymac = pymlp.Machine(biases, weights, m.hidden_activation, m.output_activation) - - X = numpy.random.rand(10,2) - assert numpy.allclose(m(X), pymac.forward(X), rtol=1e-10, atol=1e-15) - -def test_2in_3_1out(): - - m = MLP((2,3,1)) - assert m.shape == (2,3,1) - assert m.input_divide.shape == (2,) - assert m.input_subtract.shape == (2,) - assert len(m.weights) == 2 - assert m.weights[0].shape == (2,3) - assert numpy.allclose(m.weights[0], 0., rtol=1e-10, atol=1e-15) - assert m.weights[1].shape == (3,1) - assert numpy.allclose(m.weights[1], 0., rtol=1e-10, atol=1e-15) - assert len(m.biases) == 2 - assert m.biases[0].shape == (3,) - assert numpy.allclose(m.biases[0], 0., rtol=1e-10, atol=1e-15) - assert m.biases[1].shape == (1,) - assert numpy.allclose(m.biases[1], 0., rtol=1e-10, atol=1e-15) - assert m.hidden_activation == HyperbolicTangentActivation() - assert m.output_activation == HyperbolicTangentActivation() - - # calculate and match - weights = [numpy.random.rand(2,3), numpy.random.rand(3,1)] - biases = [numpy.random.rand(3), numpy.random.rand(1)] - - m.weights = weights - m.biases = biases - - pymac = pymlp.Machine(biases, weights, m.hidden_activation, m.output_activation) - - X = numpy.random.rand(10,2) - assert numpy.allclose(m(X), pymac.forward(X), rtol=1e-10, atol=1e-15) - -def test_2in_3_5_1out(): - - m = MLP((2,3,5,1)) - assert m.shape == (2,3,5,1) - assert m.input_divide.shape == (2,) - assert m.input_subtract.shape == (2,) - assert len(m.weights) == 3 - assert m.weights[0].shape == (2,3) - assert numpy.allclose(m.weights[0], 0., rtol=1e-10, atol=1e-15) - assert m.weights[1].shape == (3,5) - assert numpy.allclose(m.weights[1], 0., rtol=1e-10, atol=1e-15) - assert m.weights[2].shape == (5,1) - assert numpy.allclose(m.weights[2], 0., rtol=1e-10, atol=1e-15) - assert len(m.biases) == 3 - assert m.biases[0].shape == (3,) - assert numpy.allclose(m.biases[0], 0., rtol=1e-10, atol=1e-15) - assert m.biases[1].shape == (5,) - assert numpy.allclose(m.biases[1], 0., rtol=1e-10, atol=1e-15) - assert m.biases[2].shape == (1,) - assert numpy.allclose(m.biases[2], 0., rtol=1e-10, atol=1e-15) - assert m.hidden_activation == HyperbolicTangentActivation() - assert m.output_activation == HyperbolicTangentActivation() - - # calculate and match - weights = [ - numpy.random.rand(2,3), - numpy.random.rand(3,5), - numpy.random.rand(5,1) - ] - biases = [ - numpy.random.rand(3), - numpy.random.rand(5), - numpy.random.rand(1), - ] - - m.weights = weights - m.biases = biases - - pymac = pymlp.Machine(biases, weights, m.hidden_activation, m.output_activation) - - X = numpy.random.rand(10,2) - assert numpy.allclose(m(X), pymac.forward(X), rtol=1e-10, atol=1e-15) - -def test_100in_100_10_4out(): - - m = MLP((100,100,10,4)) - - # calculate and match - weights = [ - numpy.random.rand(100,100), - numpy.random.rand(100,10), - numpy.random.rand(10,4) - ] - biases = [ - numpy.random.rand(100), - numpy.random.rand(10), - numpy.random.rand(4), - ] - - m.weights = weights - m.biases = biases - - pymac = pymlp.Machine(biases, weights, m.hidden_activation, m.output_activation) - - X = numpy.random.rand(20,100) - assert numpy.allclose(m(X), pymac.forward(X), rtol=1e-10, atol=1e-15) -def test_resize(): - - m = MLP((2,3,5,1)) - m.shape = (2,1) - m.hidden_activation = LogisticActivation() - m.output_activation = LogisticActivation() - - assert m.shape == (2,1) - assert m.input_divide.shape == (2,) - assert m.input_subtract.shape == (2,) - assert len(m.weights) == 1 - assert m.weights[0].shape == (2,1) - assert numpy.allclose(m.weights[0], 0., rtol=1e-10, atol=1e-15) - assert len(m.biases) == 1 - assert m.biases[0].shape == (1,) - assert m.biases[0] == 0. - assert m.hidden_activation == LogisticActivation() - assert m.output_activation == LogisticActivation() - - # calculate and match - weights = [numpy.random.rand(2,1)] - biases = [numpy.random.rand(1)] - - m.weights = weights - m.biases = biases - - pymac = pymlp.Machine(biases, weights, m.hidden_activation, m.output_activation) - - X = numpy.random.rand(10,2) - assert numpy.allclose(m(X), pymac.forward(X), rtol=1e-10, atol=1e-15) - -def test_checks(): - - # tests if MLPs check wrong settings - m = MLP((2,1)) - - # the MLP shape cannot have a single entry - nose.tools.assert_raises(RuntimeError, setattr, m, 'shape', (5,)) - - # you cannot set the weights vector with the wrong size - nose.tools.assert_raises(RuntimeError, - setattr, m, 'weights', [numpy.zeros((3,1), 'float64')]) - - # the same for the bias - nose.tools.assert_raises(RuntimeError, - setattr, m, 'biases', [numpy.zeros((5,), 'float64')]) - - # it works though if the sizes are correct - new_weights = [numpy.zeros((2,1), 'float64')] - new_weights[0].fill(3.14) - m.weights = new_weights - - assert len(m.weights) == 1 - - assert (m.weights[0] == new_weights[0]).all() - - new_biases = [numpy.zeros((1,), 'float64')] - new_biases[0].fill(5.71) - m.biases = new_biases - - assert len(m.biases) == 1 - - assert (m.biases[0] == new_biases[0]).all() - -def test_persistence(): - - # make shure we can save an load an MLP machine - weights = [] - weights.append(numpy.array([[.2, -.1, .2], [.2, .3, .9]])) - weights.append(numpy.array([[.1, .5], [-.1, .2], [-.1, 1.1]])) - biases = [] - biases.append(numpy.array([-.1, .3, .1])) - biases.append(numpy.array([.2, -.1])) - - m = MLP((2,3,2)) - m.weights = weights - m.biases = biases - - # creates a file that will be used in the next test! - machine_file = test_utils.temporary_filename() - m.save(io.HDF5File(machine_file, 'w')) - m2 = MLP(io.HDF5File(machine_file)) - - assert m.is_similar_to(m2) - assert m == m2 - assert m.shape == m2.shape - assert (m.input_subtract == m2.input_subtract).all() - assert (m.input_divide == m2.input_divide).all() - - for i in range(len(m.weights)): - assert (m.weights[i] == m2.weights[i]).all() - assert (m.biases[i] == m2.biases[i]).all() - -def test_randomization(): - - m = MLP((2,3,2)) - m.randomize() - - for k in m.weights: - assert (abs(k) <= 0.1).all() - assert (k != 0).any() - - for k in m.biases: - assert (abs(k) <= 0.1).all() - assert (k != 0).any() - -def test_randomization_margins(): - - # we can also reset the margins for randomization - for k in range(10): - - m = MLP((2,3,2)) - m.randomize(-0.001, 0.001) - - for k in m.weights: - assert (abs(k) <= 0.001).all() - assert (k != 0).any() - - for k in m.biases: - assert (abs(k) <= 0.001).all() - assert (k != 0).any() - -def test_randomness(): - - m1 = MLP((2,3,2)) - m1.randomize() - - for k in range(10): - m2 = MLP((2,3,2)) - m2.randomize() - - for w1, w2 in zip(m1.weights, m2.weights): - assert (w1 == w2).all() == False - - for b1, b2 in zip(m1.biases, m2.biases): - assert (b1 == b2).all() == False diff --git a/xbob/machine/test_mlp_machine.py b/xbob/machine/test_mlp_machine.py deleted file mode 100644 index 7979526..0000000 --- a/xbob/machine/test_mlp_machine.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Andre Anjos <andre.anjos@idiap.ch> -# Thu 13 Jun 2013 15:54:19 CEST - -"""Pythonic implementations of Multi-Layer Perceptrons for code testing -""" - -import numpy - -class Machine: - """Represents a Multi-Layer Perceptron Machine with a single hidden layer""" - - def __init__(self, bias, weights, hidden_activation, output_activation): - """Initializes the MLP with a number of inputs and outputs. Weights are - initialized randomly with the specified seed. - - Keyword parameters: - - bias - A list of 1D numpy.ndarray's with 64-bit floating-point numbers - representing the biases for each layer of the MLP. Each ndarray must have - as many entries as neurons in that particular layer. If set to `None`, - disables the use of biases. - - weights - A list of 2D numpy.ndarray's with 64-bit floating-point numbers - representing the weights for the MLP. The more entries, the more layers - the MLP has. The weight matrix includes the bias terms weights and is - organized so that every neuron input is in a single column. The first - row always represents the bias connections. - - hidden_activation - The activation function to use for the hidden neurons of the network. - Should be one of the classes derived from - :py:class:`bob.machine.Activation`. - - output_activation - The activation function to use for the output neurons of the network. - Should be one of the classes derived from - :py:class:`bob.machine.Activation`. - """ - - if bias is None: - self.weights = weights - self.has_bias = False - else: - self.weights = [numpy.vstack([bias[k], weights[k]]) for k in range(len(bias))] - self.has_bias = True - - self.hidden_activation = hidden_activation - self.output_activation = output_activation - - def forward(self, X): - """Executes the forward step of the N-layer neural network. - - Remember that: - - 1. z = X . w - - and - - 2. Output: a = g(z), with g being the activation function - - Keyword attributes: - - X - The input vector containing examples organized in rows. The input - matrix does **not** contain the bias term. - - Returns the outputs of the network for each row in X. Accumulates hidden - layer outputs and activations (for backward step). At the end of this - procedure: - - self.a - Input, including the bias term for all layers. 1 example per row. Bias = - first column. - - self.z - Activations for every input X on given layer. z1 = a0 * w1 - """ - if self.has_bias: - self.a = [numpy.hstack([numpy.ones((len(X),1)), X])] - else: - self.a = [X] - - self.z = [] - - for w in self.weights[:-1]: - self.z.append(numpy.dot(self.a[-1], w)) - self.a.append(self.hidden_activation(self.z[-1])) - if self.has_bias: - self.a[-1] = numpy.hstack([numpy.ones((len(self.a[-1]),1)), self.a[-1]]) - - self.z.append(numpy.dot(self.a[-1], self.weights[-1])) - self.a.append(self.output_activation(self.z[-1])) - - return self.a[-1] diff --git a/xbob/machine/test_plda.py b/xbob/machine/test_plda.py deleted file mode 100644 index c8953ec..0000000 --- a/xbob/machine/test_plda.py +++ /dev/null @@ -1,561 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Laurent El Shafey <Laurent.El-Shafey@idiap.ch> -# Sat Oct 22 23:01:09 2011 +0200 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Tests PLDA machine -""" - -import os, sys -import unittest -import bob -import random, tempfile, math -import numpy -import numpy.linalg - -# Defines common variables globally -# Dimensionalities -C_dim_d = 7 -C_dim_f = 2 -C_dim_g = 3 -# Values for F and G -C_G=numpy.array([-1.1424, -0.5044, -0.1917, - -0.6249, 0.1021, -0.8658, - -1.1687, 1.1963, 0.1807, - 0.3926, 0.1203, 1.2665, - 1.3018, -1.0368, -0.2512, - -0.5936, -0.8571, -0.2046, - 0.4364, -0.1699, -2.2015], 'float64').reshape(C_dim_d, C_dim_g) -# F <-> PCA on G -C_F=numpy.array([-0.054222647972093, -0.000000000783146, - 0.596449127693018, 0.000000006265167, - 0.298224563846509, 0.000000003132583, - 0.447336845769764, 0.000000009397750, - -0.108445295944185, -0.000000001566292, - -0.501559493741856, -0.000000006265167, - -0.298224563846509, -0.000000003132583], 'float64').reshape(C_dim_d, C_dim_f) - -def equals(x, y, epsilon): - return (abs(x - y) < epsilon).all() - -def compute_i_sigma(sigma): - # Inverse of a diagonal matrix (represented by a 1D numpy array) - return (1. / sigma) - -def compute_alpha(G, sigma): - # alpha = (Id + G^T.sigma^-1.G)^-1 = \mathcal{G} - dim_g = G.shape[1] - isigma = numpy.diag(compute_i_sigma(sigma)) - return numpy.linalg.inv(numpy.eye(dim_g) + numpy.dot(numpy.dot(G.transpose(), isigma), G)) - -def compute_beta(G, sigma): - # beta = (sigma + G.G^T)^-1 = sigma^-1 - sigma^-1.G.alpha.G^T.sigma^-1 = \mathcal{S} - isigma = numpy.diag(compute_i_sigma(sigma)) - gt_isigma = numpy.dot(G.transpose(), isigma) - alpha = compute_alpha(G, sigma) - return (isigma - numpy.dot(numpy.dot(gt_isigma.transpose(), alpha), gt_isigma)) - -def compute_gamma(F, G, sigma, a): - # gamma_a = (Id + a.F^T.beta.F)^-1 = \mathcal{F}_{a} - dim_f = F.shape[1] - beta = compute_beta(G, sigma) - return numpy.linalg.inv(numpy.eye(dim_f) + a * numpy.dot(numpy.dot(F.transpose(), beta), F)) - -def compute_ft_beta(F, G, sigma): - # F^T.beta = F^T.\mathcal{S} - beta = compute_beta(G, sigma) - return numpy.dot(numpy.transpose(F), beta) - -def compute_gt_i_sigma(G, sigma): - # G^T.sigma^-1 - isigma = compute_i_sigma(sigma) - return numpy.transpose(G) * isigma - -def compute_logdet_alpha(G, sigma): - # \log(\det(\alpha)) = \log(\det(\mathcal{G})) - alpha = compute_alpha(G, sigma) - return math.log(numpy.linalg.det(alpha)) - -def compute_logdet_sigma(sigma): - # \log(\det(\sigma)) = \log(\det(\sigma)) = \log(\prod(\sigma_{i})) - return math.log(numpy.prod(sigma)) - -def compute_loglike_constterm(F, G, sigma, a): - # loglike_constterm[a] = a/2 * ( -D*\log(2*pi) -\log|\sigma| +\log|\alpha| +\log|\gamma_a|) - gamma_a = compute_gamma(F, G, sigma, a) - logdet_gamma_a = math.log(abs(numpy.linalg.det(gamma_a))) - ah = a/2. - dim_d = F.shape[0] - logdet_sigma = compute_logdet_sigma(sigma) - logdet_alpha = compute_logdet_alpha(G, sigma) - res = -ah*dim_d*math.log(2*math.pi) - ah*logdet_sigma + ah*logdet_alpha + logdet_gamma_a/2. - return res; - -def compute_log_likelihood_point_estimate(observation, mu, F, G, sigma, hi, wij): - """ - This function computes p(x_{ij} | h_{i}, w_{ij}, \Theta), which is given by - N_{x}[\mu + Fh_{i} + Gw_{ij} + epsilon_{ij}, \Sigma], N_{x} being a - Gaussian distribution. As it returns the corresponding log likelihood, - this is given by the sum of the following three terms: - C1 = -dim_d/2 log(2pi) - C2 = -1/2 log(det(\Sigma)) - C3 = -1/2 (x_{ij}-\mu-Fh_{i}-Gw_{ij})^{T}\Sigma^{-1}(x_{ij}-\mu-Fh_{i}-Gw_{ij}) - """ - - ### Pre-computes some of the constants - dim_d = observation.shape[0] # A scalar - log_2pi = numpy.log(2. * numpy.pi); # A scalar - C1 = -(dim_d / 2.) * log_2pi; # A scalar - C2 = -(1. / 2.) * numpy.sum( numpy.log(sigma) ); # (dim_d, 1) - - ### Subtract the identity and session components from the observed vector. - session_plus_identity = numpy.dot(F, hi) + numpy.dot(G, wij); - normalised_observation = numpy.reshape(observation - mu - session_plus_identity, (dim_d,1)); - ### Now calculate C3 - sigma_inverse = numpy.reshape(1. / sigma, (dim_d,1)); # (dim_d, 1) - C3 = -(1. / 2.) * numpy.sum(normalised_observation * sigma_inverse * normalised_observation); - - ### Returns the log likelihood - log_likelihood = C1 + C2 + C3; - return (log_likelihood); - - -def compute_log_likelihood(observations, mu, F, G, sigma): - """ - This function computes the log-likelihood of the observations given the parameters - of the PLDA model. This is done by fulling integrating out the latent variables. - """ - # Work out the number of samples that we have and normalise the data. - J_i = observations.shape[0]; # An integer > 0 - norm_observations = observations - numpy.tile(mu, [J_i,1]); # (J_i, D_x) - - # There are three terms that need to be computed: C1, C2 and C3 - - # 1. Computes C1 - # C1 = - J_{i} * dim_d/2 log(2*pi) - dim_d = observations.shape[1] # A scalar - dim_f = F.shape[1] - log_2pi = numpy.log(2. * numpy.pi); # A scalar - C1 = - J_i * (dim_d / 2.) * log_2pi; # A scalar - - # 2. Computes C2 - # C2 = - J_i/2 * [log(det(sigma)) - log(det(alpha^-1))] + log(det(gamma_{J_i}))/2 - ld_sigma = compute_logdet_sigma(sigma) - ld_alpha = compute_logdet_alpha(G, sigma) - gamma = compute_gamma(F, G, sigma, J_i) - ld_gamma = math.log(numpy.linalg.det(gamma)) - C2 = - J_i/2.*(ld_sigma - ld_alpha) + ld_gamma/2. - - # 3. Computes C3 - # This is a quadratic part and consists of - # C3 = -0.5 * sum x^T beta x + 0.5 * Quadratic term in x - # C3 = -0.5 * (C3a - C3b) - C3a = 0.0; - C3b_sum_part = numpy.zeros((dim_f,1)); - isigma = numpy.diag(compute_i_sigma(sigma)) - beta = compute_beta(G, sigma) - ft_beta = numpy.dot(numpy.transpose(F), beta) - for j in range(0, J_i): - ### Calculations for C3a - current_vector = numpy.reshape(norm_observations[j,:], (dim_d,1)); # (D_x, 1) - vector_E = numpy.dot(beta, current_vector); # (D_x, 1) - current_result = numpy.dot(current_vector.transpose(), vector_E); # A floating point value - C3a = C3a + current_result[0][0]; # A floating point value - ### Calculations for C3b - C3b_sum_part = C3b_sum_part + numpy.dot(ft_beta, current_vector); # (nf, 1) - - ### Final calculations for C3b, using the matrix gamma_{J_i} - C3b = numpy.dot(numpy.dot(C3b_sum_part.transpose(), gamma), C3b_sum_part); - C3 = -0.5 * (C3a - C3b[0][0]); - - return C1 + C2 + C3 - - -class PLDAMachineTest(unittest.TestCase): - """Performs various PLDA machine tests.""" - - def test01_plda_basemachine(self): - # Data used for performing the tests - sigma = numpy.ndarray(C_dim_d, 'float64') - sigma.fill(0.01) - mu = numpy.ndarray(C_dim_d, 'float64') - mu.fill(0) - - # Defines reference results based on matlab - alpha_ref = numpy.array([ 0.002189051545735, 0.001127099941432, - -0.000145483208153, 0.001127099941432, 0.003549267943741, - -0.000552001405453, -0.000145483208153, -0.000552001405453, - 0.001440505362615], 'float64').reshape(C_dim_g, C_dim_g) - beta_ref = numpy.array([ 50.587191765140361, -14.512478352504877, - -0.294799164567830, 13.382002504394316, 9.202063877660278, - -43.182264846086497, 11.932345916716455, -14.512478352504878, - 82.320149045633045, -12.605578822979698, 19.618675892079366, - 13.033691341150439, -8.004874490989799, -21.547363307109187, - -0.294799164567832, -12.605578822979696, 52.123885798398241, - 4.363739008635009, 44.847177605628545, 16.438137537463710, - 5.137421840557050, 13.382002504394316, 19.618675892079366, - 4.363739008635011, 75.070401560513488, -4.515472972526140, - 9.752862741017488, 34.196127678931106, 9.202063877660285, - 13.033691341150439, 44.847177605628552, -4.515472972526142, - 56.189416227691098, -7.536676357632515, -10.555735414707383, - -43.182264846086497, -8.004874490989799, 16.438137537463703, - 9.752862741017490, -7.536676357632518, 56.430571485722126, - 9.471758169835317, 11.932345916716461, -21.547363307109187, - 5.137421840557051, 34.196127678931099, -10.555735414707385, - 9.471758169835320, 27.996266602110637], 'float64').reshape(C_dim_d, C_dim_d) - gamma3_ref = numpy.array([ 0.005318799462241, -0.000000012993151, - -0.000000012993151, 0.999999999999996], 'float64').reshape(C_dim_f, C_dim_f) - - # Constructor tests - m = bob.machine.PLDABase() - self.assertTrue(m.dim_d == 0) - self.assertTrue(m.dim_f == 0) - self.assertTrue(m.dim_g == 0) - del m - m = bob.machine.PLDABase(C_dim_d, C_dim_f, C_dim_g) - self.assertTrue(m.dim_d == C_dim_d) - self.assertTrue(m.dim_f == C_dim_f) - self.assertTrue(m.dim_g == C_dim_g) - self.assertTrue( abs(m.variance_threshold - 0.) < 1e-10 ) - del m - m = bob.machine.PLDABase(C_dim_d, C_dim_f, C_dim_g, 1e-2) - self.assertTrue(m.dim_d == C_dim_d) - self.assertTrue(m.dim_f == C_dim_f) - self.assertTrue(m.dim_g == C_dim_g) - self.assertTrue( abs(m.variance_threshold - 1e-2) < 1e-10 ) - del m - - # Defines base machine - m = bob.machine.PLDABase() - m.resize(C_dim_d, C_dim_f, C_dim_g) - # Sets the current mu, F, G and sigma - m.mu = mu - m.f = C_F - m.g = C_G - m.sigma = sigma - gamma3 = m.get_add_gamma(3).copy() - constTerm3 = m.get_add_log_like_const_term(3) - - # Compares precomputed values to matlab reference - for ii in range(m.__alpha__.shape[0]): - for jj in range(m.__alpha__.shape[1]): - absdiff = abs(m.__alpha__[ii,jj]- alpha_ref[ii,jj]) - assert absdiff < 1e-10, 'PLDABase alpha matrix does not match reference at (%d,%d) to 10^-10: |%g-%g| = %g' % (ii, jj, m.__alpha__[ii,jj], alpha_ref[ii,jj], absdiff) - print(m.__alpha__ - alpha_ref) - self.assertTrue(equals(m.__alpha__, alpha_ref, 1e-10)) - self.assertTrue(equals(m.__beta__, beta_ref, 1e-10)) - self.assertTrue(equals(gamma3, gamma3_ref, 1e-10)) - - # Compares precomputed values to the ones returned by python implementation - self.assertTrue(equals(m.__isigma__, compute_i_sigma(sigma), 1e-10)) - self.assertTrue(equals(m.__alpha__, compute_alpha(C_G,sigma), 1e-10)) - self.assertTrue(equals(m.__beta__, compute_beta(C_G,sigma), 1e-10)) - self.assertTrue(equals(m.get_add_gamma(3), compute_gamma(C_F,C_G,sigma,3), 1e-10)) - self.assertTrue(m.has_gamma(3)) - self.assertTrue(equals(m.get_gamma(3), compute_gamma(C_F,C_G,sigma,3), 1e-10)) - self.assertTrue(equals(m.__ft_beta__, compute_ft_beta(C_F,C_G,sigma), 1e-10)) - self.assertTrue(equals(m.__gt_i_sigma__, compute_gt_i_sigma(C_G,sigma), 1e-10)) - self.assertTrue(math.fabs(m.__logdet_alpha__ - compute_logdet_alpha(C_G,sigma)) < 1e-10) - self.assertTrue(math.fabs(m.__logdet_sigma__ - compute_logdet_sigma(sigma)) < 1e-10) - self.assertTrue(abs(m.get_add_log_like_const_term(3) - compute_loglike_constterm(C_F,C_G,sigma,3)) < 1e-10) - self.assertTrue(m.has_log_like_const_term(3)) - self.assertTrue(abs(m.get_log_like_const_term(3) - compute_loglike_constterm(C_F,C_G,sigma,3)) < 1e-10) - - # Defines base machine - del m - m = bob.machine.PLDABase(C_dim_d, C_dim_f, C_dim_g) - # Sets the current mu, F, G and sigma - m.mu = mu - m.f = C_F - m.g = C_G - m.sigma = sigma - gamma3 = m.get_add_gamma(3).copy() - constTerm3 = m.get_add_log_like_const_term(3) - - # Compares precomputed values to matlab reference - self.assertTrue(equals(m.__alpha__, alpha_ref, 1e-10)) - self.assertTrue(equals(m.__beta__, beta_ref, 1e-10)) - self.assertTrue(equals(gamma3, gamma3_ref, 1e-10)) - - # values before being saved - isigma = m.__isigma__.copy() - alpha = m.__alpha__.copy() - beta = m.__beta__.copy() - FtBeta = m.__ft_beta__.copy() - GtISigma = m.__gt_i_sigma__.copy() - logdetAlpha = m.__logdet_alpha__ - logdetSigma = m.__logdet_sigma__ - - # Saves to file, loads and compares to original - filename = str(tempfile.mkstemp(".hdf5")[1]) - m.save(bob.io.HDF5File(filename, 'w')) - m_loaded = bob.machine.PLDABase(bob.io.HDF5File(filename)) - - # Compares the values loaded with the former ones - self.assertTrue(m_loaded == m) - self.assertFalse(m_loaded != m) - self.assertTrue(equals(m_loaded.mu, mu, 1e-10)) - self.assertTrue(equals(m_loaded.f, C_F, 1e-10)) - self.assertTrue(equals(m_loaded.g, C_G, 1e-10)) - self.assertTrue(equals(m_loaded.sigma, sigma, 1e-10)) - self.assertTrue(equals(m_loaded.__isigma__, isigma, 1e-10)) - self.assertTrue(equals(m_loaded.__alpha__, alpha, 1e-10)) - self.assertTrue(equals(m_loaded.__beta__, beta, 1e-10)) - self.assertTrue(equals(m_loaded.__ft_beta__, FtBeta, 1e-10)) - self.assertTrue(equals(m_loaded.__gt_i_sigma__, GtISigma, 1e-10)) - self.assertTrue(abs(m_loaded.__logdet_alpha__ - logdetAlpha) < 1e-10) - self.assertTrue(abs(m_loaded.__logdet_sigma__ - logdetSigma) < 1e-10) - self.assertTrue(m_loaded.has_gamma(3)) - self.assertTrue(equals(m_loaded.get_gamma(3), gamma3_ref, 1e-10)) - self.assertTrue(equals(m_loaded.get_add_gamma(3), gamma3_ref, 1e-10)) - self.assertTrue(m_loaded.has_log_like_const_term(3)) - self.assertTrue(abs(m_loaded.get_add_log_like_const_term(3) - constTerm3) < 1e-10) - - # Compares the values loaded with the former ones when copying - m_copy = bob.machine.PLDABase(m_loaded) - self.assertTrue(m_loaded == m_copy) - self.assertFalse(m_loaded != m_copy) - # Test clear_maps method - self.assertTrue(m_copy.has_gamma(3)) - self.assertTrue(m_copy.has_log_like_const_term(3)) - m_copy.clear_maps() - self.assertFalse(m_copy.has_gamma(3)) - self.assertFalse(m_copy.has_log_like_const_term(3)) - - # Check variance flooring thresholds-related methods - v_zo = numpy.array([0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01]) - v_zo_ = 0.01 - v_zzo = numpy.array([0.001, 0.001, 0.001, 0.001, 0.001, 0.001, 0.001]) - v_zzo_ = 0.001 - m_copy.variance_threshold = v_zo_ - self.assertFalse(m_loaded == m_copy) - self.assertTrue(m_loaded != m_copy) - m_copy.variance_threshold = v_zzo_ - m_copy.sigma = v_zo - self.assertTrue(equals(m_copy.sigma, v_zo, 1e-10)) - m_copy.variance_threshold = v_zo_ - m_copy.sigma = v_zzo - self.assertTrue(equals(m_copy.sigma, v_zo, 1e-10)) - m_copy.variance_threshold = v_zzo_ - m_copy.sigma = v_zzo - self.assertTrue(equals(m_copy.sigma, v_zzo, 1e-10)) - m_copy.variance_threshold = v_zo_ - self.assertTrue(equals(m_copy.sigma, v_zo, 1e-10)) - - # Clean-up - os.unlink(filename) - - - def test02_plda_basemachine_loglikelihood_pointestimate(self): - # Data used for performing the tests - # Features and subspaces dimensionality - sigma = numpy.ndarray(C_dim_d, 'float64') - sigma.fill(0.01) - mu = numpy.ndarray(C_dim_d, 'float64') - mu.fill(0) - xij = numpy.array([0.7, 1.3, 2.5, 0.3, 1.3, 2.7, 0.9]) - hi = numpy.array([-0.5, 0.5]) - wij = numpy.array([-0.1, 0.2, 0.3]) - - m = bob.machine.PLDABase(C_dim_d, C_dim_f, C_dim_g) - # Sets the current mu, F, G and sigma - m.mu = mu - m.f = C_F - m.g = C_G - m.sigma = sigma - - self.assertTrue(equals(m.compute_log_likelihood_point_estimate(xij, hi, wij), - compute_log_likelihood_point_estimate(xij, mu, C_F, C_G, sigma, hi, wij), 1e-6)) - - - def test03_plda_machine(self): - # Data used for performing the tests - # Features and subspaces dimensionality - sigma = numpy.ndarray(C_dim_d, 'float64') - sigma.fill(0.01) - mu = numpy.ndarray(C_dim_d, 'float64') - mu.fill(0) - - # Defines base machine - mb = bob.machine.PLDABase(C_dim_d, C_dim_f, C_dim_g) - # Sets the current mu, F, G and sigma - mb.mu = mu - mb.f = C_F - mb.g = C_G - mb.sigma = sigma - - # Test constructors and dim getters - m = bob.machine.PLDAMachine(mb) - self.assertTrue(m.dim_d == C_dim_d) - self.assertTrue(m.dim_f == C_dim_f) - self.assertTrue(m.dim_g == C_dim_g) - - m0 = bob.machine.PLDAMachine() - m0.plda_base = mb - self.assertTrue(m0.dim_d == C_dim_d) - self.assertTrue(m0.dim_f == C_dim_f) - self.assertTrue(m0.dim_g == C_dim_g) - - # Defines machine - n_samples = 2 - WSumXitBetaXi = 0.37 - weightedSum = numpy.array([1.39,0.54], 'float64') - log_likelihood = -0.22 - - m.n_samples = n_samples - m.w_sum_xit_beta_xi = WSumXitBetaXi - m.weighted_sum = weightedSum - m.log_likelihood = log_likelihood - - gamma3 = m.get_add_gamma(3).copy() - constTerm3 = m.get_add_log_like_const_term(3) - - # Saves to file, loads and compares to original - filename = str(tempfile.mkstemp(".hdf5")[1]) - m.save(bob.io.HDF5File(filename, 'w')) - m_loaded = bob.machine.PLDAMachine(bob.io.HDF5File(filename), mb) - - # Compares the values loaded with the former ones - self.assertTrue(m_loaded == m) - self.assertFalse(m_loaded != m) - self.assertTrue(abs(m_loaded.n_samples - n_samples) < 1e-10) - self.assertTrue(abs(m_loaded.w_sum_xit_beta_xi - WSumXitBetaXi) < 1e-10) - self.assertTrue(equals(m_loaded.weighted_sum, weightedSum, 1e-10)) - self.assertTrue(abs(m_loaded.log_likelihood - log_likelihood) < 1e-10) - self.assertTrue(m_loaded.has_gamma(3)) - self.assertTrue(equals(m_loaded.get_add_gamma(3), gamma3, 1e-10)) - self.assertTrue(equals(m_loaded.get_gamma(3), gamma3, 1e-10)) - self.assertTrue(m_loaded.has_log_like_const_term(3)) - self.assertTrue(abs(m_loaded.get_add_log_like_const_term(3) - constTerm3) < 1e-10) - self.assertTrue(abs(m_loaded.get_log_like_const_term(3) - constTerm3) < 1e-10) - - # Test clear_maps method - self.assertTrue(m_loaded.has_gamma(3)) - self.assertTrue(m_loaded.has_log_like_const_term(3)) - m_loaded.clear_maps() - self.assertFalse(m_loaded.has_gamma(3)) - self.assertFalse(m_loaded.has_log_like_const_term(3)) - - # Check exceptions - m_loaded2 = bob.machine.PLDAMachine() - m_loaded2.load(bob.io.HDF5File(filename)) - self.assertRaises(RuntimeError, getattr, m_loaded2, 'dim_d') - self.assertRaises(RuntimeError, getattr, m_loaded2, 'dim_f') - self.assertRaises(RuntimeError, getattr, m_loaded2, 'dim_g') - self.assertRaises(RuntimeError, m_loaded2.forward, [1.]) - self.assertRaises(RuntimeError, m_loaded2.compute_log_likelihood, [1.]) - - # Clean-up - os.unlink(filename) - - - def test04_plda_machine_log_likelihood_Python(self): - # Data used for performing the tests - # Features and subspaces dimensionality - sigma = numpy.ndarray(C_dim_d, 'float64') - sigma.fill(0.01) - mu = numpy.ndarray(C_dim_d, 'float64') - mu.fill(0) - - # Defines base machine - mb = bob.machine.PLDABase(C_dim_d, C_dim_f, C_dim_g) - # Sets the current mu, F, G and sigma - mb.mu = mu - mb.f = C_F - mb.g = C_G - mb.sigma = sigma - - # Defines machine - m = bob.machine.PLDAMachine(mb) - - # Defines (random) samples and check compute_log_likelihood method - ar_e = numpy.random.randn(2,C_dim_d) - ar_p = numpy.random.randn(C_dim_d) - ar_s = numpy.vstack([ar_e, ar_p]) - self.assertTrue(abs(m.compute_log_likelihood(ar_s, False) - compute_log_likelihood(ar_s, mu, C_F, C_G, sigma)) < 1e-10) - ar_p2d = numpy.reshape(ar_p, (1,C_dim_d)) - self.assertTrue(abs(m.compute_log_likelihood(ar_p, False) - compute_log_likelihood(ar_p2d, mu, C_F, C_G, sigma)) < 1e-10) - - # Defines (random) samples and check forward method - ar2_e = numpy.random.randn(4,C_dim_d) - ar2_p = numpy.random.randn(C_dim_d) - ar2_s = numpy.vstack([ar2_e, ar2_p]) - m.log_likelihood = m.compute_log_likelihood(ar2_e, False) - llr = m.compute_log_likelihood(ar2_s, True) - (m.compute_log_likelihood(ar2_s, False) + m.log_likelihood) - self.assertTrue(abs(m.forward(ar2_s) - llr) < 1e-10) - ar2_p2d = numpy.random.randn(3,C_dim_d) - ar2_s2d = numpy.vstack([ar2_e, ar2_p2d]) - llr2d = m.compute_log_likelihood(ar2_s2d, True) - (m.compute_log_likelihood(ar2_s2d, False) + m.log_likelihood) - self.assertTrue(abs(m.forward(ar2_s2d) - llr2d) < 1e-10) - - - def test05_plda_machine_log_likelihood_Prince(self): - # Data used for performing the tests - # Features and subspaces dimensionality - D = 7 - nf = 2 - ng = 3 - - # initial values for F, G and sigma - G_init=numpy.array([-1.1424, -0.5044, -0.1917, - -0.6249, 0.1021, -0.8658, - -1.1687, 1.1963, 0.1807, - 0.3926, 0.1203, 1.2665, - 1.3018, -1.0368, -0.2512, - -0.5936, -0.8571, -0.2046, - 0.4364, -0.1699, -2.2015]).reshape(D,ng) - # F <-> PCA on G - F_init=numpy.array([-0.054222647972093, -0.000000000783146, - 0.596449127693018, 0.000000006265167, - 0.298224563846509, 0.000000003132583, - 0.447336845769764, 0.000000009397750, - -0.108445295944185, -0.000000001566292, - -0.501559493741856, -0.000000006265167, - -0.298224563846509, -0.000000003132583]).reshape(D,nf) - sigma_init = 0.01 * numpy.ones((D,), 'float64') - mean_zero = numpy.zeros((D,), 'float64') - - # base machine - mb = bob.machine.PLDABase(D,nf,ng) - mb.sigma = sigma_init - mb.g = G_init - mb.f = F_init - mb.mu = mean_zero - - # Data for likelihood computation - x1 = numpy.array([0.8032, 0.3503, 0.4587, 0.9511, 0.1330, 0.0703, 0.7061]) - x2 = numpy.array([0.9317, 0.1089, 0.6517, 0.1461, 0.6940, 0.6256, 0.0437]) - x3 = numpy.array([0.7979, 0.9862, 0.4367, 0.3447, 0.0488, 0.2252, 0.5810]) - X = numpy.ndarray((3,D), 'float64') - X[0,:] = x1 - X[1,:] = x2 - X[2,:] = x3 - a = [] - a.append(x1) - a.append(x2) - a.append(x3) - a = numpy.array(a) - - # reference likelihood from Prince implementation - ll_ref = -182.8880743535197 - - # machine - m = bob.machine.PLDAMachine(mb) - ll = m.compute_log_likelihood(X) - self.assertTrue(abs(ll - ll_ref) < 1e-10) - - # log likelihood ratio - Y = numpy.ndarray((2,D), 'float64') - Y[0,:] = x1 - Y[1,:] = x2 - Z = numpy.ndarray((1,D), 'float64') - Z[0,:] = x3 - llX = m.compute_log_likelihood(X) - llY = m.compute_log_likelihood(Y) - llZ = m.compute_log_likelihood(Z) - # reference obtained by computing the likelihood of [x1,x2,x3], [x1,x2] - # and [x3] separately - llr_ref = -4.43695386675 - self.assertTrue(abs((llX - (llY + llZ)) - llr_ref) < 1e-10) diff --git a/xbob/machine/test_roll.py b/xbob/machine/test_roll.py deleted file mode 100644 index be692d1..0000000 --- a/xbob/machine/test_roll.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Laurent El Shafey <Laurent.El-Shafey@idiap.ch> -# Tue Jun 25 20:44:40 CEST 2013 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Tests on the roll/unroll functions -""" - -import unittest -import bob -import numpy - -class RollTest(unittest.TestCase): - """Performs various roll/unroll tests.""" - - def test01_roll(self): - m = bob.machine.MLP((10,3,8,5)) - m.randomize() - - vec = bob.machine.unroll(m) - m2 = bob.machine.MLP((10,3,8,5)) - bob.machine.roll(m2, vec) - self.assertTrue( m == m2 ) - - m3 = bob.machine.MLP((10,3,8,5)) - vec = bob.machine.unroll(m.weights, m.biases) - bob.machine.roll(m3, vec) - self.assertTrue( m == m3 ) - - def test02_roll(self): - w = [numpy.array([[2,3.]]), numpy.array([[2,3,4.],[5,6,7]])] - b = [numpy.array([5.,]), numpy.array([7,8.])] - vec = numpy.ndarray(11, numpy.float64) - bob.machine.unroll(w, b, vec) - - w_ = [numpy.ndarray((1,2), numpy.float64), numpy.ndarray((2,3), numpy.float64)] - b_ = [numpy.ndarray(1, numpy.float64), numpy.ndarray(2, numpy.float64)] - bob.machine.roll(w_, b_, vec) - - self.assertTrue( (w_[0] == w[0]).all() ) - self.assertTrue( (b_[0] == b[0]).all() ) - diff --git a/xbob/machine/test_svm.py b/xbob/machine/test_svm.py deleted file mode 100644 index fca235e..0000000 --- a/xbob/machine/test_svm.py +++ /dev/null @@ -1,284 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Andre Anjos <andre.anjos@idiap.ch> -# Sat Dec 17 14:41:56 2011 +0100 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Run tests on the libsvm machine infrastructure. -""" - -import os, sys -import unittest -import math -import bob -import numpy -import tempfile -import pkg_resources -from ...test import utils - -def F(f): - """Returns the test file on the "data" subdirectory""" - return pkg_resources.resource_filename(__name__, os.path.join('data', f)) - -def tempname(suffix, prefix='bobtest_machine_'): - (fd, name) = tempfile.mkstemp(suffix, prefix) - os.close(fd) - os.unlink(name) - return name - -TEST_MACHINE_NO_PROBS = F('heart_no_probs.svmmodel') - -HEART_DATA = F('heart.svmdata') #13 inputs -HEART_MACHINE = F('heart.svmmodel') #supports probabilities -HEART_EXPECTED = F('heart.out') #expected probabilities - -IRIS_DATA = F('iris.svmdata') -IRIS_MACHINE = F('iris.svmmodel') -IRIS_EXPECTED = F('iris.out') #expected probabilities - -def load_expected(filename): - """Loads libsvm's svm-predict output file with probabilities""" - - f = open(filename, 'rt') - labels = [int(k) for k in f.readline().split()[1:]] - - predictions = [] - probabilities = [] - for k in f: #load the remaning lines - s = k.split() - predictions.append(int(s[0])) - probabilities.append(numpy.array([float(c) for c in s[1:]], 'float64')) - - return tuple(labels), tuple(predictions), tuple(probabilities) - -#extracted by running svm-predict.c on the heart_scale example data -expected_heart_predictions = (1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, - -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, - 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, - -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, - 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, - -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, - 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, - 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, - -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, - -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, - 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, - -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, - 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, - -1, -1, -1, -1, -1, -1, 1) - -expected_iris_predictions = (1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3) - -class SvmTest(unittest.TestCase): - """Performs various SVM tests.""" - - @utils.libsvm_available - def test01_can_load(self): - - machine = bob.machine.SupportVector(HEART_MACHINE) - self.assertEqual(machine.shape, (13,1)) - self.assertEqual(machine.kernel_type, bob.machine.svm_kernel_type.RBF) - self.assertEqual(machine.svm_type, bob.machine.svm_type.C_SVC) - self.assertEqual(len(machine.labels), 2) - self.assertTrue( -1 in machine.labels ) - self.assertTrue( +1 in machine.labels ) - self.assertTrue( abs(machine.gamma - 0.0769231) < 1e-6 ) - - @utils.libsvm_available - def test02_can_save(self): - - machine = bob.machine.SupportVector(HEART_MACHINE) - tmp = tempname('.model') - machine.save(tmp) - del machine - - # make sure that the save machine is the same as before - machine = bob.machine.SupportVector(tmp) - self.assertEqual(machine.shape, (13,1)) - self.assertEqual(machine.kernel_type, bob.machine.svm_kernel_type.RBF) - self.assertEqual(machine.svm_type, bob.machine.svm_type.C_SVC) - self.assertEqual(len(machine.labels), 2) - self.assertTrue( -1 in machine.labels ) - self.assertTrue( +1 in machine.labels ) - self.assertTrue( abs(machine.gamma - 0.0769231) < 1e-6 ) - - os.unlink(tmp) - - @utils.libsvm_available - def test02a_can_save_hdf5(self): - - machine = bob.machine.SupportVector(HEART_MACHINE) - tmp = tempname('.hdf5') - machine.save(bob.io.HDF5File(tmp, 'w')) - del machine - - # make sure that the save machine is the same as before - machine = bob.machine.SupportVector(bob.io.HDF5File(tmp)) - self.assertEqual(machine.shape, (13,1)) - self.assertEqual(machine.kernel_type, bob.machine.svm_kernel_type.RBF) - self.assertEqual(machine.svm_type, bob.machine.svm_type.C_SVC) - self.assertEqual(len(machine.labels), 2) - self.assertTrue( -1 in machine.labels ) - self.assertTrue( +1 in machine.labels ) - self.assertTrue( abs(machine.gamma - 0.0769231) < 1e-6 ) - self.assertTrue( numpy.all(abs(machine.input_subtract - 0) < 1e-10) ) - self.assertTrue( numpy.all(abs(machine.input_divide - 1) < 1e-10) ) - - os.unlink(tmp) - - @utils.libsvm_available - def test03_data_loading(self): - - #tests if I can load data in libsvm format using SVMFile - data = bob.machine.SVMFile(HEART_DATA) - self.assertEqual(data.shape, (13,)) - self.assertEqual(data.good(), True) - self.assertEqual(data.fail(), False) - self.assertEqual(data.eof(), False) - - #tries loading the data, one by one - all_data = [] - all_labels = [] - while data.good(): - values = numpy.ndarray(data.shape, 'float64') - label = data.read(values) - if label: - all_labels.append(label) - all_data.append(values) - all_labels = tuple(all_labels) - - self.assertEqual(len(all_data), len(all_labels)) - self.assertEqual(len(all_data), 270) - - #tries loading the data with numpy arrays allocated internally - counter = 0 - data.reset() - entry = data.read() - while entry: - self.assertEqual( entry[0], all_labels[counter] ) - self.assertTrue( numpy.array_equal(entry[1], all_data[counter]) ) - counter += 1 - entry = data.read() - - #tries loading the file all in a single shot - data.reset() - labels, data = data.read_all() - self.assertEqual(labels, all_labels) - for k, l in zip(data, all_data): - self.assertTrue( numpy.array_equal(k, l) ) - - #makes sure the first 3 examples are correctly read - ex = [] - ex.append(numpy.array([0.708333 , 1, 1, -0.320755 , -0.105023 , -1, 1, - -0.419847 ,-1, -0.225806 ,0. ,1, -1], 'float64')) - ex.append(numpy.array([0.583333, -1, 0.333333, -0.603774, 1, -1, 1, - 0.358779, -1, -0.483871, 0., -1, 1], 'float64')) - ex.append(numpy.array([0.166667, 1, -0.333333, -0.433962, -0.383562, -1, - -1, 0.0687023, -1, -0.903226, -1, -1, 1], 'float64')) - ls = [+1, -1, +1] - for k, (l, e) in enumerate(zip(ls, ex)): - self.assertEqual( l, labels[k] ) - self.assertTrue ( numpy.array_equal(e, data[k]) ) - - @utils.libsvm_available - def test04_raises(self): - - #tests that the normal machine raises because probabilities are not - #supported on that model - machine = bob.machine.SupportVector(TEST_MACHINE_NO_PROBS) - labels, data = bob.machine.SVMFile(HEART_DATA).read_all() - data = numpy.vstack(data) - self.assertRaises(RuntimeError, machine.predict_classes_and_probabilities, - data) - - @utils.libsvm_available - def test05_correctness_heart(self): - - #tests the correctness of the libSVM bindings - machine = bob.machine.SupportVector(HEART_MACHINE) - labels, data = bob.machine.SVMFile(HEART_DATA).read_all() - data = numpy.vstack(data) - - pred_label = machine.predict_classes(data) - - self.assertEqual(pred_label, expected_heart_predictions) - - #finally, we test if the values also work fine. - pred_lab_values = [machine.predict_class_and_scores(k) for k in data] - - #tries the variant with multiple inputs - pred_labels2, pred_scores2 = machine.predict_classes_and_scores(data) - self.assertEqual( expected_heart_predictions, pred_labels2 ) - self.assertEqual( tuple([k[1] for k in pred_lab_values]), pred_scores2 ) - - #tries to get the probabilities - note: for some reason, when getting - #probabilities, the labels change, but notice the note bellow: - - # Note from the libSVM FAQ: - # Q: Why using the -b option does not give me better accuracy? - # There is absolutely no reason the probability outputs guarantee you - # better accuracy. The main purpose of this option is to provide you the - # probability estimates, but not to boost prediction accuracy. From our - # experience, after proper parameter selections, in general with and - # without -b have similar accuracy. Occasionally there are some - # differences. It is not recommended to compare the two under just a fixed - # parameter set as more differences will be observed. - all_labels, real_labels, real_probs = load_expected(HEART_EXPECTED) - - pred_labels, pred_probs = machine.predict_classes_and_probabilities(data) - self.assertEqual(pred_labels, real_labels) - self.assertTrue( numpy.all(abs(numpy.vstack(pred_probs) - - numpy.vstack(real_probs)) < 1e-6) ) - - @utils.libsvm_available - def test06_correctness_iris(self): - - #same test as above, but with a 3-class problem. - machine = bob.machine.SupportVector(IRIS_MACHINE) - labels, data = bob.machine.SVMFile(IRIS_DATA).read_all() - data = numpy.vstack(data) - - pred_label = machine.predict_classes(data) - - self.assertEqual(pred_label, expected_iris_predictions) - - #finally, we test if the values also work fine. - pred_lab_values = [machine.predict_class_and_scores(k) for k in data] - - #tries the variant with multiple inputs - pred_labels2, pred_scores2 = machine.predict_classes_and_scores(data) - self.assertEqual( expected_iris_predictions, pred_labels2 ) - self.assertTrue( numpy.all(abs(numpy.vstack([k[1] for k in - pred_lab_values]) - numpy.vstack(pred_scores2)) < 1e-20 ) ) - - #tries to get the probabilities - note: for some reason, when getting - #probabilities, the labels change, but notice the note bellow: - - all_labels, real_labels, real_probs = load_expected(IRIS_EXPECTED) - - pred_labels, pred_probs = machine.predict_classes_and_probabilities(data) - self.assertEqual(pred_labels, real_labels) - self.assertTrue( numpy.all(abs(numpy.vstack(pred_probs) - - numpy.vstack(real_probs)) < 1e-6) ) - - @utils.libsvm_available - def test07_correctness_inputsize_exceeds(self): - - #same test as above, but test for excess input - machine = bob.machine.SupportVector(IRIS_MACHINE) - labels, data = bob.machine.SVMFile(IRIS_DATA).read_all() - data = numpy.vstack(data) - - # add extra columns to the input data - data = numpy.hstack([data, numpy.ones((data.shape[0], 2), dtype=float)]) - - pred_label = machine.predict_classes(data) - - self.assertEqual(pred_label, expected_iris_predictions) diff --git a/xbob/machine/test_utils.py b/xbob/machine/test_utils.py deleted file mode 100644 index 2a91555..0000000 --- a/xbob/machine/test_utils.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Andre Anjos <andre.dos.anjos@gmail.com> -# Sun 2 Jun 16:09:29 2013 - -"""Utilities for checking gradients. -""" - -import numpy - -def estimate_gradient(f, x, epsilon=1e-4, args=()): - """Estimate the gradient for a given callable f - - Suppose you have a function :math:`f'(x)` that purportedly computes - :math`\frac{\partial f(x)}{\partial x}`. You'd like to check if :math:`f'(x)` - is outputting correct derivative values. You can then use this function to - estimate the gradient around a point and compare it to the output of - :math:`f'(x)`. The estimation can have a precision of up to a few decimal - houses. - - Imagine a random value for :math:`x`, called :math:`x_t` (for test). Now - imagine you modify one of the elements in :math:`x_t` so that - :math:`x_{t+\epsilon}` has that element added with a small (positive) value - :math:`\epsilon` and :math:`x_{t-\epsilon}` has the same value subtracted. - - In this case, one can use a truncated Taylor expansion of the derivative - to calculate the approximate supposed value: - - .. math:: - f'(x_t) \sim \frac{f(x_{t+\epsilon}) - f(x_{t-\epsilon})}{2\epsilon} - - The degree to which these two values should approximate each other will - depend on the details of :math:`f(x)`. But assuming :math:`\epsilon = - 10^{-4}`, you’ll usually find that the left- and right-hand sides of the - above will agree to at least 4 significant digits (and often many more). - - Keyword arguments: - - f - The function which you'd like to have the gradient estimated for. - - x - The input to ``f``. This must be the first parameter ``f`` receives. If - that is not the case, you must write a wrapper around ``f`` so it does the - parameter inversion and provide that wrapper instead. - - If f expects a multi-dimensional array, than this entry should be a - :py:class:`numpy.ndarray` with as many dimensions as required for f. - - precision - The epsilon step - - args (optional) - Extra arguments (a tuple) to ``f`` - - This function returns the estimated value for :math:`f'(x)` given ``x``. - - .. note:: - - Gradient estimation is a powerful tool for testing if a function is - correctly computing the derivative of another function, but can be quite - slow. It therefore is not a good replacement for writing specific code that - can compute the derivative of ``f``. - """ - epsilon = 1e-4 - - if isinstance(x, numpy.ndarray): - - retval = numpy.ndarray(x.shape, dtype=x.dtype) - for k in range(x.size): - xt_plus = x.copy() - xt_plus.flat[k] += epsilon - xt_minus = x.copy() - xt_minus.flat[k] -= epsilon - retval.flat[k] = (f(xt_plus,*args) - f(xt_minus,*args)) / (2*epsilon) - return retval - - else: # x is scalar - return (f(x+epsilon, *args) - f(x-epsilon, *args)) / (2*epsilon) - -def estimate_gradient_for_machine(machine, X, cost, target): - - def func(weights): - old = machine.weights - machine.weights = machine.roll(weights) - retval = cost.f(machine.forward(X), target).mean(axis=0).sum() - machine.weights = old - return retval - - weights = machine.unroll() - est = estimate(func, weights) - machine.weights = machine.roll(weights) - - return machine.roll(est) #format using the machine's organization diff --git a/xbob/machine/test_wiener.py b/xbob/machine/test_wiener.py deleted file mode 100644 index d1de97d..0000000 --- a/xbob/machine/test_wiener.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Laurent El Shafey <Laurent.El-Shafey@idiap.ch> -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Tests the WienerMachine -""" - -import os, sys -import unittest -import math -import bob -import numpy, numpy.random -import tempfile - -class WienerMachineTest(unittest.TestCase): - """Performs various WienerMachine tests.""" - - def test01_initialization(self): - - # Getters/Setters - m = bob.machine.WienerMachine(5,4,0.5) - self.assertEqual(m.height, 5) - self.assertEqual(m.width, 4) - self.assertEqual(m.shape, (5,4)) - m.height = 8 - m.width = 7 - self.assertEqual(m.height, 8) - self.assertEqual(m.width, 7) - self.assertEqual(m.shape, (8,7)) - m.shape = (5,6) - self.assertEqual(m.height, 5) - self.assertEqual(m.width, 6) - self.assertEqual(m.shape, (5,6)) - ps1 = 0.2 + numpy.fabs(numpy.random.randn(5,6)) - ps2 = 0.2 + numpy.fabs(numpy.random.randn(5,6)) - m.ps = ps1 - self.assertTrue( numpy.allclose(m.ps, ps1) ) - m.ps = ps2 - self.assertTrue( numpy.allclose(m.ps, ps2) ) - pn1 = 0.5 - m.pn = pn1 - self.assertTrue( abs(m.pn - pn1) < 1e-5 ) - var_thd = 1e-5 - m.variance_threshold = var_thd - self.assertTrue( abs(m.variance_threshold - var_thd) < 1e-5 ) - - # Comparison operators - m2 = bob.machine.WienerMachine(m) - self.assertTrue( m == m2 ) - self.assertFalse( m != m2 ) - m3 = bob.machine.WienerMachine(ps2, pn1) - m3.variance_threshold = var_thd - self.assertTrue( m == m3 ) - self.assertFalse( m != m3 ) - - # Computation of the Wiener filter W - w_py = 1 / (1. + m.pn / m.ps) - self.assertTrue( numpy.allclose(m.w, w_py) ) - - - def test02_load_save(self): - - m = bob.machine.WienerMachine(5,4,0.5) - - # Save and read from file - filename = str(tempfile.mkstemp(".hdf5")[1]) - m.save(bob.io.HDF5File(filename, 'w')) - m_loaded = bob.machine.WienerMachine(bob.io.HDF5File(filename)) - self.assertTrue( m == m_loaded ) - self.assertFalse( m != m_loaded ) - self.assertTrue(m.is_similar_to(m_loaded)) - # Make them different - m_loaded.variance_threshold = 0.001 - self.assertFalse( m == m_loaded ) - self.assertTrue( m != m_loaded ) - - # Clean-up - os.unlink(filename) - - - def test03_forward(self): - - ps = 0.2 + numpy.fabs(numpy.random.randn(5,6)) - pn = 0.5 - m = bob.machine.WienerMachine(ps,pn) - - # Python way - sample = numpy.random.randn(5,6) - sample_fft = bob.sp.fft(sample.astype(numpy.complex128)) - w = m.w - sample_fft_filtered = sample_fft * m.w - sample_filtered_py = numpy.absolute(bob.sp.ifft(sample_fft_filtered)) - - # Bob c++ way - sample_filtered0 = m.forward(sample) - sample_filtered1 = m(sample) - sample_filtered2 = numpy.zeros((5,6),numpy.float64) - m.forward_(sample, sample_filtered2) - sample_filtered3 = numpy.zeros((5,6),numpy.float64) - m.forward(sample, sample_filtered3) - sample_filtered4 = numpy.zeros((5,6),numpy.float64) - m(sample, sample_filtered4) - self.assertTrue( numpy.allclose(sample_filtered0, sample_filtered_py) ) - self.assertTrue( numpy.allclose(sample_filtered1, sample_filtered_py) ) - self.assertTrue( numpy.allclose(sample_filtered2, sample_filtered_py) ) - self.assertTrue( numpy.allclose(sample_filtered3, sample_filtered_py) ) - self.assertTrue( numpy.allclose(sample_filtered4, sample_filtered_py) ) diff --git a/xbob/machine/test_ztnorm.py b/xbob/machine/test_ztnorm.py deleted file mode 100644 index 9de2c37..0000000 --- a/xbob/machine/test_ztnorm.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Francois Moulin <Francois.Moulin@idiap.ch> -# Laurent El Shafey <Laurent.El-Shafey@idiap.ch> -# Tue Jul 19 15:33:20 2011 +0200 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""Tests on the ZTNorm function -""" - -import os, sys -import unittest -import numpy -import bob -import pkg_resources - -def F(f): - """Returns the test file on the "data" subdirectory""" - return pkg_resources.resource_filename(__name__, os.path.join('data', f)) - -def sameValue(vect_A, vect_B): - sameMatrix = numpy.zeros((vect_A.shape[0], vect_B.shape[0]), 'bool') - - for j in range(vect_A.shape[0]): - for i in range(vect_B.shape[0]): - sameMatrix[j, i] = (vect_A[j] == vect_B[i]) - - return sameMatrix - -def tnorm(A, C): - Cmean = numpy.mean(C, axis=0) - if C.shape[1] > 1: - Cstd = numpy.sqrt(numpy.sum((C - numpy.tile(Cmean.reshape(1,C.shape[1]), (C.shape[0],1))) ** 2, axis=0) / (C.shape[0]-1)) - else: - Cstd = numpy.ones(shape=(C.shape[1],), dtype=numpy.float64) - return (A - numpy.tile(Cmean.reshape(1,C.shape[1]), (A.shape[0],1))) / numpy.tile(Cstd.reshape(1,C.shape[1]), (A.shape[0],1)) - -def znorm(A, B): - Bmean = numpy.mean(B, axis=1) - if B.shape[1] > 1: - Bstd = numpy.sqrt(numpy.sum((B - numpy.tile(Bmean.reshape(B.shape[0],1), (1,B.shape[1]))) ** 2, axis=1) / (B.shape[1]-1)) - else: - Bstd = numpy.ones(shape=(B.shape[0],), dtype=numpy.float64) - - return (A - numpy.tile(Bmean.reshape(B.shape[0],1), (1,A.shape[1]))) / numpy.tile(Bstd.reshape(B.shape[0],1), (1,A.shape[1])) - -class ZTNormTest(unittest.TestCase): - """Performs various ZTNorm tests.""" - - def test01_ztnorm_simple(self): - # 3x5 - my_A = numpy.array([[1, 2, 3, 4, 5], - [6, 7, 8, 9, 8], - [7, 6, 5, 4, 3]],'float64') - # 3x4 - my_B = numpy.array([[5, 4, 7, 8],[9, 8, 7, 4],[5, 6, 3, 2]],'float64') - # 2x5 - my_C = numpy.array([[5, 4, 3, 2, 1],[2, 1, 2, 3, 4]],'float64') - # 2x4 - my_D = numpy.array([[8, 6, 4, 2],[0, 2, 4, 6]],'float64') - - # 4x1 - znorm_id = numpy.array([1, 2, 3, 4],'uint32') - # 2x1 - tnorm_id = numpy.array([1, 5],'uint32') - - scores = bob.machine.ztnorm(my_A, my_B, my_C, my_D, - sameValue(tnorm_id, znorm_id)) - - ref_scores = numpy.array([[-4.45473107e+00, -3.29289322e+00, -1.50519101e+01, -8.42086557e-01, 6.46544511e-03], [-8.27619927e-01, 7.07106781e-01, 1.13757710e+01, 2.01641412e+00, 7.63765080e-01], [ 2.52913570e+00, 2.70710678e+00, 1.24400233e+01, 7.07106781e-01, 6.46544511e-03]], 'float64') - - self.assertTrue((abs(scores - ref_scores) < 1e-7).all()) - - def test02_ztnorm_big(self): - my_A = bob.io.load(F("ztnorm_eval_eval.mat")) - my_B = bob.io.load(F("ztnorm_znorm_eval.mat")) - my_C = bob.io.load(F("ztnorm_eval_tnorm.mat")) - my_D = bob.io.load(F("ztnorm_znorm_tnorm.mat")) - - # ZT-Norm - ref_scores = bob.io.load(F("ztnorm_result.mat")) - scores = bob.machine.ztnorm(my_A, my_B, my_C, my_D) - self.assertTrue((abs(scores - ref_scores) < 1e-7).all()) - - # T-Norm - scores = bob.machine.tnorm(my_A, my_C) - scores_py = tnorm(my_A, my_C) - self.assertTrue((abs(scores - scores_py) < 1e-7).all()) - - # Z-Norm - scores = bob.machine.znorm(my_A, my_B) - scores_py = znorm(my_A, my_B) - self.assertTrue((abs(scores - scores_py) < 1e-7).all()) - - def test03_tnorm_simple(self): - # 3x5 - my_A = numpy.array([[1, 2, 3, 4, 5], - [6, 7, 8, 9, 8], - [7, 6, 5, 4, 3]],'float64') - # 2x5 - my_C = numpy.array([[5, 4, 3, 2, 1],[2, 1, 2, 3, 4]],'float64') - - zC = bob.machine.tnorm(my_A, my_C) - zC_py = tnorm(my_A, my_C) - self.assertTrue((abs(zC - zC_py) < 1e-7).all()) - - empty = numpy.zeros(shape=(0,0), dtype=numpy.float64) - zC = bob.machine.ztnorm(my_A, empty, my_C, empty) - self.assertTrue((abs(zC - zC_py) < 1e-7).all()) - - def test04_znorm_simple(self): - # 3x5 - my_A = numpy.array([[1, 2, 3, 4, 5], - [6, 7, 8, 9, 8], - [7, 6, 5, 4, 3]], numpy.float64) - # 3x4 - my_B = numpy.array([[5, 4, 7, 8],[9, 8, 7, 4],[5, 6, 3, 2]], numpy.float64) - - zA = bob.machine.znorm(my_A, my_B) - zA_py = znorm(my_A, my_B) - self.assertTrue((abs(zA - zA_py) < 1e-7).all()) - - empty = numpy.zeros(shape=(0,0), dtype=numpy.float64) - zA = bob.machine.ztnorm(my_A, my_B, empty, empty) - self.assertTrue((abs(zA - zA_py) < 1e-7).all()) diff --git a/xbob/machine/version.cc b/xbob/machine/version.cc deleted file mode 100644 index 1181e91..0000000 --- a/xbob/machine/version.cc +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file machine/python/version.cc - * @date Sat Dec 17 14:41:56 2011 +0100 - * @author AndreÌ Anjos <andre.dos.anjos@gmail.com> - * - * @brief Describes ways to retrieve version information about all dependent - * packages. - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob/config.h> - -#include <boost/python.hpp> -#include <boost/format.hpp> - -#if WITH_LIBSVM -#include <svm.h> -#endif - -using namespace boost::python; - -/** - * libsvm version - */ -static str get_libsvm_version() { -#if WITH_LIBSVM - boost::format s("%d.%d.%d"); - s % (LIBSVM_VERSION / 100); - s % ((LIBSVM_VERSION % 100) / 10); - s % (LIBSVM_VERSION % 10); - return str(s.str().c_str()); -#else - return str("unavailable"); -#endif -} - -void bind_machine_version() { - dict vdict; - vdict["libsvm"] = get_libsvm_version(); - scope().attr("version") = vdict; -} diff --git a/xbob/machine/wiener.cc b/xbob/machine/wiener.cc deleted file mode 100644 index 62aa17a..0000000 --- a/xbob/machine/wiener.cc +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @file machine/python/wiener.cc - * @date Fri Sep 30 16:58:42 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Bindings for a WienerMachine - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/python.hpp> -#include <bob/python/ndarray.h> -#include <bob/machine/WienerMachine.h> -#include <boost/shared_ptr.hpp> -#include <boost/make_shared.hpp> - -using namespace boost::python; - -static void py_forward1_(const bob::machine::WienerMachine& m, - bob::python::const_ndarray input, bob::python::ndarray output) -{ - blitz::Array<double,2> output_ = output.bz<double,2>(); - m.forward_(input.bz<double,2>(), output_); -} - -static void py_forward1(const bob::machine::WienerMachine& m, - bob::python::const_ndarray input, bob::python::ndarray output) -{ - blitz::Array<double,2> output_ = output.bz<double,2>(); - m.forward(input.bz<double,2>(), output_); -} - -static object py_forward2(const bob::machine::WienerMachine& m, - bob::python::const_ndarray input) -{ - const bob::core::array::typeinfo& info = input.type(); - bob::python::ndarray output(bob::core::array::t_float64, info.shape[0], info.shape[1]); - blitz::Array<double,2> output_ = output.bz<double,2>(); - m.forward(input.bz<double,2>(), output_); - return output.self(); -} - -static tuple get_shape(const bob::machine::WienerMachine& m) -{ - return make_tuple(m.getHeight(), m.getWidth()); -} - -static void set_shape(bob::machine::WienerMachine& m, - const blitz::TinyVector<int,2>& s) -{ - m.resize(s(0), s(1)); -} - -static void py_set_ps(bob::machine::WienerMachine& m, - bob::python::const_ndarray ps) -{ - m.setPs(ps.bz<double,2>()); -} - -void bind_machine_wiener() -{ - class_<bob::machine::WienerMachine, boost::shared_ptr<bob::machine::WienerMachine> >("WienerMachine", "A Wiener filter.\nReference:\n'Computer Vision: Algorithms and Applications', Richard Szeliski, (Part 3.4.3)", init<const size_t, const size_t, const double, optional<const double> >((arg("self"), arg("height"), arg("width"), arg("pn"), arg("variance_threshold")=1e-8), "Constructs a new Wiener filter dedicated to images of the given dimensions. The filter is initialized with zero values.")) - .def(init<const blitz::Array<double,2>&, const double> ((arg("self"), arg("ps"), arg("pn")), "Constructs a new WienerMachine from a set of variance estimates ps, a noise level pn.")) - .def(init<>((arg("self")), "Default constructor, builds a machine as with 'WienerMachine(0,0,0)'.")) - .def(init<bob::io::HDF5File&>((arg("self"), arg("config")), "Constructs a new WienerMachine from a configuration file.")) - .def(init<const bob::machine::WienerMachine&>((arg("self"), arg("machine")), "Copy constructs an WienerMachine")) - .def(self == self) - .def(self != self) - .def("is_similar_to", &bob::machine::WienerMachine::is_similar_to, (arg("self"), arg("other"), arg("r_epsilon")=1e-5, arg("a_epsilon")=1e-8), "Compares this WienerMachine with the 'other' one to be approximately the same.") - .def("load", &bob::machine::WienerMachine::load, (arg("self"), arg("config")), "Loads the filter from a configuration file.") - .def("save", &bob::machine::WienerMachine::save, (arg("self"), arg("config")), "Saves the filter to a configuration file.") - .add_property("pn", &bob::machine::WienerMachine::getPn, &bob::machine::WienerMachine::setPn, "Noise level Pn") - .add_property("variance_threshold", &bob::machine::WienerMachine::getVarianceThreshold, &bob::machine::WienerMachine::setVarianceThreshold, "Variance flooring threshold (min variance value)") - .add_property("ps",make_function(&bob::machine::WienerMachine::getPs, return_value_policy<copy_const_reference>()), &py_set_ps, "Variance Ps estimated at each frequency") - .add_property("w", make_function(&bob::machine::WienerMachine::getW, return_value_policy<copy_const_reference>()), "The Wiener filter W (W=1/(1+Pn/Ps)) (read-only)") - .add_property("height", &bob::machine::WienerMachine::getHeight, &bob::machine::WienerMachine::setHeight, "Height of the filter/image to process") - .add_property("width", &bob::machine::WienerMachine::getWidth, &bob::machine::WienerMachine::setWidth, "Width of the filter/image to process") - .add_property("shape", &get_shape, &set_shape) - .def("__call__", &py_forward1, (arg("self"), arg("input"), arg("output")), "Filters the input and saves results on the output.") - .def("forward", &py_forward1, (arg("self"), arg("input"), arg("output")), "Filters the input and saves results on the output.") - .def("forward_", &py_forward1_, (arg("self"), arg("input"), arg("output")), "Filters the input and saves results on the output. Input is not checked.") - .def("__call__", &py_forward2, (arg("self"), arg("input")), "Filters the input and returns the output. This method implies in copying out the output data and is, therefore, less efficient as its counterpart that sets the output given as parameter. If you have to do a tight loop, consider using that variant instead of this one.") - .def("forward", &py_forward2, (arg("self"), arg("input")), "Filter the input and returns the output. This method implies in copying out the output data and is, therefore, less efficient as its counterpart that sets the output given as parameter. If you have to do a tight loop, consider using that variant instead of this one.") - ; -} diff --git a/xbob/machine/ztnorm.cc b/xbob/machine/ztnorm.cc deleted file mode 100644 index 4b604a3..0000000 --- a/xbob/machine/ztnorm.cc +++ /dev/null @@ -1,154 +0,0 @@ -/** - * @file machine/python/ztnorm.cc - * @date Tue Jul 19 15:33:20 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Binds ZT-normalization to python - * - * Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob/python/ndarray.h> - -#include <boost/python.hpp> -#include <bob/machine/ZTNorm.h> - -using namespace boost::python; - -static object ztnorm1( - bob::python::const_ndarray rawscores_probes_vs_models, - bob::python::const_ndarray rawscores_zprobes_vs_models, - bob::python::const_ndarray rawscores_probes_vs_tmodels, - bob::python::const_ndarray rawscores_zprobes_vs_tmodels, - bob::python::const_ndarray mask_zprobes_vs_tmodels_istruetrial) -{ - const blitz::Array<double,2> rawscores_probes_vs_models_ = - rawscores_probes_vs_models.bz<double,2>(); - const blitz::Array<double,2> rawscores_zprobes_vs_models_ = - rawscores_zprobes_vs_models.bz<double,2>(); - const blitz::Array<double,2> rawscores_probes_vs_tmodels_ = - rawscores_probes_vs_tmodels.bz<double,2>(); - const blitz::Array<double,2> rawscores_zprobes_vs_tmodels_ = - rawscores_zprobes_vs_tmodels.bz<double,2>(); - const blitz::Array<bool,2> mask_zprobes_vs_tmodels_istruetrial_ = - mask_zprobes_vs_tmodels_istruetrial.bz<bool,2>(); - - // allocate output - bob::python::ndarray ret(bob::core::array::t_float64, rawscores_probes_vs_models_.extent(0), rawscores_probes_vs_models_.extent(1)); - blitz::Array<double, 2> ret_ = ret.bz<double,2>(); - - bob::machine::ztNorm(rawscores_probes_vs_models_, - rawscores_zprobes_vs_models_, - rawscores_probes_vs_tmodels_, - rawscores_zprobes_vs_tmodels_, - mask_zprobes_vs_tmodels_istruetrial_, - ret_); - - return ret.self(); -} - -static object ztnorm2( - bob::python::const_ndarray rawscores_probes_vs_models, - bob::python::const_ndarray rawscores_zprobes_vs_models, - bob::python::const_ndarray rawscores_probes_vs_tmodels, - bob::python::const_ndarray rawscores_zprobes_vs_tmodels) -{ - const blitz::Array<double,2> rawscores_probes_vs_models_ = - rawscores_probes_vs_models.bz<double,2>(); - const blitz::Array<double,2> rawscores_zprobes_vs_models_ = - rawscores_zprobes_vs_models.bz<double,2>(); - const blitz::Array<double,2> rawscores_probes_vs_tmodels_ = - rawscores_probes_vs_tmodels.bz<double,2>(); - const blitz::Array<double,2> rawscores_zprobes_vs_tmodels_ = - rawscores_zprobes_vs_tmodels.bz<double,2>(); - - // allocate output - bob::python::ndarray ret(bob::core::array::t_float64, rawscores_probes_vs_models_.extent(0), rawscores_probes_vs_models_.extent(1)); - blitz::Array<double, 2> ret_ = ret.bz<double,2>(); - - bob::machine::ztNorm(rawscores_probes_vs_models_, - rawscores_zprobes_vs_models_, - rawscores_probes_vs_tmodels_, - rawscores_zprobes_vs_tmodels_, - ret_); - - return ret.self(); -} - -static object tnorm( - bob::python::const_ndarray rawscores_probes_vs_models, - bob::python::const_ndarray rawscores_probes_vs_tmodels) -{ - const blitz::Array<double,2> rawscores_probes_vs_models_ = - rawscores_probes_vs_models.bz<double,2>(); - const blitz::Array<double,2> rawscores_probes_vs_tmodels_ = - rawscores_probes_vs_tmodels.bz<double,2>(); - - // allocate output - bob::python::ndarray ret(bob::core::array::t_float64, rawscores_probes_vs_models_.extent(0), rawscores_probes_vs_models_.extent(1)); - blitz::Array<double, 2> ret_ = ret.bz<double,2>(); - - bob::machine::tNorm(rawscores_probes_vs_models_, - rawscores_probes_vs_tmodels_, - ret_); - - return ret.self(); -} - -static object znorm( - bob::python::const_ndarray rawscores_probes_vs_models, - bob::python::const_ndarray rawscores_zprobes_vs_models) -{ - const blitz::Array<double,2> rawscores_probes_vs_models_ = - rawscores_probes_vs_models.bz<double,2>(); - const blitz::Array<double,2> rawscores_zprobes_vs_models_ = - rawscores_zprobes_vs_models.bz<double,2>(); - - // allocate output - bob::python::ndarray ret(bob::core::array::t_float64, rawscores_probes_vs_models_.extent(0), rawscores_probes_vs_models_.extent(1)); - blitz::Array<double, 2> ret_ = ret.bz<double,2>(); - - bob::machine::zNorm(rawscores_probes_vs_models_, - rawscores_zprobes_vs_models_, - ret_); - - return ret.self(); -} - -void bind_machine_ztnorm() -{ - def("ztnorm", - ztnorm1, - args("rawscores_probes_vs_models", - "rawscores_zprobes_vs_models", - "rawscores_probes_vs_tmodels", - "rawscores_zprobes_vs_tmodels", - "mask_zprobes_vs_tmodels_istruetrial"), - "Normalise raw scores with ZT-Norm" - ); - - def("ztnorm", - ztnorm2, - args("rawscores_probes_vs_models", - "rawscores_zprobes_vs_models", - "rawscores_probes_vs_tmodels", - "rawscores_zprobes_vs_tmodels"), - "Normalise raw scores with ZT-Norm. Assume that znorm and tnorm have no common subject id." - ); - - def("tnorm", - tnorm, - args("rawscores_probes_vs_models", - "rawscores_probes_vs_tmodels"), - "Normalise raw scores with T-Norm." - ); - - def("znorm", - znorm, - args("rawscores_probes_vs_models", - "rawscores_zprobes_vs_models"), - "Normalise raw scores with Z-Norm." - ); - -} -- GitLab