diff --git a/bob/learn/em/__init__.py b/bob/learn/em/__init__.py index 44e6b51988b903eccb68875662a682f84bb59233..99d4c77a77bedb426a1ff588e3bd2c7b24edd79e 100644 --- a/bob/learn/em/__init__.py +++ b/bob/learn/em/__init__.py @@ -1,215 +1,13 @@ -# import Libraries of other lib packages -import bob.io.base -import bob.math -import bob.learn.linear -import bob.sp +from . import cluster +from . import mixture -# import our own Library import bob.extension -bob.extension.load_bob_library("bob.learn.em", __file__) - -from ._library import * -from ._library import GMMMachine as _GMMMachine_C -from ._library import ISVBase as _ISVBase_C -from ._library import ISVMachine as _ISVMachine_C -from ._library import KMeansMachine as _KMeansMachine_C -from ._library import GMMStats as _GMMStats_C -from ._library import IVectorMachine as _IVectorMachine_C - -from . import version -from .version import module as __version__ -from .version import api as __api_version__ -from .train import * - - def get_config(): - """Returns a string containing the configuration information. - """ - return bob.extension.get_config(__name__, version.externals, version.api) + """Returns a string containing the configuration information.""" + return bob.extension.get_config(__name__) # gets sphinx autodoc done right - don't remove it __all__ = [_ for _ in dir() if not _.startswith("_")] - -class GMMMachine(_GMMMachine_C): - __doc__ = _GMMMachine_C.__doc__ - - def update_dict(self, d): - self.means = d["means"] - self.variances = d["variances"] - self.weights = d["weights"] - - @staticmethod - def gmm_shape_from_dict(d): - return d["means"].shape - - @classmethod - def create_from_dict(cls, d): - shape = GMMMachine.gmm_shape_from_dict(d) - gmm_machine = cls(shape[0], shape[1]) - gmm_machine.update_dict(d) - return gmm_machine - - @staticmethod - def to_dict(gmm_machine): - gmm_data = dict() - gmm_data["means"] = gmm_machine.means - gmm_data["variances"] = gmm_machine.variances - gmm_data["weights"] = gmm_machine.weights - return gmm_data - - def __getstate__(self): - d = dict(self.__dict__) - d.update(self.__class__.to_dict(self)) - return d - - def __setstate__(self, d): - self.__dict__ = d - shape = self.gmm_shape_from_dict(d) - self.__init__(shape[0], shape[1]) - self.update_dict(d) - - -class ISVBase(_ISVBase_C): - __doc__ = _ISVBase_C.__doc__ - - @staticmethod - def to_dict(isv_base): - isv_data = dict() - isv_data["gmm"] = GMMMachine.to_dict(isv_base.ubm) - isv_data["u"] = isv_base.u - isv_data["d"] = isv_base.d - - return isv_data - - def update_dict(self, d): - ubm = GMMMachine.create_from_dict(d["gmm"]) - u = d["u"] - self.__init__(ubm, u.shape[1]) - self.u = u - self.d = d["d"] - - @classmethod - def create_from_dict(cls, d): - ubm = GMMMachine.create_from_dict(d["gmm"]) - ru = d["u"].shape[1] - isv_base = ISVBase(ubm, ru) - isv_base.u = d["u"] - isv_base.d = d["d"] - return isv_base - - def __getstate__(self): - d = dict(self.__dict__) - d.update(self.__class__.to_dict(self)) - return d - - def __setstate__(self, d): - self.__dict__ = d - self.update_dict(d) - - -class ISVMachine(_ISVMachine_C): - __doc__ = _ISVMachine_C.__doc__ - - @staticmethod - def to_dict(isv_machine): - isv_data = dict() - isv_data["x"] = isv_machine.x - isv_data["z"] = isv_machine.z - isv_data["isv_base"] = ISVBase.to_dict(isv_machine.isv_base) - - return isv_data - - def update_dict(self, d): - isv_base = ISVBase.create_from_dict(d["isv_base"]) - self.__init__(isv_base) - self.x = d["x"] - self.z = d["z"] - - def __getstate__(self): - d = dict(self.__dict__) - d.update(self.__class__.to_dict(self)) - return d - - def __setstate__(self, d): - self.__dict__ = d - self.update_dict(d) - - -class KMeansMachine(_KMeansMachine_C): - __doc__ = _KMeansMachine_C.__doc__ - - @staticmethod - def to_dict(kmeans_machine): - kmeans_data = dict() - kmeans_data["means"] = kmeans_machine.means - return kmeans_data - - def __getstate__(self): - d = dict(self.__dict__) - d.update(self.__class__.to_dict(self)) - return d - - def __setstate__(self, d): - means = d["means"] - self.__init__(means.shape[0], means.shape[1]) - self.means = means - - -class GMMStats(_GMMStats_C): - __doc__ = _GMMStats_C.__doc__ - - @staticmethod - def to_dict(gmm_stats): - gmm_stats_data = dict() - gmm_stats_data["log_likelihood"] = gmm_stats.log_likelihood - gmm_stats_data["t"] = gmm_stats.t - gmm_stats_data["n"] = gmm_stats.n - gmm_stats_data["sum_px"] = gmm_stats.sum_px - gmm_stats_data["sum_pxx"] = gmm_stats.sum_pxx - return gmm_stats_data - - def __getstate__(self): - d = dict(self.__dict__) - d.update(self.__class__.to_dict(self)) - return d - - def __setstate__(self, d): - shape = d["sum_pxx"].shape - self.__init__(shape[0], shape[1]) - self.t = d["t"] - self.n = d["n"] - self.log_likelihood = d["log_likelihood"] - self.sum_px = d["sum_px"] - self.sum_pxx = d["sum_pxx"] - - -class IVectorMachine(_IVectorMachine_C): - __doc__ = _IVectorMachine_C.__doc__ - - @staticmethod - def to_dict(ivector_machine): - ivector_data = dict() - ivector_data["gmm"] = GMMMachine.to_dict(ivector_machine.ubm) - ivector_data["sigma"] = ivector_machine.sigma - ivector_data["t"] = ivector_machine.t - - return ivector_data - - def update_dict(self, d): - ubm = GMMMachine.create_from_dict(d["gmm"]) - t = d["t"] - self.__init__(ubm, t.shape[1]) - self.sigma = d["sigma"] - self.t = t - - def __getstate__(self): - d = dict(self.__dict__) - d.update(self.__class__.to_dict(self)) - return d - - def __setstate__(self, d): - self.__dict__ = d - self.update_dict(d) diff --git a/bob/learn/em/cpp/EMPCATrainer.cpp b/bob/learn/em/cpp/EMPCATrainer.cpp deleted file mode 100644 index 1217be261cb83818373990f97312ce8670f8d47f..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/EMPCATrainer.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/** - * @date Tue Oct 11 12:18:23 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <vector> -#include <algorithm> -#include <boost/random.hpp> -#include <cmath> - -#include <bob.learn.em/EMPCATrainer.h> -#include <bob.core/array_copy.h> -#include <bob.core/check.h> -#include <bob.math/linear.h> -#include <bob.math/det.h> -#include <bob.math/inv.h> -#include <bob.math/pinv.h> -#include <bob.math/stats.h> - -bob::learn::em::EMPCATrainer::EMPCATrainer(bool compute_likelihood): - m_compute_likelihood(compute_likelihood), - m_rng(new boost::mt19937()), - m_S(0,0), - m_z_first_order(0,0), m_z_second_order(0,0,0), - m_inW(0,0), m_invM(0,0), m_sigma2(0), m_f_log2pi(0), - m_tmp_dxf(0,0), m_tmp_d(0), m_tmp_f(0), - m_tmp_dxd_1(0,0), m_tmp_dxd_2(0,0), - m_tmp_fxd_1(0,0), m_tmp_fxd_2(0,0), - m_tmp_fxf_1(0,0), m_tmp_fxf_2(0,0) -{ -} - -bob::learn::em::EMPCATrainer::EMPCATrainer(const bob::learn::em::EMPCATrainer& other): - m_compute_likelihood(other.m_compute_likelihood), - m_rng(other.m_rng), - m_S(bob::core::array::ccopy(other.m_S)), - m_z_first_order(bob::core::array::ccopy(other.m_z_first_order)), - m_z_second_order(bob::core::array::ccopy(other.m_z_second_order)), - m_inW(bob::core::array::ccopy(other.m_inW)), - m_invM(bob::core::array::ccopy(other.m_invM)), - m_sigma2(other.m_sigma2), m_f_log2pi(other.m_f_log2pi), - m_tmp_dxf(bob::core::array::ccopy(other.m_tmp_dxf)), - m_tmp_d(bob::core::array::ccopy(other.m_tmp_d)), - m_tmp_f(bob::core::array::ccopy(other.m_tmp_f)), - m_tmp_dxd_1(bob::core::array::ccopy(other.m_tmp_dxd_1)), - m_tmp_dxd_2(bob::core::array::ccopy(other.m_tmp_dxd_2)), - m_tmp_fxd_1(bob::core::array::ccopy(other.m_tmp_fxd_1)), - m_tmp_fxd_2(bob::core::array::ccopy(other.m_tmp_fxd_2)), - m_tmp_fxf_1(bob::core::array::ccopy(other.m_tmp_fxf_1)), - m_tmp_fxf_2(bob::core::array::ccopy(other.m_tmp_fxf_2)) -{ -} - -bob::learn::em::EMPCATrainer::~EMPCATrainer() -{ -} - -bob::learn::em::EMPCATrainer& bob::learn::em::EMPCATrainer::operator= - (const bob::learn::em::EMPCATrainer& other) -{ - if (this != &other) - { - m_rng = other.m_rng; - m_compute_likelihood = other.m_compute_likelihood; - m_S = bob::core::array::ccopy(other.m_S); - m_z_first_order = bob::core::array::ccopy(other.m_z_first_order); - m_z_second_order = bob::core::array::ccopy(other.m_z_second_order); - m_inW = bob::core::array::ccopy(other.m_inW); - m_invM = bob::core::array::ccopy(other.m_invM); - m_sigma2 = other.m_sigma2; - m_f_log2pi = other.m_f_log2pi; - m_tmp_dxf = bob::core::array::ccopy(other.m_tmp_dxf); - m_tmp_d = bob::core::array::ccopy(other.m_tmp_d); - m_tmp_f = bob::core::array::ccopy(other.m_tmp_f); - m_tmp_dxd_1 = bob::core::array::ccopy(other.m_tmp_dxd_1); - m_tmp_dxd_2 = bob::core::array::ccopy(other.m_tmp_dxd_2); - m_tmp_fxd_1 = bob::core::array::ccopy(other.m_tmp_fxd_1); - m_tmp_fxd_2 = bob::core::array::ccopy(other.m_tmp_fxd_2); - m_tmp_fxf_1 = bob::core::array::ccopy(other.m_tmp_fxf_1); - m_tmp_fxf_2 = bob::core::array::ccopy(other.m_tmp_fxf_2); - } - return *this; -} - -bool bob::learn::em::EMPCATrainer::operator== - (const bob::learn::em::EMPCATrainer &other) const -{ - return m_compute_likelihood == other.m_compute_likelihood && - m_rng == other.m_rng && - bob::core::array::isEqual(m_S, other.m_S) && - bob::core::array::isEqual(m_z_first_order, other.m_z_first_order) && - bob::core::array::isEqual(m_z_second_order, other.m_z_second_order) && - bob::core::array::isEqual(m_inW, other.m_inW) && - bob::core::array::isEqual(m_invM, other.m_invM) && - m_sigma2 == other.m_sigma2 && - m_f_log2pi == other.m_f_log2pi; -} - -bool bob::learn::em::EMPCATrainer::operator!= - (const bob::learn::em::EMPCATrainer &other) const -{ - return !(this->operator==(other)); -} - -bool bob::learn::em::EMPCATrainer::is_similar_to - (const bob::learn::em::EMPCATrainer &other, const double r_epsilon, - const double a_epsilon) const -{ - return m_compute_likelihood == other.m_compute_likelihood && - m_rng == other.m_rng && - bob::core::array::isClose(m_S, other.m_S, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_z_first_order, other.m_z_first_order, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_z_second_order, other.m_z_second_order, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_inW, other.m_inW, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_invM, other.m_invM, r_epsilon, a_epsilon) && - bob::core::isClose(m_sigma2, other.m_sigma2, r_epsilon, a_epsilon) && - bob::core::isClose(m_f_log2pi, other.m_f_log2pi, r_epsilon, a_epsilon); -} - -void bob::learn::em::EMPCATrainer::initialize(bob::learn::linear::Machine& machine, - const blitz::Array<double,2>& ar) -{ - // reinitializes array members and checks dimensionality - initMembers(machine, ar); - - // computes the mean and the covariance if required - computeMeanVariance(machine, ar); - - // Random initialization of W and sigma2 - initRandomWSigma2(machine); - - // Computes the product m_inW = W^T.W - computeWtW(machine); - // Computes inverse(M), where M = Wt * W + sigma2 * Id - computeInvM(); -} - - -void bob::learn::em::EMPCATrainer::initMembers( - const bob::learn::linear::Machine& machine, - const blitz::Array<double,2>& ar) -{ - // Gets dimensions - const size_t n_samples = ar.extent(0); - const size_t n_features = ar.extent(1); - - // Checks that the dimensions are matching - const size_t n_inputs = machine.inputSize(); - const size_t n_outputs = machine.outputSize(); - - // Checks that the dimensions are matching - if (n_inputs != n_features) { - boost::format m("number of inputs (%u) does not match the number of features (%u)"); - m % n_inputs % n_features; - throw std::runtime_error(m.str()); - } - - // Covariance matrix S is only required to compute the log likelihood - if (m_compute_likelihood) - m_S.resize(n_features,n_features); - else - m_S.resize(0,0); - m_z_first_order.resize(n_samples, n_outputs); - m_z_second_order.resize(n_samples, n_outputs, n_outputs); - m_inW.resize(n_outputs, n_outputs); - m_invM.resize(n_outputs, n_outputs); - m_sigma2 = 0.; - m_f_log2pi = n_features * log(2*M_PI); - - // Cache - m_tmp_dxf.resize(n_outputs, n_features); - m_tmp_d.resize(n_outputs); - m_tmp_f.resize(n_features); - - m_tmp_dxd_1.resize(n_outputs, n_outputs); - m_tmp_dxd_2.resize(n_outputs, n_outputs); - m_tmp_fxd_1.resize(n_features, n_outputs); - m_tmp_fxd_2.resize(n_features, n_outputs); - // The following large cache matrices are only required to compute the - // log likelihood. - if (m_compute_likelihood) - { - m_tmp_fxf_1.resize(n_features, n_features); - m_tmp_fxf_2.resize(n_features, n_features); - } - else - { - m_tmp_fxf_1.resize(0,0); - m_tmp_fxf_2.resize(0,0); - } -} - -void bob::learn::em::EMPCATrainer::computeMeanVariance(bob::learn::linear::Machine& machine, - const blitz::Array<double,2>& ar) -{ - size_t n_samples = ar.extent(0); - blitz::Array<double,1> mu = machine.updateInputSubtraction(); - blitz::Range all = blitz::Range::all(); - if (m_compute_likelihood) - { - // Mean and scatter computation - bob::math::scatter(ar, m_S, mu); - // divides scatter by N-1 - m_S /= static_cast<double>(n_samples-1); - } - else - { - // computes the mean and updates mu - mu = 0.; - for (size_t i=0; i<n_samples; ++i) - mu += ar(i,all); - mu /= static_cast<double>(n_samples); - } -} - -void bob::learn::em::EMPCATrainer::initRandomWSigma2(bob::learn::linear::Machine& machine) -{ - // Initializes the random number generator - boost::uniform_01<> range01; - boost::variate_generator<boost::mt19937&, boost::uniform_01<> > die(*m_rng, range01); - - // W initialization (TODO: add method in core) - blitz::Array<double,2> W = machine.updateWeights(); - double ratio = 2.; /// Follows matlab implementation using a ratio of 2 - for (int i=0; i<W.extent(0); ++i) - for (int j=0; j<W.extent(1); ++j) - W(i,j) = die() * ratio; - // sigma2 initialization - m_sigma2 = die() * ratio; -} - -void bob::learn::em::EMPCATrainer::computeWtW(bob::learn::linear::Machine& machine) -{ - const blitz::Array<double,2> W = machine.getWeights(); - const blitz::Array<double,2> Wt = W.transpose(1,0); - bob::math::prod(Wt, W, m_inW); -} - -void bob::learn::em::EMPCATrainer::computeInvM() -{ - // Compute inverse(M), where M = W^T * W + sigma2 * Id - bob::math::eye(m_tmp_dxd_1); // m_tmp_dxd_1 = Id - m_tmp_dxd_1 *= m_sigma2; // m_tmp_dxd_1 = sigma2 * Id - m_tmp_dxd_1 += m_inW; // m_tmp_dxd_1 = M = W^T * W + sigma2 * Id - bob::math::inv(m_tmp_dxd_1, m_invM); // m_invM = inv(M) -} - - - -void bob::learn::em::EMPCATrainer::eStep(bob::learn::linear::Machine& machine, const blitz::Array<double,2>& ar) -{ - // Gets mu and W from the machine - const blitz::Array<double,1>& mu = machine.getInputSubtraction(); - const blitz::Array<double,2>& W = machine.getWeights(); - const blitz::Array<double,2> Wt = W.transpose(1,0); // W^T - - // Computes the statistics - blitz::Range a = blitz::Range::all(); - for(int i=0; i<ar.extent(0); ++i) - { - /// 1/ First order statistics: \f$z_first_order_i = inv(M) W^T (t - \mu)\f$ - // m_tmp_f = t (sample) - mu (normalized sample) - m_tmp_f = ar(i,a) - mu; - // m_tmp_dxf = inv(M) * W^T - bob::math::prod(m_invM, Wt, m_tmp_dxf); - blitz::Array<double,1> z_first_order_i = m_z_first_order(i,blitz::Range::all()); - // z_first_order_i = inv(M) * W^T * (t - mu) - bob::math::prod(m_tmp_dxf, m_tmp_f, z_first_order_i); - - /// 2/ Second order statistics: - /// z_second_order_i = sigma2 * inv(M) + z_first_order_i * z_first_order_i^T - blitz::Array<double,2> z_second_order_i = m_z_second_order(i,blitz::Range::all(),blitz::Range::all()); - // m_tmp_dxd = z_first_order_i * z_first_order_i^T - bob::math::prod(z_first_order_i, z_first_order_i, m_tmp_dxd_1); // outer product - // z_second_order_i = sigma2 * inv(M) - z_second_order_i = m_invM; - z_second_order_i *= m_sigma2; - // z_second_order_i = sigma2 * inv(M) + z_first_order_i * z_first_order_i^T - z_second_order_i += m_tmp_dxd_1; - } -} - -void bob::learn::em::EMPCATrainer::mStep(bob::learn::linear::Machine& machine, const blitz::Array<double,2>& ar) -{ - // 1/ New estimate of W - updateW(machine, ar); - - // 2/ New estimate of sigma2 - updateSigma2(machine, ar); - - // Computes the new value of inverse(M), where M = Wt * W + sigma2 * Id - computeInvM(); -} - -void bob::learn::em::EMPCATrainer::updateW(bob::learn::linear::Machine& machine, const blitz::Array<double,2>& ar) { - // Get the mean mu and the projection matrix W - const blitz::Array<double,1>& mu = machine.getInputSubtraction(); - blitz::Array<double,2>& W = machine.updateWeights(); - const blitz::Array<double,2> Wt = W.transpose(1,0); // W^T - - // Compute W = sum{ (t_{i} - mu) z_first_order_i^T} * inv( sum{z_second_order_i} ) - m_tmp_fxd_1 = 0.; - m_tmp_dxd_1 = 0.; - blitz::Range a = blitz::Range::all(); - for(int i=0; i<ar.extent(0); ++i) - { - // m_tmp_f = t (sample) - mu (normalized sample) - m_tmp_f = ar(i,a) - mu; - // first order statistics of sample i - blitz::Array<double,1> z_first_order_i = m_z_first_order(i,blitz::Range::all()); - // m_tmp_fxd_2 = (t - mu)*z_first_order_i - bob::math::prod(m_tmp_f, z_first_order_i, m_tmp_fxd_2); - m_tmp_fxd_1 += m_tmp_fxd_2; - - // second order statistics of sample i - blitz::Array<double,2> z_second_order_i = m_z_second_order(i,blitz::Range::all(),blitz::Range::all()); - m_tmp_dxd_1 += z_second_order_i; - } - - // m_tmp_dxd_2 = inv( sum(E(x_i.x_i^T)) ) - bob::math::inv(m_tmp_dxd_1, m_tmp_dxd_2); - // New estimates of W - bob::math::prod(m_tmp_fxd_1, m_tmp_dxd_2, W); - // Updates W'*W as well - bob::math::prod(Wt, W, m_inW); -} - -void bob::learn::em::EMPCATrainer::updateSigma2(bob::learn::linear::Machine& machine, const blitz::Array<double,2>& ar) { - // Get the mean mu and the projection matrix W - const blitz::Array<double,1>& mu = machine.getInputSubtraction(); - const blitz::Array<double,2>& W = machine.getWeights(); - const blitz::Array<double,2> Wt = W.transpose(1,0); // W^T - - m_sigma2 = 0.; - blitz::Range a = blitz::Range::all(); - for(int i=0; i<ar.extent(0); ++i) - { - // a. sigma2 += || t - mu ||^2 - // m_tmp_f = t (sample) - mu (normalized sample) - m_tmp_f = ar(i,a) - mu; - // sigma2 += || t - mu ||^2 - m_sigma2 += blitz::sum(blitz::pow2(m_tmp_f)); - - // b. sigma2 -= 2*E(x_i)^T*W^T*(t - mu) - // m_tmp_d = W^T*(t - mu) - bob::math::prod(Wt, m_tmp_f, m_tmp_d); - // first order of i - blitz::Array<double,1> z_first_order_i = m_z_first_order(i,blitz::Range::all()); - // sigma2 -= 2*E(x_i)^T*W^T*(t - mu) - m_sigma2 -= 2*bob::math::dot(z_first_order_i, m_tmp_d); - - // c. sigma2 += trace( E(x_i.x_i^T)*W^T*W ) - // second order of i - blitz::Array<double,2> z_second_order_i = m_z_second_order(i,blitz::Range::all(),blitz::Range::all()); - // m_tmp_dxd_1 = E(x_i.x_i^T)*W^T*W - bob::math::prod(z_second_order_i, m_inW, m_tmp_dxd_1); - // sigma2 += trace( E(x_i.x_i^T)*W^T*W ) - m_sigma2 += bob::math::trace(m_tmp_dxd_1); - } - // Normalization factor - m_sigma2 /= (static_cast<double>(ar.extent(0)) * mu.extent(0)); -} - -double bob::learn::em::EMPCATrainer::computeLikelihood(bob::learn::linear::Machine& machine) -{ - // Get W projection matrix - const blitz::Array<double,2>& W = machine.getWeights(); - const blitz::Array<double,2> Wt = W.transpose(1,0); // W^T - const size_t n_features = m_S.extent(0); - - // 1/ Compute det(C), where C = sigma2.I + W.W^T - // det(C) = det(sigma2 * C / sigma2) = det(sigma2 * Id) * det(C / sigma2) - // We are using Sylvester's determinant theorem to compute a dxd - // determinant rather than a fxf one: det(I + A.B) = det(I + B.A) - // det(C) = sigma2^n_features * det(I + W.W^T/sigma2) - // = sigma2^n_features * det(I + W^T.W/sigma2) (cf. Bishop Appendix C) - // detC = det( eye(n_features) * sigma2 ) - - // detC = sigma2^n_features - double detC = pow(m_sigma2, n_features); - // m_tmp_dxd_1 = Id - bob::math::eye(m_tmp_dxd_1); - // m_tmp_dxd_2 = W^T.W - bob::math::prod(Wt, W, m_tmp_dxd_2); - // m_tmp_dxd_2 = W^T.W / sigma2 - m_tmp_dxd_2 /= m_sigma2; - // m_tmp_dxd_1 = Id + W^T.W / sigma2 - m_tmp_dxd_1 += m_tmp_dxd_2; - // detC = sigma2^n_features * det(I + W^T.W/sigma2) - detC *= bob::math::det(m_tmp_dxd_1); - - // 2/ Compute inv(C), where C = sigma2.I + W.W^T - // We are using the following identity (Property C.7 of Bishop's book) - // (A + B.D^-1.C)^-1 = A^-1 - A^-1.B(D+C.A^-1.B)^-1.C.A^-1 - // Hence, inv(C) = sigma2^-1 .(I - W.M^-1.W^T) - - // Compute inverse(M), where M = Wt * W + sigma2 * Id - computeInvM(); - // m_tmp_fxf_1 = I = eye(n_features) - bob::math::eye(m_tmp_fxf_1); - // m_tmp_fxd_1 = W * inv(M) - bob::math::prod(W, m_invM, m_tmp_fxd_1); - // m_tmp_fxf_2 = (W * inv(M) * Wt) - bob::math::prod(m_tmp_fxd_1, Wt, m_tmp_fxf_2); - // m_tmp_fxd_1 = inv(C) = (I - W.M^-1.W^T) / sigma2 - m_tmp_fxf_1 -= m_tmp_fxf_2; - m_tmp_fxf_1 /= m_sigma2; - - // 3/ Compute inv(C).S - bob::math::prod(m_tmp_fxf_1, m_S, m_tmp_fxf_2); - - // 4/ Use previous values to compute the log likelihood: - // Log likelihood = - N/2*{ d*ln(2*PI) + ln |detC| + tr(C^-1.S) } - double llh = - static_cast<double>(m_z_first_order.extent(0)) / 2. * - ( m_f_log2pi + log(fabs(detC)) + bob::math::trace(m_tmp_fxf_2) ); - - return llh; -} diff --git a/bob/learn/em/cpp/FABase.cpp b/bob/learn/em/cpp/FABase.cpp deleted file mode 100644 index 317a368d696668824f6be9a533c5ab6d4da8ff50..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/FABase.cpp +++ /dev/null @@ -1,307 +0,0 @@ -/** - * @date Tue Jan 27 15:51:15 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - - -#include <bob.learn.em/FABase.h> -#include <bob.core/array_copy.h> -#include <bob.math/linear.h> -#include <bob.math/inv.h> -#include <limits> - - -//////////////////// FABase //////////////////// -bob::learn::em::FABase::FABase(): - m_ubm(boost::shared_ptr<bob::learn::em::GMMMachine>()), m_ru(1), m_rv(1), - m_U(0,1), m_V(0,1), m_d(0) -{} - -bob::learn::em::FABase::FABase(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm, - const size_t ru, const size_t rv): - m_ubm(ubm), m_ru(ru), m_rv(rv), - m_U(getSupervectorLength(),ru), m_V(getSupervectorLength(),rv), m_d(getSupervectorLength()) -{ - if (ru < 1) { - boost::format m("value for parameter `ru' (%lu) cannot be smaller than 1"); - m % ru; - throw std::runtime_error(m.str()); - } - if (rv < 1) { - boost::format m("value for parameter `rv' (%lu) cannot be smaller than 1"); - m % ru; - throw std::runtime_error(m.str()); - } - updateCache(); -} - -bob::learn::em::FABase::FABase(const bob::learn::em::FABase& other): - m_ubm(other.m_ubm), m_ru(other.m_ru), m_rv(other.m_rv), - m_U(bob::core::array::ccopy(other.m_U)), - m_V(bob::core::array::ccopy(other.m_V)), - m_d(bob::core::array::ccopy(other.m_d)) -{ - updateCache(); -} - -bob::learn::em::FABase::~FABase() { -} - -bob::learn::em::FABase& bob::learn::em::FABase::operator= -(const bob::learn::em::FABase& other) -{ - if (this != &other) - { - m_ubm = other.m_ubm; - m_ru = other.m_ru; - m_rv = other.m_rv; - m_U.reference(bob::core::array::ccopy(other.m_U)); - m_V.reference(bob::core::array::ccopy(other.m_V)); - m_d.reference(bob::core::array::ccopy(other.m_d)); - - updateCache(); - } - return *this; -} - -bool bob::learn::em::FABase::operator==(const bob::learn::em::FABase& b) const -{ - return ( (((m_ubm && b.m_ubm) && *m_ubm == *(b.m_ubm)) || (!m_ubm && !b.m_ubm)) && - m_ru == b.m_ru && m_rv == b.m_rv && - bob::core::array::isEqual(m_U, b.m_U) && - bob::core::array::isEqual(m_V, b.m_V) && - bob::core::array::isEqual(m_d, b.m_d)); -} - -bool bob::learn::em::FABase::operator!=(const bob::learn::em::FABase& b) const -{ - return !(this->operator==(b)); -} - -bool bob::learn::em::FABase::is_similar_to(const bob::learn::em::FABase& b, - const double r_epsilon, const double a_epsilon) const -{ - // TODO: update is_similar_to of the GMMMachine with the 2 epsilon's - return (( ((m_ubm && b.m_ubm) && m_ubm->is_similar_to(*(b.m_ubm), a_epsilon)) || - (!m_ubm && !b.m_ubm) ) && - m_ru == b.m_ru && m_rv == b.m_rv && - bob::core::array::isClose(m_U, b.m_U, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_V, b.m_V, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_d, b.m_d, r_epsilon, a_epsilon)); -} - -void bob::learn::em::FABase::resize(const size_t ru, const size_t rv) -{ - if (ru < 1) { - boost::format m("value for parameter `ru' (%lu) cannot be smaller than 1"); - m % ru; - throw std::runtime_error(m.str()); - } - if (rv < 1) { - boost::format m("value for parameter `rv' (%lu) cannot be smaller than 1"); - m % ru; - throw std::runtime_error(m.str()); - } - - m_ru = ru; - m_rv = rv; - m_U.resizeAndPreserve(m_U.extent(0), ru); - m_V.resizeAndPreserve(m_V.extent(0), rv); - - updateCacheUbmUVD(); -} - -void bob::learn::em::FABase::resize(const size_t ru, const size_t rv, const size_t cd) -{ - if (ru < 1) { - boost::format m("value for parameter `ru' (%lu) cannot be smaller than 1"); - m % ru; - throw std::runtime_error(m.str()); - } - if (rv < 1) { - boost::format m("value for parameter `rv' (%lu) cannot be smaller than 1"); - m % ru; - throw std::runtime_error(m.str()); - } - - if (!m_ubm || (m_ubm && getSupervectorLength() == cd)) - { - m_ru = ru; - m_rv = rv; - m_U.resizeAndPreserve(cd, ru); - m_V.resizeAndPreserve(cd, rv); - m_d.resizeAndPreserve(cd); - - updateCacheUbmUVD(); - } - else { - boost::format m("value for parameter `cd' (%lu) is not set to %lu"); - m % cd % getSupervectorLength(); - throw std::runtime_error(m.str()); - } -} - -void bob::learn::em::FABase::setUbm(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm) -{ - m_ubm = ubm; - m_U.resizeAndPreserve(getSupervectorLength(), m_ru); - m_V.resizeAndPreserve(getSupervectorLength(), m_rv); - m_d.resizeAndPreserve(getSupervectorLength()); - - updateCache(); -} - -void bob::learn::em::FABase::setU(const blitz::Array<double,2>& U) -{ - if(U.extent(0) != m_U.extent(0)) { //checks dimension - boost::format m("number of rows in parameter `U' (%d) does not match the expected size (%d)"); - m % U.extent(0) % m_U.extent(0); - throw std::runtime_error(m.str()); - } - if(U.extent(1) != m_U.extent(1)) { //checks dimension - boost::format m("number of columns in parameter `U' (%d) does not match the expected size (%d)"); - m % U.extent(1) % m_U.extent(1); - throw std::runtime_error(m.str()); - } - m_U.reference(bob::core::array::ccopy(U)); - - // update cache - updateCacheUbmUVD(); -} - -void bob::learn::em::FABase::setV(const blitz::Array<double,2>& V) -{ - if(V.extent(0) != m_V.extent(0)) { //checks dimension - boost::format m("number of rows in parameter `V' (%d) does not match the expected size (%d)"); - m % V.extent(0) % m_V.extent(0); - throw std::runtime_error(m.str()); - } - if(V.extent(1) != m_V.extent(1)) { //checks dimension - boost::format m("number of columns in parameter `V' (%d) does not match the expected size (%d)"); - m % V.extent(1) % m_V.extent(1); - throw std::runtime_error(m.str()); - } - m_V.reference(bob::core::array::ccopy(V)); -} - -void bob::learn::em::FABase::setD(const blitz::Array<double,1>& d) -{ - if(d.extent(0) != m_d.extent(0)) { //checks dimension - boost::format m("size of input vector `d' (%d) does not match the expected size (%d)"); - m % d.extent(0) % m_d.extent(0); - throw std::runtime_error(m.str()); - } - m_d.reference(bob::core::array::ccopy(d)); -} - - -void bob::learn::em::FABase::updateCache() -{ - updateCacheUbm(); - updateCacheUbmUVD(); - resizeTmp(); -} - -void bob::learn::em::FABase::resizeTmp() -{ - m_tmp_IdPlusUSProdInv.resize(getDimRu(),getDimRu()); - m_tmp_Fn_x.resize(getSupervectorLength()); - m_tmp_ru.resize(getDimRu()); - m_tmp_ruD.resize(getDimRu(), getNInputs()); - m_tmp_ruru.resize(getDimRu(), getDimRu()); -} - -void bob::learn::em::FABase::updateCacheUbm() -{ - // Put supervectors in cache - if (m_ubm) - { - m_cache_mean.resize(getSupervectorLength()); - m_cache_sigma.resize(getSupervectorLength()); - m_cache_mean = m_ubm->getMeanSupervector(); - m_cache_sigma = m_ubm->getVarianceSupervector(); - } -} - -void bob::learn::em::FABase::updateCacheUbmUVD() -{ - // Compute and put U^{T}.diag(sigma)^{-1} in cache - if (m_ubm) - { - blitz::firstIndex i; - blitz::secondIndex j; - m_cache_UtSigmaInv.resize(getDimRu(), getSupervectorLength()); - m_cache_UtSigmaInv = m_U(j,i) / m_cache_sigma(j); // Ut * diag(sigma)^-1 - } -} - -void bob::learn::em::FABase::computeIdPlusUSProdInv(const bob::learn::em::GMMStats& gmm_stats, - blitz::Array<double,2>& output) const -{ - // Computes (Id + U^T.Sigma^-1.U.N_{i,h}.U)^-1 = - // (Id + sum_{c=1..C} N_{i,h}.U_{c}^T.Sigma_{c}^-1.U_{c})^-1 - - // Blitz compatibility: ugly fix (const_cast, as old blitz version does not - // provide a non-const version of transpose()) - blitz::Array<double,2> Ut = const_cast<blitz::Array<double,2>&>(m_U).transpose(1,0); - - blitz::firstIndex i; - blitz::secondIndex j; - blitz::Range rall = blitz::Range::all(); - - bob::math::eye(m_tmp_ruru); // m_tmp_ruru = Id - // Loop and add N_{i,h}.U_{c}^T.Sigma_{c}^-1.U_{c} to m_tmp_ruru at each iteration - const size_t dim_c = getNGaussians(); - const size_t dim_d = getNInputs(); - for(size_t c=0; c<dim_c; ++c) { - blitz::Range rc(c*dim_d,(c+1)*dim_d-1); - blitz::Array<double,2> Ut_c = Ut(rall,rc); - blitz::Array<double,1> sigma_c = m_cache_sigma(rc); - m_tmp_ruD = Ut_c(i,j) / sigma_c(j); // U_{c}^T.Sigma_{c}^-1 - blitz::Array<double,2> U_c = m_U(rc,rall); - // Use m_cache_IdPlusUSProdInv as an intermediate array - bob::math::prod(m_tmp_ruD, U_c, output); // U_{c}^T.Sigma_{c}^-1.U_{c} - // Finally, add N_{i,h}.U_{c}^T.Sigma_{c}^-1.U_{c} to m_tmp_ruru - m_tmp_ruru += output * gmm_stats.n(c); - } - // Computes the inverse - bob::math::inv(m_tmp_ruru, output); -} - - -void bob::learn::em::FABase::computeFn_x(const bob::learn::em::GMMStats& gmm_stats, - blitz::Array<double,1>& output) const -{ - // Compute Fn_x = sum_{sessions h}(N*(o - m) (Normalised first order statistics) - blitz::Range rall = blitz::Range::all(); - const size_t dim_c = getNGaussians(); - const size_t dim_d = getNInputs(); - for(size_t c=0; c<dim_c; ++c) { - blitz::Range rc(c*dim_d,(c+1)*dim_d-1); - blitz::Array<double,1> Fn_x_c = output(rc); - blitz::Array<double,1> mean_c = m_cache_mean(rc); - Fn_x_c = gmm_stats.sumPx(c,rall) - mean_c*gmm_stats.n(c); - } -} - -void bob::learn::em::FABase::estimateX(const blitz::Array<double,2>& IdPlusUSProdInv, - const blitz::Array<double,1>& Fn_x, blitz::Array<double,1>& x) const -{ - // m_tmp_ru = UtSigmaInv * Fn_x = Ut*diag(sigma)^-1 * N*(o - m) - bob::math::prod(m_cache_UtSigmaInv, Fn_x, m_tmp_ru); - // x = IdPlusUSProdInv * m_cache_UtSigmaInv * Fn_x - bob::math::prod(IdPlusUSProdInv, m_tmp_ru, x); -} - - -void bob::learn::em::FABase::estimateX(const bob::learn::em::GMMStats& gmm_stats, blitz::Array<double,1>& x) const -{ - if (!m_ubm) throw std::runtime_error("No UBM was set in the JFA machine."); - computeIdPlusUSProdInv(gmm_stats, m_tmp_IdPlusUSProdInv); // Computes first term - computeFn_x(gmm_stats, m_tmp_Fn_x); // Computes last term - estimateX(m_tmp_IdPlusUSProdInv, m_tmp_Fn_x, x); // Estimates the value of x -} - diff --git a/bob/learn/em/cpp/FABaseTrainer.cpp b/bob/learn/em/cpp/FABaseTrainer.cpp deleted file mode 100644 index 09e4a4b69e262775b8ef529697f04ed2d2804621..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/FABaseTrainer.cpp +++ /dev/null @@ -1,547 +0,0 @@ -/** - * @date Sat Jan 31 17:16:17 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief FABaseTrainer functions - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/FABaseTrainer.h> -#include <bob.core/check.h> -#include <bob.core/array_copy.h> -#include <bob.core/array_random.h> -#include <bob.math/inv.h> -#include <bob.math/linear.h> -#include <bob.core/check.h> -#include <bob.core/array_repmat.h> -#include <algorithm> - - -bob::learn::em::FABaseTrainer::FABaseTrainer(): - m_Nid(0), m_dim_C(0), m_dim_D(0), m_dim_ru(0), m_dim_rv(0), - m_x(0), m_y(0), m_z(0), m_Nacc(0), m_Facc(0) -{ -} - -bob::learn::em::FABaseTrainer::FABaseTrainer(const bob::learn::em::FABaseTrainer& other) -{ -} - -bob::learn::em::FABaseTrainer::~FABaseTrainer() -{ -} - -void bob::learn::em::FABaseTrainer::checkStatistics( - const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats) -{ - for (size_t id=0; id<stats.size(); ++id) { - for (size_t s=0; s<stats[id].size(); ++s) { - if (stats[id][s]->sumPx.extent(0) != (int)m_dim_C) { - boost::format m("GMMStats C dimension parameter = %d is different than the expected value of %d"); - m % stats[id][s]->sumPx.extent(0) % (int)m_dim_C; - throw std::runtime_error(m.str()); - } - if (stats[id][s]->sumPx.extent(1) != (int)m_dim_D) { - boost::format m("GMMStats D dimension parameter = %d is different than the expected value of %d"); - m % stats[id][s]->sumPx.extent(1) % (int)m_dim_D; - throw std::runtime_error(m.str()); - } - } - } -} - - -void bob::learn::em::FABaseTrainer::initUbmNidSumStatistics( - const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats) -{ - m_Nid = stats.size(); - boost::shared_ptr<bob::learn::em::GMMMachine> ubm = m.getUbm(); - // Put UBM in cache - m_dim_C = ubm->getNGaussians(); - m_dim_D = ubm->getNInputs(); - m_dim_ru = m.getDimRu(); - m_dim_rv = m.getDimRv(); - // Check statistics dimensionality - checkStatistics(m, stats); - // Precomputes the sum of the statistics for each client/identity - precomputeSumStatisticsN(stats); - precomputeSumStatisticsF(stats); - // Cache and working arrays - initCache(); -} - -void bob::learn::em::FABaseTrainer::precomputeSumStatisticsN( - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats) -{ - m_Nacc.clear(); - blitz::Array<double,1> Nsum(m_dim_C); - for (size_t id=0; id<stats.size(); ++id) { - Nsum = 0.; - for (size_t s=0; s<stats[id].size(); ++s) { - Nsum += stats[id][s]->n; - } - m_Nacc.push_back(bob::core::array::ccopy(Nsum)); - } -} - -void bob::learn::em::FABaseTrainer::precomputeSumStatisticsF( - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats) -{ - m_Facc.clear(); - blitz::Array<double,1> Fsum(m_dim_C*m_dim_D); - for (size_t id=0; id<stats.size(); ++id) { - Fsum = 0.; - for (size_t s=0; s<stats[id].size(); ++s) { - for (size_t c=0; c<m_dim_C; ++c) { - blitz::Array<double,1> Fsum_c = Fsum(blitz::Range(c*m_dim_D,(c+1)*m_dim_D-1)); - Fsum_c += stats[id][s]->sumPx(c,blitz::Range::all()); - } - } - m_Facc.push_back(bob::core::array::ccopy(Fsum)); - } -} - -void bob::learn::em::FABaseTrainer::initializeXYZ(const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& vec) -{ - m_x.clear(); - m_y.clear(); - m_z.clear(); - - blitz::Array<double,1> z0(m_dim_C*m_dim_D); - z0 = 0; - blitz::Array<double,1> y0(m_dim_rv); - y0 = 0; - blitz::Array<double,2> x0(m_dim_ru,0); - x0 = 0; - for (size_t i=0; i<vec.size(); ++i) - { - m_z.push_back(bob::core::array::ccopy(z0)); - m_y.push_back(bob::core::array::ccopy(y0)); - x0.resize(m_dim_ru, vec[i].size()); - x0 = 0; - m_x.push_back(bob::core::array::ccopy(x0)); - } -} - -void bob::learn::em::FABaseTrainer::resetXYZ() -{ - for (size_t i=0; i<m_x.size(); ++i) - { - m_x[i] = 0.; - m_y[i] = 0.; - m_z[i] = 0.; - } -} - -void bob::learn::em::FABaseTrainer::initCache() -{ - const size_t dim_CD = m_dim_C*m_dim_D; - // U - m_cache_UtSigmaInv.resize(m_dim_ru, dim_CD); - m_cache_UProd.resize(m_dim_C, m_dim_ru, m_dim_ru); - m_cache_IdPlusUProd_ih.resize(m_dim_ru, m_dim_ru); - m_cache_Fn_x_ih.resize(dim_CD); - m_acc_U_A1.resize(m_dim_C, m_dim_ru, m_dim_ru); - m_acc_U_A2.resize(dim_CD, m_dim_ru); - // V - m_cache_VtSigmaInv.resize(m_dim_rv, dim_CD); - m_cache_VProd.resize(m_dim_C, m_dim_rv, m_dim_rv); - m_cache_IdPlusVProd_i.resize(m_dim_rv, m_dim_rv); - m_cache_Fn_y_i.resize(dim_CD); - m_acc_V_A1.resize(m_dim_C, m_dim_rv, m_dim_rv); - m_acc_V_A2.resize(dim_CD, m_dim_rv); - // D - m_cache_DtSigmaInv.resize(dim_CD); - m_cache_DProd.resize(dim_CD); - m_cache_IdPlusDProd_i.resize(dim_CD); - m_cache_Fn_z_i.resize(dim_CD); - m_acc_D_A1.resize(dim_CD); - m_acc_D_A2.resize(dim_CD); - - // tmp - m_tmp_CD.resize(dim_CD); - m_tmp_CD_b.resize(dim_CD); - - m_tmp_ru.resize(m_dim_ru); - m_tmp_ruD.resize(m_dim_ru, m_dim_D); - m_tmp_ruru.resize(m_dim_ru, m_dim_ru); - - m_tmp_rv.resize(m_dim_rv); - m_tmp_rvD.resize(m_dim_rv, m_dim_D); - m_tmp_rvrv.resize(m_dim_rv, m_dim_rv); -} - - - -//////////////////////////// V /////////////////////////// -void bob::learn::em::FABaseTrainer::computeVtSigmaInv(const bob::learn::em::FABase& m) -{ - const blitz::Array<double,2>& V = m.getV(); - // Blitz compatibility: ugly fix (const_cast, as old blitz version does not - // provide a non-const version of transpose()) - const blitz::Array<double,2> Vt = const_cast<blitz::Array<double,2>&>(V).transpose(1,0); - const blitz::Array<double,1>& sigma = m.getUbmVariance(); - blitz::firstIndex i; - blitz::secondIndex j; - m_cache_VtSigmaInv = Vt(i,j) / sigma(j); // Vt * diag(sigma)^-1 -} - -void bob::learn::em::FABaseTrainer::computeVProd(const bob::learn::em::FABase& m) -{ - const blitz::Array<double,2>& V = m.getV(); - blitz::firstIndex i; - blitz::secondIndex j; - const blitz::Array<double,1>& sigma = m.getUbmVariance(); - blitz::Range rall = blitz::Range::all(); - for (size_t c=0; c<m_dim_C; ++c) - { - blitz::Array<double,2> VProd_c = m_cache_VProd(c, rall, rall); - blitz::Array<double,2> Vv_c = V(blitz::Range(c*m_dim_D,(c+1)*m_dim_D-1), rall); - blitz::Array<double,2> Vt_c = Vv_c.transpose(1,0); - blitz::Array<double,1> sigma_c = sigma(blitz::Range(c*m_dim_D,(c+1)*m_dim_D-1)); - m_tmp_rvD = Vt_c(i,j) / sigma_c(j); // Vt_c * diag(sigma)^-1 - bob::math::prod(m_tmp_rvD, Vv_c, VProd_c); - } -} - -void bob::learn::em::FABaseTrainer::computeIdPlusVProd_i(const size_t id) -{ - const blitz::Array<double,1>& Ni = m_Nacc[id]; - bob::math::eye(m_tmp_rvrv); // m_tmp_rvrv = I - blitz::Range rall = blitz::Range::all(); - for (size_t c=0; c<m_dim_C; ++c) { - blitz::Array<double,2> VProd_c = m_cache_VProd(c, rall, rall); - m_tmp_rvrv += VProd_c * Ni(c); - } - bob::math::inv(m_tmp_rvrv, m_cache_IdPlusVProd_i); // m_cache_IdPlusVProd_i = ( I+Vt*diag(sigma)^-1*Ni*V)^-1 -} - -void bob::learn::em::FABaseTrainer::computeFn_y_i(const bob::learn::em::FABase& mb, - const std::vector<boost::shared_ptr<bob::learn::em::GMMStats> >& stats, const size_t id) -{ - const blitz::Array<double,2>& U = mb.getU(); - const blitz::Array<double,1>& d = mb.getD(); - // Compute Fn_yi = sum_{sessions h}(N_{i,h}*(o_{i,h} - m - D*z_{i} - U*x_{i,h}) (Normalised first order statistics) - const blitz::Array<double,1>& Fi = m_Facc[id]; - const blitz::Array<double,1>& m = mb.getUbmMean(); - const blitz::Array<double,1>& z = m_z[id]; - bob::core::array::repelem(m_Nacc[id], m_tmp_CD); - m_cache_Fn_y_i = Fi - m_tmp_CD * (m + d * z); // Fn_yi = sum_{sessions h}(N_{i,h}*(o_{i,h} - m - D*z_{i}) - const blitz::Array<double,2>& X = m_x[id]; - blitz::Range rall = blitz::Range::all(); - for (int h=0; h<X.extent(1); ++h) // Loops over the sessions - { - blitz::Array<double,1> Xh = X(rall, h); // Xh = x_{i,h} (length: ru) - bob::math::prod(U, Xh, m_tmp_CD_b); // m_tmp_CD_b = U*x_{i,h} - const blitz::Array<double,1>& Nih = stats[h]->n; - bob::core::array::repelem(Nih, m_tmp_CD); - m_cache_Fn_y_i -= m_tmp_CD * m_tmp_CD_b; // N_{i,h} * U * x_{i,h} - } - // Fn_yi = sum_{sessions h}(N_{i,h}*(o_{i,h} - m - D*z_{i} - U*x_{i,h}) -} - -void bob::learn::em::FABaseTrainer::updateY_i(const size_t id) -{ - // Computes yi = Ayi * Cvs * Fn_yi - blitz::Array<double,1>& y = m_y[id]; - // m_tmp_rv = m_cache_VtSigmaInv * m_cache_Fn_y_i = Vt*diag(sigma)^-1 * sum_{sessions h}(N_{i,h}*(o_{i,h} - m - D*z_{i} - U*x_{i,h}) - bob::math::prod(m_cache_VtSigmaInv, m_cache_Fn_y_i, m_tmp_rv); - bob::math::prod(m_cache_IdPlusVProd_i, m_tmp_rv, y); -} - -void bob::learn::em::FABaseTrainer::updateY(const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats) -{ - // Precomputation - computeVtSigmaInv(m); - computeVProd(m); - // Loops over all people - for (size_t id=0; id<stats.size(); ++id) { - computeIdPlusVProd_i(id); - computeFn_y_i(m, stats[id], id); - updateY_i(id); - } -} - -void bob::learn::em::FABaseTrainer::computeAccumulatorsV( - const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats) -{ - // Initializes the cache accumulator - m_acc_V_A1 = 0.; - m_acc_V_A2 = 0.; - // Loops over all people - blitz::firstIndex i; - blitz::secondIndex j; - blitz::Range rall = blitz::Range::all(); - for (size_t id=0; id<stats.size(); ++id) { - computeIdPlusVProd_i(id); - computeFn_y_i(m, stats[id], id); - - // Needs to return values to be accumulated for estimating V - const blitz::Array<double,1>& y = m_y[id]; - m_tmp_rvrv = m_cache_IdPlusVProd_i; - m_tmp_rvrv += y(i) * y(j); - for (size_t c=0; c<m_dim_C; ++c) - { - blitz::Array<double,2> A1_y_c = m_acc_V_A1(c, rall, rall); - A1_y_c += m_tmp_rvrv * m_Nacc[id](c); - } - m_acc_V_A2 += m_cache_Fn_y_i(i) * y(j); - } -} - -void bob::learn::em::FABaseTrainer::updateV(blitz::Array<double,2>& V) -{ - blitz::Range rall = blitz::Range::all(); - for (size_t c=0; c<m_dim_C; ++c) - { - const blitz::Array<double,2> A1 = m_acc_V_A1(c, rall, rall); - bob::math::inv(A1, m_tmp_rvrv); - const blitz::Array<double,2> A2 = m_acc_V_A2(blitz::Range(c*m_dim_D,(c+1)*m_dim_D-1), rall); - blitz::Array<double,2> V_c = V(blitz::Range(c*m_dim_D,(c+1)*m_dim_D-1), rall); - bob::math::prod(A2, m_tmp_rvrv, V_c); - } -} - - -//////////////////////////// U /////////////////////////// -void bob::learn::em::FABaseTrainer::computeUtSigmaInv(const bob::learn::em::FABase& m) -{ - const blitz::Array<double,2>& U = m.getU(); - // Blitz compatibility: ugly fix (const_cast, as old blitz version does not - // provide a non-const version of transpose()) - const blitz::Array<double,2> Ut = const_cast<blitz::Array<double,2>&>(U).transpose(1,0); - const blitz::Array<double,1>& sigma = m.getUbmVariance(); - blitz::firstIndex i; - blitz::secondIndex j; - m_cache_UtSigmaInv = Ut(i,j) / sigma(j); // Ut * diag(sigma)^-1 -} - -void bob::learn::em::FABaseTrainer::computeUProd(const bob::learn::em::FABase& m) -{ - const blitz::Array<double,2>& U = m.getU(); - blitz::firstIndex i; - blitz::secondIndex j; - const blitz::Array<double,1>& sigma = m.getUbmVariance(); - for (size_t c=0; c<m_dim_C; ++c) - { - blitz::Array<double,2> UProd_c = m_cache_UProd(c, blitz::Range::all(), blitz::Range::all()); - blitz::Array<double,2> Uu_c = U(blitz::Range(c*m_dim_D,(c+1)*m_dim_D-1), blitz::Range::all()); - blitz::Array<double,2> Ut_c = Uu_c.transpose(1,0); - blitz::Array<double,1> sigma_c = sigma(blitz::Range(c*m_dim_D,(c+1)*m_dim_D-1)); - m_tmp_ruD = Ut_c(i,j) / sigma_c(j); // Ut_c * diag(sigma)^-1 - bob::math::prod(m_tmp_ruD, Uu_c, UProd_c); - } -} - -void bob::learn::em::FABaseTrainer::computeIdPlusUProd_ih( - const boost::shared_ptr<bob::learn::em::GMMStats>& stats) -{ - const blitz::Array<double,1>& Nih = stats->n; - bob::math::eye(m_tmp_ruru); // m_tmp_ruru = I - for (size_t c=0; c<m_dim_C; ++c) { - blitz::Array<double,2> UProd_c = m_cache_UProd(c,blitz::Range::all(),blitz::Range::all()); - m_tmp_ruru += UProd_c * Nih(c); - } - bob::math::inv(m_tmp_ruru, m_cache_IdPlusUProd_ih); // m_cache_IdPlusUProd_ih = ( I+Ut*diag(sigma)^-1*Ni*U)^-1 -} - -void bob::learn::em::FABaseTrainer::computeFn_x_ih(const bob::learn::em::FABase& mb, - const boost::shared_ptr<bob::learn::em::GMMStats>& stats, const size_t id) -{ - const blitz::Array<double,2>& V = mb.getV(); - const blitz::Array<double,1>& d = mb.getD(); - // Compute Fn_x_ih = sum_{sessions h}(N_{i,h}*(o_{i,h} - m - D*z_{i} - V*y_{i}) (Normalised first order statistics) - const blitz::Array<double,2>& Fih = stats->sumPx; - const blitz::Array<double,1>& m = mb.getUbmMean(); - const blitz::Array<double,1>& z = m_z[id]; - const blitz::Array<double,1>& Nih = stats->n; - bob::core::array::repelem(Nih, m_tmp_CD); - for (size_t c=0; c<m_dim_C; ++c) { - blitz::Array<double,1> Fn_x_ih_c = m_cache_Fn_x_ih(blitz::Range(c*m_dim_D,(c+1)*m_dim_D-1)); - Fn_x_ih_c = Fih(c,blitz::Range::all()); - } - m_cache_Fn_x_ih -= m_tmp_CD * (m + d * z); // Fn_x_ih = N_{i,h}*(o_{i,h} - m - D*z_{i}) - - const blitz::Array<double,1>& y = m_y[id]; - bob::math::prod(V, y, m_tmp_CD_b); - m_cache_Fn_x_ih -= m_tmp_CD * m_tmp_CD_b; - // Fn_x_ih = N_{i,h}*(o_{i,h} - m - D*z_{i} - V*y_{i}) -} - -void bob::learn::em::FABaseTrainer::updateX_ih(const size_t id, const size_t h) -{ - // Computes xih = Axih * Cus * Fn_x_ih - blitz::Array<double,1> x = m_x[id](blitz::Range::all(), h); - // m_tmp_ru = m_cache_UtSigmaInv * m_cache_Fn_x_ih = Ut*diag(sigma)^-1 * N_{i,h}*(o_{i,h} - m - D*z_{i} - V*y_{i}) - bob::math::prod(m_cache_UtSigmaInv, m_cache_Fn_x_ih, m_tmp_ru); - bob::math::prod(m_cache_IdPlusUProd_ih, m_tmp_ru, x); -} - -void bob::learn::em::FABaseTrainer::updateX(const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats) -{ - // Precomputation - computeUtSigmaInv(m); - computeUProd(m); - // Loops over all people - for (size_t id=0; id<stats.size(); ++id) { - int n_session_i = stats[id].size(); - for (int s=0; s<n_session_i; ++s) { - computeIdPlusUProd_ih(stats[id][s]); - computeFn_x_ih(m, stats[id][s], id); - updateX_ih(id, s); - } - } -} - -void bob::learn::em::FABaseTrainer::computeAccumulatorsU( - const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats) -{ - // Initializes the cache accumulator - m_acc_U_A1 = 0.; - m_acc_U_A2 = 0.; - // Loops over all people - blitz::firstIndex i; - blitz::secondIndex j; - blitz::Range rall = blitz::Range::all(); - for (size_t id=0; id<stats.size(); ++id) { - int n_session_i = stats[id].size(); - for (int h=0; h<n_session_i; ++h) { - computeIdPlusUProd_ih(stats[id][h]); - computeFn_x_ih(m, stats[id][h], id); - - // Needs to return values to be accumulated for estimating U - blitz::Array<double,1> x = m_x[id](rall, h); - m_tmp_ruru = m_cache_IdPlusUProd_ih; - m_tmp_ruru += x(i) * x(j); - for (int c=0; c<(int)m_dim_C; ++c) - { - blitz::Array<double,2> A1_x_c = m_acc_U_A1(c,rall,rall); - A1_x_c += m_tmp_ruru * stats[id][h]->n(c); - } - m_acc_U_A2 += m_cache_Fn_x_ih(i) * x(j); - } - } -} - -void bob::learn::em::FABaseTrainer::updateU(blitz::Array<double,2>& U) -{ - for (size_t c=0; c<m_dim_C; ++c) - { - const blitz::Array<double,2> A1 = m_acc_U_A1(c,blitz::Range::all(),blitz::Range::all()); - bob::math::inv(A1, m_tmp_ruru); - const blitz::Array<double,2> A2 = m_acc_U_A2(blitz::Range(c*m_dim_D,(c+1)*m_dim_D-1),blitz::Range::all()); - blitz::Array<double,2> U_c = U(blitz::Range(c*m_dim_D,(c+1)*m_dim_D-1),blitz::Range::all()); - bob::math::prod(A2, m_tmp_ruru, U_c); - } -} - - -//////////////////////////// D /////////////////////////// -void bob::learn::em::FABaseTrainer::computeDtSigmaInv(const bob::learn::em::FABase& m) -{ - const blitz::Array<double,1>& d = m.getD(); - const blitz::Array<double,1>& sigma = m.getUbmVariance(); - m_cache_DtSigmaInv = d / sigma; // Dt * diag(sigma)^-1 -} - -void bob::learn::em::FABaseTrainer::computeDProd(const bob::learn::em::FABase& m) -{ - const blitz::Array<double,1>& d = m.getD(); - const blitz::Array<double,1>& sigma = m.getUbmVariance(); - m_cache_DProd = d / sigma * d; // Dt * diag(sigma)^-1 * D -} - -void bob::learn::em::FABaseTrainer::computeIdPlusDProd_i(const size_t id) -{ - const blitz::Array<double,1>& Ni = m_Nacc[id]; - bob::core::array::repelem(Ni, m_tmp_CD); // m_tmp_CD = Ni 'repmat' - m_cache_IdPlusDProd_i = 1.; // m_cache_IdPlusDProd_i = Id - m_cache_IdPlusDProd_i += m_cache_DProd * m_tmp_CD; // m_cache_IdPlusDProd_i = I+Dt*diag(sigma)^-1*Ni*D - m_cache_IdPlusDProd_i = 1 / m_cache_IdPlusDProd_i; // m_cache_IdPlusVProd_i = (I+Dt*diag(sigma)^-1*Ni*D)^-1 -} - -void bob::learn::em::FABaseTrainer::computeFn_z_i( - const bob::learn::em::FABase& mb, - const std::vector<boost::shared_ptr<bob::learn::em::GMMStats> >& stats, const size_t id) -{ - const blitz::Array<double,2>& U = mb.getU(); - const blitz::Array<double,2>& V = mb.getV(); - // Compute Fn_z_i = sum_{sessions h}(N_{i,h}*(o_{i,h} - m - V*y_{i} - U*x_{i,h}) (Normalised first order statistics) - const blitz::Array<double,1>& Fi = m_Facc[id]; - const blitz::Array<double,1>& m = mb.getUbmMean(); - const blitz::Array<double,1>& y = m_y[id]; - bob::core::array::repelem(m_Nacc[id], m_tmp_CD); - bob::math::prod(V, y, m_tmp_CD_b); // m_tmp_CD_b = V * y - m_cache_Fn_z_i = Fi - m_tmp_CD * (m + m_tmp_CD_b); // Fn_yi = sum_{sessions h}(N_{i,h}*(o_{i,h} - m - V*y_{i}) - - const blitz::Array<double,2>& X = m_x[id]; - blitz::Range rall = blitz::Range::all(); - for (int h=0; h<X.extent(1); ++h) // Loops over the sessions - { - const blitz::Array<double,1>& Nh = stats[h]->n; // Nh = N_{i,h} (length: C) - bob::core::array::repelem(Nh, m_tmp_CD); - blitz::Array<double,1> Xh = X(rall, h); // Xh = x_{i,h} (length: ru) - bob::math::prod(U, Xh, m_tmp_CD_b); - m_cache_Fn_z_i -= m_tmp_CD * m_tmp_CD_b; - } - // Fn_z_i = sum_{sessions h}(N_{i,h}*(o_{i,h} - m - V*y_{i} - U*x_{i,h}) -} - -void bob::learn::em::FABaseTrainer::updateZ_i(const size_t id) -{ - // Computes zi = Azi * D^T.Sigma^-1 * Fn_zi - blitz::Array<double,1>& z = m_z[id]; - // m_tmp_CD = m_cache_DtSigmaInv * m_cache_Fn_z_i = Dt*diag(sigma)^-1 * sum_{sessions h}(N_{i,h}*(o_{i,h} - m - V*y_{i} - U*x_{i,h}) - z = m_cache_IdPlusDProd_i * m_cache_DtSigmaInv * m_cache_Fn_z_i; -} - -void bob::learn::em::FABaseTrainer::updateZ(const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats) -{ - // Precomputation - computeDtSigmaInv(m); - computeDProd(m); - // Loops over all people - for (size_t id=0; id<m_Nid; ++id) { - computeIdPlusDProd_i(id); - computeFn_z_i(m, stats[id], id); - updateZ_i(id); - } -} - -void bob::learn::em::FABaseTrainer::computeAccumulatorsD( - const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats) -{ - // Initializes the cache accumulator - m_acc_D_A1 = 0.; - m_acc_D_A2 = 0.; - // Loops over all people - blitz::firstIndex i; - blitz::secondIndex j; - for (size_t id=0; id<stats.size(); ++id) { - computeIdPlusDProd_i(id); - computeFn_z_i(m, stats[id], id); - - // Needs to return values to be accumulated for estimating D - blitz::Array<double,1> z = m_z[id]; - bob::core::array::repelem(m_Nacc[id], m_tmp_CD); - m_acc_D_A1 += (m_cache_IdPlusDProd_i + z * z) * m_tmp_CD; - m_acc_D_A2 += m_cache_Fn_z_i * z; - } -} - -void bob::learn::em::FABaseTrainer::updateD(blitz::Array<double,1>& d) -{ - d = m_acc_D_A2 / m_acc_D_A1; -} - - diff --git a/bob/learn/em/cpp/GMMBaseTrainer.cpp b/bob/learn/em/cpp/GMMBaseTrainer.cpp deleted file mode 100644 index f4697bd527e018866f6dfa10232e4b36546b5169..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/GMMBaseTrainer.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/GMMBaseTrainer.h> -#include <bob.core/assert.h> -#include <bob.core/check.h> - -bob::learn::em::GMMBaseTrainer::GMMBaseTrainer(const bool update_means, - const bool update_variances, const bool update_weights, - const double mean_var_update_responsibilities_threshold): - m_ss(new bob::learn::em::GMMStats()), - m_update_means(update_means), m_update_variances(update_variances), - m_update_weights(update_weights), - m_mean_var_update_responsibilities_threshold(mean_var_update_responsibilities_threshold) -{} - -bob::learn::em::GMMBaseTrainer::GMMBaseTrainer(const bob::learn::em::GMMBaseTrainer& b): - m_ss(new bob::learn::em::GMMStats( *b.getGMMStats() )), - m_update_means(b.m_update_means), m_update_variances(b.m_update_variances), - m_mean_var_update_responsibilities_threshold(b.m_mean_var_update_responsibilities_threshold) -{} - -bob::learn::em::GMMBaseTrainer::~GMMBaseTrainer() -{} - -void bob::learn::em::GMMBaseTrainer::initialize(bob::learn::em::GMMMachine& gmm) -{ - // Allocate memory for the sufficient statistics and initialise - m_ss->resize(gmm.getNGaussians(),gmm.getNInputs()); -} - -void bob::learn::em::GMMBaseTrainer::eStep(bob::learn::em::GMMMachine& gmm, - const blitz::Array<double,2>& data) -{ - m_ss->init(); - // Calculate the sufficient statistics and save in m_ss - gmm.accStatistics(data, *m_ss); -} - -double bob::learn::em::GMMBaseTrainer::computeLikelihood(bob::learn::em::GMMMachine& gmm) -{ - return m_ss->log_likelihood / m_ss->T; -} - - -bob::learn::em::GMMBaseTrainer& bob::learn::em::GMMBaseTrainer::operator= - (const bob::learn::em::GMMBaseTrainer &other) -{ - if (this != &other) - { - *m_ss = *other.m_ss; - m_update_means = other.m_update_means; - m_update_variances = other.m_update_variances; - m_update_weights = other.m_update_weights; - m_mean_var_update_responsibilities_threshold = other.m_mean_var_update_responsibilities_threshold; - } - return *this; -} - -bool bob::learn::em::GMMBaseTrainer::operator== - (const bob::learn::em::GMMBaseTrainer &other) const -{ - return *m_ss == *other.m_ss && - m_update_means == other.m_update_means && - m_update_variances == other.m_update_variances && - m_update_weights == other.m_update_weights && - m_mean_var_update_responsibilities_threshold == other.m_mean_var_update_responsibilities_threshold; -} - -bool bob::learn::em::GMMBaseTrainer::operator!= - (const bob::learn::em::GMMBaseTrainer &other) const -{ - return !(this->operator==(other)); -} - -bool bob::learn::em::GMMBaseTrainer::is_similar_to - (const bob::learn::em::GMMBaseTrainer &other, const double r_epsilon, - const double a_epsilon) const -{ - return *m_ss == *other.m_ss && - m_update_means == other.m_update_means && - m_update_variances == other.m_update_variances && - m_update_weights == other.m_update_weights && - bob::core::isClose(m_mean_var_update_responsibilities_threshold, - other.m_mean_var_update_responsibilities_threshold, r_epsilon, a_epsilon); -} - -void bob::learn::em::GMMBaseTrainer::setGMMStats(boost::shared_ptr<bob::learn::em::GMMStats> stats) -{ - bob::core::array::assertSameShape(m_ss->sumPx, stats->sumPx); - m_ss = stats; -} diff --git a/bob/learn/em/cpp/GMMMachine.cpp b/bob/learn/em/cpp/GMMMachine.cpp deleted file mode 100644 index d2512b7085f09d9938fbed063a092251d974b5c9..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/GMMMachine.cpp +++ /dev/null @@ -1,458 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/GMMMachine.h> -#include <bob.core/assert.h> -#include <bob.math/log.h> - -bob::learn::em::GMMMachine::GMMMachine(): m_gaussians(0) { - resize(0,0); -} - -bob::learn::em::GMMMachine::GMMMachine(const size_t n_gaussians, const size_t n_inputs): - m_gaussians(0) -{ - resize(n_gaussians,n_inputs); -} - -bob::learn::em::GMMMachine::GMMMachine(bob::io::base::HDF5File& config): - m_gaussians(0) -{ - load(config); -} - -bob::learn::em::GMMMachine::GMMMachine(const GMMMachine& other) -{ - copy(other); -} - - -bob::learn::em::GMMMachine& bob::learn::em::GMMMachine::operator=(const bob::learn::em::GMMMachine &other) { - // protect against invalid self-assignment - if (this != &other) - copy(other); - - // by convention, always return *this - return *this; -} - -bool bob::learn::em::GMMMachine::operator==(const bob::learn::em::GMMMachine& b) const -{ - if (m_n_gaussians != b.m_n_gaussians || m_n_inputs != b.m_n_inputs || - !bob::core::array::isEqual(m_weights, b.m_weights)) - return false; - - for(size_t i=0; i<m_n_gaussians; ++i) { - if(!(*(m_gaussians[i]) == *(b.m_gaussians[i]))) - return false; - } - - return true; -} - -bool bob::learn::em::GMMMachine::operator!=(const bob::learn::em::GMMMachine& b) const { - return !(this->operator==(b)); -} - -bool bob::learn::em::GMMMachine::is_similar_to(const bob::learn::em::GMMMachine& b, - const double r_epsilon, const double a_epsilon) const -{ - if (m_n_gaussians != b.m_n_gaussians || m_n_inputs != b.m_n_inputs || - !bob::core::array::isClose(m_weights, b.m_weights, r_epsilon, a_epsilon)) - return false; - - for (size_t i = 0; i < m_n_gaussians; ++i) - if (!m_gaussians[i]->is_similar_to(*b.m_gaussians[i], r_epsilon, a_epsilon)) - return false; - - return true; -} - -void bob::learn::em::GMMMachine::copy(const GMMMachine& other) { - m_n_gaussians = other.m_n_gaussians; - m_n_inputs = other.m_n_inputs; - - // Initialise weights - m_weights.resize(m_n_gaussians); - m_weights = other.m_weights; - - // Initialise Gaussians - m_gaussians.clear(); - for(size_t i=0; i<m_n_gaussians; ++i) { - boost::shared_ptr<bob::learn::em::Gaussian> g(new bob::learn::em::Gaussian(*(other.m_gaussians[i]))); - m_gaussians.push_back(g); - } - - // Initialise cache - initCache(); -} - - -bob::learn::em::GMMMachine::~GMMMachine() { -} - - -///////////////////// -// Setters -//////////////////// - -void bob::learn::em::GMMMachine::setWeights(const blitz::Array<double,1> &weights) { - bob::core::array::assertSameShape(weights, m_weights); - m_weights = weights; - recomputeLogWeights(); -} - -void bob::learn::em::GMMMachine::recomputeLogWeights() const -{ - m_cache_log_weights = blitz::log(m_weights); -} - -void bob::learn::em::GMMMachine::setMeans(const blitz::Array<double,2> &means) { - bob::core::array::assertSameDimensionLength(means.extent(0), m_n_gaussians); - bob::core::array::assertSameDimensionLength(means.extent(1), m_n_inputs); - for(size_t i=0; i<m_n_gaussians; ++i) - m_gaussians[i]->updateMean() = means(i,blitz::Range::all()); - m_cache_supervector = false; -} - -void bob::learn::em::GMMMachine::setMeanSupervector(const blitz::Array<double,1> &mean_supervector) { - bob::core::array::assertSameDimensionLength(mean_supervector.extent(0), m_n_gaussians*m_n_inputs); - for(size_t i=0; i<m_n_gaussians; ++i) - m_gaussians[i]->updateMean() = mean_supervector(blitz::Range(i*m_n_inputs, (i+1)*m_n_inputs-1)); - m_cache_supervector = false; -} - - -void bob::learn::em::GMMMachine::setVariances(const blitz::Array<double, 2 >& variances) { - bob::core::array::assertSameDimensionLength(variances.extent(0), m_n_gaussians); - bob::core::array::assertSameDimensionLength(variances.extent(1), m_n_inputs); - for(size_t i=0; i<m_n_gaussians; ++i) { - m_gaussians[i]->updateVariance() = variances(i,blitz::Range::all()); - m_gaussians[i]->applyVarianceThresholds(); - } - m_cache_supervector = false; -} - -void bob::learn::em::GMMMachine::setVarianceSupervector(const blitz::Array<double,1> &variance_supervector) { - bob::core::array::assertSameDimensionLength(variance_supervector.extent(0), m_n_gaussians*m_n_inputs); - for(size_t i=0; i<m_n_gaussians; ++i) { - m_gaussians[i]->updateVariance() = variance_supervector(blitz::Range(i*m_n_inputs, (i+1)*m_n_inputs-1)); - m_gaussians[i]->applyVarianceThresholds(); - } - m_cache_supervector = false; -} - -void bob::learn::em::GMMMachine::setVarianceThresholds(const double value) { - for(size_t i=0; i<m_n_gaussians; ++i) - m_gaussians[i]->setVarianceThresholds(value); - m_cache_supervector = false; -} - -void bob::learn::em::GMMMachine::setVarianceThresholds(blitz::Array<double, 1> variance_thresholds) { - bob::core::array::assertSameDimensionLength(variance_thresholds.extent(0), m_n_inputs); - for(size_t i=0; i<m_n_gaussians; ++i) - m_gaussians[i]->setVarianceThresholds(variance_thresholds); - m_cache_supervector = false; -} - -void bob::learn::em::GMMMachine::setVarianceThresholds(const blitz::Array<double, 2>& variance_thresholds) { - bob::core::array::assertSameDimensionLength(variance_thresholds.extent(0), m_n_gaussians); - bob::core::array::assertSameDimensionLength(variance_thresholds.extent(1), m_n_inputs); - for(size_t i=0; i<m_n_gaussians; ++i) - m_gaussians[i]->setVarianceThresholds(variance_thresholds(i,blitz::Range::all())); - m_cache_supervector = false; -} - -///////////////////// -// Getters -//////////////////// - -const blitz::Array<double,2> bob::learn::em::GMMMachine::getMeans() const { - - blitz::Array<double,2> means(m_n_gaussians,m_n_inputs); - for(size_t i=0; i<m_n_gaussians; ++i) - means(i,blitz::Range::all()) = m_gaussians[i]->getMean(); - - return means; -} - -const blitz::Array<double,2> bob::learn::em::GMMMachine::getVariances() const{ - - blitz::Array<double,2> variances(m_n_gaussians,m_n_inputs); - for(size_t i=0; i<m_n_gaussians; ++i) - variances(i,blitz::Range::all()) = m_gaussians[i]->getVariance(); - - return variances; -} - - -const blitz::Array<double,2> bob::learn::em::GMMMachine::getVarianceThresholds() const { - //bob::core::array::assertSameDimensionLength(variance_thresholds.extent(0), m_n_gaussians); - //bob::core::array::assertSameDimensionLength(variance_thresholds.extent(1), m_n_inputs); - blitz::Array<double, 2> variance_thresholds(m_n_gaussians, m_n_inputs); - for(size_t i=0; i<m_n_gaussians; ++i) - variance_thresholds(i,blitz::Range::all()) = m_gaussians[i]->getVarianceThresholds(); - - return variance_thresholds; -} - - -///////////////////// -// Methods -//////////////////// - - -void bob::learn::em::GMMMachine::resize(const size_t n_gaussians, const size_t n_inputs) { - m_n_gaussians = n_gaussians; - m_n_inputs = n_inputs; - - // Initialise weights - m_weights.resize(m_n_gaussians); - m_weights = 1.0 / m_n_gaussians; - - // Initialise Gaussians - m_gaussians.clear(); - for(size_t i=0; i<m_n_gaussians; ++i) - m_gaussians.push_back(boost::shared_ptr<bob::learn::em::Gaussian>(new bob::learn::em::Gaussian(n_inputs))); - - // Initialise cache arrays - initCache(); -} - -double bob::learn::em::GMMMachine::logLikelihood(const blitz::Array<double, 1> &x, - blitz::Array<double,1> &log_weighted_gaussian_likelihoods) const -{ - // Check dimension - bob::core::array::assertSameDimensionLength(log_weighted_gaussian_likelihoods.extent(0), m_n_gaussians); - bob::core::array::assertSameDimensionLength(x.extent(0), m_n_inputs); - return logLikelihood_(x,log_weighted_gaussian_likelihoods); -} - - -double bob::learn::em::GMMMachine::logLikelihood_(const blitz::Array<double, 1> &x, - blitz::Array<double,1> &log_weighted_gaussian_likelihoods) const -{ - // Initialise variables - double log_likelihood = bob::math::Log::LogZero; - - // Accumulate the weighted log likelihoods from each Gaussian - for(size_t i=0; i<m_n_gaussians; ++i) { - double l = m_cache_log_weights(i) + m_gaussians[i]->logLikelihood_(x); - log_weighted_gaussian_likelihoods(i) = l; - log_likelihood = bob::math::Log::logAdd(log_likelihood, l); - } - - // Return log(p(x|GMMMachine)) - return log_likelihood; -} - - -double bob::learn::em::GMMMachine::logLikelihood(const blitz::Array<double, 2> &x) const { - // Check dimension - bob::core::array::assertSameDimensionLength(x.extent(1), m_n_inputs); - // Call the other logLikelihood_ (overloaded) function - - - double sum_ll = 0; - for (int i=0; i<x.extent(0); i++) - sum_ll+= logLikelihood_(x(i,blitz::Range::all())); - - return sum_ll/x.extent(0); -} - - - -double bob::learn::em::GMMMachine::logLikelihood(const blitz::Array<double, 1> &x) const { - // Check dimension - bob::core::array::assertSameDimensionLength(x.extent(0), m_n_inputs); - // Call the other logLikelihood_ (overloaded) function - // (log_weighted_gaussian_likelihoods will be discarded) - return logLikelihood_(x,m_cache_log_weighted_gaussian_likelihoods); -} - - - -double bob::learn::em::GMMMachine::logLikelihood_(const blitz::Array<double, 1> &x) const { - // Call the other logLikelihood (overloaded) function - // (log_weighted_gaussian_likelihoods will be discarded) - return logLikelihood_(x,m_cache_log_weighted_gaussian_likelihoods); -} - -void bob::learn::em::GMMMachine::accStatistics(const blitz::Array<double,2>& input, - bob::learn::em::GMMStats& stats) const { - // iterate over data - blitz::Range a = blitz::Range::all(); - for(int i=0; i<input.extent(0); ++i) { - // Get example - blitz::Array<double,1> x(input(i,a)); - // Accumulate statistics - accStatistics(x,stats); - } -} - -void bob::learn::em::GMMMachine::accStatistics_(const blitz::Array<double,2>& input, bob::learn::em::GMMStats& stats) const { - // iterate over data - blitz::Range a = blitz::Range::all(); - for(int i=0; i<input.extent(0); ++i) { - // Get example - blitz::Array<double,1> x(input(i, a)); - // Accumulate statistics - accStatistics_(x,stats); - } -} - -void bob::learn::em::GMMMachine::accStatistics(const blitz::Array<double, 1>& x, bob::learn::em::GMMStats& stats) const { - // check GMMStats size - bob::core::array::assertSameDimensionLength(stats.sumPx.extent(0), m_n_gaussians); - bob::core::array::assertSameDimensionLength(stats.sumPx.extent(1), m_n_inputs); - - // Calculate Gaussian and GMM likelihoods - // - m_cache_log_weighted_gaussian_likelihoods(i) = log(weight_i*p(x|gaussian_i)) - // - log_likelihood = log(sum_i(weight_i*p(x|gaussian_i))) - double log_likelihood = logLikelihood(x, m_cache_log_weighted_gaussian_likelihoods); - - accStatisticsInternal(x, stats, log_likelihood); -} - -void bob::learn::em::GMMMachine::accStatistics_(const blitz::Array<double, 1>& x, bob::learn::em::GMMStats& stats) const { - // Calculate Gaussian and GMM likelihoods - // - m_cache_log_weighted_gaussian_likelihoods(i) = log(weight_i*p(x|gaussian_i)) - // - log_likelihood = log(sum_i(weight_i*p(x|gaussian_i))) - double log_likelihood = logLikelihood_(x, m_cache_log_weighted_gaussian_likelihoods); - - accStatisticsInternal(x, stats, log_likelihood); -} - -void bob::learn::em::GMMMachine::accStatisticsInternal(const blitz::Array<double, 1>& x, - bob::learn::em::GMMStats& stats, const double log_likelihood) const -{ - // Calculate responsibilities - m_cache_P = blitz::exp(m_cache_log_weighted_gaussian_likelihoods - log_likelihood); - - // Accumulate statistics - // - total likelihood - stats.log_likelihood += log_likelihood; - - // - number of samples - stats.T++; - - // - responsibilities - stats.n += m_cache_P; - - // - first order stats - blitz::firstIndex i; - blitz::secondIndex j; - - m_cache_Px = m_cache_P(i) * x(j); - - stats.sumPx += m_cache_Px; - - // - second order stats - stats.sumPxx += (m_cache_Px(i,j) * x(j)); -} - -boost::shared_ptr<bob::learn::em::Gaussian> bob::learn::em::GMMMachine::getGaussian(const size_t i) { - if (i>=m_n_gaussians) { - throw std::runtime_error("getGaussian(): index out of bounds"); - } - return m_gaussians[i]; -} - -void bob::learn::em::GMMMachine::save(bob::io::base::HDF5File& config) const { - int64_t v = static_cast<int64_t>(m_n_gaussians); - config.set("m_n_gaussians", v); - v = static_cast<int64_t>(m_n_inputs); - config.set("m_n_inputs", v); - - for(size_t i=0; i<m_n_gaussians; ++i) { - std::ostringstream oss; - oss << "m_gaussians" << i; - - if (!config.hasGroup(oss.str())) config.createGroup(oss.str()); - config.cd(oss.str()); - m_gaussians[i]->save(config); - config.cd(".."); - } - - config.setArray("m_weights", m_weights); -} - -void bob::learn::em::GMMMachine::load(bob::io::base::HDF5File& config) { - int64_t v; - v = config.read<int64_t>("m_n_gaussians"); - m_n_gaussians = static_cast<size_t>(v); - v = config.read<int64_t>("m_n_inputs"); - m_n_inputs = static_cast<size_t>(v); - - m_gaussians.clear(); - for(size_t i=0; i<m_n_gaussians; ++i) { - m_gaussians.push_back(boost::shared_ptr<bob::learn::em::Gaussian>(new bob::learn::em::Gaussian(m_n_inputs))); - std::ostringstream oss; - oss << "m_gaussians" << i; - config.cd(oss.str()); - m_gaussians[i]->load(config); - config.cd(".."); - } - - m_weights.resize(m_n_gaussians); - config.readArray("m_weights", m_weights); - - // Initialise cache - initCache(); -} - -void bob::learn::em::GMMMachine::updateCacheSupervectors() const -{ - m_cache_mean_supervector.resize(m_n_gaussians*m_n_inputs); - m_cache_variance_supervector.resize(m_n_gaussians*m_n_inputs); - - for(size_t i=0; i<m_n_gaussians; ++i) { - blitz::Range range(i*m_n_inputs, (i+1)*m_n_inputs-1); - m_cache_mean_supervector(range) = m_gaussians[i]->getMean(); - m_cache_variance_supervector(range) = m_gaussians[i]->getVariance(); - } - m_cache_supervector = true; -} - -void bob::learn::em::GMMMachine::initCache() const { - // Initialise cache arrays - m_cache_log_weights.resize(m_n_gaussians); - recomputeLogWeights(); - m_cache_log_weighted_gaussian_likelihoods.resize(m_n_gaussians); - m_cache_P.resize(m_n_gaussians); - m_cache_Px.resize(m_n_gaussians,m_n_inputs); - m_cache_supervector = false; -} - -void bob::learn::em::GMMMachine::reloadCacheSupervectors() const { - if(!m_cache_supervector) - updateCacheSupervectors(); -} - -const blitz::Array<double,1>& bob::learn::em::GMMMachine::getMeanSupervector() const { - if(!m_cache_supervector) - updateCacheSupervectors(); - return m_cache_mean_supervector; -} - -const blitz::Array<double,1>& bob::learn::em::GMMMachine::getVarianceSupervector() const { - if(!m_cache_supervector) - updateCacheSupervectors(); - return m_cache_variance_supervector; -} - -namespace bob { namespace learn { namespace em { - std::ostream& operator<<(std::ostream& os, const GMMMachine& machine) { - os << "Weights = " << machine.m_weights << std::endl; - for(size_t i=0; i < machine.m_n_gaussians; ++i) { - os << "Gaussian " << i << ": " << std::endl << *(machine.m_gaussians[i]); - } - - return os; - } -} } } diff --git a/bob/learn/em/cpp/GMMStats.cpp b/bob/learn/em/cpp/GMMStats.cpp deleted file mode 100644 index 8a9f783c58068b2b67f9a7ac0e735447ff265143..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/GMMStats.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/GMMStats.h> -#include <bob.core/logging.h> -#include <bob.core/check.h> - -bob::learn::em::GMMStats::GMMStats() { - resize(0,0); -} - -bob::learn::em::GMMStats::GMMStats(const size_t n_gaussians, const size_t n_inputs) { - resize(n_gaussians,n_inputs); -} - -bob::learn::em::GMMStats::GMMStats(bob::io::base::HDF5File& config) { - load(config); -} - -bob::learn::em::GMMStats::GMMStats(const bob::learn::em::GMMStats& other) { - copy(other); -} - -bob::learn::em::GMMStats::~GMMStats() { -} - -bob::learn::em::GMMStats& -bob::learn::em::GMMStats::operator=(const bob::learn::em::GMMStats& other) { - // protect against invalid self-assignment - if (this != &other) - copy(other); - - // by convention, always return *this - return *this; -} - -bool bob::learn::em::GMMStats::operator==(const bob::learn::em::GMMStats& b) const -{ - return (T == b.T && log_likelihood == b.log_likelihood && - bob::core::array::isEqual(n, b.n) && - bob::core::array::isEqual(sumPx, b.sumPx) && - bob::core::array::isEqual(sumPxx, b.sumPxx)); -} - -bool -bob::learn::em::GMMStats::operator!=(const bob::learn::em::GMMStats& b) const -{ - return !(this->operator==(b)); -} - -bool bob::learn::em::GMMStats::is_similar_to(const bob::learn::em::GMMStats& b, - const double r_epsilon, const double a_epsilon) const -{ - return (T == b.T && - bob::core::isClose(log_likelihood, b.log_likelihood, r_epsilon, a_epsilon) && - bob::core::array::isClose(n, b.n, r_epsilon, a_epsilon) && - bob::core::array::isClose(sumPx, b.sumPx, r_epsilon, a_epsilon) && - bob::core::array::isClose(sumPxx, b.sumPxx, r_epsilon, a_epsilon)); -} - - -void bob::learn::em::GMMStats::operator+=(const bob::learn::em::GMMStats& b) { - // Check dimensions - if(n.extent(0) != b.n.extent(0) || - sumPx.extent(0) != b.sumPx.extent(0) || sumPx.extent(1) != b.sumPx.extent(1) || - sumPxx.extent(0) != b.sumPxx.extent(0) || sumPxx.extent(1) != b.sumPxx.extent(1)) - // TODO: add a specialized exception - throw std::runtime_error("if you see this exception, fill a bug report"); - - // Update GMMStats object with the content of the other one - T += b.T; - log_likelihood += b.log_likelihood; - n += b.n; - sumPx += b.sumPx; - sumPxx += b.sumPxx; -} - -void bob::learn::em::GMMStats::copy(const GMMStats& other) { - // Resize arrays - resize(other.sumPx.extent(0),other.sumPx.extent(1)); - // Copy content - T = other.T; - log_likelihood = other.log_likelihood; - n = other.n; - sumPx = other.sumPx; - sumPxx = other.sumPxx; -} - -void bob::learn::em::GMMStats::resize(const size_t n_gaussians, const size_t n_inputs) { - n.resize(n_gaussians); - sumPx.resize(n_gaussians, n_inputs); - sumPxx.resize(n_gaussians, n_inputs); - init(); -} - -void bob::learn::em::GMMStats::init() { - log_likelihood = 0; - T = 0; - n = 0.0; - sumPx = 0.0; - sumPxx = 0.0; -} - -void bob::learn::em::GMMStats::save(bob::io::base::HDF5File& config) const { - //please note we fix the output values to be of a precise type so they can be - //retrieved at any platform with the exact same precision. - // TODO: add versioning, replace int64_t by uint64_t and log_liklihood by log_likelihood - int64_t sumpx_shape_0 = sumPx.shape()[0]; - int64_t sumpx_shape_1 = sumPx.shape()[1]; - config.set("n_gaussians", sumpx_shape_0); - config.set("n_inputs", sumpx_shape_1); - config.set("log_liklihood", log_likelihood); //double - config.set("T", static_cast<int64_t>(T)); - config.setArray("n", n); //Array1d - config.setArray("sumPx", sumPx); //Array2d - config.setArray("sumPxx", sumPxx); //Array2d -} - -void bob::learn::em::GMMStats::load(bob::io::base::HDF5File& config) { - log_likelihood = config.read<double>("log_liklihood"); - int64_t n_gaussians = config.read<int64_t>("n_gaussians"); - int64_t n_inputs = config.read<int64_t>("n_inputs"); - T = static_cast<size_t>(config.read<int64_t>("T")); - - //resize arrays to prepare for HDF5 readout - n.resize(n_gaussians); - sumPx.resize(n_gaussians, n_inputs); - sumPxx.resize(n_gaussians, n_inputs); - - //load data - config.readArray("n", n); - config.readArray("sumPx", sumPx); - config.readArray("sumPxx", sumPxx); -} - -namespace bob { namespace learn { namespace em { - std::ostream& operator<<(std::ostream& os, const GMMStats& g) { - os << "log_likelihood = " << g.log_likelihood << std::endl; - os << "T = " << g.T << std::endl; - os << "n = " << g.n; - os << "sumPx = " << g.sumPx; - os << "sumPxx = " << g.sumPxx; - - return os; - } -} } } diff --git a/bob/learn/em/cpp/Gaussian.cpp b/bob/learn/em/cpp/Gaussian.cpp deleted file mode 100644 index cd45f60f4248605bc48a934fbb7e7df5bf12b766..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/Gaussian.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/Gaussian.h> - -#include <bob.core/assert.h> -#include <bob.math/log.h> - -bob::learn::em::Gaussian::Gaussian() { - resize(0); -} - -bob::learn::em::Gaussian::Gaussian(const size_t n_inputs) { - resize(n_inputs); -} - -bob::learn::em::Gaussian::Gaussian(const bob::learn::em::Gaussian& other) { - copy(other); -} - -bob::learn::em::Gaussian::Gaussian(bob::io::base::HDF5File& config) { - load(config); -} - -bob::learn::em::Gaussian::~Gaussian() { -} - -bob::learn::em::Gaussian& bob::learn::em::Gaussian::operator=(const bob::learn::em::Gaussian &other) { - if(this != &other) - copy(other); - - return *this; -} - -bool bob::learn::em::Gaussian::operator==(const bob::learn::em::Gaussian& b) const -{ - return (bob::core::array::isEqual(m_mean, b.m_mean) && - bob::core::array::isEqual(m_variance, b.m_variance) && - bob::core::array::isEqual(m_variance_thresholds, b.m_variance_thresholds)); -} - -bool bob::learn::em::Gaussian::operator!=(const bob::learn::em::Gaussian& b) const { - return !(this->operator==(b)); -} - -bool bob::learn::em::Gaussian::is_similar_to(const bob::learn::em::Gaussian& b, - const double r_epsilon, const double a_epsilon) const -{ - return (bob::core::array::isClose(m_mean, b.m_mean, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_variance, b.m_variance, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_variance_thresholds, b.m_variance_thresholds, r_epsilon, a_epsilon)); -} - -void bob::learn::em::Gaussian::copy(const bob::learn::em::Gaussian& other) { - m_n_inputs = other.m_n_inputs; - - m_mean.resize(m_n_inputs); - m_mean = other.m_mean; - - m_variance.resize(m_n_inputs); - m_variance = other.m_variance; - - m_variance_thresholds.resize(m_n_inputs); - m_variance_thresholds = other.m_variance_thresholds; - - m_n_log2pi = other.m_n_log2pi; - m_g_norm = other.m_g_norm; -} - - -void bob::learn::em::Gaussian::setNInputs(const size_t n_inputs) { - resize(n_inputs); -} - -void bob::learn::em::Gaussian::resize(const size_t n_inputs) { - m_n_inputs = n_inputs; - m_mean.resize(m_n_inputs); - m_mean = 0; - m_variance.resize(m_n_inputs); - m_variance = 1; - m_variance_thresholds.resize(m_n_inputs); - m_variance_thresholds = std::numeric_limits<double>::epsilon(); - - // Re-compute g_norm, because m_n_inputs and m_variance - // have changed - preComputeNLog2Pi(); - preComputeConstants(); -} - -void bob::learn::em::Gaussian::setMean(const blitz::Array<double,1> &mean) { - // Check and set - bob::core::array::assertSameShape(m_mean, mean); - m_mean = mean; -} - -void bob::learn::em::Gaussian::setVariance(const blitz::Array<double,1> &variance) { - // Check and set - bob::core::array::assertSameShape(m_variance, variance); - m_variance = variance; - - // Variance flooring - applyVarianceThresholds(); -} - -void bob::learn::em::Gaussian::setVarianceThresholds(const blitz::Array<double,1> &variance_thresholds) { - // Check and set - bob::core::array::assertSameShape(m_variance_thresholds, variance_thresholds); - m_variance_thresholds = variance_thresholds; - - // Variance flooring - applyVarianceThresholds(); -} - -void bob::learn::em::Gaussian::setVarianceThresholds(const double value) { - blitz::Array<double,1> variance_thresholds(m_n_inputs); - variance_thresholds = value; - setVarianceThresholds(variance_thresholds); -} - -void bob::learn::em::Gaussian::applyVarianceThresholds() { - // Apply variance flooring threshold - m_variance = blitz::where( m_variance < m_variance_thresholds, m_variance_thresholds, m_variance); - - // Re-compute g_norm, because m_variance has changed - preComputeConstants(); -} - -double bob::learn::em::Gaussian::logLikelihood(const blitz::Array<double,1> &x) const { - // Check - bob::core::array::assertSameShape(x, m_mean); - return logLikelihood_(x); -} - -double bob::learn::em::Gaussian::logLikelihood_(const blitz::Array<double,1> &x) const { - double z = blitz::sum(blitz::pow2(x - m_mean) / m_variance); - // Log Likelihood - return (-0.5 * (m_g_norm + z)); -} - -void bob::learn::em::Gaussian::preComputeNLog2Pi() { - m_n_log2pi = m_n_inputs * bob::math::Log::Log2Pi; -} - -void bob::learn::em::Gaussian::preComputeConstants() { - m_g_norm = m_n_log2pi + blitz::sum(blitz::log(m_variance)); -} - -void bob::learn::em::Gaussian::save(bob::io::base::HDF5File& config) const { - config.setArray("m_mean", m_mean); - config.setArray("m_variance", m_variance); - config.setArray("m_variance_thresholds", m_variance_thresholds); - config.set("g_norm", m_g_norm); - int64_t v = static_cast<int64_t>(m_n_inputs); - config.set("m_n_inputs", v); -} - -void bob::learn::em::Gaussian::load(bob::io::base::HDF5File& config) { - int64_t v = config.read<int64_t>("m_n_inputs"); - m_n_inputs = static_cast<size_t>(v); - - m_mean.resize(m_n_inputs); - m_variance.resize(m_n_inputs); - m_variance_thresholds.resize(m_n_inputs); - - config.readArray("m_mean", m_mean); - config.readArray("m_variance", m_variance); - config.readArray("m_variance_thresholds", m_variance_thresholds); - - preComputeNLog2Pi(); - m_g_norm = config.read<double>("g_norm"); -} - -namespace bob { namespace learn { namespace em { - std::ostream& operator<<(std::ostream& os, const Gaussian& g) { - os << "Mean = " << g.m_mean << std::endl; - os << "Variance = " << g.m_variance << std::endl; - return os; - } -} } } diff --git a/bob/learn/em/cpp/ISVBase.cpp b/bob/learn/em/cpp/ISVBase.cpp deleted file mode 100644 index c299013dc143b2b34b50a7802797b6728059e076..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/ISVBase.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @date Tue Jan 27 16:02:00 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - - -#include <bob.learn.em/ISVBase.h> -#include <bob.core/array_copy.h> -#include <bob.math/linear.h> -#include <bob.math/inv.h> -#include <bob.learn.em/LinearScoring.h> -#include <limits> - - -//////////////////// ISVBase //////////////////// -bob::learn::em::ISVBase::ISVBase() -{ -} - -bob::learn::em::ISVBase::ISVBase(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm, - const size_t ru): - m_base(ubm, ru, 1) -{ - blitz::Array<double,2>& V = m_base.updateV(); - V = 0; -} - -bob::learn::em::ISVBase::ISVBase(const bob::learn::em::ISVBase& other): - m_base(other.m_base) -{ -} - - -bob::learn::em::ISVBase::ISVBase(bob::io::base::HDF5File& config) -{ - load(config); -} - -bob::learn::em::ISVBase::~ISVBase() { -} - -void bob::learn::em::ISVBase::save(bob::io::base::HDF5File& config) const -{ - config.setArray("U", m_base.getU()); - config.setArray("d", m_base.getD()); -} - -void bob::learn::em::ISVBase::load(bob::io::base::HDF5File& config) -{ - //reads all data directly into the member variables - blitz::Array<double,2> U = config.readArray<double,2>("U"); - blitz::Array<double,1> d = config.readArray<double,1>("d"); - const int ru = U.extent(1); - if (!m_base.getUbm()) - m_base.resize(ru, 1, U.extent(0)); - else - m_base.resize(ru, 1); - m_base.setU(U); - m_base.setD(d); - blitz::Array<double,2>& V = m_base.updateV(); - V = 0; -} - -bob::learn::em::ISVBase& -bob::learn::em::ISVBase::operator=(const bob::learn::em::ISVBase& other) -{ - if (this != &other) - { - m_base = other.m_base; - } - return *this; -} - diff --git a/bob/learn/em/cpp/ISVMachine.cpp b/bob/learn/em/cpp/ISVMachine.cpp deleted file mode 100644 index 578e5d29f61f04af197c0b27aa27f32bb70e72b7..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/ISVMachine.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/** - * @date Tue Jan 27 16:06:00 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - - -#include <bob.learn.em/ISVMachine.h> -#include <bob.core/array_copy.h> -#include <bob.math/linear.h> -#include <bob.math/inv.h> -#include <bob.learn.em/LinearScoring.h> -#include <limits> - - -//////////////////// ISVMachine //////////////////// -bob::learn::em::ISVMachine::ISVMachine(): - m_z(1) -{ - resizeTmp(); -} - -bob::learn::em::ISVMachine::ISVMachine(const boost::shared_ptr<bob::learn::em::ISVBase> isv_base): - m_isv_base(isv_base), - m_z(isv_base->getSupervectorLength()) -{ - if (!m_isv_base->getUbm()) - throw std::runtime_error("No UBM was set in the JFA machine."); - updateCache(); - resizeTmp(); -} - - -bob::learn::em::ISVMachine::ISVMachine(const bob::learn::em::ISVMachine& other): - m_isv_base(other.m_isv_base), - m_z(bob::core::array::ccopy(other.m_z)) -{ - updateCache(); - resizeTmp(); -} - -bob::learn::em::ISVMachine::ISVMachine(bob::io::base::HDF5File& config) -{ - load(config); -} - -bob::learn::em::ISVMachine::~ISVMachine() { -} - -bob::learn::em::ISVMachine& -bob::learn::em::ISVMachine::operator=(const bob::learn::em::ISVMachine& other) -{ - if (this != &other) - { - m_isv_base = other.m_isv_base; - m_z.reference(bob::core::array::ccopy(other.m_z)); - } - return *this; -} - -bool bob::learn::em::ISVMachine::operator==(const bob::learn::em::ISVMachine& other) const -{ - return (*m_isv_base == *(other.m_isv_base) && - bob::core::array::isEqual(m_z, other.m_z)); -} - -bool bob::learn::em::ISVMachine::operator!=(const bob::learn::em::ISVMachine& b) const -{ - return !(this->operator==(b)); -} - - -bool bob::learn::em::ISVMachine::is_similar_to(const bob::learn::em::ISVMachine& b, - const double r_epsilon, const double a_epsilon) const -{ - return (m_isv_base->is_similar_to(*(b.m_isv_base), r_epsilon, a_epsilon) && - bob::core::array::isClose(m_z, b.m_z, r_epsilon, a_epsilon)); -} - -void bob::learn::em::ISVMachine::save(bob::io::base::HDF5File& config) const -{ - config.setArray("z", m_z); -} - -void bob::learn::em::ISVMachine::load(bob::io::base::HDF5File& config) -{ - //reads all data directly into the member variables - blitz::Array<double,1> z = config.readArray<double,1>("z"); - if (!m_isv_base) - m_z.resize(z.extent(0)); - setZ(z); - // update cache - updateCache(); - resizeTmp(); -} - -void bob::learn::em::ISVMachine::setZ(const blitz::Array<double,1>& z) -{ - if(z.extent(0) != m_z.extent(0)) { //checks dimension - boost::format m("size of input vector `z' (%d) does not match the expected size (%d)"); - m % z.extent(0) % m_z.extent(0); - throw std::runtime_error(m.str()); - } - m_z.reference(bob::core::array::ccopy(z)); - // update cache - updateCache(); -} - - -void bob::learn::em::ISVMachine::setX(const blitz::Array<double,1>& x) -{ - if(x.extent(0) != m_cache_x.extent(0)) { //checks dimension - boost::format m("size of input vector `x' (%d) does not match the expected size (%d)"); - m % x.extent(0) % m_cache_x.extent(0); - throw std::runtime_error(m.str()); - } - m_cache_x.reference(bob::core::array::ccopy(x)); - // update cache - updateCache(); -} - -void bob::learn::em::ISVMachine::setISVBase(const boost::shared_ptr<bob::learn::em::ISVBase> isv_base) -{ - if (!isv_base->getUbm()) - throw std::runtime_error("No UBM was set in the JFA machine."); - m_isv_base = isv_base; - // Resize variables - resize(); -} - -void bob::learn::em::ISVMachine::resize() -{ - m_z.resizeAndPreserve(getSupervectorLength()); - updateCache(); - resizeTmp(); -} - -void bob::learn::em::ISVMachine::resizeTmp() -{ - if (m_isv_base) - { - m_tmp_Ux.resize(getSupervectorLength()); - } -} - -void bob::learn::em::ISVMachine::updateCache() -{ - if (m_isv_base) - { - // m + Dz - m_cache_mDz.resize(getSupervectorLength()); - m_cache_mDz = m_isv_base->getD()*m_z + m_isv_base->getUbm()->getMeanSupervector(); - m_cache_x.resize(getDimRu()); - } -} - -void bob::learn::em::ISVMachine::estimateUx(const bob::learn::em::GMMStats& gmm_stats, - blitz::Array<double,1>& Ux) -{ - estimateX(gmm_stats, m_cache_x); - bob::math::prod(m_isv_base->getU(), m_cache_x, Ux); -} - -double bob::learn::em::ISVMachine::forward(const bob::learn::em::GMMStats& input) -{ - return forward_(input); -} - -double bob::learn::em::ISVMachine::forward(const bob::learn::em::GMMStats& gmm_stats, - const blitz::Array<double,1>& Ux) -{ - // Checks that a Base machine has been set - if (!m_isv_base) throw std::runtime_error("No UBM was set in the JFA machine."); - - return bob::learn::em::linearScoring(m_cache_mDz, - m_isv_base->getUbm()->getMeanSupervector(), m_isv_base->getUbm()->getVarianceSupervector(), - gmm_stats, Ux, true); -} - -double bob::learn::em::ISVMachine::forward_(const bob::learn::em::GMMStats& input) -{ - // Checks that a Base machine has been set - if(!m_isv_base) throw std::runtime_error("No UBM was set in the JFA machine."); - - // Ux and GMMStats - estimateX(input, m_cache_x); - bob::math::prod(m_isv_base->getU(), m_cache_x, m_tmp_Ux); - - return bob::learn::em::linearScoring(m_cache_mDz, - m_isv_base->getUbm()->getMeanSupervector(), m_isv_base->getUbm()->getVarianceSupervector(), - input, m_tmp_Ux, true); -} - diff --git a/bob/learn/em/cpp/ISVTrainer.cpp b/bob/learn/em/cpp/ISVTrainer.cpp deleted file mode 100644 index cb00321a7e293a76469483b6e9e6863651b7eb66..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/ISVTrainer.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/** - * @date Tue Jul 19 12:16:17 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Joint Factor Analysis Trainer - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/ISVTrainer.h> -#include <bob.core/check.h> -#include <bob.core/array_copy.h> -#include <bob.core/array_random.h> -#include <bob.math/inv.h> -#include <bob.math/linear.h> -#include <bob.core/check.h> -#include <bob.core/array_repmat.h> -#include <algorithm> - - -//////////////////////////// ISVTrainer /////////////////////////// -bob::learn::em::ISVTrainer::ISVTrainer(const double relevance_factor): - m_relevance_factor(relevance_factor), - m_rng(new boost::mt19937()) -{} - -bob::learn::em::ISVTrainer::ISVTrainer(const bob::learn::em::ISVTrainer& other): - m_rng(other.m_rng) -{ - m_relevance_factor = other.m_relevance_factor; -} - -bob::learn::em::ISVTrainer::~ISVTrainer() -{} - -bob::learn::em::ISVTrainer& bob::learn::em::ISVTrainer::operator= -(const bob::learn::em::ISVTrainer& other) -{ - if (this != &other) - { - m_rng = other.m_rng; - m_relevance_factor = other.m_relevance_factor; - } - return *this; -} - -bool bob::learn::em::ISVTrainer::operator==(const bob::learn::em::ISVTrainer& b) const -{ - return m_rng == b.m_rng && - m_relevance_factor == b.m_relevance_factor; -} - -bool bob::learn::em::ISVTrainer::operator!=(const bob::learn::em::ISVTrainer& b) const -{ - return !(this->operator==(b)); -} - -bool bob::learn::em::ISVTrainer::is_similar_to(const bob::learn::em::ISVTrainer& b, - const double r_epsilon, const double a_epsilon) const -{ - return m_rng == b.m_rng && - m_relevance_factor == b.m_relevance_factor; -} - -void bob::learn::em::ISVTrainer::initialize(bob::learn::em::ISVBase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - m_base_trainer.initUbmNidSumStatistics(machine.getBase(), ar); - m_base_trainer.initializeXYZ(ar); - - blitz::Array<double,2>& U = machine.updateU(); - bob::core::array::randn(*m_rng, U); - initializeD(machine); - machine.precompute(); -} - -void bob::learn::em::ISVTrainer::initializeD(bob::learn::em::ISVBase& machine) const -{ - // D = sqrt(variance(UBM) / relevance_factor) - blitz::Array<double,1> d = machine.updateD(); - d = sqrt(machine.getBase().getUbmVariance() / m_relevance_factor); -} - -void bob::learn::em::ISVTrainer::eStep(bob::learn::em::ISVBase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - m_base_trainer.resetXYZ(); - - const bob::learn::em::FABase& base = machine.getBase(); - m_base_trainer.updateX(base, ar); - m_base_trainer.updateZ(base, ar); - m_base_trainer.computeAccumulatorsU(base, ar); -} - -void bob::learn::em::ISVTrainer::mStep(bob::learn::em::ISVBase& machine) -{ - blitz::Array<double,2>& U = machine.updateU(); - m_base_trainer.updateU(U); - machine.precompute(); -} - -double bob::learn::em::ISVTrainer::computeLikelihood(bob::learn::em::ISVBase& machine) -{ - // TODO - return 0; -} - -void bob::learn::em::ISVTrainer::enroll(bob::learn::em::ISVMachine& machine, - const std::vector<boost::shared_ptr<bob::learn::em::GMMStats> >& ar, - const size_t n_iter) -{ - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > vvec; - vvec.push_back(ar); - - const bob::learn::em::FABase& fb = machine.getISVBase()->getBase(); - - m_base_trainer.initUbmNidSumStatistics(fb, vvec); - m_base_trainer.initializeXYZ(vvec); - - for (size_t i=0; i<n_iter; ++i) { - m_base_trainer.updateX(fb, vvec); - m_base_trainer.updateZ(fb, vvec); - } - - const blitz::Array<double,1> z(m_base_trainer.getZ()[0]); - machine.setZ(z); -} diff --git a/bob/learn/em/cpp/IVectorMachine.cpp b/bob/learn/em/cpp/IVectorMachine.cpp deleted file mode 100644 index 912ba7d556f372563061b23d623670f49f1100b1..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/IVectorMachine.cpp +++ /dev/null @@ -1,250 +0,0 @@ -/** - * @date Sat Mar 30 21:00:00 2013 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/IVectorMachine.h> -#include <bob.core/array_copy.h> -#include <bob.core/check.h> -#include <bob.math/linear.h> -#include <bob.math/linsolve.h> - -bob::learn::em::IVectorMachine::IVectorMachine() -{ -} - -bob::learn::em::IVectorMachine::IVectorMachine(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm, - const size_t rt, const double variance_threshold): - m_ubm(ubm), m_rt(rt), - m_T(getSupervectorLength(),rt), m_sigma(getSupervectorLength()), - m_variance_threshold(variance_threshold) -{ - m_sigma = 0.0; - resizePrecompute(); -} - -bob::learn::em::IVectorMachine::IVectorMachine(const bob::learn::em::IVectorMachine& other): - m_ubm(other.m_ubm), m_rt(other.m_rt), - m_T(bob::core::array::ccopy(other.m_T)), - m_sigma(bob::core::array::ccopy(other.m_sigma)), - m_variance_threshold(other.m_variance_threshold) -{ - resizePrecompute(); -} - -bob::learn::em::IVectorMachine::IVectorMachine(bob::io::base::HDF5File& config) -{ - load(config); -} - -bob::learn::em::IVectorMachine::~IVectorMachine() { -} - -void bob::learn::em::IVectorMachine::save(bob::io::base::HDF5File& config) const -{ - config.setArray("m_T", m_T); - config.setArray("m_sigma", m_sigma); - config.set("m_variance_threshold", m_variance_threshold); -} - -void bob::learn::em::IVectorMachine::load(bob::io::base::HDF5File& config) -{ - //reads all data directly into the member variables - m_T.reference(config.readArray<double,2>("m_T")); - m_rt = m_T.extent(1); - m_sigma.reference(config.readArray<double,1>("m_sigma")); - m_variance_threshold = config.read<double>("m_variance_threshold"); - resizePrecompute(); -} - -void bob::learn::em::IVectorMachine::resize(const size_t rt) -{ - m_rt = rt; - m_T.resizeAndPreserve(m_T.extent(0), rt); - resizePrecompute(); -} - -bob::learn::em::IVectorMachine& -bob::learn::em::IVectorMachine::operator=(const bob::learn::em::IVectorMachine& other) -{ - if (this != &other) - { - m_ubm = other.m_ubm; - m_rt = other.m_rt; - m_T.reference(bob::core::array::ccopy(other.m_T)); - m_sigma.reference(bob::core::array::ccopy(other.m_sigma)); - m_variance_threshold = other.m_variance_threshold; - resizePrecompute(); - } - return *this; -} - -bool bob::learn::em::IVectorMachine::operator==(const IVectorMachine& b) const -{ - return (((m_ubm && b.m_ubm) && *m_ubm == *(b.m_ubm)) || (!m_ubm && !b.m_ubm)) && - m_rt == b.m_rt && - bob::core::array::isEqual(m_T, b.m_T) && - bob::core::array::isEqual(m_sigma, b.m_sigma) && - m_variance_threshold == b.m_variance_threshold; -} - -bool bob::learn::em::IVectorMachine::operator!=(const bob::learn::em::IVectorMachine& b) const -{ - return !(this->operator==(b)); -} - -bool bob::learn::em::IVectorMachine::is_similar_to(const IVectorMachine& b, - const double r_epsilon, const double a_epsilon) const -{ - // TODO: update with new is_similar_to method - return (((m_ubm && b.m_ubm) && m_ubm->is_similar_to(*(b.m_ubm), r_epsilon)) || (!m_ubm && !b.m_ubm)) && - m_rt == b.m_rt && - bob::core::array::isClose(m_T, b.m_T, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_sigma, b.m_sigma, r_epsilon, a_epsilon) && - bob::core::isClose(m_variance_threshold, b.m_variance_threshold, r_epsilon, a_epsilon); -} - -void bob::learn::em::IVectorMachine::setUbm(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm) -{ - m_ubm = ubm; - resizePrecompute(); -} - -void bob::learn::em::IVectorMachine::setT(const blitz::Array<double,2>& T) -{ - bob::core::array::assertSameShape(m_T, T); - m_T = T; - // Update cache - precompute(); -} - -void bob::learn::em::IVectorMachine::setSigma(const blitz::Array<double,1>& sigma) -{ - bob::core::array::assertSameShape(m_sigma, sigma); - m_sigma = sigma; - // Update cache - precompute(); -} - - -void bob::learn::em::IVectorMachine::setVarianceThreshold(const double thd) -{ - m_variance_threshold = thd; - // Update cache - precompute(); -} - -void bob::learn::em::IVectorMachine::applyVarianceThreshold() -{ - // Apply variance flooring threshold - m_sigma = blitz::where(m_sigma < m_variance_threshold, m_variance_threshold, m_sigma); -} - -void bob::learn::em::IVectorMachine::precompute() -{ - if (m_ubm) - { - // Apply variance threshold - applyVarianceThreshold(); - - blitz::firstIndex i; - blitz::secondIndex j; - blitz::Range rall = blitz::Range::all(); - const int C = (int)m_ubm->getNGaussians(); - const int D = (int)m_ubm->getNInputs(); - - // T_{c}^{T}.sigma_{c}^{-1} - for (int c=0; c<C; ++c) - { - blitz::Array<double,2> Tct_sigmacInv = m_cache_Tct_sigmacInv(c, rall, rall); - blitz::Array<double,2> Tc = m_T(blitz::Range(c*D,(c+1)*D-1), rall); - blitz::Array<double,2> Tct = Tc.transpose(1,0); - blitz::Array<double,1> sigma_c = m_sigma(blitz::Range(c*D,(c+1)*D-1)); - Tct_sigmacInv = Tct(i,j) / sigma_c(j); - } - - // T_{c}^{T}.sigma_{c}^{-1}.T_{c} - for (int c=0; c<C; ++c) - { - blitz::Array<double,2> Tc = m_T(blitz::Range(c*D,(c+1)*D-1), rall); - blitz::Array<double,2> Tct_sigmacInv = m_cache_Tct_sigmacInv(c, rall, rall); - blitz::Array<double,2> Tct_sigmacInv_Tc = m_cache_Tct_sigmacInv_Tc(c, rall, rall); - bob::math::prod(Tct_sigmacInv, Tc, Tct_sigmacInv_Tc); - } - } -} - -void bob::learn::em::IVectorMachine::resizePrecompute() -{ - resizeCache(); - resizeTmp(); - precompute(); -} - -void bob::learn::em::IVectorMachine::resizeCache() -{ - if (m_ubm) - { - const int C = (int)m_ubm->getNGaussians(); - const int D = (int)m_ubm->getNInputs(); - m_cache_Tct_sigmacInv.resize(C, (int)m_rt, D); - m_cache_Tct_sigmacInv_Tc.resize(C, (int)m_rt, (int)m_rt); - } -} - -void bob::learn::em::IVectorMachine::resizeTmp() -{ - if (m_ubm) - m_tmp_d.resize(m_ubm->getNInputs()); - m_tmp_t1.resize(m_rt); - m_tmp_t2.resize(m_rt); - m_tmp_tt.resize(m_rt, m_rt); -} - -void bob::learn::em::IVectorMachine::forward(const bob::learn::em::GMMStats& gs, - blitz::Array<double,1>& ivector) const -{ - bob::core::array::assertSameDimensionLength(ivector.extent(0), (int)m_rt); - forward_(gs, ivector); -} - -void bob::learn::em::IVectorMachine::computeIdTtSigmaInvT( - const bob::learn::em::GMMStats& gs, blitz::Array<double,2>& output) const -{ - // Computes \f$(Id + \sum_{c=1}^{C} N_{i,j,c} T^{T} \Sigma_{c}^{-1} T)\f$ - blitz::Range rall = blitz::Range::all(); - bob::math::eye(output); - for (int c=0; c<(int)getNGaussians(); ++c) - output += gs.n(c) * m_cache_Tct_sigmacInv_Tc(c, rall, rall); -} - -void bob::learn::em::IVectorMachine::computeTtSigmaInvFnorm( - const bob::learn::em::GMMStats& gs, blitz::Array<double,1>& output) const -{ - // Computes \f$T^{T} \Sigma^{-1} \sum_{c=1}^{C} (F_c - N_c ubmmean_{c})\f$ - blitz::Range rall = blitz::Range::all(); - output = 0; - for (int c=0; c<(int)getNGaussians(); ++c) - { - m_tmp_d = gs.sumPx(c,rall) - gs.n(c) * m_ubm->getGaussian(c)->getMean(); - blitz::Array<double,2> Tct_sigmacInv = m_cache_Tct_sigmacInv(c, rall, rall); - bob::math::prod(Tct_sigmacInv, m_tmp_d, m_tmp_t2); - - output += m_tmp_t2; - } -} - -void bob::learn::em::IVectorMachine::forward_(const bob::learn::em::GMMStats& gs, - blitz::Array<double,1>& ivector) const -{ - // Computes \f$(Id + \sum_{c=1}^{C} N_{i,j,c} T^{T} \Sigma_{c}^{-1} T)\f$ - computeIdTtSigmaInvT(gs, m_tmp_tt); - - // Computes \f$T^{T} \Sigma^{-1} \sum_{c=1}^{C} (F_c - N_c ubmmean_{c})\f$ - computeTtSigmaInvFnorm(gs, m_tmp_t1); - - // Solves m_tmp_tt.ivector = m_tmp_t1 - bob::math::linsolve(m_tmp_tt, m_tmp_t1, ivector); -} diff --git a/bob/learn/em/cpp/IVectorTrainer.cpp b/bob/learn/em/cpp/IVectorTrainer.cpp deleted file mode 100644 index 591de601cf195b9be555a8873dc7814512d3a64f..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/IVectorTrainer.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/** - * @date Sun Mar 31 20:15:00 2013 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - - -#include <bob.learn.em/IVectorTrainer.h> -#include <bob.core/check.h> -#include <bob.core/array_copy.h> -#include <bob.core/array_random.h> -#include <bob.math/inv.h> -#include <bob.core/check.h> -#include <bob.core/array_repmat.h> -#include <algorithm> - -#include <bob.math/linear.h> -#include <bob.math/linsolve.h> - -bob::learn::em::IVectorTrainer::IVectorTrainer(const bool update_sigma): - m_update_sigma(update_sigma), - m_rng(new boost::mt19937()) -{} - -bob::learn::em::IVectorTrainer::IVectorTrainer(const bob::learn::em::IVectorTrainer& other): - m_update_sigma(other.m_update_sigma) -{ - m_rng = other.m_rng; - m_acc_Nij_wij2.reference(bob::core::array::ccopy(other.m_acc_Nij_wij2)); - m_acc_Fnormij_wij.reference(bob::core::array::ccopy(other.m_acc_Fnormij_wij)); - m_acc_Nij.reference(bob::core::array::ccopy(other.m_acc_Nij)); - m_acc_Snormij.reference(bob::core::array::ccopy(other.m_acc_Snormij)); - - m_tmp_wij.reference(bob::core::array::ccopy(other.m_tmp_wij)); - m_tmp_wij2.reference(bob::core::array::ccopy(other.m_tmp_wij2)); - m_tmp_d1.reference(bob::core::array::ccopy(other.m_tmp_d1)); - m_tmp_t1.reference(bob::core::array::ccopy(other.m_tmp_t1)); - m_tmp_dd1.reference(bob::core::array::ccopy(other.m_tmp_dd1)); - m_tmp_dt1.reference(bob::core::array::ccopy(other.m_tmp_dt1)); - m_tmp_tt1.reference(bob::core::array::ccopy(other.m_tmp_tt1)); - m_tmp_tt2.reference(bob::core::array::ccopy(other.m_tmp_tt2)); -} - -bob::learn::em::IVectorTrainer::~IVectorTrainer() -{ -} - -void bob::learn::em::IVectorTrainer::initialize( - bob::learn::em::IVectorMachine& machine) -{ - // Initializes \f$T\f$ and \f$\Sigma\f$ of the machine - blitz::Array<double,2>& T = machine.updateT(); - bob::core::array::randn(*m_rng, T); - blitz::Array<double,1>& sigma = machine.updateSigma(); - sigma = machine.getUbm()->getVarianceSupervector(); - machine.precompute(); -} - -void bob::learn::em::IVectorTrainer::resetAccumulators(const bob::learn::em::IVectorMachine& machine) -{ - // Resize the accumulator - const int C = machine.getNGaussians(); - const int D = machine.getNInputs(); - const int Rt = machine.getDimRt(); - - // Cache - m_acc_Nij_wij2.resize(C,Rt,Rt); - m_acc_Fnormij_wij.resize(C,D,Rt); - if (m_update_sigma) - { - m_acc_Nij.resize(C); - m_acc_Snormij.resize(C,D); - } - - // Tmp - m_tmp_wij.resize(Rt); - m_tmp_wij2.resize(Rt,Rt); - m_tmp_d1.resize(D); - m_tmp_t1.resize(Rt); - - m_tmp_dt1.resize(D,Rt); - m_tmp_tt1.resize(Rt,Rt); - m_tmp_tt2.resize(Rt,Rt); - if (m_update_sigma) - m_tmp_dd1.resize(D,D); - - // initialize with 0 - m_acc_Nij_wij2 = 0.; - m_acc_Fnormij_wij = 0.; - if (m_update_sigma) - { - m_acc_Nij = 0.; - m_acc_Snormij = 0.; - } -} - - -void bob::learn::em::IVectorTrainer::eStep( - bob::learn::em::IVectorMachine& machine, - const std::vector<bob::learn::em::GMMStats>& data) -{ - blitz::Range rall = blitz::Range::all(); - const int C = machine.getNGaussians(); - - // Reinitializes accumulators to 0 - resetAccumulators(machine); - - for (std::vector<bob::learn::em::GMMStats>::const_iterator it = data.begin(); - it != data.end(); ++it) - { - // Computes E{wij} and E{wij.wij^{T}} - // a. Computes \f$T^{T} \Sigma^{-1} F_{norm}\f$ - machine.computeTtSigmaInvFnorm(*it, m_tmp_t1); - // b. Computes \f$Id + T^{T} \Sigma^{-1} T\f$ - machine.computeIdTtSigmaInvT(*it, m_tmp_tt1); - // c. Computes \f$(Id + T^{T} \Sigma^{-1} T)^{-1}\f$ - - bob::math::inv(m_tmp_tt1, m_tmp_tt2); - // d. Computes \f$E{wij} = (Id + T^{T} \Sigma^{-1} T)^{-1} T^{T} \Sigma^{-1} F_{norm}\f$ - bob::math::prod(m_tmp_tt2, m_tmp_t1, m_tmp_wij); // E{wij} - // e. Computes \f$E{wij}.E{wij^{T}}\f$ - bob::math::prod(m_tmp_wij, m_tmp_wij, m_tmp_wij2); - // f. Computes \f$E{wij.wij^{T}} = (Id + T^{T} \Sigma^{-1} T)^{-1} + E{wij}.E{wij^{T}}\f$ - m_tmp_wij2 += m_tmp_tt2; // E{wij.wij^{T}} - - if (m_update_sigma) - m_acc_Nij += (*it).n; - - for (int c=0; c<C; ++c) - { - blitz::Array<double,2> acc_Nij_wij2_c = m_acc_Nij_wij2(c,rall,rall); - blitz::Array<double,2> acc_Fnormij_wij = m_acc_Fnormij_wij(c,rall,rall); - // acc_Nij_wij2_c += Nijc . E{wij.wij^{T}} - acc_Nij_wij2_c += (*it).n(c) * m_tmp_wij2; - blitz::Array<double,1> mc = machine.getUbm()->getGaussian(c)->getMean(); - // m_tmp_d1 = Fijc - Nijc * ubmmean_{c} - m_tmp_d1 = (*it).sumPx(c,rall) - (*it).n(c)*mc; // Fnorm_c - // m_tmp_dt1 = (Fijc - Nijc * ubmmean_{c}).E{wij}^{T} - bob::math::prod(m_tmp_d1, m_tmp_wij, m_tmp_dt1); - // acc_Fnormij_wij += (Fijc - Nijc * ubmmean_{c}).E{wij}^{T} - acc_Fnormij_wij += m_tmp_dt1; - if (m_update_sigma) - { - blitz::Array<double,1> acc_Snormij_c = m_acc_Snormij(c,rall); - acc_Snormij_c += (*it).sumPxx(c,rall) - mc*((*it).sumPx(c,rall) + m_tmp_d1); - } - } - } -} - -void bob::learn::em::IVectorTrainer::mStep( - bob::learn::em::IVectorMachine& machine) -{ - blitz::Range rall = blitz::Range::all(); - blitz::Array<double,2>& T = machine.updateT(); - blitz::Array<double,1>& sigma = machine.updateSigma(); - const int C = (int)machine.getNGaussians(); - const int D = (int)machine.getNInputs(); - for (int c=0; c<C; ++c) - { - // Solves linear system A.T = B to update T, based on accumulators of - // the eStep() - blitz::Array<double,2> acc_Nij_wij2_c = m_acc_Nij_wij2(c,rall,rall); - blitz::Array<double,2> tacc_Nij_wij2_c = acc_Nij_wij2_c.transpose(1,0); - blitz::Array<double,2> acc_Fnormij_wij_c = m_acc_Fnormij_wij(c,rall,rall); - blitz::Array<double,2> tacc_Fnormij_wij_c = acc_Fnormij_wij_c.transpose(1,0); - blitz::Array<double,2> T_c = T(blitz::Range(c*D,(c+1)*D-1),rall); - blitz::Array<double,2> Tt_c = T_c.transpose(1,0); - if (blitz::all(acc_Nij_wij2_c == 0)) // TODO - Tt_c = 0; - else - bob::math::linsolve(tacc_Nij_wij2_c, tacc_Fnormij_wij_c, Tt_c); - if (m_update_sigma) - { - blitz::Array<double,1> sigma_c = sigma(blitz::Range(c*D,(c+1)*D-1)); - bob::math::prod(acc_Fnormij_wij_c, Tt_c, m_tmp_dd1); - bob::math::diag(m_tmp_dd1, m_tmp_d1); - sigma_c = (m_acc_Snormij(c,rall) - m_tmp_d1) / m_acc_Nij(c); - } - } - machine.precompute(); -} - - -bob::learn::em::IVectorTrainer& bob::learn::em::IVectorTrainer::operator= - (const bob::learn::em::IVectorTrainer &other) -{ - if (this != &other) - { - m_update_sigma = other.m_update_sigma; - - m_acc_Nij_wij2.reference(bob::core::array::ccopy(other.m_acc_Nij_wij2)); - m_acc_Fnormij_wij.reference(bob::core::array::ccopy(other.m_acc_Fnormij_wij)); - m_acc_Nij.reference(bob::core::array::ccopy(other.m_acc_Nij)); - m_acc_Snormij.reference(bob::core::array::ccopy(other.m_acc_Snormij)); - - m_tmp_wij.reference(bob::core::array::ccopy(other.m_tmp_wij)); - m_tmp_wij2.reference(bob::core::array::ccopy(other.m_tmp_wij2)); - m_tmp_d1.reference(bob::core::array::ccopy(other.m_tmp_d1)); - m_tmp_t1.reference(bob::core::array::ccopy(other.m_tmp_t1)); - m_tmp_dd1.reference(bob::core::array::ccopy(other.m_tmp_dd1)); - m_tmp_dt1.reference(bob::core::array::ccopy(other.m_tmp_dt1)); - m_tmp_tt1.reference(bob::core::array::ccopy(other.m_tmp_tt1)); - m_tmp_tt2.reference(bob::core::array::ccopy(other.m_tmp_tt2)); - } - return *this; -} - -bool bob::learn::em::IVectorTrainer::operator== - (const bob::learn::em::IVectorTrainer &other) const -{ - return m_update_sigma == other.m_update_sigma && - bob::core::array::isEqual(m_acc_Nij_wij2, other.m_acc_Nij_wij2) && - bob::core::array::isEqual(m_acc_Fnormij_wij, other.m_acc_Fnormij_wij) && - bob::core::array::isEqual(m_acc_Nij, other.m_acc_Nij) && - bob::core::array::isEqual(m_acc_Snormij, other.m_acc_Snormij); -} - -bool bob::learn::em::IVectorTrainer::operator!= - (const bob::learn::em::IVectorTrainer &other) const -{ - return !(this->operator==(other)); -} - -bool bob::learn::em::IVectorTrainer::is_similar_to - (const bob::learn::em::IVectorTrainer &other, const double r_epsilon, - const double a_epsilon) const -{ - return m_update_sigma == other.m_update_sigma && - bob::core::array::isClose(m_acc_Nij_wij2, other.m_acc_Nij_wij2, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_acc_Fnormij_wij, other.m_acc_Fnormij_wij, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_acc_Nij, other.m_acc_Nij, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_acc_Snormij, other.m_acc_Snormij, r_epsilon, a_epsilon); -} diff --git a/bob/learn/em/cpp/JFABase.cpp b/bob/learn/em/cpp/JFABase.cpp deleted file mode 100644 index b80bfd31d959f8e0e7fc3004a3ee0980b49e4a50..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/JFABase.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @date Tue Jan 27 15:54:00 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - - -#include <bob.learn.em/JFABase.h> -#include <bob.core/array_copy.h> -#include <bob.math/linear.h> -#include <bob.math/inv.h> -#include <bob.learn.em/LinearScoring.h> -#include <limits> - - -//////////////////// JFABase //////////////////// -bob::learn::em::JFABase::JFABase() -{ -} - -bob::learn::em::JFABase::JFABase(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm, - const size_t ru, const size_t rv): - m_base(ubm, ru, rv) -{ -} - -bob::learn::em::JFABase::JFABase(const bob::learn::em::JFABase& other): - m_base(other.m_base) -{ -} - - -bob::learn::em::JFABase::JFABase(bob::io::base::HDF5File& config) -{ - load(config); -} - -bob::learn::em::JFABase::~JFABase() { -} - -void bob::learn::em::JFABase::save(bob::io::base::HDF5File& config) const -{ - config.setArray("U", m_base.getU()); - config.setArray("V", m_base.getV()); - config.setArray("d", m_base.getD()); -} - -void bob::learn::em::JFABase::load(bob::io::base::HDF5File& config) -{ - //reads all data directly into the member variables - blitz::Array<double,2> U = config.readArray<double,2>("U"); - blitz::Array<double,2> V = config.readArray<double,2>("V"); - blitz::Array<double,1> d = config.readArray<double,1>("d"); - const int ru = U.extent(1); - const int rv = V.extent(1); - if (!m_base.getUbm()) - m_base.resize(ru, rv, U.extent(0)); - else - m_base.resize(ru, rv); - m_base.setU(U); - m_base.setV(V); - m_base.setD(d); -} - -bob::learn::em::JFABase& -bob::learn::em::JFABase::operator=(const bob::learn::em::JFABase& other) -{ - if (this != &other) - { - m_base = other.m_base; - } - return *this; -} diff --git a/bob/learn/em/cpp/JFAMachine.cpp b/bob/learn/em/cpp/JFAMachine.cpp deleted file mode 100644 index 508c5008bcb59479e4a966eb6de31a6f14649d99..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/JFAMachine.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/** - * @date Tue Jan 27 16:47:00 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - - -#include <bob.learn.em/JFAMachine.h> -#include <bob.core/array_copy.h> -#include <bob.math/linear.h> -#include <bob.math/inv.h> -#include <bob.learn.em/LinearScoring.h> -#include <limits> - - -//////////////////// JFAMachine //////////////////// -bob::learn::em::JFAMachine::JFAMachine(): - m_y(1), m_z(1) -{ - resizeTmp(); -} - -bob::learn::em::JFAMachine::JFAMachine(const boost::shared_ptr<bob::learn::em::JFABase> jfa_base): - m_jfa_base(jfa_base), - m_y(jfa_base->getDimRv()), m_z(jfa_base->getSupervectorLength()) -{ - if (!m_jfa_base->getUbm()) throw std::runtime_error("No UBM was set in the JFA machine."); - updateCache(); - resizeTmp(); -} - - -bob::learn::em::JFAMachine::JFAMachine(const bob::learn::em::JFAMachine& other): - m_jfa_base(other.m_jfa_base), - m_y(bob::core::array::ccopy(other.m_y)), - m_z(bob::core::array::ccopy(other.m_z)) -{ - updateCache(); - resizeTmp(); -} - -bob::learn::em::JFAMachine::JFAMachine(bob::io::base::HDF5File& config) -{ - load(config); -} - -bob::learn::em::JFAMachine::~JFAMachine() { -} - -bob::learn::em::JFAMachine& -bob::learn::em::JFAMachine::operator=(const bob::learn::em::JFAMachine& other) -{ - if (this != &other) - { - m_jfa_base = other.m_jfa_base; - m_y.reference(bob::core::array::ccopy(other.m_y)); - m_z.reference(bob::core::array::ccopy(other.m_z)); - } - return *this; -} - -bool bob::learn::em::JFAMachine::operator==(const bob::learn::em::JFAMachine& other) const -{ - return (*m_jfa_base == *(other.m_jfa_base) && - bob::core::array::isEqual(m_y, other.m_y) && - bob::core::array::isEqual(m_z, other.m_z)); -} - -bool bob::learn::em::JFAMachine::operator!=(const bob::learn::em::JFAMachine& b) const -{ - return !(this->operator==(b)); -} - - -bool bob::learn::em::JFAMachine::is_similar_to(const bob::learn::em::JFAMachine& b, - const double r_epsilon, const double a_epsilon) const -{ - return (m_jfa_base->is_similar_to(*(b.m_jfa_base), r_epsilon, a_epsilon) && - bob::core::array::isClose(m_y, b.m_y, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_z, b.m_z, r_epsilon, a_epsilon)); -} - -void bob::learn::em::JFAMachine::save(bob::io::base::HDF5File& config) const -{ - config.setArray("y", m_y); - config.setArray("z", m_z); -} - -void bob::learn::em::JFAMachine::load(bob::io::base::HDF5File& config) -{ - //reads all data directly into the member variables - blitz::Array<double,1> y = config.readArray<double,1>("y"); - blitz::Array<double,1> z = config.readArray<double,1>("z"); - if (!m_jfa_base) - { - m_y.resize(y.extent(0)); - m_z.resize(z.extent(0)); - } - setY(y); - setZ(z); - // update cache - updateCache(); - resizeTmp(); -} - - -void bob::learn::em::JFAMachine::setY(const blitz::Array<double,1>& y) -{ - if(y.extent(0) != m_y.extent(0)) { //checks dimension - boost::format m("size of input vector `y' (%d) does not match the expected size (%d)"); - m % y.extent(0) % m_y.extent(0); - throw std::runtime_error(m.str()); - } - m_y.reference(bob::core::array::ccopy(y)); - // update cache - updateCache(); -} - -void bob::learn::em::JFAMachine::setZ(const blitz::Array<double,1>& z) -{ - if(z.extent(0) != m_z.extent(0)) { //checks dimension - boost::format m("size of input vector `z' (%d) does not match the expected size (%d)"); - m % z.extent(0) % m_z.extent(0); - throw std::runtime_error(m.str()); - } - m_z.reference(bob::core::array::ccopy(z)); - // update cache - updateCache(); -} - -void bob::learn::em::JFAMachine::setJFABase(const boost::shared_ptr<bob::learn::em::JFABase> jfa_base) -{ - if (!jfa_base->getUbm()) - throw std::runtime_error("No UBM was set in the JFA machine."); - m_jfa_base = jfa_base; - // Resize variables - resize(); -} - -void bob::learn::em::JFAMachine::resize() -{ - m_y.resizeAndPreserve(getDimRv()); - m_z.resizeAndPreserve(getSupervectorLength()); - updateCache(); - resizeTmp(); -} - -void bob::learn::em::JFAMachine::resizeTmp() -{ - if (m_jfa_base) - { - m_tmp_Ux.resize(getSupervectorLength()); - } -} - -void bob::learn::em::JFAMachine::updateCache() -{ - if (m_jfa_base) - { - // m + Vy + Dz - m_cache_mVyDz.resize(getSupervectorLength()); - bob::math::prod(m_jfa_base->getV(), m_y, m_cache_mVyDz); - m_cache_mVyDz += m_jfa_base->getD()*m_z + m_jfa_base->getUbm()->getMeanSupervector(); - m_cache_x.resize(getDimRu()); - } -} - -void bob::learn::em::JFAMachine::estimateUx(const bob::learn::em::GMMStats& gmm_stats, - blitz::Array<double,1>& Ux) -{ - estimateX(gmm_stats, m_cache_x); - bob::math::prod(m_jfa_base->getU(), m_cache_x, Ux); -} - -double bob::learn::em::JFAMachine::forward(const bob::learn::em::GMMStats& input) -{ - return forward_(input); -} - -double bob::learn::em::JFAMachine::forward(const bob::learn::em::GMMStats& gmm_stats, - const blitz::Array<double,1>& Ux) -{ - // Checks that a Base machine has been set - if (!m_jfa_base) throw std::runtime_error("No UBM was set in the JFA machine."); - - return bob::learn::em::linearScoring(m_cache_mVyDz, - m_jfa_base->getUbm()->getMeanSupervector(), m_jfa_base->getUbm()->getVarianceSupervector(), - gmm_stats, Ux, true); -} - -double bob::learn::em::JFAMachine::forward_(const bob::learn::em::GMMStats& input) -{ - // Checks that a Base machine has been set - if (!m_jfa_base) throw std::runtime_error("No UBM was set in the JFA machine."); - - // Ux and GMMStats - estimateX(input, m_cache_x); - bob::math::prod(m_jfa_base->getU(), m_cache_x, m_tmp_Ux); - - return bob::learn::em::linearScoring(m_cache_mVyDz, - m_jfa_base->getUbm()->getMeanSupervector(), m_jfa_base->getUbm()->getVarianceSupervector(), - input, m_tmp_Ux, true); -} - diff --git a/bob/learn/em/cpp/JFATrainer.cpp b/bob/learn/em/cpp/JFATrainer.cpp deleted file mode 100644 index 23591c8845d3795e48e9865d58fee23cf95360b8..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/JFATrainer.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/** - * @date Tue Jul 19 12:16:17 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Joint Factor Analysis Trainer - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/JFATrainer.h> -#include <bob.core/check.h> -#include <bob.core/array_copy.h> -#include <bob.core/array_random.h> -#include <bob.math/inv.h> -#include <bob.math/linear.h> -#include <bob.core/check.h> -#include <bob.core/array_repmat.h> -#include <algorithm> - - -//////////////////////////// JFATrainer /////////////////////////// -bob::learn::em::JFATrainer::JFATrainer(): - m_rng(new boost::mt19937()) -{} - -bob::learn::em::JFATrainer::JFATrainer(const bob::learn::em::JFATrainer& other): - m_rng(other.m_rng) -{} - -bob::learn::em::JFATrainer::~JFATrainer() -{} - -bob::learn::em::JFATrainer& bob::learn::em::JFATrainer::operator= -(const bob::learn::em::JFATrainer& other) -{ - if (this != &other) - { - //m_max_iterations = other.m_max_iterations; - m_rng = other.m_rng; - } - return *this; -} - -bool bob::learn::em::JFATrainer::operator==(const bob::learn::em::JFATrainer& b) const -{ - //return m_max_iterations == b.m_max_iterations && *m_rng == *(b.m_rng); - return *m_rng == *(b.m_rng); -} - -bool bob::learn::em::JFATrainer::operator!=(const bob::learn::em::JFATrainer& b) const -{ - return !(this->operator==(b)); -} - -bool bob::learn::em::JFATrainer::is_similar_to(const bob::learn::em::JFATrainer& b, - const double r_epsilon, const double a_epsilon) const -{ - //return m_max_iterations == b.m_max_iterations && *m_rng == *(b.m_rng); - return *m_rng == *(b.m_rng); -} - -void bob::learn::em::JFATrainer::initialize(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - m_base_trainer.initUbmNidSumStatistics(machine.getBase(), ar); - m_base_trainer.initializeXYZ(ar); - - blitz::Array<double,2>& U = machine.updateU(); - bob::core::array::randn(*m_rng, U); - blitz::Array<double,2>& V = machine.updateV(); - bob::core::array::randn(*m_rng, V); - blitz::Array<double,1>& D = machine.updateD(); - bob::core::array::randn(*m_rng, D); - machine.precompute(); -} - -void bob::learn::em::JFATrainer::eStep1(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - const bob::learn::em::FABase& base = machine.getBase(); - m_base_trainer.updateY(base, ar); - m_base_trainer.computeAccumulatorsV(base, ar); -} - -void bob::learn::em::JFATrainer::mStep1(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - blitz::Array<double,2>& V = machine.updateV(); - m_base_trainer.updateV(V); -} - -void bob::learn::em::JFATrainer::finalize1(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - const bob::learn::em::FABase& base = machine.getBase(); - m_base_trainer.updateY(base, ar); -} - - -void bob::learn::em::JFATrainer::eStep2(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - const bob::learn::em::FABase& base = machine.getBase(); - m_base_trainer.updateX(base, ar); - m_base_trainer.computeAccumulatorsU(base, ar); -} - -void bob::learn::em::JFATrainer::mStep2(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - blitz::Array<double,2>& U = machine.updateU(); - m_base_trainer.updateU(U); - machine.precompute(); -} - -void bob::learn::em::JFATrainer::finalize2(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - const bob::learn::em::FABase& base = machine.getBase(); - m_base_trainer.updateX(base, ar); -} - - -void bob::learn::em::JFATrainer::eStep3(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - const bob::learn::em::FABase& base = machine.getBase(); - m_base_trainer.updateZ(base, ar); - m_base_trainer.computeAccumulatorsD(base, ar); -} - -void bob::learn::em::JFATrainer::mStep3(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - blitz::Array<double,1>& d = machine.updateD(); - m_base_trainer.updateD(d); -} - -void bob::learn::em::JFATrainer::finalize3(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ -} - -/* -void bob::learn::em::JFATrainer::train_loop(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - // V subspace - for (size_t i=0; i<m_max_iterations; ++i) { - eStep1(machine, ar); - mStep1(machine, ar); - } - finalize1(machine, ar); - // U subspace - for (size_t i=0; i<m_max_iterations; ++i) { - eStep2(machine, ar); - mStep2(machine, ar); - } - finalize2(machine, ar); - // d subspace - for (size_t i=0; i<m_max_iterations; ++i) { - eStep3(machine, ar); - mStep3(machine, ar); - } - finalize3(machine, ar); -}*/ - -/* -void bob::learn::em::JFATrainer::train(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar) -{ - initialize(machine, ar); - train_loop(machine, ar); -} -*/ - -void bob::learn::em::JFATrainer::enroll(bob::learn::em::JFAMachine& machine, - const std::vector<boost::shared_ptr<bob::learn::em::GMMStats> >& ar, - const size_t n_iter) -{ - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > vvec; - vvec.push_back(ar); - - const bob::learn::em::FABase& fb = machine.getJFABase()->getBase(); - - m_base_trainer.initUbmNidSumStatistics(fb, vvec); - m_base_trainer.initializeXYZ(vvec); - - for (size_t i=0; i<n_iter; ++i) { - m_base_trainer.updateY(fb, vvec); - m_base_trainer.updateX(fb, vvec); - m_base_trainer.updateZ(fb, vvec); - } - - const blitz::Array<double,1> y(m_base_trainer.getY()[0]); - const blitz::Array<double,1> z(m_base_trainer.getZ()[0]); - machine.setY(y); - machine.setZ(z); -} diff --git a/bob/learn/em/cpp/KMeansMachine.cpp b/bob/learn/em/cpp/KMeansMachine.cpp deleted file mode 100644 index 395cb1460996cb0c77988515a3d9a8b1e7304eca..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/KMeansMachine.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/KMeansMachine.h> - -#include <bob.core/assert.h> -#include <bob.core/check.h> -#include <bob.core/array_copy.h> -#include <limits> - -bob::learn::em::KMeansMachine::KMeansMachine(): - m_n_means(0), m_n_inputs(0), m_means(0,0), - m_cache_means(0,0) -{ - m_means = 0; -} - -bob::learn::em::KMeansMachine::KMeansMachine(const size_t n_means, const size_t n_inputs): - m_n_means(n_means), m_n_inputs(n_inputs), m_means(n_means, n_inputs), - m_cache_means(n_means, n_inputs) -{ - m_means = 0; -} - -bob::learn::em::KMeansMachine::KMeansMachine(const blitz::Array<double,2>& means): - m_n_means(means.extent(0)), m_n_inputs(means.extent(1)), - m_means(bob::core::array::ccopy(means)), - m_cache_means(means.shape()) -{ -} - -bob::learn::em::KMeansMachine::KMeansMachine(const bob::learn::em::KMeansMachine& other): - m_n_means(other.m_n_means), m_n_inputs(other.m_n_inputs), - m_means(bob::core::array::ccopy(other.m_means)), - m_cache_means(other.m_cache_means.shape()) -{ -} - -bob::learn::em::KMeansMachine::KMeansMachine(bob::io::base::HDF5File& config) -{ - load(config); -} - -bob::learn::em::KMeansMachine::~KMeansMachine() { } - -bob::learn::em::KMeansMachine& bob::learn::em::KMeansMachine::operator= -(const bob::learn::em::KMeansMachine& other) -{ - if(this != &other) - { - m_n_means = other.m_n_means; - m_n_inputs = other.m_n_inputs; - m_means.reference(bob::core::array::ccopy(other.m_means)); - m_cache_means.resize(other.m_means.shape()); - } - return *this; -} - -bool bob::learn::em::KMeansMachine::operator==(const bob::learn::em::KMeansMachine& b) const -{ - return m_n_inputs == b.m_n_inputs && m_n_means == b.m_n_means && - bob::core::array::isEqual(m_means, b.m_means); -} - -bool bob::learn::em::KMeansMachine::operator!=(const bob::learn::em::KMeansMachine& b) const -{ - return !(this->operator==(b)); -} - -bool bob::learn::em::KMeansMachine::is_similar_to(const bob::learn::em::KMeansMachine& b, - const double r_epsilon, const double a_epsilon) const -{ - return m_n_inputs == b.m_n_inputs && m_n_means == b.m_n_means && - bob::core::array::isClose(m_means, b.m_means, r_epsilon, a_epsilon); -} - -void bob::learn::em::KMeansMachine::load(bob::io::base::HDF5File& config) -{ - //reads all data directly into the member variables - m_means.reference(config.readArray<double,2>("means")); - m_n_means = m_means.extent(0); - m_n_inputs = m_means.extent(1); - m_cache_means.resize(m_n_means, m_n_inputs); -} - -void bob::learn::em::KMeansMachine::save(bob::io::base::HDF5File& config) const -{ - config.setArray("means", m_means); -} - -void bob::learn::em::KMeansMachine::setMeans(const blitz::Array<double,2> &means) -{ - bob::core::array::assertSameShape(means, m_means); - m_means = means; -} - -void bob::learn::em::KMeansMachine::setMean(const size_t i, const blitz::Array<double,1> &mean) -{ - if(i>=m_n_means) { - boost::format m("cannot set mean with index %lu: out of bounds [0,%lu["); - m % i % m_n_means; - throw std::runtime_error(m.str()); - } - bob::core::array::assertSameDimensionLength(mean.extent(0), m_means.extent(1)); - m_means(i,blitz::Range::all()) = mean; -} - -const blitz::Array<double,1> bob::learn::em::KMeansMachine::getMean(const size_t i) const -{ - if(i>=m_n_means) { - boost::format m("cannot get mean with index %lu: out of bounds [0,%lu["); - m % i % m_n_means; - throw std::runtime_error(m.str()); - } - - return m_means(i,blitz::Range::all()); - -} - -double bob::learn::em::KMeansMachine::getDistanceFromMean(const blitz::Array<double,1> &x, - const size_t i) const -{ - return blitz::sum(blitz::pow2(m_means(i,blitz::Range::all()) - x)); -} - -void bob::learn::em::KMeansMachine::getClosestMean(const blitz::Array<double,1> &x, - size_t &closest_mean, double &min_distance) const -{ - min_distance = std::numeric_limits<double>::max(); - - for(size_t i=0; i<m_n_means; ++i) { - double this_distance = getDistanceFromMean(x,i); - if(this_distance < min_distance) { - min_distance = this_distance; - closest_mean = i; - } - } -} - -double bob::learn::em::KMeansMachine::getMinDistance(const blitz::Array<double,1>& input) const -{ - size_t closest_mean = 0; - double min_distance = 0; - getClosestMean(input,closest_mean,min_distance); - return min_distance; -} - -void bob::learn::em::KMeansMachine::getVariancesAndWeightsForEachClusterInit(blitz::Array<double,2>& variances, blitz::Array<double,1>& weights) const -{ - // check arguments - bob::core::array::assertSameShape(variances, m_means); - bob::core::array::assertSameDimensionLength(weights.extent(0), m_n_means); - - // initialise output arrays - bob::core::array::assertSameShape(variances, m_means); - bob::core::array::assertSameDimensionLength(weights.extent(0), m_n_means); - variances = 0; - weights = 0; - - // initialise (temporary) mean array - m_cache_means = 0; -} - -void bob::learn::em::KMeansMachine::getVariancesAndWeightsForEachClusterAcc(const blitz::Array<double,2>& data, blitz::Array<double,2>& variances, blitz::Array<double,1>& weights) const -{ - // check arguments - bob::core::array::assertSameShape(variances, m_means); - bob::core::array::assertSameDimensionLength(weights.extent(0), m_n_means); - - // iterate over data - blitz::Range a = blitz::Range::all(); - for(int i=0; i<data.extent(0); ++i) { - // - get example - blitz::Array<double,1> x(data(i,a)); - - // - find closest mean - size_t closest_mean = 0; - double min_distance = 0; - getClosestMean(x,closest_mean,min_distance); - - // - accumulate stats - m_cache_means(closest_mean, blitz::Range::all()) += x; - variances(closest_mean, blitz::Range::all()) += blitz::pow2(x); - ++weights(closest_mean); - } -} - -void bob::learn::em::KMeansMachine::getVariancesAndWeightsForEachClusterFin(blitz::Array<double,2>& variances, blitz::Array<double,1>& weights) const -{ - // check arguments - bob::core::array::assertSameShape(variances, m_means); - bob::core::array::assertSameDimensionLength(weights.extent(0), m_n_means); - - // calculate final variances and weights - blitz::firstIndex idx1; - blitz::secondIndex idx2; - - // find means - m_cache_means = m_cache_means(idx1,idx2) / weights(idx1); - - // find variances - variances = variances(idx1,idx2) / weights(idx1); - variances -= blitz::pow2(m_cache_means); - - // find weights - weights = weights / blitz::sum(weights); -} - -void bob::learn::em::KMeansMachine::setCacheMeans(const blitz::Array<double,2> &cache_means) -{ - bob::core::array::assertSameShape(cache_means, m_cache_means); - m_cache_means = cache_means; -} - -void bob::learn::em::KMeansMachine::getVariancesAndWeightsForEachCluster(const blitz::Array<double,2>& data, blitz::Array<double,2>& variances, blitz::Array<double,1>& weights) const -{ - // initialise - getVariancesAndWeightsForEachClusterInit(variances, weights); - // accumulate - getVariancesAndWeightsForEachClusterAcc(data, variances, weights); - // merge/finalize - getVariancesAndWeightsForEachClusterFin(variances, weights); -} - -void bob::learn::em::KMeansMachine::forward(const blitz::Array<double,1>& input, double& output) const -{ - if(static_cast<size_t>(input.extent(0)) != m_n_inputs) { - boost::format m("machine input size (%u) does not match the size of input array (%d)"); - m % m_n_inputs % input.extent(0); - throw std::runtime_error(m.str()); - } - forward_(input,output); -} - -void bob::learn::em::KMeansMachine::forward_(const blitz::Array<double,1>& input, double& output) const -{ - output = getMinDistance(input); -} - -void bob::learn::em::KMeansMachine::resize(const size_t n_means, const size_t n_inputs) -{ - m_n_means = n_means; - m_n_inputs = n_inputs; - m_means.resizeAndPreserve(n_means, n_inputs); - m_cache_means.resizeAndPreserve(n_means, n_inputs); -} - -namespace bob { namespace learn { namespace em { - std::ostream& operator<<(std::ostream& os, const KMeansMachine& km) { - os << "Means = " << km.m_means << std::endl; - return os; - } -} } } diff --git a/bob/learn/em/cpp/KMeansTrainer.cpp b/bob/learn/em/cpp/KMeansTrainer.cpp deleted file mode 100644 index 0c6e3c6da2e8de4addd0e97ead72086952c23329..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/KMeansTrainer.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/KMeansTrainer.h> -#include <bob.core/array_copy.h> - -#include <boost/random.hpp> -#include <bob.core/random.h> - - -bob::learn::em::KMeansTrainer::KMeansTrainer(InitializationMethod i_m): -m_rng(new boost::mt19937()), -m_average_min_distance(0), -m_zeroethOrderStats(0), -m_firstOrderStats(0) -{ - m_initialization_method = i_m; -} - - -bob::learn::em::KMeansTrainer::KMeansTrainer(const bob::learn::em::KMeansTrainer& other){ - - m_initialization_method = other.m_initialization_method; - m_rng = other.m_rng; - m_average_min_distance = other.m_average_min_distance; - m_zeroethOrderStats = bob::core::array::ccopy(other.m_zeroethOrderStats); - m_firstOrderStats = bob::core::array::ccopy(other.m_firstOrderStats); -} - - -bob::learn::em::KMeansTrainer& bob::learn::em::KMeansTrainer::operator= -(const bob::learn::em::KMeansTrainer& other) -{ - if(this != &other) - { - m_rng = other.m_rng; - m_initialization_method = other.m_initialization_method; - m_average_min_distance = other.m_average_min_distance; - - m_zeroethOrderStats = bob::core::array::ccopy(other.m_zeroethOrderStats); - m_firstOrderStats = bob::core::array::ccopy(other.m_firstOrderStats); - } - return *this; -} - - -bool bob::learn::em::KMeansTrainer::operator==(const bob::learn::em::KMeansTrainer& b) const { - return - m_initialization_method == b.m_initialization_method && - *m_rng == *(b.m_rng) && m_average_min_distance == b.m_average_min_distance && - bob::core::array::hasSameShape(m_zeroethOrderStats, b.m_zeroethOrderStats) && - bob::core::array::hasSameShape(m_firstOrderStats, b.m_firstOrderStats) && - blitz::all(m_zeroethOrderStats == b.m_zeroethOrderStats) && - blitz::all(m_firstOrderStats == b.m_firstOrderStats); -} - -bool bob::learn::em::KMeansTrainer::operator!=(const bob::learn::em::KMeansTrainer& b) const { - return !(this->operator==(b)); -} - -void bob::learn::em::KMeansTrainer::initialize(bob::learn::em::KMeansMachine& kmeans, - const blitz::Array<double,2>& ar) -{ - // split data into as many chunks as there are means - size_t n_data = ar.extent(0); - - // assign the i'th mean to a random example within the i'th chunk - blitz::Range a = blitz::Range::all(); - if(m_initialization_method == RANDOM || m_initialization_method == RANDOM_NO_DUPLICATE) // Random initialization - { - unsigned int n_chunk = n_data / kmeans.getNMeans(); - size_t n_max_trials = (size_t)n_chunk * 5; - blitz::Array<double,1> cur_mean; - if(m_initialization_method == RANDOM_NO_DUPLICATE) - cur_mean.resize(kmeans.getNInputs()); - - for(size_t i=0; i<kmeans.getNMeans(); ++i) - { - boost::uniform_int<> die(i*n_chunk, (i+1)*n_chunk-1); - - // get random index within chunk - unsigned int index = die(*m_rng); - - // get the example at that index - blitz::Array<double, 1> mean = ar(index,a); - - if(m_initialization_method == RANDOM_NO_DUPLICATE) - { - size_t count = 0; - while(count < n_max_trials) - { - // check that the selected sampled is different than all the previously - // selected ones - bool valid = true; - for(size_t j=0; j<i && valid; ++j) - { - cur_mean = kmeans.getMean(j); - valid = blitz::any(mean != cur_mean); - } - // if different, stop otherwise, try with another one - if(valid) - break; - else - { - index = die(*m_rng); - mean = ar(index,a); - ++count; - } - } - // Initialization fails - if(count >= n_max_trials) { - boost::format m("initialization failure: surpassed the maximum number of trials (%u)"); - m % n_max_trials; - throw std::runtime_error(m.str()); - } - } - - // set the mean - kmeans.setMean(i, mean); - } - } - else // K-Means++ - { - // 1.a. Selects one sample randomly - boost::uniform_int<> die(0, n_data-1); - // Gets the example at a random index - blitz::Array<double,1> mean = ar(die(*m_rng),a); - kmeans.setMean(0, mean); - - // 1.b. Loops, computes probability distribution and select samples accordingly - blitz::Array<double,1> weights(n_data); - for(size_t m=1; m<kmeans.getNMeans(); ++m) - { - // For each sample, puts the distance to the closest mean in the weight vector - for(size_t s=0; s<n_data; ++s) - { - blitz::Array<double,1> s_cur = ar(s,a); - double& w_cur = weights(s); - // Initializes with the distance to first mean - w_cur = kmeans.getDistanceFromMean(s_cur, 0); - // Loops over the remaining mean and update the mean distance if required - for(size_t i=1; i<m; ++i) - w_cur = std::min(w_cur, kmeans.getDistanceFromMean(s_cur, i)); - } - // Square and normalize the weights vectors such that - // \f$weights[x] = D(x)^{2} \sum_{y} D(y)^{2}\f$ - weights = blitz::pow2(weights); - weights /= blitz::sum(weights); - - // Takes a sample according to the weights distribution - // Blitz iterators is fine as the weights array should be C-style contiguous - bob::core::array::assertCContiguous(weights); - bob::core::random::discrete_distribution<> die2(weights.begin(), weights.end()); - blitz::Array<double,1> new_mean = ar(die2(*m_rng),a); - kmeans.setMean(m, new_mean); - } - } -} - -void bob::learn::em::KMeansTrainer::eStep(bob::learn::em::KMeansMachine& kmeans, - const blitz::Array<double,2>& ar) -{ - // initialise the accumulators - resetAccumulators(kmeans); - - // iterate over data samples - blitz::Range a = blitz::Range::all(); - for(int i=0; i<ar.extent(0); ++i) { - // get example - blitz::Array<double, 1> x(ar(i,a)); - - // find closest mean, and distance from that mean - size_t closest_mean = 0; - double min_distance = 0; - kmeans.getClosestMean(x,closest_mean,min_distance); - - // accumulate the stats - m_average_min_distance += min_distance; - ++m_zeroethOrderStats(closest_mean); - m_firstOrderStats(closest_mean,blitz::Range::all()) += x; - } - m_average_min_distance /= static_cast<double>(ar.extent(0)); -} - -void bob::learn::em::KMeansTrainer::mStep(bob::learn::em::KMeansMachine& kmeans) -{ - blitz::Array<double,2>& means = kmeans.updateMeans(); - for(size_t i=0; i<kmeans.getNMeans(); ++i) - { - means(i,blitz::Range::all()) = - m_firstOrderStats(i,blitz::Range::all()) / m_zeroethOrderStats(i); - } -} - -double bob::learn::em::KMeansTrainer::computeLikelihood(bob::learn::em::KMeansMachine& kmeans) -{ - return m_average_min_distance; -} - - -void bob::learn::em::KMeansTrainer::resetAccumulators(bob::learn::em::KMeansMachine& kmeans) -{ - // Resize the accumulator - m_zeroethOrderStats.resize(kmeans.getNMeans()); - m_firstOrderStats.resize(kmeans.getNMeans(), kmeans.getNInputs()); - - // initialize with 0 - m_average_min_distance = 0; - m_zeroethOrderStats = 0; - m_firstOrderStats = 0; -} - -void bob::learn::em::KMeansTrainer::setZeroethOrderStats(const blitz::Array<double,1>& zeroethOrderStats) -{ - bob::core::array::assertSameShape(m_zeroethOrderStats, zeroethOrderStats); - m_zeroethOrderStats = zeroethOrderStats; -} - -void bob::learn::em::KMeansTrainer::setFirstOrderStats(const blitz::Array<double,2>& firstOrderStats) -{ - bob::core::array::assertSameShape(m_firstOrderStats, firstOrderStats); - m_firstOrderStats = firstOrderStats; -} diff --git a/bob/learn/em/cpp/LinearScoring.cpp b/bob/learn/em/cpp/LinearScoring.cpp deleted file mode 100644 index 63fdb1cce18f97686948b7ed0cfb0db3413a530b..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/LinearScoring.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/** - * @date Wed Jul 13 16:00:04 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ -#include <bob.learn.em/LinearScoring.h> -#include <bob.math/linear.h> - - -static void _linearScoring(const std::vector<blitz::Array<double,1> >& models, - const blitz::Array<double,1>& ubm_mean, - const blitz::Array<double,1>& ubm_variance, - const std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> >& test_stats, - const std::vector<blitz::Array<double,1> >* test_channelOffset, - const bool frame_length_normalisation, - blitz::Array<double,2>& scores) -{ - int C = test_stats[0]->sumPx.extent(0); - int D = test_stats[0]->sumPx.extent(1); - int CD = C*D; - int Tt = test_stats.size(); - int Tm = models.size(); - - // Check output size - bob::core::array::assertSameDimensionLength(scores.extent(0), models.size()); - bob::core::array::assertSameDimensionLength(scores.extent(1), test_stats.size()); - - blitz::Array<double,2> A(Tm, CD); - blitz::Array<double,2> B(CD, Tt); - - // 1) Compute A - for(int t=0; t<Tm; ++t) { - blitz::Array<double, 1> tmp = A(t, blitz::Range::all()); - tmp = (models[t] - ubm_mean) / ubm_variance; - } - - // 2) Compute B - if(test_channelOffset == 0) { - for(int t=0; t<Tt; ++t) - for(int s=0; s<CD; ++s) - B(s, t) = test_stats[t]->sumPx(s/D, s%D) - (ubm_mean(s) * test_stats[t]->n(s/D)); - } - else { - bob::core::array::assertSameDimensionLength((*test_channelOffset).size(), Tt); - - for(int t=0; t<Tt; ++t) { - bob::core::array::assertSameDimensionLength((*test_channelOffset)[t].extent(0), CD); - for(int s=0; s<CD; ++s) - B(s, t) = test_stats[t]->sumPx(s/D, s%D) - (test_stats[t]->n(s/D) * (ubm_mean(s) + (*test_channelOffset)[t](s))); - } - } - - // Apply the normalisation if needed - if(frame_length_normalisation) { - for(int t=0; t<Tt; ++t) { - double sum_N = test_stats[t]->T; - blitz::Array<double, 1> v_t = B(blitz::Range::all(),t); - - if (sum_N <= std::numeric_limits<double>::epsilon() && sum_N >= -std::numeric_limits<double>::epsilon()) - v_t = 0; - else - v_t /= sum_N; - } - } - - // 3) Compute LLR - bob::math::prod(A, B, scores); -} - - -void bob::learn::em::linearScoring(const std::vector<blitz::Array<double,1> >& models, - const blitz::Array<double,1>& ubm_mean, const blitz::Array<double,1>& ubm_variance, - const std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> >& test_stats, - const std::vector<blitz::Array<double,1> >& test_channelOffset, - const bool frame_length_normalisation, - blitz::Array<double, 2>& scores) -{ - _linearScoring(models, ubm_mean, ubm_variance, test_stats, &test_channelOffset, frame_length_normalisation, scores); -} - -void bob::learn::em::linearScoring(const std::vector<blitz::Array<double,1> >& models, - const blitz::Array<double,1>& ubm_mean, const blitz::Array<double,1>& ubm_variance, - const std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> >& test_stats, - const bool frame_length_normalisation, - blitz::Array<double, 2>& scores) -{ - _linearScoring(models, ubm_mean, ubm_variance, test_stats, 0, frame_length_normalisation, scores); -} - -void bob::learn::em::linearScoring(const std::vector<boost::shared_ptr<const bob::learn::em::GMMMachine> >& models, - const bob::learn::em::GMMMachine& ubm, - const std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> >& test_stats, - const bool frame_length_normalisation, - blitz::Array<double, 2>& scores) -{ - int C = test_stats[0]->sumPx.extent(0); - int D = test_stats[0]->sumPx.extent(1); - int CD = C*D; - std::vector<blitz::Array<double,1> > models_b; - // Allocate and get the mean supervector - for(size_t i=0; i<models.size(); ++i) { - blitz::Array<double,1> mod(CD); - mod = models[i]->getMeanSupervector(); - models_b.push_back(mod); - } - const blitz::Array<double,1>& ubm_mean = ubm.getMeanSupervector(); - const blitz::Array<double,1>& ubm_variance = ubm.getVarianceSupervector(); - _linearScoring(models_b, ubm_mean, ubm_variance, test_stats, 0, frame_length_normalisation, scores); -} - -void bob::learn::em::linearScoring(const std::vector<boost::shared_ptr<const bob::learn::em::GMMMachine> >& models, - const bob::learn::em::GMMMachine& ubm, - const std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> >& test_stats, - const std::vector<blitz::Array<double,1> >& test_channelOffset, - const bool frame_length_normalisation, - blitz::Array<double, 2>& scores) -{ - int C = test_stats[0]->sumPx.extent(0); - int D = test_stats[0]->sumPx.extent(1); - int CD = C*D; - std::vector<blitz::Array<double,1> > models_b; - // Allocate and get the mean supervector - for(size_t i=0; i<models.size(); ++i) { - blitz::Array<double,1> mod(CD); - mod = models[i]->getMeanSupervector(); - models_b.push_back(mod); - } - const blitz::Array<double,1>& ubm_mean = ubm.getMeanSupervector(); - const blitz::Array<double,1>& ubm_variance = ubm.getVarianceSupervector(); - _linearScoring(models_b, ubm_mean, ubm_variance, test_stats, &test_channelOffset, frame_length_normalisation, scores); -} - - - -double bob::learn::em::linearScoring(const blitz::Array<double,1>& models, - const blitz::Array<double,1>& ubm_mean, const blitz::Array<double,1>& ubm_variance, - const bob::learn::em::GMMStats& test_stats, - const blitz::Array<double,1>& test_channelOffset, - const bool frame_length_normalisation) -{ - int C = test_stats.sumPx.extent(0); - int D = test_stats.sumPx.extent(1); - int CD = C*D; - - - blitz::Array<double,1> A(CD); - blitz::Array<double,1> B(CD); - - // 1) Compute A - A = (models - ubm_mean) / ubm_variance; - - // 2) Compute B - for (int s=0; s<CD; ++s) - B(s) = test_stats.sumPx(s/D, s%D) - (test_stats.n(s/D) * (ubm_mean(s) + test_channelOffset(s))); - - // Apply the normalisation if needed - if (frame_length_normalisation) { - double sum_N = test_stats.T; - if (sum_N == 0) - B = 0; - else - B /= sum_N; - } - - return blitz::sum(A * B); -} - diff --git a/bob/learn/em/cpp/MAP_GMMTrainer.cpp b/bob/learn/em/cpp/MAP_GMMTrainer.cpp deleted file mode 100644 index fc9a82ecfc44a3c8bc1329f6c3ae9a7bff6ab3c9..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/MAP_GMMTrainer.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/MAP_GMMTrainer.h> -#include <bob.core/check.h> - -bob::learn::em::MAP_GMMTrainer::MAP_GMMTrainer( - const bool update_means, - const bool update_variances, - const bool update_weights, - const double mean_var_update_responsibilities_threshold, - - const bool reynolds_adaptation, - const double relevance_factor, - const double alpha, - boost::shared_ptr<bob::learn::em::GMMMachine> prior_gmm): - - m_gmm_base_trainer(update_means, update_variances, update_weights, mean_var_update_responsibilities_threshold), - m_prior_gmm(prior_gmm) -{ - m_reynolds_adaptation = reynolds_adaptation; - m_relevance_factor = relevance_factor; - m_alpha = alpha; -} - - -bob::learn::em::MAP_GMMTrainer::MAP_GMMTrainer(const bob::learn::em::MAP_GMMTrainer& b): - m_gmm_base_trainer(b.m_gmm_base_trainer), - m_prior_gmm(b.m_prior_gmm) -{ - m_relevance_factor = b.m_relevance_factor; - m_alpha = b.m_alpha; - m_reynolds_adaptation = b.m_reynolds_adaptation; -} - -bob::learn::em::MAP_GMMTrainer::~MAP_GMMTrainer() -{} - -void bob::learn::em::MAP_GMMTrainer::initialize(bob::learn::em::GMMMachine& gmm) -{ - // Check that the prior GMM has been specified - if (!m_prior_gmm) - throw std::runtime_error("MAP_GMMTrainer: Prior GMM distribution has not been set"); - - // Allocate memory for the sufficient statistics and initialise - m_gmm_base_trainer.initialize(gmm); - - const size_t n_gaussians = gmm.getNGaussians(); - // TODO: check size? - gmm.setWeights(m_prior_gmm->getWeights()); - for(size_t i=0; i<n_gaussians; ++i) - { - gmm.getGaussian(i)->updateMean() = m_prior_gmm->getGaussian(i)->getMean(); - gmm.getGaussian(i)->updateVariance() = m_prior_gmm->getGaussian(i)->getVariance(); - gmm.getGaussian(i)->applyVarianceThresholds(); - } - // Initializes cache - m_cache_alpha.resize(n_gaussians); - m_cache_ml_weights.resize(n_gaussians); -} - -bool bob::learn::em::MAP_GMMTrainer::setPriorGMM(boost::shared_ptr<bob::learn::em::GMMMachine> prior_gmm) -{ - if (!prior_gmm) return false; - m_prior_gmm = prior_gmm; - return true; -} - - -void bob::learn::em::MAP_GMMTrainer::mStep(bob::learn::em::GMMMachine& gmm) -{ - // Read options and variables - double n_gaussians = gmm.getNGaussians(); - - //Checking if it is necessary to resize the cache - if((size_t)m_cache_alpha.extent(0) != n_gaussians) - initialize(gmm); //If it is different for some reason, there is no way, you have to initialize - - // Check that the prior GMM has been specified - if (!m_prior_gmm) - throw std::runtime_error("MAP_GMMTrainer: Prior GMM distribution has not been set"); - - blitz::firstIndex i; - blitz::secondIndex j; - - // Calculate the "data-dependent adaptation coefficient", alpha_i - // TODO: check if required // m_cache_alpha.resize(n_gaussians); - if (!m_reynolds_adaptation) - m_cache_alpha = m_alpha; - else - m_cache_alpha = m_gmm_base_trainer.getGMMStats()->n(i) / (m_gmm_base_trainer.getGMMStats()->n(i) + m_relevance_factor); - - // - Update weights if requested - // Equation 11 of Reynolds et al., "Speaker Verification Using Adapted Gaussian Mixture Models", Digital Signal Processing, 2000 - if (m_gmm_base_trainer.getUpdateWeights()) { - // Calculate the maximum likelihood weights - m_cache_ml_weights = m_gmm_base_trainer.getGMMStats()->n / static_cast<double>(m_gmm_base_trainer.getGMMStats()->T); //cast req. for linux/32-bits & osx - - // Get the prior weights - const blitz::Array<double,1>& prior_weights = m_prior_gmm->getWeights(); - blitz::Array<double,1>& new_weights = gmm.updateWeights(); - - // Calculate the new weights - new_weights = m_cache_alpha * m_cache_ml_weights + (1-m_cache_alpha) * prior_weights; - - // Apply the scale factor, gamma, to ensure the new weights sum to unity - double gamma = blitz::sum(new_weights); - new_weights /= gamma; - - // Recompute the log weights in the cache of the GMMMachine - gmm.recomputeLogWeights(); - } - - // Update GMM parameters - // - Update means if requested - // Equation 12 of Reynolds et al., "Speaker Verification Using Adapted Gaussian Mixture Models", Digital Signal Processing, 2000 - if (m_gmm_base_trainer.getUpdateMeans()) { - // Calculate new means - for (size_t i=0; i<n_gaussians; ++i) { - const blitz::Array<double,1>& prior_means = m_prior_gmm->getGaussian(i)->getMean(); - blitz::Array<double,1>& means = gmm.getGaussian(i)->updateMean(); - if (m_gmm_base_trainer.getGMMStats()->n(i) < m_gmm_base_trainer.getMeanVarUpdateResponsibilitiesThreshold()) { - means = prior_means; - } - else { - // Use the maximum likelihood means - means = m_cache_alpha(i) * (m_gmm_base_trainer.getGMMStats()->sumPx(i,blitz::Range::all()) / m_gmm_base_trainer.getGMMStats()->n(i)) + (1-m_cache_alpha(i)) * prior_means; - } - } - } - - // - Update variance if requested - // Equation 13 of Reynolds et al., "Speaker Verification Using Adapted Gaussian Mixture Models", Digital Signal Processing, 2000 - if (m_gmm_base_trainer.getUpdateVariances()) { - // Calculate new variances (equation 13) - for (size_t i=0; i<n_gaussians; ++i) { - const blitz::Array<double,1>& prior_means = m_prior_gmm->getGaussian(i)->getMean(); - blitz::Array<double,1>& means = gmm.getGaussian(i)->updateMean(); - const blitz::Array<double,1>& prior_variances = m_prior_gmm->getGaussian(i)->getVariance(); - blitz::Array<double,1>& variances = gmm.getGaussian(i)->updateVariance(); - if (m_gmm_base_trainer.getGMMStats()->n(i) < m_gmm_base_trainer.getMeanVarUpdateResponsibilitiesThreshold()) { - variances = (prior_variances + prior_means) - blitz::pow2(means); - } - else { - variances = m_cache_alpha(i) * m_gmm_base_trainer.getGMMStats()->sumPxx(i,blitz::Range::all()) / m_gmm_base_trainer.getGMMStats()->n(i) + (1-m_cache_alpha(i)) * (prior_variances + prior_means) - blitz::pow2(means); - } - gmm.getGaussian(i)->applyVarianceThresholds(); - } - } -} - - - -bob::learn::em::MAP_GMMTrainer& bob::learn::em::MAP_GMMTrainer::operator= - (const bob::learn::em::MAP_GMMTrainer &other) -{ - if (this != &other) - { - m_gmm_base_trainer = other.m_gmm_base_trainer; - m_relevance_factor = other.m_relevance_factor; - m_prior_gmm = other.m_prior_gmm; - m_alpha = other.m_alpha; - m_reynolds_adaptation = other.m_reynolds_adaptation; - m_cache_alpha.resize(other.m_cache_alpha.extent(0)); - m_cache_ml_weights.resize(other.m_cache_ml_weights.extent(0)); - } - return *this; -} - - -bool bob::learn::em::MAP_GMMTrainer::operator== - (const bob::learn::em::MAP_GMMTrainer &other) const -{ - return m_gmm_base_trainer == other.m_gmm_base_trainer && - m_relevance_factor == other.m_relevance_factor && - m_prior_gmm == other.m_prior_gmm && - m_alpha == other.m_alpha && - m_reynolds_adaptation == other.m_reynolds_adaptation; -} - - -bool bob::learn::em::MAP_GMMTrainer::operator!= - (const bob::learn::em::MAP_GMMTrainer &other) const -{ - return !(this->operator==(other)); -} - - -bool bob::learn::em::MAP_GMMTrainer::is_similar_to - (const bob::learn::em::MAP_GMMTrainer &other, const double r_epsilon, - const double a_epsilon) const -{ - return //m_gmm_base_trainer.is_similar_to(other.m_gmm_base_trainer, r_epsilon, a_epsilon) && - bob::core::isClose(m_relevance_factor, other.m_relevance_factor, r_epsilon, a_epsilon) && - m_prior_gmm == other.m_prior_gmm && - bob::core::isClose(m_alpha, other.m_alpha, r_epsilon, a_epsilon) && - m_reynolds_adaptation == other.m_reynolds_adaptation; -} diff --git a/bob/learn/em/cpp/ML_GMMTrainer.cpp b/bob/learn/em/cpp/ML_GMMTrainer.cpp deleted file mode 100644 index 9ac71029c3048fc36b98c85a7f675dd79feac8c8..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/ML_GMMTrainer.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.learn.em/ML_GMMTrainer.h> -#include <algorithm> - -bob::learn::em::ML_GMMTrainer::ML_GMMTrainer( - const bool update_means, - const bool update_variances, - const bool update_weights, - const double mean_var_update_responsibilities_threshold -): - m_gmm_base_trainer(update_means, update_variances, update_weights, mean_var_update_responsibilities_threshold) -{} - - - -bob::learn::em::ML_GMMTrainer::ML_GMMTrainer(const bob::learn::em::ML_GMMTrainer& b): - m_gmm_base_trainer(b.m_gmm_base_trainer) -{} - -bob::learn::em::ML_GMMTrainer::~ML_GMMTrainer() -{} - -void bob::learn::em::ML_GMMTrainer::initialize(bob::learn::em::GMMMachine& gmm) -{ - m_gmm_base_trainer.initialize(gmm); - - // Allocate cache - size_t n_gaussians = gmm.getNGaussians(); - m_cache_ss_n_thresholded.resize(n_gaussians); -} - - -void bob::learn::em::ML_GMMTrainer::mStep(bob::learn::em::GMMMachine& gmm) -{ - // Read options and variables - const size_t n_gaussians = gmm.getNGaussians(); - - //Checking if it is necessary to resize the cache - if((size_t)m_cache_ss_n_thresholded.extent(0) != n_gaussians) - initialize(gmm); //If it is different for some reason, there is no way, you have to initialize - - // - Update weights if requested - // Equation 9.26 of Bishop, "Pattern recognition and machine learning", 2006 - if (m_gmm_base_trainer.getUpdateWeights()) { - blitz::Array<double,1>& weights = gmm.updateWeights(); - weights = m_gmm_base_trainer.getGMMStats()->n / static_cast<double>(m_gmm_base_trainer.getGMMStats()->T); //cast req. for linux/32-bits & osx - // Recompute the log weights in the cache of the GMMMachine - gmm.recomputeLogWeights(); - } - - // Generate a thresholded version of m_ss.n - for(size_t i=0; i<n_gaussians; ++i) - m_cache_ss_n_thresholded(i) = std::max(m_gmm_base_trainer.getGMMStats()->n(i), m_gmm_base_trainer.getMeanVarUpdateResponsibilitiesThreshold()); - - // Update GMM parameters using the sufficient statistics (m_ss) - // - Update means if requested - // Equation 9.24 of Bishop, "Pattern recognition and machine learning", 2006 - if (m_gmm_base_trainer.getUpdateMeans()) { - for(size_t i=0; i<n_gaussians; ++i) { - blitz::Array<double,1>& means = gmm.getGaussian(i)->updateMean(); - means = m_gmm_base_trainer.getGMMStats()->sumPx(i, blitz::Range::all()) / m_cache_ss_n_thresholded(i); - } - } - - // - Update variance if requested - // See Equation 9.25 of Bishop, "Pattern recognition and machine learning", 2006 - // ...but we use the "computational formula for the variance", i.e. - // var = 1/n * sum (P(x-mean)(x-mean)) - // = 1/n * sum (Pxx) - mean^2 - if (m_gmm_base_trainer.getUpdateVariances()) { - for(size_t i=0; i<n_gaussians; ++i) { - const blitz::Array<double,1>& means = gmm.getGaussian(i)->getMean(); - blitz::Array<double,1>& variances = gmm.getGaussian(i)->updateVariance(); - variances = m_gmm_base_trainer.getGMMStats()->sumPxx(i, blitz::Range::all()) / m_cache_ss_n_thresholded(i) - blitz::pow2(means); - gmm.getGaussian(i)->applyVarianceThresholds(); - } - } -} - -bob::learn::em::ML_GMMTrainer& bob::learn::em::ML_GMMTrainer::operator= - (const bob::learn::em::ML_GMMTrainer &other) -{ - if (this != &other) - { - m_gmm_base_trainer = other.m_gmm_base_trainer; - m_cache_ss_n_thresholded.resize(other.m_cache_ss_n_thresholded.extent(0)); - } - return *this; -} - -bool bob::learn::em::ML_GMMTrainer::operator== - (const bob::learn::em::ML_GMMTrainer &other) const -{ - return m_gmm_base_trainer == other.m_gmm_base_trainer; -} - -bool bob::learn::em::ML_GMMTrainer::operator!= - (const bob::learn::em::ML_GMMTrainer &other) const -{ - return !(this->operator==(other)); -} diff --git a/bob/learn/em/cpp/PLDAMachine.cpp b/bob/learn/em/cpp/PLDAMachine.cpp deleted file mode 100644 index fe60630d42ad877943afb52946e7ae42018788f0..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/PLDAMachine.cpp +++ /dev/null @@ -1,960 +0,0 @@ -/** - * @date Fri Oct 14 18:07:56 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Machines that implements the PLDA model - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.core/assert.h> -#include <bob.core/check.h> -#include <bob.core/array_copy.h> -#include <bob.learn.em/PLDAMachine.h> -#include <bob.math/linear.h> -#include <bob.math/det.h> -#include <bob.math/inv.h> - -#include <cmath> -#include <boost/lexical_cast.hpp> -#include <string> - -bob::learn::em::PLDABase::PLDABase(): - m_variance_threshold(0.) -{ - resizeNoInit(0, 0, 0); -} - -bob::learn::em::PLDABase::PLDABase(const size_t dim_d, const size_t dim_f, - const size_t dim_g, const double variance_threshold): - m_variance_threshold(variance_threshold) -{ - resize(dim_d, dim_f, dim_g); -} - - -bob::learn::em::PLDABase::PLDABase(const bob::learn::em::PLDABase& other): - m_dim_d(other.m_dim_d), - m_dim_f(other.m_dim_f), - m_dim_g(other.m_dim_g), - m_F(bob::core::array::ccopy(other.m_F)), - m_G(bob::core::array::ccopy(other.m_G)), - m_sigma(bob::core::array::ccopy(other.m_sigma)), - m_mu(bob::core::array::ccopy(other.m_mu)), - m_variance_threshold(other.m_variance_threshold), - m_cache_isigma(bob::core::array::ccopy(other.m_cache_isigma)), - m_cache_alpha(bob::core::array::ccopy(other.m_cache_alpha)), - m_cache_beta(bob::core::array::ccopy(other.m_cache_beta)), - m_cache_gamma(), - m_cache_Ft_beta(bob::core::array::ccopy(other.m_cache_Ft_beta)), - m_cache_Gt_isigma(bob::core::array::ccopy(other.m_cache_Gt_isigma)), - m_cache_logdet_alpha(other.m_cache_logdet_alpha), - m_cache_logdet_sigma(other.m_cache_logdet_sigma), - m_cache_loglike_constterm(other.m_cache_loglike_constterm) -{ - bob::core::array::ccopy(other.m_cache_gamma, m_cache_gamma); - resizeTmp(); -} - -bob::learn::em::PLDABase::PLDABase(bob::io::base::HDF5File& config) { - load(config); -} - -bob::learn::em::PLDABase::~PLDABase() { -} - -bob::learn::em::PLDABase& bob::learn::em::PLDABase::operator= - (const bob::learn::em::PLDABase& other) -{ - if (this != &other) - { - m_dim_d = other.m_dim_d; - m_dim_f = other.m_dim_f; - m_dim_g = other.m_dim_g; - m_F.reference(bob::core::array::ccopy(other.m_F)); - m_G.reference(bob::core::array::ccopy(other.m_G)); - m_sigma.reference(bob::core::array::ccopy(other.m_sigma)); - m_mu.reference(bob::core::array::ccopy(other.m_mu)); - m_variance_threshold = other.m_variance_threshold; - m_cache_isigma.reference(bob::core::array::ccopy(other.m_cache_isigma)); - m_cache_alpha.reference(bob::core::array::ccopy(other.m_cache_alpha)); - m_cache_beta.reference(bob::core::array::ccopy(other.m_cache_beta)); - bob::core::array::ccopy(other.m_cache_gamma, m_cache_gamma); - m_cache_Ft_beta.reference(bob::core::array::ccopy(other.m_cache_Ft_beta)); - m_cache_Gt_isigma.reference(bob::core::array::ccopy(other.m_cache_Gt_isigma)); - m_cache_logdet_alpha = other.m_cache_logdet_alpha; - m_cache_logdet_sigma = other.m_cache_logdet_sigma; - m_cache_loglike_constterm = other.m_cache_loglike_constterm; - resizeTmp(); - } - return *this; -} - -bool bob::learn::em::PLDABase::operator== - (const bob::learn::em::PLDABase& b) const -{ - if (!(m_dim_d == b.m_dim_d && m_dim_f == b.m_dim_f && - m_dim_g == b.m_dim_g && - bob::core::array::isEqual(m_F, b.m_F) && - bob::core::array::isEqual(m_G, b.m_G) && - bob::core::array::isEqual(m_sigma, b.m_sigma) && - bob::core::array::isEqual(m_mu, b.m_mu) && - m_variance_threshold == b.m_variance_threshold && - bob::core::array::isEqual(m_cache_isigma, b.m_cache_isigma) && - bob::core::array::isEqual(m_cache_alpha, b.m_cache_alpha) && - bob::core::array::isEqual(m_cache_beta, b.m_cache_beta) && - bob::core::array::isEqual(m_cache_gamma, b.m_cache_gamma) && - bob::core::array::isEqual(m_cache_Ft_beta, b.m_cache_Ft_beta) && - bob::core::array::isEqual(m_cache_Gt_isigma, b.m_cache_Gt_isigma) && - m_cache_logdet_alpha == b.m_cache_logdet_alpha && - m_cache_logdet_sigma == b.m_cache_logdet_sigma)) - return false; - - // m_cache_loglike_constterm - if (this->m_cache_loglike_constterm.size() != b.m_cache_loglike_constterm.size()) - return false; // differing sizes, they are not the same - std::map<size_t, double>::const_iterator i, j; - for (i = this->m_cache_loglike_constterm.begin(), j = b.m_cache_loglike_constterm.begin(); - i != this->m_cache_loglike_constterm.end(); ++i, ++j) - { - if (i->first != j->first || i->second != j->second) - return false; - } - - return true; -} - -bool bob::learn::em::PLDABase::operator!= - (const bob::learn::em::PLDABase& b) const -{ - return !(this->operator==(b)); -} - -bool bob::learn::em::PLDABase::is_similar_to(const bob::learn::em::PLDABase& b, - const double r_epsilon, const double a_epsilon) const -{ - return (m_dim_d == b.m_dim_d && m_dim_f == b.m_dim_f && - m_dim_g == b.m_dim_g && - bob::core::array::isClose(m_F, b.m_F, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_G, b.m_G, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_sigma, b.m_sigma, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_mu, b.m_mu, r_epsilon, a_epsilon) && - bob::core::isClose(m_variance_threshold, b.m_variance_threshold, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_isigma, b.m_cache_isigma, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_alpha, b.m_cache_alpha, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_beta, b.m_cache_beta, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_gamma, b.m_cache_gamma, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_Ft_beta, b.m_cache_Ft_beta, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_Gt_isigma, b.m_cache_Gt_isigma, r_epsilon, a_epsilon) && - bob::core::isClose(m_cache_logdet_alpha, b.m_cache_logdet_alpha, r_epsilon, a_epsilon) && - bob::core::isClose(m_cache_logdet_sigma, b.m_cache_logdet_sigma, r_epsilon, a_epsilon) && - bob::core::isClose(m_cache_loglike_constterm, b.m_cache_loglike_constterm)); -} - -void bob::learn::em::PLDABase::load(bob::io::base::HDF5File& config) -{ - if (!config.contains("dim_d")) - { - // Then the model was saved using bob < 1.2.0 - //reads all data directly into the member variables - m_F.reference(config.readArray<double,2>("F")); - m_G.reference(config.readArray<double,2>("G")); - m_dim_d = m_F.extent(0); - m_dim_f = m_F.extent(1); - m_dim_g = m_G.extent(1); - m_sigma.reference(config.readArray<double,1>("sigma")); - m_mu.reference(config.readArray<double,1>("mu")); - m_cache_isigma.resize(m_dim_d); - precomputeISigma(); - m_variance_threshold = 0.; - m_cache_alpha.reference(config.readArray<double,2>("alpha")); - m_cache_beta.reference(config.readArray<double,2>("beta")); - // gamma and log like constant term (a-dependent terms) - if (config.contains("a_indices")) - { - blitz::Array<uint32_t, 1> a_indices; - a_indices.reference(config.readArray<uint32_t,1>("a_indices")); - for (int i=0; i<a_indices.extent(0); ++i) - { - std::string str1 = "gamma_" + boost::lexical_cast<std::string>(a_indices(i)); - m_cache_gamma[a_indices(i)].reference(config.readArray<double,2>(str1)); - std::string str2 = "loglikeconstterm_" + boost::lexical_cast<std::string>(a_indices(i)); - m_cache_loglike_constterm[a_indices(i)] = config.read<double>(str2); - } - } - m_cache_Ft_beta.reference(config.readArray<double,2>("Ft_beta")); - m_cache_Gt_isigma.reference(config.readArray<double,2>("Gt_isigma")); - m_cache_logdet_alpha = config.read<double>("logdet_alpha"); - m_cache_logdet_sigma = config.read<double>("logdet_sigma"); - } - else - { - // Then the model was saved using bob >= 1.2.0 - //reads all data directly into the member variables - m_F.reference(config.readArray<double,2>("F")); - m_G.reference(config.readArray<double,2>("G")); - // Conditional because previous versions had not these variables - m_dim_d = config.read<uint64_t>("dim_d"); - m_dim_f = config.read<uint64_t>("dim_f"); - m_dim_g = config.read<uint64_t>("dim_g"); - m_sigma.reference(config.readArray<double,1>("sigma")); - m_mu.reference(config.readArray<double,1>("mu")); - m_cache_isigma.resize(m_dim_d); - precomputeISigma(); - if (config.contains("variance_threshold")) - m_variance_threshold = config.read<double>("variance_threshold"); - else if (config.contains("variance_thresholds")) // In case 1.2.0 alpha/beta version has been used - { - blitz::Array<double,1> tmp; - tmp.reference(config.readArray<double,1>("variance_thresholds")); - m_variance_threshold = tmp(0); - } - m_cache_alpha.reference(config.readArray<double,2>("alpha")); - m_cache_beta.reference(config.readArray<double,2>("beta")); - // gamma's (a-dependent terms) - if(config.contains("a_indices_gamma")) - { - blitz::Array<uint32_t, 1> a_indices; - a_indices.reference(config.readArray<uint32_t,1>("a_indices_gamma")); - for(int i=0; i<a_indices.extent(0); ++i) - { - std::string str = "gamma_" + boost::lexical_cast<std::string>(a_indices(i)); - m_cache_gamma[a_indices(i)].reference(config.readArray<double,2>(str)); - } - } - // log likelihood constant term's (a-dependent terms) - if(config.contains("a_indices_loglikeconstterm")) - { - blitz::Array<uint32_t, 1> a_indices; - a_indices.reference(config.readArray<uint32_t,1>("a_indices_loglikeconstterm")); - for(int i=0; i<a_indices.extent(0); ++i) - { - std::string str = "loglikeconstterm_" + boost::lexical_cast<std::string>(a_indices(i)); - m_cache_loglike_constterm[a_indices(i)] = config.read<double>(str); - } - } - m_cache_Ft_beta.reference(config.readArray<double,2>("Ft_beta")); - m_cache_Gt_isigma.reference(config.readArray<double,2>("Gt_isigma")); - m_cache_logdet_alpha = config.read<double>("logdet_alpha"); - m_cache_logdet_sigma = config.read<double>("logdet_sigma"); - } - resizeTmp(); -} - -void bob::learn::em::PLDABase::save(bob::io::base::HDF5File& config) const -{ - config.set("dim_d", (uint64_t)m_dim_d); - config.set("dim_f", (uint64_t)m_dim_f); - config.set("dim_g", (uint64_t)m_dim_g); - config.setArray("F", m_F); - config.setArray("G", m_G); - config.setArray("sigma", m_sigma); - config.setArray("mu", m_mu); - config.set("variance_threshold", m_variance_threshold); - config.setArray("alpha", m_cache_alpha); - config.setArray("beta", m_cache_beta); - // gamma's - if(m_cache_gamma.size() > 0) - { - blitz::Array<uint32_t, 1> a_indices(m_cache_gamma.size()); - int i = 0; - for(std::map<size_t,blitz::Array<double,2> >::const_iterator - it=m_cache_gamma.begin(); it!=m_cache_gamma.end(); ++it) - { - a_indices(i) = it->first; - std::string str = "gamma_" + boost::lexical_cast<std::string>(it->first); - config.setArray(str, it->second); - ++i; - } - config.setArray("a_indices_gamma", a_indices); - } - // log likelihood constant terms - if(m_cache_loglike_constterm.size() > 0) - { - blitz::Array<uint32_t, 1> a_indices(m_cache_loglike_constterm.size()); - int i = 0; - for(std::map<size_t,double>::const_iterator - it=m_cache_loglike_constterm.begin(); it!=m_cache_loglike_constterm.end(); ++it) - { - a_indices(i) = it->first; - std::string str = "loglikeconstterm_" + boost::lexical_cast<std::string>(it->first); - config.set(str, it->second); - ++i; - } - config.setArray("a_indices_loglikeconstterm", a_indices); - } - - config.setArray("Ft_beta", m_cache_Ft_beta); - config.setArray("Gt_isigma", m_cache_Gt_isigma); - config.set("logdet_alpha", m_cache_logdet_alpha); - config.set("logdet_sigma", m_cache_logdet_sigma); -} - -void bob::learn::em::PLDABase::resizeNoInit(const size_t dim_d, const size_t dim_f, - const size_t dim_g) -{ - m_dim_d = dim_d; - m_dim_f = dim_f; - m_dim_g = dim_g; - m_F.resize(dim_d, dim_f); - m_G.resize(dim_d, dim_g); - m_sigma.resize(dim_d); - m_mu.resize(dim_d); - m_cache_alpha.resize(dim_g, dim_g); - m_cache_beta.resize(dim_d, dim_d); - m_cache_Ft_beta.resize(dim_f, dim_d); - m_cache_Gt_isigma.resize(dim_g, dim_d); - m_cache_gamma.clear(); - m_cache_isigma.resize(dim_d); - m_cache_loglike_constterm.clear(); - resizeTmp(); -} - -void bob::learn::em::PLDABase::resizeTmp() -{ - m_tmp_d_1.resize(m_dim_d); - m_tmp_d_2.resize(m_dim_d); - m_tmp_d_ng_1.resize(m_dim_d, m_dim_g); - m_tmp_nf_nf_1.resize(m_dim_f, m_dim_f); - m_tmp_ng_ng_1.resize(m_dim_g, m_dim_g); -} - -void bob::learn::em::PLDABase::resize(const size_t dim_d, const size_t dim_f, - const size_t dim_g) -{ - resizeNoInit(dim_d, dim_f, dim_g); - initMuFGSigma(); -} - -void bob::learn::em::PLDABase::setF(const blitz::Array<double,2>& F) -{ - bob::core::array::assertSameShape(F, m_F); - m_F.reference(bob::core::array::ccopy(F)); - // Precomputes useful matrices - precompute(); -} - -void bob::learn::em::PLDABase::setG(const blitz::Array<double,2>& G) -{ - bob::core::array::assertSameShape(G, m_G); - m_G.reference(bob::core::array::ccopy(G)); - // Precomputes useful matrices and values - precompute(); - precomputeLogDetAlpha(); -} - -void bob::learn::em::PLDABase::setSigma(const blitz::Array<double,1>& sigma) -{ - bob::core::array::assertSameShape(sigma, m_sigma); - m_sigma.reference(bob::core::array::ccopy(sigma)); - // Apply variance flooring threshold: This will also - // call the precompute() and precomputeLogLike() methods! - applyVarianceThreshold(); -} - -void bob::learn::em::PLDABase::setMu(const blitz::Array<double,1>& mu) -{ - bob::core::array::assertSameShape(mu, m_mu); - m_mu.reference(bob::core::array::ccopy(mu)); -} - -void bob::learn::em::PLDABase::setVarianceThreshold(const double value) -{ - // Variance flooring - m_variance_threshold = value; - // Apply variance flooring thresholds: This will also - // call the precompute() and precomputeLogLike() methods! - applyVarianceThreshold(); -} - -void bob::learn::em::PLDABase::applyVarianceThreshold() -{ - // Apply variance flooring threshold - m_sigma = blitz::where( m_sigma < m_variance_threshold, m_variance_threshold, m_sigma); - // Re-compute constants, because m_sigma has changed - precompute(); - precomputeLogLike(); -} - -const blitz::Array<double,2>& bob::learn::em::PLDABase::getGamma(const size_t a) const -{ - if(!hasGamma(a)) - throw std::runtime_error("Gamma for this number of samples is not currently in cache. You could use the getAddGamma() method instead"); - return (m_cache_gamma.find(a))->second; -} - -const blitz::Array<double,2>& bob::learn::em::PLDABase::getAddGamma(const size_t a) -{ - if(!hasGamma(a)) precomputeGamma(a); - return m_cache_gamma[a]; -} - -void bob::learn::em::PLDABase::initMuFGSigma() -{ - // To avoid problems related to precomputation - m_mu = 0.; - bob::math::eye(m_F); - bob::math::eye(m_G); - m_sigma = 1.; - // Precompute variables - precompute(); - precomputeLogLike(); -} - -void bob::learn::em::PLDABase::precompute() -{ - precomputeISigma(); - precomputeGtISigma(); - precomputeAlpha(); - precomputeBeta(); - m_cache_gamma.clear(); - precomputeFtBeta(); - m_cache_loglike_constterm.clear(); -} - -void bob::learn::em::PLDABase::precomputeLogLike() -{ - precomputeLogDetAlpha(); - precomputeLogDetSigma(); -} - -void bob::learn::em::PLDABase::precomputeISigma() -{ - // Updates inverse of sigma - m_cache_isigma = 1. / m_sigma; -} - -void bob::learn::em::PLDABase::precomputeGtISigma() -{ - // m_cache_Gt_isigma = G^T \Sigma^{-1} - blitz::firstIndex i; - blitz::secondIndex j; - blitz::Array<double,2> Gt = m_G.transpose(1,0); - m_cache_Gt_isigma = Gt(i,j) * m_cache_isigma(j); -} - -void bob::learn::em::PLDABase::precomputeAlpha() -{ - // alpha = (Id + G^T.sigma^-1.G)^-1 - - // m_tmp_ng_ng_1 = G^T.sigma^-1.G - bob::math::prod(m_cache_Gt_isigma, m_G, m_tmp_ng_ng_1); - // m_tmp_ng_ng_1 = Id + G^T.sigma^-1.G - for(int i=0; i<m_tmp_ng_ng_1.extent(0); ++i) m_tmp_ng_ng_1(i,i) += 1; - // m_cache_alpha = (Id + G^T.sigma^-1.G)^-1 - bob::math::inv(m_tmp_ng_ng_1, m_cache_alpha); -} - -void bob::learn::em::PLDABase::precomputeBeta() -{ - // beta = (sigma + G.G^T)^-1 - // BUT, there is a more efficient computation (Woodbury identity): - // beta = sigma^-1 - sigma^-1.G.(Id + G^T.sigma^-1.G)^-1.G^T.sigma^-1 - // beta = sigma^-1 - sigma^-1.G.alpha.G^T.sigma^-1 - - blitz::Array<double,2> GtISigmaT = m_cache_Gt_isigma.transpose(1,0); - // m_tmp_d_ng_1 = sigma^-1.G.alpha - bob::math::prod(GtISigmaT, m_cache_alpha, m_tmp_d_ng_1); - // m_cache_beta = -sigma^-1.G.alpha.G^T.sigma^-1 - bob::math::prod(m_tmp_d_ng_1, m_cache_Gt_isigma, m_cache_beta); - m_cache_beta = -m_cache_beta; - // m_cache_beta = sigma^-1 - sigma^-1.G.alpha.G^T.sigma^-1 - for(int i=0; i<m_cache_beta.extent(0); ++i) m_cache_beta(i,i) += m_cache_isigma(i); -} - -void bob::learn::em::PLDABase::precomputeGamma(const size_t a) -{ - - blitz::Array<double,2> gamma_a(getDimF(),getDimF()); - m_cache_gamma[a].reference(gamma_a); - computeGamma(a, gamma_a); -} - -void bob::learn::em::PLDABase::precomputeFtBeta() -{ - // m_cache_Ft_beta = F^T.beta = F^T.(sigma + G.G^T)^-1 - blitz::Array<double,2> Ft = m_F.transpose(1,0); - bob::math::prod(Ft, m_cache_beta, m_cache_Ft_beta); -} - -void bob::learn::em::PLDABase::computeGamma(const size_t a, - blitz::Array<double,2> res) const -{ - // gamma = (Id + a.F^T.beta.F)^-1 - - // Checks destination size - bob::core::array::assertSameShape(res, m_tmp_nf_nf_1); - // m_tmp_nf_nf_1 = F^T.beta.F - bob::math::prod(m_cache_Ft_beta, m_F, m_tmp_nf_nf_1); - // m_tmp_nf_nf_1 = a.F^T.beta.F - m_tmp_nf_nf_1 *= static_cast<double>(a); - // m_tmp_nf_nf_1 = Id + a.F^T.beta.F - for(int i=0; i<m_tmp_nf_nf_1.extent(0); ++i) m_tmp_nf_nf_1(i,i) += 1; - - // res = (Id + a.F^T.beta.F)^-1 - bob::math::inv(m_tmp_nf_nf_1, res); -} - -void bob::learn::em::PLDABase::precomputeLogDetAlpha() -{ - int sign; - m_cache_logdet_alpha = bob::math::slogdet(m_cache_alpha, sign); -} - -void bob::learn::em::PLDABase::precomputeLogDetSigma() -{ - m_cache_logdet_sigma = blitz::sum(blitz::log(m_sigma)); -} - -double bob::learn::em::PLDABase::computeLogLikeConstTerm(const size_t a, - const blitz::Array<double,2>& gamma_a) const -{ - // loglike_constterm[a] = a/2 * - // ( -D*log(2*pi) -log|sigma| +log|alpha| +log|gamma_a|) - int sign; - double logdet_gamma_a = bob::math::slogdet(gamma_a, sign); - double ah = static_cast<double>(a)/2.; - double res = ( -ah*((double)m_dim_d)*log(2*M_PI) - - ah*m_cache_logdet_sigma + ah*m_cache_logdet_alpha + logdet_gamma_a/2.); - return res; -} - -double bob::learn::em::PLDABase::computeLogLikeConstTerm(const size_t a) -{ - const blitz::Array<double,2>& gamma_a = getAddGamma(a); - return computeLogLikeConstTerm(a, gamma_a); -} - -void bob::learn::em::PLDABase::precomputeLogLikeConstTerm(const size_t a) -{ - double val = computeLogLikeConstTerm(a); - m_cache_loglike_constterm[a] = val; -} - -double bob::learn::em::PLDABase::getLogLikeConstTerm(const size_t a) const -{ - if(!hasLogLikeConstTerm(a)) - throw std::runtime_error("The LogLikelihood constant term for this number of samples is not currently in cache. You could use the getAddLogLikeConstTerm() method instead"); - return (m_cache_loglike_constterm.find(a))->second; -} - -double bob::learn::em::PLDABase::getAddLogLikeConstTerm(const size_t a) -{ - if(!hasLogLikeConstTerm(a)) precomputeLogLikeConstTerm(a); - return m_cache_loglike_constterm[a]; -} - -void bob::learn::em::PLDABase::clearMaps() -{ - m_cache_gamma.clear(); - m_cache_loglike_constterm.clear(); -} - -double bob::learn::em::PLDABase::computeLogLikelihoodPointEstimate( - const blitz::Array<double,1>& xij, const blitz::Array<double,1>& hi, - const blitz::Array<double,1>& wij) const -{ - // Check inputs - bob::core::array::assertSameDimensionLength(xij.extent(0), getDimD()); - bob::core::array::assertSameDimensionLength(hi.extent(0), getDimF()); - bob::core::array::assertSameDimensionLength(wij.extent(0), getDimG()); - // Computes: -D/2 log(2pi) -1/2 log(det(\Sigma)) - // -1/2 {(x_{ij}-(\mu+Fh_{i}+Gw_{ij}))^{T}\Sigma^{-1}(x_{ij}-(\mu+Fh_{i}+Gw_{ij}))} - double res = -0.5*((double)m_dim_d)*log(2*M_PI) - 0.5*m_cache_logdet_sigma; - // m_tmp_d_1 = (x_{ij} - (\mu+Fh_{i}+Gw_{ij})) - m_tmp_d_1 = xij - m_mu; - bob::math::prod(m_F, hi, m_tmp_d_2); - m_tmp_d_1 -= m_tmp_d_2; - bob::math::prod(m_G, wij, m_tmp_d_2); - m_tmp_d_1 -= m_tmp_d_2; - // add third term to res - res += -0.5*blitz::sum(blitz::pow2(m_tmp_d_1) * m_cache_isigma); - return res; -} - -namespace bob { namespace learn { namespace em { - /** - * @brief Prints a PLDABase in the output stream. This will print - * the values of the parameters \f$\mu\f$, \f$F\f$, \f$G\f$ and - * \f$\Sigma\f$ of the PLDA model. - */ - std::ostream& operator<<(std::ostream& os, const PLDABase& m) { - os << "mu = " << m.m_mu << std::endl; - os << "sigma = " << m.m_sigma << std::endl; - os << "F = " << m.m_F << std::endl; - os << "G = " << m.m_G << std::endl; - return os; - } -} } } - - -bob::learn::em::PLDAMachine::PLDAMachine(): - m_plda_base(), - m_n_samples(0), m_nh_sum_xit_beta_xi(0), m_weighted_sum(0), - m_loglikelihood(0), m_cache_gamma(), m_cache_loglike_constterm(), - m_tmp_d_1(0), m_tmp_d_2(0), m_tmp_nf_1(0), m_tmp_nf_2(0), m_tmp_nf_nf_1(0,0) -{ -} - -bob::learn::em::PLDAMachine::PLDAMachine(const boost::shared_ptr<bob::learn::em::PLDABase> plda_base): - m_plda_base(plda_base), - m_n_samples(0), m_nh_sum_xit_beta_xi(0), m_weighted_sum(plda_base->getDimF()), - m_loglikelihood(0), m_cache_gamma(), m_cache_loglike_constterm() -{ - resizeTmp(); -} - - -bob::learn::em::PLDAMachine::PLDAMachine(const bob::learn::em::PLDAMachine& other): - m_plda_base(other.m_plda_base), - m_n_samples(other.m_n_samples), - m_nh_sum_xit_beta_xi(other.m_nh_sum_xit_beta_xi), - m_weighted_sum(bob::core::array::ccopy(other.m_weighted_sum)), - m_loglikelihood(other.m_loglikelihood), m_cache_gamma(), - m_cache_loglike_constterm(other.m_cache_loglike_constterm) -{ - bob::core::array::ccopy(other.m_cache_gamma, m_cache_gamma); - resizeTmp(); -} - -bob::learn::em::PLDAMachine::PLDAMachine(bob::io::base::HDF5File& config, - const boost::shared_ptr<bob::learn::em::PLDABase> plda_base): - m_plda_base(plda_base) -{ - load(config); -} - -bob::learn::em::PLDAMachine::~PLDAMachine() { -} - -bob::learn::em::PLDAMachine& bob::learn::em::PLDAMachine::operator= -(const bob::learn::em::PLDAMachine& other) -{ - if(this!=&other) - { - m_plda_base = other.m_plda_base; - m_n_samples = other.m_n_samples; - m_nh_sum_xit_beta_xi = other.m_nh_sum_xit_beta_xi; - m_weighted_sum.reference(bob::core::array::ccopy(other.m_weighted_sum)); - m_loglikelihood = other.m_loglikelihood; - bob::core::array::ccopy(other.m_cache_gamma, m_cache_gamma); - m_cache_loglike_constterm = other.m_cache_loglike_constterm; - resizeTmp(); - } - return *this; -} - -bool bob::learn::em::PLDAMachine::operator== - (const bob::learn::em::PLDAMachine& b) const -{ - if (!(( (!m_plda_base && !b.m_plda_base) || - ((m_plda_base && b.m_plda_base) && *(m_plda_base) == *(b.m_plda_base))) && - m_n_samples == b.m_n_samples && - m_nh_sum_xit_beta_xi ==b.m_nh_sum_xit_beta_xi && - bob::core::array::isEqual(m_weighted_sum, b.m_weighted_sum) && - m_loglikelihood == b.m_loglikelihood && - bob::core::array::isEqual(m_cache_gamma, b.m_cache_gamma))) - return false; - - // m_cache_loglike_constterm - if (this->m_cache_loglike_constterm.size() != b.m_cache_loglike_constterm.size()) - return false; // differing sizes, they are not the same - std::map<size_t, double>::const_iterator i, j; - for (i = this->m_cache_loglike_constterm.begin(), j = b.m_cache_loglike_constterm.begin(); - i != this->m_cache_loglike_constterm.end(); ++i, ++j) - { - if (i->first != j->first || i->second != j->second) - return false; - } - - return true; -} - -bool bob::learn::em::PLDAMachine::operator!= - (const bob::learn::em::PLDAMachine& b) const -{ - return !(this->operator==(b)); -} - -bool bob::learn::em::PLDAMachine::is_similar_to( - const bob::learn::em::PLDAMachine& b, const double r_epsilon, - const double a_epsilon) const -{ - return (( (!m_plda_base && !b.m_plda_base) || - ((m_plda_base && b.m_plda_base) && - m_plda_base->is_similar_to(*(b.m_plda_base), r_epsilon, a_epsilon))) && - m_n_samples == b.m_n_samples && - bob::core::isClose(m_nh_sum_xit_beta_xi, b.m_nh_sum_xit_beta_xi, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_weighted_sum, b.m_weighted_sum, r_epsilon, a_epsilon) && - bob::core::isClose(m_loglikelihood, b.m_loglikelihood, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_gamma, b.m_cache_gamma, r_epsilon, a_epsilon) && - bob::core::isClose(m_cache_loglike_constterm, b.m_cache_loglike_constterm, r_epsilon, a_epsilon)); -} - -void bob::learn::em::PLDAMachine::load(bob::io::base::HDF5File& config) -{ - //reads all data directly into the member variables - m_n_samples = config.read<uint64_t>("n_samples"); - m_nh_sum_xit_beta_xi = config.read<double>("nh_sum_xit_beta_xi"); - m_weighted_sum.reference(config.readArray<double,1>("weighted_sum")); - m_loglikelihood = config.read<double>("loglikelihood"); - // gamma and log like constant term (a-dependent terms) - clearMaps(); - if(config.contains("a_indices")) - { - blitz::Array<uint32_t, 1> a_indices; - a_indices.reference(config.readArray<uint32_t,1>("a_indices")); - for(int i=0; i<a_indices.extent(0); ++i) - { - std::string str1 = "gamma_" + boost::lexical_cast<std::string>(a_indices(i)); - m_cache_gamma[a_indices(i)].reference(config.readArray<double,2>(str1)); - std::string str2 = "loglikeconstterm_" + boost::lexical_cast<std::string>(a_indices(i)); - m_cache_loglike_constterm[a_indices(i)] = config.read<double>(str2); - } - } - resizeTmp(); -} - -void bob::learn::em::PLDAMachine::save(bob::io::base::HDF5File& config) const -{ - config.set("n_samples", m_n_samples); - config.set("nh_sum_xit_beta_xi", m_nh_sum_xit_beta_xi); - config.setArray("weighted_sum", m_weighted_sum); - config.set("loglikelihood", m_loglikelihood); - // Gamma - if(m_cache_gamma.size() > 0) - { - blitz::Array<uint32_t, 1> a_indices(m_cache_gamma.size()); - int i = 0; - for(std::map<size_t,blitz::Array<double,2> >::const_iterator - it=m_cache_gamma.begin(); it!=m_cache_gamma.end(); ++it) - { - a_indices(i) = it->first; - std::string str1 = "gamma_" + boost::lexical_cast<std::string>(it->first); - config.setArray(str1, it->second); - std::string str2 = "loglikeconstterm_" + boost::lexical_cast<std::string>(it->first); - double v = m_cache_loglike_constterm.find(it->first)->second; - config.set(str2, v); - ++i; - } - config.setArray("a_indices", a_indices); - } -} - -void bob::learn::em::PLDAMachine::setPLDABase(const boost::shared_ptr<bob::learn::em::PLDABase> plda_base) -{ - m_plda_base = plda_base; - m_weighted_sum.resizeAndPreserve(getDimF()); - clearMaps(); - resizeTmp(); -} - - -void bob::learn::em::PLDAMachine::setWeightedSum(const blitz::Array<double,1>& ws) -{ - if(ws.extent(0) != m_weighted_sum.extent(0)) { - boost::format m("size of parameter `ws' (%d) does not match the expected size (%d)"); - m % ws.extent(0) % m_weighted_sum.extent(0); - throw std::runtime_error(m.str()); - } - m_weighted_sum.reference(bob::core::array::ccopy(ws)); -} - -const blitz::Array<double,2>& bob::learn::em::PLDAMachine::getGamma(const size_t a) const -{ - // Checks in both base machine and this machine - if (m_plda_base->hasGamma(a)) return m_plda_base->getGamma(a); - else if (!hasGamma(a)) - throw std::runtime_error("Gamma for this number of samples is not currently in cache. You could use the getAddGamma() method instead"); - return (m_cache_gamma.find(a))->second; -} - -const blitz::Array<double,2>& bob::learn::em::PLDAMachine::getAddGamma(const size_t a) -{ - if (m_plda_base->hasGamma(a)) return m_plda_base->getGamma(a); - else if (hasGamma(a)) return m_cache_gamma[a]; - // else computes it and adds it to this machine - blitz::Array<double,2> gamma_a(getDimF(),getDimF()); - m_cache_gamma[a].reference(gamma_a); - m_plda_base->computeGamma(a, gamma_a); - return m_cache_gamma[a]; -} - -double bob::learn::em::PLDAMachine::getLogLikeConstTerm(const size_t a) const -{ - // Checks in both base machine and this machine - if (!m_plda_base) throw std::runtime_error("No PLDABase set to this machine"); - if (m_plda_base->hasLogLikeConstTerm(a)) return m_plda_base->getLogLikeConstTerm(a); - else if (!hasLogLikeConstTerm(a)) - throw std::runtime_error("The LogLikelihood constant term for this number of samples is not currently in cache. You could use the getAddLogLikeConstTerm() method instead"); - return (m_cache_loglike_constterm.find(a))->second; -} - -double bob::learn::em::PLDAMachine::getAddLogLikeConstTerm(const size_t a) -{ - if (!m_plda_base) throw std::runtime_error("No PLDABase set to this machine"); - if (m_plda_base->hasLogLikeConstTerm(a)) return m_plda_base->getLogLikeConstTerm(a); - else if (hasLogLikeConstTerm(a)) return m_cache_loglike_constterm[a]; - // else computes it and adds it to this machine - m_cache_loglike_constterm[a] = - m_plda_base->computeLogLikeConstTerm(a, getAddGamma(a)); - return m_cache_loglike_constterm[a]; -} - -void bob::learn::em::PLDAMachine::clearMaps() -{ - m_cache_gamma.clear(); - m_cache_loglike_constterm.clear(); -} - -double bob::learn::em::PLDAMachine::forward(const blitz::Array<double,1>& sample) -{ - return forward_(sample); -} - -double bob::learn::em::PLDAMachine::forward_(const blitz::Array<double,1>& sample) -{ - // Computes the log likelihood ratio - return computeLogLikelihood(sample, true) - // match - (computeLogLikelihood(sample, false) + m_loglikelihood); // no match -} - -double bob::learn::em::PLDAMachine::forward(const blitz::Array<double,2>& samples) -{ - // Computes the log likelihood ratio - return computeLogLikelihood(samples, true) - // match - (computeLogLikelihood(samples, false) + m_loglikelihood); // no match -} - -double bob::learn::em::PLDAMachine::computeLogLikelihood(const blitz::Array<double,1>& sample, - bool enroll) const -{ - if (!m_plda_base) throw std::runtime_error("No PLDABase set to this machine"); - // Check dimensionality - bob::core::array::assertSameDimensionLength(sample.extent(0), getDimD()); - - int n_samples = 1 + (enroll?m_n_samples:0); - - // 3/ Third term of the likelihood: -1/2*X^T*(SIGMA+A.A^T)^-1*X - // Efficient way: -1/2*sum_i(xi^T.sigma^-1.xi - xi^T.sigma^-1*G*(I+G^T.sigma^-1.G)^-1*G^T*sigma^-1.xi - // -1/2*sumWeighted^T*(I+aF^T.(sigma^-1-sigma^-1*G*(I+G^T.sigma^-1.G)^-1*G^T*sigma^-1).F)^-1*sumWeighted - // where sumWeighted = sum_i(F^T*(sigma^-1-sigma^-1*G*(I+G^T.sigma^-1.G)^-1*G^T*sigma^-1)*xi) - const blitz::Array<double,2>& beta = getPLDABase()->getBeta(); - const blitz::Array<double,2>& Ft_beta = getPLDABase()->getFtBeta(); - const blitz::Array<double,1>& mu = getPLDABase()->getMu(); - double terma = (enroll?m_nh_sum_xit_beta_xi:0.); - // sumWeighted - if (enroll && m_n_samples > 0) m_tmp_nf_1 = m_weighted_sum; - else m_tmp_nf_1 = 0; - - // terma += -1 / 2. * (xi^t*beta*xi) - m_tmp_d_1 = sample - mu; - bob::math::prod(beta, m_tmp_d_1, m_tmp_d_2); - terma += -1 / 2. * (blitz::sum(m_tmp_d_1*m_tmp_d_2)); - - // sumWeighted - bob::math::prod(Ft_beta, m_tmp_d_1, m_tmp_nf_2); - m_tmp_nf_1 += m_tmp_nf_2; - blitz::Array<double,2> gamma_a; - if (hasGamma(n_samples) || m_plda_base->hasGamma(n_samples)) - gamma_a.reference(getGamma(n_samples)); - else - { - gamma_a.reference(m_tmp_nf_nf_1); - m_plda_base->computeGamma(n_samples, gamma_a); - } - bob::math::prod(gamma_a, m_tmp_nf_1, m_tmp_nf_2); - double termb = 1 / 2. * (blitz::sum(m_tmp_nf_1*m_tmp_nf_2)); - - // 1/2/ Constant term of the log likelihood: - // 1/ First term of the likelihood: -Nsamples*D/2*log(2*PI) - // 2/ Second term of the likelihood: -1/2*log(det(SIGMA+A.A^T)) - // Efficient way: -Nsamples/2*log(det(sigma))-Nsamples/2*log(det(I+G^T.sigma^-1.G)) - // -1/2*log(det(I+aF^T.(sigma^-1-sigma^-1*G*(I+G^T.sigma^-1.G)*G^T*sigma^-1).F)) - double log_likelihood; // = getAddLogLikeConstTerm(static_cast<size_t>(n_samples)); - if (hasLogLikeConstTerm(n_samples) || m_plda_base->hasLogLikeConstTerm(n_samples)) - log_likelihood = getLogLikeConstTerm(n_samples); - else - log_likelihood = m_plda_base->computeLogLikeConstTerm(n_samples, gamma_a); - - log_likelihood += terma + termb; - return log_likelihood; -} - -double bob::learn::em::PLDAMachine::computeLogLikelihood(const blitz::Array<double,2>& samples, - bool enroll) const -{ - if (!m_plda_base) throw std::runtime_error("No PLDABase set to this machine"); - // Check dimensionality - bob::core::array::assertSameDimensionLength(samples.extent(1), getDimD()); - - int n_samples = samples.extent(0) + (enroll?m_n_samples:0); - // 3/ Third term of the likelihood: -1/2*X^T*(SIGMA+A.A^T)^-1*X - // Efficient way: -1/2*sum_i(xi^T.sigma^-1.xi - xi^T.sigma^-1*G*(I+G^T.sigma^-1.G)^-1*G^T*sigma^-1.xi - // -1/2*sumWeighted^T*(I+aF^T.(sigma^-1-sigma^-1*G*(I+G^T.sigma^-1.G)^-1*G^T*sigma^-1).F)^-1*sumWeighted - // where sumWeighted = sum_i(F^T*(sigma^-1-sigma^-1*G*(I+G^T.sigma^-1.G)^-1*G^T*sigma^-1)*xi) - const blitz::Array<double,2>& beta = getPLDABase()->getBeta(); - const blitz::Array<double,2>& Ft_beta = getPLDABase()->getFtBeta(); - const blitz::Array<double,1>& mu = getPLDABase()->getMu(); - double terma = (enroll?m_nh_sum_xit_beta_xi:0.); - // sumWeighted - if (enroll && m_n_samples > 0) m_tmp_nf_1 = m_weighted_sum; - else m_tmp_nf_1 = 0; - for (int k=0; k<samples.extent(0); ++k) - { - blitz::Array<double,1> samp = samples(k,blitz::Range::all()); - m_tmp_d_1 = samp - mu; - // terma += -1 / 2. * (xi^t*beta*xi) - bob::math::prod(beta, m_tmp_d_1, m_tmp_d_2); - terma += -1 / 2. * (blitz::sum(m_tmp_d_1*m_tmp_d_2)); - - // sumWeighted - bob::math::prod(Ft_beta, m_tmp_d_1, m_tmp_nf_2); - m_tmp_nf_1 += m_tmp_nf_2; - } - - blitz::Array<double,2> gamma_a; - if (hasGamma(n_samples) || m_plda_base->hasGamma(n_samples)) - gamma_a.reference(getGamma(n_samples)); - else - { - gamma_a.reference(m_tmp_nf_nf_1); - m_plda_base->computeGamma(n_samples, gamma_a); - } - bob::math::prod(gamma_a, m_tmp_nf_1, m_tmp_nf_2); - double termb = 1 / 2. * (blitz::sum(m_tmp_nf_1*m_tmp_nf_2)); - - // 1/2/ Constant term of the log likelihood: - // 1/ First term of the likelihood: -Nsamples*D/2*log(2*PI) - // 2/ Second term of the likelihood: -1/2*log(det(SIGMA+A.A^T)) - // Efficient way: -Nsamples/2*log(det(sigma))-Nsamples/2*log(det(I+G^T.sigma^-1.G)) - // -1/2*log(det(I+aF^T.(sigma^-1-sigma^-1*G*(I+G^T.sigma^-1.G)*G^T*sigma^-1).F)) - double log_likelihood; // = getAddLogLikeConstTerm(static_cast<size_t>(n_samples)); - if (hasLogLikeConstTerm(n_samples) || m_plda_base->hasLogLikeConstTerm(n_samples)) - log_likelihood = getLogLikeConstTerm(n_samples); - else - log_likelihood = m_plda_base->computeLogLikeConstTerm(n_samples, gamma_a); - - log_likelihood += terma + termb; - return log_likelihood; -} - -void bob::learn::em::PLDAMachine::resize(const size_t dim_d, const size_t dim_f, - const size_t dim_g) -{ - m_weighted_sum.resizeAndPreserve(dim_f); - clearMaps(); - resizeTmp(); -} - -void bob::learn::em::PLDAMachine::resizeTmp() -{ - if (m_plda_base) - { - m_tmp_d_1.resize(getDimD()); - m_tmp_d_2.resize(getDimD()); - m_tmp_nf_1.resize(getDimF()); - m_tmp_nf_2.resize(getDimF()); - m_tmp_nf_nf_1.resize(getDimF(), getDimF()); - } -} diff --git a/bob/learn/em/cpp/PLDATrainer.cpp b/bob/learn/em/cpp/PLDATrainer.cpp deleted file mode 100644 index 323ea6c9420c808d122c734d1d8537ea9d0666fc..0000000000000000000000000000000000000000 --- a/bob/learn/em/cpp/PLDATrainer.cpp +++ /dev/null @@ -1,800 +0,0 @@ -/** - * @date Fri Oct 14 18:07:56 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Probabilistic Linear Discriminant Analysis - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - - -#include <bob.learn.em/PLDATrainer.h> -#include <bob.core/check.h> -#include <bob.core/array_copy.h> -#include <bob.core/array_random.h> -#include <bob.math/inv.h> -#include <bob.math/svd.h> -#include <bob.core/check.h> -#include <bob.core/array_repmat.h> -#include <algorithm> -#include <limits> -#include <vector> - -#include <bob.math/linear.h> -#include <bob.math/linsolve.h> - - - -bob::learn::em::PLDATrainer::PLDATrainer(const bool use_sum_second_order): - m_rng(new boost::mt19937()), - m_dim_d(0), m_dim_f(0), m_dim_g(0), - m_use_sum_second_order(use_sum_second_order), - m_initF_method(bob::learn::em::PLDATrainer::RANDOM_F), m_initF_ratio(1.), - m_initG_method(bob::learn::em::PLDATrainer::RANDOM_G), m_initG_ratio(1.), - m_initSigma_method(bob::learn::em::PLDATrainer::RANDOM_SIGMA), - m_initSigma_ratio(1.), - m_cache_S(0,0), - m_cache_z_first_order(0), m_cache_sum_z_second_order(0,0), m_cache_z_second_order(0), - m_cache_n_samples_per_id(0), m_cache_n_samples_in_training(), m_cache_B(0,0), - m_cache_Ft_isigma_G(0,0), m_cache_eta(0,0), m_cache_zeta(), m_cache_iota(), - m_tmp_nf_1(0), m_tmp_nf_2(0), m_tmp_ng_1(0), - m_tmp_D_1(0), m_tmp_D_2(0), - m_tmp_nfng_nfng(0,0), m_tmp_D_nfng_1(0,0), m_tmp_D_nfng_2(0,0) -{ -} - -bob::learn::em::PLDATrainer::PLDATrainer(const bob::learn::em::PLDATrainer& other): - m_rng(other.m_rng), - m_dim_d(other.m_dim_d), m_dim_f(other.m_dim_f), m_dim_g(other.m_dim_g), - m_use_sum_second_order(other.m_use_sum_second_order), - m_initF_method(other.m_initF_method), m_initF_ratio(other.m_initF_ratio), - m_initG_method(other.m_initG_method), m_initG_ratio(other.m_initG_ratio), - m_initSigma_method(other.m_initSigma_method), m_initSigma_ratio(other.m_initSigma_ratio), - m_cache_S(bob::core::array::ccopy(other.m_cache_S)), - m_cache_z_first_order(), - m_cache_sum_z_second_order(bob::core::array::ccopy(other.m_cache_sum_z_second_order)), - m_cache_z_second_order(), - m_cache_n_samples_per_id(other.m_cache_n_samples_per_id), - m_cache_n_samples_in_training(other.m_cache_n_samples_in_training), - m_cache_B(bob::core::array::ccopy(other.m_cache_B)), - m_cache_Ft_isigma_G(bob::core::array::ccopy(other.m_cache_Ft_isigma_G)), - m_cache_eta(bob::core::array::ccopy(other.m_cache_eta)) -{ - bob::core::array::ccopy(other.m_cache_z_first_order, m_cache_z_first_order); - bob::core::array::ccopy(other.m_cache_z_second_order, m_cache_z_second_order); - bob::core::array::ccopy(other.m_cache_zeta, m_cache_zeta); - bob::core::array::ccopy(other.m_cache_iota, m_cache_iota); - // Resize working arrays - resizeTmp(); -} - -bob::learn::em::PLDATrainer::~PLDATrainer() {} - -bob::learn::em::PLDATrainer& bob::learn::em::PLDATrainer::operator= -(const bob::learn::em::PLDATrainer& other) -{ - if(this != &other) - { - m_rng = m_rng, - m_dim_d = other.m_dim_d; - m_dim_f = other.m_dim_f; - m_dim_g = other.m_dim_g; - m_use_sum_second_order = other.m_use_sum_second_order; - m_initF_method = other.m_initF_method; - m_initF_ratio = other.m_initF_ratio; - m_initG_method = other.m_initG_method; - m_initG_ratio = other.m_initG_ratio; - m_initSigma_method = other.m_initSigma_method; - m_initSigma_ratio = other.m_initSigma_ratio; - m_cache_S = bob::core::array::ccopy(other.m_cache_S); - bob::core::array::ccopy(other.m_cache_z_first_order, m_cache_z_first_order); - m_cache_sum_z_second_order = bob::core::array::ccopy(other.m_cache_sum_z_second_order); - bob::core::array::ccopy(other.m_cache_z_second_order, m_cache_z_second_order); - m_cache_n_samples_per_id = other.m_cache_n_samples_per_id; - m_cache_n_samples_in_training = other.m_cache_n_samples_in_training; - m_cache_B = bob::core::array::ccopy(other.m_cache_B); - m_cache_Ft_isigma_G = bob::core::array::ccopy(other.m_cache_Ft_isigma_G); - m_cache_eta = bob::core::array::ccopy(other.m_cache_eta); - bob::core::array::ccopy(other.m_cache_iota, m_cache_iota); - // Resize working arrays - resizeTmp(); - } - return *this; -} - -bool bob::learn::em::PLDATrainer::operator== - (const bob::learn::em::PLDATrainer& other) const -{ - return m_rng == m_rng && - m_dim_d == other.m_dim_d && - m_dim_f == other.m_dim_f && - m_dim_g == other.m_dim_g && - m_initF_method == other.m_initF_method && - m_initF_ratio == other.m_initF_ratio && - m_initG_method == other.m_initG_method && - m_initG_ratio == other.m_initG_ratio && - m_initSigma_method == other.m_initSigma_method && - m_initSigma_ratio == other.m_initSigma_ratio && - bob::core::array::isEqual(m_cache_S, m_cache_S) && - bob::core::array::isEqual(m_cache_z_first_order, other.m_cache_z_first_order) && - bob::core::array::isEqual(m_cache_sum_z_second_order, other.m_cache_sum_z_second_order) && - bob::core::array::isEqual(m_cache_z_second_order, other.m_cache_z_second_order) && - m_cache_n_samples_per_id.size() == m_cache_n_samples_per_id.size() && - std::equal(m_cache_n_samples_per_id.begin(), m_cache_n_samples_per_id.end(), other.m_cache_n_samples_per_id.begin()) && - m_cache_n_samples_in_training.size() == m_cache_n_samples_in_training.size() && - std::equal(m_cache_n_samples_in_training.begin(), m_cache_n_samples_in_training.end(), other.m_cache_n_samples_in_training.begin()) && - bob::core::array::isEqual(m_cache_B, other.m_cache_B) && - bob::core::array::isEqual(m_cache_Ft_isigma_G, other.m_cache_Ft_isigma_G) && - bob::core::array::isEqual(m_cache_eta, other.m_cache_eta) && - bob::core::array::isEqual(m_cache_zeta, other.m_cache_zeta) && - bob::core::array::isEqual(m_cache_iota, other.m_cache_iota); -} - -bool bob::learn::em::PLDATrainer::operator!= - (const bob::learn::em::PLDATrainer &other) const -{ - return !(this->operator==(other)); -} - -bool bob::learn::em::PLDATrainer::is_similar_to - (const bob::learn::em::PLDATrainer &other, const double r_epsilon, - const double a_epsilon) const -{ - return m_rng == m_rng && - m_dim_d == other.m_dim_d && - m_dim_f == other.m_dim_f && - m_dim_g == other.m_dim_g && - m_use_sum_second_order == other.m_use_sum_second_order && - m_initF_method == other.m_initF_method && - bob::core::isClose(m_initF_ratio, other.m_initF_ratio, r_epsilon, a_epsilon) && - m_initG_method == other.m_initG_method && - bob::core::isClose(m_initG_ratio, other.m_initG_ratio, r_epsilon, a_epsilon) && - m_initSigma_method == other.m_initSigma_method && - bob::core::isClose(m_initSigma_ratio, other.m_initSigma_ratio, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_S, m_cache_S, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_z_first_order, other.m_cache_z_first_order, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_sum_z_second_order, other.m_cache_sum_z_second_order, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_z_second_order, other.m_cache_z_second_order, r_epsilon, a_epsilon) && - m_cache_n_samples_per_id.size() == m_cache_n_samples_per_id.size() && - std::equal(m_cache_n_samples_per_id.begin(), m_cache_n_samples_per_id.end(), other.m_cache_n_samples_per_id.begin()) && - m_cache_n_samples_in_training.size() == m_cache_n_samples_in_training.size() && - std::equal(m_cache_n_samples_in_training.begin(), m_cache_n_samples_in_training.end(), other.m_cache_n_samples_in_training.begin()) && - bob::core::array::isClose(m_cache_B, other.m_cache_B, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_Ft_isigma_G, other.m_cache_Ft_isigma_G, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_eta, other.m_cache_eta, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_zeta, other.m_cache_zeta, r_epsilon, a_epsilon) && - bob::core::array::isClose(m_cache_iota, other.m_cache_iota, r_epsilon, a_epsilon); -} - -void bob::learn::em::PLDATrainer::initialize(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - // Checks training data - checkTrainingData(v_ar); - - // Gets dimension (first Arrayset) - size_t n_features = v_ar[0].extent(1); - m_dim_d = machine.getDimD(); - // Get dimensionalities from the PLDABase - bob::core::array::assertSameDimensionLength(n_features, m_dim_d); - m_dim_f = machine.getDimF(); - m_dim_g = machine.getDimG(); - - // Reinitializes array members - initMembers(v_ar); - - // Computes the mean and the covariance if required - computeMeanVariance(machine, v_ar); - - // Initialization (e.g. using scatter) - initFGSigma(machine, v_ar); -} - -void bob::learn::em::PLDATrainer::finalize(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - // Precomputes constant parts of the log likelihood and (gamma_a) - precomputeLogLike(machine, v_ar); - // Adds the case 1 sample if not already done (always used for scoring) - machine.getAddGamma(1); - machine.getAddLogLikeConstTerm(1); -} - -void bob::learn::em::PLDATrainer::checkTrainingData(const std::vector<blitz::Array<double,2> >& v_ar) -{ - // Checks that the vector of Arraysets is not empty - if (v_ar.size() == 0) { - throw std::runtime_error("input training set is empty"); - } - - // Gets dimension (first Arrayset) - int n_features = v_ar[0].extent(1); - // Checks dimension consistency - for (size_t i=0; i<v_ar.size(); ++i) { - if (v_ar[i].extent(1) != n_features) { - boost::format m("number of features (columns) of array for class %u (%d) does not match that of array for class 0 (%d)"); - m % i % v_ar[0].extent(1) % n_features; - throw std::runtime_error(m.str()); - } - } -} - -void bob::learn::em::PLDATrainer::initMembers(const std::vector<blitz::Array<double,2> >& v_ar) -{ - // Gets dimension (first Arrayset) - const size_t n_features = v_ar[0].extent(1); // dimensionality of the data - const size_t n_identities = v_ar.size(); - - m_cache_S.resize(n_features, n_features); - m_cache_sum_z_second_order.resize(m_dim_f+m_dim_g, m_dim_f+m_dim_g); - - // Loops over the identities - for (size_t i=0; i<n_identities; ++i) - { - // Number of training samples for this identity - const size_t n_i = v_ar[i].extent(0); - // m_cache_z_first_order - blitz::Array<double,2> z_i(n_i, m_dim_f+m_dim_g); - m_cache_z_first_order.push_back(z_i); - // m_z_second_order - if (!m_use_sum_second_order) - { - blitz::Array<double,3> z2_i(n_i, m_dim_f+m_dim_g, m_dim_f+m_dim_g); - m_cache_z_second_order.push_back(z2_i); - } - - // m_cache_n_samples_per_id - m_cache_n_samples_per_id.push_back(n_i); - - // Maps dependent on the number of samples per identity - std::map<size_t,bool>::iterator it; - it = m_cache_n_samples_in_training.find(n_i); - if (it == m_cache_n_samples_in_training.end()) - { - // Indicates if there are identities with n_i training samples and if - // corresponding matrices are up to date. - m_cache_n_samples_in_training[n_i] = false; - // Allocates arrays for identities with n_i training samples - m_cache_zeta[n_i].reference(blitz::Array<double,2>(m_dim_g, m_dim_g)); - m_cache_iota[n_i].reference(blitz::Array<double,2>(m_dim_f, m_dim_g)); - } - } - - m_cache_B.resize(n_features, m_dim_f+m_dim_g); - m_cache_Ft_isigma_G.resize(m_dim_f, m_dim_g); - m_cache_eta.resize(m_dim_f, m_dim_g); - - // Working arrays - resizeTmp(); -} - -void bob::learn::em::PLDATrainer::resizeTmp() -{ - m_tmp_nf_1.resize(m_dim_f); - m_tmp_nf_2.resize(m_dim_f); - m_tmp_ng_1.resize(m_dim_g); - m_tmp_D_1.resize(m_dim_d); - m_tmp_D_2.resize(m_dim_d); - m_tmp_nfng_nfng.resize(m_dim_f+m_dim_g, m_dim_f+m_dim_g); - m_tmp_D_nfng_1.resize(m_dim_d, m_dim_f+m_dim_g); - m_tmp_D_nfng_2.resize(m_dim_d, m_dim_f+m_dim_g); -} - -void bob::learn::em::PLDATrainer::computeMeanVariance(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - blitz::Array<double,1>& mu = machine.updateMu(); - blitz::Range all = blitz::Range::all(); - // TODO: Uncomment variance computation if required - /* if(m_compute_likelihood) - { - // loads all the data in a single shot - required for scatter - blitz::Array<double,2> data(n_features, n_samples); - for (size_t i=0; i<n_samples; ++i) - data(all,i) = ar(i,all); - // Mean and scatter computation - bob::math::scatter(data, m_cache_S, mu); - // divides scatter by N-1 - m_cache_S /= static_cast<double>(n_samples-1); - } - else */ - { - // Computes the mean and updates mu - mu = 0.; - size_t n_samples = 0; - for (size_t j=0; j<v_ar.size(); ++j) { - n_samples += v_ar[j].extent(0); - for (int i=0; i<v_ar[j].extent(0); ++i) - mu += v_ar[j](i,all); - } - mu /= static_cast<double>(n_samples); - m_cache_S = 0.; - } -} - -void bob::learn::em::PLDATrainer::initFGSigma(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - // Initializes F, G and sigma - initF(machine, v_ar); - initG(machine, v_ar); - initSigma(machine, v_ar); - - // Precomputes values using new F, G and sigma - machine.precompute(); -} - -void bob::learn::em::PLDATrainer::initF(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - blitz::Array<double,2>& F = machine.updateF(); - blitz::Range a = blitz::Range::all(); - - // 1: between-class scatter - if (m_initF_method == bob::learn::em::PLDATrainer::BETWEEN_SCATTER) - { - if (machine.getDimF() > v_ar.size()) { - boost::format m("The rank of the matrix F ('%ld') can't be larger than the number of classes in the training set ('%ld')"); - m % machine.getDimF() % v_ar.size(); - throw std::runtime_error(m.str()); - } - - // a/ Computes between-class scatter matrix - blitz::firstIndex bi; - blitz::secondIndex bj; - blitz::Array<double,2> S(machine.getDimD(), v_ar.size()); - S = 0.; - m_tmp_D_1 = 0.; - for (size_t i=0; i<v_ar.size(); ++i) - { - blitz::Array<double,1> Si = S(blitz::Range::all(),i); - Si = 0.; - for (int j=0; j<v_ar[i].extent(0); ++j) - { - // Si += x_ij - Si += v_ar[i](j,a); - } - // Si = mean of the samples class i - Si /= static_cast<double>(v_ar[i].extent(0)); - m_tmp_D_1 += Si; - } - m_tmp_D_1 /= static_cast<double>(v_ar.size()); - - // b/ Removes the mean - S = S(bi,bj) - m_tmp_D_1(bi); - - // c/ SVD of the between-class scatter matrix - const size_t n_singular = std::min(machine.getDimD(),v_ar.size()); - blitz::Array<double,2> U(machine.getDimD(), n_singular); - blitz::Array<double,1> sigma(n_singular); - bob::math::svd(S, U, sigma); - - // d/ Updates F - blitz::Array<double,2> Uslice = U(a, blitz::Range(0,m_dim_f-1)); - blitz::Array<double,1> sigma_slice = sigma(blitz::Range(0,m_dim_f-1)); - sigma_slice = blitz::sqrt(sigma_slice); - F = Uslice(bi,bj) / sigma_slice(bj); - } - // otherwise: random initialization - else { - // F initialization - bob::core::array::randn(*m_rng, F); - F *= m_initF_ratio; - } -} - -void bob::learn::em::PLDATrainer::initG(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - blitz::Array<double,2>& G = machine.updateG(); - blitz::Range a = blitz::Range::all(); - - // 1: within-class scatter - if (m_initG_method == bob::learn::em::PLDATrainer::WITHIN_SCATTER) - { - // a/ Computes within-class scatter matrix - blitz::firstIndex bi; - blitz::secondIndex bj; - size_t Nsamples=0; - for (size_t i=0; i<v_ar.size(); ++i) - Nsamples += v_ar[i].extent(0); - - blitz::Array<double,2> S(machine.getDimD(), Nsamples); - S = 0.; - m_tmp_D_1 = 0.; - int counter = 0; - for (size_t i=0; i<v_ar.size(); ++i) - { - // Computes the mean of the samples class i - m_tmp_D_2 = 0.; - for (int j=0; j<v_ar[i].extent(0); ++j) - { - // m_tmp_D_2 += x_ij - m_tmp_D_2 += v_ar[i](j,a); - } - // m_tmp_D_2 = mean of the samples class i - m_tmp_D_2 /= static_cast<double>(v_ar[i].extent(0)); - - // Generates the scatter - for (int j=0; j<v_ar[i].extent(0); ++j) - { - blitz::Array<double,1> Si = S(a, counter); - // Si = x_ij - mean_i - Si = v_ar[i](j,a) - m_tmp_D_2; - // mean of the within class - m_tmp_D_1 += Si; - ++counter; - } - } - m_tmp_D_1 /= static_cast<double>(Nsamples); - - // b/ Removes the mean - S = S(bi,bj) - m_tmp_D_1(bi); - - // c/ SVD of the between-class scatter matrix - blitz::Array<double,2> U(m_dim_d, std::min(m_dim_d, Nsamples)); - blitz::Array<double,1> sigma(std::min(m_dim_d, Nsamples)); - bob::math::svd(S, U, sigma); - - // d/ Updates G - blitz::Array<double,2> Uslice = U(blitz::Range::all(), blitz::Range(0,m_dim_g-1)); - blitz::Array<double,1> sigma_slice = sigma(blitz::Range(0,m_dim_g-1)); - sigma_slice = blitz::sqrt(sigma_slice); - G = Uslice(bi,bj) / sigma_slice(bj); - } - // otherwise: random initialization - else { - // G initialization - bob::core::array::randn(*m_rng, G); - G *= m_initG_ratio; - } -} - -void bob::learn::em::PLDATrainer::initSigma(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - blitz::Array<double,1>& sigma = machine.updateSigma(); - blitz::Range a = blitz::Range::all(); - - // 1: percentage of the variance of G - if (m_initSigma_method == bob::learn::em::PLDATrainer::VARIANCE_G) { - const blitz::Array<double,2>& G = machine.getG(); - blitz::secondIndex bj; - m_tmp_D_1 = blitz::mean(G, bj); - // Updates sigma - sigma = blitz::fabs(m_tmp_D_1) * m_initSigma_ratio; - } - // 2: constant value - else if (m_initSigma_method == bob::learn::em::PLDATrainer::CONSTANT) { - sigma = m_initSigma_ratio; - } - // 3: percentage of the variance of the data - else if (m_initSigma_method == bob::learn::em::PLDATrainer::VARIANCE_DATA) { - // a/ Computes the global mean - // m_tmp_D_1 = 1/N sum_i x_i - m_tmp_D_1 = 0.; - size_t Ns = 0; - for (size_t i=0; i<v_ar.size(); ++i) - { - for (int j=0; j<v_ar[i].extent(0); ++j) - m_tmp_D_1 += v_ar[i](j,a); - Ns += v_ar[i].extent(0); - } - m_tmp_D_1 /= static_cast<double>(Ns); - - // b/ Computes the variance: - m_tmp_D_2 = 0.; - for (size_t i=0; i<v_ar.size(); ++i) - for (int j=0; j<v_ar[i].extent(0); ++j) - m_tmp_D_2 += blitz::pow2(v_ar[i](j,a) - m_tmp_D_1); - sigma = m_initSigma_ratio * m_tmp_D_2 / static_cast<double>(Ns-1); - } - // otherwise: random initialization - else { - // sigma initialization - bob::core::array::randn(*m_rng, sigma); - sigma = blitz::fabs(sigma) * m_initSigma_ratio; - } - // Apply variance threshold - machine.applyVarianceThreshold(); -} - -void bob::learn::em::PLDATrainer::eStep(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - // Precomputes useful variables using current estimates of F,G, and sigma - precomputeFromFGSigma(machine); - // Gets the mean mu from the machine - const blitz::Array<double,1>& mu = machine.getMu(); - const blitz::Array<double,2>& alpha = machine.getAlpha(); - const blitz::Array<double,2>& F = machine.getF(); - const blitz::Array<double,2>& FtBeta = machine.getFtBeta(); - const blitz::Array<double,2>& GtISigma = machine.getGtISigma(); - blitz::Range a = blitz::Range::all(); - - // blitz indices - blitz::firstIndex bi; - blitz::secondIndex bj; - // Initializes sum of z second order statistics to 0 - m_cache_sum_z_second_order = 0.; - for (size_t i=0; i<v_ar.size(); ++i) - { - // Computes expectation of z_ij = [h_i w_ij] - // 1/a/ Computes expectation of h_i - // Loop over the samples - m_tmp_nf_1 = 0.; - for (int j=0; j<v_ar[i].extent(0); ++j) - { - // m_tmp_D_1 = x_sj-mu - m_tmp_D_1 = v_ar[i](j,a) - mu; - - // m_tmp_nf_2 = F^T.beta.(x_sj-mu) - bob::math::prod(FtBeta, m_tmp_D_1, m_tmp_nf_2); - // m_tmp_nf_1 = sum_j F^T.beta.(x_sj-mu) - m_tmp_nf_1 += m_tmp_nf_2; - } - const blitz::Array<double,2>& gamma_a = machine.getAddGamma(v_ar[i].extent(0)); - blitz::Range r_hi(0, m_dim_f-1); - // m_tmp_nf_2 = E(h_i) = gamma_A sum_j F^T.beta.(x_sj-mu) - bob::math::prod(gamma_a, m_tmp_nf_1, m_tmp_nf_2); - - // 1/b/ Precomputes: m_tmp_D_2 = F.E{h_i} - bob::math::prod(F, m_tmp_nf_2, m_tmp_D_2); - - // 2/ First and second order statistics of z - // Precomputed values - blitz::Array<double,2>& zeta_a = m_cache_zeta[v_ar[i].extent(0)]; - blitz::Array<double,2>& iota_a = m_cache_iota[v_ar[i].extent(0)]; - blitz::Array<double,2> iotat_a = iota_a.transpose(1,0); - - // Extracts statistics of z_ij = [h_i w_ij] from y_i = [h_i w_i1 ... w_iJ] - blitz::Range r1(0, m_dim_f-1); - blitz::Range r2(m_dim_f, m_dim_f+m_dim_g-1); - for (int j=0; j<v_ar[i].extent(0); ++j) - { - // 1/ First order statistics of z - blitz::Array<double,1> z_first_order_ij_1 = m_cache_z_first_order[i](j,r1); - z_first_order_ij_1 = m_tmp_nf_2; // E{h_i} - // m_tmp_D_1 = x_sj - mu - F.E{h_i} - m_tmp_D_1 = v_ar[i](j,a) - mu - m_tmp_D_2; - // m_tmp_ng_1 = G^T.sigma^-1.(x_sj-mu-fhi) - bob::math::prod(GtISigma, m_tmp_D_1, m_tmp_ng_1); - // z_first_order_ij_2 = (Id+G^T.sigma^-1.G)^-1.G^T.sigma^-1.(x_sj-mu) = E{w_ij} - blitz::Array<double,1> z_first_order_ij_2 = m_cache_z_first_order[i](j,r2); - bob::math::prod(alpha, m_tmp_ng_1, z_first_order_ij_2); - - // 2/ Second order statistics of z - blitz::Array<double,2> z_sum_so_11 = m_cache_sum_z_second_order(r1,r1); - blitz::Array<double,2> z_sum_so_12 = m_cache_sum_z_second_order(r1,r2); - blitz::Array<double,2> z_sum_so_21 = m_cache_sum_z_second_order(r2,r1); - blitz::Array<double,2> z_sum_so_22 = m_cache_sum_z_second_order(r2,r2); - if (m_use_sum_second_order) - { - z_sum_so_11 += gamma_a + z_first_order_ij_1(bi) * z_first_order_ij_1(bj); - z_sum_so_12 += iota_a + z_first_order_ij_1(bi) * z_first_order_ij_2(bj); - z_sum_so_21 += iotat_a + z_first_order_ij_2(bi) * z_first_order_ij_1(bj); - z_sum_so_22 += zeta_a + z_first_order_ij_2(bi) * z_first_order_ij_2(bj); - } - else - { - blitz::Array<double,2> z_so_11 = m_cache_z_second_order[i](j,r1,r1); - z_so_11 = gamma_a + z_first_order_ij_1(bi) * z_first_order_ij_1(bj); - z_sum_so_11 += z_so_11; - blitz::Array<double,2> z_so_12 = m_cache_z_second_order[i](j,r1,r2); - z_so_12 = iota_a + z_first_order_ij_1(bi) * z_first_order_ij_2(bj); - z_sum_so_12 += z_so_12; - blitz::Array<double,2> z_so_21 = m_cache_z_second_order[i](j,r2,r1); - z_so_21 = iotat_a + z_first_order_ij_2(bi) * z_first_order_ij_1(bj); - z_sum_so_21 += z_so_21; - blitz::Array<double,2> z_so_22 = m_cache_z_second_order[i](j,r2,r2); - z_so_22 = zeta_a + z_first_order_ij_2(bi) * z_first_order_ij_2(bj); - z_sum_so_22 += z_so_22; - } - } - } -} - -void bob::learn::em::PLDATrainer::precomputeFromFGSigma(bob::learn::em::PLDABase& machine) -{ - // Blitz compatibility: ugly fix (const_cast, as old blitz version does not - // provide a non-const version of transpose()) - const blitz::Array<double,2>& F = machine.getF(); - const blitz::Array<double,2> Ft = const_cast<blitz::Array<double,2>&>(F).transpose(1,0); - const blitz::Array<double,2>& Gt_isigma = machine.getGtISigma(); - const blitz::Array<double,2> Gt_isigma_t = const_cast<blitz::Array<double,2>&>(Gt_isigma).transpose(1,0); - const blitz::Array<double,2>& alpha = machine.getAlpha(); - - // Precomputes F, G and sigma-based expressions - bob::math::prod(Ft, Gt_isigma_t, m_cache_Ft_isigma_G); - bob::math::prod(m_cache_Ft_isigma_G, alpha, m_cache_eta); - blitz::Array<double,2> etat = m_cache_eta.transpose(1,0); - - // Reinitializes all the zeta_a and iota_a - std::map<size_t,bool>::iterator it; - for (it=m_cache_n_samples_in_training.begin(); it!=m_cache_n_samples_in_training.end(); - ++it) - it->second = false; - - for (it=m_cache_n_samples_in_training.begin(); it!=m_cache_n_samples_in_training.end(); - ++it) - { - size_t n_i = it->first; - // Precomputes zeta and iota for identities with q_i training samples, - // if not already done - if (!it->second) - { - const blitz::Array<double,2>& gamma_a = machine.getAddGamma(n_i); - blitz::Array<double,2>& zeta_a = m_cache_zeta[n_i]; - blitz::Array<double,2>& iota_a = m_cache_iota[n_i]; - bob::math::prod(gamma_a, m_cache_eta, iota_a); - bob::math::prod(etat, iota_a, zeta_a); - zeta_a += alpha; - iota_a = - iota_a; - // Now up to date - it->second = true; - } - } -} - -void bob::learn::em::PLDATrainer::precomputeLogLike(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - // Precomputes the log determinant of alpha and sigma - machine.precomputeLogLike(); - - // Precomputes the log likelihood constant term - std::map<size_t,bool>::iterator it; - for (it=m_cache_n_samples_in_training.begin(); - it!=m_cache_n_samples_in_training.end(); ++it) - { - // Precomputes the log likelihood constant term for identities with q_i - // training samples, if not already done - machine.getAddLogLikeConstTerm(it->first); - } -} - - -void bob::learn::em::PLDATrainer::mStep(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - // 1/ New estimate of B = {F G} - updateFG(machine, v_ar); - - // 2/ New estimate of Sigma - updateSigma(machine, v_ar); - - // 3/ Precomputes new values after updating F, G and sigma - machine.precompute(); - // Precomputes useful variables using current estimates of F,G, and sigma - precomputeFromFGSigma(machine); -} - -void bob::learn::em::PLDATrainer::updateFG(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - /// Computes the B matrix (B = [F G]) - /// B = (sum_ij (x_ij-mu).E{z_i}^T).(sum_ij E{z_i.z_i^T})^-1 - - // 1/ Computes the numerator (sum_ij (x_ij-mu).E{z_i}^T) - // Gets the mean mu from the machine - const blitz::Array<double,1>& mu = machine.getMu(); - blitz::Range a = blitz::Range::all(); - m_tmp_D_nfng_2 = 0.; - for (size_t i=0; i<v_ar.size(); ++i) - { - // Loop over the samples - for (int j=0; j<v_ar[i].extent(0); ++j) - { - // m_tmp_D_1 = x_sj-mu - m_tmp_D_1 = v_ar[i](j,a) - mu; - // z_first_order_ij = E{z_ij} - blitz::Array<double,1> z_first_order_ij = m_cache_z_first_order[i](j, a); - // m_tmp_D_nfng_1 = (x_sj-mu).E{z_ij}^T - bob::math::prod(m_tmp_D_1, z_first_order_ij, m_tmp_D_nfng_1); - m_tmp_D_nfng_2 += m_tmp_D_nfng_1; - } - } - - // 2/ Computes the denominator inv(sum_ij E{z_i.z_i^T}) - bob::math::inv(m_cache_sum_z_second_order, m_tmp_nfng_nfng); - - // 3/ Computes numerator / denominator - bob::math::prod(m_tmp_D_nfng_2, m_tmp_nfng_nfng, m_cache_B); - - // 4/ Updates the machine - blitz::Array<double, 2>& F = machine.updateF(); - blitz::Array<double, 2>& G = machine.updateG(); - F = m_cache_B(a, blitz::Range(0, m_dim_f-1)); - G = m_cache_B(a, blitz::Range(m_dim_f, m_dim_f+m_dim_g-1)); -} - -void bob::learn::em::PLDATrainer::updateSigma(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar) -{ - /// Computes the Sigma matrix - /// Sigma = 1/IJ sum_ij Diag{(x_ij-mu).(x_ij-mu)^T - B.E{z_i}.(x_ij-mu)^T} - - // Gets the mean mu and the matrix sigma from the machine - blitz::Array<double,1>& sigma = machine.updateSigma(); - const blitz::Array<double,1>& mu = machine.getMu(); - blitz::Range a = blitz::Range::all(); - - sigma = 0.; - size_t n_IJ=0; /// counts the number of samples - for (size_t i=0; i<v_ar.size(); ++i) - { - // Loop over the samples - for (int j=0; j<v_ar[i].extent(0); ++j) - { - // m_tmp_D_1 = x_ij-mu - m_tmp_D_1 = v_ar[i](j,a) - mu; - // sigma += Diag{(x_ij-mu).(x_ij-mu)^T} - sigma += blitz::pow2(m_tmp_D_1); - - // z_first_order_ij = E{z_ij} - blitz::Array<double,1> z_first_order_ij = m_cache_z_first_order[i](j,a); - // m_tmp_D_2 = B.E{z_ij} - bob::math::prod(m_cache_B, z_first_order_ij, m_tmp_D_2); - // sigma -= Diag{B.E{z_ij}.(x_ij-mu) - sigma -= (m_tmp_D_1 * m_tmp_D_2); - ++n_IJ; - } - } - // Normalizes by the number of samples - sigma /= static_cast<double>(n_IJ); - // Apply variance threshold - machine.applyVarianceThreshold(); -} - - -void bob::learn::em::PLDATrainer::enroll(bob::learn::em::PLDAMachine& plda_machine, - const blitz::Array<double,2>& ar) const -{ - // Gets dimension - const size_t dim_d = ar.extent(1); - const int n_samples = ar.extent(0); - // Compare the dimensionality from the base trainer/machine with the one - // of the enrollment samples - if (plda_machine.getDimD() != dim_d) { - boost::format m("the extent of the D dimension of the input machine (%u) does not match the input sample (%u)"); - m % plda_machine.getDimD() % dim_d; - throw std::runtime_error(m.str()); - } - const size_t dim_f = plda_machine.getDimF(); - - // Resize working arrays - m_tmp_D_1.resize(dim_d); - m_tmp_D_2.resize(dim_d); - m_tmp_nf_1.resize(dim_f); - - // Useful values from the base machine - blitz::Array<double,1>& weighted_sum = plda_machine.updateWeightedSum(); - const blitz::Array<double,1>& mu = plda_machine.getPLDABase()->getMu(); - const blitz::Array<double,2>& beta = plda_machine.getPLDABase()->getBeta(); - const blitz::Array<double,2>& FtBeta = plda_machine.getPLDABase()->getFtBeta(); - - // Updates the PLDA machine - plda_machine.setNSamples(n_samples); - double terma = 0.; - weighted_sum = 0.; - blitz::Range a = blitz::Range::all(); - for (int i=0; i<n_samples; ++i) { - m_tmp_D_1 = ar(i,a) - mu; - // a/ weighted sum - bob::math::prod(FtBeta, m_tmp_D_1, m_tmp_nf_1); - weighted_sum += m_tmp_nf_1; - // b/ first xi dependent term of the log likelihood - bob::math::prod(beta, m_tmp_D_1, m_tmp_D_2); - terma += -1 / 2. * blitz::sum(m_tmp_D_1 * m_tmp_D_2); - } - plda_machine.setWSumXitBetaXi(terma); - - // Adds the precomputed values for the cases N and N+1 if not already - // in the base machine (used by the forward function, 1 already added) - plda_machine.getAddGamma(n_samples); - plda_machine.getAddLogLikeConstTerm(n_samples); - plda_machine.getAddGamma(n_samples+1); - plda_machine.getAddLogLikeConstTerm(n_samples+1); - plda_machine.setLogLikelihood(plda_machine.computeLogLikelihood( - blitz::Array<double,2>(0,dim_d),true)); -} diff --git a/bob/learn/em/empca_trainer.cpp b/bob/learn/em/empca_trainer.cpp deleted file mode 100644 index 70cbe2037f8adc051c8db0202dd8da6e352bbe53..0000000000000000000000000000000000000000 --- a/bob/learn/em/empca_trainer.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Tue 03 Fev 11:22:00 2015 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static auto EMPCATrainer_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".EMPCATrainer", - "Trains a :py:class:`bob.learn.linear.Machine` using an Expectation-Maximization algorithm on the given dataset [Bishop1999]_ [Roweis1998]_ \n\n" - "Notations used are the ones from [Bishop1999]_\n\n" - "The probabilistic model is given by: :math:`t = Wx + \\mu + \\epsilon`\n\n" - " - :math:`t` is the observed data (dimension :math:`f`)\n" - " - :math:`W` is a projection matrix (dimension :math:`f \\times d`)\n" - " - :math:`x` is the projected data (dimension :math:`d < f`)\n" - " - :math:`\\mu` is the mean of the data (dimension :math:`f`)\n" - " - :math:`\\epsilon` is the noise of the data (dimension :math:`f`) \n" - " - Gaussian with zero-mean and covariance matrix :math:`\\sigma^2 Id`" - -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - - "Creates a EMPCATrainer", - "", - true - ) - .add_prototype("other","") - .add_prototype("","") - - .add_parameter("other", ":py:class:`bob.learn.em.EMPCATrainer`", "A EMPCATrainer object to be copied.") - -); - - -static int PyBobLearnEMEMPCATrainer_init_copy(PyBobLearnEMEMPCATrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = EMPCATrainer_doc.kwlist(1); - PyBobLearnEMEMPCATrainerObject* tt; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMEMPCATrainer_Type, &tt)){ - EMPCATrainer_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::EMPCATrainer(*tt->cxx)); - return 0; -} - - -static int PyBobLearnEMEMPCATrainer_init(PyBobLearnEMEMPCATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - switch (nargs) { - - case 0:{ //default initializer () - self->cxx.reset(new bob::learn::em::EMPCATrainer()); - return 0; - } - case 1:{ - return PyBobLearnEMEMPCATrainer_init_copy(self, args, kwargs); - } - default:{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires 0 or 1 arguments, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - EMPCATrainer_doc.print_usage(); - return -1; - } - } - BOB_CATCH_MEMBER("cannot create EMPCATrainer", -1) - return 0; -} - - -static void PyBobLearnEMEMPCATrainer_delete(PyBobLearnEMEMPCATrainerObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - - -int PyBobLearnEMEMPCATrainer_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMEMPCATrainer_Type)); -} - - -static PyObject* PyBobLearnEMEMPCATrainer_RichCompare(PyBobLearnEMEMPCATrainerObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMEMPCATrainer_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMEMPCATrainerObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare EMPCATrainer objects", 0) -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - - -/***** sigma_2 *****/ -static auto sigma2 = bob::extension::VariableDoc( - "sigma2", - "float", - "The noise sigma2 of the probabilistic model", - "" -); -PyObject* PyBobLearnEMEMPCATrainer_getSigma2(PyBobLearnEMEMPCATrainerObject* self, void*){ - BOB_TRY - return Py_BuildValue("d",self->cxx->getSigma2()); - BOB_CATCH_MEMBER("sigma2 could not be read", 0) -} -int PyBobLearnEMEMPCATrainer_setSigma2(PyBobLearnEMEMPCATrainerObject* self, PyObject* value, void*){ - BOB_TRY - - if(!PyBob_NumberCheck(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a float", Py_TYPE(self)->tp_name, sigma2.name()); - return -1; - } - - self->cxx->setSigma2(PyFloat_AS_DOUBLE(value)); - return 0; - BOB_CATCH_MEMBER("sigma2 could not be set", -1) -} - - -static PyGetSetDef PyBobLearnEMEMPCATrainer_getseters[] = { - { - sigma2.name(), - (getter)PyBobLearnEMEMPCATrainer_getSigma2, - (setter)PyBobLearnEMEMPCATrainer_setSigma2, - sigma2.doc(), - 0 - }, - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - -/*** initialize ***/ -static auto initialize = bob::extension::FunctionDoc( - "initialize", - "", - "", - true -) -.add_prototype("linear_machine, data, [rng]") -.add_parameter("linear_machine", ":py:class:`bob.learn.linear.Machine`", "LinearMachine Object") -.add_parameter("data", "array_like <float, 2D>", "Input data") -.add_parameter("rng", ":py:class:`bob.core.random.mt19937`", "The Mersenne Twister mt19937 random generator used for the initialization of subspaces/arrays before the EM loop."); -static PyObject* PyBobLearnEMEMPCATrainer_initialize(PyBobLearnEMEMPCATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = initialize.kwlist(0); - - PyBobLearnLinearMachineObject* linear_machine = 0; - PyBlitzArrayObject* data = 0; - PyBoostMt19937Object* rng = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&|O!", kwlist, &PyBobLearnLinearMachine_Type, &linear_machine, - &PyBlitzArray_Converter, &data, - &PyBoostMt19937_Type, &rng)) return 0; - auto data_ = make_safe(data); - - if(rng){ - self->cxx->setRng(rng->rng); - } - - - self->cxx->initialize(*linear_machine->cxx, *PyBlitzArrayCxx_AsBlitz<double,2>(data)); - - BOB_CATCH_MEMBER("cannot perform the initialize method", 0) - - Py_RETURN_NONE; -} - - -/*** e_step ***/ -static auto e_step = bob::extension::FunctionDoc( - "e_step", - "", - "", - true -) -.add_prototype("linear_machine,data") -.add_parameter("linear_machine", ":py:class:`bob.learn.linear.Machine`", "LinearMachine Object") -.add_parameter("data", "array_like <float, 2D>", "Input data"); -static PyObject* PyBobLearnEMEMPCATrainer_e_step(PyBobLearnEMEMPCATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = e_step.kwlist(0); - - PyBobLearnLinearMachineObject* linear_machine; - PyBlitzArrayObject* data = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnLinearMachine_Type, &linear_machine, - &PyBlitzArray_Converter, &data)) return 0; - auto data_ = make_safe(data); - - self->cxx->eStep(*linear_machine->cxx, *PyBlitzArrayCxx_AsBlitz<double,2>(data)); - - - BOB_CATCH_MEMBER("cannot perform the e_step method", 0) - - Py_RETURN_NONE; -} - - -/*** m_step ***/ -static auto m_step = bob::extension::FunctionDoc( - "m_step", - "", - 0, - true -) -.add_prototype("linear_machine,data") -.add_parameter("linear_machine", ":py:class:`bob.learn.linear.Machine`", "LinearMachine Object") -.add_parameter("data", "array_like <float, 2D>", "Input data"); -static PyObject* PyBobLearnEMEMPCATrainer_m_step(PyBobLearnEMEMPCATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = m_step.kwlist(0); - - PyBobLearnLinearMachineObject* linear_machine; - PyBlitzArrayObject* data = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnLinearMachine_Type, &linear_machine, - &PyBlitzArray_Converter, &data)) return 0; - auto data_ = make_safe(data); - - self->cxx->mStep(*linear_machine->cxx, *PyBlitzArrayCxx_AsBlitz<double,2>(data)); - - - BOB_CATCH_MEMBER("cannot perform the m_step method", 0) - - Py_RETURN_NONE; -} - - -/*** computeLikelihood ***/ -static auto compute_likelihood = bob::extension::FunctionDoc( - "compute_likelihood", - "", - 0, - true -) -.add_prototype("linear_machine") -.add_parameter("linear_machine", ":py:class:`bob.learn.linear.Machine`", "LinearMachine Object"); -static PyObject* PyBobLearnEMEMPCATrainer_compute_likelihood(PyBobLearnEMEMPCATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = compute_likelihood.kwlist(0); - - PyBobLearnLinearMachineObject* linear_machine; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnLinearMachine_Type, &linear_machine)) return 0; - - double value = self->cxx->computeLikelihood(*linear_machine->cxx); - return Py_BuildValue("d", value); - - BOB_CATCH_MEMBER("cannot perform the computeLikelihood method", 0) -} - - - -static PyMethodDef PyBobLearnEMEMPCATrainer_methods[] = { - { - initialize.name(), - (PyCFunction)PyBobLearnEMEMPCATrainer_initialize, - METH_VARARGS|METH_KEYWORDS, - initialize.doc() - }, - { - e_step.name(), - (PyCFunction)PyBobLearnEMEMPCATrainer_e_step, - METH_VARARGS|METH_KEYWORDS, - e_step.doc() - }, - { - m_step.name(), - (PyCFunction)PyBobLearnEMEMPCATrainer_m_step, - METH_VARARGS|METH_KEYWORDS, - m_step.doc() - }, - { - compute_likelihood.name(), - (PyCFunction)PyBobLearnEMEMPCATrainer_compute_likelihood, - METH_VARARGS|METH_KEYWORDS, - compute_likelihood.doc() - }, - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMEMPCATrainer_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMEMPCATrainer(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMEMPCATrainer_Type.tp_name = EMPCATrainer_doc.name(); - PyBobLearnEMEMPCATrainer_Type.tp_basicsize = sizeof(PyBobLearnEMEMPCATrainerObject); - PyBobLearnEMEMPCATrainer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;//Enable the class inheritance - PyBobLearnEMEMPCATrainer_Type.tp_doc = EMPCATrainer_doc.doc(); - - // set the functions - PyBobLearnEMEMPCATrainer_Type.tp_new = PyType_GenericNew; - PyBobLearnEMEMPCATrainer_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMEMPCATrainer_init); - PyBobLearnEMEMPCATrainer_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMEMPCATrainer_delete); - PyBobLearnEMEMPCATrainer_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMEMPCATrainer_RichCompare); - PyBobLearnEMEMPCATrainer_Type.tp_methods = PyBobLearnEMEMPCATrainer_methods; - PyBobLearnEMEMPCATrainer_Type.tp_getset = PyBobLearnEMEMPCATrainer_getseters; - PyBobLearnEMEMPCATrainer_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMEMPCATrainer_compute_likelihood); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMEMPCATrainer_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMEMPCATrainer_Type); - return PyModule_AddObject(module, "EMPCATrainer", (PyObject*)&PyBobLearnEMEMPCATrainer_Type) >= 0; -} diff --git a/bob/learn/em/gaussian.cpp b/bob/learn/em/gaussian.cpp deleted file mode 100644 index 945da0f93f76bb6546452f781c5ebedd8faddd55..0000000000000000000000000000000000000000 --- a/bob/learn/em/gaussian.cpp +++ /dev/null @@ -1,652 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Fri 21 Nov 10:38:48 2013 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static auto Gaussian_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".Gaussian", - "This class implements a multivariate diagonal Gaussian distribution" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Constructs a new multivariate gaussian object", - "", - true - ) - .add_prototype("n_inputs","") - .add_prototype("other","") - .add_prototype("hdf5","") - .add_prototype("","") - - .add_parameter("n_inputs", "int", "Dimension of the feature vector") - .add_parameter("other", ":py:class:`bob.learn.em.GMMStats`", "A GMMStats object to be copied.") - .add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading") -); - - - -static int PyBobLearnEMGaussian_init_number(PyBobLearnEMGaussianObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = Gaussian_doc.kwlist(0); - int n_inputs=1; - //Parsing the input argments - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &n_inputs)) - return -1; - - if(n_inputs < 0){ - PyErr_Format(PyExc_TypeError, "input argument must be greater than or equal to zero"); - Gaussian_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::Gaussian(n_inputs)); - return 0; -} - -static int PyBobLearnEMGaussian_init_copy(PyBobLearnEMGaussianObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = Gaussian_doc.kwlist(1); - PyBobLearnEMGaussianObject* tt; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMGaussian_Type, &tt)){ - Gaussian_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::Gaussian(*tt->cxx)); - return 0; -} - -static int PyBobLearnEMGaussian_init_hdf5(PyBobLearnEMGaussianObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = Gaussian_doc.kwlist(2); - - PyBobIoHDF5FileObject* config = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBobIoHDF5File_Converter, &config)){ - Gaussian_doc.print_usage(); - return -1; - } - auto config_ = make_safe(config); - - self->cxx.reset(new bob::learn::em::Gaussian(*(config->f))); - - return 0; -} - - -static int PyBobLearnEMGaussian_init(PyBobLearnEMGaussianObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - // get the number of command line arguments - Py_ssize_t nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - if (nargs==0){ - self->cxx.reset(new bob::learn::em::Gaussian()); - return 0; - } - - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - /**If the constructor input is a number**/ - if (PyBob_NumberCheck(arg)) - return PyBobLearnEMGaussian_init_number(self, args, kwargs); - /**If the constructor input is Gaussian object**/ - else if (PyBobLearnEMGaussian_Check(arg)) - return PyBobLearnEMGaussian_init_copy(self, args, kwargs); - /**If the constructor input is a HDF5**/ - else if (PyBobIoHDF5File_Check(arg)) - return PyBobLearnEMGaussian_init_hdf5(self, args, kwargs); - else { - PyErr_Format(PyExc_TypeError, "invalid input argument"); - Gaussian_doc.print_usage(); - return -1; - } - - BOB_CATCH_MEMBER("cannot create Gaussian", -1) - return 0; -} - - - -static void PyBobLearnEMGaussian_delete(PyBobLearnEMGaussianObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* PyBobLearnEMGaussian_RichCompare(PyBobLearnEMGaussianObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMGaussian_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMGaussianObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare Gaussian objects", 0) -} - -int PyBobLearnEMGaussian_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMGaussian_Type)); -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** MEAN *****/ -static auto mean = bob::extension::VariableDoc( - "mean", - "array_like <float, 1D>", - "Mean of the Gaussian", - "" -); -PyObject* PyBobLearnEMGaussian_getMean(PyBobLearnEMGaussianObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getMean()); - BOB_CATCH_MEMBER("mean could not be read", 0) -} -int PyBobLearnEMGaussian_setMean(PyBobLearnEMGaussianObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, mean.name()); - return -1; - } - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, mean.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, mean.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0], mean.name()); - return -1; - } - - auto o_ = make_safe(input); - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "mean"); - if (!b) return -1; - self->cxx->setMean(*b); - return 0; - BOB_CATCH_MEMBER("mean could not be set", -1) -} - -/***** Variance *****/ -static auto variance = bob::extension::VariableDoc( - "variance", - "array_like <float, 1D>", - "Variance of the Gaussian", - "" -); -PyObject* PyBobLearnEMGaussian_getVariance(PyBobLearnEMGaussianObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getVariance()); - BOB_CATCH_MEMBER("variance could not be read", 0) -} -int PyBobLearnEMGaussian_setVariance(PyBobLearnEMGaussianObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, variance.name()); - return -1; - } - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, variance.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, variance.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0], variance.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "variance"); - if (!b) return -1; - self->cxx->setVariance(*b); - return 0; - BOB_CATCH_MEMBER("variance could not be set", -1) -} - - -/***** variance_thresholds *****/ -static auto variance_thresholds = bob::extension::VariableDoc( - "variance_thresholds", - "array_like <float, 1D>", - "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." -); -PyObject* PyBobLearnEMGaussian_getVarianceThresholds(PyBobLearnEMGaussianObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getVarianceThresholds()); - BOB_CATCH_MEMBER("variance_thresholds could not be read", 0) -} -int PyBobLearnEMGaussian_setVarianceThresholds(PyBobLearnEMGaussianObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, variance_thresholds.name()); - return -1; - } - - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, variance_thresholds.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, variance_thresholds.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0], variance_thresholds.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "variance_thresholds"); - if (!b) return -1; - self->cxx->setVarianceThresholds(*b); - return 0; - BOB_CATCH_MEMBER("variance_thresholds could not be set", -1) -} - - -/***** shape *****/ -static auto shape = bob::extension::VariableDoc( - "shape", - "(int)", - "A tuple that represents the dimensionality of the Gaussian ``(dim,)``.", - "" -); -PyObject* PyBobLearnEMGaussian_getShape(PyBobLearnEMGaussianObject* self, void*) { - BOB_TRY - return Py_BuildValue("(i)", self->cxx->getNInputs()); - BOB_CATCH_MEMBER("shape could not be read", 0) -} - -static PyGetSetDef PyBobLearnEMGaussian_getseters[] = { - { - mean.name(), - (getter)PyBobLearnEMGaussian_getMean, - (setter)PyBobLearnEMGaussian_setMean, - mean.doc(), - 0 - }, - { - variance.name(), - (getter)PyBobLearnEMGaussian_getVariance, - (setter)PyBobLearnEMGaussian_setVariance, - variance.doc(), - 0 - }, - { - variance_thresholds.name(), - (getter)PyBobLearnEMGaussian_getVarianceThresholds, - (setter)PyBobLearnEMGaussian_setVarianceThresholds, - variance_thresholds.doc(), - 0 - }, - { - shape.name(), - (getter)PyBobLearnEMGaussian_getShape, - 0, - shape.doc(), - 0 - }, - - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - -/*** resize ***/ -static auto resize = bob::extension::FunctionDoc( - "resize", - "Set the input dimensionality, reset the mean to zero and the variance to one." -) -.add_prototype("input") -.add_parameter("input", "int", "Dimensionality of the feature vector"); -static PyObject* PyBobLearnEMGaussian_resize(PyBobLearnEMGaussianObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = resize.kwlist(0); - - int input = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &input)) return 0; - if (input <= 0){ - PyErr_Format(PyExc_TypeError, "input must be greater than zero"); - resize.print_usage(); - return 0; - } - self->cxx->setNInputs(input); - - BOB_CATCH_MEMBER("cannot perform the resize method", 0) - - Py_RETURN_NONE; -} - -/*** log_likelihood ***/ -static auto log_likelihood = bob::extension::FunctionDoc( - "log_likelihood", - "Output the log likelihood of the sample, x. The input size is checked.", - ".. note:: The ``__call__`` function is an alias for this.", - true -) -.add_prototype("input","output") -.add_parameter("input", "array_like <float, 1D>", "Input vector") -.add_return("output","float","The log likelihood"); -static PyObject* PyBobLearnEMGaussian_loglikelihood(PyBobLearnEMGaussianObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = log_likelihood.kwlist(0); - - PyBlitzArrayObject* input = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBlitzArray_Converter, &input)) return 0; - //protects acquired resources through this scope - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `input`", Py_TYPE(self)->tp_name); - log_likelihood.print_usage(); - return 0; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64", Py_TYPE(self)->tp_name); - log_likelihood.print_usage(); - return 0; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0]); - log_likelihood.print_usage(); - return 0; - } - - double value = self->cxx->logLikelihood(*PyBlitzArrayCxx_AsBlitz<double,1>(input)); - return Py_BuildValue("d", value); - - BOB_CATCH_MEMBER("cannot compute the likelihood", 0) -} - - -/*** log_likelihood_ ***/ -static auto log_likelihood_ = bob::extension::FunctionDoc( - "log_likelihood_", - "Output the log likelihood given a sample. The input size is NOT checked." -) -.add_prototype("input","output") -.add_parameter("input", "array_like <float, 1D>", "Input vector") -.add_return("output","float","The log likelihood"); -static PyObject* PyBobLearnEMGaussian_loglikelihood_(PyBobLearnEMGaussianObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - char** kwlist = log_likelihood_.kwlist(0); - - PyBlitzArrayObject* input = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBlitzArray_Converter, &input)) return 0; - //protects acquired resources through this scope - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `input`", Py_TYPE(self)->tp_name); - log_likelihood.print_usage(); - return 0; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64", Py_TYPE(self)->tp_name); - log_likelihood.print_usage(); - return 0; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0]); - log_likelihood.print_usage(); - return 0; - } - - double value = self->cxx->logLikelihood_(*PyBlitzArrayCxx_AsBlitz<double,1>(input)); - return Py_BuildValue("d", value); - - BOB_CATCH_MEMBER("cannot compute the likelihood", 0) -} - - -/*** save ***/ -static auto save = bob::extension::FunctionDoc( - "save", - "Save the configuration of the Gassian Machine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for writing"); -static PyObject* PyBobLearnEMGaussian_Save(PyBobLearnEMGaussianObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get list of arguments - char** kwlist = save.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - - self->cxx->save(*hdf5->f); - - BOB_CATCH_MEMBER("cannot save the data", 0) - Py_RETURN_NONE; -} - -/*** load ***/ -static auto load = bob::extension::FunctionDoc( - "load", - "Load the configuration of the Gassian Machine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading"); -static PyObject* PyBobLearnEMGaussian_Load(PyBobLearnEMGaussianObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - char** kwlist = load.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->load(*hdf5->f); - - BOB_CATCH_MEMBER("cannot load the data", 0) - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this Gaussian with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` and any other values internal to this machine.", - true -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.Gaussian`", "A gaussian to be compared.") -.add_parameter("[r_epsilon]", "float", "Relative precision.") -.add_parameter("[a_epsilon]", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMGaussian_IsSimilarTo(PyBobLearnEMGaussianObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - PyBobLearnEMGaussianObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMGaussian_Type, &other, - &r_epsilon, &a_epsilon)) return 0; - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - -/*** set_variance_thresholds ***/ -static auto set_variance_thresholds = bob::extension::FunctionDoc( - "set_variance_thresholds", - "Set the variance flooring thresholds equal to the given threshold for all the dimensions." -) -.add_prototype("input") -.add_parameter("input","float","Threshold") -; -static PyObject* PyBobLearnEMGaussian_SetVarianceThresholds(PyBobLearnEMGaussianObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = set_variance_thresholds.kwlist(0); - - double input = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d", kwlist, &input)) return 0; - - self->cxx->setVarianceThresholds(input); - - BOB_CATCH_MEMBER("cannot perform the set_variance_Thresholds method", 0) - - Py_RETURN_NONE; -} - - -static PyMethodDef PyBobLearnEMGaussian_methods[] = { - { - resize.name(), - (PyCFunction)PyBobLearnEMGaussian_resize, - METH_VARARGS|METH_KEYWORDS, - resize.doc() - }, - { - log_likelihood.name(), - (PyCFunction)PyBobLearnEMGaussian_loglikelihood, - METH_VARARGS|METH_KEYWORDS, - log_likelihood.doc() - }, - { - log_likelihood_.name(), - (PyCFunction)PyBobLearnEMGaussian_loglikelihood_, - METH_VARARGS|METH_KEYWORDS, - log_likelihood_.doc() - }, - { - save.name(), - (PyCFunction)PyBobLearnEMGaussian_Save, - METH_VARARGS|METH_KEYWORDS, - save.doc() - }, - { - load.name(), - (PyCFunction)PyBobLearnEMGaussian_Load, - METH_VARARGS|METH_KEYWORDS, - load.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMGaussian_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - { - set_variance_thresholds.name(), - (PyCFunction)PyBobLearnEMGaussian_SetVarianceThresholds, - METH_VARARGS|METH_KEYWORDS, - set_variance_thresholds.doc() - }, - - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMGaussian_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMGaussian(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMGaussian_Type.tp_name = Gaussian_doc.name(); - PyBobLearnEMGaussian_Type.tp_basicsize = sizeof(PyBobLearnEMGaussianObject); - PyBobLearnEMGaussian_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyBobLearnEMGaussian_Type.tp_doc = Gaussian_doc.doc(); - - // set the functions - PyBobLearnEMGaussian_Type.tp_new = PyType_GenericNew; - PyBobLearnEMGaussian_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMGaussian_init); - PyBobLearnEMGaussian_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMGaussian_delete); - PyBobLearnEMGaussian_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMGaussian_RichCompare); - PyBobLearnEMGaussian_Type.tp_methods = PyBobLearnEMGaussian_methods; - PyBobLearnEMGaussian_Type.tp_getset = PyBobLearnEMGaussian_getseters; - PyBobLearnEMGaussian_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMGaussian_loglikelihood); - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMGaussian_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMGaussian_Type); - return PyModule_AddObject(module, "Gaussian", (PyObject*)&PyBobLearnEMGaussian_Type) >= 0; -} - diff --git a/bob/learn/em/gmm_machine.cpp b/bob/learn/em/gmm_machine.cpp deleted file mode 100644 index 429c3097d9471ddfbf9d26b043d23e3407062aaf..0000000000000000000000000000000000000000 --- a/bob/learn/em/gmm_machine.cpp +++ /dev/null @@ -1,988 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Wed 11 Dec 18:01:00 2014 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static auto GMMMachine_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".GMMMachine", - "This class implements the statistical model for multivariate diagonal mixture Gaussian distribution (GMM). " - "A GMM is defined as :math:`\\sum_{c=0}^{C} \\omega_c \\mathcal{N}(x | \\mu_c, \\sigma_c)`, where :math:`C` is the number of Gaussian components :math:`\\mu_c`, :math:`\\sigma_c` and :math:`\\omega_c` are respectively the the mean, variance and the weight of each gaussian component :math:`c`.", - "See Section 2.3.9 of Bishop, \"Pattern recognition and machine learning\", 2006" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Creates a GMMMachine", - "", - true - ) - .add_prototype("n_gaussians,n_inputs","") - .add_prototype("other","") - .add_prototype("hdf5","") - .add_prototype("","") - - .add_parameter("n_gaussians", "int", "Number of gaussians") - .add_parameter("n_inputs", "int", "Dimension of the feature vector") - .add_parameter("other", ":py:class:`bob.learn.em.GMMMachine`", "A GMMMachine object to be copied.") - .add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading") - -); - - -static int PyBobLearnEMGMMMachine_init_number(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = GMMMachine_doc.kwlist(0); - int n_inputs = 1; - int n_gaussians = 1; - //Parsing the input argments - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &n_gaussians, &n_inputs)) - return -1; - - if(n_gaussians < 0){ - PyErr_Format(PyExc_TypeError, "gaussians argument must be greater than or equal to zero"); - return -1; - } - - if(n_inputs < 0){ - PyErr_Format(PyExc_TypeError, "input argument must be greater than or equal to zero"); - return -1; - } - - self->cxx.reset(new bob::learn::em::GMMMachine(n_gaussians, n_inputs)); - return 0; -} - - -static int PyBobLearnEMGMMMachine_init_copy(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = GMMMachine_doc.kwlist(1); - PyBobLearnEMGMMMachineObject* tt; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMGMMMachine_Type, &tt)){ - GMMMachine_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::GMMMachine(*tt->cxx)); - return 0; -} - - -static int PyBobLearnEMGMMMachine_init_hdf5(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = GMMMachine_doc.kwlist(2); - - PyBobIoHDF5FileObject* config = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBobIoHDF5File_Converter, &config)){ - GMMMachine_doc.print_usage(); - return -1; - } - auto config_ = make_safe(config); - - self->cxx.reset(new bob::learn::em::GMMMachine(*(config->f))); - - return 0; -} - - - -static int PyBobLearnEMGMMMachine_init(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - switch (nargs) { - - case 0: //default initializer () - self->cxx.reset(new bob::learn::em::GMMMachine()); - return 0; - - case 1:{ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is Gaussian object - if (PyBobLearnEMGMMMachine_Check(arg)) - return PyBobLearnEMGMMMachine_init_copy(self, args, kwargs); - // If the constructor input is a HDF5 - else if (PyBobIoHDF5File_Check(arg)) - return PyBobLearnEMGMMMachine_init_hdf5(self, args, kwargs); - } - case 2: - return PyBobLearnEMGMMMachine_init_number(self, args, kwargs); - default: - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires 0, 1 or 2 arguments, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - GMMMachine_doc.print_usage(); - return -1; - } - BOB_CATCH_MEMBER("cannot create GMMMachine", -1) - return 0; -} - - - -static void PyBobLearnEMGMMMachine_delete(PyBobLearnEMGMMMachineObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* PyBobLearnEMGMMMachine_RichCompare(PyBobLearnEMGMMMachineObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMGMMMachine_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMGMMMachineObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare GMMMachine objects", 0) -} - -int PyBobLearnEMGMMMachine_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMGMMMachine_Type)); -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** shape *****/ -static auto shape = bob::extension::VariableDoc( - "shape", - "(int,int)", - "A tuple that represents the number of gaussians and dimensionality of each Gaussian ``(n_gaussians, dim)``.", - "" -); -PyObject* PyBobLearnEMGMMMachine_getShape(PyBobLearnEMGMMMachineObject* self, void*) { - BOB_TRY - return Py_BuildValue("(i,i)", self->cxx->getNGaussians(), self->cxx->getNInputs()); - BOB_CATCH_MEMBER("shape could not be read", 0) -} - -/***** MEAN *****/ - -static auto means = bob::extension::VariableDoc( - "means", - "array_like <float, 2D>", - "The means of the gaussians", - "" -); -PyObject* PyBobLearnEMGMMMachine_getMeans(PyBobLearnEMGMMMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getMeans()); - BOB_CATCH_MEMBER("means could not be read", 0) -} -int PyBobLearnEMGMMMachine_setMeans(PyBobLearnEMGMMMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, means.name()); - return -1; - } - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, means.name()); - return -1; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, means.name()); - return -1; - } - - if (input->shape[1] != (Py_ssize_t)self->cxx->getNInputs() && input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNGaussians(), self->cxx->getNInputs(), input->shape[1], input->shape[0], means.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "means"); - if (!b) return -1; - self->cxx->setMeans(*b); - return 0; - BOB_CATCH_MEMBER("means could not be set", -1) -} - -/***** Variance *****/ -static auto variances = bob::extension::VariableDoc( - "variances", - "array_like <float, 2D>", - "Variances of the gaussians", - "" -); -PyObject* PyBobLearnEMGMMMachine_getVariances(PyBobLearnEMGMMMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getVariances()); - BOB_CATCH_MEMBER("variances could not be read", 0) -} -int PyBobLearnEMGMMMachine_setVariances(PyBobLearnEMGMMMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, variances.name()); - return -1; - } - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, variances.name()); - return -1; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, variances.name()); - return -1; - } - - if (input->shape[1] != (Py_ssize_t)self->cxx->getNInputs() && input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNGaussians(), self->cxx->getNInputs(), input->shape[1], input->shape[0], variances.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "variances"); - if (!b) return -1; - self->cxx->setVariances(*b); - return 0; - BOB_CATCH_MEMBER("variances could not be set", -1) -} - -/***** Weights *****/ -static auto weights = bob::extension::VariableDoc( - "weights", - "array_like <float, 1D>", - "The weights (also known as \"mixing coefficients\")", - "" -); -PyObject* PyBobLearnEMGMMMachine_getWeights(PyBobLearnEMGMMMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getWeights()); - BOB_CATCH_MEMBER("weights could not be read", 0) -} -int PyBobLearnEMGMMMachine_setWeights(PyBobLearnEMGMMMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, weights.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, weights.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, weights.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNGaussians(), input->shape[0], weights.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "weights"); - if (!b) return -1; - self->cxx->setWeights(*b); - return 0; - BOB_CATCH_MEMBER("weights could not be set", -1) -} - - -/***** variance_supervector *****/ -static auto variance_supervector = bob::extension::VariableDoc( - "variance_supervector", - "array_like <float, 1D>", - "The variance supervector of the GMMMachine", - "Concatenation of the variance vectors of each Gaussian of the GMMMachine" -); -PyObject* PyBobLearnEMGMMMachine_getVarianceSupervector(PyBobLearnEMGMMMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getVarianceSupervector()); - BOB_CATCH_MEMBER("variance_supervector could not be read", 0) -} -int PyBobLearnEMGMMMachine_setVarianceSupervector(PyBobLearnEMGMMMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, variance_supervector.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, variance_supervector.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, variance_supervector.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs(), input->shape[0], variance_supervector.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "variance_supervector"); - if (!b) return -1; - self->cxx->setVarianceSupervector(*b); - return 0; - BOB_CATCH_MEMBER("variance_supervector could not be set", -1) -} - -/***** mean_supervector *****/ -static auto mean_supervector = bob::extension::VariableDoc( - "mean_supervector", - "array_like <float, 1D>", - "The mean supervector of the GMMMachine", - "Concatenation of the mean vectors of each Gaussian of the GMMMachine" -); -PyObject* PyBobLearnEMGMMMachine_getMeanSupervector(PyBobLearnEMGMMMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getMeanSupervector()); - BOB_CATCH_MEMBER("mean_supervector could not be read", 0) -} -int PyBobLearnEMGMMMachine_setMeanSupervector(PyBobLearnEMGMMMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, mean_supervector.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, mean_supervector.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, mean_supervector.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs(), input->shape[0], mean_supervector.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "mean_supervector"); - if (!b) return -1; - self->cxx->setMeanSupervector(*b); - return 0; - BOB_CATCH_MEMBER("mean_supervector could not be set", -1) -} - - - -/***** variance_thresholds *****/ -static auto variance_thresholds = bob::extension::VariableDoc( - "variance_thresholds", - "array_like <float, 2D>", - "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. ", - "" -); -PyObject* PyBobLearnEMGMMMachine_getVarianceThresholds(PyBobLearnEMGMMMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getVarianceThresholds()); - BOB_CATCH_MEMBER("variance_thresholds could not be read", 0) -} -int PyBobLearnEMGMMMachine_setVarianceThresholds(PyBobLearnEMGMMMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, variance_thresholds.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, variance_thresholds.name()); - return -1; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, variance_thresholds.name()); - return -1; - } - - if (input->shape[1] != (Py_ssize_t)self->cxx->getNInputs() && input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNGaussians(), self->cxx->getNInputs(), input->shape[1], input->shape[0], variance_thresholds.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "variance_thresholds"); - if (!b) return -1; - self->cxx->setVarianceThresholds(*b); - return 0; - BOB_CATCH_MEMBER("variance_thresholds could not be set", -1) -} - - - - -static PyGetSetDef PyBobLearnEMGMMMachine_getseters[] = { - { - shape.name(), - (getter)PyBobLearnEMGMMMachine_getShape, - 0, - shape.doc(), - 0 - }, - { - means.name(), - (getter)PyBobLearnEMGMMMachine_getMeans, - (setter)PyBobLearnEMGMMMachine_setMeans, - means.doc(), - 0 - }, - { - variances.name(), - (getter)PyBobLearnEMGMMMachine_getVariances, - (setter)PyBobLearnEMGMMMachine_setVariances, - variances.doc(), - 0 - }, - { - weights.name(), - (getter)PyBobLearnEMGMMMachine_getWeights, - (setter)PyBobLearnEMGMMMachine_setWeights, - weights.doc(), - 0 - }, - { - variance_thresholds.name(), - (getter)PyBobLearnEMGMMMachine_getVarianceThresholds, - (setter)PyBobLearnEMGMMMachine_setVarianceThresholds, - variance_thresholds.doc(), - 0 - }, - { - variance_supervector.name(), - (getter)PyBobLearnEMGMMMachine_getVarianceSupervector, - (setter)PyBobLearnEMGMMMachine_setVarianceSupervector, - variance_supervector.doc(), - 0 - }, - - { - mean_supervector.name(), - (getter)PyBobLearnEMGMMMachine_getMeanSupervector, - (setter)PyBobLearnEMGMMMachine_setMeanSupervector, - mean_supervector.doc(), - 0 - }, - - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - - -/*** save ***/ -static auto save = bob::extension::FunctionDoc( - "save", - "Save the configuration of the GMMMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for writing"); -static PyObject* PyBobLearnEMGMMMachine_Save(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - // get list of arguments - char** kwlist = save.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->save(*hdf5->f); - - BOB_CATCH_MEMBER("cannot save the data", 0) - Py_RETURN_NONE; -} - -/*** load ***/ -static auto load = bob::extension::FunctionDoc( - "load", - "Load the configuration of the GMMMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading"); -static PyObject* PyBobLearnEMGMMMachine_Load(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = load.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->load(*hdf5->f); - - BOB_CATCH_MEMBER("cannot load the data", 0) - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this GMMMachine with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` " - "and any other values internal to this machine." -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.GMMMachine`", "A GMMMachine object to be compared.") -.add_parameter("r_epsilon", "float", "Relative precision.") -.add_parameter("a_epsilon", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMGMMMachine_IsSimilarTo(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - //PyObject* other = 0; - PyBobLearnEMGMMMachineObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMGMMMachine_Type, &other, - &r_epsilon, &a_epsilon)){ - - is_similar_to.print_usage(); - return 0; - } - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - -/*** resize ***/ -static auto resize = bob::extension::FunctionDoc( - "resize", - "Allocates space for the statistics and resets to zero.", - 0, - true -) -.add_prototype("n_gaussians,n_inputs") -.add_parameter("n_gaussians", "int", "Number of gaussians") -.add_parameter("n_inputs", "int", "Dimensionality of the feature vector"); -static PyObject* PyBobLearnEMGMMMachine_resize(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = resize.kwlist(0); - - int n_gaussians = 0; - int n_inputs = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &n_gaussians, &n_inputs)) Py_RETURN_NONE; - - if (n_gaussians <= 0){ - PyErr_Format(PyExc_TypeError, "n_gaussians must be greater than zero"); - resize.print_usage(); - return 0; - } - if (n_inputs <= 0){ - PyErr_Format(PyExc_TypeError, "n_inputs must be greater than zero"); - resize.print_usage(); - return 0; - } - - self->cxx->resize(n_gaussians, n_inputs); - - BOB_CATCH_MEMBER("cannot perform the resize method", 0) - - Py_RETURN_NONE; -} - - -/*** log_likelihood ***/ -static auto log_likelihood = bob::extension::FunctionDoc( - "log_likelihood", - "Output the log likelihood of the sample, x, i.e. :math:`log(p(x|GMM))`. Inputs are checked.", - ".. note:: The ``__call__`` function is an alias for this. \n " - "If `input` is 2D the average along the samples will be computed (:math:`\\frac{log(p(x|GMM))}{N}`) ", - true -) -.add_prototype("input","output") -.add_parameter("input", "array_like <float, 1D>", "Input vector") -.add_return("output","float","The log likelihood"); -static PyObject* PyBobLearnEMGMMMachine_loglikelihood(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = log_likelihood.kwlist(0); - - PyBlitzArrayObject* input = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBlitzArray_Converter, &input)) return 0; - //protects acquired resources through this scope - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `input`", Py_TYPE(self)->tp_name); - log_likelihood.print_usage(); - return 0; - } - - if (input->ndim > 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D or 2D arrays of float64", Py_TYPE(self)->tp_name); - log_likelihood.print_usage(); - return 0; - } - - int shape_index = input->ndim - 1; //Getting the index of the dimensionality (0 for 1D arrays, 1 for 2D arrays) - - if (input->shape[shape_index] != (Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0]); - log_likelihood.print_usage(); - return 0; - } - - double value = 0; - if (input->ndim == 1) - value = self->cxx->logLikelihood(*PyBlitzArrayCxx_AsBlitz<double,1>(input)); - else - value = self->cxx->logLikelihood(*PyBlitzArrayCxx_AsBlitz<double,2>(input)); - - - return Py_BuildValue("d", value); - BOB_CATCH_MEMBER("cannot compute the likelihood", 0) -} - - -/*** log_likelihood_ ***/ -static auto log_likelihood_ = bob::extension::FunctionDoc( - "log_likelihood_", - "Output the log likelihood of the sample, x, i.e. :math:`log(p(x|GMM))`. Inputs are NOT checked.", - "", - true -) -.add_prototype("input","output") -.add_parameter("input", "array_like <float, 1D>", "Input vector") -.add_return("output","float","The log likelihood"); -static PyObject* PyBobLearnEMGMMMachine_loglikelihood_(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = log_likelihood_.kwlist(0); - - PyBlitzArrayObject* input = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBlitzArray_Converter, &input)) return 0; - //protects acquired resources through this scope - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `input`", Py_TYPE(self)->tp_name); - log_likelihood.print_usage(); - return 0; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64", Py_TYPE(self)->tp_name); - log_likelihood.print_usage(); - return 0; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0]); - log_likelihood.print_usage(); - return 0; - } - - double value = self->cxx->logLikelihood_(*PyBlitzArrayCxx_AsBlitz<double,1>(input)); - return Py_BuildValue("d", value); - - BOB_CATCH_MEMBER("cannot compute the likelihood", 0) -} - - -/*** acc_statistics ***/ -static auto acc_statistics = bob::extension::FunctionDoc( - "acc_statistics", - "Accumulate the GMM statistics (:py:class:`bob.learn.em.GMMStats`) for this sample(s). Inputs are checked.", - "", - true -) -.add_prototype("input,stats") -.add_parameter("input", "array_like <float, 2D>", "Input vector") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics of the GMM"); -static PyObject* PyBobLearnEMGMMMachine_accStatistics(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = acc_statistics.kwlist(0); - - PyBlitzArrayObject* input = 0; - PyBobLearnEMGMMStatsObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!", kwlist, &PyBlitzArray_Converter,&input, - &PyBobLearnEMGMMStats_Type, &stats)) - return 0; - - //protects acquired resources through this scope - auto input_ = make_safe(input); - - if (input->ndim == 1) - self->cxx->accStatistics(*PyBlitzArrayCxx_AsBlitz<double,1>(input), *stats->cxx); - else - self->cxx->accStatistics(*PyBlitzArrayCxx_AsBlitz<double,2>(input), *stats->cxx); - - - BOB_CATCH_MEMBER("cannot accumulate the statistics", 0) - Py_RETURN_NONE; -} - - -/*** acc_statistics_ ***/ -static auto acc_statistics_ = bob::extension::FunctionDoc( - "acc_statistics_", - "Accumulate the GMM statistics (:py:class:`bob.learn.em.GMMStats`) for this sample(s). Inputs are NOT checked.", - "", - true -) -.add_prototype("input,stats") -.add_parameter("input", "array_like <float, 2D>", "Input vector") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics of the GMM"); -static PyObject* PyBobLearnEMGMMMachine_accStatistics_(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = acc_statistics_.kwlist(0); - - PyBlitzArrayObject* input = 0; - PyBobLearnEMGMMStatsObject* stats = 0; - - if(!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!", kwlist, &PyBlitzArray_Converter,&input, - &PyBobLearnEMGMMStats_Type, &stats)) - return 0; - - //protects acquired resources through this scope - auto input_ = make_safe(input); - - if (input->ndim==1) - self->cxx->accStatistics_(*PyBlitzArrayCxx_AsBlitz<double,1>(input), *stats->cxx); - else - self->cxx->accStatistics_(*PyBlitzArrayCxx_AsBlitz<double,2>(input), *stats->cxx); - - BOB_CATCH_MEMBER("cannot accumulate the statistics", 0) - Py_RETURN_NONE; -} - - - -/*** set_variance_thresholds ***/ -static auto set_variance_thresholds = bob::extension::FunctionDoc( - "set_variance_thresholds", - "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.", - "", - true -) -.add_prototype("input") -.add_parameter("input", "float or array_like <float, 1D>", "The new variance threshold, or a vector of thresholds for all Gaussian components"); -static PyObject* PyBobLearnEMGMMMachine_setVarianceThresholds_method(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = set_variance_thresholds.kwlist(0); - - PyBlitzArrayObject* input_array = 0; - double input_number = 0; - if(PyArg_ParseTupleAndKeywords(args, kwargs, "d", kwlist, &input_number)){ - self->cxx->setVarianceThresholds(input_number); - } - else if(PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBlitzArray_Converter, &input_array)) { - //protects acquired resources through this scope - auto input_ = make_safe(input_array); - self->cxx->setVarianceThresholds(*PyBlitzArrayCxx_AsBlitz<double,1>(input_array)); - } - else - return 0; - - // clear any error that might have been set in the functions above - PyErr_Clear(); - - BOB_CATCH_MEMBER("cannot accumulate set the variance threshold", 0) - Py_RETURN_NONE; -} - - - - -/*** get_gaussian ***/ -static auto get_gaussian = bob::extension::FunctionDoc( - "get_gaussian", - "Get the specified Gaussian (:py:class:`bob.learn.em.Gaussian`) component.", - ".. note:: An exception is thrown if i is out of range.", - true -) -.add_prototype("i","gaussian") -.add_parameter("i", "int", "Index of the gaussian") -.add_return("gaussian",":py:class:`bob.learn.em.Gaussian`","Gaussian object"); -static PyObject* PyBobLearnEMGMMMachine_get_gaussian(PyBobLearnEMGMMMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_gaussian.kwlist(0); - - int i = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - //Allocating the correspondent python object - PyBobLearnEMGaussianObject* retval = - (PyBobLearnEMGaussianObject*)PyBobLearnEMGaussian_Type.tp_alloc(&PyBobLearnEMGaussian_Type, 0); - - retval->cxx = self->cxx->getGaussian(i); - - return Py_BuildValue("N",retval); - - BOB_CATCH_MEMBER("cannot compute the likelihood", 0) -} - - - -static PyMethodDef PyBobLearnEMGMMMachine_methods[] = { - { - save.name(), - (PyCFunction)PyBobLearnEMGMMMachine_Save, - METH_VARARGS|METH_KEYWORDS, - save.doc() - }, - { - load.name(), - (PyCFunction)PyBobLearnEMGMMMachine_Load, - METH_VARARGS|METH_KEYWORDS, - load.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMGMMMachine_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - { - resize.name(), - (PyCFunction)PyBobLearnEMGMMMachine_resize, - METH_VARARGS|METH_KEYWORDS, - resize.doc() - }, - { - log_likelihood.name(), - (PyCFunction)PyBobLearnEMGMMMachine_loglikelihood, - METH_VARARGS|METH_KEYWORDS, - log_likelihood.doc() - }, - { - log_likelihood_.name(), - (PyCFunction)PyBobLearnEMGMMMachine_loglikelihood_, - METH_VARARGS|METH_KEYWORDS, - log_likelihood_.doc() - }, - { - acc_statistics.name(), - (PyCFunction)PyBobLearnEMGMMMachine_accStatistics, - METH_VARARGS|METH_KEYWORDS, - acc_statistics.doc() - }, - { - acc_statistics_.name(), - (PyCFunction)PyBobLearnEMGMMMachine_accStatistics_, - METH_VARARGS|METH_KEYWORDS, - acc_statistics_.doc() - }, - - { - get_gaussian.name(), - (PyCFunction)PyBobLearnEMGMMMachine_get_gaussian, - METH_VARARGS|METH_KEYWORDS, - get_gaussian.doc() - }, - - { - set_variance_thresholds.name(), - (PyCFunction)PyBobLearnEMGMMMachine_setVarianceThresholds_method, - METH_VARARGS|METH_KEYWORDS, - set_variance_thresholds.doc() - }, - - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMGMMMachine_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMGMMMachine(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMGMMMachine_Type.tp_name = GMMMachine_doc.name(); - PyBobLearnEMGMMMachine_Type.tp_basicsize = sizeof(PyBobLearnEMGMMMachineObject); - PyBobLearnEMGMMMachine_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyBobLearnEMGMMMachine_Type.tp_doc = GMMMachine_doc.doc(); - - // set the functions - PyBobLearnEMGMMMachine_Type.tp_new = PyType_GenericNew; - PyBobLearnEMGMMMachine_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMGMMMachine_init); - PyBobLearnEMGMMMachine_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMGMMMachine_delete); - PyBobLearnEMGMMMachine_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMGMMMachine_RichCompare); - PyBobLearnEMGMMMachine_Type.tp_methods = PyBobLearnEMGMMMachine_methods; - PyBobLearnEMGMMMachine_Type.tp_getset = PyBobLearnEMGMMMachine_getseters; - PyBobLearnEMGMMMachine_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMGMMMachine_loglikelihood); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMGMMMachine_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMGMMMachine_Type); - return PyModule_AddObject(module, "GMMMachine", (PyObject*)&PyBobLearnEMGMMMachine_Type) >= 0; -} diff --git a/bob/learn/em/gmm_stats.cpp b/bob/learn/em/gmm_stats.cpp deleted file mode 100644 index 32011ca86aeccf112af86f4a9c3b37abdad5881b..0000000000000000000000000000000000000000 --- a/bob/learn/em/gmm_stats.cpp +++ /dev/null @@ -1,673 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Wed 03 Dec 14:38:48 2014 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static auto GMMStats_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".GMMStats", - "A container for GMM statistics", - "With respect to [Reynolds2000]_ the class computes: \n\n" - "* Eq (8) is :py:class:`bob.learn.em.GMMStats.n`: :math:`n_i=\\sum\\limits_{t=1}^T Pr(i | x_t)`\n\n" - "* Eq (9) is :py:class:`bob.learn.em.GMMStats.sum_px`: :math:`E_i(x)=\\frac{1}{n(i)}\\sum\\limits_{t=1}^T Pr(i | x_t)x_t`\n\n" - "* Eq (10) is :py:class:`bob.learn.em.GMMStats.sum_pxx`: :math:`E_i(x^2)=\\frac{1}{n(i)}\\sum\\limits_{t=1}^T Pr(i | x_t)x_t^2`\n\n" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "A container for GMM statistics.", - "", - true - ) - .add_prototype("n_gaussians,n_inputs","") - .add_prototype("other","") - .add_prototype("hdf5","") - .add_prototype("","") - - .add_parameter("n_gaussians", "int", "Number of gaussians") - .add_parameter("n_inputs", "int", "Dimension of the feature vector") - .add_parameter("other", ":py:class:`bob.learn.em.GMMStats`", "A GMMStats object to be copied.") - .add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading") - -); - - -static int PyBobLearnEMGMMStats_init_number(PyBobLearnEMGMMStatsObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = GMMStats_doc.kwlist(0); - int n_inputs = 1; - int n_gaussians = 1; - //Parsing the input argments - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &n_gaussians, &n_inputs)) - return -1; - - if(n_gaussians < 0){ - PyErr_Format(PyExc_TypeError, "gaussians argument must be greater than or equal to zero"); - GMMStats_doc.print_usage(); - return -1; - } - - if(n_inputs < 0){ - PyErr_Format(PyExc_TypeError, "input argument must be greater than or equal to zero"); - GMMStats_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::GMMStats(n_gaussians, n_inputs)); - return 0; -} - - -static int PyBobLearnEMGMMStats_init_copy(PyBobLearnEMGMMStatsObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = GMMStats_doc.kwlist(1); - PyBobLearnEMGMMStatsObject* tt; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMGMMStats_Type, &tt)){ - GMMStats_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::GMMStats(*tt->cxx)); - return 0; -} - - -static int PyBobLearnEMGMMStats_init_hdf5(PyBobLearnEMGMMStatsObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = GMMStats_doc.kwlist(2); - - PyBobIoHDF5FileObject* config = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBobIoHDF5File_Converter, &config)){ - GMMStats_doc.print_usage(); - return -1; - } - auto config_ = make_safe(config); - self->cxx.reset(new bob::learn::em::GMMStats(*(config->f))); - - return 0; -} - - - -static int PyBobLearnEMGMMStats_init(PyBobLearnEMGMMStatsObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - switch (nargs) { - - case 0: //default initializer () - self->cxx.reset(new bob::learn::em::GMMStats()); - return 0; - - case 1:{ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - /**If the constructor input is Gaussian object**/ - if (PyBobLearnEMGMMStats_Check(arg)) - return PyBobLearnEMGMMStats_init_copy(self, args, kwargs); - /**If the constructor input is a HDF5**/ - else if (PyBobIoHDF5File_Check(arg)) - return PyBobLearnEMGMMStats_init_hdf5(self, args, kwargs); - } - case 2: - return PyBobLearnEMGMMStats_init_number(self, args, kwargs); - default: - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires 0, 1 or 2 arguments, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - GMMStats_doc.print_usage(); - return -1; - } - BOB_CATCH_MEMBER("cannot create GMMStats", -1) - return 0; -} - - - -static void PyBobLearnEMGMMStats_delete(PyBobLearnEMGMMStatsObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* PyBobLearnEMGMMStats_RichCompare(PyBobLearnEMGMMStatsObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMGMMStats_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMGMMStatsObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare GMMStats objects", 0) -} - -int PyBobLearnEMGMMStats_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMGMMStats_Type)); -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** n *****/ -static auto n = bob::extension::VariableDoc( - "n", - "array_like <float, 1D>", - "For each Gaussian, the accumulated sum of responsibilities, i.e. the sum of :math:`P(gaussian_i|x)`" -); -PyObject* PyBobLearnEMGMMStats_getN(PyBobLearnEMGMMStatsObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->n); - BOB_CATCH_MEMBER("n could not be read", 0) -} -int PyBobLearnEMGMMStats_setN(PyBobLearnEMGMMStatsObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, n.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, n.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, n.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->n.extent(0)){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->n.extent(0), input->shape[0], n.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "n"); - if (!b) return -1; - self->cxx->n = *b; - return 0; - BOB_CATCH_MEMBER("n could not be set", -1) -} - - -/***** sum_px *****/ -static auto sum_px = bob::extension::VariableDoc( - "sum_px", - "array_like <float, 2D>", - "For each Gaussian, the accumulated sum of responsibility times the sample" -); -PyObject* PyBobLearnEMGMMStats_getSum_px(PyBobLearnEMGMMStatsObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->sumPx); - BOB_CATCH_MEMBER("sum_px could not be read", 0) -} -int PyBobLearnEMGMMStats_setSum_px(PyBobLearnEMGMMStatsObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, sum_px.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, sum_px.name()); - return -1; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, sum_px.name()); - return -1; - } - - if (input->shape[1] != (Py_ssize_t)self->cxx->sumPx.extent(1) && input->shape[0] != (Py_ssize_t)self->cxx->sumPx.extent(0)) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->sumPx.extent(1), (Py_ssize_t)self->cxx->sumPx.extent(0), (Py_ssize_t)input->shape[1], (Py_ssize_t)input->shape[0], sum_px.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "sum_px"); - if (!b) return -1; - self->cxx->sumPx = *b; - return 0; - BOB_CATCH_MEMBER("sum_px could not be set", -1) -} - - -/***** sum_pxx *****/ -static auto sum_pxx = bob::extension::VariableDoc( - "sum_pxx", - "array_like <float, 2D>", - "For each Gaussian, the accumulated sum of responsibility times the sample squared" -); -PyObject* PyBobLearnEMGMMStats_getSum_pxx(PyBobLearnEMGMMStatsObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->sumPxx); - BOB_CATCH_MEMBER("sum_pxx could not be read", 0) -} -int PyBobLearnEMGMMStats_setSum_pxx(PyBobLearnEMGMMStatsObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, sum_pxx.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, sum_pxx.name()); - return -1; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, sum_pxx.name()); - return -1; - } - - if (input->shape[1] != (Py_ssize_t)self->cxx->sumPxx.extent(1) && input->shape[0] != (Py_ssize_t)self->cxx->sumPxx.extent(0)) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->sumPxx.extent(1), (Py_ssize_t)self->cxx->sumPxx.extent(0), (Py_ssize_t)input->shape[1], (Py_ssize_t)input->shape[0], sum_pxx.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "sum_pxx"); - if (!b) return -1; - self->cxx->sumPxx = *b; - return 0; - BOB_CATCH_MEMBER("sum_pxx could not be set", -1) -} - - -/***** t *****/ -static auto t = bob::extension::VariableDoc( - "t", - "int", - "The number of samples" -); -PyObject* PyBobLearnEMGMMStats_getT(PyBobLearnEMGMMStatsObject* self, void*){ - BOB_TRY - return Py_BuildValue("i", self->cxx->T); - BOB_CATCH_MEMBER("t could not be read", 0) -} -int PyBobLearnEMGMMStats_setT(PyBobLearnEMGMMStatsObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyInt_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects an int", Py_TYPE(self)->tp_name, t.name()); - return -1; - } - - if (PyInt_AS_LONG(value) < 0){ - PyErr_Format(PyExc_TypeError, "t must be greater than or equal to zero"); - return -1; - } - - self->cxx->T = PyInt_AS_LONG(value); - BOB_CATCH_MEMBER("t could not be set", -1) - return 0; -} - - -/***** log_likelihood *****/ -static auto log_likelihood = bob::extension::VariableDoc( - "log_likelihood", - "float", - "The accumulated log likelihood of all samples" -); -PyObject* PyBobLearnEMGMMStats_getLog_likelihood(PyBobLearnEMGMMStatsObject* self, void*){ - BOB_TRY - return Py_BuildValue("d", self->cxx->log_likelihood); - BOB_CATCH_MEMBER("log_likelihood could not be read", 0) -} -int PyBobLearnEMGMMStats_setLog_likelihood(PyBobLearnEMGMMStatsObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyBob_NumberCheck(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects an double", Py_TYPE(self)->tp_name, t.name()); - return -1; - } - - self->cxx->log_likelihood = PyFloat_AsDouble(value); - return 0; - BOB_CATCH_MEMBER("log_likelihood could not be set", -1) -} - - -/***** shape *****/ -static auto shape = bob::extension::VariableDoc( - "shape", - "(int,int)", - "A tuple that represents the number of gaussians and dimensionality of each Gaussian ``(n_gaussians, dim)``.", - "" -); -PyObject* PyBobLearnEMGMMStats_getShape(PyBobLearnEMGMMStatsObject* self, void*) { - BOB_TRY - return Py_BuildValue("(i,i)", self->cxx->sumPx.shape()[0], self->cxx->sumPx.shape()[1]); - BOB_CATCH_MEMBER("shape could not be read", 0) -} - - - -static PyGetSetDef PyBobLearnEMGMMStats_getseters[] = { - { - n.name(), - (getter)PyBobLearnEMGMMStats_getN, - (setter)PyBobLearnEMGMMStats_setN, - n.doc(), - 0 - }, - { - sum_px.name(), - (getter)PyBobLearnEMGMMStats_getSum_px, - (setter)PyBobLearnEMGMMStats_setSum_px, - sum_px.doc(), - 0 - }, - { - sum_pxx.name(), - (getter)PyBobLearnEMGMMStats_getSum_pxx, - (setter)PyBobLearnEMGMMStats_setSum_pxx, - sum_pxx.doc(), - 0 - }, - { - t.name(), - (getter)PyBobLearnEMGMMStats_getT, - (setter)PyBobLearnEMGMMStats_setT, - t.doc(), - 0 - }, - { - log_likelihood.name(), - (getter)PyBobLearnEMGMMStats_getLog_likelihood, - (setter)PyBobLearnEMGMMStats_setLog_likelihood, - log_likelihood.doc(), - 0 - }, - { - shape.name(), - (getter)PyBobLearnEMGMMStats_getShape, - 0, - shape.doc(), - 0 - }, - - - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - - -/*** save ***/ -static auto save = bob::extension::FunctionDoc( - "save", - "Save the configuration of the GMMStats to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for writing"); -static PyObject* PyBobLearnEMGMMStats_Save(PyBobLearnEMGMMStatsObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - // get list of arguments - char** kwlist = save.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->save(*hdf5->f); - - BOB_CATCH_MEMBER("cannot save the data", 0) - Py_RETURN_NONE; -} - -/*** load ***/ -static auto load = bob::extension::FunctionDoc( - "load", - "Load the configuration of the GMMStats to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading"); -static PyObject* PyBobLearnEMGMMStats_Load(PyBobLearnEMGMMStatsObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = load.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->load(*hdf5->f); - - BOB_CATCH_MEMBER("cannot load the data", 0) - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this GMMStats with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` " - "and any other values internal to this machine." -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.GMMStats`", "A GMMStats object to be compared.") -.add_parameter("r_epsilon", "float", "Relative precision.") -.add_parameter("a_epsilon", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMGMMStats_IsSimilarTo(PyBobLearnEMGMMStatsObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - //PyObject* other = 0; - PyBobLearnEMGMMStatsObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMGMMStats_Type, &other, - &r_epsilon, &a_epsilon)){ - - is_similar_to.print_usage(); - return 0; - } - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - -/*** resize ***/ -static auto resize = bob::extension::FunctionDoc( - "resize", - "Allocates space for the statistics and resets to zero.", - 0, - true -) -.add_prototype("n_gaussians,n_inputs") -.add_parameter("n_gaussians", "int", "Number of gaussians") -.add_parameter("n_inputs", "int", "Dimensionality of the feature vector"); -static PyObject* PyBobLearnEMGMMStats_resize(PyBobLearnEMGMMStatsObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = resize.kwlist(0); - - int n_gaussians = 0; - int n_inputs = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &n_gaussians, &n_inputs)) return 0; - - if (n_gaussians <= 0){ - PyErr_Format(PyExc_TypeError, "n_gaussians must be greater than zero"); - resize.print_usage(); - return 0; - } - if (n_inputs <= 0){ - PyErr_Format(PyExc_TypeError, "n_inputs must be greater than zero"); - resize.print_usage(); - return 0; - } - - - self->cxx->resize(n_gaussians, n_inputs); - - BOB_CATCH_MEMBER("cannot perform the resize method", 0) - - Py_RETURN_NONE; -} - - -/*** init ***/ -static auto init = bob::extension::FunctionDoc( - "init", - " Resets statistics to zero." -) -.add_prototype(""); -static PyObject* PyBobLearnEMGMMStats_init_method(PyBobLearnEMGMMStatsObject* self) { - BOB_TRY - - self->cxx->init(); - - BOB_CATCH_MEMBER("cannot perform the init method", 0) - - Py_RETURN_NONE; -} - - - -static PyMethodDef PyBobLearnEMGMMStats_methods[] = { - { - save.name(), - (PyCFunction)PyBobLearnEMGMMStats_Save, - METH_VARARGS|METH_KEYWORDS, - save.doc() - }, - { - load.name(), - (PyCFunction)PyBobLearnEMGMMStats_Load, - METH_VARARGS|METH_KEYWORDS, - load.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMGMMStats_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - { - resize.name(), - (PyCFunction)PyBobLearnEMGMMStats_resize, - METH_VARARGS|METH_KEYWORDS, - resize.doc() - }, - { - init.name(), - (PyCFunction)PyBobLearnEMGMMStats_init_method, - METH_NOARGS, - init.doc() - }, - - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Operators *******************************************/ -/******************************************************************/ - -static PyBobLearnEMGMMStatsObject* PyBobLearnEMGMMStats_inplaceadd(PyBobLearnEMGMMStatsObject* self, PyObject* other) { - BOB_TRY - - if (!PyBobLearnEMGMMStats_Check(other)){ - PyErr_Format(PyExc_TypeError, "expected bob.learn.em.GMMStats object"); - return 0; - } - - auto other_ = reinterpret_cast<PyBobLearnEMGMMStatsObject*>(other); - - self->cxx->operator+=(*other_->cxx); - - BOB_CATCH_MEMBER("it was not possible to process the operator +=", 0) - - Py_INCREF(self); - return self; -} - -static PyNumberMethods PyBobLearnEMGMMStats_operators = {0}; - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMGMMStats_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMGMMStats(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMGMMStats_Type.tp_name = GMMStats_doc.name(); - PyBobLearnEMGMMStats_Type.tp_basicsize = sizeof(PyBobLearnEMGMMStatsObject); - PyBobLearnEMGMMStats_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyBobLearnEMGMMStats_Type.tp_doc = GMMStats_doc.doc(); - - // set the functions - PyBobLearnEMGMMStats_Type.tp_new = PyType_GenericNew; - PyBobLearnEMGMMStats_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMGMMStats_init); - PyBobLearnEMGMMStats_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMGMMStats_delete); - PyBobLearnEMGMMStats_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMGMMStats_RichCompare); - PyBobLearnEMGMMStats_Type.tp_methods = PyBobLearnEMGMMStats_methods; - PyBobLearnEMGMMStats_Type.tp_getset = PyBobLearnEMGMMStats_getseters; - PyBobLearnEMGMMStats_Type.tp_call = 0; - PyBobLearnEMGMMStats_Type.tp_as_number = &PyBobLearnEMGMMStats_operators; - - //set operators - PyBobLearnEMGMMStats_operators.nb_inplace_add = reinterpret_cast<binaryfunc>(PyBobLearnEMGMMStats_inplaceadd); - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMGMMStats_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMGMMStats_Type); - return PyModule_AddObject(module, "GMMStats", (PyObject*)&PyBobLearnEMGMMStats_Type) >= 0; -} diff --git a/bob/learn/em/include/bob.learn.em/EMPCATrainer.h b/bob/learn/em/include/bob.learn.em/EMPCATrainer.h deleted file mode 100644 index 90153c2adaeece5b179598316ecb7e766bb4850b..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/EMPCATrainer.h +++ /dev/null @@ -1,200 +0,0 @@ -/** - * @date Tue Oct 11 12:18:23 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Expectation Maximization Algorithm for Principal Component - * Analysis - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_EMPCA_TRAINER_H -#define BOB_LEARN_EM_EMPCA_TRAINER_H - -#include <bob.learn.linear/machine.h> -#include <blitz/array.h> - -namespace bob { namespace learn { namespace em { - -/** - * @brief Trains a linear machine using an Expectation-Maximization algorithm - * on the given dataset.\n - * References:\n - * 1. "Probabilistic Principal Component Analysis", - * Michael Tipping and Christopher Bishop, - * Journal of the Royal Statistical Society, - * Series B, 61, Part 3, pp. 611–622\n - * 2. "EM Algorithms for PCA and SPCA", - * Sam Roweis, Neural Information Processing Systems 10 (NIPS'97), - * pp.626-632 (Sensible Principal Component Analysis part)\n - * - * Notations used are the ones from reference 1.\n - * The probabilistic model is given by: \f$t = W x + \mu + \epsilon\f$\n - * - \f$t\f$ is the observed data (dimension \f$f\f$)\n - * - \f$W\f$ is a projection matrix (dimension \f$f \times d\f$)\n - * - \f$x\f$ is the projected data (dimension \f$d < f\f$)\n - * - \f$\mu\f$ is the mean of the data (dimension \f$f\f$)\n - * - \f$\epsilon\f$ is the noise of the data (dimension \f$f\f$) - * Gaussian with zero-mean and covariance matrix \f$\sigma^2 Id\f$ - */ -class EMPCATrainer -{ - public: //api - /** - * @brief Initializes a new EM PCA trainer. The training stage will place the - * resulting components in the linear machine and set it up to - * extract the variable means automatically. - */ - EMPCATrainer(bool compute_likelihood=true); - - /** - * @brief Copy constructor - */ - EMPCATrainer(const EMPCATrainer& other); - - /** - * @brief (virtual) Destructor - */ - virtual ~EMPCATrainer(); - - /** - * @brief Assignment operator - */ - EMPCATrainer& operator=(const EMPCATrainer& other); - - /** - * @brief Equal to - */ - bool operator==(const EMPCATrainer& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const EMPCATrainer& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const EMPCATrainer& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief This methods performs some initialization before the EM loop. - */ - virtual void initialize(bob::learn::linear::Machine& machine, - const blitz::Array<double,2>& ar); - - /** - * @brief Calculates and saves statistics across the dataset, and saves - * these as m_z_{first,second}_order. - * - * The statistics will be used in the mStep() that follows. - */ - virtual void eStep(bob::learn::linear::Machine& machine, - const blitz::Array<double,2>& ar); - - /** - * @brief Performs a maximization step to update the parameters of the - * factor analysis model. - */ - virtual void mStep(bob::learn::linear::Machine& machine, - const blitz::Array<double,2>& ar); - - /** - * @brief Computes the average log likelihood using the current estimates - * of the latent variables. - */ - virtual double computeLikelihood(bob::learn::linear::Machine& machine); - - /** - * @brief Sets \f$\sigma^2\f$ (Mostly for test purpose) - */ - void setSigma2(double sigma2) { m_sigma2 = sigma2; } - - /** - * @brief Gets \f$\sigma^2\f$ (Mostly for test purpose) - */ - double getSigma2() const { return m_sigma2; } - - /** - * @brief Sets the Random Number Generator - */ - void setRng(const boost::shared_ptr<boost::mt19937> rng) - { m_rng = rng; } - - /** - * @brief Gets the Random Number Generator - */ - const boost::shared_ptr<boost::mt19937> getRng() const - { return m_rng; } - - - private: //representation - - bool m_compute_likelihood; - boost::shared_ptr<boost::mt19937> m_rng; - - blitz::Array<double,2> m_S; /// Covariance of the training data (required only if we need to compute the log likelihood) - blitz::Array<double,2> m_z_first_order; /// Current mean of the \f$z_{n}\f$ latent variable - blitz::Array<double,3> m_z_second_order; /// Current covariance of the \f$z_{n}\f$ latent variable - blitz::Array<double,2> m_inW; /// The matrix product \f$W^T W\f$ - blitz::Array<double,2> m_invM; /// The matrix \f$inv(M)\f$, where \f$M = W^T W + \sigma^2 Id\f$ - double m_sigma2; /// The variance \f$sigma^2\f$ of the noise epsilon of the probabilistic model - double m_f_log2pi; /// The constant \f$n_{features} log(2*\pi)\f$ used during the likelihood computation - - // Working arrays - mutable blitz::Array<double,2> m_tmp_dxf; /// size dimensionality x n_features - mutable blitz::Array<double,1> m_tmp_d; /// size dimensionality - mutable blitz::Array<double,1> m_tmp_f; /// size n_features - mutable blitz::Array<double,2> m_tmp_dxd_1; /// size dimensionality x dimensionality - mutable blitz::Array<double,2> m_tmp_dxd_2; /// size dimensionality x dimensionality - mutable blitz::Array<double,2> m_tmp_fxd_1; /// size n_features x dimensionality - mutable blitz::Array<double,2> m_tmp_fxd_2; /// size n_features x dimensionality - mutable blitz::Array<double,2> m_tmp_fxf_1; /// size n_features x n_features - mutable blitz::Array<double,2> m_tmp_fxf_2; /// size n_features x n_features - - - /** - * @brief Initializes/resizes the (array) members - */ - void initMembers(const bob::learn::linear::Machine& machine, - const blitz::Array<double,2>& ar); - /** - * @brief Computes the mean and the variance (if required) of the training - * data - */ - void computeMeanVariance(bob::learn::linear::Machine& machine, - const blitz::Array<double,2>& ar); - /** - * @brief Random initialization of \f$W\f$ and \f$sigma^2\f$. - * W is the projection matrix (from the LinearMachine) - */ - void initRandomWSigma2(bob::learn::linear::Machine& machine); - /** - * @brief Computes the product \f$W^T W\f$. - * \f$W\f$ is the projection matrix (from the LinearMachine) - */ - void computeWtW(bob::learn::linear::Machine& machine); - /** - * @brief Computes the inverse of \f$M\f$ matrix, where - * \f$M = W^T W + \sigma^2 Id\f$. - * \f$W\f$ is the projection matrix (from the LinearMachine) - */ - void computeInvM(); - /** - * @brief M-Step (part 1): Computes the new estimate of \f$W\f$ using the - * new estimated statistics. - */ - void updateW(bob::learn::linear::Machine& machine, - const blitz::Array<double,2>& ar); - /** - * @brief M-Step (part 2): Computes the new estimate of \f$\sigma^2\f$ using - * the new estimated statistics. - */ - void updateSigma2(bob::learn::linear::Machine& machine, - const blitz::Array<double,2>& ar); -}; - -} } } // namespaces - -#endif /* BOB_LEARN_EM_EMPCA_TRAINER_H */ diff --git a/bob/learn/em/include/bob.learn.em/FABase.h b/bob/learn/em/include/bob.learn.em/FABase.h deleted file mode 100644 index 3b521989e96e50c27518a7929249abd6f15d9414..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/FABase.h +++ /dev/null @@ -1,293 +0,0 @@ -/** - * @date Tue Jan 27 15:51:15 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief A base class for Factor Analysis - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_FABASE_H -#define BOB_LEARN_EM_FABASE_H - -#include <stdexcept> - -#include <bob.learn.em/GMMMachine.h> -#include <boost/shared_ptr.hpp> - -namespace bob { namespace learn { namespace em { - -/** - * @brief A FA Base class which contains U, V and D matrices - * TODO: add a reference to the journal articles - */ -class FABase -{ - public: - /** - * @brief Default constructor. Builds an otherwise invalid 0 x 0 FABase - * The Universal Background Model and the matrices U, V and diag(d) are - * not initialized. - */ - FABase(); - - /** - * @brief Constructor. Builds a new FABase. - * The Universal Background Model and the matrices U, V and diag(d) are - * not initialized. - * - * @param ubm The Universal Background Model - * @param ru size of U (CD x ru) - * @param rv size of U (CD x rv) - * @warning ru and rv SHOULD BE >= 1. Just set U/V/D to zero if you want - * to ignore one subspace. This is the case for ISV. - */ - FABase(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm, const size_t ru=1, const size_t rv=1); - - /** - * @brief Copy constructor - */ - FABase(const FABase& other); - - /** - * @brief Just to virtualise the destructor - */ - virtual ~FABase(); - - /** - * @brief Assigns from a different JFA machine - */ - FABase& operator=(const FABase &other); - - /** - * @brief Equal to - */ - bool operator==(const FABase& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const FABase& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const FABase& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief Returns the UBM - */ - const boost::shared_ptr<bob::learn::em::GMMMachine> getUbm() const - { return m_ubm; } - - /** - * @brief Returns the U matrix - */ - const blitz::Array<double,2>& getU() const - { return m_U; } - - /** - * @brief Returns the V matrix - */ - const blitz::Array<double,2>& getV() const - { return m_V; } - - /** - * @brief Returns the diagonal matrix diag(d) (as a 1D vector) - */ - const blitz::Array<double,1>& getD() const - { return m_d; } - - /** - * @brief Returns the UBM mean supervector (as a 1D vector) - */ - const blitz::Array<double,1>& getUbmMean() const - { return m_cache_mean; } - - /** - * @brief Returns the UBM variance supervector (as a 1D vector) - */ - const blitz::Array<double,1>& getUbmVariance() const - { return m_cache_sigma; } - - /** - * @brief Returns the number of Gaussian components C - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNGaussians() const - { if(!m_ubm) throw std::runtime_error("No UBM was set in the JFA machine."); - return m_ubm->getNGaussians(); } - - /** - * @brief Returns the feature dimensionality D - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNInputs() const - { if(!m_ubm) throw std::runtime_error("No UBM was set in the JFA machine."); - return m_ubm->getNInputs(); } - - /** - * @brief Returns the supervector length CD - * (CxD: Number of Gaussian components by the feature dimensionality) - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getSupervectorLength() const - { if(!m_ubm) throw std::runtime_error("No UBM was set in the JFA machine."); - return m_ubm->getNInputs()*m_ubm->getNGaussians(); } - - /** - * @brief Returns the size/rank ru of the U matrix - */ - const size_t getDimRu() const - { return m_ru; } - - /** - * @brief Returns the size/rank rv of the V matrix - */ - const size_t getDimRv() const - { return m_rv; } - - /** - * @brief Resets the dimensionality of the subspace U and V - * U and V are hence uninitialized. - */ - void resize(const size_t ru, const size_t rv); - - /** - * @brief Resets the dimensionality of the subspace U and V, - * assuming that no UBM has yet been set - * U and V are hence uninitialized. - */ - void resize(const size_t ru, const size_t rv, const size_t cd); - - /** - * @brief Returns the U matrix in order to update it - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - blitz::Array<double,2>& updateU() - { return m_U; } - - /** - * @brief Returns the V matrix in order to update it - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - blitz::Array<double,2>& updateV() - { return m_V; } - - /** - * @brief Returns the diagonal matrix diag(d) (as a 1D vector) in order - * to update it - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - blitz::Array<double,1>& updateD() - { return m_d; } - - - /** - * @brief Sets (the mean supervector of) the Universal Background Model - * U, V and d are uninitialized in case of dimensions update (C or D) - */ - void setUbm(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm); - - /** - * @brief Sets the U matrix - */ - void setU(const blitz::Array<double,2>& U); - - /** - * @brief Sets the V matrix - */ - void setV(const blitz::Array<double,2>& V); - - /** - * @brief Sets the diagonal matrix diag(d) - * (a 1D vector is expected as an argument) - */ - void setD(const blitz::Array<double,1>& d); - - - /** - * @brief Estimates x from the GMM statistics considering the LPT - * assumption, that is the latent session variable x is approximated - * using the UBM - */ - void estimateX(const bob::learn::em::GMMStats& gmm_stats, blitz::Array<double,1>& x) const; - - /** - * @brief Compute and put U^{T}.Sigma^{-1} matrix in cache - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - void updateCacheUbmUVD(); - - - private: - /** - * @brief Update cache arrays/variables - */ - void updateCache(); - /** - * @brief Put GMM mean/variance supervector in cache - */ - void updateCacheUbm(); - /** - * @brief Resize working arrays - */ - void resizeTmp(); - /** - * @brief Computes (Id + U^T.Sigma^-1.U.N_{i,h}.U)^-1 = - * (Id + sum_{c=1..C} N_{i,h}.U_{c}^T.Sigma_{c}^-1.U_{c})^-1 - */ - void computeIdPlusUSProdInv(const bob::learn::em::GMMStats& gmm_stats, - blitz::Array<double,2>& out) const; - /** - * @brief Computes Fn_x = sum_{sessions h}(N*(o - m)) - * (Normalised first order statistics) - */ - void computeFn_x(const bob::learn::em::GMMStats& gmm_stats, - blitz::Array<double,1>& out) const; - /** - * @brief Estimates the value of x from the passed arguments - * (IdPlusUSProdInv and Fn_x), considering the LPT assumption - */ - void estimateX(const blitz::Array<double,2>& IdPlusUSProdInv, - const blitz::Array<double,1>& Fn_x, blitz::Array<double,1>& x) const; - - - // UBM - boost::shared_ptr<bob::learn::em::GMMMachine> m_ubm; - - // dimensionality - size_t m_ru; // size of U (CD x ru) - size_t m_rv; // size of V (CD x rv) - - // U, V, D matrices - // D is assumed to be diagonal, and only the diagonal is stored - blitz::Array<double,2> m_U; - blitz::Array<double,2> m_V; - blitz::Array<double,1> m_d; - - // Vectors/Matrices precomputed in cache - blitz::Array<double,1> m_cache_mean; - blitz::Array<double,1> m_cache_sigma; - blitz::Array<double,2> m_cache_UtSigmaInv; - - mutable blitz::Array<double,2> m_tmp_IdPlusUSProdInv; - mutable blitz::Array<double,1> m_tmp_Fn_x; - mutable blitz::Array<double,1> m_tmp_ru; - mutable blitz::Array<double,2> m_tmp_ruD; - mutable blitz::Array<double,2> m_tmp_ruru; -}; - - -} } } // namespaces - -#endif // BOB_LEARN_EM_FABASE_H diff --git a/bob/learn/em/include/bob.learn.em/FABaseTrainer.h b/bob/learn/em/include/bob.learn.em/FABaseTrainer.h deleted file mode 100644 index 037b4f2a35ab7d2237b0291a7fa75631a5008aa5..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/FABaseTrainer.h +++ /dev/null @@ -1,350 +0,0 @@ -/** - * @date Sat Jan 31 17:16:17 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief FABaseTrainer functions - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_FABASETRAINER_H -#define BOB_LEARN_EM_FABASETRAINER_H - -#include <blitz/array.h> -#include <bob.learn.em/GMMStats.h> -#include <bob.learn.em/JFAMachine.h> -#include <vector> - -#include <map> -#include <string> -#include <bob.core/array_copy.h> -#include <boost/shared_ptr.hpp> -#include <boost/random.hpp> -#include <bob.core/logging.h> - -namespace bob { namespace learn { namespace em { - -class FABaseTrainer -{ - public: - /** - * @brief Constructor - */ - FABaseTrainer(); - - /** - * @brief Copy constructor - */ - FABaseTrainer(const FABaseTrainer& other); - - /** - * @brief Destructor - */ - ~FABaseTrainer(); - - /** - * @brief Check that the dimensionality of the statistics match. - */ - void checkStatistics(const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats); - - /** - * @brief Initialize the dimensionality, the UBM, the sums of the - * statistics and the number of identities. - */ - void initUbmNidSumStatistics(const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats); - - /** - * @brief Precomputes the sums of the zeroth order statistics over the - * sessions for each client - */ - void precomputeSumStatisticsN(const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats); - /** - * @brief Precomputes the sums of the first order statistics over the - * sessions for each client - */ - void precomputeSumStatisticsF(const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats); - - /** - * @brief Initializes (allocates and sets to zero) the x, y, z speaker - * factors - */ - void initializeXYZ(const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats); - - /** - * @brief Resets the x, y, z speaker factors to zero values - */ - void resetXYZ(); - - - /**** Y and V functions ****/ - /** - * @brief Computes Vt * diag(sigma)^-1 - */ - void computeVtSigmaInv(const bob::learn::em::FABase& m); - /** - * @brief Computes Vt_{c} * diag(sigma)^-1 * V_{c} for each Gaussian c - */ - void computeVProd(const bob::learn::em::FABase& m); - /** - * @brief Computes (I+Vt*diag(sigma)^-1*Ni*V)^-1 which occurs in the y - * estimation for the given person - */ - void computeIdPlusVProd_i(const size_t id); - /** - * @brief Computes sum_{sessions h}(N_{i,h}*(o_{i,h} - m - D*z_{i} - U*x_{i,h}) - * which occurs in the y estimation of the given person - */ - void computeFn_y_i(const bob::learn::em::FABase& m, - const std::vector<boost::shared_ptr<bob::learn::em::GMMStats> >& stats, - const size_t id); - /** - * @brief Updates y_i (of the current person) and the accumulators to - * compute V with the cache values m_cache_IdPlusVprod_i, m_VtSigmaInv and - * m_cache_Fn_y_i - */ - void updateY_i(const size_t id); - /** - * @brief Updates y and the accumulators to compute V - */ - void updateY(const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats); - /** - * @brief Computes the accumulators m_acc_V_A1 and m_acc_V_A2 for V - * V = A2 * A1^-1 - */ - void computeAccumulatorsV(const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats); - /** - * @brief Updates V from the accumulators m_acc_V_A1 and m_acc_V_A2 - */ - void updateV(blitz::Array<double,2>& V); - - - /**** X and U functions ****/ - /** - * @brief Computes Ut * diag(sigma)^-1 - */ - void computeUtSigmaInv(const bob::learn::em::FABase& m); - /** - * @brief Computes Ut_{c} * diag(sigma)^-1 * U_{c} for each Gaussian c - */ - void computeUProd(const bob::learn::em::FABase& m); - /** - * @brief Computes (I+Ut*diag(sigma)^-1*Ni*U)^-1 which occurs in the x - * estimation - */ - void computeIdPlusUProd_ih(const boost::shared_ptr<bob::learn::em::GMMStats>& stats); - /** - * @brief Computes sum_{sessions h}(N_{i,h}*(o_{i,h} - m - D*z_{i} - U*x_{i,h}) - * which occurs in the y estimation of the given person - */ - void computeFn_x_ih(const bob::learn::em::FABase& m, - const boost::shared_ptr<bob::learn::em::GMMStats>& stats, const size_t id); - /** - * @brief Updates x_ih (of the current person/session) and the - * accumulators to compute U with the cache values m_cache_IdPlusVprod_i, - * m_VtSigmaInv and m_cache_Fn_y_i - */ - void updateX_ih(const size_t id, const size_t h); - /** - * @brief Updates x - */ - void updateX(const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats); - /** - * @brief Computes the accumulators m_acc_U_A1 and m_acc_U_A2 for U - * U = A2 * A1^-1 - */ - void computeAccumulatorsU(const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats); - /** - * @brief Updates U from the accumulators m_acc_U_A1 and m_acc_U_A2 - */ - void updateU(blitz::Array<double,2>& U); - - - /**** z and D functions ****/ - /** - * @brief Computes diag(D) * diag(sigma)^-1 - */ - void computeDtSigmaInv(const bob::learn::em::FABase& m); - /** - * @brief Computes Dt_{c} * diag(sigma)^-1 * D_{c} for each Gaussian c - */ - void computeDProd(const bob::learn::em::FABase& m); - /** - * @brief Computes (I+diag(d)t*diag(sigma)^-1*Ni*diag(d))^-1 which occurs - * in the z estimation for the given person - */ - void computeIdPlusDProd_i(const size_t id); - /** - * @brief Computes sum_{sessions h}(N_{i,h}*(o_{i,h} - m - V*y_{i} - U*x_{i,h}) - * which occurs in the y estimation of the given person - */ - void computeFn_z_i(const bob::learn::em::FABase& m, - const std::vector<boost::shared_ptr<bob::learn::em::GMMStats> >& stats, const size_t id); - /** - * @brief Updates z_i (of the current person) and the accumulators to - * compute D with the cache values m_cache_IdPlusDProd_i, m_VtSigmaInv - * and m_cache_Fn_z_i - */ - void updateZ_i(const size_t id); - /** - * @brief Updates z and the accumulators to compute D - */ - void updateZ(const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats); - /** - * @brief Computes the accumulators m_acc_D_A1 and m_acc_D_A2 for d - * d = A2 * A1^-1 - */ - void computeAccumulatorsD(const bob::learn::em::FABase& m, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& stats); - /** - * @brief Updates d from the accumulators m_acc_D_A1 and m_acc_D_A2 - */ - void updateD(blitz::Array<double,1>& d); - - - /** - * @brief Get the zeroth order statistics - */ - const std::vector<blitz::Array<double,1> >& getNacc() const - { return m_Nacc; } - /** - * @brief Get the first order statistics - */ - const std::vector<blitz::Array<double,1> >& getFacc() const - { return m_Facc; } - /** - * @brief Get the x speaker factors - */ - const std::vector<blitz::Array<double,2> >& getX() const - { return m_x; } - /** - * @brief Get the y speaker factors - */ - const std::vector<blitz::Array<double,1> >& getY() const - { return m_y; } - /** - * @brief Get the z speaker factors - */ - const std::vector<blitz::Array<double,1> >& getZ() const - { return m_z; } - /** - * @brief Set the x speaker factors - */ - void setX(const std::vector<blitz::Array<double,2> >& X) - { m_x = X; } - /** - * @brief Set the y speaker factors - */ - void setY(const std::vector<blitz::Array<double,1> >& y) - { m_y = y; } - /** - * @brief Set the z speaker factors - */ - void setZ(const std::vector<blitz::Array<double,1> >& z) - { m_z = z; } - - /** - * @brief Initializes the cache to process the given statistics - */ - void initCache(); - - /** - * @brief Getters for the accumulators - */ - const blitz::Array<double,3>& getAccVA1() const - { return m_acc_V_A1; } - const blitz::Array<double,2>& getAccVA2() const - { return m_acc_V_A2; } - const blitz::Array<double,3>& getAccUA1() const - { return m_acc_U_A1; } - const blitz::Array<double,2>& getAccUA2() const - { return m_acc_U_A2; } - const blitz::Array<double,1>& getAccDA1() const - { return m_acc_D_A1; } - const blitz::Array<double,1>& getAccDA2() const - { return m_acc_D_A2; } - - /** - * @brief Setters for the accumulators, Very useful if the e-Step needs - * to be parallelized. - */ - void setAccVA1(const blitz::Array<double,3>& acc) - { bob::core::array::assertSameShape(acc, m_acc_V_A1); - m_acc_V_A1 = acc; } - void setAccVA2(const blitz::Array<double,2>& acc) - { bob::core::array::assertSameShape(acc, m_acc_V_A2); - m_acc_V_A2 = acc; } - void setAccUA1(const blitz::Array<double,3>& acc) - { bob::core::array::assertSameShape(acc, m_acc_U_A1); - m_acc_U_A1 = acc; } - void setAccUA2(const blitz::Array<double,2>& acc) - { bob::core::array::assertSameShape(acc, m_acc_U_A2); - m_acc_U_A2 = acc; } - void setAccDA1(const blitz::Array<double,1>& acc) - { bob::core::array::assertSameShape(acc, m_acc_D_A1); - m_acc_D_A1 = acc; } - void setAccDA2(const blitz::Array<double,1>& acc) - { bob::core::array::assertSameShape(acc, m_acc_D_A2); - m_acc_D_A2 = acc; } - - - private: - size_t m_Nid; // Number of identities - size_t m_dim_C; // Number of Gaussian components of the UBM GMM - size_t m_dim_D; // Dimensionality of the feature space - size_t m_dim_ru; // Rank of the U subspace - size_t m_dim_rv; // Rank of the V subspace - - std::vector<blitz::Array<double,2> > m_x; // matrix x of speaker factors for eigenchannels U, for each client - std::vector<blitz::Array<double,1> > m_y; // vector y of spealer factors for eigenvoices V, for each client - std::vector<blitz::Array<double,1> > m_z; // vector z of spealer factors for eigenvoices Z, for each client - - std::vector<blitz::Array<double,1> > m_Nacc; // Sum of the zeroth order statistics over the sessions for each client, dimension C - std::vector<blitz::Array<double,1> > m_Facc; // Sum of the first order statistics over the sessions for each client, dimension CD - - // Accumulators for the M-step - blitz::Array<double,3> m_acc_V_A1; - blitz::Array<double,2> m_acc_V_A2; - blitz::Array<double,3> m_acc_U_A1; - blitz::Array<double,2> m_acc_U_A2; - blitz::Array<double,1> m_acc_D_A1; - blitz::Array<double,1> m_acc_D_A2; - - // Cache/Precomputation - blitz::Array<double,2> m_cache_VtSigmaInv; // Vt * diag(sigma)^-1 - blitz::Array<double,3> m_cache_VProd; // first dimension is the Gaussian id - blitz::Array<double,2> m_cache_IdPlusVProd_i; - blitz::Array<double,1> m_cache_Fn_y_i; - - blitz::Array<double,2> m_cache_UtSigmaInv; // Ut * diag(sigma)^-1 - blitz::Array<double,3> m_cache_UProd; // first dimension is the Gaussian id - blitz::Array<double,2> m_cache_IdPlusUProd_ih; - blitz::Array<double,1> m_cache_Fn_x_ih; - - blitz::Array<double,1> m_cache_DtSigmaInv; // Dt * diag(sigma)^-1 - blitz::Array<double,1> m_cache_DProd; // supervector length dimension - blitz::Array<double,1> m_cache_IdPlusDProd_i; - blitz::Array<double,1> m_cache_Fn_z_i; - - // Working arrays - mutable blitz::Array<double,2> m_tmp_ruru; - mutable blitz::Array<double,2> m_tmp_ruD; - mutable blitz::Array<double,2> m_tmp_rvrv; - mutable blitz::Array<double,2> m_tmp_rvD; - mutable blitz::Array<double,1> m_tmp_rv; - mutable blitz::Array<double,1> m_tmp_ru; - mutable blitz::Array<double,1> m_tmp_CD; - mutable blitz::Array<double,1> m_tmp_CD_b; -}; - - -} } } // namespaces - -#endif /* BOB_LEARN_EM_FABASETRAINER_H */ diff --git a/bob/learn/em/include/bob.learn.em/GMMBaseTrainer.h b/bob/learn/em/include/bob.learn.em/GMMBaseTrainer.h deleted file mode 100644 index 9160c6b0a9b34b6480445c5175637de3970fd5c0..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/GMMBaseTrainer.h +++ /dev/null @@ -1,161 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * - * @brief This class implements the E-step of the expectation-maximisation algorithm for a GMM Machine. - * @details See Section 9.2.2 of Bishop, "Pattern recognition and machine learning", 2006 - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_GMMBASETRAINER_H -#define BOB_LEARN_EM_GMMBASETRAINER_H - -#include <bob.learn.em/GMMMachine.h> -#include <bob.learn.em/GMMStats.h> -#include <limits> - -namespace bob { namespace learn { namespace em { - -/** - * @brief This class implements the E-step of the expectation-maximisation - * algorithm for a GMM Machine. - * @details See Section 9.2.2 of Bishop, - * "Pattern recognition and machine learning", 2006 - */ -class GMMBaseTrainer -{ - public: - /** - * @brief Default constructor - */ - GMMBaseTrainer(const bool update_means=true, - const bool update_variances=false, - const bool update_weights=false, - const double mean_var_update_responsibilities_threshold = std::numeric_limits<double>::epsilon()); - - /** - * @brief Copy constructor - */ - GMMBaseTrainer(const GMMBaseTrainer& other); - - /** - * @brief Destructor - */ - virtual ~GMMBaseTrainer(); - - /** - * @brief Initialization before the EM steps - */ - void initialize(bob::learn::em::GMMMachine& gmm); - - /** - * @brief Calculates and saves statistics across the dataset, - * and saves these as m_ss. Calculates the average - * log likelihood of the observations given the GMM, - * and returns this in average_log_likelihood. - * - * The statistics, m_ss, will be used in the mStep() that follows. - * Implements EMTrainer::eStep(double &) - */ - void eStep(bob::learn::em::GMMMachine& gmm, - const blitz::Array<double,2>& data); - - /** - * @brief Computes the likelihood using current estimates of the latent - * variables - */ - double computeLikelihood(bob::learn::em::GMMMachine& gmm); - - - /** - * @brief Assigns from a different GMMBaseTrainer - */ - GMMBaseTrainer& operator=(const GMMBaseTrainer &other); - - /** - * @brief Equal to - */ - bool operator==(const GMMBaseTrainer& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const GMMBaseTrainer& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const GMMBaseTrainer& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief Returns the internal GMM statistics. Useful to parallelize the - * E-step - */ - const boost::shared_ptr<bob::learn::em::GMMStats> getGMMStats() const - { return m_ss; } - - /** - * @brief Sets the internal GMM statistics. Useful to parallelize the - * E-step - */ - void setGMMStats(boost::shared_ptr<bob::learn::em::GMMStats> stats); - - /** - * update means on each iteration - */ - bool getUpdateMeans() - {return m_update_means;} - - /** - * update variances on each iteration - */ - bool getUpdateVariances() - {return m_update_variances;} - - - bool getUpdateWeights() - {return m_update_weights;} - - - double getMeanVarUpdateResponsibilitiesThreshold() - {return m_mean_var_update_responsibilities_threshold;} - - - private: - - /** - * These are the sufficient statistics, calculated during the - * E-step and used during the M-step - */ - boost::shared_ptr<bob::learn::em::GMMStats> m_ss; - - - /** - * update means on each iteration - */ - bool m_update_means; - - /** - * update variances on each iteration - */ - bool m_update_variances; - - /** - * update weights on each iteration - */ - bool m_update_weights; - - /** - * threshold over the responsibilities of the Gaussians - * Equations 9.24, 9.25 of Bishop, "Pattern recognition and machine learning", 2006 - * require a division by the responsibilities, which might be equal to zero - * because of numerical issue. This threshold is used to avoid such divisions. - */ - double m_mean_var_update_responsibilities_threshold; -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_GMMBASETRAINER_H diff --git a/bob/learn/em/include/bob.learn.em/GMMMachine.h b/bob/learn/em/include/bob.learn.em/GMMMachine.h deleted file mode 100644 index 0a46f822b22acce84d9faa3914729a1e48b7d115..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/GMMMachine.h +++ /dev/null @@ -1,380 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief This class implements a multivariate diagonal Gaussian distribution. - * @details See Section 2.3.9 of Bishop, "Pattern recognition and machine learning", 2006 - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_GMMMACHINE_H -#define BOB_LEARN_EM_GMMMACHINE_H - -#include <bob.learn.em/Gaussian.h> -#include <bob.learn.em/GMMStats.h> -#include <bob.io.base/HDF5File.h> -#include <iostream> -#include <boost/shared_ptr.hpp> -#include <vector> - -namespace bob { namespace learn { namespace em { - -/** - * @brief This class implements a multivariate diagonal Gaussian distribution. - * @details See Section 2.3.9 of Bishop, "Pattern recognition and machine learning", 2006 - */ -class GMMMachine -{ - public: - /** - * Default constructor - */ - GMMMachine(); - - /** - * Constructor - * @param[in] n_gaussians The number of Gaussian components - * @param[in] n_inputs The feature dimensionality - */ - GMMMachine(const size_t n_gaussians, const size_t n_inputs); - - /** - * Copy constructor - * (Needed because the GMM points to its constituent Gaussian members) - */ - GMMMachine(const GMMMachine& other); - - /** - * Constructor from a Configuration - */ - GMMMachine(bob::io::base::HDF5File& config); - - /** - * Assignment - */ - GMMMachine& operator=(const GMMMachine &other); - - /** - * Equal to - */ - bool operator==(const GMMMachine& b) const; - - /** - * Not equal to - */ - bool operator!=(const GMMMachine& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const GMMMachine& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * Destructor - */ - virtual ~GMMMachine(); - - - /** - * Reset the input dimensionality, and the number of Gaussian components. - * Initialises the weights to uniform distribution. - * @param n_gaussians The number of Gaussian components - * @param n_inputs The feature dimensionality - */ - void resize(const size_t n_gaussians, const size_t n_inputs); - - - ///////////////////////// - // Getters - //////////////////////// - - /** - * Get number of inputs - */ - size_t getNInputs() const - { return m_n_inputs; } - - /** - * Get the weights ("mixing coefficients") of the Gaussian components - */ - const blitz::Array<double,1>& getWeights() const - { return m_weights; } - - /** - * Get the logarithm of the weights of the Gaussian components - */ - inline const blitz::Array<double,1>& getLogWeights() const - { return m_cache_log_weights; } - - - /** - * Get the means - */ - const blitz::Array<double,2> getMeans() const; - - /** - * Get the mean supervector - */ - void getMeanSupervector(blitz::Array<double,1> &mean_supervector) const; - - /** - * Returns a const reference to the supervector (Put in cache) - */ - const blitz::Array<double,1>& getMeanSupervector() const; - - /** - * Get the variances - */ - const blitz::Array<double,2> getVariances() const; - - /** - * Returns a const reference to the supervector (Put in cache) - */ - const blitz::Array<double,1>& getVarianceSupervector() const; - - - /** - * Get the variance flooring thresholds for each Gaussian in each dimension - */ - const blitz::Array<double,2> getVarianceThresholds() const; - - - - /////////////////////// - // Setters - /////////////////////// - - /** - * Set the weights - */ - void setWeights(const blitz::Array<double,1> &weights); - - /** - * Set the means - */ - void setMeans(const blitz::Array<double,2> &means); - /** - * Set the means from a supervector - */ - void setMeanSupervector(const blitz::Array<double,1> &mean_supervector); - - /** - * Set the variances - */ - void setVariances(const blitz::Array<double,2> &variances); - /** - * Set the variances from a supervector - */ - void setVarianceSupervector(const blitz::Array<double,1> &variance_supervector); - - /** - * Set the variance flooring thresholds in each dimension - */ - void setVarianceThresholds(const double value); - /** - * Set the variance flooring thresholds in each dimension - * (equal for all Gaussian components) - */ - void setVarianceThresholds(blitz::Array<double,1> variance_thresholds); - /** - * Set the variance flooring thresholds for each Gaussian in each dimension - */ - void setVarianceThresholds(const blitz::Array<double,2> &variance_thresholds); - - - //////////////// - // Methods - ///////////////// - - /** - * Get the weights in order to be updated - * ("mixing coefficients") of the Gaussian components - * @warning Only trainers should use this function for efficiency reason - */ - inline blitz::Array<double,1>& updateWeights() - { return m_weights; } - - - /** - * Update the log of the weights in cache - * @warning Should be used by trainer only when using updateWeights() - */ - void recomputeLogWeights() const; - - - - /** - * Output the log likelihood of the sample, x, i.e. log(p(x|GMMMachine)) - * @param[in] x The sample - * @param[out] log_weighted_gaussian_likelihoods For each Gaussian, i: log(weight_i*p(x|Gaussian_i)) - * @return The GMMMachine log likelihood, i.e. log(p(x|GMMMachine)) - * Dimensions of the parameters are checked - */ - double logLikelihood(const blitz::Array<double, 1> &x, blitz::Array<double,1> &log_weighted_gaussian_likelihoods) const; - - /** - * Output the log likelihood of the sample, x, i.e. log(p(x|GMMMachine)) - * @param[in] x The sample - * @param[out] log_weighted_gaussian_likelihoods For each Gaussian, i: log(weight_i*p(x|Gaussian_i)) - * @return The GMMMachine log likelihood, i.e. log(p(x|GMMMachine)) - * @warning Dimensions of the parameters are not checked - */ - double logLikelihood_(const blitz::Array<double, 1> &x, blitz::Array<double,1> &log_weighted_gaussian_likelihoods) const; - - /** - * Output the log likelihood of the sample, x, i.e. log(p(x|GMM)) - * @param[in] x The sample - * Dimension of the input is checked - */ - double logLikelihood(const blitz::Array<double, 1> &x) const; - - - /** - * Output the averaged log likelihood of a set of samples, x, i.e. log(p(x|GMM)) - * @param[in] x The sample - * Dimension of the input is checked - */ - double logLikelihood(const blitz::Array<double, 2> &x) const; - - - /** - * Output the log likelihood of the sample, x, i.e. log(p(x|GMM)) - * @param[in] x The sample - * @warning Dimension of the input is not checked - */ - double logLikelihood_(const blitz::Array<double, 1> &x) const; - - /** - * Accumulates the GMM statistics over a set of samples. - * @see bool accStatistics(const blitz::Array<double,1> &x, GMMStats stats) - * Dimensions of the parameters are checked - */ - void accStatistics(const blitz::Array<double,2>& input, GMMStats &stats) const; - - /** - * Accumulates the GMM statistics over a set of samples. - * @see bool accStatistics(const blitz::Array<double,1> &x, GMMStats stats) - * @warning Dimensions of the parameters are not checked - */ - void accStatistics_(const blitz::Array<double,2>& input, GMMStats &stats) const; - - /** - * Accumulate the GMM statistics for this sample. - * - * @param[in] x The current sample - * @param[out] stats The accumulated statistics - * Dimensions of the parameters are checked - */ - void accStatistics(const blitz::Array<double,1> &x, GMMStats &stats) const; - - /** - * Accumulate the GMM statistics for this sample. - * - * @param[in] x The current sample - * @param[out] stats The accumulated statistics - * @warning Dimensions of the parameters are not checked - */ - void accStatistics_(const blitz::Array<double,1> &x, GMMStats &stats) const; - - - /** - * Get a pointer to a particular Gaussian component - * @param[in] i The index of the Gaussian component - * @return A smart pointer to the i'th Gaussian component - * if it exists, otherwise throws an exception - */ - boost::shared_ptr<bob::learn::em::Gaussian> getGaussian(const size_t i); - - - /** - * Return the number of Gaussian components - */ - inline size_t getNGaussians() const - { return m_n_gaussians; } - - /** - * Save to a Configuration - */ - void save(bob::io::base::HDF5File& config) const; - - /** - * Load from a Configuration - */ - void load(bob::io::base::HDF5File& config); - - /** - * Load/Reload mean/variance supervector in cache - */ - void reloadCacheSupervectors() const; - - friend std::ostream& operator<<(std::ostream& os, const GMMMachine& machine); - - - private: - /** - * Copy another GMMMachine - */ - void copy(const GMMMachine&); - - /** - * The number of Gaussian components - */ - size_t m_n_gaussians; - - /** - * The feature dimensionality - */ - size_t m_n_inputs; - - /** - * The Gaussian components - */ - std::vector<boost::shared_ptr<Gaussian> > m_gaussians; - - /** - * The weights (also known as "mixing coefficients") - */ - blitz::Array<double,1> m_weights; - - /** - * Update the mean and variance supervectors - * in cache (into a 1D blitz array) - */ - void updateCacheSupervectors() const; - - /** - * Initialise the cache members (allocate arrays) - */ - void initCache() const; - - /** - * Accumulate the GMM statistics for this sample. - * Called by accStatistics() and accStatistics_() - * - * @param[in] x The current sample - * @param[out] stats The accumulated statistics - * @param[in] log_likelihood The current log_likelihood - * @warning Dimensions of the parameters are not checked - */ - void accStatisticsInternal(const blitz::Array<double,1> &x, - GMMStats &stats, const double log_likelihood) const; - - - /// Some cache arrays to avoid re-allocation when computing log-likelihoods - mutable blitz::Array<double,1> m_cache_log_weights; - mutable blitz::Array<double,1> m_cache_log_weighted_gaussian_likelihoods; - mutable blitz::Array<double,1> m_cache_P; - mutable blitz::Array<double,2> m_cache_Px; - - mutable blitz::Array<double,1> m_cache_mean_supervector; - mutable blitz::Array<double,1> m_cache_variance_supervector; - mutable bool m_cache_supervector; - -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_GMMMACHINE_H diff --git a/bob/learn/em/include/bob.learn.em/GMMStats.h b/bob/learn/em/include/bob.learn.em/GMMStats.h deleted file mode 100644 index af56f05ce1d6a4285d4bd3d43f0ac7b9561214a9..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/GMMStats.h +++ /dev/null @@ -1,141 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_GMMSTATS_H -#define BOB_LEARN_EM_GMMSTATS_H - -#include <blitz/array.h> -#include <bob.io.base/HDF5File.h> - -namespace bob { namespace learn { namespace em { - -/** - * @brief A container for GMM statistics. - * @see GMMMachine - * - * With respect to Reynolds, "Speaker Verification Using Adapted - * Gaussian Mixture Models", DSP, 2000: - * Eq (8) is n(i) - * Eq (9) is sumPx(i) / n(i) - * Eq (10) is sumPxx(i) / n(i) - */ -class GMMStats { - public: - - /** - * Default constructor. - */ - GMMStats(); - - /** - * Constructor. - * @param n_gaussians Number of Gaussians in the mixture model. - * @param n_inputs Feature dimensionality. - */ - GMMStats(const size_t n_gaussians, const size_t n_inputs); - - /** - * Copy constructor - */ - GMMStats(const GMMStats& other); - - /** - * Constructor (from a Configuration) - */ - GMMStats(bob::io::base::HDF5File& config); - - /** - * Assigment - */ - GMMStats& operator=(const GMMStats& other); - - /** - * Equal to - */ - bool operator==(const GMMStats& b) const; - - /** - * Not Equal to - */ - bool operator!=(const GMMStats& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const GMMStats& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * Updates a GMMStats with another GMMStats - */ - void operator+=(const GMMStats& b); - - /** - * Destructor - */ - ~GMMStats(); - - /** - * Allocates space for the statistics and resets to zero. - * @param n_gaussians Number of Gaussians in the mixture model. - * @param n_inputs Feature dimensionality. - */ - void resize(const size_t n_gaussians, const size_t n_inputs); - - /** - * Resets statistics to zero. - */ - void init(); - - /** - * The accumulated log likelihood of all samples - */ - double log_likelihood; - - /** - * The accumulated number of samples - */ - size_t T; - - /** - * For each Gaussian, the accumulated sum of responsibilities, i.e. the sum of P(gaussian_i|x) - */ - blitz::Array<double,1> n; - - /** - * For each Gaussian, the accumulated sum of responsibility times the sample - */ - blitz::Array<double,2> sumPx; - - /** - * For each Gaussian, the accumulated sum of responsibility times the sample squared - */ - blitz::Array<double,2> sumPxx; - - /** - * Save to a Configuration - */ - void save(bob::io::base::HDF5File& config) const; - - /** - * Load from a Configuration - */ - void load(bob::io::base::HDF5File& config); - - friend std::ostream& operator<<(std::ostream& os, const GMMStats& g); - - private: - /** - * Copy another GMMStats - */ - void copy(const GMMStats&); -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_GMMSTATS_H diff --git a/bob/learn/em/include/bob.learn.em/Gaussian.h b/bob/learn/em/include/bob.learn.em/Gaussian.h deleted file mode 100644 index 023f0080b1d2fe7a56c18e114b748d0ac629fcd6..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/Gaussian.h +++ /dev/null @@ -1,247 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_GAUSSIAN_H -#define BOB_LEARN_EM_GAUSSIAN_H - -#include <bob.io.base/HDF5File.h> -#include <blitz/array.h> -#include <limits> - -namespace bob { namespace learn { namespace em { - -/** - * @brief This class implements a multivariate diagonal Gaussian distribution. - */ -class Gaussian -{ - public: - /** - * Default constructor - */ - Gaussian(); - - /** - * Constructor - * @param[in] n_inputs The feature dimensionality - */ - Gaussian(const size_t n_inputs); - - /** - * Destructor - */ - virtual ~Gaussian(); - - /** - * Copy constructor - */ - Gaussian(const Gaussian& other); - - /** - * Constructs from a configuration file - */ - Gaussian(bob::io::base::HDF5File& config); - - /** - * Assignment - */ - Gaussian& operator=(const Gaussian &other); - - /** - * Equal to - */ - bool operator==(const Gaussian& b) const; - /** - * Not equal to - */ - bool operator!=(const Gaussian& b) const; - /** - * @brief Similar to - */ - bool is_similar_to(const Gaussian& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * Set the input dimensionality, reset the mean to zero - * and the variance to one. - * @see resize() - * @param n_inputs The feature dimensionality - * @warning The mean and variance are not initialized - */ - void setNInputs(const size_t n_inputs); - - /** - * Get the input dimensionality - */ - size_t getNInputs() const - { return m_n_inputs; } - - /** - * Set the input dimensionality, reset the mean to zero - * and the variance to one. - * @see setNInputs() - * @param n_inputs The feature dimensionality - */ - void resize(const size_t n_inputs); - - /** - * Get the mean - */ - inline const blitz::Array<double,1>& getMean() const - { return m_mean; } - - /** - * Get the mean in order to be updated - * @warning Only trainers should use this function for efficiency reason - */ - inline blitz::Array<double,1>& updateMean() - { return m_mean; } - - /** - * Set the mean - */ - void setMean(const blitz::Array<double,1> &mean); - - /** - * Get the variance (the diagonal of the covariance matrix) - */ - inline const blitz::Array<double,1>& getVariance() const - { return m_variance; } - - /** - * Get the variance in order to be updated - * @warning Only trainers should use this function for efficiency reason - */ - inline blitz::Array<double,1>& updateVariance() - { return m_variance; } - - /** - * Set the variance - */ - void setVariance(const blitz::Array<double,1> &variance); - - /** - * Get the variance flooring thresholds - */ - const blitz::Array<double,1>& getVarianceThresholds() const - { return m_variance_thresholds; } - - /** - * Get the variance thresholds in order to be updated - * @warning Only trainers should use this function for efficiency reason - */ - inline blitz::Array<double,1>& updateVarianceThreshods() - { return m_variance_thresholds; } - - /** - * Set the variance flooring thresholds - */ - void setVarianceThresholds(const blitz::Array<double,1> &variance_thresholds); - - /** - * Set the variance flooring thresholds - */ - void setVarianceThresholds(const double value); - - /** - * Apply the variance flooring thresholds - * This method is called when using setVarianceThresholds() - * @warning It is only useful when using updateVarianceThreshods(), - * and should mostly be done by trainers - */ - void applyVarianceThresholds(); - - /** - * Output the log likelihood of the sample, x - * @param x The data sample (feature vector) - */ - double logLikelihood(const blitz::Array<double,1>& x) const; - - /** - * Output the log likelihood of the sample, x - * @param x The data sample (feature vector) - * @warning The input is NOT checked - */ - double logLikelihood_(const blitz::Array<double,1>& x) const; - - /** - * Saves to a Configuration - */ - void save(bob::io::base::HDF5File& config) const; - - /** - * Loads from a Configuration - */ - void load(bob::io::base::HDF5File& config); - - /** - * Prints a Gaussian in the output stream - */ - friend std::ostream& operator<<(std::ostream& os, const bob::learn::em::Gaussian& g); - - - private: - /** - * Copies another Gaussian - */ - void copy(const Gaussian& other); - - /** - * Computes n_inputs * log(2*pi) - */ - void preComputeNLog2Pi(); - - /** - * Computes and stores the value of g_norm, - * to later speed up evaluation of logLikelihood() - * Note: g_norm is defined as follows: - * log(Gaussian pdf) = log(1/((2pi)^(k/2)(det)^(1/2)) * exp(...)) - * = -1/2 * g_norm * (...) - */ - void preComputeConstants(); - - /** - * The mean vector of the Gaussian - */ - blitz::Array<double,1> m_mean; - - /** - * The diagonal of the covariance matrix (assumed to be diagonal) - */ - blitz::Array<double,1> m_variance; - - /** - * 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. - */ - blitz::Array<double,1> m_variance_thresholds; - - /** - * A constant that depends only on the feature dimensionality - * m_n_log2pi = n_inputs * log(2*pi) (used to compute m_gnorm) - */ - double m_n_log2pi; - - /** - * A constant that depends only on the feature dimensionality - * (m_n_inputs) and the variance - * @see bool preComputeConstants() - */ - double m_g_norm; - - /** - * The number of inputs (feature dimensionality) - */ - size_t m_n_inputs; -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_GAUSSIAN_H diff --git a/bob/learn/em/include/bob.learn.em/ISVBase.h b/bob/learn/em/include/bob.learn.em/ISVBase.h deleted file mode 100644 index 477d1972e44a59e6f8d38705256e71162ab46353..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/ISVBase.h +++ /dev/null @@ -1,228 +0,0 @@ -/** - * @date Tue Jan 27 16:02:00 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief A base class for Joint Factor Analysis-like machines - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_ISVBASE_H -#define BOB_LEARN_EM_ISVBASE_H - -#include <stdexcept> - -#include <bob.learn.em/GMMMachine.h> -#include <bob.learn.em/FABase.h> - -#include <bob.io.base/HDF5File.h> -#include <boost/shared_ptr.hpp> - -namespace bob { namespace learn { namespace em { - - -/** - * @brief An ISV Base class which contains U and D matrices - * TODO: add a reference to the journal articles - */ -class ISVBase -{ - public: - /** - * @brief Default constructor. Builds an otherwise invalid 0 x 0 ISVBase - * The Universal Background Model and the matrices U, V and diag(d) are - * not initialized. - */ - ISVBase(); - - /** - * @brief Constructor. Builds a new ISVBase. - * The Universal Background Model and the matrices U, V and diag(d) are - * not initialized. - * - * @param ubm The Universal Background Model - * @param ru size of U (CD x ru) - * @warning ru SHOULD BE >= 1. - */ - ISVBase(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm, const size_t ru=1); - - /** - * @brief Copy constructor - */ - ISVBase(const ISVBase& other); - - /** - * @deprecated Starts a new JFAMachine from an existing Configuration object. - */ - ISVBase(bob::io::base::HDF5File& config); - - /** - * @brief Just to virtualise the destructor - */ - virtual ~ISVBase(); - - /** - * @brief Assigns from a different JFA machine - */ - ISVBase& operator=(const ISVBase &other); - - /** - * @brief Equal to - */ - bool operator==(const ISVBase& b) const - { return m_base.operator==(b.m_base); } - - /** - * @brief Not equal to - */ - bool operator!=(const ISVBase& b) const - { return m_base.operator!=(b.m_base); } - - /** - * @brief Similar to - */ - bool is_similar_to(const ISVBase& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const - { return m_base.is_similar_to(b.m_base, r_epsilon, a_epsilon); } - - /** - * @brief Saves machine to an HDF5 file - */ - void save(bob::io::base::HDF5File& config) const; - - /** - * @brief Loads data from an existing configuration object. Resets - * the current state. - */ - void load(bob::io::base::HDF5File& config); - - /** - * @brief Returns the UBM - */ - const boost::shared_ptr<bob::learn::em::GMMMachine> getUbm() const - { return m_base.getUbm(); } - - /** - * @brief Returns the U matrix - */ - const blitz::Array<double,2>& getU() const - { return m_base.getU(); } - - /** - * @brief Returns the diagonal matrix diag(d) (as a 1D vector) - */ - const blitz::Array<double,1>& getD() const - { return m_base.getD(); } - - /** - * @brief Returns the number of Gaussian components C - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNGaussians() const - { return m_base.getNGaussians(); } - - /** - * @brief Returns the feature dimensionality D - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNInputs() const - { return m_base.getNInputs(); } - - /** - * @brief Returns the supervector length CD - * (CxD: Number of Gaussian components by the feature dimensionality) - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getSupervectorLength() const - { return m_base.getSupervectorLength(); } - - /** - * @brief Returns the size/rank ru of the U matrix - */ - const size_t getDimRu() const - { return m_base.getDimRu(); } - - /** - * @brief Resets the dimensionality of the subspace U - * U is hence uninitialized. - */ - void resize(const size_t ru) - { m_base.resize(ru, 1); - blitz::Array<double,2>& V = m_base.updateV(); - V = 0; - } - - /** - * @brief Returns the U matrix in order to update it - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - blitz::Array<double,2>& updateU() - { return m_base.updateU(); } - - /** - * @brief Returns the diagonal matrix diag(d) (as a 1D vector) in order - * to update it - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - blitz::Array<double,1>& updateD() - { return m_base.updateD(); } - - - /** - * @brief Sets (the mean supervector of) the Universal Background Model - * U, V and d are uninitialized in case of dimensions update (C or D) - */ - void setUbm(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm) - { m_base.setUbm(ubm); } - - /** - * @brief Sets the U matrix - */ - void setU(const blitz::Array<double,2>& U) - { m_base.setU(U); } - - /** - * @brief Sets the diagonal matrix diag(d) - * (a 1D vector is expected as an argument) - */ - void setD(const blitz::Array<double,1>& d) - { m_base.setD(d); } - - /** - * @brief Estimates x from the GMM statistics considering the LPT - * assumption, that is the latent session variable x is approximated - * using the UBM - */ - void estimateX(const bob::learn::em::GMMStats& gmm_stats, blitz::Array<double,1>& x) const - { m_base.estimateX(gmm_stats, x); } - - /** - * @brief Precompute (put U^{T}.Sigma^{-1} matrix in cache) - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - void precompute() - { m_base.updateCacheUbmUVD(); } - - /** - * @brief Returns the FABase member - */ - const bob::learn::em::FABase& getBase() const - { return m_base; } - - - private: - // FABase - bob::learn::em::FABase m_base; -}; - - -} } } // namespaces - -#endif // BOB_LEARN_EM_JFABASE_H diff --git a/bob/learn/em/include/bob.learn.em/ISVMachine.h b/bob/learn/em/include/bob.learn.em/ISVMachine.h deleted file mode 100644 index f51f4dbf008638e91cd3cc850ba0f9f9e6cff172..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/ISVMachine.h +++ /dev/null @@ -1,237 +0,0 @@ -/** - * @date Tue Jan 27 16:06:00 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief A base class for Joint Factor Analysis-like machines - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_ISVMACHINE_H -#define BOB_LEARN_EM_ISVMACHINE_H - -#include <stdexcept> - -#include <bob.learn.em/ISVBase.h> -#include <bob.learn.em/GMMMachine.h> -#include <bob.learn.em/LinearScoring.h> - -#include <bob.io.base/HDF5File.h> -#include <boost/shared_ptr.hpp> - -namespace bob { namespace learn { namespace em { - - -/** - * @brief A ISVMachine which is associated to a ISVBase that contains - * U D matrices. - * TODO: add a reference to the journal articles - */ -class ISVMachine -{ - public: - /** - * @brief Default constructor. Builds an otherwise invalid 0 x 0 ISVMachine - * The Universal Background Model and the matrices U, V and diag(d) are - * not initialized. - */ - ISVMachine(); - - /** - * @brief Constructor. Builds a new ISVMachine. - * - * @param isv_base The ISVBase associated with this machine - */ - ISVMachine(const boost::shared_ptr<bob::learn::em::ISVBase> isv_base); - - /** - * @brief Copy constructor - */ - ISVMachine(const ISVMachine& other); - - /** - * @brief Starts a new ISVMachine from an existing Configuration object. - */ - ISVMachine(bob::io::base::HDF5File& config); - - /** - * @brief Just to virtualise the destructor - */ - virtual ~ISVMachine(); - - /** - * @brief Assigns from a different ISV machine - */ - ISVMachine& operator=(const ISVMachine &other); - - /** - * @brief Equal to - */ - bool operator==(const ISVMachine& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const ISVMachine& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const ISVMachine& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief Saves machine to an HDF5 file - */ - void save(bob::io::base::HDF5File& config) const; - - /** - * @brief Loads data from an existing configuration object. Resets - * the current state. - */ - void load(bob::io::base::HDF5File& config); - - - /** - * @brief Returns the number of Gaussian components C - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNGaussians() const - { return m_isv_base->getNGaussians(); } - - /** - * @brief Returns the feature dimensionality D - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNInputs() const - { return m_isv_base->getNInputs(); } - - /** - * @brief Returns the supervector length CD - * (CxD: Number of Gaussian components by the feature dimensionality) - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getSupervectorLength() const - { return m_isv_base->getSupervectorLength(); } - - /** - * @brief Returns the size/rank ru of the U matrix - */ - const size_t getDimRu() const - { return m_isv_base->getDimRu(); } - - /** - * @brief Returns the x session factor - */ - const blitz::Array<double,1>& getX() const - { return m_cache_x; } - - /** - * @brief Returns the z speaker factor - */ - const blitz::Array<double,1>& getZ() const - { return m_z; } - - /** - * @brief Returns the z speaker factors in order to update it - */ - blitz::Array<double,1>& updateZ() - { return m_z; } - - /** - * @brief Returns the V matrix - */ - void setZ(const blitz::Array<double,1>& z); - - - /** - * @brief Sets the session variable - */ - void setX(const blitz::Array<double,1>& x); - - - /** - * @brief Returns the ISVBase - */ - const boost::shared_ptr<bob::learn::em::ISVBase> getISVBase() const - { return m_isv_base; } - - /** - * @brief Sets the ISVBase - */ - void setISVBase(const boost::shared_ptr<bob::learn::em::ISVBase> isv_base); - - - /** - * @brief Estimates x from the GMM statistics considering the LPT - * assumption, that is the latent session variable x is approximated - * using the UBM - */ - void estimateX(const bob::learn::em::GMMStats& gmm_stats, blitz::Array<double,1>& x) const - { m_isv_base->estimateX(gmm_stats, x); } - /** - * @brief Estimates Ux from the GMM statistics considering the LPT - * assumption, that is the latent session variable x is approximated - * using the UBM - */ - void estimateUx(const bob::learn::em::GMMStats& gmm_stats, blitz::Array<double,1>& Ux); - - /** - * @brief Execute the machine - * - * @param input input data used by the machine - * @warning Inputs are checked - * @return score value computed by the machine - */ - double forward(const bob::learn::em::GMMStats& input); - /** - * @brief Computes a score for the given UBM statistics and given the - * Ux vector - */ - double forward(const bob::learn::em::GMMStats& gmm_stats, - const blitz::Array<double,1>& Ux); - - /** - * @brief Execute the machine - * - * @param input input data used by the machine - * @warning Inputs are NOT checked - * @return score value computed by the machine - */ - double forward_(const bob::learn::em::GMMStats& input); - - private: - /** - * @brief Resize latent variable according to the ISVBase - */ - void resize(); - /** - * @ Update cache - */ - void updateCache(); - /** - * @brief Resize working arrays - */ - void resizeTmp(); - - // UBM - boost::shared_ptr<bob::learn::em::ISVBase> m_isv_base; - - // y and z vectors/factors learned during the enrollment procedure - blitz::Array<double,1> m_z; - - // cache - blitz::Array<double,1> m_cache_mDz; - mutable blitz::Array<double,1> m_cache_x; - - // x vector/factor in cache when computing scores - mutable blitz::Array<double,1> m_tmp_Ux; -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_ISVMACHINE_H diff --git a/bob/learn/em/include/bob.learn.em/ISVTrainer.h b/bob/learn/em/include/bob.learn.em/ISVTrainer.h deleted file mode 100644 index ae8f0087aa8fe9526719bc8c49d750fc291e2a9b..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/ISVTrainer.h +++ /dev/null @@ -1,166 +0,0 @@ -/** - * @date Tue Jul 19 12:16:17 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief JFA functions - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_ISVTRAINER_H -#define BOB_LEARN_EM_ISVTRAINER_H - -#include <blitz/array.h> -#include <bob.learn.em/GMMStats.h> -#include <bob.learn.em/FABaseTrainer.h> -#include <bob.learn.em/ISVMachine.h> -#include <vector> - -#include <map> -#include <string> -#include <bob.core/array_copy.h> -#include <boost/shared_ptr.hpp> -#include <boost/random.hpp> -#include <bob.core/logging.h> - -namespace bob { namespace learn { namespace em { - -class ISVTrainer -{ - public: - /** - * @brief Constructor - */ - ISVTrainer(const double relevance_factor=4.); - - /** - * @brief Copy onstructor - */ - ISVTrainer(const ISVTrainer& other); - - /** - * @brief Destructor - */ - virtual ~ISVTrainer(); - - /** - * @brief Assignment operator - */ - ISVTrainer& operator=(const ISVTrainer& other); - - /** - * @brief Equal to - */ - bool operator==(const ISVTrainer& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const ISVTrainer& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const ISVTrainer& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief This methods performs some initialization before the EM loop. - */ - virtual void initialize(bob::learn::em::ISVBase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - - /** - * @brief Calculates and saves statistics across the dataset - * The statistics will be used in the mStep() that follows. - */ - virtual void eStep(bob::learn::em::ISVBase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - - /** - * @brief Performs a maximization step to update the parameters of the - * factor analysis model. - */ - virtual void mStep(bob::learn::em::ISVBase& machine); - - /** - * @brief Computes the average log likelihood using the current estimates - * of the latent variables. - */ - virtual double computeLikelihood(bob::learn::em::ISVBase& machine); - - /** - * @brief Enrol a client - */ - void enroll(bob::learn::em::ISVMachine& machine, - const std::vector<boost::shared_ptr<bob::learn::em::GMMStats> >& features, - const size_t n_iter); - - /** - * @brief Get the x speaker factors - */ - const std::vector<blitz::Array<double,2> >& getX() const - { return m_base_trainer.getX(); } - /** - * @brief Get the z speaker factors - */ - const std::vector<blitz::Array<double,1> >& getZ() const - { return m_base_trainer.getZ(); } - /** - * @brief Set the x speaker factors - */ - void setX(const std::vector<blitz::Array<double,2> >& X) - { m_base_trainer.setX(X); } - /** - * @brief Set the z speaker factors - */ - void setZ(const std::vector<blitz::Array<double,1> >& z) - { m_base_trainer.setZ(z); } - - /** - * @brief Getters for the accumulators - */ - const blitz::Array<double,3>& getAccUA1() const - { return m_base_trainer.getAccUA1(); } - const blitz::Array<double,2>& getAccUA2() const - { return m_base_trainer.getAccUA2(); } - - /** - * @brief Setters for the accumulators, Very useful if the e-Step needs - * to be parallelized. - */ - void setAccUA1(const blitz::Array<double,3>& acc) - { m_base_trainer.setAccUA1(acc); } - void setAccUA2(const blitz::Array<double,2>& acc) - { m_base_trainer.setAccUA2(acc); } - - /** - * @brief Sets the Random Number Generator - */ - void setRng(const boost::shared_ptr<boost::mt19937> rng) - { m_rng = rng; } - - /** - * @brief Gets the Random Number Generator - */ - const boost::shared_ptr<boost::mt19937> getRng() const - { return m_rng; } - - - private: - /** - * @brief Initialize D to sqrt(ubm_var/relevance_factor) - */ - void initializeD(bob::learn::em::ISVBase& machine) const; - - // Attributes - bob::learn::em::FABaseTrainer m_base_trainer; - - double m_relevance_factor; - - boost::shared_ptr<boost::mt19937> m_rng; ///< The random number generator for the inialization}; -}; - -} } } // namespaces - -#endif /* BOB_LEARN_EM_ISVTRAINER_H */ diff --git a/bob/learn/em/include/bob.learn.em/IVectorMachine.h b/bob/learn/em/include/bob.learn.em/IVectorMachine.h deleted file mode 100644 index 59c67493a44bfb048feb27dba39b3d18ed0b90bc..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/IVectorMachine.h +++ /dev/null @@ -1,274 +0,0 @@ -/** - * @date Sat Mar 30 20:55:00 2013 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_IVECTOR_MACHINE_H -#define BOB_LEARN_EM_IVECTOR_MACHINE_H - -#include <blitz/array.h> -#include <bob.learn.em/GMMMachine.h> -#include <bob.learn.em/GMMStats.h> -#include <bob.io.base/HDF5File.h> - -namespace bob { namespace learn { namespace em { - -/** - * @brief An IVectorMachine consists of a Total Variability subspace \f$T\f$ - * and allows the extraction of IVector\n - * Reference:\n - * "Front-End Factor Analysis For Speaker Verification", - * N. Dehak, P. Kenny, R. Dehak, P. Dumouchel, P. Ouellet, - * IEEE Trans. on Audio, Speech and Language Processing - */ -class IVectorMachine -{ - public: - /** - * @brief Default constructor. Builds an IVectorMachine. - * The Universal Background Model and the matrices \f$T\f$ and - * \f$diag(\Sigma)\f$ are not initialized. - */ - IVectorMachine(); - - /** - * @brief Constructor. Builds a new IVectorMachine. - * The Universal Background Model and the matrices \f$T\f$ and - * \f$diag(\Sigma)\f$ are not initialized. - * - * @param ubm The Universal Background Model - * @param rt size of \f$T\f$ (CD x rt) - * @param variance_threshold variance flooring threshold for the - * \f$\Sigma\f$ (diagonal) matrix - * @warning rt SHOULD BE >= 1. - */ - IVectorMachine(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm, - const size_t rt=1, const double variance_threshold=1e-10); - - /** - * @brief Copy constructor - */ - IVectorMachine(const IVectorMachine& other); - - /** - * @brief Starts a new IVectorMachine from an existing Configuration object. - */ - IVectorMachine(bob::io::base::HDF5File& config); - - /** - * @brief Destructor - */ - virtual ~IVectorMachine(); - - /** - * @brief Assigns from a different IVectorMachine - */ - IVectorMachine& operator=(const IVectorMachine &other); - - /** - * @brief Equal to - */ - bool operator==(const IVectorMachine& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const IVectorMachine& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const IVectorMachine& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief Saves model to an HDF5 file - */ - void save(bob::io::base::HDF5File& config) const; - - /** - * @brief Loads data from an existing configuration object. Resets - * the current state. - */ - void load(bob::io::base::HDF5File& config); - - /** - * @brief Returns the UBM - */ - const boost::shared_ptr<bob::learn::em::GMMMachine> getUbm() const - { return m_ubm; } - - /** - * @brief Returns the \f$T\f$ matrix - */ - const blitz::Array<double,2>& getT() const - { return m_T; } - - /** - * @brief Returns the \f$\Sigma\f$ (diagonal) matrix as a 1D array - */ - const blitz::Array<double,1>& getSigma() const - { return m_sigma; } - - /** - * @brief Gets the variance flooring threshold - */ - const double getVarianceThreshold() const - { return m_variance_threshold; } - - /** - * @brief Returns the number of Gaussian components C. - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNGaussians() const - { return m_ubm->getNGaussians(); } - - /** - * @brief Returns the feature dimensionality D. - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNInputs() const - { return m_ubm->getNInputs(); } - - /** - * @brief Returns the supervector length CD. - * (CxD: Number of Gaussian components by the feature dimensionality) - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getSupervectorLength() const - { return m_ubm->getNGaussians()*m_ubm->getNInputs(); } - - /** - * @brief Returns the size/rank rt of the \f$T\f$ matrix - */ - const size_t getDimRt() const - { return m_rt; } - - /** - * @brief Resets the dimensionality of the subspace \f$T\f$. - * \f$T\f$ is hence uninitialized. - */ - void resize(const size_t rt); - - /** - * @brief Returns the \f$T\f$ matrix in order to update it. - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - blitz::Array<double,2>& updateT() - { return m_T; } - - /** - * @brief Returns the \f$\Sigma\f$ (diagonal) matrix in order to update it. - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - blitz::Array<double,1>& updateSigma() - { return m_sigma; } - - /** - * @brief Sets (the mean supervector of) the Universal Background Model. - * \f$T\f$ and \f$\Sigma\f$ are uninitialized in case of dimensions update (C or D) - */ - void setUbm(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm); - - /** - * @brief Sets the \f$T\f$ matrix - */ - void setT(const blitz::Array<double,2>& T); - - /** - * @brief Sets the \f$\Sigma\f$ (diagonal) matrix - */ - void setSigma(const blitz::Array<double,1>& sigma); - - /** - * @brief Set the variance flooring threshold - */ - void setVarianceThreshold(const double value); - - /** - * @brief Update arrays in cache - * @warning It is only useful when using updateT() or updateSigma() - * and should mostly be done by trainers - */ - void precompute(); - - /** - * @brief Computes \f$(Id + \sum_{c=1}^{C} N_{i,j,c} T^{T} \Sigma_{c}^{-1} T)\f$ - * @warning No check is perform - */ - void computeIdTtSigmaInvT(const bob::learn::em::GMMStats& input, blitz::Array<double,2>& output) const; - - /** - * @brief Computes \f$T^{T} \Sigma^{-1} \sum_{c=1}^{C} (F_c - N_c ubmmean_{c})\f$ - * @warning No check is perform - */ - void computeTtSigmaInvFnorm(const bob::learn::em::GMMStats& input, blitz::Array<double,1>& output) const; - - /** - * @brief Extracts an ivector from the input GMM statistics - * - * @param input GMM statistics to be used by the machine - * @param output I-vector computed by the machine - */ - void forward(const bob::learn::em::GMMStats& input, blitz::Array<double,1>& output) const; - - /** - * @brief Extracts an ivector from the input GMM statistics - * - * @param input GMM statistics to be used by the machine - * @param output I-vector computed by the machine - * @warning Inputs are NOT checked - */ - void forward_(const bob::learn::em::GMMStats& input, blitz::Array<double,1>& output) const; - - private: - /** - * @brief Apply the variance flooring thresholds. - * This method is called when using setVarianceThresholds() - */ - void applyVarianceThreshold(); - - /** - * @brief Resize cache - */ - void resizeCache(); - /** - * @brief Resize working arrays - */ - void resizeTmp(); - /** - * @brief Resize cache and working arrays before updating cache - */ - void resizePrecompute(); - - // UBM - boost::shared_ptr<bob::learn::em::GMMMachine> m_ubm; - - // dimensionality - size_t m_rt; ///< size of \f$T\f$ (CD x rt) - - ///< \f$T\f$ and \f$Sigma\f$ matrices. - ///< \f$Sigma\f$ is assumed to be diagonal, and only the diagonal is stored - blitz::Array<double,2> m_T; ///< The total variability matrix \f$T\f$ - blitz::Array<double,1> m_sigma; ///< The diagonal covariance matrix \f$\Sigma\f$ - double m_variance_threshold; ///< The variance flooring threshold - - blitz::Array<double,3> m_cache_Tct_sigmacInv; - blitz::Array<double,3> m_cache_Tct_sigmacInv_Tc; - - mutable blitz::Array<double,1> m_tmp_d; - mutable blitz::Array<double,1> m_tmp_t1; - mutable blitz::Array<double,1> m_tmp_t2; - mutable blitz::Array<double,2> m_tmp_tt; -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_IVECTOR_MACHINE_H diff --git a/bob/learn/em/include/bob.learn.em/IVectorTrainer.h b/bob/learn/em/include/bob.learn.em/IVectorTrainer.h deleted file mode 100644 index 0482f1513116289ecf1242bfa20d8e4856d4c7db..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/IVectorTrainer.h +++ /dev/null @@ -1,162 +0,0 @@ -/** - * @date Sat Mar 30 20:55:00 2013 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_IVECTOR_TRAINER_H -#define BOB_LEARN_EM_IVECTOR_TRAINER_H - -#include <blitz/array.h> -#include <bob.learn.em/IVectorMachine.h> -#include <bob.learn.em/GMMStats.h> -#include <boost/shared_ptr.hpp> -#include <vector> -#include <bob.core/array_copy.h> -#include <boost/random.hpp> - -#include <boost/random/mersenne_twister.hpp> - -namespace bob { namespace learn { namespace em { - -/** - * @brief An IVectorTrainer to learn a Total Variability subspace \f$T\f$ - * (and eventually a covariance matrix \f$\Sigma\f$).\n - * Reference:\n - * "Front-End Factor Analysis For Speaker Verification", - * N. Dehak, P. Kenny, R. Dehak, P. Dumouchel, P. Ouellet, - * IEEE Trans. on Audio, Speech and Language Processing - */ -class IVectorTrainer -{ - public: - /** - * @brief Default constructor. Builds an IVectorTrainer - */ - IVectorTrainer(const bool update_sigma=false); - - /** - * @brief Copy constructor - */ - IVectorTrainer(const IVectorTrainer& other); - - /** - * @brief Destructor - */ - virtual ~IVectorTrainer(); - - /** - * @brief Initialization before the EM loop - */ - virtual void initialize(bob::learn::em::IVectorMachine& ivector); - - /** - * @brief Reset the statistics accumulators - * to the correct size and a value of zero. - */ - void resetAccumulators(const bob::learn::em::IVectorMachine& ivector); - - /** - * @brief Calculates statistics across the dataset, - * and saves these as: - * - m_acc_Nij_wij2 - * - m_acc_Fnormij_wij - * - m_acc_Nij (only if update_sigma is enabled) - * - m_acc_Snormij (only if update_sigma is enabled) - * - * These statistics will be used in the mStep() that follows. - */ - virtual void eStep(bob::learn::em::IVectorMachine& ivector, - const std::vector<bob::learn::em::GMMStats>& data); - - /** - * @brief Maximisation step: Update the Total Variability matrix \f$T\f$ - * and \f$\Sigma\f$ if update_sigma is enabled. - */ - virtual void mStep(bob::learn::em::IVectorMachine& ivector); - - - /** - * @brief Assigns from a different IVectorTrainer - */ - IVectorTrainer& operator=(const IVectorTrainer &other); - - /** - * @brief Equal to - */ - bool operator==(const IVectorTrainer& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const IVectorTrainer& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const IVectorTrainer& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief Getters for the accumulators - */ - const blitz::Array<double,3>& getAccNijWij2() const - { return m_acc_Nij_wij2; } - const blitz::Array<double,3>& getAccFnormijWij() const - { return m_acc_Fnormij_wij; } - const blitz::Array<double,1>& getAccNij() const - { return m_acc_Nij; } - const blitz::Array<double,2>& getAccSnormij() const - { return m_acc_Snormij; } - - /** - * @brief Setters for the accumulators, Very useful if the e-Step needs - * to be parallelized. - */ - void setAccNijWij2(const blitz::Array<double,3>& acc) - { bob::core::array::assertSameShape(acc, m_acc_Nij_wij2); - m_acc_Nij_wij2 = acc; } - void setAccFnormijWij(const blitz::Array<double,3>& acc) - { bob::core::array::assertSameShape(acc, m_acc_Fnormij_wij); - m_acc_Fnormij_wij = acc; } - void setAccNij(const blitz::Array<double,1>& acc) - { bob::core::array::assertSameShape(acc, m_acc_Nij); - m_acc_Nij = acc; } - void setAccSnormij(const blitz::Array<double,2>& acc) - { bob::core::array::assertSameShape(acc, m_acc_Snormij); - m_acc_Snormij = acc; } - - void setRng(boost::shared_ptr<boost::mt19937> rng){ - m_rng = rng; - }; - - protected: - // Attributes - bool m_update_sigma; - - // Acccumulators - blitz::Array<double,3> m_acc_Nij_wij2; - blitz::Array<double,3> m_acc_Fnormij_wij; - blitz::Array<double,1> m_acc_Nij; - blitz::Array<double,2> m_acc_Snormij; - - // Working arrays - mutable blitz::Array<double,1> m_tmp_wij; - mutable blitz::Array<double,2> m_tmp_wij2; - mutable blitz::Array<double,1> m_tmp_d1; - mutable blitz::Array<double,1> m_tmp_t1; - mutable blitz::Array<double,2> m_tmp_dd1; - mutable blitz::Array<double,2> m_tmp_dt1; - mutable blitz::Array<double,2> m_tmp_tt1; - mutable blitz::Array<double,2> m_tmp_tt2; - - /** - * @brief The random number generator for the inialization - */ - boost::shared_ptr<boost::mt19937> m_rng; -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_IVECTOR_TRAINER_H diff --git a/bob/learn/em/include/bob.learn.em/JFABase.h b/bob/learn/em/include/bob.learn.em/JFABase.h deleted file mode 100644 index c75cec864187c46a1648e6a7288188c1a2754929..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/JFABase.h +++ /dev/null @@ -1,253 +0,0 @@ -/** - * @date Tue Jan 27 15:54:00 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief A base class for Joint Factor Analysis-like machines - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_JFABASE_H -#define BOB_LEARN_EM_JFABASE_H - -#include <stdexcept> - -#include <bob.learn.em/GMMMachine.h> -#include <bob.learn.em/FABase.h> -//#include <bob.learn.em/LinearScoring.h> - -#include <bob.io.base/HDF5File.h> -#include <boost/shared_ptr.hpp> - -namespace bob { namespace learn { namespace em { - - -/** - * @brief A JFA Base class which contains U, V and D matrices - * TODO: add a reference to the journal articles - */ -class JFABase -{ - public: - /** - * @brief Default constructor. Builds a 1 x 1 JFABase - * The Universal Background Model and the matrices U, V and diag(d) are - * not initialized. - */ - JFABase(); - - /** - * @brief Constructor. Builds a new JFABase. - * The Universal Background Model and the matrices U, V and diag(d) are - * not initialized. - * - * @param ubm The Universal Background Model - * @param ru size of U (CD x ru) - * @param rv size of U (CD x rv) - * @warning ru and rv SHOULD BE >= 1. - */ - JFABase(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm, const size_t ru=1, const size_t rv=1); - - /** - * @brief Copy constructor - */ - JFABase(const JFABase& other); - - /** - * @deprecated Starts a new JFAMachine from an existing Configuration object. - */ - JFABase(bob::io::base::HDF5File& config); - - /** - * @brief Just to virtualise the destructor - */ - virtual ~JFABase(); - - /** - * @brief Assigns from a different JFA machine - */ - JFABase& operator=(const JFABase &other); - - /** - * @brief Equal to - */ - bool operator==(const JFABase& b) const - { return m_base.operator==(b.m_base); } - - /** - * @brief Not equal to - */ - bool operator!=(const JFABase& b) const - { return m_base.operator!=(b.m_base); } - - /** - * @brief Similar to - */ - bool is_similar_to(const JFABase& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const - { return m_base.is_similar_to(b.m_base, r_epsilon, a_epsilon); } - - /** - * @brief Saves model to an HDF5 file - */ - void save(bob::io::base::HDF5File& config) const; - - /** - * @brief Loads data from an existing configuration object. Resets - * the current state. - */ - void load(bob::io::base::HDF5File& config); - - /** - * @brief Returns the UBM - */ - const boost::shared_ptr<bob::learn::em::GMMMachine> getUbm() const - { return m_base.getUbm(); } - - /** - * @brief Returns the U matrix - */ - const blitz::Array<double,2>& getU() const - { return m_base.getU(); } - - /** - * @brief Returns the V matrix - */ - const blitz::Array<double,2>& getV() const - { return m_base.getV(); } - - /** - * @brief Returns the diagonal matrix diag(d) (as a 1D vector) - */ - const blitz::Array<double,1>& getD() const - { return m_base.getD(); } - - /** - * @brief Returns the number of Gaussian components - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNGaussians() const - { return m_base.getNGaussians();} - - /** - * @brief Returns the feature dimensionality D - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNInputs() const - { return m_base.getNInputs(); } - - /** - * @brief Returns the supervector length CD - * (CxD: Number of Gaussian components by the feature dimensionality) - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getSupervectorLength() const - { return m_base.getSupervectorLength(); } - - /** - * @brief Returns the size/rank ru of the U matrix - */ - const size_t getDimRu() const - { return m_base.getDimRu(); } - - /** - * @brief Returns the size/rank rv of the V matrix - */ - const size_t getDimRv() const - { return m_base.getDimRv(); } - - /** - * @brief Resets the dimensionality of the subspace U and V - * U and V are hence uninitialized. - */ - void resize(const size_t ru, const size_t rv) - { m_base.resize(ru, rv); } - - /** - * @brief Returns the U matrix in order to update it - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - blitz::Array<double,2>& updateU() - { return m_base.updateU(); } - - /** - * @brief Returns the V matrix in order to update it - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - blitz::Array<double,2>& updateV() - { return m_base.updateV(); } - - /** - * @brief Returns the diagonal matrix diag(d) (as a 1D vector) in order - * to update it - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - blitz::Array<double,1>& updateD() - { return m_base.updateD(); } - - - /** - * @brief Sets (the mean supervector of) the Universal Background Model - * U, V and d are uninitialized in case of dimensions update (C or D) - */ - void setUbm(const boost::shared_ptr<bob::learn::em::GMMMachine> ubm) - { m_base.setUbm(ubm); } - - /** - * @brief Sets the U matrix - */ - void setU(const blitz::Array<double,2>& U) - { m_base.setU(U); } - - /** - * @brief Sets the V matrix - */ - void setV(const blitz::Array<double,2>& V) - { m_base.setV(V); } - - /** - * @brief Sets the diagonal matrix diag(d) - * (a 1D vector is expected as an argument) - */ - void setD(const blitz::Array<double,1>& d) - { m_base.setD(d); } - - /** - * @brief Estimates x from the GMM statistics considering the LPT - * assumption, that is the latent session variable x is approximated - * using the UBM - */ - void estimateX(const bob::learn::em::GMMStats& gmm_stats, blitz::Array<double,1>& x) const - { m_base.estimateX(gmm_stats, x); } - - /** - * @brief Precompute (put U^{T}.Sigma^{-1} matrix in cache) - * @warning Should only be used by the trainer for efficiency reason, - * or for testing purpose. - */ - void precompute() - { m_base.updateCacheUbmUVD(); } - - /** - * @brief Returns the FABase member - */ - const bob::learn::em::FABase& getBase() const - { return m_base; } - - - private: - // FABase - bob::learn::em::FABase m_base; -}; - - -} } } // namespaces - -#endif // BOB_LEARN_EM_JFABASE_H diff --git a/bob/learn/em/include/bob.learn.em/JFAMachine.h b/bob/learn/em/include/bob.learn.em/JFAMachine.h deleted file mode 100644 index 51649fef10d089d4055b87f33ba3a0d53e861335..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/JFAMachine.h +++ /dev/null @@ -1,254 +0,0 @@ -/** - * @date Tue Jan 27 16:47:00 2015 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief A base class for Joint Factor Analysis-like machines - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_JFAMACHINE_H -#define BOB_LEARN_EM_JFAMACHINE_H - -#include <stdexcept> - -#include <bob.learn.em/JFABase.h> -#include <bob.learn.em/GMMMachine.h> -#include <bob.learn.em/LinearScoring.h> - -#include <bob.io.base/HDF5File.h> -#include <boost/shared_ptr.hpp> - -namespace bob { namespace learn { namespace em { - - -/** - * @brief A JFAMachine which is associated to a JFABase that contains - * U, V and D matrices. The JFAMachine describes the identity part - * (latent variables y and z) - * TODO: add a reference to the journal articles - */ -class JFAMachine -{ - public: - /** - * @brief Default constructor. Builds an otherwise invalid 0 x 0 JFAMachine - * The Universal Background Model and the matrices U, V and diag(d) are - * not initialized. - */ - JFAMachine(); - - /** - * @brief Constructor. Builds a new JFAMachine. - * - * @param jfa_base The JFABase associated with this machine - */ - JFAMachine(const boost::shared_ptr<bob::learn::em::JFABase> jfa_base); - - /** - * @brief Copy constructor - */ - JFAMachine(const JFAMachine& other); - - /** - * @deprecated Starts a new JFAMachine from an existing Configuration object. - */ - JFAMachine(bob::io::base::HDF5File& config); - - /** - * @brief Just to virtualise the destructor - */ - virtual ~JFAMachine(); - - /** - * @brief Assigns from a different JFA machine - */ - JFAMachine& operator=(const JFAMachine &other); - - /** - * @brief Equal to - */ - bool operator==(const JFAMachine& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const JFAMachine& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const JFAMachine& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief Saves machine to an HDF5 file - */ - void save(bob::io::base::HDF5File& config) const; - - /** - * @brief Loads data from an existing configuration object. Resets - * the current state. - */ - void load(bob::io::base::HDF5File& config); - - /** - * @brief Returns the number of Gaussian components C - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNGaussians() const - { return m_jfa_base->getNGaussians(); } - - /** - * @brief Returns the feature dimensionality D - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getNInputs() const - { return m_jfa_base->getNInputs(); } - - /** - * @brief Returns the supervector length CD - * (CxD: Number of Gaussian components by the feature dimensionality) - * @warning An exception is thrown if no Universal Background Model has - * been set yet. - */ - const size_t getSupervectorLength() const - { return m_jfa_base->getSupervectorLength(); } - - /** - * @brief Returns the size/rank ru of the U matrix - */ - const size_t getDimRu() const - { return m_jfa_base->getDimRu(); } - - /** - * @brief Returns the size/rank rv of the V matrix - */ - const size_t getDimRv() const - { return m_jfa_base->getDimRv(); } - - /** - * @brief Returns the x session factor - */ - const blitz::Array<double,1>& getX() const - { return m_cache_x; } - - /** - * @brief Returns the y speaker factor - */ - const blitz::Array<double,1>& getY() const - { return m_y; } - - /** - * @brief Returns the z speaker factor - */ - const blitz::Array<double,1>& getZ() const - { return m_z; } - - /** - * @brief Returns the y speaker factors in order to update it - */ - blitz::Array<double,1>& updateY() - { return m_y; } - - /** - * @brief Returns the z speaker factors in order to update it - */ - blitz::Array<double,1>& updateZ() - { return m_z; } - - /** - * @brief Returns the y speaker factors - */ - void setY(const blitz::Array<double,1>& y); - - /** - * @brief Returns the V matrix - */ - void setZ(const blitz::Array<double,1>& z); - - /** - * @brief Returns the JFABase - */ - const boost::shared_ptr<bob::learn::em::JFABase> getJFABase() const - { return m_jfa_base; } - - /** - * @brief Sets the JFABase - */ - void setJFABase(const boost::shared_ptr<bob::learn::em::JFABase> jfa_base); - - - /** - * @brief Estimates x from the GMM statistics considering the LPT - * assumption, that is the latent session variable x is approximated - * using the UBM - */ - void estimateX(const bob::learn::em::GMMStats& gmm_stats, blitz::Array<double,1>& x) const - { m_jfa_base->estimateX(gmm_stats, x); } - /** - * @brief Estimates Ux from the GMM statistics considering the LPT - * assumption, that is the latent session variable x is approximated - * using the UBM - */ - void estimateUx(const bob::learn::em::GMMStats& gmm_stats, blitz::Array<double,1>& Ux); - - /** - * @brief Execute the machine - * - * @param input input data used by the machine - * @warning Inputs are checked - * @return score value computed by the machine - */ - double forward(const bob::learn::em::GMMStats& input); - /** - * @brief Computes a score for the given UBM statistics and given the - * Ux vector - */ - double forward(const bob::learn::em::GMMStats& gmm_stats, - const blitz::Array<double,1>& Ux); - - /** - * @brief Execute the machine - * - * @param input input data used by the machine - * @param score value computed by the machine - * @warning Inputs are NOT checked - */ - double forward_(const bob::learn::em::GMMStats& input); - - private: - /** - * @brief Resize latent variable according to the JFABase - */ - void resize(); - /** - * @brief Resize working arrays - */ - void resizeTmp(); - /** - * @brief Update the cache - */ - void updateCache(); - - // UBM - boost::shared_ptr<bob::learn::em::JFABase> m_jfa_base; - - // y and z vectors/factors learned during the enrollment procedure - blitz::Array<double,1> m_y; - blitz::Array<double,1> m_z; - - // cache - blitz::Array<double,1> m_cache_mVyDz; - mutable blitz::Array<double,1> m_cache_x; - - // x vector/factor in cache when computing scores - mutable blitz::Array<double,1> m_tmp_Ux; -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_JFAMACHINE_H diff --git a/bob/learn/em/include/bob.learn.em/JFATrainer.h b/bob/learn/em/include/bob.learn.em/JFATrainer.h deleted file mode 100644 index d697442edceb4f970bb97309d36abda00ce38e23..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/JFATrainer.h +++ /dev/null @@ -1,238 +0,0 @@ -/** - * @date Tue Jul 19 12:16:17 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief JFA functions - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_JFATRAINER_H -#define BOB_LEARN_EM_JFATRAINER_H - -#include <blitz/array.h> -#include <bob.learn.em/GMMStats.h> -#include <bob.learn.em/FABaseTrainer.h> -#include <bob.learn.em/JFAMachine.h> -#include <vector> - -#include <map> -#include <string> -#include <bob.core/array_copy.h> -#include <boost/shared_ptr.hpp> -#include <boost/random.hpp> -#include <bob.core/logging.h> - -namespace bob { namespace learn { namespace em { - -class JFATrainer -{ - public: - /** - * @brief Constructor - */ - JFATrainer(); - - /** - * @brief Copy onstructor - */ - JFATrainer(const JFATrainer& other); - - /** - * @brief Destructor - */ - virtual ~JFATrainer(); - - /** - * @brief Assignment operator - */ - JFATrainer& operator=(const JFATrainer& other); - - /** - * @brief Equal to - */ - bool operator==(const JFATrainer& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const JFATrainer& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const JFATrainer& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief Sets the maximum number of EM-like iterations (for each subspace) - */ - //void setMaxIterations(const size_t max_iterations) - //{ m_max_iterations = max_iterations; } - - /** - * @brief Gets the maximum number of EM-like iterations (for each subspace) - */ - //size_t getMaxIterations() const - //{ return m_max_iterations; } - - /** - * @brief This methods performs some initialization before the EM loop. - */ - virtual void initialize(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - - /** - * @brief This methods performs the e-Step to train the first subspace V - */ - virtual void eStep1(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - /** - * @brief This methods performs the m-Step to train the first subspace V - */ - virtual void mStep1(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - /** - * @brief This methods performs the finalization after training the first - * subspace V - */ - virtual void finalize1(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - /** - * @brief This methods performs the e-Step to train the second subspace U - */ - virtual void eStep2(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - /** - * @brief This methods performs the m-Step to train the second subspace U - */ - virtual void mStep2(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - /** - * @brief This methods performs the finalization after training the second - * subspace U - */ - virtual void finalize2(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - /** - * @brief This methods performs the e-Step to train the third subspace d - */ - virtual void eStep3(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - /** - * @brief This methods performs the m-Step to train the third subspace d - */ - virtual void mStep3(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - /** - * @brief This methods performs the finalization after training the third - * subspace d - */ - virtual void finalize3(bob::learn::em::JFABase& machine, - const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - - /** - * @brief This methods performs the main loops to train the subspaces U, V and d - */ - //virtual void train_loop(bob::learn::em::JFABase& machine, - //const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - /** - * @brief This methods trains the subspaces U, V and d - */ - //virtual void train(bob::learn::em::JFABase& machine, - //const std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& ar); - - /** - * @brief Enrol a client - */ - void enroll(bob::learn::em::JFAMachine& machine, - const std::vector<boost::shared_ptr<bob::learn::em::GMMStats> >& features, - const size_t n_iter); - - /** - * @brief Sets the Random Number Generator - */ - void setRng(const boost::shared_ptr<boost::mt19937> rng) - { m_rng = rng; } - - /** - * @brief Gets the Random Number Generator - */ - const boost::shared_ptr<boost::mt19937> getRng() const - { return m_rng; } - - /** - * @brief Get the x speaker factors - */ - const std::vector<blitz::Array<double,2> >& getX() const - { return m_base_trainer.getX(); } - /** - * @brief Get the y speaker factors - */ - const std::vector<blitz::Array<double,1> >& getY() const - { return m_base_trainer.getY(); } - /** - * @brief Get the z speaker factors - */ - const std::vector<blitz::Array<double,1> >& getZ() const - { return m_base_trainer.getZ(); } - /** - * @brief Set the x speaker factors - */ - void setX(const std::vector<blitz::Array<double,2> >& X) - { m_base_trainer.setX(X); } - /** - * @brief Set the y speaker factors - */ - void setY(const std::vector<blitz::Array<double,1> >& y) - { m_base_trainer.setY(y); } - /** - * @brief Set the z speaker factors - */ - void setZ(const std::vector<blitz::Array<double,1> >& z) - { m_base_trainer.setZ(z); } - - /** - * @brief Getters for the accumulators - */ - const blitz::Array<double,3>& getAccVA1() const - { return m_base_trainer.getAccVA1(); } - const blitz::Array<double,2>& getAccVA2() const - { return m_base_trainer.getAccVA2(); } - const blitz::Array<double,3>& getAccUA1() const - { return m_base_trainer.getAccUA1(); } - const blitz::Array<double,2>& getAccUA2() const - { return m_base_trainer.getAccUA2(); } - const blitz::Array<double,1>& getAccDA1() const - { return m_base_trainer.getAccDA1(); } - const blitz::Array<double,1>& getAccDA2() const - { return m_base_trainer.getAccDA2(); } - - /** - * @brief Setters for the accumulators, Very useful if the e-Step needs - * to be parallelized. - */ - void setAccVA1(const blitz::Array<double,3>& acc) - { m_base_trainer.setAccVA1(acc); } - void setAccVA2(const blitz::Array<double,2>& acc) - { m_base_trainer.setAccVA2(acc); } - void setAccUA1(const blitz::Array<double,3>& acc) - { m_base_trainer.setAccUA1(acc); } - void setAccUA2(const blitz::Array<double,2>& acc) - { m_base_trainer.setAccUA2(acc); } - void setAccDA1(const blitz::Array<double,1>& acc) - { m_base_trainer.setAccDA1(acc); } - void setAccDA2(const blitz::Array<double,1>& acc) - { m_base_trainer.setAccDA2(acc); } - - - private: - // Attributes - //size_t m_max_iterations; - boost::shared_ptr<boost::mt19937> m_rng; ///< The random number generator for the inialization - bob::learn::em::FABaseTrainer m_base_trainer; -}; - -} } } // namespaces - -#endif /* BOB_LEARN_EM_JFATRAINER_H */ diff --git a/bob/learn/em/include/bob.learn.em/KMeansMachine.h b/bob/learn/em/include/bob.learn.em/KMeansMachine.h deleted file mode 100644 index 2c8113a6a06644b7af2f6839e76106da8de930bf..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/KMeansMachine.h +++ /dev/null @@ -1,244 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ -#ifndef BOB_LEARN_EM_KMEANSMACHINE_H -#define BOB_LEARN_EM_KMEANSMACHINE_H - -#include <blitz/array.h> -#include <cfloat> - -#include <bob.io.base/HDF5File.h> - -namespace bob { namespace learn { namespace em { - -/** - * @brief This class implements a k-means classifier. - * @details See Section 9.1 of Bishop, "Pattern recognition and machine learning", 2006 - */ -class KMeansMachine { - public: - /** - * Default constructor. Builds an otherwise invalid 0 x 0 k-means - * machine. This is equivalent to construct a LinearMachine with two - * size_t parameters set to 0, as in LinearMachine(0, 0). - */ - KMeansMachine(); - - /** - * Constructor - * @param[in] n_means The number of means - * @param[in] n_inputs The feature dimensionality - */ - KMeansMachine(const size_t n_means, const size_t n_inputs); - - /** - * Builds a new machine with the given means. Each row of the means - * matrix should represent a mean. - */ - KMeansMachine(const blitz::Array<double,2>& means); - - /** - * Copies another machine (copy constructor) - */ - KMeansMachine(const KMeansMachine& other); - - /** - * Starts a new KMeansMachine from an existing Configuration object. - */ - KMeansMachine(bob::io::base::HDF5File& config); - - /** - * Destructor - */ - virtual ~KMeansMachine(); - - /** - * Assigns from a different machine - */ - KMeansMachine& operator=(const KMeansMachine& other); - - /** - * Equal to - */ - bool operator==(const KMeansMachine& b) const; - - /** - * Not equal to - */ - bool operator!=(const KMeansMachine& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const KMeansMachine& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * Loads data from an existing configuration object. Resets the current - * state. - */ - void load(bob::io::base::HDF5File& config); - - /** - * Saves an existing machine to a Configuration object. - */ - void save(bob::io::base::HDF5File& config) const; - - /** - * Output the minimum (Square Euclidean) distance between the input and - * one of the means (overrides Machine::forward) - */ - void forward(const blitz::Array<double,1>& input, double& output) const; - - /** - * Output the minimum (Square Euclidean) distance between the input and - * one of the means (overrides Machine::forward_) - * @warning Inputs are NOT checked - */ - void forward_(const blitz::Array<double,1>& input, double& output) const; - - - /** - * Set the means - */ - void setMeans(const blitz::Array<double,2>& means); - - /** - * Set the i'th mean - */ - void setMean(const size_t i, const blitz::Array<double,1>& mean); - - /** - * Get a mean - * @param[in] i The index of the mean - * @param[out] mean The mean, a 1D array, with a length equal to the number of feature dimensions. - */ - const blitz::Array<double,1> getMean(const size_t i) const; - - /** - * Get the means (i.e. a 2D array, with as many rows as means, and as - * many columns as feature dimensions.) - */ - const blitz::Array<double,2>& getMeans() const - { return m_means; } - - /** - * Get the means in order to be updated (i.e. a 2D array, with as many - * rows as means, and as many columns as feature dimensions.) - * @warning Only trainers should use this function for efficiency reasons - */ - blitz::Array<double,2>& updateMeans() - { return m_means; } - - /** - * Return the power of two of the (Square Euclidean) distance of the - * sample, x, to the i'th mean - * @param x The data sample (feature vector) - * @param i The index of the mean - */ - double getDistanceFromMean(const blitz::Array<double,1>& x, - const size_t i) const; - - /** - * Calculate the index of the mean that is closest - * (in terms of Square Euclidean distance) to the data sample, x - * @param x The data sample (feature vector) - * @param closest_mean (output) The index of the mean closest to the sample - * @param min_distance (output) The distance of the sample from the closest mean - */ - void getClosestMean(const blitz::Array<double,1>& x, - size_t &closest_mean, double &min_distance) const; - - /** - * Output the minimum (Square Euclidean) distance between the input and - * one of the means - */ - double getMinDistance(const blitz::Array<double,1>& input) const; - - /** - * For each mean, find the subset of the samples - * that is closest to that mean, and calculate - * 1) the variance of that subset (the cluster variance) - * 2) the proportion of the samples represented by that subset (the cluster weight) - * @param[in] data The data - * @param[out] variances The cluster variances (one row per cluster), - * with as many columns as feature dimensions. - * @param[out] weights A vector of weights, one per cluster - */ - void getVariancesAndWeightsForEachCluster(const blitz::Array<double,2> &data, blitz::Array<double,2>& variances, blitz::Array<double,1>& weights) const; - /** - * Methods consecutively called by getVariancesAndWeightsForEachCluster() - * This should help for the parallelization on several nodes by splitting the data and calling - * getVariancesAndWeightsForEachClusterAcc() for each split. In this case, there is a need to sum - * with the m_cache_means, variances, and weights variables before performing the merge on one - * node using getVariancesAndWeightsForEachClusterFin(). - */ - void getVariancesAndWeightsForEachClusterInit(blitz::Array<double,2>& variances, blitz::Array<double,1>& weights) const; - void getVariancesAndWeightsForEachClusterAcc(const blitz::Array<double,2> &data, blitz::Array<double,2>& variances, blitz::Array<double,1>& weights) const; - void getVariancesAndWeightsForEachClusterFin(blitz::Array<double,2>& variances, blitz::Array<double,1>& weights) const; - - /** - * Get the m_cache_means array. - * @warning This variable should only be used in the case you want to parallelize the - * getVariancesAndWeightsForEachCluster() method! - */ - const blitz::Array<double,2>& getCacheMeans() const - { return m_cache_means; } - - /** - * Set the m_cache_means array. - * @warning This variable should only be used in the case you want to parallelize the - * getVariancesAndWeightsForEachCluster() method! - */ - void setCacheMeans(const blitz::Array<double,2>& cache_means); - - /** - * Resize the means - */ - void resize(const size_t n_means, const size_t n_inputs); - - /** - * Return the number of means - */ - size_t getNMeans() const { return m_n_means; } - - /** - * Return the number of inputs - */ - size_t getNInputs() const { return m_n_inputs; } - - /** - * Prints a KMeansMachine in the output stream - */ - friend std::ostream& operator<<(std::ostream& os, const KMeansMachine& km); - - - private: - /** - * The number of means - */ - size_t m_n_means; - - /** - * The number of inputs - */ - size_t m_n_inputs; - - /** - * The means (each row is a mean) - */ - blitz::Array<double,2> m_means; - - /** - * cache to avoid re-allocation - */ - mutable blitz::Array<double,2> m_cache_means; -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_KMEANSMACHINE_H diff --git a/bob/learn/em/include/bob.learn.em/KMeansTrainer.h b/bob/learn/em/include/bob.learn.em/KMeansTrainer.h deleted file mode 100644 index 58bf1bedaff51a3413c5b75cf52a1314e7626a52..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/KMeansTrainer.h +++ /dev/null @@ -1,181 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ -#ifndef BOB_LEARN_EM_KMEANSTRAINER_H -#define BOB_LEARN_EM_KMEANSTRAINER_H - -#include <bob.learn.em/KMeansMachine.h> -#include <boost/version.hpp> -#include <boost/random/mersenne_twister.hpp> - -namespace bob { namespace learn { namespace em { - -/** - * Trains a KMeans machine. - * @brief This class implements the expectation-maximisation algorithm for a k-means machine. - * @details See Section 9.1 of Bishop, "Pattern recognition and machine learning", 2006 - * It uses a random initialisation of the means followed by the expectation-maximization algorithm - */ -class KMeansTrainer -{ - public: - /** - * @brief This enumeration defines different initialization methods for - * K-means - */ - typedef enum { - RANDOM=0, - RANDOM_NO_DUPLICATE -#if BOOST_VERSION >= 104700 - , - KMEANS_PLUS_PLUS -#endif - } - InitializationMethod; - - /** - * @brief Constructor - */ - KMeansTrainer(InitializationMethod=RANDOM_NO_DUPLICATE); - - /** - * @brief Virtualize destructor - */ - virtual ~KMeansTrainer() {} - - /** - * @brief Copy constructor - */ - KMeansTrainer(const KMeansTrainer& other); - - /** - * @brief Assigns from a different machine - */ - KMeansTrainer& operator=(const KMeansTrainer& other); - - /** - * @brief Equal to - */ - bool operator==(const KMeansTrainer& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const KMeansTrainer& b) const; - - /** - * @brief The name for this trainer - */ - virtual std::string name() const { return "KMeansTrainer"; } - - /** - * @brief Initialise the means randomly. - * Data is split into as many chunks as there are means, - * then each mean is set to a random example within each chunk. - */ - void initialize(bob::learn::em::KMeansMachine& kMeansMachine, - const blitz::Array<double,2>& sampler); - - /** - * @brief Accumulate across the dataset: - * - zeroeth and first order statistics - * - average (Square Euclidean) distance from the closest mean - * Implements EMTrainer::eStep(double &) - */ - void eStep(bob::learn::em::KMeansMachine& kmeans, - const blitz::Array<double,2>& data); - - /** - * @brief Updates the mean based on the statistics from the E-step. - */ - void mStep(bob::learn::em::KMeansMachine& kmeans); - - /** - * @brief This functions returns the average min (Square Euclidean) - * distance (average distance to the closest mean) - */ - double computeLikelihood(bob::learn::em::KMeansMachine& kmeans); - - - /** - * @brief Reset the statistics accumulators - * to the correct size and a value of zero. - */ - void resetAccumulators(bob::learn::em::KMeansMachine& kMeansMachine); - - /** - * @brief Sets the Random Number Generator - */ - void setRng(const boost::shared_ptr<boost::mt19937> rng) - { m_rng = rng; } - - /** - * @brief Gets the Random Number Generator - */ - const boost::shared_ptr<boost::mt19937> getRng() const - { return m_rng; } - - /** - * @brief Sets the initialization method used to generate the initial means - */ - void setInitializationMethod(InitializationMethod v) { m_initialization_method = v; } - - /** - * @brief Gets the initialization method used to generate the initial means - */ - InitializationMethod getInitializationMethod() const { return m_initialization_method; } - - /** - * @brief Returns the internal statistics. Useful to parallelize the E-step - */ - const blitz::Array<double,1>& getZeroethOrderStats() const { return m_zeroethOrderStats; } - const blitz::Array<double,2>& getFirstOrderStats() const { return m_firstOrderStats; } - double getAverageMinDistance() const { return m_average_min_distance; } - /** - * @brief Sets the internal statistics. Useful to parallelize the E-step - */ - void setZeroethOrderStats(const blitz::Array<double,1>& zeroethOrderStats); - void setFirstOrderStats(const blitz::Array<double,2>& firstOrderStats); - void setAverageMinDistance(const double value) { m_average_min_distance = value; } - - - private: - - /** - * @brief The initialization method - * Check that there is no duplicated means during the random initialization - */ - InitializationMethod m_initialization_method; - - /** - * @brief The random number generator for the inialization - */ - boost::shared_ptr<boost::mt19937> m_rng; - - /** - * @brief Average min (Square Euclidean) distance - */ - double m_average_min_distance; - - /** - * @brief Zeroeth order statistics accumulator. - * The k'th value in m_zeroethOrderStats is the denominator of - * equation 9.4, Bishop, "Pattern recognition and machine learning", 2006 - */ - blitz::Array<double,1> m_zeroethOrderStats; - - /** - * @brief First order statistics accumulator. - * The k'th row of m_firstOrderStats is the numerator of - * equation 9.4, Bishop, "Pattern recognition and machine learning", 2006 - */ - blitz::Array<double,2> m_firstOrderStats; -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_KMEANSTRAINER_H diff --git a/bob/learn/em/include/bob.learn.em/LinearScoring.h b/bob/learn/em/include/bob.learn.em/LinearScoring.h deleted file mode 100644 index 822922ceefbbd8a5069fb77f6a788cf63dd617e9..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/LinearScoring.h +++ /dev/null @@ -1,98 +0,0 @@ -/** - * @date Wed Jul 13 16:00:04 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ -#ifndef BOB_LEARN_EM_LINEARSCORING_H -#define BOB_LEARN_EM_LINEARSCORING_H - -#include <blitz/array.h> -#include <boost/shared_ptr.hpp> -#include <vector> -#include <bob.learn.em/GMMMachine.h> - -namespace bob { namespace learn { namespace em { - -/** - * Compute a matrix of scores using linear scoring. - * - * @warning Each GMM must have the same size. - * - * @param models list of mean supervector for the client models - * @param ubm_mean mean supervector of the world model - * @param ubm_variance variance supervector of the world model - * @param test_stats list of accumulate statistics for each test trial - * @param test_channelOffset list of channel offset if any (for JFA/ISA for instance) - * @param frame_length_normalisation perform a normalisation by the number of feature vectors - * @param[out] scores 2D matrix of scores, <tt>scores[m, s]</tt> is the score for model @c m against statistics @c s - * @warning the output scores matrix should have the correct size (number of models x number of test_stats) - */ -void linearScoring(const std::vector<blitz::Array<double,1> >& models, - const blitz::Array<double,1>& ubm_mean, const blitz::Array<double,1>& ubm_variance, - const std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> >& test_stats, - const std::vector<blitz::Array<double, 1> >& test_channelOffset, - const bool frame_length_normalisation, - blitz::Array<double,2>& scores); -void linearScoring(const std::vector<blitz::Array<double,1> >& models, - const blitz::Array<double,1>& ubm_mean, const blitz::Array<double,1>& ubm_variance, - const std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> >& test_stats, - const bool frame_length_normalisation, - blitz::Array<double,2>& scores); - -/** - * Compute a matrix of scores using linear scoring. - * - * @warning Each GMM must have the same size. - * - * @param models list of client models as GMMMachines - * @param ubm world model as a GMMMachine - * @param test_stats list of accumulate statistics for each test trial - * @param frame_length_normalisation perform a normalisation by the number of feature vectors - * @param[out] scores 2D matrix of scores, <tt>scores[m, s]</tt> is the score for model @c m against statistics @c s - * @warning the output scores matrix should have the correct size (number of models x number of test_stats) - */ -void linearScoring(const std::vector<boost::shared_ptr<const bob::learn::em::GMMMachine> >& models, - const bob::learn::em::GMMMachine& ubm, - const std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> >& test_stats, - const bool frame_length_normalisation, - blitz::Array<double,2>& scores); -/** - * Compute a matrix of scores using linear scoring. - * - * @warning Each GMM must have the same size. - * - * @param models list of client models as GMMMachines - * @param ubm world model as a GMMMachine - * @param test_stats list of accumulate statistics for each test trial - * @param test_channelOffset list of channel offset if any (for JFA/ISA for instance) - * @param frame_length_normalisation perform a normalisation by the number of feature vectors - * @param[out] scores 2D matrix of scores, <tt>scores[m, s]</tt> is the score for model @c m against statistics @c s - * @warning the output scores matrix should have the correct size (number of models x number of test_stats) - */ -void linearScoring(const std::vector<boost::shared_ptr<const bob::learn::em::GMMMachine> >& models, - const bob::learn::em::GMMMachine& ubm, - const std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> >& test_stats, - const std::vector<blitz::Array<double, 1> >& test_channelOffset, - const bool frame_length_normalisation, - blitz::Array<double,2>& scores); - -/** - * Compute a score using linear scoring. - * - * @param model mean supervector for the client model - * @param ubm_mean mean supervector of the world model - * @param ubm_variance variance supervector of the world model - * @param test_stats accumulate statistics of the test trial - * @param test_channelOffset channel offset - * @param frame_length_normalisation perform a normalisation by the number of feature vectors - */ -double linearScoring(const blitz::Array<double,1>& model, - const blitz::Array<double,1>& ubm_mean, const blitz::Array<double,1>& ubm_variance, - const bob::learn::em::GMMStats& test_stats, - const blitz::Array<double,1>& test_channelOffset, - const bool frame_length_normalisation); - -} } } // namespaces - -#endif // BOB_LEARN_EM_LINEARSCORING_H diff --git a/bob/learn/em/include/bob.learn.em/MAP_GMMTrainer.h b/bob/learn/em/include/bob.learn.em/MAP_GMMTrainer.h deleted file mode 100644 index aac7087fcd84c69334f2fe0cbfb14cfeff5a5369..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/MAP_GMMTrainer.h +++ /dev/null @@ -1,172 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * - * @brief This class implements the maximum a posteriori M-step of the expectation-maximisation algorithm for a GMM Machine. The prior parameters are encoded in the form of a GMM (e.g. a universal background model). The EM algorithm thus performs GMM adaptation. - * @details See Section 3.4 of Reynolds et al., "Speaker Verification Using Adapted Gaussian Mixture Models", Digital Signal Processing, 2000. We use a "single adaptation coefficient", alpha_i, and thus a single relevance factor, r. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_MAP_GMMTRAINER_H -#define BOB_LEARN_EM_MAP_GMMTRAINER_H - -#include <bob.learn.em/GMMBaseTrainer.h> -#include <limits> - -namespace bob { namespace learn { namespace em { - -/** - * @brief This class implements the maximum a posteriori M-step of the expectation-maximisation algorithm for a GMM Machine. The prior parameters are encoded in the form of a GMM (e.g. a universal background model). The EM algorithm thus performs GMM adaptation. - * @details See Section 3.4 of Reynolds et al., "Speaker Verification Using Adapted Gaussian Mixture Models", Digital Signal Processing, 2000. We use a "single adaptation coefficient", alpha_i, and thus a single relevance factor, r. - */ -class MAP_GMMTrainer -{ - public: - /** - * @brief Default constructor - */ - MAP_GMMTrainer( - const bool update_means=true, - const bool update_variances=false, - const bool update_weights=false, - const double mean_var_update_responsibilities_threshold = std::numeric_limits<double>::epsilon(), - const bool reynolds_adaptation=false, - const double relevance_factor=4, - const double alpha=0.5, - boost::shared_ptr<bob::learn::em::GMMMachine> prior_gmm = boost::shared_ptr<bob::learn::em::GMMMachine>()); - - /** - * @brief Copy constructor - */ - MAP_GMMTrainer(const MAP_GMMTrainer& other); - - /** - * @brief Destructor - */ - virtual ~MAP_GMMTrainer(); - - /** - * @brief Initialization - */ - void initialize(bob::learn::em::GMMMachine& gmm); - - /** - * @brief Assigns from a different MAP_GMMTrainer - */ - MAP_GMMTrainer& operator=(const MAP_GMMTrainer &other); - - /** - * @brief Equal to - */ - bool operator==(const MAP_GMMTrainer& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const MAP_GMMTrainer& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const MAP_GMMTrainer& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief Set the GMM to use as a prior for MAP adaptation. - * Generally, this is a "universal background model" (UBM), - * also referred to as a "world model". - */ - bool setPriorGMM(boost::shared_ptr<bob::learn::em::GMMMachine> prior_gmm); - - /** - * @brief Calculates and saves statistics across the dataset, - * and saves these as m_ss. Calculates the average - * log likelihood of the observations given the GMM, - * and returns this in average_log_likelihood. - * - * The statistics, m_ss, will be used in the mStep() that follows. - * Implements EMTrainer::eStep(double &) - */ - void eStep(bob::learn::em::GMMMachine& gmm, - const blitz::Array<double,2>& data){ - m_gmm_base_trainer.eStep(gmm,data); - } - - - /** - * @brief Performs a maximum a posteriori (MAP) update of the GMM - * parameters using the accumulated statistics in m_ss and the - * parameters of the prior model - * Implements EMTrainer::mStep() - */ - void mStep(bob::learn::em::GMMMachine& gmm); - - /** - * @brief Computes the likelihood using current estimates of the latent - * variables - */ - double computeLikelihood(bob::learn::em::GMMMachine& gmm){ - return m_gmm_base_trainer.computeLikelihood(gmm); - } - - bool getReynoldsAdaptation() - {return m_reynolds_adaptation;} - - void setReynoldsAdaptation(const bool reynolds_adaptation) - {m_reynolds_adaptation = reynolds_adaptation;} - - - double getRelevanceFactor() - {return m_relevance_factor;} - - void setRelevanceFactor(const double relevance_factor) - {m_relevance_factor = relevance_factor;} - - - double getAlpha() - {return m_alpha;} - - void setAlpha(const double alpha) - {m_alpha = alpha;} - - bob::learn::em::GMMBaseTrainer& base_trainer(){return m_gmm_base_trainer;} - - - protected: - - /** - * The relevance factor for MAP adaptation, r (see Reynolds et al., \"Speaker Verification Using Adapted Gaussian Mixture Models\", Digital Signal Processing, 2000). - */ - double m_relevance_factor; - - /** - Base Trainer for the MAP algorithm. Basically implements the e-step - */ - bob::learn::em::GMMBaseTrainer m_gmm_base_trainer; - - /** - * The GMM to use as a prior for MAP adaptation. - * Generally, this is a "universal background model" (UBM), - * also referred to as a "world model" - */ - boost::shared_ptr<bob::learn::em::GMMMachine> m_prior_gmm; - - /** - * The alpha for the Torch3-like adaptation - */ - double m_alpha; - /** - * Whether Torch3-like adaptation should be used or not - */ - bool m_reynolds_adaptation; - - private: - /// cache to avoid re-allocation - mutable blitz::Array<double,1> m_cache_alpha; - mutable blitz::Array<double,1> m_cache_ml_weights; -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_MAP_GMMTRAINER_H diff --git a/bob/learn/em/include/bob.learn.em/ML_GMMTrainer.h b/bob/learn/em/include/bob.learn.em/ML_GMMTrainer.h deleted file mode 100644 index 40f1e70cb1c3955284b628d91714a9e3901d6986..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/ML_GMMTrainer.h +++ /dev/null @@ -1,121 +0,0 @@ -/** - * @date Tue May 10 11:35:58 2011 +0200 - * @author Francois Moulin <Francois.Moulin@idiap.ch> - * - * @brief This class implements the maximum likelihood M-step of the expectation-maximisation algorithm for a GMM Machine. - * @details See Section 9.2.2 of Bishop, "Pattern recognition and machine learning", 2006 - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_ML_GMMTRAINER_H -#define BOB_LEARN_EM_ML_GMMTRAINER_H - -#include <bob.learn.em/GMMBaseTrainer.h> -#include <limits> - -namespace bob { namespace learn { namespace em { - -/** - * @brief This class implements the maximum likelihood M-step of the - * expectation-maximisation algorithm for a GMM Machine. - * @details See Section 9.2.2 of Bishop, - * "Pattern recognition and machine learning", 2006 - */ -class ML_GMMTrainer{ - public: - /** - * @brief Default constructor - */ - ML_GMMTrainer(const bool update_means=true, - const bool update_variances=false, - const bool update_weights=false, - const double mean_var_update_responsibilities_threshold = std::numeric_limits<double>::epsilon()); - - /** - * @brief Copy constructor - */ - ML_GMMTrainer(const ML_GMMTrainer& other); - - /** - * @brief Destructor - */ - virtual ~ML_GMMTrainer(); - - /** - * @brief Initialisation before the EM steps - */ - void initialize(bob::learn::em::GMMMachine& gmm); - - /** - * @brief Calculates and saves statistics across the dataset, - * and saves these as m_ss. Calculates the average - * log likelihood of the observations given the GMM, - * and returns this in average_log_likelihood. - * - * The statistics, m_ss, will be used in the mStep() that follows. - * Implements EMTrainer::eStep(double &) - */ - void eStep(bob::learn::em::GMMMachine& gmm, - const blitz::Array<double,2>& data){ - m_gmm_base_trainer.eStep(gmm,data); - } - - /** - * @brief Performs a maximum likelihood (ML) update of the GMM parameters - * using the accumulated statistics in m_ss - * Implements EMTrainer::mStep() - */ - void mStep(bob::learn::em::GMMMachine& gmm); - - /** - * @brief Computes the likelihood using current estimates of the latent - * variables - */ - double computeLikelihood(bob::learn::em::GMMMachine& gmm){ - return m_gmm_base_trainer.computeLikelihood(gmm); - } - - - /** - * @brief Assigns from a different ML_GMMTrainer - */ - ML_GMMTrainer& operator=(const ML_GMMTrainer &other); - - /** - * @brief Equal to - */ - bool operator==(const ML_GMMTrainer& b) const; - - /** - * @brief Not equal to - */ - bool operator!=(const ML_GMMTrainer& b) const; - - /** - * @brief Similar to - */ - bool is_similar_to(const ML_GMMTrainer& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - - bob::learn::em::GMMBaseTrainer& base_trainer(){return m_gmm_base_trainer;} - - protected: - - /** - Base Trainer for the MAP algorithm. Basically implements the e-step - */ - bob::learn::em::GMMBaseTrainer m_gmm_base_trainer; - - - private: - /** - * @brief Add cache to avoid re-allocation at each iteration - */ - mutable blitz::Array<double,1> m_cache_ss_n_thresholded; -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_ML_GMMTRAINER_H diff --git a/bob/learn/em/include/bob.learn.em/PLDAMachine.h b/bob/learn/em/include/bob.learn.em/PLDAMachine.h deleted file mode 100644 index 4f6362ddc322f9ef1b601c9cbee8d6239f8f6200..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/PLDAMachine.h +++ /dev/null @@ -1,702 +0,0 @@ -/** - * @date Fri Oct 14 18:07:56 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Machines that implements the Probabilistic Linear Discriminant - * Analysis Model of Prince and Helder, - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_PLDAMACHINE_H -#define BOB_LEARN_EM_PLDAMACHINE_H - -#include <blitz/array.h> -#include <bob.io.base/HDF5File.h> -#include <map> -#include <iostream> -#include <stdexcept> - -namespace bob { namespace learn { namespace em { - -/** - * @brief This class is a container for the \f$F\f$, \f$G\f$ and \f$\Sigma\f$ - * matrices and the mean vector \f$\mu\f$ of a PLDA model. This also - * precomputes useful matrices to make the model scalable.\n - * References:\n - * 1. 'A Scalable Formulation of Probabilistic Linear Discriminant Analysis: - * Applied to Face Recognition', Laurent El Shafey, Chris McCool, - * Roy Wallace, Sebastien Marcel, TPAMI'2013 - * 2. 'Probabilistic Linear Discriminant Analysis for Inference About - * Identity', Prince and Elder, ICCV'2007\n - * 3. 'Probabilistic Models for Inference about Identity', Li, Fu, Mohammed, - * Elder and Prince, TPAMI'2012 - */ -class PLDABase -{ - public: - /** - * @brief Default constructor.\n Builds an otherwise invalid 0x0x0 - * PLDABase. - */ - PLDABase(); - /** - * @brief Constructor, builds a new PLDABase.\n \f$F\f$, \f$G\f$ - * and \f$\Sigma\f$ are initialized to the 'eye' matrix (matrix with 1's - * on the diagonal and 0 outside), and \f$\mu\f$ is initialized to 0. - * - * @param dim_d Dimensionality of the feature vector - * @param dim_f size of \f$F\f$ (dim_d x dim_f) - * @param dim_g size of \f$G\f$ (dim_d x dim_g) - * @param variance_threshold The smallest possible value of the variance - * (Ignored if set to 0.) - */ - PLDABase(const size_t dim_d, const size_t dim_f, - const size_t dim_g, const double variance_threshold=0.); - /** - * @brief Copies another PLDABase - */ - PLDABase(const PLDABase& other); - /** - * @brief Starts a new PLDABase from an existing configuration - * object. - * @param config HDF5 configuration file - */ - PLDABase(bob::io::base::HDF5File& config); - - /** - * @brief Just to virtualize the destructor - */ - virtual ~PLDABase(); - - /** - * @brief Assigns from a different PLDABase - */ - PLDABase& operator=(const PLDABase &other); - - /** - * @brief Equal to.\n Even precomputed members such as \f$\alpha\f$, - * \f$\beta\f$ and \f$\gamma_a\f$'s are compared! - */ - bool operator==(const PLDABase& b) const; - /** - * @brief Not equal to.\n Defined as the negation of operator== - */ - bool operator!=(const PLDABase& b) const; - /** - * @brief Similar to.\n Even precomputed members such as \f$\alpha\f$, - * \f$\beta\f$ and \f$\gamma_a\f$'s are compared! - */ - bool is_similar_to(const PLDABase& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief Loads data from an existing configuration object. Resets the - * current state. - * @param config HDF5 configuration file - */ - void load(bob::io::base::HDF5File& config); - /** - * @brief Saves an existing machine to a configuration object. - * @param config HDF5 configuration file - */ - void save(bob::io::base::HDF5File& config) const; - - /** - * @brief Resizes the PLDABase. - * @warning \f$F\f$, \f$G\f$, \f$\Sigma\f$, \f$\mu\f$ and the variance - * flooring thresholds will be reinitialized! - * @param dim_d Dimensionality of the feature vector - * @param dim_f Rank of \f$F\f$ (dim_d x dim_f) - * @param dim_g Rank of \f$G\f$ (dim_d x dim_g) - */ - void resize(const size_t dim_d, const size_t dim_f, const size_t dim_g); - - /** - * @brief Gets the \f$F\f$ subspace/matrix of the PLDA model - */ - const blitz::Array<double,2>& getF() const - { return m_F; } - /** - * @brief Sets the \f$F\f$ subspace/matrix of the PLDA model - */ - void setF(const blitz::Array<double,2>& F); - /** - * @brief Returns the current \f$F\f$ matrix/subspace of the PLDA model - * in order to be updated. - * @warning Use with care. Only trainers should use this function for - * efficiency reasons. - */ - blitz::Array<double,2>& updateF() - { return m_F; } - - /** - * @brief Gets the \f$G\f$ subspace/matrix of the PLDA model - */ - const blitz::Array<double,2>& getG() const - { return m_G; } - /** - * @brief Sets the \f$G\f$ subspace/matrix of the PLDA model - */ - void setG(const blitz::Array<double,2>& G); - /** - * @brief Returns the current \f$G\f$ subspace/matrix of the PLDA model - * in order to be updated. - * @warning Use with care. Only trainers should use this function for - * efficiency reasons. - */ - blitz::Array<double,2>& updateG() - { return m_G; } - - /** - * @brief Gets the \f$\Sigma\f$ (diagonal) covariance matrix of the PLDA - * model - */ - const blitz::Array<double,1>& getSigma() const - { return m_sigma; } - /** - * @brief Sets the \f$\Sigma\f$ (diagonal) covariance matrix of the PLDA - * model - */ - void setSigma(const blitz::Array<double,1>& s); - /** - * @brief Returns the current \f$\Sigma\f$ (diagonal) covariance matrix of - * the PLDA model in order to be updated. - * @warning Use with care. Only trainers should use this function for - * efficiency reasons. Variance threshold should be applied after - * updating \f$\Sigma\f$! - */ - blitz::Array<double,1>& updateSigma() - { return m_sigma; } - - /** - * @brief Gets the \f$\mu\f$ mean vector of the PLDA model - */ - const blitz::Array<double,1>& getMu() const - { return m_mu; } - /** - * @brief Sets the \f$\mu\f$ mean vector of the PLDA model - */ - void setMu(const blitz::Array<double,1>& mu); - /** - * @brief Returns the current \f$\mu\f$ mean vector of the PLDA model - * in order to be updated. - * @warning Use with care. Only trainers should use this function for - * efficiency reasons. - */ - blitz::Array<double,1>& updateMu() - { return m_mu; } - - /** - * @brief Gets the variance flooring threshold - */ - double getVarianceThreshold() const - { return m_variance_threshold; } - /** - * @brief Sets the variance flooring threshold - */ - void setVarianceThreshold(const double value); - /** - * @brief Apply the variance flooring thresholds. - * This method is automatically called when using setVarianceThresholds(). - * @warning It is only useful when using updateVarianceThreshods(), - * and should mostly be done by trainers - */ - void applyVarianceThreshold(); - - /** - * @brief Gets the feature dimensionality - */ - size_t getDimD() const - { return m_dim_d; } - /** - * @brief Gets the size/rank the \f$F\f$ subspace/matrix of the PLDA model - */ - size_t getDimF() const - { return m_dim_f; } - /** - * @brief Gets the size/rank the \f$G\f$ subspace/matrix of the PLDA model - */ - size_t getDimG() const - { return m_dim_g; } - - /** - * @brief Precomputes useful values such as \f$\Sigma^{-1}\f$, - * \f$G^{T}\Sigma^{-1}\f$, \f$\alpha\f$, \f$\beta\f$, and - * \f$F^{T}\beta\f$. - * @warning Previous \f$\gamma_a\f$ values and log likelihood constant - * terms are cleared. - */ - void precompute(); - /** - * @brief Precomputes useful values for the log likelihood - * \f$\log(\det(\alpha))\f$ and \f$\log(\det(\Sigma))\f$. - */ - void precomputeLogLike(); - /** - * @brief Gets the inverse vector/diagonal matrix of \f$\Sigma^{-1}\f$ - */ - const blitz::Array<double,1>& getISigma() const - { return m_cache_isigma; } - /** - * @brief Gets the \f$\alpha\f$ matrix. - * \f$\alpha = (Id + G^T \Sigma^{-1} G)^{-1} = \mathcal{G}\f$ - */ - const blitz::Array<double,2>& getAlpha() const - { return m_cache_alpha; } - /** - * @brief Gets the \f$\beta\f$ matrix - * \f$\beta = (\Sigma + G G^T)^{-1} = \mathcal{S} = - * \Sigma^{-1} - \Sigma^{-1} G \mathcal{G} G^{T} \Sigma^{-1}\f$ - */ - const blitz::Array<double,2>& getBeta() const - { return m_cache_beta; } - /** - * @brief Gets the \f$\gamma_a\f$ matrix for a given \f$a\f$ (number of - * samples). - * \f$\gamma_{a} = (Id + a F^T \beta F)^{-1} = \mathcal{F}_{a}\f$ - * @warning an exception is thrown if \f$\gamma_a\f$ does not exists - */ - const blitz::Array<double,2>& getGamma(const size_t a) const; - /** - * @brief Gets the \f$\gamma_a\f$ matrix for a given \f$a\f$ (number of - * samples). - * \f$\gamma_a = (Id + a F^T \beta F)^{-1} = \mathcal{F}_{a}\f$ - * @warning The matrix is computed if it does not already exists - */ - const blitz::Array<double,2>& getAddGamma(const size_t a); - /** - * @brief Gets the \f$F^T \beta\f$ matrix - */ - const blitz::Array<double,2>& getFtBeta() const - { return m_cache_Ft_beta; } - /** - * @brief Gets the \f$G^T \Sigma^{-1}\f$ matrix - */ - const blitz::Array<double,2>& getGtISigma() const - { return m_cache_Gt_isigma; } - /** - * @brief Gets \f$\log(\det(\alpha))\f$ - */ - double getLogDetAlpha() const - { return m_cache_logdet_alpha; } - /** - * @brief Gets \f$\log(\det(\Sigma))\f$ - */ - double getLogDetSigma() const - { return m_cache_logdet_sigma; } - /** - * @brief Computes the log likelihood constant term for a given \f$a\f$ - * (number of samples), given the provided \f$\gamma_a\f$ matrix - * \f$l_{a} = \frac{a}{2} ( -D log(2\pi) -log|\Sigma| +log|\alpha| +log|\gamma_a|)\f$ - */ - double computeLogLikeConstTerm(const size_t a, - const blitz::Array<double,2>& gamma_a) const; - /** - * @brief Computes the log likelihood constant term for a given \f$a\f$ - * (number of samples) - * \f$l_{a} = \frac{a}{2} ( -D log(2\pi) -log|\Sigma| +log|\alpha| +log|\gamma_a|)\f$ - * @warning: gamma_a will be computed and added if it does - * not already exists - */ - double computeLogLikeConstTerm(const size_t a); - /** - * @brief Tells if the log likelihood constant term for a given \f$a\f$ - * (number of samples) exists - * \f$l_{a} = \frac{a}{2} ( -D log(2\pi) -log|\Sigma| +log|\alpha| +log|\gamma_a|)\f$ - */ - bool hasLogLikeConstTerm(const size_t a) const - { return (m_cache_loglike_constterm.find(a) != m_cache_loglike_constterm.end()); } - /** - * @brief Gets the log likelihood constant term for a given \f$a\f$ - * (number of samples) - * \f$l_{a} = \frac{a}{2} ( -D log(2\pi) -log|\Sigma| +log|\alpha| +log|\gamma_a|)\f$ - * @warning an exception is thrown if the value does not exists - */ - double getLogLikeConstTerm(const size_t a) const; - /** - * @brief Gets the log likelihood constant term for a given \f$a\f$ - * (number of samples) - * \f$l_{a} = \frac{a}{2} ( -D log(2\pi) -log|\Sigma| +log|\alpha| +log|\gamma_a|)\f$ - * @warning The value is computed if it does not already exists - */ - double getAddLogLikeConstTerm(const size_t a); - - /** - * @brief Computes the \f$\gamma_a\f$ matrix for a given \f$a\f$ (number - * of samples) and put the result in the provided array. - * \f$\gamma_a = (Id + a F^T \beta F)^{-1}\f$ - */ - void computeGamma(const size_t a, blitz::Array<double,2> res) const; - /** - * @brief Tells if the \f$\gamma_a\f$ matrix for a given a (number of - * samples) exists. - * \f$\gamma_a = (Id + a F^T \beta F)^{-1}\f$ - */ - bool hasGamma(const size_t a) const - { return (m_cache_gamma.find(a) != m_cache_gamma.end()); } - - /** - * @brief Clears the maps (\f$\gamma_a\f$ and loglike_constterm_a). - */ - void clearMaps(); - - /** - * @brief Gets the log-likelihood of an observation, given the current model - * and the latent variables (point estimate).\n - * This will basically compute \f$p(x_{ij} | h_{i}, w_{ij}, \Theta)\f$\n - * , given by \n - * \f$\mathcal{N}(x_{ij}|[\mu + F h_{i} + G w_{ij} + \epsilon_{ij}, \Sigma])\f$\n - * , which is in logarithm, \n - * \f$-\frac{D}{2} log(2\pi) -\frac{1}{2} log(det(\Sigma)) -\frac{1}{2} {(x_{ij}-(\mu+F h_{i}+G w_{ij}))^{T}\Sigma^{-1}(x_{ij}-(\mu+F h_{i}+G w_{ij}))}\f$. - */ - double computeLogLikelihoodPointEstimate(const blitz::Array<double,1>& xij, - const blitz::Array<double,1>& hi, const blitz::Array<double,1>& wij) const; - - // Friend method declaration - friend std::ostream& operator<<(std::ostream& os, const PLDABase& m); - - - private: - // Attributes - size_t m_dim_d; ///< Dimensionality of the input feature vector - size_t m_dim_f; ///< Size/rank of the \f$F\f$ subspace - size_t m_dim_g; ///< Size/rank of the \f$G\f$ subspace - blitz::Array<double,2> m_F; ///< \f$F\f$ subspace of the PLDA model - blitz::Array<double,2> m_G; ///< \f$G\f$ subspace of the PLDA model - /** - * @brief \f$\Sigma\f$ diagonal (by assumption) covariance matrix of the - * PLDA model - */ - blitz::Array<double,1> m_sigma; - blitz::Array<double,1> m_mu; ///< \f$\mu\f$ mean vector of the PLDA model - /** - * @brief The variance flooring thresholds, i.e. the minimum allowed - * value of variance m_sigma in each dimension. - * The variance will be set to this value if an attempt is made - * to set it to a smaller value. - */ - double m_variance_threshold; - - // Internal values very useful used to optimize the code - blitz::Array<double,1> m_cache_isigma; ///< \f$\Sigma^{-1}\f$ - blitz::Array<double,2> m_cache_alpha; ///< \f$\alpha = (Id + G^T \Sigma^{-1} G)^{-1}\f$ - /** - * @brief \f$\beta = (\Sigma+G G^T)^{-1} = (\Sigma^{-1} - \Sigma^{-1} G \alpha G^T \Sigma^{-1})^{-1}\f$ - */ - blitz::Array<double,2> m_cache_beta; - std::map<size_t, blitz::Array<double,2> > m_cache_gamma; ///< \f$\gamma_{a} = (Id + a F^T \beta F)^{-1}\f$ - blitz::Array<double,2> m_cache_Ft_beta; ///< \f$F^{T} \beta \f$ - blitz::Array<double,2> m_cache_Gt_isigma; ///< \f$G^{T} \Sigma^{-1} \f$ - double m_cache_logdet_alpha; ///< \f$\log(\det(\alpha))\f$ - double m_cache_logdet_sigma; ///< \f$\log(\det(\Sigma))\f$ - /** - * @brief \f$l_{a} = \frac{a}{2} ( -D log(2*\pi) -log|\Sigma| +log|\alpha| +log|\gamma_a|)\f$ - */ - std::map<size_t, double> m_cache_loglike_constterm; - - // working arrays - mutable blitz::Array<double,1> m_tmp_d_1; ///< Cache vector of size dim_d - mutable blitz::Array<double,1> m_tmp_d_2; ///< Cache vector of size dim_d - mutable blitz::Array<double,2> m_tmp_d_ng_1; ///< Cache matrix of size dim_d x dim_g - mutable blitz::Array<double,2> m_tmp_nf_nf_1; ///< Cache matrix of size dim_f x dim_f - mutable blitz::Array<double,2> m_tmp_ng_ng_1; ///< Cache matrix of size dim_g x dim_g - - // private methods - void resizeNoInit(const size_t dim_d, const size_t dim_f, const size_t dim_g); - void resizeTmp(); - void initMuFGSigma(); - void precomputeISigma(); - void precomputeAlpha(); - void precomputeBeta(); - void precomputeGamma(const size_t a); - void precomputeFtBeta(); - void precomputeGtISigma(); - void precomputeLogDetAlpha(); - void precomputeLogDetSigma(); - void precomputeLogLikeConstTerm(const size_t a); -}; - - -/** - * @brief This class is a container for an enrolled identity/class. It - * contains information extracted from the enrollment samples. It should - * be used in combination with a PLDABase instance.\n - * References:\n - * 1. 'A Scalable Formulation of Probabilistic Linear Discriminant Analysis: - * Applied to Face Recognition', Laurent El Shafey, Chris McCool, - * Roy Wallace, Sebastien Marcel, TPAMI'2013 - * 2. 'Probabilistic Linear Discriminant Analysis for Inference About - * Identity', Prince and Elder, ICCV'2007\n - * 3. 'Probabilistic Models for Inference about Identity', Li, Fu, Mohammed, - * Elder and Prince, TPAMI'2012 - */ -class PLDAMachine -{ - public: - /** - * @brief Default constructor.\n - * Builds an otherwise invalid (No attached PLDABase) PLDAMachine. - */ - PLDAMachine(); - /** - * @brief Constructor, builds a new PLDAMachine, setting a - * PLDABase. - */ - PLDAMachine(const boost::shared_ptr<bob::learn::em::PLDABase> pldabase); - /** - * @brief Copies another PLDAMachine.\n Both PLDAMachine's will point - * to the same PLDABase. - */ - PLDAMachine(const PLDAMachine& other); - /** - * @brief Starts a new PLDAMachine from an existing configuration object, - * and a PLDABase. - */ - PLDAMachine(bob::io::base::HDF5File& config, - const boost::shared_ptr<bob::learn::em::PLDABase> pldabase); - - /** - * @brief Just to virtualise the destructor - */ - virtual ~PLDAMachine(); - - /** - * @brief Assigns from a different machine - */ - PLDAMachine& operator=(const PLDAMachine &other); - - /** - * @brief Equal to.\n The two PLDAMachine's should have the same - * PLDABase. Precomputed members such as \f$\gamma_a\f$'s - * are compared! - */ - bool operator==(const PLDAMachine& b) const; - /** - * @brief Not equal to.\n Defined as the negation of operator== - */ - bool operator!=(const PLDAMachine& b) const; - /** - * @brief Equal to.\n The two PLDAMachine's should have the same - * PLDABase. Precomputed members such as \f$\gamma_a\f$'s - * are compared! - */ - bool is_similar_to(const PLDAMachine& b, const double r_epsilon=1e-5, - const double a_epsilon=1e-8) const; - - /** - * @brief Loads data from an existing configuration object. Resets the - * current state. - */ - void load(bob::io::base::HDF5File& config); - /** - * @brief Saves an existing machine to a configuration object. - */ - void save(bob::io::base::HDF5File& config) const; - - /** - * @brief Gets the attached PLDABase - */ - const boost::shared_ptr<PLDABase> getPLDABase() const - { return m_plda_base; } - /** - * @brief Sets the attached PLDABase - */ - void setPLDABase(const boost::shared_ptr<bob::learn::em::PLDABase> plda_base); - - /** - * @brief Gets the feature dimensionality - */ - size_t getDimD() const - { if (!m_plda_base) throw std::runtime_error("No PLDABase set to this machine"); - return m_plda_base->getDimD(); } - /** - * @brief Gets the size/rank the \f$F\f$ subspace/matrix of the PLDA model - */ - size_t getDimF() const - { if (!m_plda_base) throw std::runtime_error("No PLDABase set to this machine"); - return m_plda_base->getDimF(); } - /** - * @brief Gets the size/rank the \f$G\f$ subspace/matrix of the PLDA model - */ - size_t getDimG() const - { if (!m_plda_base) throw std::runtime_error("No PLDABase set to this machine"); - return m_plda_base->getDimG(); } - - /** - * @brief Gets the number of enrolled samples - */ - uint64_t getNSamples() const - { return m_n_samples; } - /** - * @brief Sets the number of enrolled samples - */ - void setNSamples(const uint64_t n_samples) - { m_n_samples = n_samples; } - /** - * @brief Gets the \f$A = -0.5 \sum_{i} x_{i}^T \beta x_{i}\f$ value - */ - double getWSumXitBetaXi() const - { return m_nh_sum_xit_beta_xi; } - /** - * @brief Sets the \f$A = -0.5 \sum_{i} x_{i}^T \beta x_{i}\f$ value - */ - void setWSumXitBetaXi(const double val) - { m_nh_sum_xit_beta_xi = val; } - /** - * @brief Gets the current \f$\sum_{i} F^T \beta x_{i}\f$ value - */ - const blitz::Array<double,1>& getWeightedSum() const - { return m_weighted_sum; } - /** - * @brief Sets the \f$\sum_{i} F^T \beta x_{i}\f$ value - */ - void setWeightedSum(const blitz::Array<double,1>& weighted_sum); - /** - * @brief Returns the current \f$\sum_{i} F^T \beta x_{i}\f$ value - * in order to be updated. - * @warning Use with care. Only trainers should use this function for - * efficiency reasons. - */ - blitz::Array<double,1>& updateWeightedSum() - { return m_weighted_sum; } - /** - * @brief Gets the log likelihood of the enrollment samples - */ - double getLogLikelihood() const - { return m_loglikelihood; } - /** - * @brief Sets the log likelihood of the enrollment samples - */ - void setLogLikelihood(const double val) - { m_loglikelihood = val; } - - /** - * @brief Tells if the \f$\gamma_a\f$ matrix for a given \f$a\f$ (number - * of samples) exists in this machine (does not check the base machine) - * \f$\gamma_a = (Id + a F^T \beta F)^{-1} = \mathcal{F}_{a}\f$ - */ - bool hasGamma(const size_t a) const - { return (m_cache_gamma.find(a) != m_cache_gamma.end()); } - /** - * @brief Gets the \f$\gamma_a\f$ matrix for a given \f$a\f$ (number of - * samples) \f$\gamma_a = (Id + a F^T \beta F)^{-1} = \mathcal{F}_{a}\f$ - * Tries to find it from the base machine and then from this machine - * @warning an exception is thrown if gamma does not exists - */ - const blitz::Array<double,2>& getGamma(const size_t a) const; - /** - * @brief Gets the \f$\gamma_a\f$ matrix for a given \f$a\f$ (number of - * samples) \f$\gamma_a = (Id + a F^T \beta F)^{-1} = \mathcal{F}_{a}\f$ - * Tries to find it from the base machine and then from this machine - * @warning The matrix is computed if it does not already exists, - * and stored in this machine - */ - const blitz::Array<double,2>& getAddGamma(const size_t a); - - /** - * @brief Tells if the log likelihood constant term for a given \f$a\f$ - * (number of samples) exists in this machine - * (does not check the base machine) - * \f$l_{a} = \frac{a}{2} ( -D log(2\pi) -log|\Sigma| +log|\alpha| +log|\gamma_a|)\f$ - */ - bool hasLogLikeConstTerm(const size_t a) const - { return (m_cache_loglike_constterm.find(a) != m_cache_loglike_constterm.end()); } - /** - * @brief Gets the log likelihood constant term for a given \f$a\f$ - * (number of samples) - * Tries to find it from the base machine and then from this machine - * \f$l_{a} = \frac{a}{2} ( -D log(2\pi) -log|\Sigma| +log|\alpha| +log|\gamma_a|)\f$ - * @warning an exception is thrown if the value does not exists - */ - double getLogLikeConstTerm(const size_t a) const; - /** - * @brief Gets the log likelihood constant term for a given \f$a\f$ - * (number of samples) - * Tries to find it from the base machine and then from this machine - * \f$l_{a} = \frac{a}{2} ( -D log(2\pi) -log|\Sigma| +log|\alpha| +log|\gamma_a|)\f$ - * @warning The value is computed if it does not already exists - */ - double getAddLogLikeConstTerm(const size_t a); - - /** - * @brief Clears the maps (\f$\gamma_a\f$ and loglike_constterm[a]). - */ - void clearMaps(); - - - /** - * @brief Compute the log-likelihood of the given sample and (optionally) - * the enrolled samples - */ - double computeLogLikelihood(const blitz::Array<double,1>& sample, - bool with_enrolled_samples=true) const; - /** - * @brief Compute the log-likelihood of the given samples and (optionally) - * the enrolled samples - */ - double computeLogLikelihood(const blitz::Array<double,2>& samples, - bool with_enrolled_samples=true) const; - - /** - * @brief Computes a log likelihood ratio from a 1D or 2D blitz::Array - */ - double forward(const blitz::Array<double,1>& sample); - double forward_(const blitz::Array<double,1>& sample); - double forward(const blitz::Array<double,2>& samples); - - - private: - /** - * @brief Associated PLDABase containing the model (\f$\mu\f$, - * \f$F\f$, \f$G\f$ and \f$\Sigma\f$) - */ - boost::shared_ptr<PLDABase> m_plda_base; - uint64_t m_n_samples; ///< Number of enrollment samples - /** - * @brief Contains the value:\n - * \f$A = -0.5 (\sum_{i} x_{i}^{T} \Sigma^{-1} x_{i} - x_{i}^T \Sigma^{-1} G \alpha G^{T} \Sigma^{-1} x_{i})\f$\n - * \f$A = -0.5 \sum_{i} x_{i}^T \beta x_{i}\f$\n - * used in the likelihood computation (first \f$x_{i}\f$ dependent term) - */ - double m_nh_sum_xit_beta_xi; - /** - * @brief Contains the value \f$\sum_{i} F^T \beta x_{i}\f$ used in the - * likelihood computation (for the second \f$x_{i}\f$ dependent term) - */ - blitz::Array<double,1> m_weighted_sum; - double m_loglikelihood; ///< Log likelihood of the enrollment samples - /** - * @brief \f$\gamma_a\f$ balues which are not already in the - * PLDABase \f$\gamma_a = (Id + a F^T \beta F)^{-1}\f$ - * (depend on the number of samples \f$a\f$) - */ - std::map<size_t, blitz::Array<double,2> > m_cache_gamma; - /** - * @brief Log likelihood constant terms which depend on the number of - * samples \f$a\f$ - * \f$l_{a} = \frac{a}{2} ( -D log(2\pi) -log|\Sigma| +log|\alpha| +log|\gamma_a|)\f$ - */ - std::map<size_t, double> m_cache_loglike_constterm; - - - // working arrays - mutable blitz::Array<double,1> m_tmp_d_1; ///< Cache vector of size dim_d - mutable blitz::Array<double,1> m_tmp_d_2; ///< Cache vector of size dim_d - mutable blitz::Array<double,1> m_tmp_nf_1; ///< Cache vector of size dim_f - mutable blitz::Array<double,1> m_tmp_nf_2; ///< Cache vector of size dim_f - mutable blitz::Array<double,2> m_tmp_nf_nf_1; ///< Cache vector of size dim_f dim_f - - /** - * @brief Resizes the PLDAMachine - */ - void resize(const size_t dim_d, const size_t dim_f, const size_t dim_g); - /** - * @brief Resize working arrays - */ - void resizeTmp(); -}; - -} } } // namespaces - -#endif // BOB_LEARN_EM_PLDAMACHINE_H diff --git a/bob/learn/em/include/bob.learn.em/PLDATrainer.h b/bob/learn/em/include/bob.learn.em/PLDATrainer.h deleted file mode 100644 index f5bc4024c14b3e013e52795201fe9ba72f9ba813..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/PLDATrainer.h +++ /dev/null @@ -1,310 +0,0 @@ -/** - * @date Fri Oct 14 18:07:56 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Probabilistic PLDA Discriminant Analysis implemented using - * Expectation Maximization. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_LEARN_EM_PLDA_TRAINER_H -#define BOB_LEARN_EM_PLDA_TRAINER_H - -#include <bob.learn.em/PLDAMachine.h> -#include <boost/shared_ptr.hpp> -#include <vector> -#include <map> -#include <bob.core/array_copy.h> -#include <boost/random.hpp> -#include <boost/random/mersenne_twister.hpp> - -namespace bob { namespace learn { namespace em { - -/** - * @brief This class can be used to train the \f$F\f$, \f$G\f$ and - * \f$\Sigma\f$ matrices and the mean vector \f$\mu\f$ of a PLDA model.\n - * References:\n - * 1. 'A Scalable Formulation of Probabilistic Linear Discriminant Analysis: - * Applied to Face Recognition', Laurent El Shafey, Chris McCool, - * Roy Wallace, Sebastien Marcel, TPAMI'2013 - * 2. 'Probabilistic Linear Discriminant Analysis for Inference About - * Identity', Prince and Elder, ICCV'2007\n - * 3. 'Probabilistic Models for Inference about Identity', Li, Fu, Mohammed, - * Elder and Prince, TPAMI'2012 - */ -class PLDATrainer -{ - public: //api - /** - * @brief Default constructor.\n Initializes a new PLDA trainer. The - * training stage will place the resulting components in the - * PLDABase. - */ - PLDATrainer(const bool use_sum_second_order); - - /** - * @brief Copy constructor - */ - PLDATrainer(const PLDATrainer& other); - - /** - * @brief (virtual) Destructor - */ - virtual ~PLDATrainer(); - - /** - * @brief Assignment operator - */ - PLDATrainer& operator=(const PLDATrainer& other); - - /** - * @brief Equal to - */ - bool operator==(const PLDATrainer& other) const; - - /** - * @brief Not equal to - */ - bool operator!=(const PLDATrainer& other) const; - - /** - * @brief Similarity operator - */ - bool is_similar_to(const PLDATrainer& b, - const double r_epsilon=1e-5, const double a_epsilon=1e-8) const; - - /** - * @brief Performs some initialization before the E- and M-steps. - */ - void initialize(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - /** - * @brief Performs some actions after the end of the E- and M-steps. - */ - void finalize(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - - /** - * @brief Calculates and saves statistics across the dataset, and saves - * these as m_z_{first,second}_order. - * The statistics will be used in the mStep() that follows. - */ - void eStep(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - - /** - * @brief Performs a maximization step to update the parameters of the - * PLDABase - */ - void mStep(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - - - /** - * @brief Sets whether the second order statistics are stored during the - * training procedure, or only their sum. - */ - void setUseSumSecondOrder(bool v) { m_use_sum_second_order = v; } - /** - * @brief Tells whether the second order statistics are stored during the - * training procedure, or only their sum. - */ - bool getUseSumSecondOrder() const - { return m_use_sum_second_order; } - - /** - * @brief This enum defines different methods for initializing the \f$F\f$ - * subspace - */ - typedef enum { - RANDOM_F=0, - BETWEEN_SCATTER=1 - } - InitFMethod; - /** - * @brief This enum defines different methods for initializing the \f$G\f$ - * subspace - */ - typedef enum { - RANDOM_G=0, - WITHIN_SCATTER=1 - } - InitGMethod; - /** - * @brief This enum defines different methods for initializing the - * \f$\Sigma\f$ covariance matrix - */ - typedef enum { - RANDOM_SIGMA=0, - VARIANCE_G=1, - CONSTANT=2, - VARIANCE_DATA=3 - } - InitSigmaMethod; - /** - * @brief Sets the method used to initialize \f$F\f$ - */ - void setInitFMethod(const InitFMethod m) { m_initF_method = m; } - /** - * @brief Gets the method used to initialize \f$F\f$ - */ - InitFMethod getInitFMethod() const { return m_initF_method; } - /** - * @brief Sets the ratio value used to initialize \f$F\f$ - */ - void setInitFRatio(double d) { m_initF_ratio = d; } - /** - * @brief Gets the ratio value used to initialize \f$F\f$ - */ - double getInitFRatio() const { return m_initF_ratio; } - /** - * @brief Sets the method used to initialize \f$G\f$ - */ - void setInitGMethod(const InitGMethod m) { m_initG_method = m; } - /** - * @brief Gets the method used to initialize \f$G\f$ - */ - InitGMethod getInitGMethod() const { return m_initG_method; } - /** - * @brief Sets the ratio value used to initialize \f$G\f$ - */ - void setInitGRatio(double d) { m_initG_ratio = d; } - /** - * @brief Gets the ratio value used to initialize \f$G\f$ - */ - double getInitGRatio() const { return m_initG_ratio; } - /** - * @brief Sets the method used to initialize \f$\Sigma\f$ - */ - void setInitSigmaMethod(const InitSigmaMethod m) - { m_initSigma_method = m; } - /** - * @brief Gets the method used to initialize \f$\Sigma\f$ - */ - InitSigmaMethod getInitSigmaMethod() const - { return m_initSigma_method; } - /** - * @brief Sets the ratio value used to initialize \f$\Sigma\f$ - */ - void setInitSigmaRatio(double d) { m_initSigma_ratio = d; } - /** - * @brief Gets the ratio value used to initialize \f$\Sigma\f$ - */ - double getInitSigmaRatio() const { return m_initSigma_ratio; } - - /** - * @brief Gets the z first order statistics (mostly for test purposes) - */ - const std::vector<blitz::Array<double,2> >& getZFirstOrder() const - { return m_cache_z_first_order;} - /** - * @brief Gets the z second order statistics (mostly for test purposes) - */ - const blitz::Array<double,2>& getZSecondOrderSum() const - { return m_cache_sum_z_second_order;} - /** - * @brief Gets the z second order statistics (mostly for test purposes) - */ - const std::vector<blitz::Array<double,3> >& getZSecondOrder() const - { if(m_use_sum_second_order) - throw std::runtime_error("You should disable the use_sum_second_order flag to use this feature"); - return m_cache_z_second_order; - } - - /** - * @brief Main procedure for enrolling a PLDAMachine - */ - void enroll(bob::learn::em::PLDAMachine& plda_machine, - const blitz::Array<double,2>& ar) const; - - - /** - * @brief Sets the Random Number Generator - */ - void setRng(boost::shared_ptr<boost::mt19937> rng) - { m_rng = rng; } - - /** - * @brief Gets the Random Number Generator - */ - boost::shared_ptr<boost::mt19937> getRng() const - { return m_rng; } - - private: - - boost::shared_ptr<boost::mt19937> m_rng; - - //representation - size_t m_dim_d; ///< Dimensionality of the input features - size_t m_dim_f; ///< Size/rank of the \f$F\f$ subspace - size_t m_dim_g; ///< Size/rank of the \f$G\f$ subspace - bool m_use_sum_second_order; ///< If set, only the sum of the second order statistics is stored/allocated - InitFMethod m_initF_method; ///< Initialization method for \f$F\f$ - double m_initF_ratio; ///< Ratio/factor used for the initialization of \f$F\f$ - InitGMethod m_initG_method; ///< Initialization method for \f$G\f$ - double m_initG_ratio; ///< Ratio/factor used for the initialization of \f$G\f$ - InitSigmaMethod m_initSigma_method; ///< Initialization method for \f$\Sigma\f$ - double m_initSigma_ratio; ///< Ratio/factor used for the initialization of \f$\Sigma\f$ - - // Statistics and covariance computed during the training process - blitz::Array<double,2> m_cache_S; ///< Covariance of the training data - std::vector<blitz::Array<double,2> > m_cache_z_first_order; ///< Current mean of the z_{n} latent variable (1 for each sample) - blitz::Array<double,2> m_cache_sum_z_second_order; ///< Current sum of the covariance of the z_{n} latent variable - std::vector<blitz::Array<double,3> > m_cache_z_second_order; ///< Current covariance of the z_{n} latent variable - // Precomputed - /** - * @brief Number of training samples for each individual in the training set - */ - std::vector<size_t> m_cache_n_samples_per_id; - /** - * @brief Tells if there is an identity with a 'key'/particular number of - * training samples, and if corresponding matrices are up to date. - */ - std::map<size_t,bool> m_cache_n_samples_in_training; - blitz::Array<double,2> m_cache_B; ///< \f$B = [F, G]\f$ (size nfeatures x (m_dim_f+m_dim_g) ) - blitz::Array<double,2> m_cache_Ft_isigma_G; ///< \f$F^T \Sigma^-1 G\f$ - blitz::Array<double,2> m_cache_eta; ///< \f$F^T \Sigma^-1 G \alpha\f$ - // Blocks (with \f$\gamma_{a}\f$) of \f$(Id + A^T \Sigma'^-1 A)^-1\f$ (efficient inversion) - std::map<size_t,blitz::Array<double,2> > m_cache_zeta; ///< \f$\zeta_{a} = \alpha + \eta^T \gamma_{a} \eta\f$ - std::map<size_t,blitz::Array<double,2> > m_cache_iota; ///< \f$\iota_{a} = -\gamma_{a} \eta\f$ - - // Working arrays - mutable blitz::Array<double,1> m_tmp_nf_1; ///< vector of dimension dim_f - mutable blitz::Array<double,1> m_tmp_nf_2; ///< vector of dimension dim_f - mutable blitz::Array<double,1> m_tmp_ng_1; ///< vector of dimension dim_f - mutable blitz::Array<double,1> m_tmp_D_1; ///< vector of dimension dim_d - mutable blitz::Array<double,1> m_tmp_D_2; ///< vector of dimension dim_d - mutable blitz::Array<double,2> m_tmp_nfng_nfng; ///< matrix of dimension (dim_f+dim_g)x(dim_f+dim_g) - mutable blitz::Array<double,2> m_tmp_D_nfng_1; ///< matrix of dimension (dim_d)x(dim_f+dim_g) - mutable blitz::Array<double,2> m_tmp_D_nfng_2; ///< matrix of dimension (dim_d)x(dim_f+dim_g) - - // internal methods - void computeMeanVariance(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - void initMembers(const std::vector<blitz::Array<double,2> >& v_ar); - void initFGSigma(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - void initF(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - void initG(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - void initSigma(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - - void checkTrainingData(const std::vector<blitz::Array<double,2> >& v_ar); - void precomputeFromFGSigma(bob::learn::em::PLDABase& machine); - void precomputeLogLike(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - - void updateFG(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - void updateSigma(bob::learn::em::PLDABase& machine, - const std::vector<blitz::Array<double,2> >& v_ar); - - void resizeTmp(); -}; - -} } } // namespaces - -#endif /* BOB_LEARN_EM_PLDA_TRAINER_H */ diff --git a/bob/learn/em/include/bob.learn.em/api.h b/bob/learn/em/include/bob.learn.em/api.h deleted file mode 100644 index 7548a302f751d0a20b13d5966affffed670b8bf6..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/api.h +++ /dev/null @@ -1,127 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Fri 21 Nov 10:38:48 2013 - * - * @brief Python API for bob::learn::em - */ - -#ifndef BOB_LEARN_EM_API_H -#define BOB_LEARN_EM_API_H - -/* Define Module Name and Prefix for other Modules - Note: We cannot use BOB_EXT_* macros here, unfortunately */ -#define BOB_LEARN_EM_PREFIX "bob.learn.em" -#define BOB_LEARN_EM_FULL_NAME "bob.learn.em._library" - -#include <Python.h> - -#include <bob.learn.em/config.h> -#include <boost/shared_ptr.hpp> - -/******************* - * C API functions * - *******************/ - -/* Enum defining entries in the function table */ -enum _PyBobLearnEM_ENUM{ - PyBobLearnEM_APIVersion_NUM = 0, - // bindings - ////PyBobIpBaseLBP_Type_NUM, - ////PyBobIpBaseLBP_Check_NUM, - ////PyBobIpBaseLBP_Converter_NUM, - // Total number of C API pointers - PyBobLearnEM_API_pointers -}; - - -#ifdef BOB_LEARN_EM_MODULE - - /* This section is used when compiling `bob.io.base' itself */ - - /************** - * Versioning * - **************/ - - extern int PyBobLearnEM_APIVersion; - -#else // BOB_LEARN_EM_MODULE - - /* This section is used in modules that use `bob.io.base's' C-API */ - -#if defined(NO_IMPORT_ARRAY) - extern void **PyBobLearnEM_API; -#elif defined(PY_ARRAY_UNIQUE_SYMBOL) - void **PyBobLearnEM_API; -#else - static void **PyBobLearnEM_API=NULL; -#endif - - /************** - * Versioning * - **************/ - -#define PyBobLearnEM_APIVersion (*(int *)PyBobLearnEM_API[PyBobLearnEM_APIVersion_NUM]) - -#if !defined(NO_IMPORT_ARRAY) - - /** - * Returns -1 on error, 0 on success. - */ - static int import_bob_learn_em(void) { - - PyObject *c_api_object; - PyObject *module; - - module = PyImport_ImportModule(BOB_LEARN_EM_FULL_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)) { - PyBobLearnEM_API = (void **)PyCapsule_GetPointer(c_api_object, PyCapsule_GetName(c_api_object)); - } -#else - if (PyCObject_Check(c_api_object)) { - PyBobLearnEM_API = (void **)PyCObject_AsVoidPtr(c_api_object); - } -#endif - - Py_DECREF(c_api_object); - Py_DECREF(module); - - if (!PyBobLearnEM_API) { - PyErr_SetString(PyExc_ImportError, "cannot find C/C++ API " -#if PY_VERSION_HEX >= 0x02070000 - "capsule" -#else - "cobject" -#endif - " at `" BOB_LEARN_EM_FULL_NAME "._C_API'"); - return -1; - } - - /* Checks that the imported version matches the compiled version */ - int imported_version = *(int*)PyBobLearnEM_API[PyBobLearnEM_APIVersion_NUM]; - - if (BOB_LEARN_EM_API_VERSION != imported_version) { - PyErr_Format(PyExc_ImportError, BOB_LEARN_EM_FULL_NAME " 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", BOB_LEARN_EM_API_VERSION, imported_version); - return -1; - } - - /* If you get to this point, all is good */ - return 0; - - } - -#endif //!defined(NO_IMPORT_ARRAY) - -#endif /* BOB_LEARN_EM_MODULE */ - -#endif /* BOB_LEARN_EM_API_H */ diff --git a/bob/learn/em/include/bob.learn.em/config.h b/bob/learn/em/include/bob.learn.em/config.h deleted file mode 100644 index 71676a62966c87370c320b1c692ed5fa78f531e6..0000000000000000000000000000000000000000 --- a/bob/learn/em/include/bob.learn.em/config.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @author Manuel Guenther <manuel.guenther@idiap.ch> - * @date Thu Aug 21 20:49:42 CEST 2014 - * - * @brief General directives for all modules in bob.learn.em - */ - -#ifndef BOB_LEARN_EM_CONFIG_H -#define BOB_LEARN_EM_CONFIG_H - -/* Macros that define versions and important names */ -#define BOB_LEARN_EM_API_VERSION 0x0200 - -#ifdef BOB_IMPORT_VERSION - - /*************************************** - * Here we define some functions that should be used to build version dictionaries in the version.cpp file - * There will be a compiler warning, when these functions are not used, so use them! - ***************************************/ - - #include <Python.h> - #include <boost/preprocessor/stringize.hpp> - - /** - * bob.learn.em c/c++ api version - */ - static PyObject* bob_learn_em_version() { - return Py_BuildValue("{ss}", "api", BOOST_PP_STRINGIZE(BOB_LEARN_EM_API_VERSION)); - } - -#endif // BOB_IMPORT_VERSION - -#endif /* BOB_LEARN_EM_CONFIG_H */ diff --git a/bob/learn/em/isv_base.cpp b/bob/learn/em/isv_base.cpp deleted file mode 100644 index 352e8ef66ed09519cdcbd96804fbbc97dee6e545..0000000000000000000000000000000000000000 --- a/bob/learn/em/isv_base.cpp +++ /dev/null @@ -1,562 +0,0 @@ -/** - * @date Wed Jan 28 11:13:15 2015 +0200 - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static auto ISVBase_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".ISVBase", - - "A ISVBase instance can be seen as a container for U and D when performing Joint Factor Analysis (JFA).\n\n" - "References: [Vogt2008]_ [McCool2013]_", - "" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Creates a ISVBase", - "", - true - ) - .add_prototype("ubm,ru","") - .add_prototype("other","") - .add_prototype("hdf5","") - .add_prototype("","") - - .add_parameter("ubm", ":py:class:`bob.learn.em.GMMMachine`", "The Universal Background Model.") - .add_parameter("ru", "int", "Size of U (Within client variation matrix). In the end the U matrix will have (number_of_gaussians * feature_dimension x ru)") - .add_parameter("other", ":py:class:`bob.learn.em.ISVBase`", "A ISVBase object to be copied.") - .add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading") - -); - - -static int PyBobLearnEMISVBase_init_copy(PyBobLearnEMISVBaseObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = ISVBase_doc.kwlist(1); - PyBobLearnEMISVBaseObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMISVBase_Type, &o)){ - ISVBase_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::ISVBase(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMISVBase_init_hdf5(PyBobLearnEMISVBaseObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = ISVBase_doc.kwlist(2); - - PyBobIoHDF5FileObject* config = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBobIoHDF5File_Converter, &config)){ - ISVBase_doc.print_usage(); - return -1; - } - auto config_ = make_safe(config); - - self->cxx.reset(new bob::learn::em::ISVBase(*(config->f))); - - return 0; -} - - -static int PyBobLearnEMISVBase_init_ubm(PyBobLearnEMISVBaseObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = ISVBase_doc.kwlist(0); - - PyBobLearnEMGMMMachineObject* ubm; - int ru = 1; - - //Here we have to select which keyword argument to read - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!i", kwlist, &PyBobLearnEMGMMMachine_Type, &ubm, &ru)){ - ISVBase_doc.print_usage(); - return -1; - } - - if(ru < 0){ - PyErr_Format(PyExc_TypeError, "ru argument must be greater than or equal to one"); - return -1; - } - - self->cxx.reset(new bob::learn::em::ISVBase(ubm->cxx, ru)); - return 0; -} - - -static int PyBobLearnEMISVBase_init(PyBobLearnEMISVBaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - switch (nargs) { - - case 1:{ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is Gaussian object - if (PyBobLearnEMISVBase_Check(arg)) - return PyBobLearnEMISVBase_init_copy(self, args, kwargs); - // If the constructor input is a HDF5 - else if (PyBobIoHDF5File_Check(arg)) - return PyBobLearnEMISVBase_init_hdf5(self, args, kwargs); - } - case 2: - return PyBobLearnEMISVBase_init_ubm(self, args, kwargs); - default: - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires 1 or 2 arguments, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - ISVBase_doc.print_usage(); - return -1; - } - BOB_CATCH_MEMBER("cannot create ISVBase", -1) - return 0; -} - - -static void PyBobLearnEMISVBase_delete(PyBobLearnEMISVBaseObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* PyBobLearnEMISVBase_RichCompare(PyBobLearnEMISVBaseObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMISVBase_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMISVBaseObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare ISVBase objects", 0) -} - -int PyBobLearnEMISVBase_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMISVBase_Type)); -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** shape *****/ -static auto shape = bob::extension::VariableDoc( - "shape", - "(int,int, int)", - "A tuple that represents the number of gaussians, dimensionality of each Gaussian, dimensionality of the rU (within client variability matrix) `(#Gaussians, #Inputs, #rU)`.", - "" -); -PyObject* PyBobLearnEMISVBase_getShape(PyBobLearnEMISVBaseObject* self, void*) { - BOB_TRY - return Py_BuildValue("(i,i,i)", self->cxx->getNGaussians(), self->cxx->getNInputs(), self->cxx->getDimRu()); - BOB_CATCH_MEMBER("shape could not be read", 0) -} - -/***** supervector_length *****/ -static auto supervector_length = bob::extension::VariableDoc( - "supervector_length", - "int", - "Returns the supervector length.", - "NGaussians x NInputs: Number of Gaussian components by the feature dimensionality" - "An exception is thrown if no Universal Background Model has been set yet." - "" -); -PyObject* PyBobLearnEMISVBase_getSupervectorLength(PyBobLearnEMISVBaseObject* self, void*) { - BOB_TRY - return Py_BuildValue("i", self->cxx->getSupervectorLength()); - BOB_CATCH_MEMBER("supervector_length could not be read", 0) -} - - -/***** u *****/ -static auto U = bob::extension::VariableDoc( - "u", - "array_like <float, 2D>", - "Returns the U matrix (within client variability matrix)", - "" -); -PyObject* PyBobLearnEMISVBase_getU(PyBobLearnEMISVBaseObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getU()); - BOB_CATCH_MEMBER("``u`` could not be read", 0) -} -int PyBobLearnEMISVBase_setU(PyBobLearnEMISVBaseObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, U.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, U.name()); - return -1; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, U.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getU().extent(0) && input->shape[1] != self->cxx->getU().extent(1)) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getU().extent(0), (Py_ssize_t)self->cxx->getU().extent(1), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], U.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "u"); - if (!b) return -1; - self->cxx->setU(*b); - return 0; - BOB_CATCH_MEMBER("``u`` matrix could not be set", -1) -} - - -/***** d *****/ -static auto D = bob::extension::VariableDoc( - "d", - "array_like <float, 1D>", - "Returns the diagonal matrix diag(d) (as a 1D vector)", - "" -); -PyObject* PyBobLearnEMISVBase_getD(PyBobLearnEMISVBaseObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getD()); - BOB_CATCH_MEMBER("``d`` could not be read", 0) -} -int PyBobLearnEMISVBase_setD(PyBobLearnEMISVBaseObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, D.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, D.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, D.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getD().extent(0)) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getU().extent(0), (Py_ssize_t)input->shape[0], D.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "d"); - if (!b) return -1; - self->cxx->setD(*b); - return 0; - BOB_CATCH_MEMBER("``d`` matrix could not be set", -1) -} - - -/***** ubm *****/ -static auto ubm = bob::extension::VariableDoc( - "ubm", - ":py:class:`bob.learn.em.GMMMachine`", - "Returns the UBM (Universal Background Model", - "" -); -PyObject* PyBobLearnEMISVBase_getUBM(PyBobLearnEMISVBaseObject* self, void*){ - BOB_TRY - - boost::shared_ptr<bob::learn::em::GMMMachine> ubm_gmmMachine = self->cxx->getUbm(); - - //Allocating the correspondent python object - PyBobLearnEMGMMMachineObject* retval = - (PyBobLearnEMGMMMachineObject*)PyBobLearnEMGMMMachine_Type.tp_alloc(&PyBobLearnEMGMMMachine_Type, 0); - retval->cxx = ubm_gmmMachine; - - return Py_BuildValue("N",retval); - BOB_CATCH_MEMBER("ubm could not be read", 0) -} -int PyBobLearnEMISVBase_setUBM(PyBobLearnEMISVBaseObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyBobLearnEMGMMMachine_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a :py:class:`bob.learn.em.GMMMachine`", Py_TYPE(self)->tp_name, ubm.name()); - return -1; - } - - PyBobLearnEMGMMMachineObject* ubm_gmmMachine = 0; - PyArg_Parse(value, "O!", &PyBobLearnEMGMMMachine_Type,&ubm_gmmMachine); - - self->cxx->setUbm(ubm_gmmMachine->cxx); - - return 0; - BOB_CATCH_MEMBER("ubm could not be set", -1) -} - - - -static PyGetSetDef PyBobLearnEMISVBase_getseters[] = { - { - shape.name(), - (getter)PyBobLearnEMISVBase_getShape, - 0, - shape.doc(), - 0 - }, - - { - supervector_length.name(), - (getter)PyBobLearnEMISVBase_getSupervectorLength, - 0, - supervector_length.doc(), - 0 - }, - - { - U.name(), - (getter)PyBobLearnEMISVBase_getU, - (setter)PyBobLearnEMISVBase_setU, - U.doc(), - 0 - }, - - { - D.name(), - (getter)PyBobLearnEMISVBase_getD, - (setter)PyBobLearnEMISVBase_setD, - D.doc(), - 0 - }, - - { - ubm.name(), - (getter)PyBobLearnEMISVBase_getUBM, - (setter)PyBobLearnEMISVBase_setUBM, - ubm.doc(), - 0 - }, - - - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - - -/*** save ***/ -static auto save = bob::extension::FunctionDoc( - "save", - "Save the configuration of the ISVBase to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for writing"); -static PyObject* PyBobLearnEMISVBase_Save(PyBobLearnEMISVBaseObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - // get list of arguments - char** kwlist = save.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->save(*hdf5->f); - - BOB_CATCH_MEMBER("cannot save the data", 0) - Py_RETURN_NONE; -} - -/*** load ***/ -static auto load = bob::extension::FunctionDoc( - "load", - "Load the configuration of the ISVBase to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading"); -static PyObject* PyBobLearnEMISVBase_Load(PyBobLearnEMISVBaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = load.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->load(*hdf5->f); - - BOB_CATCH_MEMBER("cannot load the data", 0) - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this ISVBase with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` " - "and any other values internal to this machine." -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.ISVBase`", "A ISVBase object to be compared.") -.add_parameter("r_epsilon", "float", "Relative precision.") -.add_parameter("a_epsilon", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMISVBase_IsSimilarTo(PyBobLearnEMISVBaseObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - //PyObject* other = 0; - PyBobLearnEMISVBaseObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMISVBase_Type, &other, - &r_epsilon, &a_epsilon)){ - - is_similar_to.print_usage(); - return 0; - } - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - -/*** resize ***/ -static auto resize = bob::extension::FunctionDoc( - "resize", - "Resets the dimensionality of the subspace U. " - "U is hence uninitialized.", - 0, - true -) -.add_prototype("rU") -.add_parameter("rU", "int", "Size of U (Within client variation matrix)"); -static PyObject* PyBobLearnEMISVBase_resize(PyBobLearnEMISVBaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = resize.kwlist(0); - - int rU = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &rU)) return 0; - - if (rU <= 0){ - PyErr_Format(PyExc_TypeError, "rU must be greater than zero"); - resize.print_usage(); - return 0; - } - - self->cxx->resize(rU); - - BOB_CATCH_MEMBER("cannot perform the resize method", 0) - - Py_RETURN_NONE; -} - - - - -static PyMethodDef PyBobLearnEMISVBase_methods[] = { - { - save.name(), - (PyCFunction)PyBobLearnEMISVBase_Save, - METH_VARARGS|METH_KEYWORDS, - save.doc() - }, - { - load.name(), - (PyCFunction)PyBobLearnEMISVBase_Load, - METH_VARARGS|METH_KEYWORDS, - load.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMISVBase_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - { - resize.name(), - (PyCFunction)PyBobLearnEMISVBase_resize, - METH_VARARGS|METH_KEYWORDS, - resize.doc() - }, - - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the ISV type struct; will be initialized later -PyTypeObject PyBobLearnEMISVBase_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMISVBase(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMISVBase_Type.tp_name = ISVBase_doc.name(); - PyBobLearnEMISVBase_Type.tp_basicsize = sizeof(PyBobLearnEMISVBaseObject); - PyBobLearnEMISVBase_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyBobLearnEMISVBase_Type.tp_doc = ISVBase_doc.doc(); - - // set the functions - PyBobLearnEMISVBase_Type.tp_new = PyType_GenericNew; - PyBobLearnEMISVBase_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMISVBase_init); - PyBobLearnEMISVBase_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMISVBase_delete); - PyBobLearnEMISVBase_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMISVBase_RichCompare); - PyBobLearnEMISVBase_Type.tp_methods = PyBobLearnEMISVBase_methods; - PyBobLearnEMISVBase_Type.tp_getset = PyBobLearnEMISVBase_getseters; - //PyBobLearnEMISVBase_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMISVBase_forward); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMISVBase_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMISVBase_Type); - return PyModule_AddObject(module, "ISVBase", (PyObject*)&PyBobLearnEMISVBase_Type) >= 0; -} - diff --git a/bob/learn/em/isv_machine.cpp b/bob/learn/em/isv_machine.cpp deleted file mode 100644 index 097467a553d36b617fe1be644e3fddc04ba52bbf..0000000000000000000000000000000000000000 --- a/bob/learn/em/isv_machine.cpp +++ /dev/null @@ -1,702 +0,0 @@ -/** - * @date Wed Jan 28 13:03:15 2015 +0200 - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static auto ISVMachine_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".ISVMachine", - "A ISVMachine. An attached :py:class:`bob.learn.em.ISVBase` should be provided for Joint Factor Analysis. The :py:class:`bob.learn.em.ISVMachine` carries information about the speaker factors :math:`y` and :math:`z`, whereas a :py:class:`bob.learn.em.JFABase` carries information about the matrices :math:`U` and :math:`D`.\n\n" - "References: [Vogt2008]_ [McCool2013]_", - "" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Constructor. Builds a new ISVMachine", - "", - true - ) - .add_prototype("isv_base","") - .add_prototype("other","") - .add_prototype("hdf5","") - - .add_parameter("isv_base", ":py:class:`bob.learn.em.ISVBase`", "The ISVBase associated with this machine") - .add_parameter("other", ":py:class:`bob.learn.em.ISVMachine`", "A ISVMachine object to be copied.") - .add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading") - -); - - -static int PyBobLearnEMISVMachine_init_copy(PyBobLearnEMISVMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = ISVMachine_doc.kwlist(1); - PyBobLearnEMISVMachineObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMISVMachine_Type, &o)){ - ISVMachine_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::ISVMachine(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMISVMachine_init_hdf5(PyBobLearnEMISVMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = ISVMachine_doc.kwlist(2); - - PyBobIoHDF5FileObject* config = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBobIoHDF5File_Converter, &config)){ - ISVMachine_doc.print_usage(); - return -1; - } - auto config_ = make_safe(config); - self->cxx.reset(new bob::learn::em::ISVMachine(*(config->f))); - - return 0; -} - - -static int PyBobLearnEMISVMachine_init_isvbase(PyBobLearnEMISVMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = ISVMachine_doc.kwlist(0); - - PyBobLearnEMISVBaseObject* isv_base; - - //Here we have to select which keyword argument to read - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMISVBase_Type, &isv_base)){ - ISVMachine_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::ISVMachine(isv_base->cxx)); - return 0; -} - - -static int PyBobLearnEMISVMachine_init(PyBobLearnEMISVMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - if(nargs == 1){ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is Gaussian object - if (PyBobLearnEMISVMachine_Check(arg)) - return PyBobLearnEMISVMachine_init_copy(self, args, kwargs); - // If the constructor input is a HDF5 - else if (PyBobIoHDF5File_Check(arg)) - return PyBobLearnEMISVMachine_init_hdf5(self, args, kwargs); - // If the constructor input is a JFABase Object - else - return PyBobLearnEMISVMachine_init_isvbase(self, args, kwargs); - } - else{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires only 1 argument, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - ISVMachine_doc.print_usage(); - return -1; - } - - BOB_CATCH_MEMBER("cannot create ISVMachine", -1) - return 0; -} - -static void PyBobLearnEMISVMachine_delete(PyBobLearnEMISVMachineObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* PyBobLearnEMISVMachine_RichCompare(PyBobLearnEMISVMachineObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMISVMachine_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMISVMachineObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare ISVMachine objects", 0) -} - -int PyBobLearnEMISVMachine_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMISVMachine_Type)); -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** shape *****/ -static auto shape = bob::extension::VariableDoc( - "shape", - "(int,int, int, int)", - "A tuple that represents the number of gaussians, dimensionality of each Gaussian and dimensionality of the rU (within client variability matrix)) ``(#Gaussians, #Inputs, #rU)``.", - "" -); -PyObject* PyBobLearnEMISVMachine_getShape(PyBobLearnEMISVMachineObject* self, void*) { - BOB_TRY - return Py_BuildValue("(i,i,i)", self->cxx->getNGaussians(), self->cxx->getNInputs(), self->cxx->getDimRu()); - BOB_CATCH_MEMBER("shape could not be read", 0) -} - -/***** supervector_length *****/ -static auto supervector_length = bob::extension::VariableDoc( - "supervector_length", - "int", - - "Returns the supervector length.", - "NGaussians x NInputs: Number of Gaussian components by the feature dimensionality. " - "An exception is thrown if no Universal Background Model has been set yet." - "" -); -PyObject* PyBobLearnEMISVMachine_getSupervectorLength(PyBobLearnEMISVMachineObject* self, void*) { - BOB_TRY - return Py_BuildValue("i", self->cxx->getSupervectorLength()); - BOB_CATCH_MEMBER("supervector_length could not be read", 0) -} - -/***** z *****/ -static auto Z = bob::extension::VariableDoc( - "z", - "array_like <float, 1D>", - "Returns the :math:`z` speaker factor. Eq (31) from [McCool2013]_", - "" -); -PyObject* PyBobLearnEMISVMachine_getZ(PyBobLearnEMISVMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getZ()); - BOB_CATCH_MEMBER("`z` could not be read", 0) -} -int PyBobLearnEMISVMachine_setZ(PyBobLearnEMISVMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, Z.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, Z.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, Z.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getZ().extent(0)) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getZ().extent(0), (Py_ssize_t)input->shape[0], Z.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "z"); - if (!b) return -1; - self->cxx->setZ(*b); - return 0; - BOB_CATCH_MEMBER("`z` vector could not be set", -1) -} - - -/***** x *****/ -static auto X = bob::extension::VariableDoc( - "x", - "array_like <float, 1D>", - "Returns the :math:`X` session factor. Eq (29) from [McCool2013]_", - "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 :math:`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." -); -PyObject* PyBobLearnEMISVMachine_getX(PyBobLearnEMISVMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getX()); - BOB_CATCH_MEMBER("`x` could not be read", 0) -} -int PyBobLearnEMISVMachine_setX(PyBobLearnEMISVMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, X.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, X.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, X.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getX().extent(0)) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getX().extent(0), (Py_ssize_t)input->shape[0], X.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "x"); - if (!b) return -1; - self->cxx->setX(*b); - return 0; - BOB_CATCH_MEMBER("`x` vector could not be set", -1) -} - - -/***** isv_base *****/ -static auto isv_base = bob::extension::VariableDoc( - "isv_base", - ":py:class:`bob.learn.em.ISVBase`", - "The ISVBase attached to this machine", - "" -); -PyObject* PyBobLearnEMISVMachine_getISVBase(PyBobLearnEMISVMachineObject* self, void*){ - BOB_TRY - - boost::shared_ptr<bob::learn::em::ISVBase> isv_base_o = self->cxx->getISVBase(); - - //Allocating the correspondent python object - PyBobLearnEMISVBaseObject* retval = - (PyBobLearnEMISVBaseObject*)PyBobLearnEMISVBase_Type.tp_alloc(&PyBobLearnEMISVBase_Type, 0); - retval->cxx = isv_base_o; - - return Py_BuildValue("N",retval); - BOB_CATCH_MEMBER("isv_base could not be read", 0) -} -int PyBobLearnEMISVMachine_setISVBase(PyBobLearnEMISVMachineObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyBobLearnEMISVBase_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a :py:class:`bob.learn.em.ISVBase`", Py_TYPE(self)->tp_name, isv_base.name()); - return -1; - } - - PyBobLearnEMISVBaseObject* isv_base_o = 0; - PyArg_Parse(value, "O!", &PyBobLearnEMISVBase_Type,&isv_base_o); - - self->cxx->setISVBase(isv_base_o->cxx); - - return 0; - BOB_CATCH_MEMBER("isv_base could not be set", -1) -} - - - - -static PyGetSetDef PyBobLearnEMISVMachine_getseters[] = { - { - shape.name(), - (getter)PyBobLearnEMISVMachine_getShape, - 0, - shape.doc(), - 0 - }, - - { - supervector_length.name(), - (getter)PyBobLearnEMISVMachine_getSupervectorLength, - 0, - supervector_length.doc(), - 0 - }, - - { - isv_base.name(), - (getter)PyBobLearnEMISVMachine_getISVBase, - (setter)PyBobLearnEMISVMachine_setISVBase, - isv_base.doc(), - 0 - }, - - { - Z.name(), - (getter)PyBobLearnEMISVMachine_getZ, - (setter)PyBobLearnEMISVMachine_setZ, - Z.doc(), - 0 - }, - - { - X.name(), - (getter)PyBobLearnEMISVMachine_getX, - (setter)PyBobLearnEMISVMachine_setX, - X.doc(), - 0 - }, - - - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - - -/*** save ***/ -static auto save = bob::extension::FunctionDoc( - "save", - "Save the configuration of the ISVMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for writing"); -static PyObject* PyBobLearnEMISVMachine_Save(PyBobLearnEMISVMachineObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - // get list of arguments - char** kwlist = save.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->save(*hdf5->f); - - BOB_CATCH_MEMBER("cannot save the data", 0) - Py_RETURN_NONE; -} - -/*** load ***/ -static auto load = bob::extension::FunctionDoc( - "load", - "Load the configuration of the ISVMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading"); -static PyObject* PyBobLearnEMISVMachine_Load(PyBobLearnEMISVMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = load.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->load(*hdf5->f); - - BOB_CATCH_MEMBER("cannot load the data", 0) - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this ISVMachine with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` " - "and any other values internal to this machine." -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.ISVMachine`", "A ISVMachine object to be compared.") -.add_parameter("r_epsilon", "float", "Relative precision.") -.add_parameter("a_epsilon", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMISVMachine_IsSimilarTo(PyBobLearnEMISVMachineObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - //PyObject* other = 0; - PyBobLearnEMISVMachineObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMISVMachine_Type, &other, - &r_epsilon, &a_epsilon)){ - - is_similar_to.print_usage(); - return 0; - } - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - -/*** estimate_x ***/ -static auto estimate_x = bob::extension::FunctionDoc( - "estimate_x", - "Estimates the session offset x (LPT assumption) given GMM statistics.", - "Estimates :math:`x` from the GMM statistics considering the LPT assumption, that is the latent session variable :math:`x` is approximated using the UBM", - true -) -.add_prototype("stats,input") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics of the GMM") -.add_parameter("input", "array_like <float, 1D>", "Input vector"); -static PyObject* PyBobLearnEMISVMachine_estimateX(PyBobLearnEMISVMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = estimate_x.kwlist(0); - - PyBobLearnEMGMMStatsObject* stats = 0; - PyBlitzArrayObject* input = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMStats_Type, &stats, - &PyBlitzArray_Converter,&input)) - return 0; - - //protects acquired resources through this scope - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, estimate_x.name()); - return 0; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, estimate_x.name()); - return 0; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), (Py_ssize_t)input->shape[0], estimate_x.name()); - return 0; - } - - self->cxx->estimateX(*stats->cxx, *PyBlitzArrayCxx_AsBlitz<double,1>(input)); - - BOB_CATCH_MEMBER("cannot estimate X", 0) - Py_RETURN_NONE; -} - - -/*** estimate_ux ***/ -static auto estimate_ux = bob::extension::FunctionDoc( - "estimate_ux", - "Estimates Ux (LPT assumption) given GMM statistics.", - "Estimates Ux from the GMM statistics considering the LPT assumption, that is the latent session variable x is approximated using the UBM.", - true -) -.add_prototype("stats,input") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics of the GMM") -.add_parameter("input", "array_like <float, 1D>", "Input vector"); -static PyObject* PyBobLearnEMISVMachine_estimateUx(PyBobLearnEMISVMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = estimate_ux.kwlist(0); - - PyBobLearnEMGMMStatsObject* stats = 0; - PyBlitzArrayObject* input = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMStats_Type, &stats, - &PyBlitzArray_Converter,&input)) - return 0; - - //protects acquired resources through this scope - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, estimate_ux.name()); - return 0; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, estimate_ux.name()); - return 0; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs()) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs()*(Py_ssize_t)self->cxx->getNGaussians(), (Py_ssize_t)input->shape[0], estimate_ux.name()); - return 0; - } - - self->cxx->estimateUx(*stats->cxx, *PyBlitzArrayCxx_AsBlitz<double,1>(input)); - - BOB_CATCH_MEMBER("cannot estimate Ux", 0) - Py_RETURN_NONE; -} - - -/*** forward_ux ***/ -static auto forward_ux = bob::extension::FunctionDoc( - "forward_ux", - "Computes a score for the given UBM statistics and given the Ux vector", - "", - true -) -.add_prototype("stats,ux") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics as input") -.add_parameter("ux", "array_like <float, 1D>", "Input vector"); -static PyObject* PyBobLearnEMISVMachine_ForwardUx(PyBobLearnEMISVMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = forward_ux.kwlist(0); - - PyBobLearnEMGMMStatsObject* stats = 0; - PyBlitzArrayObject* ux_input = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMStats_Type, &stats, - &PyBlitzArray_Converter,&ux_input)) - return 0; - - //protects acquired resources through this scope - auto ux_input_ = make_safe(ux_input); - - // perform check on the input - if (ux_input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, forward_ux.name()); - return 0; - } - - if (ux_input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, forward_ux.name()); - return 0; - } - - if (ux_input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs()) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs(), (Py_ssize_t)ux_input->shape[0], forward_ux.name()); - return 0; - } - double score = self->cxx->forward(*stats->cxx, *PyBlitzArrayCxx_AsBlitz<double,1>(ux_input)); - - return Py_BuildValue("d", score); - BOB_CATCH_MEMBER("cannot forward_ux", 0) -} - - -/*** forward ***/ -static auto forward = bob::extension::FunctionDoc( - "forward", - "Execute the machine", - "", - true -) -.add_prototype("stats") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics as input"); -static PyObject* PyBobLearnEMISVMachine_Forward(PyBobLearnEMISVMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = forward.kwlist(0); - - PyBobLearnEMGMMStatsObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMGMMStats_Type, &stats)) - return 0; - - //protects acquired resources through this scope - double score = self->cxx->forward(*stats->cxx); - - return Py_BuildValue("d", score); - BOB_CATCH_MEMBER("cannot forward", 0) - -} - - -static PyMethodDef PyBobLearnEMISVMachine_methods[] = { - { - save.name(), - (PyCFunction)PyBobLearnEMISVMachine_Save, - METH_VARARGS|METH_KEYWORDS, - save.doc() - }, - { - load.name(), - (PyCFunction)PyBobLearnEMISVMachine_Load, - METH_VARARGS|METH_KEYWORDS, - load.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMISVMachine_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - - { - estimate_x.name(), - (PyCFunction)PyBobLearnEMISVMachine_estimateX, - METH_VARARGS|METH_KEYWORDS, - estimate_x.doc() - }, - - { - estimate_ux.name(), - (PyCFunction)PyBobLearnEMISVMachine_estimateUx, - METH_VARARGS|METH_KEYWORDS, - estimate_ux.doc() - }, - - { - forward_ux.name(), - (PyCFunction)PyBobLearnEMISVMachine_ForwardUx, - METH_VARARGS|METH_KEYWORDS, - forward_ux.doc() - }, - - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the JFA type struct; will be initialized later -PyTypeObject PyBobLearnEMISVMachine_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMISVMachine(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMISVMachine_Type.tp_name = ISVMachine_doc.name(); - PyBobLearnEMISVMachine_Type.tp_basicsize = sizeof(PyBobLearnEMISVMachineObject); - PyBobLearnEMISVMachine_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyBobLearnEMISVMachine_Type.tp_doc = ISVMachine_doc.doc(); - - // set the functions - PyBobLearnEMISVMachine_Type.tp_new = PyType_GenericNew; - PyBobLearnEMISVMachine_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMISVMachine_init); - PyBobLearnEMISVMachine_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMISVMachine_delete); - PyBobLearnEMISVMachine_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMISVMachine_RichCompare); - PyBobLearnEMISVMachine_Type.tp_methods = PyBobLearnEMISVMachine_methods; - PyBobLearnEMISVMachine_Type.tp_getset = PyBobLearnEMISVMachine_getseters; - PyBobLearnEMISVMachine_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMISVMachine_Forward); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMISVMachine_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMISVMachine_Type); - return PyModule_AddObject(module, "ISVMachine", (PyObject*)&PyBobLearnEMISVMachine_Type) >= 0; -} - diff --git a/bob/learn/em/isv_trainer.cpp b/bob/learn/em/isv_trainer.cpp deleted file mode 100644 index dbf310d1ee27aa999ad019aa27fef29d720b4036..0000000000000000000000000000000000000000 --- a/bob/learn/em/isv_trainer.cpp +++ /dev/null @@ -1,612 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Mon 02 Fev 20:20:00 2015 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" -#include <boost/make_shared.hpp> - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static int extract_GMMStats_1d(PyObject *list, - std::vector<boost::shared_ptr<bob::learn::em::GMMStats> >& training_data) -{ - for (int i=0; i<PyList_GET_SIZE(list); i++){ - - PyBobLearnEMGMMStatsObject* stats; - if (!PyArg_Parse(PyList_GetItem(list, i), "O!", &PyBobLearnEMGMMStats_Type, &stats)){ - PyErr_Format(PyExc_RuntimeError, "Expected GMMStats objects"); - return -1; - } - training_data.push_back(stats->cxx); - } - return 0; -} - -static int extract_GMMStats_2d(PyObject *list, - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& training_data) -{ - for (int i=0; i<PyList_GET_SIZE(list); i++) - { - PyObject* another_list; - if(!PyArg_Parse(PyList_GetItem(list, i), "O!", &PyList_Type, &another_list)){ - PyErr_Format(PyExc_RuntimeError, "Expected a list of lists of GMMStats objects [[GMMStats,GMMStats],[GMMStats,GMMStats].....[GMMStats,GMMStats]]"); - return -1; - } - - std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > another_training_data; - for (int j=0; j<PyList_GET_SIZE(another_list); j++){ - - PyBobLearnEMGMMStatsObject* stats; - if (!PyArg_Parse(PyList_GetItem(another_list, j), "O!", &PyBobLearnEMGMMStats_Type, &stats)){ - PyErr_Format(PyExc_RuntimeError, "Expected GMMStats objects"); - return -1; - } - another_training_data.push_back(stats->cxx); - } - training_data.push_back(another_training_data); - } - return 0; -} - -template <int N> -static PyObject* vector_as_list(const std::vector<blitz::Array<double,N> >& vec) -{ - PyObject* list = PyList_New(vec.size()); - for(size_t i=0; i<vec.size(); i++){ - blitz::Array<double,N> numpy_array = vec[i]; - PyObject* numpy_py_object = PyBlitzArrayCxx_AsNumpy(numpy_array); - PyList_SET_ITEM(list, i, numpy_py_object); - } - return list; -} - -template <int N> -int list_as_vector(PyObject* list, std::vector<blitz::Array<double,N> >& vec) -{ - for (int i=0; i<PyList_GET_SIZE(list); i++) - { - PyBlitzArrayObject* blitz_object; - if (!PyArg_Parse(PyList_GetItem(list, i), "O&", &PyBlitzArray_Converter, &blitz_object)){ - PyErr_Format(PyExc_RuntimeError, "Expected numpy array object"); - return -1; - } - auto blitz_object_ = make_safe(blitz_object); - vec.push_back(*PyBlitzArrayCxx_AsBlitz<double,N>(blitz_object)); - } - return 0; -} - - - -static auto ISVTrainer_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".ISVTrainer", - "ISVTrainer" - "Train Intersession varibility modeling :ref:`ISV <isv>`.", - "" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Constructor. Builds a new ISVTrainer", - "", - true - ) - .add_prototype("relevance_factor","") - .add_prototype("other","") - .add_prototype("","") - .add_parameter("other", ":py:class:`bob.learn.em.ISVTrainer`", "A ISVTrainer object to be copied.") - .add_parameter("relevance_factor", "float", "") -); - - -static int PyBobLearnEMISVTrainer_init_copy(PyBobLearnEMISVTrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = ISVTrainer_doc.kwlist(1); - PyBobLearnEMISVTrainerObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMISVTrainer_Type, &o)){ - ISVTrainer_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::ISVTrainer(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMISVTrainer_init_number(PyBobLearnEMISVTrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = ISVTrainer_doc.kwlist(0); - double relevance_factor = 4.; - - //Parsing the input argments - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d", kwlist, &relevance_factor)) - return -1; - - if(relevance_factor < 0){ - PyErr_Format(PyExc_TypeError, "gaussians argument must be greater than zero"); - return -1; - } - - self->cxx.reset(new bob::learn::em::ISVTrainer(relevance_factor)); - return 0; -} - - -static int PyBobLearnEMISVTrainer_init(PyBobLearnEMISVTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - switch(nargs){ - case 0:{ - self->cxx.reset(new bob::learn::em::ISVTrainer()); - return 0; - } - case 1:{ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - if(PyBobLearnEMISVTrainer_Check(arg)) - // If the constructor input is ISVTrainer object - return PyBobLearnEMISVTrainer_init_copy(self, args, kwargs); - else - return PyBobLearnEMISVTrainer_init_number(self, args, kwargs); - - } - default:{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires only 0 or 1 arguments, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - ISVTrainer_doc.print_usage(); - return -1; - } - } - BOB_CATCH_MEMBER("cannot create ISVTrainer", -1) - return 0; -} - - -static void PyBobLearnEMISVTrainer_delete(PyBobLearnEMISVTrainerObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - - -int PyBobLearnEMISVTrainer_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMISVTrainer_Type)); -} - - -static PyObject* PyBobLearnEMISVTrainer_RichCompare(PyBobLearnEMISVTrainerObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMISVTrainer_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMISVTrainerObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare ISVTrainer objects", 0) -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -static auto acc_u_a1 = bob::extension::VariableDoc( - "acc_u_a1", - "array_like <float, 3D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMISVTrainer_get_acc_u_a1(PyBobLearnEMISVTrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccUA1()); - BOB_CATCH_MEMBER("acc_u_a1 could not be read", 0) -} -int PyBobLearnEMISVTrainer_set_acc_u_a1(PyBobLearnEMISVTrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 3D array of floats", Py_TYPE(self)->tp_name, acc_u_a1.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_u_a1.name()); - return -1; - } - - if (input->ndim != 3){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 3D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_u_a1.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getAccUA1().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccUA1().extent(1) && input->shape[2] != (Py_ssize_t)self->cxx->getAccUA1().extent(2)) { - PyErr_Format(PyExc_TypeError, "`%s' 3D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccUA1().extent(0), (Py_ssize_t)self->cxx->getAccUA1().extent(1), (Py_ssize_t)self->cxx->getAccUA1().extent(2), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], (Py_ssize_t)input->shape[2], acc_u_a1.name()); - return -1; - } - - - auto b = PyBlitzArrayCxx_AsBlitz<double,3>(input, "acc_u_a1"); - if (!b) return -1; - self->cxx->setAccUA1(*b); - return 0; - BOB_CATCH_MEMBER("acc_u_a1 could not be set", -1) -} - - -static auto acc_u_a2 = bob::extension::VariableDoc( - "acc_u_a2", - "array_like <float, 2D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMISVTrainer_get_acc_u_a2(PyBobLearnEMISVTrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccUA2()); - BOB_CATCH_MEMBER("acc_u_a2 could not be read", 0) -} -int PyBobLearnEMISVTrainer_set_acc_u_a2(PyBobLearnEMISVTrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, acc_u_a2.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_u_a2.name()); - return -1; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_u_a2.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getAccUA2().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccUA2().extent(1)) { - PyErr_Format(PyExc_TypeError, "`%s' 3D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccUA2().extent(0), (Py_ssize_t)self->cxx->getAccUA2().extent(1), input->shape[0], input->shape[1], acc_u_a2.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "acc_u_a2"); - if (!b) return -1; - self->cxx->setAccUA2(*b); - return 0; - BOB_CATCH_MEMBER("acc_u_a2 could not be set", -1) -} - - -static auto __X__ = bob::extension::VariableDoc( - "__X__", - "list", - "", - "" -); -PyObject* PyBobLearnEMISVTrainer_get_X(PyBobLearnEMISVTrainerObject* self, void*){ - BOB_TRY - return vector_as_list(self->cxx->getX()); - BOB_CATCH_MEMBER("__X__ could not be read", 0) -} -int PyBobLearnEMISVTrainer_set_X(PyBobLearnEMISVTrainerObject* self, PyObject* value, void*){ - BOB_TRY - - // Parses input arguments in a single shot - if (!PyList_Check(value)){ - PyErr_Format(PyExc_TypeError, "Expected a list in `%s'", __X__.name()); - return -1; - } - - std::vector<blitz::Array<double,2> > data; - if(list_as_vector(value ,data)==0){ - self->cxx->setX(data); - } - - return 0; - BOB_CATCH_MEMBER("__X__ could not be written", -1) -} - - -static auto __Z__ = bob::extension::VariableDoc( - "__Z__", - "list", - "", - "" -); -PyObject* PyBobLearnEMISVTrainer_get_Z(PyBobLearnEMISVTrainerObject* self, void*){ - BOB_TRY - return vector_as_list(self->cxx->getZ()); - BOB_CATCH_MEMBER("__Z__ could not be read", 0) -} -int PyBobLearnEMISVTrainer_set_Z(PyBobLearnEMISVTrainerObject* self, PyObject* value, void*){ - BOB_TRY - - // Parses input arguments in a single shot - if (!PyList_Check(value)){ - PyErr_Format(PyExc_TypeError, "Expected a list in `%s'", __Z__.name()); - return -1; - } - - std::vector<blitz::Array<double,1> > data; - if(list_as_vector(value ,data)==0){ - self->cxx->setZ(data); - } - - return 0; - BOB_CATCH_MEMBER("__Z__ could not be written", -1) -} - - -static PyGetSetDef PyBobLearnEMISVTrainer_getseters[] = { - { - acc_u_a1.name(), - (getter)PyBobLearnEMISVTrainer_get_acc_u_a1, - (setter)PyBobLearnEMISVTrainer_set_acc_u_a1, - acc_u_a1.doc(), - 0 - }, - { - acc_u_a2.name(), - (getter)PyBobLearnEMISVTrainer_get_acc_u_a2, - (setter)PyBobLearnEMISVTrainer_set_acc_u_a2, - acc_u_a2.doc(), - 0 - }, - { - __X__.name(), - (getter)PyBobLearnEMISVTrainer_get_X, - (setter)PyBobLearnEMISVTrainer_set_X, - __X__.doc(), - 0 - }, - { - __Z__.name(), - (getter)PyBobLearnEMISVTrainer_get_Z, - (setter)PyBobLearnEMISVTrainer_set_Z, - __Z__.doc(), - 0 - }, - - - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - -/*** initialize ***/ -static auto initialize = bob::extension::FunctionDoc( - "initialize", - "Initialization before the EM steps", - "", - true -) -.add_prototype("isv_base, stats, [rng]") -.add_parameter("isv_base", ":py:class:`bob.learn.em.ISVBase`", "ISVBase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object") -.add_parameter("rng", ":py:class:`bob.core.random.mt19937`", "The Mersenne Twister mt19937 random generator used for the initialization of subspaces/arrays before the EM loop."); -static PyObject* PyBobLearnEMISVTrainer_initialize(PyBobLearnEMISVTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = initialize.kwlist(0); - - PyBobLearnEMISVBaseObject* isv_base = 0; - PyObject* stats = 0; - PyBoostMt19937Object* rng = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!|O!", kwlist, &PyBobLearnEMISVBase_Type, &isv_base, - &PyList_Type, &stats, - &PyBoostMt19937_Type, &rng)) return 0; - - if(rng){ - self->cxx->setRng(rng->rng); - } - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->initialize(*isv_base->cxx, training_data); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the initialize method", 0) - - Py_RETURN_NONE; -} - - -/*** e_step ***/ -static auto e_step = bob::extension::FunctionDoc( - "e_step", - "Call the e-step procedure (for the U subspace).", - "", - true -) -.add_prototype("isv_base, stats") -.add_parameter("isv_base", ":py:class:`bob.learn.em.ISVBase`", "ISVBase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object"); -static PyObject* PyBobLearnEMISVTrainer_e_step(PyBobLearnEMISVTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = e_step.kwlist(0); - - PyBobLearnEMISVBaseObject* isv_base = 0; - PyObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMISVBase_Type, &isv_base, - &PyList_Type, &stats)) return 0; - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->eStep(*isv_base->cxx, training_data); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the e_step method", 0) - - Py_RETURN_NONE; -} - - -/*** m_step ***/ -static auto m_step = bob::extension::FunctionDoc( - "m_step", - "Call the m-step procedure (for the U subspace).", - "", - true -) -.add_prototype("isv_base, [stats]") -.add_parameter("isv_base", ":py:class:`bob.learn.em.ISVBase`", "ISVBase Object") -.add_parameter("stats", "object", "Ignored."); -static PyObject* PyBobLearnEMISVTrainer_m_step(PyBobLearnEMISVTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = m_step.kwlist(0); - - PyBobLearnEMISVBaseObject* isv_base = 0; - PyObject* stats; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", kwlist, &PyBobLearnEMISVBase_Type, &isv_base, - &stats)) return 0; - - self->cxx->mStep(*isv_base->cxx); - - BOB_CATCH_MEMBER("cannot perform the m_step method", 0) - - Py_RETURN_NONE; -} - - - -/*** enroll ***/ -static auto enroll = bob::extension::FunctionDoc( - "enroll", - "", - "", - true -) -.add_prototype("isv_machine, features, n_iter") -.add_parameter("isv_machine", ":py:class:`bob.learn.em.ISVMachine`", "ISVMachine Object") -.add_parameter("features", "list(:py:class:`bob.learn.em.GMMStats`)`", "") -.add_parameter("n_iter", "int", "Number of iterations"); -static PyObject* PyBobLearnEMISVTrainer_enroll(PyBobLearnEMISVTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = enroll.kwlist(0); - - PyBobLearnEMISVMachineObject* isv_machine = 0; - PyObject* stats = 0; - int n_iter = 1; - - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!i", kwlist, &PyBobLearnEMISVMachine_Type, &isv_machine, - &PyList_Type, &stats, &n_iter)) return 0; - - std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > training_data; - if(extract_GMMStats_1d(stats ,training_data)==0) - self->cxx->enroll(*isv_machine->cxx, training_data, n_iter); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the enroll method", 0) - - Py_RETURN_NONE; -} - - - -static PyMethodDef PyBobLearnEMISVTrainer_methods[] = { - { - initialize.name(), - (PyCFunction)PyBobLearnEMISVTrainer_initialize, - METH_VARARGS|METH_KEYWORDS, - initialize.doc() - }, - { - e_step.name(), - (PyCFunction)PyBobLearnEMISVTrainer_e_step, - METH_VARARGS|METH_KEYWORDS, - e_step.doc() - }, - { - m_step.name(), - (PyCFunction)PyBobLearnEMISVTrainer_m_step, - METH_VARARGS|METH_KEYWORDS, - m_step.doc() - }, - { - enroll.name(), - (PyCFunction)PyBobLearnEMISVTrainer_enroll, - METH_VARARGS|METH_KEYWORDS, - enroll.doc() - }, - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMISVTrainer_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMISVTrainer(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMISVTrainer_Type.tp_name = ISVTrainer_doc.name(); - PyBobLearnEMISVTrainer_Type.tp_basicsize = sizeof(PyBobLearnEMISVTrainerObject); - PyBobLearnEMISVTrainer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;//Enable the class inheritance; - PyBobLearnEMISVTrainer_Type.tp_doc = ISVTrainer_doc.doc(); - - // set the functions - PyBobLearnEMISVTrainer_Type.tp_new = PyType_GenericNew; - PyBobLearnEMISVTrainer_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMISVTrainer_init); - PyBobLearnEMISVTrainer_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMISVTrainer_delete); - PyBobLearnEMISVTrainer_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMISVTrainer_RichCompare); - PyBobLearnEMISVTrainer_Type.tp_methods = PyBobLearnEMISVTrainer_methods; - PyBobLearnEMISVTrainer_Type.tp_getset = PyBobLearnEMISVTrainer_getseters; - //PyBobLearnEMISVTrainer_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMISVTrainer_compute_likelihood); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMISVTrainer_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMISVTrainer_Type); - return PyModule_AddObject(module, "ISVTrainer", (PyObject*)&PyBobLearnEMISVTrainer_Type) >= 0; -} diff --git a/bob/learn/em/ivector_machine.cpp b/bob/learn/em/ivector_machine.cpp deleted file mode 100644 index 159bec7415c9e44abe24675a75c8dc7bf28ed192..0000000000000000000000000000000000000000 --- a/bob/learn/em/ivector_machine.cpp +++ /dev/null @@ -1,673 +0,0 @@ -/** - * @date Wed Jan 28 17:46:15 2015 +0200 - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static auto IVectorMachine_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".IVectorMachine", - "Statistical model for the Total Variability training for more information and explanation see the user guide in documentation (:ref:`iVectors <ivector>`)" // this documentation text is intentionally written to be long! - "", - "" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Constructor. Builds a new IVectorMachine", - "", - true - ) - .add_prototype("ubm,rt,variance_threshold","") - .add_prototype("other","") - .add_prototype("hdf5","") - - .add_parameter("ubm", ":py:class:`bob.learn.em.GMMMachine`", "The Universal Background Model.") - .add_parameter("rt", "int", "Size of the Total Variability matrix (CD x rt).") - .add_parameter("variance_threshold", "float", "Variance flooring threshold for the :math:`\\Sigma` (diagonal) matrix") - - .add_parameter("other", ":py:class:`bob.learn.em.IVectorMachine`", "A IVectorMachine object to be copied.") - .add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading") - -); - - -static int PyBobLearnEMIVectorMachine_init_copy(PyBobLearnEMIVectorMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = IVectorMachine_doc.kwlist(1); - PyBobLearnEMIVectorMachineObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMIVectorMachine_Type, &o)){ - IVectorMachine_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::IVectorMachine(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMIVectorMachine_init_hdf5(PyBobLearnEMIVectorMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = IVectorMachine_doc.kwlist(2); - - PyBobIoHDF5FileObject* config = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBobIoHDF5File_Converter, &config)){ - IVectorMachine_doc.print_usage(); - return -1; - } - auto config_ = make_safe(config); - self->cxx.reset(new bob::learn::em::IVectorMachine(*(config->f))); - - return 0; -} - - -static int PyBobLearnEMIVectorMachine_init_ubm(PyBobLearnEMIVectorMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = IVectorMachine_doc.kwlist(0); - - PyBobLearnEMGMMMachineObject* gmm_machine; - int rt = 1; - double variance_threshold = 1e-10; - - //Here we have to select which keyword argument to read - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!i|d", kwlist, &PyBobLearnEMGMMMachine_Type, &gmm_machine, - &rt, &variance_threshold)){ - IVectorMachine_doc.print_usage(); - return -1; - } - - if(rt < 1){ - PyErr_Format(PyExc_TypeError, "rt argument must be greater than or equal to one"); - return -1; - } - - if(variance_threshold <= 0){ - PyErr_Format(PyExc_TypeError, "variance_threshold argument must be greater than zero"); - return -1; - } - - self->cxx.reset(new bob::learn::em::IVectorMachine(gmm_machine->cxx, rt, variance_threshold)); - return 0; -} - - -static int PyBobLearnEMIVectorMachine_init(PyBobLearnEMIVectorMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - if(nargs == 1){ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is Gaussian object - if (PyBobLearnEMIVectorMachine_Check(arg)) - return PyBobLearnEMIVectorMachine_init_copy(self, args, kwargs); - // If the constructor input is a HDF5 - else - return PyBobLearnEMIVectorMachine_init_hdf5(self, args, kwargs); - } - else if ((nargs == 2) || (nargs == 3)) - PyBobLearnEMIVectorMachine_init_ubm(self, args, kwargs); - else{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires 1,2 or 3 argument, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - IVectorMachine_doc.print_usage(); - return -1; - } - - BOB_CATCH_MEMBER("cannot create IVectorMachine", -1) - return 0; -} - -static void PyBobLearnEMIVectorMachine_delete(PyBobLearnEMIVectorMachineObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* PyBobLearnEMIVectorMachine_RichCompare(PyBobLearnEMIVectorMachineObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMIVectorMachine_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMIVectorMachineObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare IVectorMachine objects", 0) -} - -int PyBobLearnEMIVectorMachine_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMIVectorMachine_Type)); -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** shape *****/ -static auto shape = bob::extension::VariableDoc( - "shape", - "(int,int, int)", - "A tuple that represents the number of gaussians, dimensionality of each Gaussian, dimensionality of the rT (total variability matrix) ``(#Gaussians, #Inputs, #rT)``.", - "" -); -PyObject* PyBobLearnEMIVectorMachine_getShape(PyBobLearnEMIVectorMachineObject* self, void*) { - BOB_TRY - return Py_BuildValue("(i,i,i)", self->cxx->getNGaussians(), self->cxx->getNInputs(), self->cxx->getDimRt()); - BOB_CATCH_MEMBER("shape could not be read", 0) -} - -/***** supervector_length *****/ -static auto supervector_length = bob::extension::VariableDoc( - "supervector_length", - "int", - - "Returns the supervector length.", - "NGaussians x NInputs: Number of Gaussian components by the feature dimensionality" - "An exception is thrown if no Universal Background Model has been set yet." - "" -); -PyObject* PyBobLearnEMIVectorMachine_getSupervectorLength(PyBobLearnEMIVectorMachineObject* self, void*) { - BOB_TRY - return Py_BuildValue("i", self->cxx->getSupervectorLength()); - BOB_CATCH_MEMBER("supervector_length could not be read", 0) -} - - -/***** T *****/ -static auto T = bob::extension::VariableDoc( - "t", - "array_like <float, 2D>", - "Returns the Total Variability matrix, :math:`T`", - "" -); -PyObject* PyBobLearnEMIVectorMachine_getT(PyBobLearnEMIVectorMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getT()); - BOB_CATCH_MEMBER("`t` could not be read", 0) -} -int PyBobLearnEMIVectorMachine_setT(PyBobLearnEMIVectorMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, T.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(o, "t"); - if (!b) return -1; - self->cxx->setT(*b); - return 0; - BOB_CATCH_MEMBER("`t` vector could not be set", -1) -} - - -/***** sigma *****/ -static auto sigma = bob::extension::VariableDoc( - "sigma", - "array_like <float, 1D>", - "The residual matrix of the model sigma", - "" -); -PyObject* PyBobLearnEMIVectorMachine_getSigma(PyBobLearnEMIVectorMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getSigma()); - BOB_CATCH_MEMBER("`sigma` could not be read", 0) -} -int PyBobLearnEMIVectorMachine_setSigma(PyBobLearnEMIVectorMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, sigma.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(o, "sigma"); - if (!b) return -1; - self->cxx->setSigma(*b); - return 0; - BOB_CATCH_MEMBER("`sigma` vector could not be set", -1) -} - - -/***** variance_threshold *****/ -static auto variance_threshold = bob::extension::VariableDoc( - "variance_threshold", - "float", - "Threshold for the variance contained in sigma", - "" -); -PyObject* PyBobLearnEMIVectorMachine_getVarianceThreshold(PyBobLearnEMIVectorMachineObject* self, void*) { - BOB_TRY - return Py_BuildValue("d", self->cxx->getVarianceThreshold()); - BOB_CATCH_MEMBER("variance_threshold could not be read", 0) -} -int PyBobLearnEMIVectorMachine_setVarianceThreshold(PyBobLearnEMIVectorMachineObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyBob_NumberCheck(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a float", Py_TYPE(self)->tp_name, variance_threshold.name()); - return -1; - } - - if (PyFloat_AS_DOUBLE(value) < 0){ - PyErr_Format(PyExc_TypeError, "variance_threshold must be greater than or equal to zero"); - return -1; - } - - self->cxx->setVarianceThreshold(PyFloat_AS_DOUBLE(value)); - BOB_CATCH_MEMBER("variance_threshold could not be set", -1) - return 0; -} - - -/***** ubm *****/ -static auto ubm = bob::extension::VariableDoc( - "ubm", - ":py:class:`bob.learn.em.GMMMachine`", - "Returns the UBM (Universal Background Model)", - "" -); -PyObject* PyBobLearnEMIVectorMachine_getUBM(PyBobLearnEMIVectorMachineObject* self, void*){ - BOB_TRY - - boost::shared_ptr<bob::learn::em::GMMMachine> ubm_gmmMachine = self->cxx->getUbm(); - - //Allocating the correspondent python object - PyBobLearnEMGMMMachineObject* retval = - (PyBobLearnEMGMMMachineObject*)PyBobLearnEMGMMMachine_Type.tp_alloc(&PyBobLearnEMGMMMachine_Type, 0); - retval->cxx = ubm_gmmMachine; - - return Py_BuildValue("N",retval); - BOB_CATCH_MEMBER("ubm could not be read", 0) -} -int PyBobLearnEMIVectorMachine_setUBM(PyBobLearnEMIVectorMachineObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyBobLearnEMGMMMachine_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a :py:class:`bob.learn.em.GMMMachine`", Py_TYPE(self)->tp_name, ubm.name()); - return -1; - } - - PyBobLearnEMGMMMachineObject* ubm_gmmMachine = 0; - PyArg_Parse(value, "O!", &PyBobLearnEMGMMMachine_Type,&ubm_gmmMachine); - - self->cxx->setUbm(ubm_gmmMachine->cxx); - - return 0; - BOB_CATCH_MEMBER("ubm could not be set", -1) -} - - -static PyGetSetDef PyBobLearnEMIVectorMachine_getseters[] = { - { - shape.name(), - (getter)PyBobLearnEMIVectorMachine_getShape, - 0, - shape.doc(), - 0 - }, - - { - supervector_length.name(), - (getter)PyBobLearnEMIVectorMachine_getSupervectorLength, - 0, - supervector_length.doc(), - 0 - }, - - { - T.name(), - (getter)PyBobLearnEMIVectorMachine_getT, - (setter)PyBobLearnEMIVectorMachine_setT, - T.doc(), - 0 - }, - - { - variance_threshold.name(), - (getter)PyBobLearnEMIVectorMachine_getVarianceThreshold, - (setter)PyBobLearnEMIVectorMachine_setVarianceThreshold, - variance_threshold.doc(), - 0 - }, - - { - sigma.name(), - (getter)PyBobLearnEMIVectorMachine_getSigma, - (setter)PyBobLearnEMIVectorMachine_setSigma, - sigma.doc(), - 0 - }, - - { - ubm.name(), - (getter)PyBobLearnEMIVectorMachine_getUBM, - (setter)PyBobLearnEMIVectorMachine_setUBM, - ubm.doc(), - 0 - }, - - - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - - -/*** save ***/ -static auto save = bob::extension::FunctionDoc( - "save", - "Save the configuration of the IVectorMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for writing"); -static PyObject* PyBobLearnEMIVectorMachine_Save(PyBobLearnEMIVectorMachineObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - // get list of arguments - char** kwlist = save.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->save(*hdf5->f); - - BOB_CATCH_MEMBER("cannot save the data", 0) - Py_RETURN_NONE; -} - -/*** load ***/ -static auto load = bob::extension::FunctionDoc( - "load", - "Load the configuration of the IVectorMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading"); -static PyObject* PyBobLearnEMIVectorMachine_Load(PyBobLearnEMIVectorMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = load.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->load(*hdf5->f); - - BOB_CATCH_MEMBER("cannot load the data", 0) - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this IVectorMachine with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` " - "and any other values internal to this machine." -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.IVectorMachine`", "A IVectorMachine object to be compared.") -.add_parameter("r_epsilon", "float", "Relative precision.") -.add_parameter("a_epsilon", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMIVectorMachine_IsSimilarTo(PyBobLearnEMIVectorMachineObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - //PyObject* other = 0; - PyBobLearnEMIVectorMachineObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMIVectorMachine_Type, &other, - &r_epsilon, &a_epsilon)){ - - is_similar_to.print_usage(); - return 0; - } - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - - -/*** project ***/ -static auto project = bob::extension::FunctionDoc( - "project", - "Projects the given GMM statistics into the i-vector subspace", - ".. note:: The ``__call__`` function is an alias for this function", - true -) -.add_prototype("stats") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics as input"); -static PyObject* PyBobLearnEMIVectorMachine_project(PyBobLearnEMIVectorMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = project.kwlist(0); - - PyBobLearnEMGMMStatsObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMGMMStats_Type, &stats)) - return 0; - - blitz::Array<double,1> ivector(self->cxx->getDimRt()); - self->cxx->forward(*stats->cxx, ivector); - - return PyBlitzArrayCxx_AsConstNumpy(ivector); - - BOB_CATCH_MEMBER("cannot project", 0) - -} - -/*** resize ***/ -static auto resize = bob::extension::FunctionDoc( - "resize", - "Resets the dimensionality of the subspace T. ", - 0, - true -) -.add_prototype("rT") -.add_parameter("rT", "int", "Size of T (Total variability matrix)"); -static PyObject* PyBobLearnEMIVectorMachine_resize(PyBobLearnEMIVectorMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = resize.kwlist(0); - - int rT = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &rT)) return 0; - - if (rT < 1){ - PyErr_Format(PyExc_TypeError, "rU must be greater than one"); - resize.print_usage(); - return 0; - } - - self->cxx->resize(rT); - - BOB_CATCH_MEMBER("cannot perform the resize method", 0) - - Py_RETURN_NONE; -} - - -/*** __compute_Id_TtSigmaInvT__ ***/ -static auto __compute_Id_TtSigmaInvT__ = bob::extension::FunctionDoc( - "__compute_Id_TtSigmaInvT__", - "", - "", - true -) -.add_prototype("stats") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics as input"); -static PyObject* PyBobLearnEMIVectorMachine_compute_Id_TtSigmaInvT__(PyBobLearnEMIVectorMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = __compute_Id_TtSigmaInvT__.kwlist(0); - - PyBobLearnEMGMMStatsObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMGMMStats_Type, &stats)) - return 0; - - - blitz::Array<double,2> output(self->cxx->getDimRt(), self->cxx->getDimRt()); - self->cxx->computeIdTtSigmaInvT(*stats->cxx, output); - return PyBlitzArrayCxx_AsConstNumpy(output); - - BOB_CATCH_MEMBER("cannot __compute_Id_TtSigmaInvT__", 0) -} - - - -/*** __compute_TtSigmaInvFnorm__ ***/ -static auto __compute_TtSigmaInvFnorm__ = bob::extension::FunctionDoc( - "__compute_TtSigmaInvFnorm__", - "", - "", - true -) -.add_prototype("stats") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics as input"); -static PyObject* PyBobLearnEMIVectorMachine_compute_TtSigmaInvFnorm__(PyBobLearnEMIVectorMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = __compute_TtSigmaInvFnorm__.kwlist(0); - - PyBobLearnEMGMMStatsObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMGMMStats_Type, &stats)) - return 0; - - - blitz::Array<double,1> output(self->cxx->getDimRt()); - self->cxx->computeTtSigmaInvFnorm(*stats->cxx, output); - return PyBlitzArrayCxx_AsConstNumpy(output); - - BOB_CATCH_MEMBER("cannot __compute_TtSigmaInvFnorm__", 0) -} - - - - -static PyMethodDef PyBobLearnEMIVectorMachine_methods[] = { - { - save.name(), - (PyCFunction)PyBobLearnEMIVectorMachine_Save, - METH_VARARGS|METH_KEYWORDS, - save.doc() - }, - { - load.name(), - (PyCFunction)PyBobLearnEMIVectorMachine_Load, - METH_VARARGS|METH_KEYWORDS, - load.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMIVectorMachine_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - { - resize.name(), - (PyCFunction)PyBobLearnEMIVectorMachine_resize, - METH_VARARGS|METH_KEYWORDS, - resize.doc() - }, - { - project.name(), - (PyCFunction)PyBobLearnEMIVectorMachine_project, - METH_VARARGS|METH_KEYWORDS, - project.doc() - }, - { - __compute_Id_TtSigmaInvT__.name(), - (PyCFunction)PyBobLearnEMIVectorMachine_compute_Id_TtSigmaInvT__, - METH_VARARGS|METH_KEYWORDS, - __compute_Id_TtSigmaInvT__.doc() - }, - { - __compute_TtSigmaInvFnorm__.name(), - (PyCFunction)PyBobLearnEMIVectorMachine_compute_TtSigmaInvFnorm__, - METH_VARARGS|METH_KEYWORDS, - __compute_TtSigmaInvFnorm__.doc() - }, - - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the JFA type struct; will be initialized later -PyTypeObject PyBobLearnEMIVectorMachine_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMIVectorMachine(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMIVectorMachine_Type.tp_name = IVectorMachine_doc.name(); - PyBobLearnEMIVectorMachine_Type.tp_basicsize = sizeof(PyBobLearnEMIVectorMachineObject); - PyBobLearnEMIVectorMachine_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyBobLearnEMIVectorMachine_Type.tp_doc = IVectorMachine_doc.doc(); - - // set the functions - PyBobLearnEMIVectorMachine_Type.tp_new = PyType_GenericNew; - PyBobLearnEMIVectorMachine_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMIVectorMachine_init); - PyBobLearnEMIVectorMachine_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMIVectorMachine_delete); - PyBobLearnEMIVectorMachine_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMIVectorMachine_RichCompare); - PyBobLearnEMIVectorMachine_Type.tp_methods = PyBobLearnEMIVectorMachine_methods; - PyBobLearnEMIVectorMachine_Type.tp_getset = PyBobLearnEMIVectorMachine_getseters; - PyBobLearnEMIVectorMachine_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMIVectorMachine_project); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMIVectorMachine_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMIVectorMachine_Type); - return PyModule_AddObject(module, "IVectorMachine", (PyObject*)&PyBobLearnEMIVectorMachine_Type) >= 0; -} diff --git a/bob/learn/em/ivector_trainer.cpp b/bob/learn/em/ivector_trainer.cpp deleted file mode 100644 index 96f2c3af971959710c26fea302f9556321433e14..0000000000000000000000000000000000000000 --- a/bob/learn/em/ivector_trainer.cpp +++ /dev/null @@ -1,496 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Tue 03 Fev 10:29:00 2015 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" -#include <boost/make_shared.hpp> - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static inline bool f(PyObject* o){return o != 0 && PyObject_IsTrue(o) > 0;} /* converts PyObject to bool and returns false if object is NULL */ - -static int extract_GMMStats_1d(PyObject *list, - std::vector<bob::learn::em::GMMStats>& training_data) -{ - for (int i=0; i<PyList_GET_SIZE(list); i++){ - - PyBobLearnEMGMMStatsObject* stats; - if (!PyArg_Parse(PyList_GetItem(list, i), "O!", &PyBobLearnEMGMMStats_Type, &stats)){ - PyErr_Format(PyExc_RuntimeError, "Expected GMMStats objects"); - return -1; - } - training_data.push_back(*stats->cxx); - - } - return 0; -} - - -static auto IVectorTrainer_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".IVectorTrainer", - "IVectorTrainer" - "Trains the Total Variability subspace :math:`$T$` to generate :ref:`iVectors <ivector>`." - "", - "" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Constructor. Builds a new IVectorTrainer", - "", - true - ) - .add_prototype("update_sigma","") - .add_prototype("other","") - .add_prototype("","") - .add_parameter("other", ":py:class:`bob.learn.em.IVectorTrainer`", "A IVectorTrainer object to be copied.") - .add_parameter("update_sigma", "bool", "") -); - - -static int PyBobLearnEMIVectorTrainer_init_copy(PyBobLearnEMIVectorTrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = IVectorTrainer_doc.kwlist(1); - PyBobLearnEMIVectorTrainerObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMIVectorTrainer_Type, &o)){ - IVectorTrainer_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::IVectorTrainer(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMIVectorTrainer_init_bool(PyBobLearnEMIVectorTrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = IVectorTrainer_doc.kwlist(0); - PyObject* update_sigma = 0; - - //Parsing the input argments - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBool_Type, &update_sigma)) - return -1; - - self->cxx.reset(new bob::learn::em::IVectorTrainer(f(update_sigma))); - return 0; -} - - -static int PyBobLearnEMIVectorTrainer_init(PyBobLearnEMIVectorTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - switch(nargs){ - case 0:{ - self->cxx.reset(new bob::learn::em::IVectorTrainer()); - return 0; - } - case 1:{ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is IVectorTrainer object - if(PyBobLearnEMIVectorTrainer_Check(arg)) - return PyBobLearnEMIVectorTrainer_init_copy(self, args, kwargs); - else - return PyBobLearnEMIVectorTrainer_init_bool(self, args, kwargs); - - } - default:{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires only 0 or 1 arguments, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - IVectorTrainer_doc.print_usage(); - return -1; - } - } - BOB_CATCH_MEMBER("cannot create IVectorTrainer", -1) - return 0; -} - - -static void PyBobLearnEMIVectorTrainer_delete(PyBobLearnEMIVectorTrainerObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - - -int PyBobLearnEMIVectorTrainer_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMIVectorTrainer_Type)); -} - - -static PyObject* PyBobLearnEMIVectorTrainer_RichCompare(PyBobLearnEMIVectorTrainerObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMIVectorTrainer_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMIVectorTrainerObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare IVectorTrainer objects", 0) -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -static auto acc_nij_wij2 = bob::extension::VariableDoc( - "acc_nij_wij2", - "array_like <float, 3D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMIVectorTrainer_get_acc_nij_wij2(PyBobLearnEMIVectorTrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccNijWij2()); - BOB_CATCH_MEMBER("acc_nij_wij2 could not be read", 0) -} -int PyBobLearnEMIVectorTrainer_set_acc_nij_wij2(PyBobLearnEMIVectorTrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 3D array of floats", Py_TYPE(self)->tp_name, acc_nij_wij2.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,3>(o, "acc_nij_wij2"); - if (!b) return -1; - self->cxx->setAccNijWij2(*b); - return 0; - BOB_CATCH_MEMBER("acc_nij_wij2 could not be set", -1) -} - - -static auto acc_fnormij_wij = bob::extension::VariableDoc( - "acc_fnormij_wij", - "array_like <float, 3D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMIVectorTrainer_get_acc_fnormij_wij(PyBobLearnEMIVectorTrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccFnormijWij()); - BOB_CATCH_MEMBER("acc_fnormij_wij could not be read", 0) -} -int PyBobLearnEMIVectorTrainer_set_acc_fnormij_wij(PyBobLearnEMIVectorTrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 3D array of floats", Py_TYPE(self)->tp_name, acc_fnormij_wij.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,3>(o, "acc_fnormij_wij"); - if (!b) return -1; - self->cxx->setAccFnormijWij(*b); - return 0; - BOB_CATCH_MEMBER("acc_fnormij_wij could not be set", -1) -} - - -static auto acc_nij = bob::extension::VariableDoc( - "acc_nij", - "array_like <float, 1D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMIVectorTrainer_get_acc_nij(PyBobLearnEMIVectorTrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccNij()); - BOB_CATCH_MEMBER("acc_nij could not be read", 0) -} -int PyBobLearnEMIVectorTrainer_set_acc_nij(PyBobLearnEMIVectorTrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, acc_nij.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(o, "acc_nij"); - if (!b) return -1; - self->cxx->setAccNij(*b); - return 0; - BOB_CATCH_MEMBER("acc_nij could not be set", -1) -} - - -static auto acc_snormij = bob::extension::VariableDoc( - "acc_snormij", - "array_like <float, 2D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMIVectorTrainer_get_acc_snormij(PyBobLearnEMIVectorTrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccSnormij()); - BOB_CATCH_MEMBER("acc_snormij could not be read", 0) -} -int PyBobLearnEMIVectorTrainer_set_acc_snormij(PyBobLearnEMIVectorTrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, acc_snormij.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(o, "acc_snormij"); - if (!b) return -1; - self->cxx->setAccSnormij(*b); - return 0; - BOB_CATCH_MEMBER("acc_snormij could not be set", -1) -} - - - - -static PyGetSetDef PyBobLearnEMIVectorTrainer_getseters[] = { - { - acc_nij_wij2.name(), - (getter)PyBobLearnEMIVectorTrainer_get_acc_nij_wij2, - (setter)PyBobLearnEMIVectorTrainer_set_acc_nij_wij2, - acc_nij_wij2.doc(), - 0 - }, - { - acc_fnormij_wij.name(), - (getter)PyBobLearnEMIVectorTrainer_get_acc_fnormij_wij, - (setter)PyBobLearnEMIVectorTrainer_set_acc_fnormij_wij, - acc_fnormij_wij.doc(), - 0 - }, - { - acc_nij.name(), - (getter)PyBobLearnEMIVectorTrainer_get_acc_nij, - (setter)PyBobLearnEMIVectorTrainer_set_acc_nij, - acc_nij.doc(), - 0 - }, - { - acc_snormij.name(), - (getter)PyBobLearnEMIVectorTrainer_get_acc_snormij, - (setter)PyBobLearnEMIVectorTrainer_set_acc_snormij, - acc_snormij.doc(), - 0 - }, - - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - -/*** initialize ***/ -static auto initialize = bob::extension::FunctionDoc( - "initialize", - "Initialization before the EM steps", - "", - true -) -.add_prototype("ivector_machine, [stats], [rng]") -.add_parameter("ivector_machine", ":py:class:`bob.learn.em.IVectorMachine`", "IVectorMachine Object") -.add_parameter("stats", "object", "Ignored") -.add_parameter("rng", ":py:class:`bob.core.random.mt19937`", "The Mersenne Twister mt19937 random generator used for the initialization of subspaces/arrays before the EM loop."); -static PyObject* PyBobLearnEMIVectorTrainer_initialize(PyBobLearnEMIVectorTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = initialize.kwlist(0); - - PyBobLearnEMIVectorMachineObject* ivector_machine = 0; - PyObject* stats; - PyBoostMt19937Object* rng = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO!", kwlist, &PyBobLearnEMIVectorMachine_Type, &ivector_machine, - &stats, - &PyBoostMt19937_Type, &rng)) return 0; - - if(rng){ - self->cxx->setRng(rng->rng); - } - - self->cxx->initialize(*ivector_machine->cxx); - - BOB_CATCH_MEMBER("cannot perform the initialize method", 0) - - Py_RETURN_NONE; -} - - -/*** e_step ***/ -static auto e_step = bob::extension::FunctionDoc( - "e_step", - "Call the e-step procedure (for the U subspace).", - "", - true -) -.add_prototype("ivector_machine,stats") -.add_parameter("ivector_machine", ":py:class:`bob.learn.em.ISVBase`", "IVectorMachine Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object"); -static PyObject* PyBobLearnEMIVectorTrainer_e_step(PyBobLearnEMIVectorTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = e_step.kwlist(0); - - PyBobLearnEMIVectorMachineObject* ivector_machine = 0; - PyObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMIVectorMachine_Type, &ivector_machine, - &PyList_Type, &stats)) return 0; - - std::vector<bob::learn::em::GMMStats> training_data; - if(extract_GMMStats_1d(stats ,training_data)==0) - self->cxx->eStep(*ivector_machine->cxx, training_data); - else - return 0; - - Py_RETURN_NONE; - BOB_CATCH_MEMBER("cannot perform the e_step method", 0) -} - - -/*** m_step ***/ -static auto m_step = bob::extension::FunctionDoc( - "m_step", - "Call the m-step procedure (for the U subspace).", - "", - true -) -.add_prototype("ivector_machine, [stats]") -.add_parameter("ivector_machine", ":py:class:`bob.learn.em.ISVBase`", "IVectorMachine Object") -.add_parameter("stats", "object", "Ignored"); -static PyObject* PyBobLearnEMIVectorTrainer_m_step(PyBobLearnEMIVectorTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = m_step.kwlist(0); - - PyBobLearnEMIVectorMachineObject* ivector_machine = 0; - PyObject* stats; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", kwlist, &PyBobLearnEMIVectorMachine_Type, &ivector_machine, - &stats)) return 0; - - self->cxx->mStep(*ivector_machine->cxx); - - BOB_CATCH_MEMBER("cannot perform the m_step method", 0) - - Py_RETURN_NONE; -} - -/*** reset_accumulators ***/ -static auto reset_accumulators = bob::extension::FunctionDoc( - "reset_accumulators", - "Reset the statistics accumulators to the correct size and a value of zero.", - 0, - true -) -.add_prototype("ivector_machine") -.add_parameter("ivector_machine", ":py:class:`bob.learn.em.IVectorMachine`", "The IVector machine containing the right dimensions"); -static PyObject* PyBobLearnEMIVectorTrainer_reset_accumulators(PyBobLearnEMIVectorTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = reset_accumulators.kwlist(0); - - PyBobLearnEMIVectorMachineObject* machine; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMIVectorMachine_Type, &machine)) return 0; - - self->cxx->resetAccumulators(*machine->cxx); - Py_RETURN_NONE; - - BOB_CATCH_MEMBER("cannot perform the reset_accumulators method", 0) -} - - -static PyMethodDef PyBobLearnEMIVectorTrainer_methods[] = { - { - initialize.name(), - (PyCFunction)PyBobLearnEMIVectorTrainer_initialize, - METH_VARARGS|METH_KEYWORDS, - initialize.doc() - }, - { - e_step.name(), - (PyCFunction)PyBobLearnEMIVectorTrainer_e_step, - METH_VARARGS|METH_KEYWORDS, - e_step.doc() - }, - { - m_step.name(), - (PyCFunction)PyBobLearnEMIVectorTrainer_m_step, - METH_VARARGS|METH_KEYWORDS, - m_step.doc() - }, - { - reset_accumulators.name(), - (PyCFunction)PyBobLearnEMIVectorTrainer_reset_accumulators, - METH_VARARGS|METH_KEYWORDS, - reset_accumulators.doc() - }, - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMIVectorTrainer_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMIVectorTrainer(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMIVectorTrainer_Type.tp_name = IVectorTrainer_doc.name(); - PyBobLearnEMIVectorTrainer_Type.tp_basicsize = sizeof(PyBobLearnEMIVectorTrainerObject); - PyBobLearnEMIVectorTrainer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;//Enable the class inheritance; - PyBobLearnEMIVectorTrainer_Type.tp_doc = IVectorTrainer_doc.doc(); - - // set the functions - PyBobLearnEMIVectorTrainer_Type.tp_new = PyType_GenericNew; - PyBobLearnEMIVectorTrainer_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMIVectorTrainer_init); - PyBobLearnEMIVectorTrainer_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMIVectorTrainer_delete); - PyBobLearnEMIVectorTrainer_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMIVectorTrainer_RichCompare); - PyBobLearnEMIVectorTrainer_Type.tp_methods = PyBobLearnEMIVectorTrainer_methods; - PyBobLearnEMIVectorTrainer_Type.tp_getset = PyBobLearnEMIVectorTrainer_getseters; - //PyBobLearnEMIVectorTrainer_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMIVectorTrainer_compute_likelihood); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMIVectorTrainer_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMIVectorTrainer_Type); - return PyModule_AddObject(module, "IVectorTrainer", (PyObject*)&PyBobLearnEMIVectorTrainer_Type) >= 0; -} diff --git a/bob/learn/em/jfa_base.cpp b/bob/learn/em/jfa_base.cpp deleted file mode 100644 index aeec4a0367f758e18ba109bd13473afc25cea9cf..0000000000000000000000000000000000000000 --- a/bob/learn/em/jfa_base.cpp +++ /dev/null @@ -1,630 +0,0 @@ -/** - * @date Wed Jan 27 17:03:15 2015 +0200 - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static auto JFABase_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".JFABase", - "Container for :math:`U`, :math:`V` and :math:`D` when performing Joint Factor Analysis (:ref:`JFA <jfa>`).\n\n" - "", - "" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Constructor. Builds a new JFABase", - "", - true - ) - .add_prototype("ubm,ru,rv","") - .add_prototype("other","") - .add_prototype("hdf5","") - .add_prototype("","") - - .add_parameter("ubm", ":py:class:`bob.learn.em.GMMMachine`", "The Universal Background Model.") - .add_parameter("ru", "int", "Size of :math:`U` (Within client variation matrix). In the end the U matrix will have (#gaussians * #feature_dimension x ru)") - .add_parameter("rv", "int", "Size of :math:`V` (Between client variation matrix). In the end the U matrix will have (#gaussians * #feature_dimension x rv)") - .add_parameter("other", ":py:class:`bob.learn.em.JFABase`", "A JFABase object to be copied.") - .add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading") - -); - - -static int PyBobLearnEMJFABase_init_copy(PyBobLearnEMJFABaseObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = JFABase_doc.kwlist(1); - PyBobLearnEMJFABaseObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMJFABase_Type, &o)){ - JFABase_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::JFABase(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMJFABase_init_hdf5(PyBobLearnEMJFABaseObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = JFABase_doc.kwlist(2); - - PyBobIoHDF5FileObject* config = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBobIoHDF5File_Converter, &config)){ - JFABase_doc.print_usage(); - return -1; - } - auto config_ = make_safe(config); - self->cxx.reset(new bob::learn::em::JFABase(*(config->f))); - - return 0; -} - - -static int PyBobLearnEMJFABase_init_ubm(PyBobLearnEMJFABaseObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = JFABase_doc.kwlist(0); - - PyBobLearnEMGMMMachineObject* ubm; - int ru = 1; - int rv = 1; - - //Here we have to select which keyword argument to read - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!ii", kwlist, &PyBobLearnEMGMMMachine_Type, &ubm, - &ru, &rv)){ - JFABase_doc.print_usage(); - return -1; - } - - if(ru < 0){ - PyErr_Format(PyExc_TypeError, "ru argument must be greater than or equal to one"); - return -1; - } - - if(rv < 0){ - PyErr_Format(PyExc_TypeError, "rv argument must be greater than or equal to one"); - return -1; - } - - self->cxx.reset(new bob::learn::em::JFABase(ubm->cxx, ru, rv)); - return 0; -} - - -static int PyBobLearnEMJFABase_init(PyBobLearnEMJFABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - switch (nargs) { - - case 1:{ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is Gaussian object - if (PyBobLearnEMJFABase_Check(arg)) - return PyBobLearnEMJFABase_init_copy(self, args, kwargs); - // If the constructor input is a HDF5 - else if (PyBobIoHDF5File_Check(arg)) - return PyBobLearnEMJFABase_init_hdf5(self, args, kwargs); - } - case 3: - return PyBobLearnEMJFABase_init_ubm(self, args, kwargs); - default: - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires 1 or 3 arguments, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - JFABase_doc.print_usage(); - return -1; - } - BOB_CATCH_MEMBER("cannot create JFABase", -1) - return 0; -} - - - -static void PyBobLearnEMJFABase_delete(PyBobLearnEMJFABaseObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* PyBobLearnEMJFABase_RichCompare(PyBobLearnEMJFABaseObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMJFABase_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMJFABaseObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare JFABase objects", 0) -} - -int PyBobLearnEMJFABase_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMJFABase_Type)); -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** shape *****/ -static auto shape = bob::extension::VariableDoc( - "shape", - "(int,int, int, int)", - "A tuple that represents the number of gaussians, dimensionality of each Gaussian, dimensionality of the :math:`rU` (within client variability matrix) and dimensionality of the :math:`rV` (between client variability matrix) ``(#Gaussians, #Inputs, #rU, #rV)``.", - "" -); -PyObject* PyBobLearnEMJFABase_getShape(PyBobLearnEMJFABaseObject* self, void*) { - BOB_TRY - return Py_BuildValue("(i,i,i,i)", self->cxx->getNGaussians(), self->cxx->getNInputs(), self->cxx->getDimRu(), self->cxx->getDimRv()); - BOB_CATCH_MEMBER("shape could not be read", 0) -} - -/***** supervector_length *****/ -static auto supervector_length = bob::extension::VariableDoc( - "supervector_length", - "int", - - "Returns the supervector length.", - "NGaussians x NInputs: Number of Gaussian components by the feature dimensionality" - "An exception is thrown if no Universal Background Model has been set yet." - "" -); -PyObject* PyBobLearnEMJFABase_getSupervectorLength(PyBobLearnEMJFABaseObject* self, void*) { - BOB_TRY - return Py_BuildValue("i", self->cxx->getSupervectorLength()); - BOB_CATCH_MEMBER("supervector_length could not be read", 0) -} - - -/***** u *****/ -static auto U = bob::extension::VariableDoc( - "u", - "array_like <float, 2D>", - "Returns the :math:`U` matrix (within client variability matrix)", - "" -); -PyObject* PyBobLearnEMJFABase_getU(PyBobLearnEMJFABaseObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getU()); - BOB_CATCH_MEMBER("``u`` could not be read", 0) -} -int PyBobLearnEMJFABase_setU(PyBobLearnEMJFABaseObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, U.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, U.name()); - return -1; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, U.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getU().extent(0) && input->shape[1] != self->cxx->getU().extent(1)) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getU().extent(0), (Py_ssize_t)self->cxx->getU().extent(1), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], U.name()); - return -1; - } - - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "u"); - if (!b) return -1; - self->cxx->setU(*b); - return 0; - BOB_CATCH_MEMBER("``u`` matrix could not be set", -1) -} - -/***** v *****/ -static auto V = bob::extension::VariableDoc( - "v", - "array_like <float, 2D>", - "Returns the :math:`V` matrix (between client variability matrix)", - "" -); -PyObject* PyBobLearnEMJFABase_getV(PyBobLearnEMJFABaseObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getV()); - BOB_CATCH_MEMBER("``v`` could not be read", 0) -} -int PyBobLearnEMJFABase_setV(PyBobLearnEMJFABaseObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, V.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, V.name()); - return -1; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, V.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getV().extent(0) && input->shape[1] != self->cxx->getV().extent(1)) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getV().extent(0), (Py_ssize_t)self->cxx->getV().extent(1), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], V.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "v"); - if (!b) return -1; - self->cxx->setV(*b); - return 0; - BOB_CATCH_MEMBER("``v`` matrix could not be set", -1) -} - - -/***** d *****/ -static auto D = bob::extension::VariableDoc( - "d", - "array_like <float, 1D>", - "Returns the diagonal matrix :math:`diag(d)` (as a 1D vector)", - "" -); -PyObject* PyBobLearnEMJFABase_getD(PyBobLearnEMJFABaseObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getD()); - BOB_CATCH_MEMBER("``d`` could not be read", 0) -} -int PyBobLearnEMJFABase_setD(PyBobLearnEMJFABaseObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, D.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, D.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, D.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getD().extent(0)) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not [%" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getD().extent(0), (Py_ssize_t)input->shape[0], D.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "d"); - if (!b) return -1; - self->cxx->setD(*b); - return 0; - BOB_CATCH_MEMBER("``d`` matrix could not be set", -1) -} - - -/***** ubm *****/ -static auto ubm = bob::extension::VariableDoc( - "ubm", - ":py:class:`bob.learn.em.GMMMachine`", - "Returns the UBM (Universal Background Model", - "" -); -PyObject* PyBobLearnEMJFABase_getUBM(PyBobLearnEMJFABaseObject* self, void*){ - BOB_TRY - - boost::shared_ptr<bob::learn::em::GMMMachine> ubm_gmmMachine = self->cxx->getUbm(); - - //Allocating the correspondent python object - PyBobLearnEMGMMMachineObject* retval = - (PyBobLearnEMGMMMachineObject*)PyBobLearnEMGMMMachine_Type.tp_alloc(&PyBobLearnEMGMMMachine_Type, 0); - retval->cxx = ubm_gmmMachine; - - return Py_BuildValue("N",retval); - BOB_CATCH_MEMBER("ubm could not be read", 0) -} -int PyBobLearnEMJFABase_setUBM(PyBobLearnEMJFABaseObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyBobLearnEMGMMMachine_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a :py:class:`bob.learn.em.GMMMachine`", Py_TYPE(self)->tp_name, ubm.name()); - return -1; - } - - PyBobLearnEMGMMMachineObject* ubm_gmmMachine = 0; - PyArg_Parse(value, "O!", &PyBobLearnEMGMMMachine_Type,&ubm_gmmMachine); - - self->cxx->setUbm(ubm_gmmMachine->cxx); - - return 0; - BOB_CATCH_MEMBER("ubm could not be set", -1) -} - - - - -static PyGetSetDef PyBobLearnEMJFABase_getseters[] = { - { - shape.name(), - (getter)PyBobLearnEMJFABase_getShape, - 0, - shape.doc(), - 0 - }, - - { - supervector_length.name(), - (getter)PyBobLearnEMJFABase_getSupervectorLength, - 0, - supervector_length.doc(), - 0 - }, - - { - U.name(), - (getter)PyBobLearnEMJFABase_getU, - (setter)PyBobLearnEMJFABase_setU, - U.doc(), - 0 - }, - - { - V.name(), - (getter)PyBobLearnEMJFABase_getV, - (setter)PyBobLearnEMJFABase_setV, - V.doc(), - 0 - }, - - { - D.name(), - (getter)PyBobLearnEMJFABase_getD, - (setter)PyBobLearnEMJFABase_setD, - D.doc(), - 0 - }, - - { - ubm.name(), - (getter)PyBobLearnEMJFABase_getUBM, - (setter)PyBobLearnEMJFABase_setUBM, - ubm.doc(), - 0 - }, - - - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - - -/*** save ***/ -static auto save = bob::extension::FunctionDoc( - "save", - "Save the configuration of the JFABase to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for writing"); -static PyObject* PyBobLearnEMJFABase_Save(PyBobLearnEMJFABaseObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - // get list of arguments - char** kwlist = save.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->save(*hdf5->f); - - BOB_CATCH_MEMBER("cannot save the data", 0) - Py_RETURN_NONE; -} - -/*** load ***/ -static auto load = bob::extension::FunctionDoc( - "load", - "Load the configuration of the JFABase to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading"); -static PyObject* PyBobLearnEMJFABase_Load(PyBobLearnEMJFABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = load.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->load(*hdf5->f); - - BOB_CATCH_MEMBER("cannot load the data", 0) - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this JFABase with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` " - "and any other values internal to this machine." -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.JFABase`", "A JFABase object to be compared.") -.add_parameter("r_epsilon", "float", "Relative precision.") -.add_parameter("a_epsilon", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMJFABase_IsSimilarTo(PyBobLearnEMJFABaseObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - //PyObject* other = 0; - PyBobLearnEMJFABaseObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMJFABase_Type, &other, - &r_epsilon, &a_epsilon)){ - - is_similar_to.print_usage(); - return 0; - } - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - -/*** resize ***/ -static auto resize = bob::extension::FunctionDoc( - "resize", - "Resets the dimensionality of the subspace U and V. " - "U and V are hence uninitialized", - 0, - true -) -.add_prototype("rU,rV") -.add_parameter("rU", "int", "Size of :math:`U` (Within client variation matrix)") -.add_parameter("rV", "int", "Size of :math:`V` (Between client variation matrix)"); -static PyObject* PyBobLearnEMJFABase_resize(PyBobLearnEMJFABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = resize.kwlist(0); - - int rU = 0; - int rV = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &rU, &rV)) return 0; - - if (rU <= 0){ - PyErr_Format(PyExc_TypeError, "rU must be greater than zero"); - resize.print_usage(); - return 0; - } - if (rV <= 0){ - PyErr_Format(PyExc_TypeError, "rV must be greater than zero"); - resize.print_usage(); - return 0; - } - self->cxx->resize(rU, rV); - - BOB_CATCH_MEMBER("cannot perform the resize method", 0) - - Py_RETURN_NONE; -} - - - - -static PyMethodDef PyBobLearnEMJFABase_methods[] = { - { - save.name(), - (PyCFunction)PyBobLearnEMJFABase_Save, - METH_VARARGS|METH_KEYWORDS, - save.doc() - }, - { - load.name(), - (PyCFunction)PyBobLearnEMJFABase_Load, - METH_VARARGS|METH_KEYWORDS, - load.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMJFABase_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - { - resize.name(), - (PyCFunction)PyBobLearnEMJFABase_resize, - METH_VARARGS|METH_KEYWORDS, - resize.doc() - }, - - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the JFA type struct; will be initialized later -PyTypeObject PyBobLearnEMJFABase_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMJFABase(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMJFABase_Type.tp_name = JFABase_doc.name(); - PyBobLearnEMJFABase_Type.tp_basicsize = sizeof(PyBobLearnEMJFABaseObject); - PyBobLearnEMJFABase_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyBobLearnEMJFABase_Type.tp_doc = JFABase_doc.doc(); - - // set the functions - PyBobLearnEMJFABase_Type.tp_new = PyType_GenericNew; - PyBobLearnEMJFABase_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMJFABase_init); - PyBobLearnEMJFABase_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMJFABase_delete); - PyBobLearnEMJFABase_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMJFABase_RichCompare); - PyBobLearnEMJFABase_Type.tp_methods = PyBobLearnEMJFABase_methods; - PyBobLearnEMJFABase_Type.tp_getset = PyBobLearnEMJFABase_getseters; - //PyBobLearnEMJFABase_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMJFABase_forward); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMJFABase_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMJFABase_Type); - return PyModule_AddObject(module, "JFABase", (PyObject*)&PyBobLearnEMJFABase_Type) >= 0; -} - diff --git a/bob/learn/em/jfa_machine.cpp b/bob/learn/em/jfa_machine.cpp deleted file mode 100644 index 95ceb9766959bbd31d55e269f31bc9c2c4b1dd93..0000000000000000000000000000000000000000 --- a/bob/learn/em/jfa_machine.cpp +++ /dev/null @@ -1,734 +0,0 @@ -/** - * @date Wed Jan 28 17:03:15 2015 +0200 - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static auto JFAMachine_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".JFAMachine", - "A JFAMachine. An attached :py:class:`bob.learn.em.JFABase` should be provided for Joint Factor Analysis. The :py:class:`bob.learn.em.JFAMachine` carries information about the speaker factors :math:`y` and :math:`z`, whereas a :py:class:`bob.learn.em.JFABase` carries information about the matrices :math:`U`, :math:`V` and :math:`D`.\n\n" - "References: [Vogt2008]_ [McCool2013]_", - "" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Constructor. Builds a new JFAMachine", - "", - true - ) - .add_prototype("jfa_base","") - .add_prototype("other","") - .add_prototype("hdf5","") - - .add_parameter("jfa_base", ":py:class:`bob.learn.em.JFABase`", "The JFABase associated with this machine") - .add_parameter("other", ":py:class:`bob.learn.em.JFAMachine`", "A JFAMachine object to be copied.") - .add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading") - -); - - -static int PyBobLearnEMJFAMachine_init_copy(PyBobLearnEMJFAMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = JFAMachine_doc.kwlist(1); - PyBobLearnEMJFAMachineObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMJFAMachine_Type, &o)){ - JFAMachine_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::JFAMachine(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMJFAMachine_init_hdf5(PyBobLearnEMJFAMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = JFAMachine_doc.kwlist(2); - - PyBobIoHDF5FileObject* config = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBobIoHDF5File_Converter, &config)){ - JFAMachine_doc.print_usage(); - return -1; - } - auto config_ = make_safe(config); - self->cxx.reset(new bob::learn::em::JFAMachine(*(config->f))); - - return 0; -} - - -static int PyBobLearnEMJFAMachine_init_jfabase(PyBobLearnEMJFAMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = JFAMachine_doc.kwlist(0); - - PyBobLearnEMJFABaseObject* jfa_base; - - //Here we have to select which keyword argument to read - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMJFABase_Type, &jfa_base)){ - JFAMachine_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::JFAMachine(jfa_base->cxx)); - return 0; -} - - -static int PyBobLearnEMJFAMachine_init(PyBobLearnEMJFAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - if(nargs == 1){ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is Gaussian object - if (PyBobLearnEMJFAMachine_Check(arg)) - return PyBobLearnEMJFAMachine_init_copy(self, args, kwargs); - // If the constructor input is a HDF5 - else if (PyBobIoHDF5File_Check(arg)) - return PyBobLearnEMJFAMachine_init_hdf5(self, args, kwargs); - // If the constructor input is a JFABase Object - else - return PyBobLearnEMJFAMachine_init_jfabase(self, args, kwargs); - } - else{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires only 1 argument, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - JFAMachine_doc.print_usage(); - return -1; - } - - BOB_CATCH_MEMBER("cannot create JFAMachine", -1) - return 0; -} - -static void PyBobLearnEMJFAMachine_delete(PyBobLearnEMJFAMachineObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* PyBobLearnEMJFAMachine_RichCompare(PyBobLearnEMJFAMachineObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMJFAMachine_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMJFAMachineObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare JFAMachine objects", 0) -} - -int PyBobLearnEMJFAMachine_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMJFAMachine_Type)); -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** shape *****/ -static auto shape = bob::extension::VariableDoc( - "shape", - "(int,int, int, int)", - "A tuple that represents the number of gaussians, dimensionality of each Gaussian, dimensionality of the rU (within client variability matrix) and dimensionality of the rV (between client variability matrix) ``(#Gaussians, #Inputs, #rU, #rV)``.", - "" -); -PyObject* PyBobLearnEMJFAMachine_getShape(PyBobLearnEMJFAMachineObject* self, void*) { - BOB_TRY - return Py_BuildValue("(i,i,i,i)", self->cxx->getNGaussians(), self->cxx->getNInputs(), self->cxx->getDimRu(), self->cxx->getDimRv()); - BOB_CATCH_MEMBER("shape could not be read", 0) -} - -/***** supervector_length *****/ -static auto supervector_length = bob::extension::VariableDoc( - "supervector_length", - "int", - - "Returns the supervector length.", - "NGaussians x NInputs: Number of Gaussian components by the feature dimensionality. " - "An exception is thrown if no Universal Background Model has been set yet." - "" -); -PyObject* PyBobLearnEMJFAMachine_getSupervectorLength(PyBobLearnEMJFAMachineObject* self, void*) { - BOB_TRY - return Py_BuildValue("i", self->cxx->getSupervectorLength()); - BOB_CATCH_MEMBER("supervector_length could not be read", 0) -} - - -/***** y *****/ -static auto Y = bob::extension::VariableDoc( - "y", - "array_like <float, 1D>", - "Returns the :math:`y` speaker factor. Eq (30) from [McCool2013]_", - "" -); -PyObject* PyBobLearnEMJFAMachine_getY(PyBobLearnEMJFAMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getY()); - BOB_CATCH_MEMBER("`y` could not be read", 0) -} -int PyBobLearnEMJFAMachine_setY(PyBobLearnEMJFAMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, Y.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, Y.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, Y.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getY().extent(0)) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getY().extent(0), (Py_ssize_t)input->shape[0], Y.name()); - return -1; - } - - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "y"); - if (!b) return -1; - self->cxx->setY(*b); - return 0; - BOB_CATCH_MEMBER("`y` vector could not be set", -1) -} - - -/***** z *****/ -static auto Z = bob::extension::VariableDoc( - "z", - "array_like <float, 1D>", - "Returns the :math:`z` speaker factor. Eq (31) from [McCool2013]_", - "" -); -PyObject* PyBobLearnEMJFAMachine_getZ(PyBobLearnEMJFAMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getZ()); - BOB_CATCH_MEMBER("`z` could not be read", 0) -} -int PyBobLearnEMJFAMachine_setZ(PyBobLearnEMJFAMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, Z.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, Z.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, Z.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getZ().extent(0)) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getZ().extent(0), (Py_ssize_t)input->shape[0], Z.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "z"); - if (!b) return -1; - self->cxx->setZ(*b); - return 0; - BOB_CATCH_MEMBER("`z` vector could not be set", -1) -} - - -/***** x *****/ -static auto X = bob::extension::VariableDoc( - "x", - "array_like <float, 1D>", - "Returns the :math:`X` session factor. Eq (29) from [McCool2013]_", - "The latent variable :math:`x` (last one computed). This is a feature provided for convenience, but this attribute is not 'part' of the machine. The session latent variable :math:`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." -); -PyObject* PyBobLearnEMJFAMachine_getX(PyBobLearnEMJFAMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getX()); - BOB_CATCH_MEMBER("`x` could not be read", 0) -} - - -/***** jfa_base *****/ -static auto jfa_base = bob::extension::VariableDoc( - "jfa_base", - ":py:class:`bob.learn.em.JFABase`", - "The JFABase attached to this machine", - "" -); -PyObject* PyBobLearnEMJFAMachine_getJFABase(PyBobLearnEMJFAMachineObject* self, void*){ - BOB_TRY - - boost::shared_ptr<bob::learn::em::JFABase> jfa_base_o = self->cxx->getJFABase(); - - //Allocating the correspondent python object - PyBobLearnEMJFABaseObject* retval = - (PyBobLearnEMJFABaseObject*)PyBobLearnEMJFABase_Type.tp_alloc(&PyBobLearnEMJFABase_Type, 0); - retval->cxx = jfa_base_o; - - return Py_BuildValue("N",retval); - BOB_CATCH_MEMBER("jfa_base could not be read", 0) -} -int PyBobLearnEMJFAMachine_setJFABase(PyBobLearnEMJFAMachineObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyBobLearnEMJFABase_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a :py:class:`bob.learn.em.JFABase`", Py_TYPE(self)->tp_name, jfa_base.name()); - return -1; - } - - PyBobLearnEMJFABaseObject* jfa_base_o = 0; - PyArg_Parse(value, "O!", &PyBobLearnEMJFABase_Type,&jfa_base_o); - - self->cxx->setJFABase(jfa_base_o->cxx); - - return 0; - BOB_CATCH_MEMBER("jfa_base could not be set", -1) -} - - - - -static PyGetSetDef PyBobLearnEMJFAMachine_getseters[] = { - { - shape.name(), - (getter)PyBobLearnEMJFAMachine_getShape, - 0, - shape.doc(), - 0 - }, - - { - supervector_length.name(), - (getter)PyBobLearnEMJFAMachine_getSupervectorLength, - 0, - supervector_length.doc(), - 0 - }, - - { - jfa_base.name(), - (getter)PyBobLearnEMJFAMachine_getJFABase, - (setter)PyBobLearnEMJFAMachine_setJFABase, - jfa_base.doc(), - 0 - }, - - { - Y.name(), - (getter)PyBobLearnEMJFAMachine_getY, - (setter)PyBobLearnEMJFAMachine_setY, - Y.doc(), - 0 - }, - - { - Z.name(), - (getter)PyBobLearnEMJFAMachine_getZ, - (setter)PyBobLearnEMJFAMachine_setZ, - Z.doc(), - 0 - }, - - { - X.name(), - (getter)PyBobLearnEMJFAMachine_getX, - 0, - X.doc(), - 0 - }, - - - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - - -/*** save ***/ -static auto save = bob::extension::FunctionDoc( - "save", - "Save the configuration of the JFAMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for writing"); -static PyObject* PyBobLearnEMJFAMachine_Save(PyBobLearnEMJFAMachineObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - // get list of arguments - char** kwlist = save.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->save(*hdf5->f); - - BOB_CATCH_MEMBER("cannot save the data", 0) - Py_RETURN_NONE; -} - -/*** load ***/ -static auto load = bob::extension::FunctionDoc( - "load", - "Load the configuration of the JFAMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading"); -static PyObject* PyBobLearnEMJFAMachine_Load(PyBobLearnEMJFAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = load.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->load(*hdf5->f); - - BOB_CATCH_MEMBER("cannot load the data", 0) - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this JFAMachine with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` " - "and any other values internal to this machine." -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.JFAMachine`", "A JFAMachine object to be compared.") -.add_parameter("r_epsilon", "float", "Relative precision.") -.add_parameter("a_epsilon", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMJFAMachine_IsSimilarTo(PyBobLearnEMJFAMachineObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - //PyObject* other = 0; - PyBobLearnEMJFAMachineObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMJFAMachine_Type, &other, - &r_epsilon, &a_epsilon)){ - - is_similar_to.print_usage(); - return 0; - } - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - -/*** estimate_x ***/ -static auto estimate_x = bob::extension::FunctionDoc( - "estimate_x", - "Estimates the session offset x (LPT assumption) given GMM statistics.", - "Estimates x from the GMM statistics considering the LPT assumption, that is the latent session variable x is approximated using the UBM", - true -) -.add_prototype("stats,input") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics of the GMM") -.add_parameter("input", "array_like <float, 1D>", "Input vector"); -static PyObject* PyBobLearnEMJFAMachine_estimateX(PyBobLearnEMJFAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = estimate_x.kwlist(0); - - PyBobLearnEMGMMStatsObject* stats = 0; - PyBlitzArrayObject* input = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMStats_Type, &stats, - &PyBlitzArray_Converter,&input)) - return 0; - - //protects acquired resources through this scope - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, estimate_x.name()); - return 0; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, estimate_x.name()); - return 0; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), (Py_ssize_t)input->shape[0], estimate_x.name()); - return 0; - } - - self->cxx->estimateX(*stats->cxx, *PyBlitzArrayCxx_AsBlitz<double,1>(input)); - - BOB_CATCH_MEMBER("cannot estimate X", 0) - Py_RETURN_NONE; -} - - -/*** estimate_ux ***/ -static auto estimate_ux = bob::extension::FunctionDoc( - "estimate_ux", - "Estimates Ux (LPT assumption) given GMM statistics.", - "Estimates Ux from the GMM statistics considering the LPT assumption, that is the latent session variable x is approximated using the UBM.", - true -) -.add_prototype("stats,input") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics of the GMM") -.add_parameter("input", "array_like <float, 1D>", "Input vector"); -static PyObject* PyBobLearnEMJFAMachine_estimateUx(PyBobLearnEMJFAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = estimate_ux.kwlist(0); - - PyBobLearnEMGMMStatsObject* stats = 0; - PyBlitzArrayObject* input = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMStats_Type, &stats, - &PyBlitzArray_Converter,&input)) - return 0; - - //protects acquired resources through this scope - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, estimate_ux.name()); - return 0; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, estimate_ux.name()); - return 0; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs()) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs()*(Py_ssize_t)self->cxx->getNGaussians(), (Py_ssize_t)input->shape[0], estimate_ux.name()); - return 0; - } - - self->cxx->estimateUx(*stats->cxx, *PyBlitzArrayCxx_AsBlitz<double,1>(input)); - - BOB_CATCH_MEMBER("cannot estimate Ux", 0) - Py_RETURN_NONE; -} - - -/*** forward_ux ***/ -static auto forward_ux = bob::extension::FunctionDoc( - "forward_ux", - "Computes a score for the given UBM statistics and given the Ux vector", - "", - true -) -.add_prototype("stats,ux") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics as input") -.add_parameter("ux", "array_like <float, 1D>", "Input vector"); -static PyObject* PyBobLearnEMJFAMachine_ForwardUx(PyBobLearnEMJFAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = forward_ux.kwlist(0); - - PyBobLearnEMGMMStatsObject* stats = 0; - PyBlitzArrayObject* ux_input = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMStats_Type, &stats, - &PyBlitzArray_Converter,&ux_input)) - return 0; - - //protects acquired resources through this scope - auto ux_input_ = make_safe(ux_input); - - // perform check on the input - if (ux_input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, forward_ux.name()); - return 0; - } - - if (ux_input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, forward_ux.name()); - return 0; - } - - if (ux_input->shape[0] != (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs()) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d, elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getNGaussians()*(Py_ssize_t)self->cxx->getNInputs(), (Py_ssize_t)ux_input->shape[0], forward_ux.name()); - return 0; - } - - double score = self->cxx->forward(*stats->cxx, *PyBlitzArrayCxx_AsBlitz<double,1>(ux_input)); - - return Py_BuildValue("d", score); - BOB_CATCH_MEMBER("cannot forward_ux", 0) - -} - - -/*** log_likelihood ***/ -static auto log_likelihood = bob::extension::FunctionDoc( - "log_likelihood", - "Computes the log-likelihood of the given samples", - ".. note:: the ``__call__`` function is an alias for this function.", - true -) -.add_prototype("stats") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "Statistics as input"); -static PyObject* PyBobLearnEMJFAMachine_log_likelihood(PyBobLearnEMJFAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = log_likelihood.kwlist(0); - - PyBobLearnEMGMMStatsObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMGMMStats_Type, &stats)) - return 0; - - //protects acquired resources through this scope - double score = self->cxx->forward(*stats->cxx); - - return Py_BuildValue("d", score); - BOB_CATCH_MEMBER("cannot log_likelihood", 0) - -} - - -static PyMethodDef PyBobLearnEMJFAMachine_methods[] = { - { - save.name(), - (PyCFunction)PyBobLearnEMJFAMachine_Save, - METH_VARARGS|METH_KEYWORDS, - save.doc() - }, - { - load.name(), - (PyCFunction)PyBobLearnEMJFAMachine_Load, - METH_VARARGS|METH_KEYWORDS, - load.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMJFAMachine_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - - { - estimate_x.name(), - (PyCFunction)PyBobLearnEMJFAMachine_estimateX, - METH_VARARGS|METH_KEYWORDS, - estimate_x.doc() - }, - - { - estimate_ux.name(), - (PyCFunction)PyBobLearnEMJFAMachine_estimateUx, - METH_VARARGS|METH_KEYWORDS, - estimate_ux.doc() - }, - - { - forward_ux.name(), - (PyCFunction)PyBobLearnEMJFAMachine_ForwardUx, - METH_VARARGS|METH_KEYWORDS, - forward_ux.doc() - }, - { - log_likelihood.name(), - (PyCFunction)PyBobLearnEMJFAMachine_log_likelihood, - METH_VARARGS|METH_KEYWORDS, - log_likelihood.doc() - }, - - - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the JFA type struct; will be initialized later -PyTypeObject PyBobLearnEMJFAMachine_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMJFAMachine(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMJFAMachine_Type.tp_name = JFAMachine_doc.name(); - PyBobLearnEMJFAMachine_Type.tp_basicsize = sizeof(PyBobLearnEMJFAMachineObject); - PyBobLearnEMJFAMachine_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyBobLearnEMJFAMachine_Type.tp_doc = JFAMachine_doc.doc(); - - // set the functions - PyBobLearnEMJFAMachine_Type.tp_new = PyType_GenericNew; - PyBobLearnEMJFAMachine_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMJFAMachine_init); - PyBobLearnEMJFAMachine_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMJFAMachine_delete); - PyBobLearnEMJFAMachine_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMJFAMachine_RichCompare); - PyBobLearnEMJFAMachine_Type.tp_methods = PyBobLearnEMJFAMachine_methods; - PyBobLearnEMJFAMachine_Type.tp_getset = PyBobLearnEMJFAMachine_getseters; - PyBobLearnEMJFAMachine_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMJFAMachine_log_likelihood); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMJFAMachine_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMJFAMachine_Type); - return PyModule_AddObject(module, "JFAMachine", (PyObject*)&PyBobLearnEMJFAMachine_Type) >= 0; -} diff --git a/bob/learn/em/jfa_trainer.cpp b/bob/learn/em/jfa_trainer.cpp deleted file mode 100644 index 5d9abadc96821d28cec456dc20b1ef49c5364376..0000000000000000000000000000000000000000 --- a/bob/learn/em/jfa_trainer.cpp +++ /dev/null @@ -1,1107 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Sun 01 Fev 09:40:00 2015 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" -#include <boost/make_shared.hpp> - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static int extract_GMMStats_1d(PyObject *list, - std::vector<boost::shared_ptr<bob::learn::em::GMMStats> >& training_data) -{ - for (int i=0; i<PyList_GET_SIZE(list); i++){ - - PyBobLearnEMGMMStatsObject* stats; - if (!PyArg_Parse(PyList_GetItem(list, i), "O!", &PyBobLearnEMGMMStats_Type, &stats)){ - PyErr_Format(PyExc_RuntimeError, "Expected GMMStats objects"); - return -1; - } - training_data.push_back(stats->cxx); - } - return 0; -} - -static int extract_GMMStats_2d(PyObject *list, - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > >& training_data) -{ - for (int i=0; i<PyList_GET_SIZE(list); i++) - { - PyObject* another_list; - if(!PyArg_Parse(PyList_GetItem(list, i), "O!", &PyList_Type, &another_list)){ - PyErr_Format(PyExc_RuntimeError, "Expected a list of lists of GMMStats objects [[GMMStats,GMMStats],[GMMStats,GMMStats].....[GMMStats,GMMStats]]"); - return -1; - } - - std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > another_training_data; - for (int j=0; j<PyList_GET_SIZE(another_list); j++){ - - PyBobLearnEMGMMStatsObject* stats; - if (!PyArg_Parse(PyList_GetItem(another_list, j), "O!", &PyBobLearnEMGMMStats_Type, &stats)){ - PyErr_Format(PyExc_RuntimeError, "Expected GMMStats objects"); - return -1; - } - another_training_data.push_back(stats->cxx); - } - training_data.push_back(another_training_data); - } - return 0; -} - -template <int N> -static PyObject* vector_as_list(const std::vector<blitz::Array<double,N> >& vec) -{ - PyObject* list = PyList_New(vec.size()); - for(size_t i=0; i<vec.size(); i++){ - blitz::Array<double,N> numpy_array = vec[i]; - PyObject* numpy_py_object = PyBlitzArrayCxx_AsNumpy(numpy_array); - PyList_SET_ITEM(list, i, numpy_py_object); - } - return list; -} - -template <int N> -int list_as_vector(PyObject* list, std::vector<blitz::Array<double,N> >& vec) -{ - for (int i=0; i<PyList_GET_SIZE(list); i++) - { - PyBlitzArrayObject* blitz_object; - if (!PyArg_Parse(PyList_GetItem(list, i), "O&", &PyBlitzArray_Converter, &blitz_object)){ - PyErr_Format(PyExc_RuntimeError, "Expected numpy array object"); - return -1; - } - auto blitz_object_ = make_safe(blitz_object); - vec.push_back(*PyBlitzArrayCxx_AsBlitz<double,N>(blitz_object)); - } - return 0; -} - - - -static auto JFATrainer_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".JFATrainer", - "Trains a Joint Factor Analysis (:ref:`JFA <jfa>`) on top of GMMs" - "", - "" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Constructor. Builds a new JFATrainer", - "", - true - ) - .add_prototype("other","") - .add_prototype("","") - .add_parameter("other", ":py:class:`bob.learn.em.JFATrainer`", "A JFATrainer object to be copied.") -); - - -static int PyBobLearnEMJFATrainer_init_copy(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = JFATrainer_doc.kwlist(0); - PyBobLearnEMJFATrainerObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMJFATrainer_Type, &o)){ - JFATrainer_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::JFATrainer(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMJFATrainer_init(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - switch(nargs){ - case 0:{ - self->cxx.reset(new bob::learn::em::JFATrainer()); - return 0; - } - case 1:{ - // If the constructor input is JFATrainer object - return PyBobLearnEMJFATrainer_init_copy(self, args, kwargs); - } - default:{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires only 0 and 1 argument, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - JFATrainer_doc.print_usage(); - return -1; - } - } - BOB_CATCH_MEMBER("cannot create JFATrainer", -1) - return 0; -} - - -static void PyBobLearnEMJFATrainer_delete(PyBobLearnEMJFATrainerObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - - -int PyBobLearnEMJFATrainer_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMJFATrainer_Type)); -} - - -static PyObject* PyBobLearnEMJFATrainer_RichCompare(PyBobLearnEMJFATrainerObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMJFATrainer_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMJFATrainerObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare JFATrainer objects", 0) -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -static auto acc_v_a1 = bob::extension::VariableDoc( - "acc_v_a1", - "array_like <float, 3D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMJFATrainer_get_acc_v_a1(PyBobLearnEMJFATrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccVA1()); - BOB_CATCH_MEMBER("acc_v_a1 could not be read", 0) -} -int PyBobLearnEMJFATrainer_set_acc_v_a1(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 3D array of floats", Py_TYPE(self)->tp_name, acc_v_a1.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_v_a1.name()); - return -1; - } - - if (input->ndim != 3){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 3D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_v_a1.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getAccVA1().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccVA1().extent(1) && input->shape[2] != (Py_ssize_t)self->cxx->getAccVA1().extent(2)) { - PyErr_Format(PyExc_TypeError, "`%s' 3D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccVA1().extent(0), (Py_ssize_t)self->cxx->getAccVA1().extent(1), (Py_ssize_t)self->cxx->getAccVA1().extent(2), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], (Py_ssize_t)input->shape[2], acc_v_a1.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,3>(input, "acc_v_a1"); - if (!b) return -1; - self->cxx->setAccVA1(*b); - return 0; - BOB_CATCH_MEMBER("acc_v_a1 could not be set", -1) -} - - -static auto acc_v_a2 = bob::extension::VariableDoc( - "acc_v_a2", - "array_like <float, 2D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMJFATrainer_get_acc_v_a2(PyBobLearnEMJFATrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccVA2()); - BOB_CATCH_MEMBER("acc_v_a2 could not be read", 0) -} -int PyBobLearnEMJFATrainer_set_acc_v_a2(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, acc_v_a2.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_v_a2.name()); - return -1; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_v_a2.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getAccVA2().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccVA2().extent(1)) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccVA2().extent(0), (Py_ssize_t)self->cxx->getAccVA2().extent(1), input->shape[0], input->shape[1], acc_v_a2.name()); - return -1; - } - - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "acc_v_a2"); - if (!b) return -1; - self->cxx->setAccVA2(*b); - return 0; - BOB_CATCH_MEMBER("acc_v_a2 could not be set", -1) -} - - -static auto acc_u_a1 = bob::extension::VariableDoc( - "acc_u_a1", - "array_like <float, 3D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMJFATrainer_get_acc_u_a1(PyBobLearnEMJFATrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccUA1()); - BOB_CATCH_MEMBER("acc_u_a1 could not be read", 0) -} -int PyBobLearnEMJFATrainer_set_acc_u_a1(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 3D array of floats", Py_TYPE(self)->tp_name, acc_u_a1.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_u_a1.name()); - return -1; - } - - if (input->ndim != 3){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 3D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_u_a1.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getAccUA1().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccUA1().extent(1) && input->shape[2] != (Py_ssize_t)self->cxx->getAccUA1().extent(2)) { - PyErr_Format(PyExc_TypeError, "`%s' 3D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccUA1().extent(0), (Py_ssize_t)self->cxx->getAccUA1().extent(1), (Py_ssize_t)self->cxx->getAccUA1().extent(2), (Py_ssize_t)input->shape[0], (Py_ssize_t)input->shape[1], (Py_ssize_t)input->shape[2], acc_u_a1.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,3>(input, "acc_u_a1"); - if (!b) return -1; - self->cxx->setAccUA1(*b); - return 0; - BOB_CATCH_MEMBER("acc_u_a1 could not be set", -1) -} - - -static auto acc_u_a2 = bob::extension::VariableDoc( - "acc_u_a2", - "array_like <float, 2D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMJFATrainer_get_acc_u_a2(PyBobLearnEMJFATrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccUA2()); - BOB_CATCH_MEMBER("acc_u_a2 could not be read", 0) -} -int PyBobLearnEMJFATrainer_set_acc_u_a2(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, acc_u_a2.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_u_a2.name()); - return -1; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_u_a2.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getAccUA2().extent(0) && input->shape[1] != (Py_ssize_t)self->cxx->getAccUA2().extent(1)) { - PyErr_Format(PyExc_TypeError, "`%s' 3D `input` array should have the shape [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] not [%" PY_FORMAT_SIZE_T "d, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccUA2().extent(0), (Py_ssize_t)self->cxx->getAccUA2().extent(1), input->shape[0], input->shape[1], acc_u_a2.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "acc_u_a2"); - if (!b) return -1; - self->cxx->setAccUA2(*b); - return 0; - BOB_CATCH_MEMBER("acc_u_a2 could not be set", -1) -} - - -static auto acc_d_a1 = bob::extension::VariableDoc( - "acc_d_a1", - "array_like <float, 1D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMJFATrainer_get_acc_d_a1(PyBobLearnEMJFATrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccDA1()); - BOB_CATCH_MEMBER("acc_d_a1 could not be read", 0) -} -int PyBobLearnEMJFATrainer_set_acc_d_a1(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, acc_d_a1.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_d_a1.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_d_a1.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getAccDA1().extent(0)) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccDA1().extent(0), input->shape[0], acc_d_a1.name()); - return -1; - } - - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "acc_d_a1"); - if (!b) return -1; - self->cxx->setAccDA1(*b); - return 0; - BOB_CATCH_MEMBER("acc_d_a1 could not be set", -1) -} - - -static auto acc_d_a2 = bob::extension::VariableDoc( - "acc_d_a2", - "array_like <float, 1D>", - "Accumulator updated during the E-step", - "" -); -PyObject* PyBobLearnEMJFATrainer_get_acc_d_a2(PyBobLearnEMJFATrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAccDA2()); - BOB_CATCH_MEMBER("acc_d_a2 could not be read", 0) -} -int PyBobLearnEMJFATrainer_set_acc_d_a2(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, acc_d_a1.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, acc_d_a2.name()); - return -1; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, acc_d_a2.name()); - return -1; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getAccDA2().extent(0)) { - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, (Py_ssize_t)self->cxx->getAccDA2().extent(0), input->shape[0], acc_d_a2.name()); - return -1; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(input, "acc_d_a2"); - if (!b) return -1; - self->cxx->setAccDA2(*b); - return 0; - BOB_CATCH_MEMBER("acc_d_a2 could not be set", -1) -} - - -static auto __X__ = bob::extension::VariableDoc( - "__X__", - "list", - "", - "" -); -PyObject* PyBobLearnEMJFATrainer_get_X(PyBobLearnEMJFATrainerObject* self, void*){ - BOB_TRY - return vector_as_list(self->cxx->getX()); - BOB_CATCH_MEMBER("__X__ could not be read", 0) -} -int PyBobLearnEMJFATrainer_set_X(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ - BOB_TRY - - // Parses input arguments in a single shot - if (!PyList_Check(value)){ - PyErr_Format(PyExc_TypeError, "Expected a list in `%s'", __X__.name()); - return -1; - } - - std::vector<blitz::Array<double,2> > data; - if(list_as_vector(value ,data)==0){ - self->cxx->setX(data); - } - - return 0; - BOB_CATCH_MEMBER("__X__ could not be written", -1) -} - - - -static auto __Y__ = bob::extension::VariableDoc( - "__Y__", - "list", - "", - "" -); -PyObject* PyBobLearnEMJFATrainer_get_Y(PyBobLearnEMJFATrainerObject* self, void*){ - BOB_TRY - return vector_as_list(self->cxx->getY()); - BOB_CATCH_MEMBER("__Y__ could not be read", 0) -} -int PyBobLearnEMJFATrainer_set_Y(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ - BOB_TRY - - // Parses input arguments in a single shot - if (!PyList_Check(value)){ - PyErr_Format(PyExc_TypeError, "Expected a list in `%s'", __Y__.name()); - return -1; - } - - std::vector<blitz::Array<double,1> > data; - if(list_as_vector(value ,data)==0){ - self->cxx->setY(data); - } - - return 0; - BOB_CATCH_MEMBER("__Y__ could not be written", -1) -} - - - -static auto __Z__ = bob::extension::VariableDoc( - "__Z__", - "list", - "", - "" -); -PyObject* PyBobLearnEMJFATrainer_get_Z(PyBobLearnEMJFATrainerObject* self, void*){ - BOB_TRY - return vector_as_list(self->cxx->getZ()); - BOB_CATCH_MEMBER("__Z__ could not be read", 0) -} -int PyBobLearnEMJFATrainer_set_Z(PyBobLearnEMJFATrainerObject* self, PyObject* value, void*){ - BOB_TRY - - // Parses input arguments in a single shot - if (!PyList_Check(value)){ - PyErr_Format(PyExc_TypeError, "Expected a list in `%s'", __Z__.name()); - return -1; - } - - std::vector<blitz::Array<double,1> > data; - if(list_as_vector(value ,data)==0){ - self->cxx->setZ(data); - } - - return 0; - BOB_CATCH_MEMBER("__Z__ could not be written", -1) -} - - - -static PyGetSetDef PyBobLearnEMJFATrainer_getseters[] = { - { - acc_v_a1.name(), - (getter)PyBobLearnEMJFATrainer_get_acc_v_a1, - (setter)PyBobLearnEMJFATrainer_set_acc_v_a1, - acc_v_a1.doc(), - 0 - }, - { - acc_v_a2.name(), - (getter)PyBobLearnEMJFATrainer_get_acc_v_a2, - (setter)PyBobLearnEMJFATrainer_set_acc_v_a2, - acc_v_a2.doc(), - 0 - }, - { - acc_u_a1.name(), - (getter)PyBobLearnEMJFATrainer_get_acc_u_a1, - (setter)PyBobLearnEMJFATrainer_set_acc_u_a1, - acc_u_a1.doc(), - 0 - }, - { - acc_u_a2.name(), - (getter)PyBobLearnEMJFATrainer_get_acc_u_a2, - (setter)PyBobLearnEMJFATrainer_set_acc_u_a2, - acc_u_a2.doc(), - 0 - }, - { - acc_d_a1.name(), - (getter)PyBobLearnEMJFATrainer_get_acc_d_a1, - (setter)PyBobLearnEMJFATrainer_set_acc_d_a1, - acc_d_a1.doc(), - 0 - }, - { - acc_d_a2.name(), - (getter)PyBobLearnEMJFATrainer_get_acc_d_a2, - (setter)PyBobLearnEMJFATrainer_set_acc_d_a2, - acc_d_a2.doc(), - 0 - }, - { - __X__.name(), - (getter)PyBobLearnEMJFATrainer_get_X, - (setter)PyBobLearnEMJFATrainer_set_X, - __X__.doc(), - 0 - }, - { - __Y__.name(), - (getter)PyBobLearnEMJFATrainer_get_Y, - (setter)PyBobLearnEMJFATrainer_set_Y, - __Y__.doc(), - 0 - }, - { - __Z__.name(), - (getter)PyBobLearnEMJFATrainer_get_Z, - (setter)PyBobLearnEMJFATrainer_set_Z, - __Z__.doc(), - 0 - }, - - - - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - -/*** initialize ***/ -static auto initialize = bob::extension::FunctionDoc( - "initialize", - "Initialization before the EM steps", - "", - true -) -.add_prototype("jfa_base, stats, [rng]") -.add_parameter("jfa_base", ":py:class:`bob.learn.em.JFABase`", "JFABase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object") -.add_parameter("rng", ":py:class:`bob.core.random.mt19937`", "The Mersenne Twister mt19937 random generator used for the initialization of subspaces/arrays before the EM loop."); -static PyObject* PyBobLearnEMJFATrainer_initialize(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = initialize.kwlist(0); - - PyBobLearnEMJFABaseObject* jfa_base = 0; - PyObject* stats = 0; - PyBoostMt19937Object* rng = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!|O!", kwlist, &PyBobLearnEMJFABase_Type, &jfa_base, - &PyList_Type, &stats, - &PyBoostMt19937_Type, &rng)) return 0; - - if(rng){ - self->cxx->setRng(rng->rng); - } - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->initialize(*jfa_base->cxx, training_data); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the initialize method", 0) - - Py_RETURN_NONE; -} - - -/*** e_stepv ***/ -static auto e_step_v = bob::extension::FunctionDoc( - "e_step_v", - "Call the 1st e-step procedure (for the V subspace).", - "", - true -) -.add_prototype("jfa_base,stats") -.add_parameter("jfa_base", ":py:class:`bob.learn.em.JFABase`", "JFABase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object"); -static PyObject* PyBobLearnEMJFATrainer_e_step_v(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - //Parses input arguments in a single shot - char** kwlist = e_step_v.kwlist(0); - - PyBobLearnEMJFABaseObject* jfa_base = 0; - PyObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMJFABase_Type, &jfa_base, - &PyList_Type, &stats)) return 0; - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->eStep1(*jfa_base->cxx, training_data); - else - return 0; - - - BOB_CATCH_MEMBER("cannot perform the e_step_v method", 0) - - Py_RETURN_NONE; -} - - -/*** m_step_v ***/ -static auto m_step_v = bob::extension::FunctionDoc( - "m_step_v", - "Call the 1st m-step procedure (for the V subspace).", - "", - true -) -.add_prototype("jfa_base,stats") -.add_parameter("jfa_base", ":py:class:`bob.learn.em.JFABase`", "JFABase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object"); -static PyObject* PyBobLearnEMJFATrainer_m_step_v(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = m_step_v.kwlist(0); - - PyBobLearnEMJFABaseObject* jfa_base = 0; - PyObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMJFABase_Type, &jfa_base, - &PyList_Type, &stats)) return 0; - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->mStep1(*jfa_base->cxx, training_data); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the m_step_v method", 0) - - Py_RETURN_NONE; -} - - -/*** finalize_v ***/ -static auto finalize_v = bob::extension::FunctionDoc( - "finalize_v", - "Call the 1st finalize procedure (for the V subspace).", - "", - true -) -.add_prototype("jfa_base,stats") -.add_parameter("jfa_base", ":py:class:`bob.learn.em.JFABase`", "JFABase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object"); -static PyObject* PyBobLearnEMJFATrainer_finalize_v(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - //Parses input arguments in a single shot - char** kwlist = finalize_v.kwlist(0); - - PyBobLearnEMJFABaseObject* jfa_base = 0; - PyObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMJFABase_Type, &jfa_base, - &PyList_Type, &stats)) return 0; - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->finalize1(*jfa_base->cxx, training_data); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the finalize_v method", 0) - - Py_RETURN_NONE; -} - - -/*** e_step_u ***/ -static auto e_step_u = bob::extension::FunctionDoc( - "e_step_u", - "Call the 2nd e-step procedure (for the U subspace).", - "", - true -) -.add_prototype("jfa_base,stats") -.add_parameter("jfa_base", ":py:class:`bob.learn.em.JFABase`", "JFABase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object"); -static PyObject* PyBobLearnEMJFATrainer_e_step_u(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = e_step_u.kwlist(0); - - PyBobLearnEMJFABaseObject* jfa_base = 0; - PyObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMJFABase_Type, &jfa_base, - &PyList_Type, &stats)) return 0; - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->eStep2(*jfa_base->cxx, training_data); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the e_step_u method", 0) - - Py_RETURN_NONE; -} - - -/*** m_step_u ***/ -static auto m_step_u = bob::extension::FunctionDoc( - "m_step_u", - "Call the 2nd m-step procedure (for the U subspace).", - "", - true -) -.add_prototype("jfa_base,stats") -.add_parameter("jfa_base", ":py:class:`bob.learn.em.JFABase`", "JFABase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object"); -static PyObject* PyBobLearnEMJFATrainer_m_step_u(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = m_step_u.kwlist(0); - - PyBobLearnEMJFABaseObject* jfa_base = 0; - PyObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMJFABase_Type, &jfa_base, - &PyList_Type, &stats)) return 0; - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->mStep2(*jfa_base->cxx, training_data); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the m_step_u method", 0) - - Py_RETURN_NONE; -} - - -/*** finalize_u ***/ -static auto finalize_u = bob::extension::FunctionDoc( - "finalize_u", - "Call the 2nd finalize procedure (for the U subspace).", - "", - true -) -.add_prototype("jfa_base,stats") -.add_parameter("jfa_base", ":py:class:`bob.learn.em.JFABase`", "JFABase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object"); -static PyObject* PyBobLearnEMJFATrainer_finalize_u(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = finalize_u.kwlist(0); - - PyBobLearnEMJFABaseObject* jfa_base = 0; - PyObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMJFABase_Type, &jfa_base, - &PyList_Type, &stats)) return 0; - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->finalize2(*jfa_base->cxx, training_data); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the finalize_u method", 0) - - Py_RETURN_NONE; -} - - -/*** e_step_d ***/ -static auto e_step_d = bob::extension::FunctionDoc( - "e_step_d", - "Call the 3rd e-step procedure (for the d subspace).", - "", - true -) -.add_prototype("jfa_base,stats") -.add_parameter("jfa_base", ":py:class:`bob.learn.em.JFABase`", "JFABase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object"); -static PyObject* PyBobLearnEMJFATrainer_e_step_d(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = e_step_d.kwlist(0); - - PyBobLearnEMJFABaseObject* jfa_base = 0; - PyObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMJFABase_Type, &jfa_base, - &PyList_Type, &stats)) return 0; - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->eStep3(*jfa_base->cxx, training_data); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the e_step_d method", 0) - - Py_RETURN_NONE; -} - - -/*** m_step_d ***/ -static auto m_step_d = bob::extension::FunctionDoc( - "m_step_d", - "Call the 3rd m-step procedure (for the d subspace).", - "", - true -) -.add_prototype("jfa_base,stats") -.add_parameter("jfa_base", ":py:class:`bob.learn.em.JFABase`", "JFABase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object"); -static PyObject* PyBobLearnEMJFATrainer_m_step_d(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = m_step_d.kwlist(0); - - PyBobLearnEMJFABaseObject* jfa_base = 0; - PyObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMJFABase_Type, &jfa_base, - &PyList_Type, &stats)) return 0; - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->mStep3(*jfa_base->cxx, training_data); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the m_step_d method", 0) - - Py_RETURN_NONE; -} - - -/*** finalize_d ***/ -static auto finalize_d = bob::extension::FunctionDoc( - "finalize_d", - "Call the 3rd finalize procedure (for the d subspace).", - "", - true -) -.add_prototype("jfa_base,stats") -.add_parameter("jfa_base", ":py:class:`bob.learn.em.JFABase`", "JFABase Object") -.add_parameter("stats", ":py:class:`bob.learn.em.GMMStats`", "GMMStats Object"); -static PyObject* PyBobLearnEMJFATrainer_finalize_d(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = finalize_d.kwlist(0); - - PyBobLearnEMJFABaseObject* jfa_base = 0; - PyObject* stats = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMJFABase_Type, &jfa_base, - &PyList_Type, &stats)) return 0; - - std::vector<std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > > training_data; - if(extract_GMMStats_2d(stats ,training_data)==0) - self->cxx->finalize3(*jfa_base->cxx, training_data); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the finalize_d method", 0) - - Py_RETURN_NONE; -} - - -/*** enroll ***/ -static auto enroll = bob::extension::FunctionDoc( - "enroll", - "", - "", - true -) -.add_prototype("jfa_machine,features,n_iter") -.add_parameter("jfa_machine", ":py:class:`bob.learn.em.JFAMachine`", "JFAMachine Object") -.add_parameter("features", "[:py:class:`bob.learn.em.GMMStats`]", "") -.add_parameter("n_iter", "int", "Number of iterations"); -static PyObject* PyBobLearnEMJFATrainer_enroll(PyBobLearnEMJFATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // Parses input arguments in a single shot - char** kwlist = enroll.kwlist(0); - - PyBobLearnEMJFAMachineObject* jfa_machine = 0; - PyObject* stats = 0; - int n_iter = 1; - - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!i", kwlist, &PyBobLearnEMJFAMachine_Type, &jfa_machine, - &PyList_Type, &stats, &n_iter)) return 0; - - std::vector<boost::shared_ptr<bob::learn::em::GMMStats> > training_data; - if(extract_GMMStats_1d(stats ,training_data)==0) - self->cxx->enroll(*jfa_machine->cxx, training_data, n_iter); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the enroll method", 0) - - Py_RETURN_NONE; -} - - - -static PyMethodDef PyBobLearnEMJFATrainer_methods[] = { - { - initialize.name(), - (PyCFunction)PyBobLearnEMJFATrainer_initialize, - METH_VARARGS|METH_KEYWORDS, - initialize.doc() - }, - { - e_step_v.name(), - (PyCFunction)PyBobLearnEMJFATrainer_e_step_v, - METH_VARARGS|METH_KEYWORDS, - e_step_v.doc() - }, - { - e_step_u.name(), - (PyCFunction)PyBobLearnEMJFATrainer_e_step_u, - METH_VARARGS|METH_KEYWORDS, - e_step_u.doc() - }, - { - e_step_d.name(), - (PyCFunction)PyBobLearnEMJFATrainer_e_step_d, - METH_VARARGS|METH_KEYWORDS, - e_step_d.doc() - }, - { - m_step_v.name(), - (PyCFunction)PyBobLearnEMJFATrainer_m_step_v, - METH_VARARGS|METH_KEYWORDS, - m_step_v.doc() - }, - { - m_step_u.name(), - (PyCFunction)PyBobLearnEMJFATrainer_m_step_u, - METH_VARARGS|METH_KEYWORDS, - m_step_u.doc() - }, - { - m_step_d.name(), - (PyCFunction)PyBobLearnEMJFATrainer_m_step_d, - METH_VARARGS|METH_KEYWORDS, - m_step_d.doc() - }, - { - finalize_v.name(), - (PyCFunction)PyBobLearnEMJFATrainer_finalize_v, - METH_VARARGS|METH_KEYWORDS, - finalize_v.doc() - }, - { - finalize_u.name(), - (PyCFunction)PyBobLearnEMJFATrainer_finalize_u, - METH_VARARGS|METH_KEYWORDS, - finalize_u.doc() - }, - { - finalize_d.name(), - (PyCFunction)PyBobLearnEMJFATrainer_finalize_d, - METH_VARARGS|METH_KEYWORDS, - finalize_d.doc() - }, - { - enroll.name(), - (PyCFunction)PyBobLearnEMJFATrainer_enroll, - METH_VARARGS|METH_KEYWORDS, - enroll.doc() - }, - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMJFATrainer_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMJFATrainer(PyObject* module) -{ - // initialize the type JFATrainer - PyBobLearnEMJFATrainer_Type.tp_name = JFATrainer_doc.name(); - PyBobLearnEMJFATrainer_Type.tp_basicsize = sizeof(PyBobLearnEMJFATrainerObject); - PyBobLearnEMJFATrainer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;//Enable the class inheritance; - PyBobLearnEMJFATrainer_Type.tp_doc = JFATrainer_doc.doc(); - - // set the functions - PyBobLearnEMJFATrainer_Type.tp_new = PyType_GenericNew; - PyBobLearnEMJFATrainer_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMJFATrainer_init); - PyBobLearnEMJFATrainer_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMJFATrainer_delete); - PyBobLearnEMJFATrainer_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMJFATrainer_RichCompare); - PyBobLearnEMJFATrainer_Type.tp_methods = PyBobLearnEMJFATrainer_methods; - PyBobLearnEMJFATrainer_Type.tp_getset = PyBobLearnEMJFATrainer_getseters; - //PyBobLearnEMJFATrainer_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMJFATrainer_compute_likelihood); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMJFATrainer_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMJFATrainer_Type); - return PyModule_AddObject(module, "JFATrainer", (PyObject*)&PyBobLearnEMJFATrainer_Type) >= 0; -} diff --git a/bob/learn/em/kmeans_machine.cpp b/bob/learn/em/kmeans_machine.cpp deleted file mode 100644 index 9fc87269c50f4c89aa9289c66988d7404568431a..0000000000000000000000000000000000000000 --- a/bob/learn/em/kmeans_machine.cpp +++ /dev/null @@ -1,865 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Fri 26 Dec 16:18:00 2014 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static auto KMeansMachine_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".KMeansMachine", - "Statistical model for the :ref:`k-means <kmeans>` .\n" - "See Section 9.1 of Bishop, \"Pattern recognition and machine learning\", 2006" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Creates a KMeansMachine", - "", - true - ) - .add_prototype("n_means,n_inputs","") - .add_prototype("other","") - .add_prototype("hdf5","") - .add_prototype("","") - - .add_parameter("n_means", "int", "Number of means") - .add_parameter("n_inputs", "int", "Dimension of the feature vector") - .add_parameter("other", ":py:class:`bob.learn.em.KMeansMachine`", "A KMeansMachine object to be copied.") - .add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading") - -); - - -static int PyBobLearnEMKMeansMachine_init_number(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = KMeansMachine_doc.kwlist(0); - int n_inputs = 1; - int n_means = 1; - //Parsing the input argments - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &n_means, &n_inputs)) - return -1; - - if(n_means < 0){ - PyErr_Format(PyExc_TypeError, "means argument must be greater than or equal to zero"); - KMeansMachine_doc.print_usage(); - return -1; - } - - if(n_inputs < 0){ - PyErr_Format(PyExc_TypeError, "input argument must be greater than or equal to zero"); - KMeansMachine_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::KMeansMachine(n_means, n_inputs)); - return 0; -} - - -static int PyBobLearnEMKMeansMachine_init_copy(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = KMeansMachine_doc.kwlist(1); - PyBobLearnEMKMeansMachineObject* tt; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMKMeansMachine_Type, &tt)){ - KMeansMachine_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::KMeansMachine(*tt->cxx)); - return 0; -} - - -static int PyBobLearnEMKMeansMachine_init_hdf5(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = KMeansMachine_doc.kwlist(2); - - PyBobIoHDF5FileObject* config = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBobIoHDF5File_Converter, &config)){ - KMeansMachine_doc.print_usage(); - return -1; - } - auto config_ = make_safe(config); - self->cxx.reset(new bob::learn::em::KMeansMachine(*(config->f))); - - return 0; -} - - -static int PyBobLearnEMKMeansMachine_init(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - switch (nargs) { - - case 0: //default initializer () - self->cxx.reset(new bob::learn::em::KMeansMachine()); - return 0; - - case 1:{ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is Gaussian object - if (PyBobLearnEMKMeansMachine_Check(arg)) - return PyBobLearnEMKMeansMachine_init_copy(self, args, kwargs); - // If the constructor input is a HDF5 - else if (PyBobIoHDF5File_Check(arg)) - return PyBobLearnEMKMeansMachine_init_hdf5(self, args, kwargs); - } - case 2: - return PyBobLearnEMKMeansMachine_init_number(self, args, kwargs); - default: - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires 0, 1 or 2 arguments, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - KMeansMachine_doc.print_usage(); - return -1; - } - BOB_CATCH_MEMBER("cannot create KMeansMachine", -1) - return 0; -} - - - -static void PyBobLearnEMKMeansMachine_delete(PyBobLearnEMKMeansMachineObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* PyBobLearnEMKMeansMachine_RichCompare(PyBobLearnEMKMeansMachineObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMKMeansMachine_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMKMeansMachineObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare KMeansMachine objects", 0) -} - -int PyBobLearnEMKMeansMachine_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMKMeansMachine_Type)); -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** shape *****/ -static auto shape = bob::extension::VariableDoc( - "shape", - "(int,int)", - "A tuple that represents the number of means and dimensionality of the feature vector``(n_means, dim)``.", - "" -); -PyObject* PyBobLearnEMKMeansMachine_getShape(PyBobLearnEMKMeansMachineObject* self, void*) { - BOB_TRY - return Py_BuildValue("(i,i)", self->cxx->getNMeans(), self->cxx->getNInputs()); - BOB_CATCH_MEMBER("shape could not be read", 0) -} - -/***** MEAN *****/ - -static auto means = bob::extension::VariableDoc( - "means", - "array_like <float, 2D>", - "The means", - "" -); -PyObject* PyBobLearnEMKMeansMachine_getMeans(PyBobLearnEMKMeansMachineObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getMeans()); - BOB_CATCH_MEMBER("means could not be read", 0) -} -int PyBobLearnEMKMeansMachine_setMeans(PyBobLearnEMKMeansMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* input; - if (!PyBlitzArray_Converter(value, &input)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, means.name()); - return -1; - } - auto o_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, means.name()); - return 0; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, means.name()); - return 0; - } - - if (input->shape[1] != (Py_ssize_t)self->cxx->getNInputs()) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0], means.name()); - return 0; - } - - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(input, "means"); - if (!b) return -1; - self->cxx->setMeans(*b); - return 0; - BOB_CATCH_MEMBER("means could not be set", -1) -} - - -static PyGetSetDef PyBobLearnEMKMeansMachine_getseters[] = { - { - shape.name(), - (getter)PyBobLearnEMKMeansMachine_getShape, - 0, - shape.doc(), - 0 - }, - { - means.name(), - (getter)PyBobLearnEMKMeansMachine_getMeans, - (setter)PyBobLearnEMKMeansMachine_setMeans, - means.doc(), - 0 - }, - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - - -/*** save ***/ -static auto save = bob::extension::FunctionDoc( - "save", - "Save the configuration of the KMeansMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for writing"); -static PyObject* PyBobLearnEMKMeansMachine_Save(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - // get list of arguments - char** kwlist = save.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->save(*hdf5->f); - - BOB_CATCH_MEMBER("cannot save the data", 0) - Py_RETURN_NONE; -} - -/*** load ***/ -static auto load = bob::extension::FunctionDoc( - "load", - "Load the configuration of the KMeansMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading"); -static PyObject* PyBobLearnEMKMeansMachine_Load(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = load.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->load(*hdf5->f); - - BOB_CATCH_MEMBER("cannot load the data", 0) - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this KMeansMachine with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` " - "and any other values internal to this machine." -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.KMeansMachine`", "A KMeansMachine object to be compared.") -.add_parameter("r_epsilon", "float", "Relative precision.") -.add_parameter("a_epsilon", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMKMeansMachine_IsSimilarTo(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - //PyObject* other = 0; - PyBobLearnEMKMeansMachineObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMKMeansMachine_Type, &other, - &r_epsilon, &a_epsilon)){ - - is_similar_to.print_usage(); - return 0; - } - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - -/*** resize ***/ -static auto resize = bob::extension::FunctionDoc( - "resize", - "Allocates space for the statistics and resets to zero.", - 0, - true -) -.add_prototype("n_means,n_inputs") -.add_parameter("n_means", "int", "Number of means") -.add_parameter("n_inputs", "int", "Dimensionality of the feature vector"); -static PyObject* PyBobLearnEMKMeansMachine_resize(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = resize.kwlist(0); - - int n_means = 0; - int n_inputs = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &n_means, &n_inputs)) return 0; - - if (n_means <= 0){ - PyErr_Format(PyExc_TypeError, "n_means must be greater than zero"); - resize.print_usage(); - return 0; - } - if (n_inputs <= 0){ - PyErr_Format(PyExc_TypeError, "n_inputs must be greater than zero"); - resize.print_usage(); - return 0; - } - - self->cxx->resize(n_means, n_inputs); - - BOB_CATCH_MEMBER("cannot perform the resize method", 0) - - Py_RETURN_NONE; -} - -/*** get_mean ***/ -static auto get_mean = bob::extension::FunctionDoc( - "get_mean", - "Get the i'th mean.", - ".. note:: An exception is thrown if i is out of range.", - true -) -.add_prototype("i","mean") -.add_parameter("i", "int", "Index of the mean") -.add_return("mean","array_like <float, 1D>","Mean array"); -static PyObject* PyBobLearnEMKMeansMachine_get_mean(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_mean.kwlist(0); - - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getMean(i)); - - BOB_CATCH_MEMBER("cannot get the mean", 0) -} - - -/*** set_mean ***/ -static auto set_mean = bob::extension::FunctionDoc( - "set_mean", - "Set the i'th mean.", - ".. note:: An exception is thrown if i is out of range.", - true -) -.add_prototype("i,mean") -.add_parameter("i", "int", "Index of the mean") -.add_parameter("mean", "array_like <float, 1D>", "Mean array"); -static PyObject* PyBobLearnEMKMeansMachine_set_mean(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = set_mean.kwlist(0); - - int i = 0; - PyBlitzArrayObject* mean = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO&", kwlist, &i, &PyBlitzArray_Converter, &mean)) return 0; - - //protects acquired resources through this scope - auto mean_ = make_safe(mean); - - // perform check on the input - if (mean->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, set_mean.name()); - return 0; - } - - if (mean->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, set_mean.name()); - return 0; - } - - if (mean->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), mean->shape[0], set_mean.name()); - return 0; - } - - //setting the mean - self->cxx->setMean(i, *PyBlitzArrayCxx_AsBlitz<double,1>(mean)); - - BOB_CATCH_MEMBER("cannot set the mean", 0) - - Py_RETURN_NONE; -} - - - -/*** get_distance_from_mean ***/ -static auto get_distance_from_mean = bob::extension::FunctionDoc( - "get_distance_from_mean", - "Return the power of two of the square Euclidean distance of the sample, x, to the i'th mean.", - ".. note:: An exception is thrown if i is out of range.", - true -) -.add_prototype("input,i","output") -.add_parameter("input", "array_like <float, 1D>", "The data sample (feature vector)") -.add_parameter("i", "int", "The index of the mean") -.add_return("output","float","Square Euclidean distance of the sample, x, to the i'th mean"); -static PyObject* PyBobLearnEMKMeansMachine_get_distance_from_mean(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_distance_from_mean.kwlist(0); - - PyBlitzArrayObject* input = 0; - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&i", kwlist, &PyBlitzArray_Converter, &input, &i)){ - return 0; - } - - //protects acquired resources through this scope - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, get_distance_from_mean.name()); - return 0; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, get_distance_from_mean.name()); - return 0; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0], get_distance_from_mean.name()); - return 0; - } - - double output = self->cxx->getDistanceFromMean(*PyBlitzArrayCxx_AsBlitz<double,1>(input),i); - return Py_BuildValue("d", output); - - BOB_CATCH_MEMBER("cannot compute the likelihood", 0) -} - - -/*** get_closest_mean ***/ -static auto get_closest_mean = bob::extension::FunctionDoc( - "get_closest_mean", - "Calculate the index of the mean that is closest (in terms of square Euclidean distance) to the data sample, x.", - "", - true -) -.add_prototype("input","output") -.add_parameter("input", "array_like <float, 1D>", "The data sample (feature vector)") -.add_return("output", "(int, int)", "Tuple containing the closest mean and the minimum distance from the input"); -static PyObject* PyBobLearnEMKMeansMachine_get_closest_mean(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_closest_mean.kwlist(0); - - PyBlitzArrayObject* input = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBlitzArray_Converter, &input)) return 0; - - //protects acquired resources through this scope - auto input_ = make_safe(input); - - size_t closest_mean = 0; - double min_distance = -1; - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, get_closest_mean.name()); - return 0; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, get_closest_mean.name()); - return 0; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0], get_closest_mean.name()); - return 0; - } - - self->cxx->getClosestMean(*PyBlitzArrayCxx_AsBlitz<double,1>(input), closest_mean, min_distance); - - return Py_BuildValue("(i,d)", closest_mean, min_distance); - - BOB_CATCH_MEMBER("cannot compute the closest mean", 0) -} - - -/*** get_min_distance ***/ -static auto get_min_distance = bob::extension::FunctionDoc( - "get_min_distance", - "Output the minimum (Square Euclidean) distance between the input and the closest mean ", - "", - true -) -.add_prototype("input","output") -.add_parameter("input", "array_like <float, 1D>", "The data sample (feature vector)") -.add_return("output", "float", "The minimum distance"); -static PyObject* PyBobLearnEMKMeansMachine_get_min_distance(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_min_distance.kwlist(0); - - PyBlitzArrayObject* input = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBlitzArray_Converter, &input)) return 0; - - //protects acquired resources through this scope - auto input_ = make_safe(input); - double min_distance = 0; - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, get_min_distance.name()); - return 0; - } - - if (input->ndim != 1){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 1D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, get_min_distance.name()); - return 0; - } - - if (input->shape[0] != (Py_ssize_t)self->cxx->getNInputs()){ - PyErr_Format(PyExc_TypeError, "`%s' 1D `input` array should have %" PY_FORMAT_SIZE_T "d elements, not %" PY_FORMAT_SIZE_T "d for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[0], get_min_distance.name()); - return 0; - } - - min_distance = self->cxx->getMinDistance(*PyBlitzArrayCxx_AsBlitz<double,1>(input)); - - return Py_BuildValue("d", min_distance); - - BOB_CATCH_MEMBER("cannot compute the min distance", 0) -} - -/**** get_variances_and_weights_for_each_cluster ***/ -static auto get_variances_and_weights_for_each_cluster = bob::extension::FunctionDoc( - "get_variances_and_weights_for_each_cluster", - "For each mean, find the subset of the samples that is closest to that mean, and calculate" - " 1) the variance of that subset (the cluster variance)" - " 2) the proportion of the samples represented by that subset (the cluster weight)", - "", - true -) -.add_prototype("input","output") -.add_parameter("input", "array_like <float, 2D>", "The data sample (feature vector)") -.add_return("output", "(array_like <float, 2D>, array_like <float, 1D>)", "A tuple with the variances and the weights respectively"); -static PyObject* PyBobLearnEMKMeansMachine_get_variances_and_weights_for_each_cluster(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_variances_and_weights_for_each_cluster.kwlist(0); - - PyBlitzArrayObject* input = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBlitzArray_Converter, &input)) return 0; - - //protects acquired resources through this scope - auto input_ = make_safe(input); - - // perform check on the input - if (input->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, get_variances_and_weights_for_each_cluster.name()); - return 0; - } - - if (input->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, get_variances_and_weights_for_each_cluster.name()); - return 0; - } - - if (input->shape[1] != (Py_ssize_t)self->cxx->getNInputs() ) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, self->cxx->getNInputs(), input->shape[1], get_variances_and_weights_for_each_cluster.name()); - return 0; - } - - blitz::Array<double,2> variances(self->cxx->getNMeans(),self->cxx->getNInputs()); - blitz::Array<double,1> weights(self->cxx->getNMeans()); - - self->cxx->getVariancesAndWeightsForEachCluster(*PyBlitzArrayCxx_AsBlitz<double,2>(input),variances,weights); - - return Py_BuildValue("(N,N)",PyBlitzArrayCxx_AsConstNumpy(variances), PyBlitzArrayCxx_AsConstNumpy(weights)); - - BOB_CATCH_MEMBER("cannot compute the variances and weights for each cluster", 0) -} - - -/**** __get_variances_and_weights_for_each_cluster_init__ ***/ -static auto __get_variances_and_weights_for_each_cluster_init__ = bob::extension::FunctionDoc( - "__get_variances_and_weights_for_each_cluster_init__", - "Methods consecutively called by getVariancesAndWeightsForEachCluster()" - "This should help for the parallelization on several nodes by splitting the data and calling" - "getVariancesAndWeightsForEachClusterAcc() for each split. In this case, there is a need to sum" - "with the m_cache_means, variances, and weights variables before performing the merge on one" - "node using getVariancesAndWeightsForEachClusterFin().", - "", - true -) -.add_prototype("variances,weights","") -.add_parameter("variances", "array_like <float, 2D>", "Variance array") -.add_parameter("weights", "array_like <float, 1D>", "Weight array"); -static PyObject* PyBobLearnEMKMeansMachine_get_variances_and_weights_for_each_cluster_init(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = __get_variances_and_weights_for_each_cluster_init__.kwlist(0); - - PyBlitzArrayObject* variances = 0; - PyBlitzArrayObject* weights = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&", kwlist, &PyBlitzArray_Converter, &variances, &PyBlitzArray_Converter, &weights)) return 0; - - //protects acquired resources through this scope - auto weights_ = make_safe(weights); - auto variances_ = make_safe(variances); - - self->cxx->getVariancesAndWeightsForEachClusterInit(*PyBlitzArrayCxx_AsBlitz<double,2>(variances), *PyBlitzArrayCxx_AsBlitz<double,1>(weights)); - Py_RETURN_NONE; - - BOB_CATCH_MEMBER("cannot compute the variances and weights for each cluster", 0) -} - - -/**** __get_variances_and_weights_for_each_cluster_acc__ ***/ -static auto __get_variances_and_weights_for_each_cluster_acc__ = bob::extension::FunctionDoc( - "__get_variances_and_weights_for_each_cluster_acc__", - "Methods consecutively called by getVariancesAndWeightsForEachCluster()" - "This should help for the parallelization on several nodes by splitting the data and calling" - "getVariancesAndWeightsForEachClusterAcc() for each split. In this case, there is a need to sum" - "with the m_cache_means, variances, and weights variables before performing the merge on one" - "node using getVariancesAndWeightsForEachClusterFin().", - "", - true -) -.add_prototype("data,variances,weights","") -.add_parameter("data", "array_like <float, 2D>", "data array") -.add_parameter("variances", "array_like <float, 2D>", "Variance array") -.add_parameter("weights", "array_like <float, 1D>", "Weight array"); -static PyObject* PyBobLearnEMKMeansMachine_get_variances_and_weights_for_each_cluster_acc(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = __get_variances_and_weights_for_each_cluster_acc__.kwlist(0); - - PyBlitzArrayObject* data = 0; - PyBlitzArrayObject* variances = 0; - PyBlitzArrayObject* weights = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&O&", kwlist, &PyBlitzArray_Converter, &data, &PyBlitzArray_Converter, &variances, &PyBlitzArray_Converter, &weights)) return 0; - - //protects acquired resources through this scope - auto data_ = make_safe(data); - auto weights_ = make_safe(weights); - auto variances_ = make_safe(variances); - - self->cxx->getVariancesAndWeightsForEachClusterAcc(*PyBlitzArrayCxx_AsBlitz<double,2>(data), *PyBlitzArrayCxx_AsBlitz<double,2>(variances), *PyBlitzArrayCxx_AsBlitz<double,1>(weights)); - Py_RETURN_NONE; - - BOB_CATCH_MEMBER("cannot compute the variances and weights for each cluster", 0) -} - - -/**** __get_variances_and_weights_for_each_cluster_fin__ ***/ -static auto __get_variances_and_weights_for_each_cluster_fin__ = bob::extension::FunctionDoc( - "__get_variances_and_weights_for_each_cluster_fin__", - "Methods consecutively called by getVariancesAndWeightsForEachCluster()" - "This should help for the parallelization on several nodes by splitting the data and calling" - "getVariancesAndWeightsForEachClusterAcc() for each split. In this case, there is a need to sum" - "with the m_cache_means, variances, and weights variables before performing the merge on one" - "node using getVariancesAndWeightsForEachClusterFin().", - "", - true -) -.add_prototype("variances,weights","") -.add_parameter("variances", "array_like <float, 2D>", "Variance array") -.add_parameter("weights", "array_like <float, 1D>", "Weight array"); -static PyObject* PyBobLearnEMKMeansMachine_get_variances_and_weights_for_each_cluster_fin(PyBobLearnEMKMeansMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = __get_variances_and_weights_for_each_cluster_fin__.kwlist(0); - - PyBlitzArrayObject* variances = 0; - PyBlitzArrayObject* weights = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&", kwlist, &PyBlitzArray_Converter, &variances, &PyBlitzArray_Converter, &weights)) return 0; - - //protects acquired resources through this scope - auto weights_ = make_safe(weights); - auto variances_ = make_safe(variances); - - self->cxx->getVariancesAndWeightsForEachClusterFin(*PyBlitzArrayCxx_AsBlitz<double,2>(variances), *PyBlitzArrayCxx_AsBlitz<double,1>(weights)); - Py_RETURN_NONE; - - BOB_CATCH_MEMBER("cannot compute the variances and weights for each cluster", 0) -} - - -static PyMethodDef PyBobLearnEMKMeansMachine_methods[] = { - { - save.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_Save, - METH_VARARGS|METH_KEYWORDS, - save.doc() - }, - { - load.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_Load, - METH_VARARGS|METH_KEYWORDS, - load.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - { - resize.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_resize, - METH_VARARGS|METH_KEYWORDS, - resize.doc() - }, - { - get_mean.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_get_mean, - METH_VARARGS|METH_KEYWORDS, - get_mean.doc() - }, - { - set_mean.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_set_mean, - METH_VARARGS|METH_KEYWORDS, - set_mean.doc() - }, - { - get_distance_from_mean.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_get_distance_from_mean, - METH_VARARGS|METH_KEYWORDS, - get_distance_from_mean.doc() - }, - { - get_closest_mean.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_get_closest_mean, - METH_VARARGS|METH_KEYWORDS, - get_closest_mean.doc() - }, - { - get_min_distance.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_get_min_distance, - METH_VARARGS|METH_KEYWORDS, - get_min_distance.doc() - }, - { - get_variances_and_weights_for_each_cluster.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_get_variances_and_weights_for_each_cluster, - METH_VARARGS|METH_KEYWORDS, - get_variances_and_weights_for_each_cluster.doc() - }, - { - __get_variances_and_weights_for_each_cluster_init__.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_get_variances_and_weights_for_each_cluster_init, - METH_VARARGS|METH_KEYWORDS, - __get_variances_and_weights_for_each_cluster_init__.doc() - }, - { - __get_variances_and_weights_for_each_cluster_acc__.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_get_variances_and_weights_for_each_cluster_acc, - METH_VARARGS|METH_KEYWORDS, - __get_variances_and_weights_for_each_cluster_acc__.doc() - }, - { - __get_variances_and_weights_for_each_cluster_fin__.name(), - (PyCFunction)PyBobLearnEMKMeansMachine_get_variances_and_weights_for_each_cluster_fin, - METH_VARARGS|METH_KEYWORDS, - __get_variances_and_weights_for_each_cluster_fin__.doc() - }, - - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMKMeansMachine_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMKMeansMachine(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMKMeansMachine_Type.tp_name = KMeansMachine_doc.name(); - PyBobLearnEMKMeansMachine_Type.tp_basicsize = sizeof(PyBobLearnEMKMeansMachineObject); - PyBobLearnEMKMeansMachine_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyBobLearnEMKMeansMachine_Type.tp_doc = KMeansMachine_doc.doc(); - - // set the functions - PyBobLearnEMKMeansMachine_Type.tp_new = PyType_GenericNew; - PyBobLearnEMKMeansMachine_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMKMeansMachine_init); - PyBobLearnEMKMeansMachine_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMKMeansMachine_delete); - PyBobLearnEMKMeansMachine_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMKMeansMachine_RichCompare); - PyBobLearnEMKMeansMachine_Type.tp_methods = PyBobLearnEMKMeansMachine_methods; - PyBobLearnEMKMeansMachine_Type.tp_getset = PyBobLearnEMKMeansMachine_getseters; - //PyBobLearnEMGMMMachine_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMGMMMachine_loglikelihood); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMKMeansMachine_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMKMeansMachine_Type); - return PyModule_AddObject(module, "KMeansMachine", (PyObject*)&PyBobLearnEMKMeansMachine_Type) >= 0; -} diff --git a/bob/learn/em/kmeans_trainer.cpp b/bob/learn/em/kmeans_trainer.cpp deleted file mode 100644 index d03148cdb70482dfce55ddc807f9a7fb0ede96ff..0000000000000000000000000000000000000000 --- a/bob/learn/em/kmeans_trainer.cpp +++ /dev/null @@ -1,567 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Tue 13 Jan 16:50:00 2015 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" -#include <boost/assign.hpp> - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -// InitializationMethod type conversion - -#if BOOST_VERSION >= 104700 - static const std::map<std::string, bob::learn::em::KMeansTrainer::InitializationMethod> IM = boost::assign::map_list_of - ("RANDOM", bob::learn::em::KMeansTrainer::InitializationMethod::RANDOM) - ("RANDOM_NO_DUPLICATE", bob::learn::em::KMeansTrainer::InitializationMethod::RANDOM_NO_DUPLICATE) - ("KMEANS_PLUS_PLUS", bob::learn::em::KMeansTrainer::InitializationMethod::KMEANS_PLUS_PLUS) - ; -#else - static const std::map<std::string, bob::learn::em::KMeansTrainer::InitializationMethod> IM = boost::assign::map_list_of - ("RANDOM", bob::learn::em::KMeansTrainer::InitializationMethod::RANDOM), - ("RANDOM_NO_DUPLICATE", bob::learn::em::KMeansTrainer::InitializationMethod::RANDOM_NO_DUPLICATE) - ; -#endif - -static inline bob::learn::em::KMeansTrainer::InitializationMethod string2IM(const std::string& o){ /* converts string to InitializationMethod type */ - auto it = IM.find(o); - if (it == IM.end()) throw std::runtime_error("The given InitializationMethod '" + o + "' is not known; choose one of ('RANDOM', 'RANDOM_NO_DUPLICATE', 'KMEANS_PLUS_PLUS')"); - else return it->second; -} -static inline const std::string& IM2string(bob::learn::em::KMeansTrainer::InitializationMethod o){ /* converts InitializationMethod type to string */ - for (auto it = IM.begin(); it != IM.end(); ++it) if (it->second == o) return it->first; - throw std::runtime_error("The given InitializationMethod type is not known"); -} - - -static auto KMeansTrainer_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".KMeansTrainer", - "Trains a KMeans clustering :ref:`k-means <kmeans>`." - "This class implements the expectation-maximization algorithm for a k-means." - "See Section 9.1 of Bishop, \"Pattern recognition and machine learning\", 2006" - "It uses a random initialization of the means followed by the expectation-maximization algorithm" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Creates a KMeansTrainer", - "", - true - ) - .add_prototype("initialization_method","") - .add_prototype("other","") - .add_prototype("","") - - .add_parameter("initialization_method", "str", "The initialization method of the means.\nPossible values are: 'RANDOM', 'RANDOM_NO_DUPLICATE', 'KMEANS_PLUS_PLUS' ") - .add_parameter("other", ":py:class:`bob.learn.em.KMeansTrainer`", "A KMeansTrainer object to be copied.") - -); - - -static int PyBobLearnEMKMeansTrainer_init_copy(PyBobLearnEMKMeansTrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = KMeansTrainer_doc.kwlist(1); - PyBobLearnEMKMeansTrainerObject* tt; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMKMeansTrainer_Type, &tt)){ - KMeansTrainer_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::KMeansTrainer(*tt->cxx)); - return 0; -} - -static int PyBobLearnEMKMeansTrainer_init_str(PyBobLearnEMKMeansTrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = KMeansTrainer_doc.kwlist(0); - char* value; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &value)){ - KMeansTrainer_doc.print_usage(); - return -1; - } - self->cxx.reset(new bob::learn::em::KMeansTrainer(string2IM(std::string(value)))); - return 0; -} - - -static int PyBobLearnEMKMeansTrainer_init(PyBobLearnEMKMeansTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - switch (nargs) { - - case 0:{ //default initializer () - self->cxx.reset(new bob::learn::em::KMeansTrainer()); - return 0; - } - case 1:{ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is KMeansTrainer object - if (PyBobLearnEMKMeansTrainer_Check(arg)) - return PyBobLearnEMKMeansTrainer_init_copy(self, args, kwargs); - else if(PyString_Check(arg)) - return PyBobLearnEMKMeansTrainer_init_str(self, args, kwargs); - } - default:{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires 0 or 1 arguments, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - KMeansTrainer_doc.print_usage(); - return -1; - } - } - BOB_CATCH_MEMBER("cannot create KMeansTrainer", -1) - return 0; -} - - -static void PyBobLearnEMKMeansTrainer_delete(PyBobLearnEMKMeansTrainerObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - - -int PyBobLearnEMKMeansTrainer_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMKMeansTrainer_Type)); -} - - -static PyObject* PyBobLearnEMKMeansTrainer_RichCompare(PyBobLearnEMKMeansTrainerObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMKMeansTrainer_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMKMeansTrainerObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare KMeansTrainer objects", 0) -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** initialization_method *****/ -static auto initialization_method = bob::extension::VariableDoc( - "initialization_method", - "str", - "Initialization method.", - "Possible values:\n" - " `RANDOM`: Random initialization \n\n" - " `RANDOM_NO_DUPLICATE`: Random initialization without repetition \n\n" - " `KMEANS_PLUS_PLUS`: Apply the kmeans++ initialization http://en.wikipedia.org/wiki/K-means%2B%2B \n\n" -); -PyObject* PyBobLearnEMKMeansTrainer_getInitializationMethod(PyBobLearnEMKMeansTrainerObject* self, void*) { - BOB_TRY - return Py_BuildValue("s", IM2string(self->cxx->getInitializationMethod()).c_str()); - BOB_CATCH_MEMBER("initialization method could not be read", 0) -} -int PyBobLearnEMKMeansTrainer_setInitializationMethod(PyBobLearnEMKMeansTrainerObject* self, PyObject* value, void*) { - BOB_TRY - - if (!PyString_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects an str", Py_TYPE(self)->tp_name, initialization_method.name()); - return -1; - } - self->cxx->setInitializationMethod(string2IM(PyString_AS_STRING(value))); - - return 0; - BOB_CATCH_MEMBER("initialization method could not be set", -1) -} - - -/***** zeroeth_order_statistics *****/ -static auto zeroeth_order_statistics = bob::extension::VariableDoc( - "zeroeth_order_statistics", - "array_like <float, 1D>", - "Returns the internal statistics. Useful to parallelize the E-step", - "" -); -PyObject* PyBobLearnEMKMeansTrainer_getZeroethOrderStatistics(PyBobLearnEMKMeansTrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getZeroethOrderStats()); - BOB_CATCH_MEMBER("zeroeth_order_statistics could not be read", 0) -} -int PyBobLearnEMKMeansTrainer_setZeroethOrderStatistics(PyBobLearnEMKMeansTrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, zeroeth_order_statistics.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(o, "zeroeth_order_statistics"); - if (!b) return -1; - self->cxx->setZeroethOrderStats(*b); - return 0; - BOB_CATCH_MEMBER("zeroeth_order_statistics could not be set", -1) -} - - -/***** first_order_statistics *****/ -static auto first_order_statistics = bob::extension::VariableDoc( - "first_order_statistics", - "array_like <float, 2D>", - "Returns the internal statistics. Useful to parallelize the E-step", - "" -); -PyObject* PyBobLearnEMKMeansTrainer_getFirstOrderStatistics(PyBobLearnEMKMeansTrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getFirstOrderStats()); - BOB_CATCH_MEMBER("first_order_statistics could not be read", 0) -} -int PyBobLearnEMKMeansTrainer_setFirstOrderStatistics(PyBobLearnEMKMeansTrainerObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 1D array of floats", Py_TYPE(self)->tp_name, first_order_statistics.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(o, "first_order_statistics"); - if (!b) return -1; - self->cxx->setFirstOrderStats(*b); - return 0; - BOB_CATCH_MEMBER("first_order_statistics could not be set", -1) -} - - -/***** average_min_distance *****/ -static auto average_min_distance = bob::extension::VariableDoc( - "average_min_distance", - "str", - "Average min (square Euclidean) distance. Useful to parallelize the E-step.", - "" -); -PyObject* PyBobLearnEMKMeansTrainer_getAverageMinDistance(PyBobLearnEMKMeansTrainerObject* self, void*) { - BOB_TRY - return Py_BuildValue("d", self->cxx->getAverageMinDistance()); - BOB_CATCH_MEMBER("Average Min Distance method could not be read", 0) -} -int PyBobLearnEMKMeansTrainer_setAverageMinDistance(PyBobLearnEMKMeansTrainerObject* self, PyObject* value, void*) { - BOB_TRY - - if (!PyBob_NumberCheck(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects an double", Py_TYPE(self)->tp_name, average_min_distance.name()); - return -1; - } - self->cxx->setAverageMinDistance(PyFloat_AS_DOUBLE(value)); - - return 0; - BOB_CATCH_MEMBER("Average Min Distance could not be set", -1) -} - - - - -static PyGetSetDef PyBobLearnEMKMeansTrainer_getseters[] = { - { - initialization_method.name(), - (getter)PyBobLearnEMKMeansTrainer_getInitializationMethod, - (setter)PyBobLearnEMKMeansTrainer_setInitializationMethod, - initialization_method.doc(), - 0 - }, - { - zeroeth_order_statistics.name(), - (getter)PyBobLearnEMKMeansTrainer_getZeroethOrderStatistics, - (setter)PyBobLearnEMKMeansTrainer_setZeroethOrderStatistics, - zeroeth_order_statistics.doc(), - 0 - }, - { - first_order_statistics.name(), - (getter)PyBobLearnEMKMeansTrainer_getFirstOrderStatistics, - (setter)PyBobLearnEMKMeansTrainer_setFirstOrderStatistics, - first_order_statistics.doc(), - 0 - }, - { - average_min_distance.name(), - (getter)PyBobLearnEMKMeansTrainer_getAverageMinDistance, - (setter)PyBobLearnEMKMeansTrainer_setAverageMinDistance, - average_min_distance.doc(), - 0 - }, - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - -/*** initialize ***/ -static auto initialize = bob::extension::FunctionDoc( - "initialize", - "Initialise the means randomly", - "Data is split into as many chunks as there are means, then each mean is set to a random example within each chunk.", - true -) -.add_prototype("kmeans_machine, data, [rng]") -.add_parameter("kmeans_machine", ":py:class:`bob.learn.em.KMeansMachine`", "KMeansMachine Object") -.add_parameter("data", "array_like <float, 2D>", "Input data") -.add_parameter("rng", ":py:class:`bob.core.random.mt19937`", "The Mersenne Twister mt19937 random generator used for the initialization of subspaces/arrays before the EM loop."); -static PyObject* PyBobLearnEMKMeansTrainer_initialize(PyBobLearnEMKMeansTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = initialize.kwlist(0); - - PyBobLearnEMKMeansMachineObject* kmeans_machine = 0; - PyBlitzArrayObject* data = 0; - PyBoostMt19937Object* rng = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&|O!", kwlist, &PyBobLearnEMKMeansMachine_Type, &kmeans_machine, - &PyBlitzArray_Converter, &data, - &PyBoostMt19937_Type, &rng)) return 0; - auto data_ = make_safe(data); - - // perform check on the input - if (data->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, initialize.name()); - return 0; - } - - if (data->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, initialize.name()); - return 0; - } - - if (data->shape[1] != (Py_ssize_t)kmeans_machine->cxx->getNInputs() ) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, kmeans_machine->cxx->getNInputs(), data->shape[1], initialize.name()); - return 0; - } - - if(rng){ - self->cxx->setRng(rng->rng); - } - - self->cxx->initialize(*kmeans_machine->cxx, *PyBlitzArrayCxx_AsBlitz<double,2>(data)); - - BOB_CATCH_MEMBER("cannot perform the initialize method", 0) - - Py_RETURN_NONE; -} - - -/*** e_step ***/ -static auto e_step = bob::extension::FunctionDoc( - "e_step", - "Compute the E-step, which is basically the distances ", - "Accumulate across the dataset:" - " -zeroeth and first order statistics" - " -average (Square Euclidean) distance from the closest mean", - true -) -.add_prototype("kmeans_machine,data") -.add_parameter("kmeans_machine", ":py:class:`bob.learn.em.KMeansMachine`", "KMeansMachine Object") -.add_parameter("data", "array_like <float, 2D>", "Input data"); -static PyObject* PyBobLearnEMKMeansTrainer_e_step(PyBobLearnEMKMeansTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = e_step.kwlist(0); - - PyBobLearnEMKMeansMachineObject* kmeans_machine; - PyBlitzArrayObject* data = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMKMeansMachine_Type, &kmeans_machine, - &PyBlitzArray_Converter, &data)) return 0; - auto data_ = make_safe(data); - - if (data->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, e_step.name()); - return 0; - } - - if (data->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, e_step.name()); - return 0; - } - - if (data->shape[1] != (Py_ssize_t)kmeans_machine->cxx->getNInputs() ) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, kmeans_machine->cxx->getNInputs(), data->shape[1], e_step.name()); - return 0; - } - - auto state = PyEval_SaveThread(); - self->cxx->eStep(*kmeans_machine->cxx, *PyBlitzArrayCxx_AsBlitz<double,2>(data)); - PyEval_RestoreThread(state); - - BOB_CATCH_MEMBER("cannot perform the e_step method", 0) - - Py_RETURN_NONE; -} - - -/*** m_step ***/ -static auto m_step = bob::extension::FunctionDoc( - "m_step", - "Updates the mean based on the statistics from the E-step", - 0, - true -) -.add_prototype("kmeans_machine, [data]") -.add_parameter("kmeans_machine", ":py:class:`bob.learn.em.KMeansMachine`", "KMeansMachine Object") -.add_parameter("data", "object", "Ignored."); -static PyObject* PyBobLearnEMKMeansTrainer_m_step(PyBobLearnEMKMeansTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = m_step.kwlist(0); - - PyBobLearnEMKMeansMachineObject* kmeans_machine; - PyObject* data = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", kwlist, &PyBobLearnEMKMeansMachine_Type, &kmeans_machine, - &data)) return 0; - self->cxx->mStep(*kmeans_machine->cxx); - - BOB_CATCH_MEMBER("cannot perform the m_step method", 0) - - Py_RETURN_NONE; -} - - -/*** computeLikelihood ***/ -static auto compute_likelihood = bob::extension::FunctionDoc( - "compute_likelihood", - "This functions returns the average min (Square Euclidean) distance (average distance to the closest mean)", - 0, - true -) -.add_prototype("kmeans_machine") -.add_parameter("kmeans_machine", ":py:class:`bob.learn.em.KMeansMachine`", "KMeansMachine Object"); -static PyObject* PyBobLearnEMKMeansTrainer_compute_likelihood(PyBobLearnEMKMeansTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = compute_likelihood.kwlist(0); - - PyBobLearnEMKMeansMachineObject* kmeans_machine; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMKMeansMachine_Type, &kmeans_machine)) return 0; - - double value = self->cxx->computeLikelihood(*kmeans_machine->cxx); - return Py_BuildValue("d", value); - - BOB_CATCH_MEMBER("cannot perform the computeLikelihood method", 0) -} - - -/*** reset_accumulators ***/ -static auto reset_accumulators = bob::extension::FunctionDoc( - "reset_accumulators", - "Reset the statistics accumulators to the correct size and a value of zero.", - 0, - true -) -.add_prototype("kmeans_machine") -.add_parameter("kmeans_machine", ":py:class:`bob.learn.em.KMeansMachine`", "KMeansMachine Object"); -static PyObject* PyBobLearnEMKMeansTrainer_reset_accumulators(PyBobLearnEMKMeansTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = reset_accumulators.kwlist(0); - - PyBobLearnEMKMeansMachineObject* kmeans_machine; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMKMeansMachine_Type, &kmeans_machine)) return 0; - - self->cxx->resetAccumulators(*kmeans_machine->cxx); - Py_RETURN_NONE; - - BOB_CATCH_MEMBER("cannot perform the reset_accumulators method", 0) -} - - -static PyMethodDef PyBobLearnEMKMeansTrainer_methods[] = { - { - initialize.name(), - (PyCFunction)PyBobLearnEMKMeansTrainer_initialize, - METH_VARARGS|METH_KEYWORDS, - initialize.doc() - }, - { - e_step.name(), - (PyCFunction)PyBobLearnEMKMeansTrainer_e_step, - METH_VARARGS|METH_KEYWORDS, - e_step.doc() - }, - { - m_step.name(), - (PyCFunction)PyBobLearnEMKMeansTrainer_m_step, - METH_VARARGS|METH_KEYWORDS, - m_step.doc() - }, - { - compute_likelihood.name(), - (PyCFunction)PyBobLearnEMKMeansTrainer_compute_likelihood, - METH_VARARGS|METH_KEYWORDS, - compute_likelihood.doc() - }, - { - reset_accumulators.name(), - (PyCFunction)PyBobLearnEMKMeansTrainer_reset_accumulators, - METH_VARARGS|METH_KEYWORDS, - reset_accumulators.doc() - }, - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMKMeansTrainer_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMKMeansTrainer(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMKMeansTrainer_Type.tp_name = KMeansTrainer_doc.name(); - PyBobLearnEMKMeansTrainer_Type.tp_basicsize = sizeof(PyBobLearnEMKMeansTrainerObject); - PyBobLearnEMKMeansTrainer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;//Enable the class inheritance - PyBobLearnEMKMeansTrainer_Type.tp_doc = KMeansTrainer_doc.doc(); - - // set the functions - PyBobLearnEMKMeansTrainer_Type.tp_new = PyType_GenericNew; - PyBobLearnEMKMeansTrainer_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMKMeansTrainer_init); - PyBobLearnEMKMeansTrainer_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMKMeansTrainer_delete); - PyBobLearnEMKMeansTrainer_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMKMeansTrainer_RichCompare); - PyBobLearnEMKMeansTrainer_Type.tp_methods = PyBobLearnEMKMeansTrainer_methods; - PyBobLearnEMKMeansTrainer_Type.tp_getset = PyBobLearnEMKMeansTrainer_getseters; - PyBobLearnEMKMeansTrainer_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMKMeansTrainer_compute_likelihood); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMKMeansTrainer_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMKMeansTrainer_Type); - return PyModule_AddObject(module, "KMeansTrainer", (PyObject*)&PyBobLearnEMKMeansTrainer_Type) >= 0; -} diff --git a/bob/learn/em/linear_scoring.cpp b/bob/learn/em/linear_scoring.cpp deleted file mode 100644 index f29b59370b12ef35635c78ec6a267dec756f8ac9..0000000000000000000000000000000000000000 --- a/bob/learn/em/linear_scoring.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Wed 05 Feb 16:10:48 2015 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/*Convert a PyObject to a a list of GMMStats*/ -//template<class R, class P1, class P2> -static int extract_gmmstats_list(PyObject *list, - std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> >& training_data) -{ - for (int i=0; i<PyList_GET_SIZE(list); i++){ - - PyBobLearnEMGMMStatsObject* stats; - if (!PyArg_Parse(PyList_GetItem(list, i), "O!", &PyBobLearnEMGMMStats_Type, &stats)){ - PyErr_Format(PyExc_RuntimeError, "Expected GMMStats objects"); - return -1; - } - training_data.push_back(stats->cxx); - } - return 0; -} - -static int extract_gmmmachine_list(PyObject *list, - std::vector<boost::shared_ptr<const bob::learn::em::GMMMachine> >& training_data) -{ - for (int i=0; i<PyList_GET_SIZE(list); i++){ - - PyBobLearnEMGMMMachineObject* stats; - if (!PyArg_Parse(PyList_GetItem(list, i), "O!", &PyBobLearnEMGMMMachine_Type, &stats)){ - PyErr_Format(PyExc_RuntimeError, "Expected GMMMachine objects"); - return -1; - } - training_data.push_back(stats->cxx); - } - return 0; -} - - - -/*Convert a PyObject to a list of blitz Array*/ -template <int N> -int extract_array_list(PyObject* list, std::vector<blitz::Array<double,N> >& vec) -{ - - if(list==0) - return 0; - - for (int i=0; i<PyList_GET_SIZE(list); i++) - { - PyBlitzArrayObject* blitz_object; - if (!PyArg_Parse(PyList_GetItem(list, i), "O&", &PyBlitzArray_Converter, &blitz_object)){ - PyErr_Format(PyExc_RuntimeError, "Expected numpy array object"); - return -1; - } - auto blitz_object_ = make_safe(blitz_object); - vec.push_back(*PyBlitzArrayCxx_AsBlitz<double,N>(blitz_object)); - } - return 0; -} - -/* converts PyObject to bool and returns false if object is NULL */ -static inline bool f(PyObject* o){return o != 0 && PyObject_IsTrue(o) > 0;} - - -/*** linear_scoring ***/ -bob::extension::FunctionDoc linear_scoring1 = bob::extension::FunctionDoc( - "linear_scoring", - "The :ref:`Linear scoring <linearscoring>` is an approximation to the log-likelihood ratio that was shown to be as accurate and up to two orders of magnitude more efficient to compute [Glembek2009]_." - "", - 0, - true -) -.add_prototype("models, ubm, test_stats, test_channelOffset, frame_length_normalisation", "output") -.add_parameter("models", "[:py:class:`bob.learn.em.GMMMachine`]", "") -.add_parameter("ubm", ":py:class:`bob.learn.em.GMMMachine`", "") -.add_parameter("test_stats", "[:py:class:`bob.learn.em.GMMStats`]", "") -.add_parameter("test_channelOffset", "[array_like<float,1>]", "") -.add_parameter("frame_length_normalisation", "bool", "") -.add_return("output","array_like<float,1>","Score"); - - -bob::extension::FunctionDoc linear_scoring2 = bob::extension::FunctionDoc( - "linear_scoring", - "", - 0, - true -) -.add_prototype("models, ubm_mean, ubm_variance, test_stats, test_channelOffset, frame_length_normalisation", "output") -.add_parameter("models", "list(array_like<float,1>)", "") -.add_parameter("ubm_mean", "list(array_like<float,1>)", "") -.add_parameter("ubm_variance", "list(array_like<float,1>)", "") -.add_parameter("test_stats", "list(:py:class:`bob.learn.em.GMMStats`)", "") -.add_parameter("test_channelOffset", "list(array_like<float,1>)", "") -.add_parameter("frame_length_normalisation", "bool", "") -.add_return("output","array_like<float,1>","Score"); - - - -bob::extension::FunctionDoc linear_scoring3 = bob::extension::FunctionDoc( - "linear_scoring", - "", - 0, - true -) -.add_prototype("model, ubm_mean, ubm_variance, test_stats, test_channelOffset, frame_length_normalisation", "output") -.add_parameter("model", "array_like<float,1>", "") -.add_parameter("ubm_mean", "array_like<float,1>", "") -.add_parameter("ubm_variance", "array_like<float,1>", "") -.add_parameter("test_stats", ":py:class:`bob.learn.em.GMMStats`", "") -.add_parameter("test_channelOffset", "array_like<float,1>", "") -.add_parameter("frame_length_normalisation", "bool", "") -.add_return("output","array_like<float,1>","Score"); - -PyObject* PyBobLearnEM_linear_scoring(PyObject*, PyObject* args, PyObject* kwargs) { - - //Cheking the number of arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - //Reading the first input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - //Checking the signature of the method (list of GMMMachine as input) - if ((PyList_Check(arg)) && PyBobLearnEMGMMMachine_Check(PyList_GetItem(arg, 0)) && (nargs >= 3) && (nargs<=5) ){ - - char** kwlist = linear_scoring1.kwlist(0); - - PyObject* gmm_list_o = 0; - PyBobLearnEMGMMMachineObject* ubm = 0; - PyObject* stats_list_o = 0; - PyObject* channel_offset_list_o = 0; - PyObject* frame_length_normalisation = Py_False; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!O!|O!O!", kwlist, &PyList_Type, &gmm_list_o, - &PyBobLearnEMGMMMachine_Type, &ubm, - &PyList_Type, &stats_list_o, - &PyList_Type, &channel_offset_list_o, - &PyBool_Type, &frame_length_normalisation)){ - linear_scoring1.print_usage(); - return 0; - } - - std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> > stats_list; - if(extract_gmmstats_list(stats_list_o ,stats_list)!=0) - Py_RETURN_NONE; - - std::vector<boost::shared_ptr<const bob::learn::em::GMMMachine> > gmm_list; - if(extract_gmmmachine_list(gmm_list_o ,gmm_list)!=0) - Py_RETURN_NONE; - - std::vector<blitz::Array<double,1> > channel_offset_list; - if(extract_array_list(channel_offset_list_o ,channel_offset_list)!=0) - Py_RETURN_NONE; - - blitz::Array<double, 2> scores = blitz::Array<double, 2>(gmm_list.size(), stats_list.size()); - if(channel_offset_list.size()==0) - bob::learn::em::linearScoring(gmm_list, *ubm->cxx, stats_list, f(frame_length_normalisation),scores); - else - bob::learn::em::linearScoring(gmm_list, *ubm->cxx, stats_list, channel_offset_list, f(frame_length_normalisation),scores); - - return PyBlitzArrayCxx_AsConstNumpy(scores); - } - - //Checking the signature of the method (list of arrays as input - else if ((PyList_Check(arg)) && PyArray_Check(PyList_GetItem(arg, 0)) && (nargs >= 4) && (nargs<=6) ){ - - char** kwlist = linear_scoring2.kwlist(0); - - PyObject* model_supervector_list_o = 0; - PyBlitzArrayObject* ubm_means = 0; - PyBlitzArrayObject* ubm_variances = 0; - PyObject* stats_list_o = 0; - PyObject* channel_offset_list_o = 0; - PyObject* frame_length_normalisation = Py_False; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&O&O!|O!O!", kwlist, &PyList_Type, &model_supervector_list_o, - &PyBlitzArray_Converter, &ubm_means, - &PyBlitzArray_Converter, &ubm_variances, - &PyList_Type, &stats_list_o, - &PyList_Type, &channel_offset_list_o, - &PyBool_Type, &frame_length_normalisation)){ - linear_scoring2.print_usage(); - return 0; - } - - //protects acquired resources through this scope - auto ubm_means_ = make_safe(ubm_means); - auto ubm_variances_ = make_safe(ubm_variances); - - std::vector<blitz::Array<double,1> > model_supervector_list; - if(extract_array_list(model_supervector_list_o ,model_supervector_list)!=0) - Py_RETURN_NONE; - - std::vector<boost::shared_ptr<const bob::learn::em::GMMStats> > stats_list; - if(extract_gmmstats_list(stats_list_o ,stats_list)!=0) - Py_RETURN_NONE; - - std::vector<blitz::Array<double,1> > channel_offset_list; - if(extract_array_list(channel_offset_list_o ,channel_offset_list)!=0) - Py_RETURN_NONE; - - blitz::Array<double, 2> scores = blitz::Array<double, 2>(model_supervector_list.size(), stats_list.size()); - if(channel_offset_list.size()==0) - bob::learn::em::linearScoring(model_supervector_list, *PyBlitzArrayCxx_AsBlitz<double,1>(ubm_means),*PyBlitzArrayCxx_AsBlitz<double,1>(ubm_variances), stats_list, f(frame_length_normalisation),scores); - else - bob::learn::em::linearScoring(model_supervector_list, *PyBlitzArrayCxx_AsBlitz<double,1>(ubm_means),*PyBlitzArrayCxx_AsBlitz<double,1>(ubm_variances), stats_list, channel_offset_list, f(frame_length_normalisation),scores); - - return PyBlitzArrayCxx_AsConstNumpy(scores); - - } - - //Checking the signature of the method (list of arrays as input - else if (PyArray_Check(arg) && (nargs >= 5) && (nargs<=6) ){ - - char** kwlist = linear_scoring3.kwlist(0); - - PyBlitzArrayObject* model = 0; - PyBlitzArrayObject* ubm_means = 0; - PyBlitzArrayObject* ubm_variances = 0; - PyBobLearnEMGMMStatsObject* stats = 0; - PyBlitzArrayObject* channel_offset = 0; - PyObject* frame_length_normalisation = Py_False; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&O&O!O&|O!", kwlist, &PyBlitzArray_Converter, &model, - &PyBlitzArray_Converter, &ubm_means, - &PyBlitzArray_Converter, &ubm_variances, - &PyBobLearnEMGMMStats_Type, &stats, - &PyBlitzArray_Converter, &channel_offset, - &PyBool_Type, &frame_length_normalisation)){ - linear_scoring3.print_usage(); - return 0; - } - - //protects acquired resources through this scope - auto model_ = make_safe(model); - auto ubm_means_ = make_safe(ubm_means); - auto ubm_variances_ = make_safe(ubm_variances); - auto channel_offset_ = make_safe(channel_offset); - - double score = bob::learn::em::linearScoring(*PyBlitzArrayCxx_AsBlitz<double,1>(model), *PyBlitzArrayCxx_AsBlitz<double,1>(ubm_means),*PyBlitzArrayCxx_AsBlitz<double,1>(ubm_variances), *stats->cxx, *PyBlitzArrayCxx_AsBlitz<double,1>(channel_offset), f(frame_length_normalisation)); - - return Py_BuildValue("d",score); - } - - - else{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - linear_scoring requires 5 or 6 arguments, but you provided %d (see help)", nargs); - linear_scoring1.print_usage(); - linear_scoring2.print_usage(); - linear_scoring3.print_usage(); - return 0; - } - -} diff --git a/bob/learn/em/main.cpp b/bob/learn/em/main.cpp deleted file mode 100644 index c2e7211f47fb44321375a2ffd56640c29c31f97c..0000000000000000000000000000000000000000 --- a/bob/learn/em/main.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Fri Nov 21 12:39:21 CET 2014 - * - * @brief Bindings to bob::learn::em routines - */ - -#ifdef NO_IMPORT_ARRAY -#undef NO_IMPORT_ARRAY -#endif -#include "main.h" - -static PyMethodDef module_methods[] = { - { - linear_scoring1.name(), - (PyCFunction)PyBobLearnEM_linear_scoring, - METH_VARARGS|METH_KEYWORDS, - linear_scoring1.doc() - }, - - {0}//Sentinel -}; - - -PyDoc_STRVAR(module_docstr, "Bob EM based Machine Learning Routines"); - -int PyBobLearnEM_APIVersion = BOB_LEARN_EM_API_VERSION; - - -#if PY_VERSION_HEX >= 0x03000000 -static PyModuleDef module_definition = { - PyModuleDef_HEAD_INIT, - BOB_EXT_MODULE_NAME, - module_docstr, - -1, - module_methods, - 0, 0, 0, 0 -}; -#endif - -static PyObject* create_module (void) { - -# if PY_VERSION_HEX >= 0x03000000 - PyObject* module = PyModule_Create(&module_definition); - auto module_ = make_xsafe(module); - const char* ret = "O"; -# else - PyObject* module = Py_InitModule3(BOB_EXT_MODULE_NAME, module_methods, module_docstr); - const char* ret = "N"; -# endif - if (!module) return 0; - - if (!init_BobLearnEMGaussian(module)) return 0; - if (!init_BobLearnEMGMMStats(module)) return 0; - if (!init_BobLearnEMGMMMachine(module)) return 0; - if (!init_BobLearnEMKMeansMachine(module)) return 0; - if (!init_BobLearnEMKMeansTrainer(module)) return 0; - if (!init_BobLearnEMMLGMMTrainer(module)) return 0; - if (!init_BobLearnEMMAPGMMTrainer(module)) return 0; - - if (!init_BobLearnEMJFABase(module)) return 0; - if (!init_BobLearnEMJFAMachine(module)) return 0; - if (!init_BobLearnEMJFATrainer(module)) return 0; - - if (!init_BobLearnEMISVBase(module)) return 0; - if (!init_BobLearnEMISVMachine(module)) return 0; - if (!init_BobLearnEMISVTrainer(module)) return 0; - - if (!init_BobLearnEMIVectorMachine(module)) return 0; - if (!init_BobLearnEMIVectorTrainer(module)) return 0; - - if (!init_BobLearnEMPLDABase(module)) return 0; - if (!init_BobLearnEMPLDAMachine(module)) return 0; - if (!init_BobLearnEMPLDATrainer(module)) return 0; - - if (!init_BobLearnEMEMPCATrainer(module)) return 0; - - - static void* PyBobLearnEM_API[PyBobLearnEM_API_pointers]; - - /* exhaustive list of C APIs */ - - /************** - * Versioning * - **************/ - - PyBobLearnEM_API[PyBobLearnEM_APIVersion_NUM] = (void *)&PyBobLearnEM_APIVersion; - - -#if PY_VERSION_HEX >= 0x02070000 - - /* defines the PyCapsule */ - - PyObject* c_api_object = PyCapsule_New((void *)PyBobLearnEM_API, - BOB_EXT_MODULE_PREFIX "." BOB_EXT_MODULE_NAME "._C_API", 0); - -#else - - PyObject* c_api_object = PyCObject_FromVoidPtr((void *)PyBobLearnEM_API, 0); - -#endif - - if (!c_api_object) return 0; - - if (PyModule_AddObject(module, "_C_API", c_api_object) < 0) return 0; - - /* imports bob.learn.em's C-API dependencies */ - if (import_bob_blitz() < 0) return 0; - if (import_bob_core_logging() < 0) return 0; - if (import_bob_core_random() < 0) return 0; - if (import_bob_io_base() < 0) return 0; - if (import_bob_sp() < 0) return 0; - if (import_bob_learn_activation() < 0) return 0; - if (import_bob_learn_linear() < 0) return 0; - - return Py_BuildValue(ret, module); -} - -PyMODINIT_FUNC BOB_EXT_ENTRY_NAME (void) { -# if PY_VERSION_HEX >= 0x03000000 - return -# endif - create_module(); -} diff --git a/bob/learn/em/main.h b/bob/learn/em/main.h deleted file mode 100644 index 7d2cb43eca159beb3b16bc03430a5c8dc9039584..0000000000000000000000000000000000000000 --- a/bob/learn/em/main.h +++ /dev/null @@ -1,274 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Fri Nov 21 10:31:25 CET 2014 - * - * @brief Header file for bindings to bob::learn::em - */ - -#ifndef BOB_LEARN_EM_MAIN_H -#define BOB_LEARN_EM_MAIN_H - -#include <bob.blitz/cppapi.h> -#include <bob.blitz/cleanup.h> -#include <bob.core/api.h> -#include <bob.core/random_api.h> -#include <bob.io.base/api.h> -#include <bob.sp/api.h> -#include <bob.learn.activation/api.h> -#include <bob.learn.linear/api.h> - -#include <bob.extension/documentation.h> - -#define BOB_LEARN_EM_MODULE -#include <bob.learn.em/api.h> - -#include <bob.learn.em/Gaussian.h> -#include <bob.learn.em/GMMStats.h> -#include <bob.learn.em/GMMMachine.h> -#include <bob.learn.em/KMeansMachine.h> - -#include <bob.learn.em/KMeansTrainer.h> -//#include <bob.learn.em/GMMBaseTrainer.h> -#include <bob.learn.em/ML_GMMTrainer.h> -#include <bob.learn.em/MAP_GMMTrainer.h> - -#include <bob.learn.em/JFABase.h> -#include <bob.learn.em/JFAMachine.h> -#include <bob.learn.em/JFATrainer.h> - -#include <bob.learn.em/ISVBase.h> -#include <bob.learn.em/ISVMachine.h> -#include <bob.learn.em/ISVTrainer.h> - - -#include <bob.learn.em/IVectorMachine.h> -#include <bob.learn.em/IVectorTrainer.h> - -#include <bob.learn.em/EMPCATrainer.h> - -#include <bob.learn.em/PLDAMachine.h> -#include <bob.learn.em/PLDATrainer.h> - - -/// inserts the given key, value pair into the given dictionaries -static inline int insert_item_string(PyObject* dict, PyObject* entries, const char* key, Py_ssize_t value){ - auto v = make_safe(Py_BuildValue("n", value)); - if (PyDict_SetItemString(dict, key, v.get()) < 0) return -1; - return PyDict_SetItemString(entries, key, v.get()); -} - -// Gaussian -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::Gaussian> cxx; -} PyBobLearnEMGaussianObject; - -extern PyTypeObject PyBobLearnEMGaussian_Type; -bool init_BobLearnEMGaussian(PyObject* module); -int PyBobLearnEMGaussian_Check(PyObject* o); - - -// GMMStats -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::GMMStats> cxx; -} PyBobLearnEMGMMStatsObject; - -extern PyTypeObject PyBobLearnEMGMMStats_Type; -bool init_BobLearnEMGMMStats(PyObject* module); -int PyBobLearnEMGMMStats_Check(PyObject* o); - - -// GMMMachine -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::GMMMachine> cxx; -} PyBobLearnEMGMMMachineObject; - -extern PyTypeObject PyBobLearnEMGMMMachine_Type; -bool init_BobLearnEMGMMMachine(PyObject* module); -int PyBobLearnEMGMMMachine_Check(PyObject* o); - - -// KMeansMachine -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::KMeansMachine> cxx; -} PyBobLearnEMKMeansMachineObject; - -extern PyTypeObject PyBobLearnEMKMeansMachine_Type; -bool init_BobLearnEMKMeansMachine(PyObject* module); -int PyBobLearnEMKMeansMachine_Check(PyObject* o); - - -// KMeansTrainer -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::KMeansTrainer> cxx; -} PyBobLearnEMKMeansTrainerObject; - -extern PyTypeObject PyBobLearnEMKMeansTrainer_Type; -bool init_BobLearnEMKMeansTrainer(PyObject* module); -int PyBobLearnEMKMeansTrainer_Check(PyObject* o); - - -// ML_GMMTrainer -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::ML_GMMTrainer> cxx; -} PyBobLearnEMMLGMMTrainerObject; - -extern PyTypeObject PyBobLearnEMMLGMMTrainer_Type; -bool init_BobLearnEMMLGMMTrainer(PyObject* module); -int PyBobLearnEMMLGMMTrainer_Check(PyObject* o); - - -// MAP_GMMTrainer -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::MAP_GMMTrainer> cxx; -} PyBobLearnEMMAPGMMTrainerObject; - -extern PyTypeObject PyBobLearnEMMAPGMMTrainer_Type; -bool init_BobLearnEMMAPGMMTrainer(PyObject* module); -int PyBobLearnEMMAPGMMTrainer_Check(PyObject* o); - - -// JFABase -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::JFABase> cxx; -} PyBobLearnEMJFABaseObject; - -extern PyTypeObject PyBobLearnEMJFABase_Type; -bool init_BobLearnEMJFABase(PyObject* module); -int PyBobLearnEMJFABase_Check(PyObject* o); - - -// ISVBase -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::ISVBase> cxx; -} PyBobLearnEMISVBaseObject; - -extern PyTypeObject PyBobLearnEMISVBase_Type; -bool init_BobLearnEMISVBase(PyObject* module); -int PyBobLearnEMISVBase_Check(PyObject* o); - - -// JFAMachine -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::JFAMachine> cxx; -} PyBobLearnEMJFAMachineObject; - -extern PyTypeObject PyBobLearnEMJFAMachine_Type; -bool init_BobLearnEMJFAMachine(PyObject* module); -int PyBobLearnEMJFAMachine_Check(PyObject* o); - -// JFATrainer -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::JFATrainer> cxx; -} PyBobLearnEMJFATrainerObject; - - -extern PyTypeObject PyBobLearnEMJFATrainer_Type; -bool init_BobLearnEMJFATrainer(PyObject* module); -int PyBobLearnEMJFATrainer_Check(PyObject* o); - -// ISVMachine -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::ISVMachine> cxx; -} PyBobLearnEMISVMachineObject; - -extern PyTypeObject PyBobLearnEMISVMachine_Type; -bool init_BobLearnEMISVMachine(PyObject* module); -int PyBobLearnEMISVMachine_Check(PyObject* o); - -// ISVTrainer -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::ISVTrainer> cxx; -} PyBobLearnEMISVTrainerObject; - -extern PyTypeObject PyBobLearnEMISVTrainer_Type; -bool init_BobLearnEMISVTrainer(PyObject* module); -int PyBobLearnEMISVTrainer_Check(PyObject* o); - -// IVectorMachine -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::IVectorMachine> cxx; -} PyBobLearnEMIVectorMachineObject; - -extern PyTypeObject PyBobLearnEMIVectorMachine_Type; -bool init_BobLearnEMIVectorMachine(PyObject* module); -int PyBobLearnEMIVectorMachine_Check(PyObject* o); - - -// IVectorTrainer -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::IVectorTrainer> cxx; -} PyBobLearnEMIVectorTrainerObject; - -extern PyTypeObject PyBobLearnEMIVectorTrainer_Type; -bool init_BobLearnEMIVectorTrainer(PyObject* module); -int PyBobLearnEMIVectorTrainer_Check(PyObject* o); - - -// PLDABase -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::PLDABase> cxx; -} PyBobLearnEMPLDABaseObject; - -extern PyTypeObject PyBobLearnEMPLDABase_Type; -bool init_BobLearnEMPLDABase(PyObject* module); -int PyBobLearnEMPLDABase_Check(PyObject* o); - - -// PLDAMachine -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::PLDAMachine> cxx; -} PyBobLearnEMPLDAMachineObject; - -extern PyTypeObject PyBobLearnEMPLDAMachine_Type; -bool init_BobLearnEMPLDAMachine(PyObject* module); -int PyBobLearnEMPLDAMachine_Check(PyObject* o); - - -// PLDATrainer -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::PLDATrainer> cxx; -} PyBobLearnEMPLDATrainerObject; - -extern PyTypeObject PyBobLearnEMPLDATrainer_Type; -bool init_BobLearnEMPLDATrainer(PyObject* module); -int PyBobLearnEMPLDATrainer_Check(PyObject* o); - - - -// EMPCATrainer -typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::learn::em::EMPCATrainer> cxx; -} PyBobLearnEMEMPCATrainerObject; - -extern PyTypeObject PyBobLearnEMEMPCATrainer_Type; -bool init_BobLearnEMEMPCATrainer(PyObject* module); -int PyBobLearnEMEMPCATrainer_Check(PyObject* o); - - - -//Linear scoring -PyObject* PyBobLearnEM_linear_scoring(PyObject*, PyObject* args, PyObject* kwargs); -extern bob::extension::FunctionDoc linear_scoring1; -extern bob::extension::FunctionDoc linear_scoring2; -extern bob::extension::FunctionDoc linear_scoring3; - -#endif // BOB_LEARN_EM_MAIN_H diff --git a/bob/learn/em/map_gmm_trainer.cpp b/bob/learn/em/map_gmm_trainer.cpp deleted file mode 100644 index 5616892a52878ff8077b458bb80ee46d820e84b9..0000000000000000000000000000000000000000 --- a/bob/learn/em/map_gmm_trainer.cpp +++ /dev/null @@ -1,508 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Web 23 Jan 16:42:00 2015 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static inline bool f(PyObject* o){return o != 0 && PyObject_IsTrue(o) > 0;} /* converts PyObject to bool and returns false if object is NULL */ - -static auto MAP_GMMTrainer_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".MAP_GMMTrainer", - "This class implements the maximum a posteriori (:ref:`MAP <map>`) M-step of the expectation-maximization algorithm for a GMM Machine. The prior parameters are encoded in the form of a GMM (e.g. a universal background model). The EM algorithm thus performs GMM adaptation." -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Creates a MAP_GMMTrainer", - "Additionally to the copy constructor, there are two different ways to call this constructor, one using the ``relevance_factor`` and one using the ``alpha``, both which have the same signature. " - "Hence, the only way to differentiate the two functions is by using keyword arguments.", - true - ) - - .add_prototype("prior_gmm, relevance_factor, [update_means], [update_variances], [update_weights], [mean_var_update_responsibilities_threshold]","") - .add_prototype("prior_gmm, alpha, [update_means], [update_variances], [update_weights], [mean_var_update_responsibilities_threshold]","") - .add_prototype("other","") - - .add_parameter("prior_gmm", ":py:class:`bob.learn.em.GMMMachine`", "The prior GMM to be adapted (Universal Background Model UBM).") - .add_parameter("relevance_factor", "float", "If set the Reynolds Adaptation procedure will be applied. See Eq (14) from [Reynolds2000]_") - .add_parameter("alpha", "float", "Set directly the alpha parameter (Eq (14) from [Reynolds2000]_), ignoring zeroth order statistics as a weighting factor.") - - .add_parameter("update_means", "bool", "[Default: ``True``] Update means on each iteration") - .add_parameter("update_variances", "bool", "[Default: ``True``] Update variances on each iteration") - .add_parameter("update_weights", "bool", "[Default: ``True``] Update weights on each iteration") - .add_parameter("mean_var_update_responsibilities_threshold", "float", "[Default: min_float] Threshold over the responsibilities of the Gaussians Equations 9.24, 9.25 of Bishop, `Pattern recognition and machine learning`, 2006 require a division by the responsibilities, which might be equal to zero because of numerical issue. This threshold is used to avoid such divisions.") - - .add_parameter("other", ":py:class:`bob.learn.em.MAP_GMMTrainer`", "A MAP_GMMTrainer object to be copied.") -); - - -static int PyBobLearnEMMAPGMMTrainer_init_copy(PyBobLearnEMMAPGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = MAP_GMMTrainer_doc.kwlist(2); - PyBobLearnEMMAPGMMTrainerObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMMAPGMMTrainer_Type, &o)){ - MAP_GMMTrainer_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::MAP_GMMTrainer(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMMAPGMMTrainer_init_base_trainer(PyBobLearnEMMAPGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist1 = MAP_GMMTrainer_doc.kwlist(0); - char** kwlist2 = MAP_GMMTrainer_doc.kwlist(1); - - PyBobLearnEMGMMMachineObject* gmm_machine; - bool reynolds_adaptation = false; - double alpha = 0.5; - double relevance_factor = 4.0; - double aux = 0; - - PyObject* update_means = Py_True; - PyObject* update_variances = Py_False; - PyObject* update_weights = Py_False; - double mean_var_update_responsibilities_threshold = std::numeric_limits<double>::epsilon(); - - PyObject* keyword_relevance_factor = Py_BuildValue("s", kwlist1[1]); - PyObject* keyword_alpha = Py_BuildValue("s", kwlist2[1]); - - auto keyword_relevance_factor_ = make_safe(keyword_relevance_factor); - auto keyword_alpha_ = make_safe(keyword_alpha); - - //Here we have to select which keyword argument to read - if (kwargs && PyDict_Contains(kwargs, keyword_relevance_factor)){ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!d|O!O!O!d", kwlist1, - &PyBobLearnEMGMMMachine_Type, &gmm_machine, - &aux, - &PyBool_Type, &update_means, - &PyBool_Type, &update_variances, - &PyBool_Type, &update_weights, - &mean_var_update_responsibilities_threshold)) - return -1; - reynolds_adaptation = true; - } else if (kwargs && PyDict_Contains(kwargs, keyword_alpha)){ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!d|O!O!O!d", kwlist2, - &PyBobLearnEMGMMMachine_Type, &gmm_machine, - &aux, - &PyBool_Type, &update_means, - &PyBool_Type, &update_variances, - &PyBool_Type, &update_weights, - &mean_var_update_responsibilities_threshold)) - return -1; - reynolds_adaptation = false; - } else { - PyErr_Format(PyExc_RuntimeError, "%s. One of the two keyword arguments '%s' or '%s' must be present.", Py_TYPE(self)->tp_name, kwlist1[1], kwlist2[1]); - MAP_GMMTrainer_doc.print_usage(); - return -1; - } - - if (reynolds_adaptation) - relevance_factor = aux; - else - alpha = aux; - - - self->cxx.reset(new bob::learn::em::MAP_GMMTrainer(f(update_means), f(update_variances), f(update_weights), - mean_var_update_responsibilities_threshold, - reynolds_adaptation, relevance_factor, alpha, gmm_machine->cxx)); - return 0; - -} - - - -static int PyBobLearnEMMAPGMMTrainer_init(PyBobLearnEMMAPGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - if (nargs==0){ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s (see help)", Py_TYPE(self)->tp_name); - MAP_GMMTrainer_doc.print_usage(); - return -1; - } - - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is GMMBaseTrainer object - if(PyBobLearnEMMAPGMMTrainer_Check(arg)) - return PyBobLearnEMMAPGMMTrainer_init_copy(self, args, kwargs); - else{ - return PyBobLearnEMMAPGMMTrainer_init_base_trainer(self, args, kwargs); - } - - BOB_CATCH_MEMBER("cannot create MAP_GMMTrainer", -1) - return 0; -} - - -static void PyBobLearnEMMAPGMMTrainer_delete(PyBobLearnEMMAPGMMTrainerObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - - -int PyBobLearnEMMAPGMMTrainer_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMMAPGMMTrainer_Type)); -} - - -static PyObject* PyBobLearnEMMAPGMMTrainer_RichCompare(PyBobLearnEMMAPGMMTrainerObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMMAPGMMTrainer_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMMAPGMMTrainerObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare MAP_GMMTrainer objects", 0) -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** relevance_factor *****/ -static auto relevance_factor = bob::extension::VariableDoc( - "relevance_factor", - "float", - "If set the reynolds_adaptation parameters, will apply the Reynolds Adaptation Factor. See Eq (14) from [Reynolds2000]_", - "" -); -PyObject* PyBobLearnEMMAPGMMTrainer_getRelevanceFactor(PyBobLearnEMMAPGMMTrainerObject* self, void*){ - BOB_TRY - return Py_BuildValue("d",self->cxx->getRelevanceFactor()); - BOB_CATCH_MEMBER("relevance_factor could not be read", 0) -} -int PyBobLearnEMMAPGMMTrainer_setRelevanceFactor(PyBobLearnEMMAPGMMTrainerObject* self, PyObject* value, void*){ - BOB_TRY - - if(!PyBob_NumberCheck(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a float", Py_TYPE(self)->tp_name, relevance_factor.name()); - return -1; - } - - self->cxx->setRelevanceFactor(PyFloat_AS_DOUBLE(value)); - return 0; - BOB_CATCH_MEMBER("relevance_factor could not be set", -1) -} - - -/***** alpha *****/ -static auto alpha = bob::extension::VariableDoc( - "alpha", - "float", - "Set directly the alpha parameter (Eq (14) from [Reynolds2000]_), ignoring zeroth order statistics as a weighting factor.", - "" -); -PyObject* PyBobLearnEMMAPGMMTrainer_getAlpha(PyBobLearnEMMAPGMMTrainerObject* self, void*){ - BOB_TRY - return Py_BuildValue("d",self->cxx->getAlpha()); - BOB_CATCH_MEMBER("alpha could not be read", 0) -} -int PyBobLearnEMMAPGMMTrainer_setAlpha(PyBobLearnEMMAPGMMTrainerObject* self, PyObject* value, void*){ - BOB_TRY - - if(!PyBob_NumberCheck(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a float", Py_TYPE(self)->tp_name, alpha.name()); - return -1; - } - - self->cxx->setAlpha(PyFloat_AS_DOUBLE(value)); - return 0; - BOB_CATCH_MEMBER("alpha could not be set", -1) -} - - -static auto gmm_statistics = bob::extension::VariableDoc( - "gmm_statistics", - ":py:class:`GMMStats`", - "The GMM statistics that were used internally in the E- and M-steps", - "Setting and getting the internal GMM statistics might be useful to parallelize the GMM training." -); -PyObject* PyBobLearnEMMAPGMMTrainer_get_gmm_statistics(PyBobLearnEMMAPGMMTrainerObject* self, void*){ - BOB_TRY - PyBobLearnEMGMMStatsObject* stats = (PyBobLearnEMGMMStatsObject*)PyBobLearnEMGMMStats_Type.tp_alloc(&PyBobLearnEMGMMStats_Type, 0); - stats->cxx = self->cxx->base_trainer().getGMMStats(); - return Py_BuildValue("N", stats); - BOB_CATCH_MEMBER("gmm_statistics could not be read", 0) -} -int PyBobLearnEMMAPGMMTrainer_set_gmm_statistics(PyBobLearnEMMAPGMMTrainerObject* self, PyObject* value, void*){ - BOB_TRY - if (!PyBobLearnEMGMMStats_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a GMMStats object", Py_TYPE(self)->tp_name, gmm_statistics.name()); - return -1; - } - self->cxx->base_trainer().setGMMStats(reinterpret_cast<PyBobLearnEMGMMStatsObject*>(value)->cxx); - return 0; - BOB_CATCH_MEMBER("gmm_statistics could not be set", -1) -} - - -static PyGetSetDef PyBobLearnEMMAPGMMTrainer_getseters[] = { - { - alpha.name(), - (getter)PyBobLearnEMMAPGMMTrainer_getAlpha, - (setter)PyBobLearnEMMAPGMMTrainer_setAlpha, - alpha.doc(), - 0 - }, - { - relevance_factor.name(), - (getter)PyBobLearnEMMAPGMMTrainer_getRelevanceFactor, - (setter)PyBobLearnEMMAPGMMTrainer_setRelevanceFactor, - relevance_factor.doc(), - 0 - }, - { - gmm_statistics.name(), - (getter)PyBobLearnEMMAPGMMTrainer_get_gmm_statistics, - (setter)PyBobLearnEMMAPGMMTrainer_set_gmm_statistics, - gmm_statistics.doc(), - 0 - }, - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - -/*** initialize ***/ -static auto initialize = bob::extension::FunctionDoc( - "initialize", - "Initialization before the EM steps", - "", - true -) -.add_prototype("gmm_machine, [data], [rng]") -.add_parameter("gmm_machine", ":py:class:`bob.learn.em.GMMMachine`", "GMMMachine Object") -.add_parameter("data", "object", "Ignored.") -.add_parameter("rng", "object", "Ignored."); -static PyObject* PyBobLearnEMMAPGMMTrainer_initialize(PyBobLearnEMMAPGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = initialize.kwlist(0); - - PyBobLearnEMGMMMachineObject* gmm_machine = 0; - PyObject* data; - PyObject* rng; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", kwlist, &PyBobLearnEMGMMMachine_Type, &gmm_machine, - &data, &rng)) return 0; - - self->cxx->initialize(*gmm_machine->cxx); - - BOB_CATCH_MEMBER("cannot perform the initialize method", 0) - - Py_RETURN_NONE; -} - - -/*** e_step ***/ -static auto e_step = bob::extension::FunctionDoc( - "e_step", - "Calculates and saves statistics across the dataset and saves these as :py:attr:`gmm_statistics`. ", - - "Calculates the average log likelihood of the observations given the GMM," - "and returns this in average_log_likelihood." - "The statistics, :py:attr:`gmm_statistics`, will be used in the :py:meth:`m_step` that follows.", - - true -) -.add_prototype("gmm_machine,data") -.add_parameter("gmm_machine", ":py:class:`bob.learn.em.GMMMachine`", "GMMMachine Object") -.add_parameter("data", "array_like <float, 2D>", "Input data"); -static PyObject* PyBobLearnEMMAPGMMTrainer_e_step(PyBobLearnEMMAPGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = e_step.kwlist(0); - - PyBobLearnEMGMMMachineObject* gmm_machine; - PyBlitzArrayObject* data = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMMachine_Type, &gmm_machine, - &PyBlitzArray_Converter, &data)) return 0; - auto data_ = make_safe(data); - - - // perform check on the input - if (data->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, e_step.name()); - return 0; - } - - if (data->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, e_step.name()); - return 0; - } - - if (data->shape[1] != (Py_ssize_t)gmm_machine->cxx->getNInputs() ) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, gmm_machine->cxx->getNInputs(), data->shape[1], e_step.name()); - return 0; - } - - auto state = PyEval_SaveThread(); - self->cxx->eStep(*gmm_machine->cxx, *PyBlitzArrayCxx_AsBlitz<double,2>(data)); - PyEval_RestoreThread(state); - - BOB_CATCH_MEMBER("cannot perform the e_step method", 0) - - Py_RETURN_NONE; -} - - -/*** m_step ***/ -static auto m_step = bob::extension::FunctionDoc( - "m_step", - - "Performs a maximum a posteriori (MAP) update of the GMM parameters using the accumulated statistics in :py:attr:`gmm_statistics` and the parameters of the prior model", - "", - true -) -.add_prototype("gmm_machine, [data]") -.add_parameter("gmm_machine", ":py:class:`bob.learn.em.GMMMachine`", "GMMMachine Object") -.add_parameter("data", "object", "Ignored."); -static PyObject* PyBobLearnEMMAPGMMTrainer_m_step(PyBobLearnEMMAPGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = m_step.kwlist(0); - - PyBobLearnEMGMMMachineObject* gmm_machine; - PyObject* data; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", kwlist, &PyBobLearnEMGMMMachine_Type, &gmm_machine, - &data)) return 0; - - self->cxx->mStep(*gmm_machine->cxx); - - BOB_CATCH_MEMBER("cannot perform the m_step method", 0) - - Py_RETURN_NONE; -} - - -/*** computeLikelihood ***/ -static auto compute_likelihood = bob::extension::FunctionDoc( - "compute_likelihood", - "This functions returns the average min (Square Euclidean) distance (average distance to the closest mean)", - 0, - true -) -.add_prototype("gmm_machine") -.add_parameter("gmm_machine", ":py:class:`bob.learn.em.GMMMachine`", "GMMMachine Object"); -static PyObject* PyBobLearnEMMAPGMMTrainer_compute_likelihood(PyBobLearnEMMAPGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = compute_likelihood.kwlist(0); - - PyBobLearnEMGMMMachineObject* gmm_machine; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMGMMMachine_Type, &gmm_machine)) return 0; - - double value = self->cxx->computeLikelihood(*gmm_machine->cxx); - return Py_BuildValue("d", value); - - BOB_CATCH_MEMBER("cannot perform the computeLikelihood method", 0) -} - - - -static PyMethodDef PyBobLearnEMMAPGMMTrainer_methods[] = { - { - initialize.name(), - (PyCFunction)PyBobLearnEMMAPGMMTrainer_initialize, - METH_VARARGS|METH_KEYWORDS, - initialize.doc() - }, - { - e_step.name(), - (PyCFunction)PyBobLearnEMMAPGMMTrainer_e_step, - METH_VARARGS|METH_KEYWORDS, - e_step.doc() - }, - { - m_step.name(), - (PyCFunction)PyBobLearnEMMAPGMMTrainer_m_step, - METH_VARARGS|METH_KEYWORDS, - m_step.doc() - }, - { - compute_likelihood.name(), - (PyCFunction)PyBobLearnEMMAPGMMTrainer_compute_likelihood, - METH_VARARGS|METH_KEYWORDS, - compute_likelihood.doc() - }, - - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMMAPGMMTrainer_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMMAPGMMTrainer(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMMAPGMMTrainer_Type.tp_name = MAP_GMMTrainer_doc.name(); - PyBobLearnEMMAPGMMTrainer_Type.tp_basicsize = sizeof(PyBobLearnEMMAPGMMTrainerObject); - PyBobLearnEMMAPGMMTrainer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;//Enable the class inheritance - PyBobLearnEMMAPGMMTrainer_Type.tp_doc = MAP_GMMTrainer_doc.doc(); - - // set the functions - PyBobLearnEMMAPGMMTrainer_Type.tp_new = PyType_GenericNew; - PyBobLearnEMMAPGMMTrainer_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMMAPGMMTrainer_init); - PyBobLearnEMMAPGMMTrainer_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMMAPGMMTrainer_delete); - PyBobLearnEMMAPGMMTrainer_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMMAPGMMTrainer_RichCompare); - PyBobLearnEMMAPGMMTrainer_Type.tp_methods = PyBobLearnEMMAPGMMTrainer_methods; - PyBobLearnEMMAPGMMTrainer_Type.tp_getset = PyBobLearnEMMAPGMMTrainer_getseters; - PyBobLearnEMMAPGMMTrainer_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMMAPGMMTrainer_compute_likelihood); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMMAPGMMTrainer_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMMAPGMMTrainer_Type); - return PyModule_AddObject(module, "MAP_GMMTrainer", (PyObject*)&PyBobLearnEMMAPGMMTrainer_Type) >= 0; -} diff --git a/bob/learn/em/ml_gmm_trainer.cpp b/bob/learn/em/ml_gmm_trainer.cpp deleted file mode 100644 index 7e7dc488fd7f11903dc32fea1d04030bd5d7c6b7..0000000000000000000000000000000000000000 --- a/bob/learn/em/ml_gmm_trainer.cpp +++ /dev/null @@ -1,393 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Web 22 Jan 16:45:00 2015 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static inline bool f(PyObject* o){return o != 0 && PyObject_IsTrue(o) > 0;} /* converts PyObject to bool and returns false if object is NULL */ - -static auto ML_GMMTrainer_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".ML_GMMTrainer", - "This class implements the maximum likelihood M-step (:ref:`MLE <mle>`) of the expectation-maximisation algorithm for a GMM Machine." -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Creates a ML_GMMTrainer", - "", - true - ) - .add_prototype("update_means, [update_variances], [update_weights], [mean_var_update_responsibilities_threshold]","") - .add_prototype("other","") - - .add_parameter("update_means", "bool", "Update means on each iteration") - .add_parameter("update_variances", "bool", "Update variances on each iteration") - .add_parameter("update_weights", "bool", "Update weights on each iteration") - .add_parameter("mean_var_update_responsibilities_threshold", "float", "Threshold over the responsibilities of the Gaussians Equations 9.24, 9.25 of Bishop, `Pattern recognition and machine learning`, 2006 require a division by the responsibilities, which might be equal to zero because of numerical issue. This threshold is used to avoid such divisions.") - - - .add_parameter("other", ":py:class:`bob.learn.em.ML_GMMTrainer`", "A ML_GMMTrainer object to be copied.") -); - - -static int PyBobLearnEMMLGMMTrainer_init_copy(PyBobLearnEMMLGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = ML_GMMTrainer_doc.kwlist(1); - PyBobLearnEMMLGMMTrainerObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMMLGMMTrainer_Type, &o)){ - ML_GMMTrainer_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::ML_GMMTrainer(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMMLGMMTrainer_init_base_trainer(PyBobLearnEMMLGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = ML_GMMTrainer_doc.kwlist(0); - - PyObject* update_means = Py_True; - PyObject* update_variances = Py_False; - PyObject* update_weights = Py_False; - double mean_var_update_responsibilities_threshold = std::numeric_limits<double>::epsilon(); - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O!O!O!d", kwlist, - &PyBool_Type, &update_means, - &PyBool_Type, &update_variances, - &PyBool_Type, &update_weights, - &mean_var_update_responsibilities_threshold)){ - ML_GMMTrainer_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::ML_GMMTrainer(f(update_means), f(update_variances), f(update_weights), - mean_var_update_responsibilities_threshold)); - return 0; -} - - - -static int PyBobLearnEMMLGMMTrainer_init(PyBobLearnEMMLGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - if (nargs==0) - return PyBobLearnEMMLGMMTrainer_init_base_trainer(self, args, kwargs); - else{ - - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is GMMBaseTrainer object - if (PyBobLearnEMMLGMMTrainer_Check(arg)) - return PyBobLearnEMMLGMMTrainer_init_copy(self, args, kwargs); - else - return PyBobLearnEMMLGMMTrainer_init_base_trainer(self, args, kwargs); - } - BOB_CATCH_MEMBER("cannot create GMMBaseTrainer_init_bool", -1) - return 0; -} - - -static void PyBobLearnEMMLGMMTrainer_delete(PyBobLearnEMMLGMMTrainerObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - - -int PyBobLearnEMMLGMMTrainer_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMMLGMMTrainer_Type)); -} - - -static PyObject* PyBobLearnEMMLGMMTrainer_RichCompare(PyBobLearnEMMLGMMTrainerObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMMLGMMTrainer_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMMLGMMTrainerObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare ML_GMMTrainer objects", 0) -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -static auto gmm_statistics = bob::extension::VariableDoc( - "gmm_statistics", - ":py:class:`GMMStats`", - "The GMM statistics that were used internally in the E- and M-steps", - "Setting and getting the internal GMM statistics might be useful to parallelize the GMM training." -); -PyObject* PyBobLearnEMMLGMMTrainer_get_gmm_statistics(PyBobLearnEMMLGMMTrainerObject* self, void*){ - BOB_TRY - PyBobLearnEMGMMStatsObject* stats = (PyBobLearnEMGMMStatsObject*)PyBobLearnEMGMMStats_Type.tp_alloc(&PyBobLearnEMGMMStats_Type, 0); - stats->cxx = self->cxx->base_trainer().getGMMStats(); - return Py_BuildValue("N", stats); - BOB_CATCH_MEMBER("gmm_statistics could not be read", 0) -} -int PyBobLearnEMMLGMMTrainer_set_gmm_statistics(PyBobLearnEMMLGMMTrainerObject* self, PyObject* value, void*){ - BOB_TRY - if (!PyBobLearnEMGMMStats_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a GMMStats object", Py_TYPE(self)->tp_name, gmm_statistics.name()); - return -1; - } - self->cxx->base_trainer().setGMMStats(reinterpret_cast<PyBobLearnEMGMMStatsObject*>(value)->cxx); - return 0; - BOB_CATCH_MEMBER("gmm_statistics could not be set", -1) -} - - -static PyGetSetDef PyBobLearnEMMLGMMTrainer_getseters[] = { - { - gmm_statistics.name(), - (getter)PyBobLearnEMMLGMMTrainer_get_gmm_statistics, - (setter)PyBobLearnEMMLGMMTrainer_set_gmm_statistics, - gmm_statistics.doc(), - 0 - }, - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - -/*** initialize ***/ -static auto initialize = bob::extension::FunctionDoc( - "initialize", - "Initialization before the EM steps", - "", - true -) -.add_prototype("gmm_machine, [data], [rng]") -.add_parameter("gmm_machine", ":py:class:`bob.learn.em.GMMMachine`", "GMMMachine Object") -.add_parameter("data", "object", "Ignored.") -.add_parameter("rng", "object", "Ignored."); -static PyObject* PyBobLearnEMMLGMMTrainer_initialize(PyBobLearnEMMLGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = initialize.kwlist(0); - PyBobLearnEMGMMMachineObject* gmm_machine = 0; - PyObject* data; - PyObject* rng; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", kwlist, &PyBobLearnEMGMMMachine_Type, &gmm_machine, - &data, &rng)) return 0; - - self->cxx->initialize(*gmm_machine->cxx); - BOB_CATCH_MEMBER("cannot perform the initialize method", 0) - - Py_RETURN_NONE; -} - - -/*** e_step ***/ -static auto e_step = bob::extension::FunctionDoc( - "e_step", - "Calculates and saves statistics across the dataset," - "and saves these as m_ss. ", - - "Calculates the average log likelihood of the observations given the GMM," - "and returns this in average_log_likelihood." - "The statistics, :py:attr:`gmm_statistics`, will be used in the :py:func:`m_step` that follows.", - - true -) -.add_prototype("gmm_machine,data") -.add_parameter("gmm_machine", ":py:class:`bob.learn.em.GMMMachine`", "GMMMachine Object") -.add_parameter("data", "array_like <float, 2D>", "Input data"); -static PyObject* PyBobLearnEMMLGMMTrainer_e_step(PyBobLearnEMMLGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = e_step.kwlist(0); - - PyBobLearnEMGMMMachineObject* gmm_machine; - PyBlitzArrayObject* data = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMMachine_Type, &gmm_machine, - &PyBlitzArray_Converter, &data)) return 0; - auto data_ = make_safe(data); - - // perform check on the input - if (data->type_num != NPY_FLOAT64){ - PyErr_Format(PyExc_TypeError, "`%s' only supports 64-bit float arrays for input array `%s`", Py_TYPE(self)->tp_name, e_step.name()); - return 0; - } - - if (data->ndim != 2){ - PyErr_Format(PyExc_TypeError, "`%s' only processes 2D arrays of float64 for `%s`", Py_TYPE(self)->tp_name, e_step.name()); - return 0; - } - - if (data->shape[1] != (Py_ssize_t)gmm_machine->cxx->getNInputs() ) { - PyErr_Format(PyExc_TypeError, "`%s' 2D `input` array should have the shape [N, %" PY_FORMAT_SIZE_T "d] not [N, %" PY_FORMAT_SIZE_T "d] for `%s`", Py_TYPE(self)->tp_name, gmm_machine->cxx->getNInputs(), data->shape[1], e_step.name()); - return 0; - } - - auto state = PyEval_SaveThread(); - self->cxx->eStep(*gmm_machine->cxx, *PyBlitzArrayCxx_AsBlitz<double,2>(data)); - PyEval_RestoreThread(state); - - BOB_CATCH_MEMBER("cannot perform the e_step method", 0) - - Py_RETURN_NONE; -} - - -/*** m_step ***/ -static auto m_step = bob::extension::FunctionDoc( - "m_step", - "Performs a maximum likelihood (ML) update of the GMM parameters " - "using the accumulated statistics in :py:attr:`gmm_statistics`", - - "See Section 9.2.2 of Bishop, \"Pattern recognition and machine learning\", 2006", - - true -) -.add_prototype("gmm_machine, [data]") -.add_parameter("gmm_machine", ":py:class:`bob.learn.em.GMMMachine`", "GMMMachine Object") -.add_parameter("data", "object", "Ignored."); -static PyObject* PyBobLearnEMMLGMMTrainer_m_step(PyBobLearnEMMLGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = m_step.kwlist(0); - - PyBobLearnEMGMMMachineObject* gmm_machine = 0; - PyObject* data; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O", kwlist, &PyBobLearnEMGMMMachine_Type, &gmm_machine, - &data)) return 0; - - self->cxx->mStep(*gmm_machine->cxx); - - BOB_CATCH_MEMBER("cannot perform the m_step method", 0) - - Py_RETURN_NONE; -} - - -/*** computeLikelihood ***/ -static auto compute_likelihood = bob::extension::FunctionDoc( - "compute_likelihood", - "This functions returns the average min (Square Euclidean) distance (average distance to the closest mean)", - 0, - true -) -.add_prototype("gmm_machine") -.add_parameter("gmm_machine", ":py:class:`bob.learn.em.GMMMachine`", "GMMMachine Object"); -static PyObject* PyBobLearnEMMLGMMTrainer_compute_likelihood(PyBobLearnEMMLGMMTrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = compute_likelihood.kwlist(0); - - PyBobLearnEMGMMMachineObject* gmm_machine; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMGMMMachine_Type, &gmm_machine)) return 0; - - double value = self->cxx->computeLikelihood(*gmm_machine->cxx); - return Py_BuildValue("d", value); - - BOB_CATCH_MEMBER("cannot perform the computeLikelihood method", 0) -} - - - -static PyMethodDef PyBobLearnEMMLGMMTrainer_methods[] = { - { - initialize.name(), - (PyCFunction)PyBobLearnEMMLGMMTrainer_initialize, - METH_VARARGS|METH_KEYWORDS, - initialize.doc() - }, - { - e_step.name(), - (PyCFunction)PyBobLearnEMMLGMMTrainer_e_step, - METH_VARARGS|METH_KEYWORDS, - e_step.doc() - }, - { - m_step.name(), - (PyCFunction)PyBobLearnEMMLGMMTrainer_m_step, - METH_VARARGS|METH_KEYWORDS, - m_step.doc() - }, - { - compute_likelihood.name(), - (PyCFunction)PyBobLearnEMMLGMMTrainer_compute_likelihood, - METH_VARARGS|METH_KEYWORDS, - compute_likelihood.doc() - }, - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMMLGMMTrainer_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMMLGMMTrainer(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMMLGMMTrainer_Type.tp_name = ML_GMMTrainer_doc.name(); - PyBobLearnEMMLGMMTrainer_Type.tp_basicsize = sizeof(PyBobLearnEMMLGMMTrainerObject); - PyBobLearnEMMLGMMTrainer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;//Enable the class inheritance - PyBobLearnEMMLGMMTrainer_Type.tp_doc = ML_GMMTrainer_doc.doc(); - - // set the functions - PyBobLearnEMMLGMMTrainer_Type.tp_new = PyType_GenericNew; - PyBobLearnEMMLGMMTrainer_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMMLGMMTrainer_init); - PyBobLearnEMMLGMMTrainer_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMMLGMMTrainer_delete); - PyBobLearnEMMLGMMTrainer_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMMLGMMTrainer_RichCompare); - PyBobLearnEMMLGMMTrainer_Type.tp_methods = PyBobLearnEMMLGMMTrainer_methods; - PyBobLearnEMMLGMMTrainer_Type.tp_getset = PyBobLearnEMMLGMMTrainer_getseters; - PyBobLearnEMMLGMMTrainer_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMMLGMMTrainer_compute_likelihood); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMMLGMMTrainer_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMMLGMMTrainer_Type); - return PyModule_AddObject(module, "ML_GMMTrainer", (PyObject*)&PyBobLearnEMMLGMMTrainer_Type) >= 0; -} diff --git a/bob/learn/em/plda_base.cpp b/bob/learn/em/plda_base.cpp deleted file mode 100644 index 839dc9c233ab87d0e187c2493ad8d89f8d490474..0000000000000000000000000000000000000000 --- a/bob/learn/em/plda_base.cpp +++ /dev/null @@ -1,1097 +0,0 @@ -/** - * @date Thu Jan 29 15:44:15 2015 +0200 - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static auto PLDABase_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".PLDABase", - - "This class is a container for the :math:`F` (between class variantion matrix), :math:`G` (within class variantion matrix) and :math:`\\Sigma` " - "matrices and the mean vector :math:`\\mu` of a PLDA model. This also" - "precomputes useful matrices to make the model scalable." - "References: [ElShafey2014]_ [PrinceElder2007]_ [LiFu2012]_ ", - "" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - - "Constructor, builds a new PLDABase. :math:`F`, :math:`G` " - "and :math:`\\Sigma` are initialized to the 'eye' matrix (matrix with 1's " - "on the diagonal and 0 outside), and :math:`\\mu` is initialized to 0.", - - "", - true - ) - .add_prototype("dim_d,dim_f,dim_g,variance_threshold","") - .add_prototype("other","") - .add_prototype("hdf5","") - - .add_parameter("dim_d", "int", "Dimensionality of the feature vector.") - .add_parameter("dim_f", "int", "Size of :math:`F` (between class variantion matrix).") - .add_parameter("dim_g", "int", "Size of :math:`G` (within class variantion matrix).") - .add_parameter("variance_threshold", "float", "The smallest possible value of the variance (Ignored if set to 0.)") - - .add_parameter("other", ":py:class:`bob.learn.em.PLDABase`", "A PLDABase object to be copied.") - .add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading") - -); - - -static int PyBobLearnEMPLDABase_init_copy(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = PLDABase_doc.kwlist(1); - PyBobLearnEMPLDABaseObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMPLDABase_Type, &o)){ - PLDABase_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::PLDABase(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMPLDABase_init_hdf5(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = PLDABase_doc.kwlist(2); - - PyBobIoHDF5FileObject* config = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBobIoHDF5File_Converter, &config)){ - PLDABase_doc.print_usage(); - return -1; - } - auto config_ = make_safe(config); - self->cxx.reset(new bob::learn::em::PLDABase(*(config->f))); - - return 0; -} - - -static int PyBobLearnEMPLDABase_init_dim(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = PLDABase_doc.kwlist(0); - - int dim_D, dim_F, dim_G = 1; - double variance_threshold = 0.0; - - //Here we have to select which keyword argument to read - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii|d", kwlist, &dim_D, &dim_F, &dim_G, &variance_threshold)){ - PLDABase_doc.print_usage(); - return -1; - } - - if(dim_D <= 0){ - PyErr_Format(PyExc_TypeError, "dim_D argument must be greater than or equal to one"); - return -1; - } - - if(dim_F <= 0){ - PyErr_Format(PyExc_TypeError, "dim_F argument must be greater than or equal to one"); - return -1; - } - - if(dim_G <= 0){ - PyErr_Format(PyExc_TypeError, "dim_G argument must be greater than or equal to one"); - return -1; - } - - if(variance_threshold < 0){ - PyErr_Format(PyExc_TypeError, "variance_threshold argument must be greater than or equal to zero"); - return -1; - } - - - self->cxx.reset(new bob::learn::em::PLDABase(dim_D, dim_F, dim_G, variance_threshold)); - return 0; -} - -static int PyBobLearnEMPLDABase_init(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - if(nargs==1){ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is Gaussian object - if (PyBobLearnEMPLDABase_Check(arg)) - return PyBobLearnEMPLDABase_init_copy(self, args, kwargs); - // If the constructor input is a HDF5 - else if (PyBobIoHDF5File_Check(arg)) - return PyBobLearnEMPLDABase_init_hdf5(self, args, kwargs); - } - else if((nargs==3)||(nargs==4)) - return PyBobLearnEMPLDABase_init_dim(self, args, kwargs); - else{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires 1, 3 or 4 arguments, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - PLDABase_doc.print_usage(); - return -1; - } - BOB_CATCH_MEMBER("cannot create PLDABase", -1) - return 0; -} - - - -static void PyBobLearnEMPLDABase_delete(PyBobLearnEMPLDABaseObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* PyBobLearnEMPLDABase_RichCompare(PyBobLearnEMPLDABaseObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMPLDABase_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMPLDABaseObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare PLDABase objects", 0) -} - -int PyBobLearnEMPLDABase_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMPLDABase_Type)); -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** shape *****/ -static auto shape = bob::extension::VariableDoc( - "shape", - "(int,int, int)", - "A tuple that represents the dimensionality of the feature vector dim_d, the :math:`F` matrix and the :math:`G` matrix.", - "" -); -PyObject* PyBobLearnEMPLDABase_getShape(PyBobLearnEMPLDABaseObject* self, void*) { - BOB_TRY - return Py_BuildValue("(i,i,i)", self->cxx->getDimD(), self->cxx->getDimF(), self->cxx->getDimG()); - BOB_CATCH_MEMBER("shape could not be read", 0) -} - - -/***** F *****/ -static auto F = bob::extension::VariableDoc( - "f", - "array_like <float, 2D>", - "Returns the :math:`F` matrix (between class variantion matrix)", - "" -); -PyObject* PyBobLearnEMPLDABase_getF(PyBobLearnEMPLDABaseObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getF()); - BOB_CATCH_MEMBER("`f` could not be read", 0) -} -int PyBobLearnEMPLDABase_setF(PyBobLearnEMPLDABaseObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, F.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(o, "f"); - if (!b) return -1; - self->cxx->setF(*b); - return 0; - BOB_CATCH_MEMBER("`f` vector could not be set", -1) -} - -/***** G *****/ -static auto G = bob::extension::VariableDoc( - "g", - "array_like <float, 2D>", - "Returns the :math:`G` matrix (between class variantion matrix)", - "" -); -PyObject* PyBobLearnEMPLDABase_getG(PyBobLearnEMPLDABaseObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getG()); - BOB_CATCH_MEMBER("`g` could not be read", 0) -} -int PyBobLearnEMPLDABase_setG(PyBobLearnEMPLDABaseObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, G.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,2>(o, "g"); - if (!b) return -1; - self->cxx->setG(*b); - return 0; - BOB_CATCH_MEMBER("`g` vector could not be set", -1) -} - - -/***** mu *****/ -static auto mu = bob::extension::VariableDoc( - "mu", - "array_like <float, 1D>", - "Gets the :math:`\\mu` mean vector of the PLDA model", - "" -); -PyObject* PyBobLearnEMPLDABase_getMu(PyBobLearnEMPLDABaseObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getMu()); - BOB_CATCH_MEMBER("`mu` could not be read", 0) -} -int PyBobLearnEMPLDABase_setMu(PyBobLearnEMPLDABaseObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, mu.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(o, "mu"); - if (!b) return -1; - self->cxx->setMu(*b); - return 0; - BOB_CATCH_MEMBER("`mu` vector could not be set", -1) -} - - -/***** __isigma__ *****/ -static auto __isigma__ = bob::extension::VariableDoc( - "__isigma__", - "array_like <float, 1D>", - "Gets the inverse vector/diagonal matrix of :math:`\\Sigma^{-1}`", - "" -); -static PyObject* PyBobLearnEMPLDABase_getISigma(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getISigma()); - BOB_CATCH_MEMBER("__isigma__ could not be read", 0) -} - - -/***** __alpha__ *****/ -static auto __alpha__ = bob::extension::VariableDoc( - "__alpha__", - "array_like <float, 2D>", - "Gets the \f$\alpha\f$ matrix." - ":math:`\\alpha = (Id + G^T \\Sigma^{-1} G)^{-1} = \\mathcal{G}`", - "" -); -static PyObject* PyBobLearnEMPLDABase_getAlpha(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAlpha()); - BOB_CATCH_MEMBER("__alpha__ could not be read", 0) -} - - -/***** __beta__ *****/ -static auto __beta__ = bob::extension::VariableDoc( - "__beta__", - "array_like <float, 2D>", - "Gets the :math:`\\beta` matrix " - ":math:`\\beta = (\\Sigma + G G^T)^{-1} = \\mathcal{S} = \\Sigma^{-1} - \\Sigma^{-1} G \\mathcal{G} G^{T} \\Sigma^{-1}`", - "" -); -static PyObject* PyBobLearnEMPLDABase_getBeta(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getBeta()); - BOB_CATCH_MEMBER("__beta__ could not be read", 0) -} - - -/***** __ft_beta__ *****/ -static auto __ft_beta__ = bob::extension::VariableDoc( - "__ft_beta__", - "array_like <float, 2D>", - "Gets the :math:`F^T \\beta' matrix", - "" -); -static PyObject* PyBobLearnEMPLDABase_getFtBeta(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getFtBeta()); - BOB_CATCH_MEMBER("__ft_beta__ could not be read", 0) -} - - -/***** __gt_i_sigma__ *****/ -static auto __gt_i_sigma__ = bob::extension::VariableDoc( - "__gt_i_sigma__", - "array_like <float, 2D>", - "Gets the :math:`G^T \\Sigma^{-1}` matrix", - "" -); -static PyObject* PyBobLearnEMPLDABase_getGtISigma(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getGtISigma()); - BOB_CATCH_MEMBER("__gt_i_sigma__ could not be read", 0) -} - - -/***** __logdet_alpha__ *****/ -static auto __logdet_alpha__ = bob::extension::VariableDoc( - "__logdet_alpha__", - "float", - "Gets :math:`\\log(\\det(\\alpha))`", - "" -); -static PyObject* PyBobLearnEMPLDABase_getLogDetAlpha(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return Py_BuildValue("d",self->cxx->getLogDetAlpha()); - BOB_CATCH_MEMBER("__logdet_alpha__ could not be read", 0) -} - -/***** __logdet_sigma__ *****/ -static auto __logdet_sigma__ = bob::extension::VariableDoc( - "__logdet_sigma__", - "float", - "Gets :math:`\\log(\\det(\\Sigma))`", - "" -); -static PyObject* PyBobLearnEMPLDABase_getLogDetSigma(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return Py_BuildValue("d",self->cxx->getLogDetSigma()); - BOB_CATCH_MEMBER("__logdet_sigma__ could not be read", 0) -} - - -/***** variance_threshold *****/ -static auto variance_threshold = bob::extension::VariableDoc( - "variance_threshold", - "float", - "", - "" -); -static PyObject* PyBobLearnEMPLDABase_getVarianceThreshold(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return Py_BuildValue("d",self->cxx->getVarianceThreshold()); - BOB_CATCH_MEMBER("variance_threshold could not be read", 0) -} -int PyBobLearnEMPLDABase_setVarianceThreshold(PyBobLearnEMPLDABaseObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyBob_NumberCheck(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects an float", Py_TYPE(self)->tp_name, variance_threshold.name()); - return -1; - } - - self->cxx->setVarianceThreshold(PyFloat_AS_DOUBLE(value)); - BOB_CATCH_MEMBER("variance_threshold could not be set", -1) - return 0; -} - - - - -/***** sigma *****/ -static auto sigma = bob::extension::VariableDoc( - "sigma", - "array_like <float, 1D>", - "Gets the :math:`\\sigma` (diagonal) covariance matrix of the PLDA model", - "" -); -static PyObject* PyBobLearnEMPLDABase_getSigma(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getSigma()); - BOB_CATCH_MEMBER("sigma could not be read", 0) -} -int PyBobLearnEMPLDABase_setSigma(PyBobLearnEMPLDABaseObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, sigma.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(o, "sigma"); - if (!b) return -1; - self->cxx->setSigma(*b); - return 0; - BOB_CATCH_MEMBER("`sigma` vector could not be set", -1) -} - - -static PyGetSetDef PyBobLearnEMPLDABase_getseters[] = { - { - shape.name(), - (getter)PyBobLearnEMPLDABase_getShape, - 0, - shape.doc(), - 0 - }, - { - F.name(), - (getter)PyBobLearnEMPLDABase_getF, - (setter)PyBobLearnEMPLDABase_setF, - F.doc(), - 0 - }, - { - G.name(), - (getter)PyBobLearnEMPLDABase_getG, - (setter)PyBobLearnEMPLDABase_setG, - G.doc(), - 0 - }, - { - mu.name(), - (getter)PyBobLearnEMPLDABase_getMu, - (setter)PyBobLearnEMPLDABase_setMu, - mu.doc(), - 0 - }, - { - __isigma__.name(), - (getter)PyBobLearnEMPLDABase_getISigma, - 0, - __isigma__.doc(), - 0 - }, - { - __alpha__.name(), - (getter)PyBobLearnEMPLDABase_getAlpha, - 0, - __alpha__.doc(), - 0 - }, - { - __beta__.name(), - (getter)PyBobLearnEMPLDABase_getBeta, - 0, - __beta__.doc(), - 0 - }, - { - __ft_beta__.name(), - (getter)PyBobLearnEMPLDABase_getFtBeta, - 0, - __ft_beta__.doc(), - 0 - }, - { - __gt_i_sigma__.name(), - (getter)PyBobLearnEMPLDABase_getGtISigma, - 0, - __gt_i_sigma__.doc(), - 0 - }, - { - __logdet_alpha__.name(), - (getter)PyBobLearnEMPLDABase_getLogDetAlpha, - 0, - __logdet_alpha__.doc(), - 0 - }, - { - __logdet_sigma__.name(), - (getter)PyBobLearnEMPLDABase_getLogDetSigma, - 0, - __logdet_sigma__.doc(), - 0 - }, - { - sigma.name(), - (getter)PyBobLearnEMPLDABase_getSigma, - (setter)PyBobLearnEMPLDABase_setSigma, - sigma.doc(), - 0 - }, - { - variance_threshold.name(), - (getter)PyBobLearnEMPLDABase_getVarianceThreshold, - (setter)PyBobLearnEMPLDABase_setVarianceThreshold, - variance_threshold.doc(), - 0 - }, - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - - -/*** save ***/ -static auto save = bob::extension::FunctionDoc( - "save", - "Save the configuration of the PLDABase to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for writing"); -static PyObject* PyBobLearnEMPLDABase_Save(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - // get list of arguments - char** kwlist = save.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->save(*hdf5->f); - - BOB_CATCH_MEMBER("cannot save the data", 0) - Py_RETURN_NONE; -} - -/*** load ***/ -static auto load = bob::extension::FunctionDoc( - "load", - "Load the configuration of the PLDABase to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading"); -static PyObject* PyBobLearnEMPLDABase_Load(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = load.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->load(*hdf5->f); - - BOB_CATCH_MEMBER("cannot load the data", 0) - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this PLDABase with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` " - "and any other values internal to this machine." -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.PLDABase`", "A PLDABase object to be compared.") -.add_parameter("r_epsilon", "float", "Relative precision.") -.add_parameter("a_epsilon", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMPLDABase_IsSimilarTo(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - //PyObject* other = 0; - PyBobLearnEMPLDABaseObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMPLDABase_Type, &other, - &r_epsilon, &a_epsilon)){ - - is_similar_to.print_usage(); - return 0; - } - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - -/*** resize ***/ -static auto resize = bob::extension::FunctionDoc( - "resize", - "Resizes the dimensionality of the PLDA model. Paramaters :math:`\\mu`, :math:`F`, :math:`G` and :math:`\\Sigma` are reinitialized.", - 0, - true -) -.add_prototype("dim_d,dim_f,dim_g") -.add_parameter("dim_d", "int", "Dimensionality of the feature vector.") -.add_parameter("dim_f", "int", "Size of :math:`F` (between class variantion matrix).") -.add_parameter("dim_g", "int", "Size of :math:`G` (within class variantion matrix)."); -static PyObject* PyBobLearnEMPLDABase_resize(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = resize.kwlist(0); - - int dim_D, dim_F, dim_G = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iii", kwlist, &dim_D, &dim_F, &dim_G)) return 0; - - if(dim_D <= 0){ - PyErr_Format(PyExc_TypeError, "dim_d argument must be greater than or equal to one"); - Py_RETURN_NONE; - } - - if(dim_F <= 0){ - PyErr_Format(PyExc_TypeError, "dim_f argument must be greater than or equal to one"); - Py_RETURN_NONE; - } - - if(dim_G <= 0){ - PyErr_Format(PyExc_TypeError, "dim_g argument must be greater than or equal to one"); - Py_RETURN_NONE; - } - - self->cxx->resize(dim_D, dim_F, dim_G); - - BOB_CATCH_MEMBER("cannot perform the resize method", 0) - - Py_RETURN_NONE; -} - - -/***** get_gamma *****/ -static auto get_gamma = bob::extension::FunctionDoc( - "get_gamma", - "Gets the :math:`\\gamma_a` matrix for a given :math:`a` (number of samples). " - ":math:`\\gamma_{a}=(Id + a F^T \\beta F)^{-1} = \\mathcal{F}_{a}`", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","array_like <float, 2D>","Get the :math:`\\gamma` matrix"); -static PyObject* PyBobLearnEMPLDABase_getGamma(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_gamma.kwlist(0); - - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getGamma(i)); - BOB_CATCH_MEMBER("`get_gamma` could not be read", 0) -} - - -/***** has_gamma *****/ -static auto has_gamma = bob::extension::FunctionDoc( - "has_gamma", - "Tells if the :math:`\\gamma_a` matrix for a given a (number of samples) exists. " - ":math:`\\gamma_a=(Id + aF^T \\beta F)^{-1}`", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","bool",""); -static PyObject* PyBobLearnEMPLDABase_hasGamma(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = has_gamma.kwlist(0); - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - if(self->cxx->hasGamma(i)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; - BOB_CATCH_MEMBER("`has_gamma` could not be read", 0) -} - - -/***** compute_gamma *****/ -static auto compute_gamma = bob::extension::FunctionDoc( - "compute_gamma", - "Tells if the :math:`\\gamma_a` matrix for a given a (number of samples) exists." - " :math:`\\gamma_a=(Id + a F^T \\beta F)^{-1}`", - 0, - true -) -.add_prototype("a,res") -.add_parameter("a", "int", "Index") -.add_parameter("res", "array_like <float, 2D>", "Input data"); -static PyObject* PyBobLearnEMPLDABase_computeGamma(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = compute_gamma.kwlist(0); - int i = 0; - PyBlitzArrayObject* res = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO&", kwlist, &i, &PyBlitzArray_Converter, &res)) return 0; - - auto res_ = make_safe(res); - - self->cxx->computeGamma(i,*PyBlitzArrayCxx_AsBlitz<double,2>(res)); - Py_RETURN_NONE; - BOB_CATCH_MEMBER("`compute_gamma` could not be read", 0) -} - -/***** get_add_gamma *****/ -static auto get_add_gamma = bob::extension::FunctionDoc( - "get_add_gamma", - "Gets the :math:`gamma_a` matrix for a given :math:`f_a` (number of samples)." - " :math:`\\gamma_a=(Id + a F^T \\beta F)^{-1} =\\mathcal{F}_{a}`." - "Tries to find it from the base machine and then from this machine.", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","array_like <float, 2D>",""); -static PyObject* PyBobLearnEMPLDABase_getAddGamma(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_add_gamma.kwlist(0); - - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAddGamma(i)); - BOB_CATCH_MEMBER("`get_add_gamma` could not be read", 0) -} - - -/***** has_log_like_const_term *****/ -static auto has_log_like_const_term = bob::extension::FunctionDoc( - "has_log_like_const_term", - "Tells if the log likelihood constant term for a given :math:`a` (number of samples) exists in this machine (does not check the base machine). " - ":math:`l_{a}=\\frac{a}{2} ( -D log(2\\pi) -log|\\Sigma| +log|\\alpha| +log|\\gamma_a|)`", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","bool",""); -static PyObject* PyBobLearnEMPLDABase_hasLogLikeConstTerm(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = has_log_like_const_term.kwlist(0); - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - if(self->cxx->hasLogLikeConstTerm(i)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; - BOB_CATCH_MEMBER("`has_log_like_const_term` could not be read", 0) -} - - -/***** compute_log_like_const_term" *****/ -static auto compute_log_like_const_term = bob::extension::FunctionDoc( - "compute_log_like_const_term", - "Computes the log likelihood constant term for a given :math:`a` (number of samples), given the provided :math:`\\gamma_a` matrix. " - ":math:`l_{a} = \\frac{a}{2} ( -D log(2\\pi) -log|\\Sigma| +log|\\alpha| +log|\\gamma_a|)`", - - 0, - true -) -.add_prototype("a,res") -.add_parameter("a", "int", "Index") -.add_parameter("res", "array_like <float, 2D>", "Input data"); -static PyObject* PyBobLearnEMPLDABase_computeLogLikeConstTerm(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = compute_log_like_const_term.kwlist(0); - int i = 0; - PyBlitzArrayObject* res = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO&", kwlist, &i, &PyBlitzArray_Converter, &res)) return 0; - - auto res_ = make_safe(res); - - self->cxx->computeLogLikeConstTerm(i,*PyBlitzArrayCxx_AsBlitz<double,2>(res)); - Py_RETURN_NONE; - BOB_CATCH_MEMBER("`compute_gamma` could not be read", 0) -} - - -/***** get_add_log_like_const_term *****/ -static auto get_add_log_like_const_term = bob::extension::FunctionDoc( - "get_add_log_like_const_term", - - "Gets the log likelihood constant term for a given :math:`a` (number of samples). " - ":math:`l_{a} = \\frac{a}{2} ( -D log(2\\pi) -log|\\Sigma| +log|\\alpha| +log|\\gamma_a|)`", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","float",""); -static PyObject* PyBobLearnEMPLDABase_getAddLogLikeConstTerm(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_add_log_like_const_term.kwlist(0); - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - return Py_BuildValue("d",self->cxx->getAddLogLikeConstTerm(i)); - - BOB_CATCH_MEMBER("`get_add_log_like_const_term` could not be read", 0) -} - - -/***** get_log_like_const_term *****/ -static auto get_log_like_const_term = bob::extension::FunctionDoc( - "get_log_like_const_term", - "Gets the log likelihood constant term for a given :math:`a` (number of samples). " - ":math:`l_{a}=\\frac{a}{2} ( -D log(2\\pi) -log|\\Sigma| +log|\\alpha| +log|\\gamma_a|)`", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","float",""); -static PyObject* PyBobLearnEMPLDABase_getLogLikeConstTerm(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_log_like_const_term.kwlist(0); - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - return Py_BuildValue("d",self->cxx->getLogLikeConstTerm(i)); - - BOB_CATCH_MEMBER("`get_log_like_const_term` could not be read", 0) -} - -/***** clear_maps *****/ -static auto clear_maps = bob::extension::FunctionDoc( - "clear_maps", - "Clears the maps (:math:`\\gamma_a` and loglike_constterm_a).", - 0, - true -) -.add_prototype(""); -static PyObject* PyBobLearnEMPLDABase_clearMaps(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - self->cxx->clearMaps(); - Py_RETURN_NONE; - - BOB_CATCH_MEMBER("`clear_maps` could not be read", 0) -} - - -/***** compute_log_likelihood_point_estimate *****/ -static auto compute_log_likelihood_point_estimate = bob::extension::FunctionDoc( - "compute_log_likelihood_point_estimate", - "Gets the log-likelihood of an observation, given the current model and the latent variables (point estimate)." - "This will basically compute :math:`p(x_{ij} | h_{i}, w_{ij}, \\Theta)`, given by " - ":math:`\\mathcal{N}(x_{ij}|[\\mu + F h_{i} + G w_{ij} + \\epsilon_{ij}, \\Sigma])`, which is in logarithm, " - ":math:`\\frac{D}{2} log(2\\pi) -\\frac{1}{2} log(det(\\Sigma)) -\\frac{1}{2} {(x_{ij}-(\\mu+F h_{i}+G w_{ij}))^{T}\\Sigma^{-1}(x_{ij}-(\\mu+F h_{i}+G w_{ij}))}`", - 0, - true -) -.add_prototype("xij,hi,wij","output") -.add_parameter("xij", "array_like <float, 1D>", "") -.add_parameter("hi", "array_like <float, 1D>", "") -.add_parameter("wij", "array_like <float, 1D>", "") -.add_return("output", "float", ""); -static PyObject* PyBobLearnEMPLDABase_computeLogLikelihoodPointEstimate(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = compute_log_likelihood_point_estimate.kwlist(0); - PyBlitzArrayObject* xij, *hi, *wij; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&O&", kwlist, &PyBlitzArray_Converter, &xij, - &PyBlitzArray_Converter, &hi, - &PyBlitzArray_Converter, &wij)) return 0; - - auto xij_ = make_safe(xij); - auto hi_ = make_safe(hi); - auto wij_ = make_safe(wij); - - return Py_BuildValue("d", self->cxx->computeLogLikelihoodPointEstimate(*PyBlitzArrayCxx_AsBlitz<double,1>(xij), *PyBlitzArrayCxx_AsBlitz<double,1>(hi), *PyBlitzArrayCxx_AsBlitz<double,1>(wij))); - - BOB_CATCH_MEMBER("`compute_log_likelihood_point_estimate` could not be read", 0) -} - -/***** __precompute__ *****/ -static auto __precompute__ = bob::extension::FunctionDoc( - "__precompute__", - "Precomputes useful values for the log likelihood " - ":math:`\\log(\\det(\\alpha))` and :math:`\\log(\\det(\\Sigma))`.", - 0, - true -); -static PyObject* PyBobLearnEMPLDABase_precompute(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - self->cxx->precompute(); - Py_RETURN_NONE; - - BOB_CATCH_MEMBER("`precompute` could not be read", 0) -} - - -/***** __precompute_log_like__ *****/ -static auto __precompute_log_like__ = bob::extension::FunctionDoc( - "__precompute_log_like__", - - "Precomputes useful values for the log likelihood " - ":math:`\\log(\\det(\\alpha))` and :math:`\\log(\\det(\\Sigma))`.", - - 0, - true -); -static PyObject* PyBobLearnEMPLDABase_precomputeLogLike(PyBobLearnEMPLDABaseObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - self->cxx->precomputeLogLike(); - Py_RETURN_NONE; - - BOB_CATCH_MEMBER("`__precompute_log_like__` could not be read", 0) -} - - -static PyMethodDef PyBobLearnEMPLDABase_methods[] = { - { - save.name(), - (PyCFunction)PyBobLearnEMPLDABase_Save, - METH_VARARGS|METH_KEYWORDS, - save.doc() - }, - { - load.name(), - (PyCFunction)PyBobLearnEMPLDABase_Load, - METH_VARARGS|METH_KEYWORDS, - load.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMPLDABase_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - { - resize.name(), - (PyCFunction)PyBobLearnEMPLDABase_resize, - METH_VARARGS|METH_KEYWORDS, - resize.doc() - }, - { - get_gamma.name(), - (PyCFunction)PyBobLearnEMPLDABase_getGamma, - METH_VARARGS|METH_KEYWORDS, - get_gamma.doc() - }, - { - has_gamma.name(), - (PyCFunction)PyBobLearnEMPLDABase_hasGamma, - METH_VARARGS|METH_KEYWORDS, - has_gamma.doc() - }, - { - compute_gamma.name(), - (PyCFunction)PyBobLearnEMPLDABase_computeGamma, - METH_VARARGS|METH_KEYWORDS, - compute_gamma.doc() - }, - { - get_add_gamma.name(), - (PyCFunction)PyBobLearnEMPLDABase_getAddGamma, - METH_VARARGS|METH_KEYWORDS, - get_add_gamma.doc() - }, - { - has_log_like_const_term.name(), - (PyCFunction)PyBobLearnEMPLDABase_hasLogLikeConstTerm, - METH_VARARGS|METH_KEYWORDS, - has_log_like_const_term.doc() - }, - { - compute_log_like_const_term.name(), - (PyCFunction)PyBobLearnEMPLDABase_computeLogLikeConstTerm, - METH_VARARGS|METH_KEYWORDS, - compute_log_like_const_term.doc() - }, - { - get_add_log_like_const_term.name(), - (PyCFunction)PyBobLearnEMPLDABase_getAddLogLikeConstTerm, - METH_VARARGS|METH_KEYWORDS, - get_add_log_like_const_term.doc() - }, - { - get_log_like_const_term.name(), - (PyCFunction)PyBobLearnEMPLDABase_getLogLikeConstTerm, - METH_VARARGS|METH_KEYWORDS, - get_log_like_const_term.doc() - }, - { - clear_maps.name(), - (PyCFunction)PyBobLearnEMPLDABase_clearMaps, - METH_NOARGS, - clear_maps.doc() - }, - { - compute_log_likelihood_point_estimate.name(), - (PyCFunction)PyBobLearnEMPLDABase_computeLogLikelihoodPointEstimate, - METH_VARARGS|METH_KEYWORDS, - compute_log_likelihood_point_estimate.doc() - }, - { - __precompute__.name(), - (PyCFunction)PyBobLearnEMPLDABase_precompute, - METH_NOARGS, - __precompute__.doc() - }, - { - __precompute_log_like__.name(), - (PyCFunction)PyBobLearnEMPLDABase_precomputeLogLike, - METH_NOARGS, - __precompute_log_like__.doc() - }, - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the JFA type struct; will be initialized later -PyTypeObject PyBobLearnEMPLDABase_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMPLDABase(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMPLDABase_Type.tp_name = PLDABase_doc.name(); - PyBobLearnEMPLDABase_Type.tp_basicsize = sizeof(PyBobLearnEMPLDABaseObject); - PyBobLearnEMPLDABase_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyBobLearnEMPLDABase_Type.tp_doc = PLDABase_doc.doc(); - - // set the functions - PyBobLearnEMPLDABase_Type.tp_new = PyType_GenericNew; - PyBobLearnEMPLDABase_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMPLDABase_init); - PyBobLearnEMPLDABase_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMPLDABase_delete); - PyBobLearnEMPLDABase_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMPLDABase_RichCompare); - PyBobLearnEMPLDABase_Type.tp_methods = PyBobLearnEMPLDABase_methods; - PyBobLearnEMPLDABase_Type.tp_getset = PyBobLearnEMPLDABase_getseters; - //PyBobLearnEMPLDABase_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMPLDABase_forward); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMPLDABase_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMPLDABase_Type); - return PyModule_AddObject(module, "PLDABase", (PyObject*)&PyBobLearnEMPLDABase_Type) >= 0; -} diff --git a/bob/learn/em/plda_machine.cpp b/bob/learn/em/plda_machine.cpp deleted file mode 100644 index c85e9d542c3536343385f8c87e01d54098e20001..0000000000000000000000000000000000000000 --- a/bob/learn/em/plda_machine.cpp +++ /dev/null @@ -1,806 +0,0 @@ -/** - * @date Thu Jan 30 11:10:15 2015 +0200 - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - -static inline bool f(PyObject* o){return o != 0 && PyObject_IsTrue(o) > 0;} /* converts PyObject to bool and returns false if object is NULL */ - -static auto PLDAMachine_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".PLDAMachine", - - "This class is a container for an enrolled identity/class. It contains information extracted from the enrollment samples. " - "It should be used in combination with a PLDABase instance.\n\n" - "References: [ElShafey2014]_ [PrinceElder2007]_ [LiFu2012]_ ", - "" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - - "Constructor, builds a new PLDAMachine.", - - "", - true - ) - .add_prototype("plda_base","") - .add_prototype("other","") - .add_prototype("hdf5,plda_base","") - - .add_parameter("plda_base", ":py:class:`bob.learn.em.PLDABase`", "") - .add_parameter("other", ":py:class:`bob.learn.em.PLDAMachine`", "A PLDAMachine object to be copied.") - .add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading") - -); - - -static int PyBobLearnEMPLDAMachine_init_copy(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = PLDAMachine_doc.kwlist(1); - PyBobLearnEMPLDAMachineObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMPLDAMachine_Type, &o)){ - PLDAMachine_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::PLDAMachine(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMPLDAMachine_init_hdf5(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = PLDAMachine_doc.kwlist(2); - - PyBobIoHDF5FileObject* config = 0; - PyBobLearnEMPLDABaseObject* plda_base; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!", kwlist, &PyBobIoHDF5File_Converter, &config, - &PyBobLearnEMPLDABase_Type, &plda_base)){ - PLDAMachine_doc.print_usage(); - return -1; - } - auto config_ = make_safe(config); - self->cxx.reset(new bob::learn::em::PLDAMachine(*(config->f),plda_base->cxx)); - - return 0; -} - - -static int PyBobLearnEMPLDAMachine_init_pldabase(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = PLDAMachine_doc.kwlist(0); - PyBobLearnEMPLDABaseObject* plda_base; - - //Here we have to select which keyword argument to read - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMPLDABase_Type, &plda_base)){ - PLDAMachine_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::PLDAMachine(plda_base->cxx)); - return 0; -} - -static int PyBobLearnEMPLDAMachine_init(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - if(nargs==1){ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - // If the constructor input is Gaussian object - if (PyBobLearnEMPLDAMachine_Check(arg)) - return PyBobLearnEMPLDAMachine_init_copy(self, args, kwargs); - // If the constructor input is a HDF5 - else if (PyBobLearnEMPLDABase_Check(arg)) - return PyBobLearnEMPLDAMachine_init_pldabase(self, args, kwargs); - } - else if(nargs==2) - return PyBobLearnEMPLDAMachine_init_hdf5(self, args, kwargs); - else{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires 1 or 2 arguments, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - PLDAMachine_doc.print_usage(); - return -1; - } - BOB_CATCH_MEMBER("cannot create PLDAMachine", -1) - return 0; -} - - - -static void PyBobLearnEMPLDAMachine_delete(PyBobLearnEMPLDAMachineObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* PyBobLearnEMPLDAMachine_RichCompare(PyBobLearnEMPLDAMachineObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMPLDAMachine_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMPLDAMachineObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare PLDAMachine objects", 0) -} - -int PyBobLearnEMPLDAMachine_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMPLDAMachine_Type)); -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -/***** shape *****/ -static auto shape = bob::extension::VariableDoc( - "shape", - "(int,int, int)", - "A tuple that represents the dimensionality of the feature vector dim_d, the :math:`F` matrix and the :math:`G` matrix.", - "" -); -PyObject* PyBobLearnEMPLDAMachine_getShape(PyBobLearnEMPLDAMachineObject* self, void*) { - BOB_TRY - return Py_BuildValue("(i,i,i)", self->cxx->getDimD(), self->cxx->getDimF(), self->cxx->getDimG()); - BOB_CATCH_MEMBER("shape could not be read", 0) -} - - -/***** n_samples *****/ -static auto n_samples = bob::extension::VariableDoc( - "n_samples", - "int", - "Number of enrolled samples", - "" -); -static PyObject* PyBobLearnEMPLDAMachine_getNSamples(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return Py_BuildValue("i",self->cxx->getNSamples()); - BOB_CATCH_MEMBER("n_samples could not be read", 0) -} -int PyBobLearnEMPLDAMachine_setNSamples(PyBobLearnEMPLDAMachineObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyInt_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects an int", Py_TYPE(self)->tp_name, n_samples.name()); - return -1; - } - - if (PyInt_AS_LONG(value) < 0){ - PyErr_Format(PyExc_TypeError, "n_samples must be greater than or equal to zero"); - return -1; - } - - self->cxx->setNSamples(PyInt_AS_LONG(value)); - BOB_CATCH_MEMBER("n_samples could not be set", -1) - return 0; -} - - -/***** w_sum_xit_beta_xi *****/ -static auto w_sum_xit_beta_xi = bob::extension::VariableDoc( - "w_sum_xit_beta_xi", - "float", - "Gets the :math:`A = -0.5 \\sum_{i} x_{i}^T \\beta x_{i}` value", - "" -); -static PyObject* PyBobLearnEMPLDAMachine_getWSumXitBetaXi(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return Py_BuildValue("d",self->cxx->getWSumXitBetaXi()); - BOB_CATCH_MEMBER("w_sum_xit_beta_xi could not be read", 0) -} -int PyBobLearnEMPLDAMachine_setWSumXitBetaXi(PyBobLearnEMPLDAMachineObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyBob_NumberCheck(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects an float", Py_TYPE(self)->tp_name, w_sum_xit_beta_xi.name()); - return -1; - } - - self->cxx->setWSumXitBetaXi(PyFloat_AS_DOUBLE(value)); - BOB_CATCH_MEMBER("w_sum_xit_beta_xi could not be set", -1) - return 0; -} - - -/***** plda_base *****/ -static auto plda_base = bob::extension::VariableDoc( - "plda_base", - ":py:class:`bob.learn.em.PLDABase`", - "The PLDABase attached to this machine", - "" -); -PyObject* PyBobLearnEMPLDAMachine_getPLDABase(PyBobLearnEMPLDAMachineObject* self, void*){ - BOB_TRY - - boost::shared_ptr<bob::learn::em::PLDABase> plda_base_o = self->cxx->getPLDABase(); - - //Allocating the correspondent python object - PyBobLearnEMPLDABaseObject* retval = - (PyBobLearnEMPLDABaseObject*)PyBobLearnEMPLDABase_Type.tp_alloc(&PyBobLearnEMPLDABase_Type, 0); - retval->cxx = plda_base_o; - - return Py_BuildValue("N",retval); - BOB_CATCH_MEMBER("plda_base could not be read", 0) -} -int PyBobLearnEMPLDAMachine_setPLDABase(PyBobLearnEMPLDAMachineObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyBobLearnEMPLDABase_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a :py:class:`bob.learn.em.PLDABase`", Py_TYPE(self)->tp_name, plda_base.name()); - return -1; - } - - PyBobLearnEMPLDABaseObject* plda_base_o = 0; - PyArg_Parse(value, "O!", &PyBobLearnEMPLDABase_Type,&plda_base_o); - - self->cxx->setPLDABase(plda_base_o->cxx); - - return 0; - BOB_CATCH_MEMBER("plda_base could not be set", -1) -} - - -/***** weighted_sum *****/ -static auto weighted_sum = bob::extension::VariableDoc( - "weighted_sum", - "array_like <float, 1D>", - "Get/Set :math:`\\sum_{i} F^T \\beta x_{i}` value", - "" -); -static PyObject* PyBobLearnEMPLDAMachine_getWeightedSum(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getWeightedSum()); - BOB_CATCH_MEMBER("weighted_sum could not be read", 0) -} -int PyBobLearnEMPLDAMachine_setWeightedSum(PyBobLearnEMPLDAMachineObject* self, PyObject* value, void*){ - BOB_TRY - PyBlitzArrayObject* o; - if (!PyBlitzArray_Converter(value, &o)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a 2D array of floats", Py_TYPE(self)->tp_name, weighted_sum.name()); - return -1; - } - auto o_ = make_safe(o); - auto b = PyBlitzArrayCxx_AsBlitz<double,1>(o, "weighted_sum"); - if (!b) return -1; - self->cxx->setWeightedSum(*b); - return 0; - BOB_CATCH_MEMBER("`weighted_sum` vector could not be set", -1) -} - - -/***** log_likelihood *****/ -static auto log_likelihood = bob::extension::VariableDoc( - "log_likelihood", - "float", - "Get the current log likelihood", - "" -); -static PyObject* PyBobLearnEMPLDAMachine_getLogLikelihood(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - return Py_BuildValue("d",self->cxx->getLogLikelihood()); - BOB_CATCH_MEMBER("log_likelihood could not be read", 0) -} -int PyBobLearnEMPLDAMachine_setLogLikelihood(PyBobLearnEMPLDAMachineObject* self, PyObject* value, void*){ - BOB_TRY - - if (!PyBob_NumberCheck(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects a float", Py_TYPE(self)->tp_name, log_likelihood.name()); - return -1; - } - - self->cxx->setLogLikelihood(PyFloat_AS_DOUBLE(value)); - BOB_CATCH_MEMBER("log_likelihood could not be set", -1) - return 0; -} - - -static PyGetSetDef PyBobLearnEMPLDAMachine_getseters[] = { - { - shape.name(), - (getter)PyBobLearnEMPLDAMachine_getShape, - 0, - shape.doc(), - 0 - }, - { - n_samples.name(), - (getter)PyBobLearnEMPLDAMachine_getNSamples, - (setter)PyBobLearnEMPLDAMachine_setNSamples, - n_samples.doc(), - 0 - }, - { - w_sum_xit_beta_xi.name(), - (getter)PyBobLearnEMPLDAMachine_getWSumXitBetaXi, - (setter)PyBobLearnEMPLDAMachine_setWSumXitBetaXi, - w_sum_xit_beta_xi.doc(), - 0 - }, - { - plda_base.name(), - (getter)PyBobLearnEMPLDAMachine_getPLDABase, - (setter)PyBobLearnEMPLDAMachine_setPLDABase, - plda_base.doc(), - 0 - }, - { - weighted_sum.name(), - (getter)PyBobLearnEMPLDAMachine_getWeightedSum, - (setter)PyBobLearnEMPLDAMachine_setWeightedSum, - weighted_sum.doc(), - 0 - }, - { - log_likelihood.name(), - (getter)PyBobLearnEMPLDAMachine_getLogLikelihood, - (setter)PyBobLearnEMPLDAMachine_setLogLikelihood, - log_likelihood.doc(), - 0 - }, - {0} // Sentinel -}; - - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - - -/*** save ***/ -static auto save = bob::extension::FunctionDoc( - "save", - "Save the configuration of the PLDAMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for writing"); -static PyObject* PyBobLearnEMPLDAMachine_Save(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - - BOB_TRY - - // get list of arguments - char** kwlist = save.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->save(*hdf5->f); - - BOB_CATCH_MEMBER("cannot save the data", 0) - Py_RETURN_NONE; -} - -/*** load ***/ -static auto load = bob::extension::FunctionDoc( - "load", - "Load the configuration of the PLDAMachine to a given HDF5 file" -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`bob.io.base.HDF5File`", "An HDF5 file open for reading"); -static PyObject* PyBobLearnEMPLDAMachine_Load(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = load.kwlist(0); - PyBobIoHDF5FileObject* hdf5; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0; - - auto hdf5_ = make_safe(hdf5); - self->cxx->load(*hdf5->f); - - BOB_CATCH_MEMBER("cannot load the data", 0) - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this PLDAMachine with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` " - "and any other values internal to this machine." -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.PLDAMachine`", "A PLDAMachine object to be compared.") -.add_parameter("r_epsilon", "float", "Relative precision.") -.add_parameter("a_epsilon", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMPLDAMachine_IsSimilarTo(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - //PyObject* other = 0; - PyBobLearnEMPLDAMachineObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMPLDAMachine_Type, &other, - &r_epsilon, &a_epsilon)){ - - is_similar_to.print_usage(); - return 0; - } - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - -/***** get_gamma *****/ -static auto get_gamma = bob::extension::FunctionDoc( - "get_gamma", - "Gets the :math:`\\gamma_a` matrix for a given :math:`a` (number of samples). " - ":math:`\\gamma_{a}=(Id + a F^T \\beta F)^{-1}= \\mathcal{F}_{a}`", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","array_like <float, 2D>","Get the :math:`\\gamma` matrix"); -static PyObject* PyBobLearnEMPLDAMachine_getGamma(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_gamma.kwlist(0); - - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getGamma(i)); - BOB_CATCH_MEMBER("`get_gamma` could not be read", 0) -} - - -/***** has_gamma *****/ -static auto has_gamma = bob::extension::FunctionDoc( - "has_gamma", - "Tells if the :math:`\\gamma_a` matrix for a given a (number of samples) exists. " - ":math:`\\gamma_a=(Id + a F^T \\beta F)^{-1}`", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","bool",""); -static PyObject* PyBobLearnEMPLDAMachine_hasGamma(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = has_gamma.kwlist(0); - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - if(self->cxx->hasGamma(i)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; - BOB_CATCH_MEMBER("`has_gamma` could not be read", 0) -} - - -/***** get_add_gamma *****/ -static auto get_add_gamma = bob::extension::FunctionDoc( - "get_add_gamma", - "Gets the :math:`gamma_a` matrix for a given :math:`f_a` (number of samples)." - " :math:`\\gamma_a=(Id + a F^T \\beta F)^{-1} =\\mathcal{F}_{a}`." - "Tries to find it from the base machine and then from this machine.", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","array_like <float, 2D>",""); -static PyObject* PyBobLearnEMPLDAMachine_getAddGamma(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_add_gamma.kwlist(0); - - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getAddGamma(i)); - BOB_CATCH_MEMBER("`get_add_gamma` could not be read", 0) -} - - -/***** has_log_like_const_term *****/ -static auto has_log_like_const_term = bob::extension::FunctionDoc( - "has_log_like_const_term", - "Tells if the log likelihood constant term for a given :math:`a` (number of samples) exists in this machine (does not check the base machine). " - ":math:`l_{a}=\\frac{a}{2} ( -D log(2\\pi) -log|\\Sigma| +log|\\alpha| +log|\\gamma_a|)`", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","bool",""); -static PyObject* PyBobLearnEMPLDAMachine_hasLogLikeConstTerm(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = has_log_like_const_term.kwlist(0); - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - if(self->cxx->hasLogLikeConstTerm(i)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; - BOB_CATCH_MEMBER("`has_log_like_const_term` could not be read", 0) -} - - -/***** get_add_log_like_const_term *****/ -static auto get_add_log_like_const_term = bob::extension::FunctionDoc( - "get_add_log_like_const_term", - - "Gets the log likelihood constant term for a given :math:`a` (number of samples). " - ":math:`l_{a} = \\frac{a}{2} ( -D log(2\\pi) -log|\\Sigma| +log|\\alpha| +log|gamma_a|)`", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","float",""); -static PyObject* PyBobLearnEMPLDAMachine_getAddLogLikeConstTerm(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_add_log_like_const_term.kwlist(0); - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - return Py_BuildValue("d",self->cxx->getAddLogLikeConstTerm(i)); - - BOB_CATCH_MEMBER("`get_add_log_like_const_term` could not be read", 0) -} - - -/***** get_log_like_const_term *****/ -static auto get_log_like_const_term = bob::extension::FunctionDoc( - "get_log_like_const_term", - "Gets the log likelihood constant term for a given :math:`a` (number of samples). " - ":math:`l_{a}=\\frac{a}{2}( -D log(2\\pi) -log|\\Sigma| +log|\\alpha| + log|\\gamma_a|)`", - 0, - true -) -.add_prototype("a","output") -.add_parameter("a", "int", "Index") -.add_return("output","float",""); -static PyObject* PyBobLearnEMPLDAMachine_getLogLikeConstTerm(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = get_log_like_const_term.kwlist(0); - int i = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) return 0; - - return Py_BuildValue("d",self->cxx->getLogLikeConstTerm(i)); - - BOB_CATCH_MEMBER("`get_log_like_const_term` could not be read", 0) -} - -/***** clear_maps *****/ -static auto clear_maps = bob::extension::FunctionDoc( - "clear_maps", - "Clears the maps (:math:`\\gamma_a` and loglike_constterm_a).", - 0, - true -) -.add_prototype(""); -static PyObject* PyBobLearnEMPLDAMachine_clearMaps(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - self->cxx->clearMaps(); - Py_RETURN_NONE; - - BOB_CATCH_MEMBER("`clear_maps` could not be read", 0) -} - - -/***** compute_log_likelihood *****/ -static auto compute_log_likelihood = bob::extension::FunctionDoc( - "compute_log_likelihood", - "Compute the log-likelihood of the given sample and (optionally) the enrolled samples", - 0, - true -) -.add_prototype("sample,with_enrolled_samples","output") -.add_parameter("sample", "array_like <float, 1D>,array_like <float, 2D>", "Sample") -.add_parameter("with_enrolled_samples", "bool", "") -.add_return("output","float","The log-likelihood"); -static PyObject* PyBobLearnEMPLDAMachine_computeLogLikelihood(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = compute_log_likelihood.kwlist(0); - - PyBlitzArrayObject* samples; - PyObject* with_enrolled_samples = Py_True; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|O!", kwlist, &PyBlitzArray_Converter, &samples, - &PyBool_Type, &with_enrolled_samples)) return 0; - auto samples_ = make_safe(samples); - - /*Using the proper method according to the dimension*/ - if (samples->ndim==1) - return Py_BuildValue("d",self->cxx->computeLogLikelihood(*PyBlitzArrayCxx_AsBlitz<double,1>(samples), f(with_enrolled_samples))); - else - return Py_BuildValue("d",self->cxx->computeLogLikelihood(*PyBlitzArrayCxx_AsBlitz<double,2>(samples), f(with_enrolled_samples))); - - - BOB_CATCH_MEMBER("`compute_log_likelihood` could not be read", 0) -} - - -/***** log_likelihood_ratio *****/ -static auto log_likelihood_ratio = bob::extension::FunctionDoc( - "log_likelihood_ratio", - "Computes a log likelihood ratio from a 1D or 2D blitz::Array", - 0, - true -) -.add_prototype("samples","output") -.add_parameter("samples", "array_like <float, 1D>,array_like <float, 2D>", "Sample") -.add_return("output","float","The log-likelihood ratio"); -static PyObject* PyBobLearnEMPLDAMachine_log_likelihood_ratio(PyBobLearnEMPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - char** kwlist = log_likelihood_ratio.kwlist(0); - - PyBlitzArrayObject* samples; - - /*Convert to PyObject first to access the number of dimensions*/ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBlitzArray_Converter, &samples)) return 0; - auto samples_ = make_safe(samples); - - //There are 2 methods in C++, one <double,1> and the another <double,2> - if(samples->ndim==1) - return Py_BuildValue("d",self->cxx->forward(*PyBlitzArrayCxx_AsBlitz<double,1>(samples))); - else - return Py_BuildValue("d",self->cxx->forward(*PyBlitzArrayCxx_AsBlitz<double,2>(samples))); - - BOB_CATCH_MEMBER("log_likelihood_ratio could not be executed", 0) -} - - -static PyMethodDef PyBobLearnEMPLDAMachine_methods[] = { - { - save.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_Save, - METH_VARARGS|METH_KEYWORDS, - save.doc() - }, - { - load.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_Load, - METH_VARARGS|METH_KEYWORDS, - load.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - { - get_gamma.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_getGamma, - METH_VARARGS|METH_KEYWORDS, - get_gamma.doc() - }, - { - has_gamma.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_hasGamma, - METH_VARARGS|METH_KEYWORDS, - has_gamma.doc() - }, - { - get_add_gamma.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_getAddGamma, - METH_VARARGS|METH_KEYWORDS, - get_add_gamma.doc() - }, - { - has_log_like_const_term.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_hasLogLikeConstTerm, - METH_VARARGS|METH_KEYWORDS, - has_log_like_const_term.doc() - }, - { - get_add_log_like_const_term.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_getAddLogLikeConstTerm, - METH_VARARGS|METH_KEYWORDS, - get_add_log_like_const_term.doc() - }, - { - get_log_like_const_term.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_getLogLikeConstTerm, - METH_VARARGS|METH_KEYWORDS, - get_log_like_const_term.doc() - }, - { - clear_maps.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_clearMaps, - METH_NOARGS, - clear_maps.doc() - }, - { - compute_log_likelihood.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_computeLogLikelihood, - METH_VARARGS|METH_KEYWORDS, - compute_log_likelihood.doc() - }, - { - log_likelihood_ratio.name(), - (PyCFunction)PyBobLearnEMPLDAMachine_log_likelihood_ratio, - METH_VARARGS|METH_KEYWORDS, - log_likelihood_ratio.doc() - }, - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the JFA type struct; will be initialized later -PyTypeObject PyBobLearnEMPLDAMachine_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMPLDAMachine(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMPLDAMachine_Type.tp_name = PLDAMachine_doc.name(); - PyBobLearnEMPLDAMachine_Type.tp_basicsize = sizeof(PyBobLearnEMPLDAMachineObject); - PyBobLearnEMPLDAMachine_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyBobLearnEMPLDAMachine_Type.tp_doc = PLDAMachine_doc.doc(); - - // set the functions - PyBobLearnEMPLDAMachine_Type.tp_new = PyType_GenericNew; - PyBobLearnEMPLDAMachine_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMPLDAMachine_init); - PyBobLearnEMPLDAMachine_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMPLDAMachine_delete); - PyBobLearnEMPLDAMachine_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMPLDAMachine_RichCompare); - PyBobLearnEMPLDAMachine_Type.tp_methods = PyBobLearnEMPLDAMachine_methods; - PyBobLearnEMPLDAMachine_Type.tp_getset = PyBobLearnEMPLDAMachine_getseters; - PyBobLearnEMPLDAMachine_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMPLDAMachine_log_likelihood_ratio); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMPLDAMachine_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMPLDAMachine_Type); - return PyModule_AddObject(module, "PLDAMachine", (PyObject*)&PyBobLearnEMPLDAMachine_Type) >= 0; -} diff --git a/bob/learn/em/plda_trainer.cpp b/bob/learn/em/plda_trainer.cpp deleted file mode 100644 index 49842a3b086f4c3e865812a69a71eaedf553924d..0000000000000000000000000000000000000000 --- a/bob/learn/em/plda_trainer.cpp +++ /dev/null @@ -1,721 +0,0 @@ -/** - * @author Tiago de Freitas Pereira <tiago.pereira@idiap.ch> - * @date Wed 04 Feb 14:15:00 2015 - * - * @brief Python API for bob::learn::em - * - * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - */ - -#include "main.h" -#include <boost/make_shared.hpp> -#include <boost/assign.hpp> - -//Defining maps for each initializatio method -static const std::map<std::string, bob::learn::em::PLDATrainer::InitFMethod> FMethod = boost::assign::map_list_of - ("RANDOM_F", bob::learn::em::PLDATrainer::RANDOM_F) - ("BETWEEN_SCATTER", bob::learn::em::PLDATrainer::BETWEEN_SCATTER) - ; - -static const std::map<std::string, bob::learn::em::PLDATrainer::InitGMethod> GMethod = boost::assign::map_list_of - ("RANDOM_G", bob::learn::em::PLDATrainer::RANDOM_G) - ("WITHIN_SCATTER", bob::learn::em::PLDATrainer::WITHIN_SCATTER) - ; - -static const std::map<std::string, bob::learn::em::PLDATrainer::InitSigmaMethod> SigmaMethod = boost::assign::map_list_of - ("RANDOM_SIGMA", bob::learn::em::PLDATrainer::RANDOM_SIGMA) - ("VARIANCE_G", bob::learn::em::PLDATrainer::VARIANCE_G) - ("CONSTANT", bob::learn::em::PLDATrainer::CONSTANT) - ("VARIANCE_DATA", bob::learn::em::PLDATrainer::VARIANCE_DATA) - ; - -//String to type -static inline bob::learn::em::PLDATrainer::InitFMethod string2FMethod(const std::string& o){ - auto it = FMethod.find(o); - if (it == FMethod.end()) throw std::runtime_error("The given FMethod '" + o + "' is not known; choose one of ('RANDOM_F','BETWEEN_SCATTER')"); - else return it->second; -} - -static inline bob::learn::em::PLDATrainer::InitGMethod string2GMethod(const std::string& o){ - auto it = GMethod.find(o); - if (it == GMethod.end()) throw std::runtime_error("The given GMethod '" + o + "' is not known; choose one of ('RANDOM_G','WITHIN_SCATTER')"); - else return it->second; -} - -static inline bob::learn::em::PLDATrainer::InitSigmaMethod string2SigmaMethod(const std::string& o){ - auto it = SigmaMethod.find(o); - if (it == SigmaMethod.end()) throw std::runtime_error("The given SigmaMethod '" + o + "' is not known; choose one of ('RANDOM_SIGMA','VARIANCE_G', 'CONSTANT', 'VARIANCE_DATA')"); - else return it->second; -} - -//Type to string -static inline const std::string& FMethod2string(bob::learn::em::PLDATrainer::InitFMethod o){ - for (auto it = FMethod.begin(); it != FMethod.end(); ++it) if (it->second == o) return it->first; - throw std::runtime_error("The given FMethod type is not known"); -} - -static inline const std::string& GMethod2string(bob::learn::em::PLDATrainer::InitGMethod o){ - for (auto it = GMethod.begin(); it != GMethod.end(); ++it) if (it->second == o) return it->first; - throw std::runtime_error("The given GMethod type is not known"); -} - -static inline const std::string& SigmaMethod2string(bob::learn::em::PLDATrainer::InitSigmaMethod o){ - for (auto it = SigmaMethod.begin(); it != SigmaMethod.end(); ++it) if (it->second == o) return it->first; - throw std::runtime_error("The given SigmaMethod type is not known"); -} - - -static inline bool f(PyObject* o){return o != 0 && PyObject_IsTrue(o) > 0;} /* converts PyObject to bool and returns false if object is NULL */ - -template <int N> -int list_as_vector(PyObject* list, std::vector<blitz::Array<double,N> >& vec) -{ - for (int i=0; i<PyList_GET_SIZE(list); i++) - { - PyBlitzArrayObject* blitz_object; - if (!PyArg_Parse(PyList_GetItem(list, i), "O&", &PyBlitzArray_Converter, &blitz_object)){ - PyErr_Format(PyExc_RuntimeError, "Expected numpy array object"); - return -1; - } - auto blitz_object_ = make_safe(blitz_object); - vec.push_back(*PyBlitzArrayCxx_AsBlitz<double,N>(blitz_object)); - } - return 0; -} - - -template <int N> -static PyObject* vector_as_list(const std::vector<blitz::Array<double,N> >& vec) -{ - PyObject* list = PyList_New(vec.size()); - for(size_t i=0; i<vec.size(); i++){ - blitz::Array<double,N> numpy_array = vec[i]; - PyObject* numpy_py_object = PyBlitzArrayCxx_AsNumpy(numpy_array); - PyList_SET_ITEM(list, i, numpy_py_object); - } - return list; -} - - -/******************************************************************/ -/************ Constructor Section *********************************/ -/******************************************************************/ - - -static auto PLDATrainer_doc = bob::extension::ClassDoc( - BOB_EXT_MODULE_PREFIX ".PLDATrainer", - "This class can be used to train the :math:`F`, :math:`G` and " - " :math:`\\Sigma` matrices and the mean vector :math:`\\mu` of a PLDA model." - "References: [ElShafey2014]_ [PrinceElder2007]_ [LiFu2012]_ ", - "" -).add_constructor( - bob::extension::FunctionDoc( - "__init__", - "Default constructor.\n Initializes a new PLDA trainer. The " - "training stage will place the resulting components in the " - "PLDABase.", - "", - true - ) - .add_prototype("use_sum_second_order","") - .add_prototype("other","") - .add_prototype("","") - - .add_parameter("other", ":py:class:`bob.learn.em.PLDATrainer`", "A PLDATrainer object to be copied.") - .add_parameter("use_sum_second_order", "bool", "") -); - -static int PyBobLearnEMPLDATrainer_init_copy(PyBobLearnEMPLDATrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = PLDATrainer_doc.kwlist(1); - PyBobLearnEMPLDATrainerObject* o; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMPLDATrainer_Type, &o)){ - PLDATrainer_doc.print_usage(); - return -1; - } - - self->cxx.reset(new bob::learn::em::PLDATrainer(*o->cxx)); - return 0; -} - - -static int PyBobLearnEMPLDATrainer_init_bool(PyBobLearnEMPLDATrainerObject* self, PyObject* args, PyObject* kwargs) { - - char** kwlist = PLDATrainer_doc.kwlist(0); - PyObject* use_sum_second_order = Py_False; - - //Parsing the input argments - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O!", kwlist, &PyBool_Type, &use_sum_second_order)) - return -1; - - self->cxx.reset(new bob::learn::em::PLDATrainer(f(use_sum_second_order))); - return 0; -} - - -static int PyBobLearnEMPLDATrainer_init(PyBobLearnEMPLDATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - // get the number of command line arguments - int nargs = (args?PyTuple_Size(args):0) + (kwargs?PyDict_Size(kwargs):0); - - if(nargs==0) - return PyBobLearnEMPLDATrainer_init_bool(self, args, kwargs); - else if(nargs==1){ - //Reading the input argument - PyObject* arg = 0; - if (PyTuple_Size(args)) - arg = PyTuple_GET_ITEM(args, 0); - else { - PyObject* tmp = PyDict_Values(kwargs); - auto tmp_ = make_safe(tmp); - arg = PyList_GET_ITEM(tmp, 0); - } - - if(PyBobLearnEMPLDATrainer_Check(arg)) - // If the constructor input is PLDATrainer object - return PyBobLearnEMPLDATrainer_init_copy(self, args, kwargs); - else - return PyBobLearnEMPLDATrainer_init_bool(self, args, kwargs); - } - else{ - PyErr_Format(PyExc_RuntimeError, "number of arguments mismatch - %s requires only 0 or 1 argument, but you provided %d (see help)", Py_TYPE(self)->tp_name, nargs); - PLDATrainer_doc.print_usage(); - return -1; - } - - BOB_CATCH_MEMBER("cannot create PLDATrainer", -1) - return 0; -} - - -static void PyBobLearnEMPLDATrainer_delete(PyBobLearnEMPLDATrainerObject* self) { - self->cxx.reset(); - Py_TYPE(self)->tp_free((PyObject*)self); -} - - -int PyBobLearnEMPLDATrainer_Check(PyObject* o) { - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnEMPLDATrainer_Type)); -} - - -static PyObject* PyBobLearnEMPLDATrainer_RichCompare(PyBobLearnEMPLDATrainerObject* self, PyObject* other, int op) { - BOB_TRY - - if (!PyBobLearnEMPLDATrainer_Check(other)) { - PyErr_Format(PyExc_TypeError, "cannot compare `%s' with `%s'", Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name); - return 0; - } - auto other_ = reinterpret_cast<PyBobLearnEMPLDATrainerObject*>(other); - switch (op) { - case Py_EQ: - if (*self->cxx==*other_->cxx) Py_RETURN_TRUE; else Py_RETURN_FALSE; - case Py_NE: - if (*self->cxx==*other_->cxx) Py_RETURN_FALSE; else Py_RETURN_TRUE; - default: - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } - BOB_CATCH_MEMBER("cannot compare PLDATrainer objects", 0) -} - - -/******************************************************************/ -/************ Variables Section ***********************************/ -/******************************************************************/ - -static auto z_second_order = bob::extension::VariableDoc( - "z_second_order", - "array_like <float, 3D>", - "", - "" -); -PyObject* PyBobLearnEMPLDATrainer_get_z_second_order(PyBobLearnEMPLDATrainerObject* self, void*){ - BOB_TRY - //return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getZSecondOrder()); - return vector_as_list(self->cxx->getZSecondOrder()); - BOB_CATCH_MEMBER("z_second_order could not be read", 0) -} - - -static auto z_second_order_sum = bob::extension::VariableDoc( - "z_second_order_sum", - "array_like <float, 2D>", - "", - "" -); -PyObject* PyBobLearnEMPLDATrainer_get_z_second_order_sum(PyBobLearnEMPLDATrainerObject* self, void*){ - BOB_TRY - return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getZSecondOrderSum()); - BOB_CATCH_MEMBER("z_second_order_sum could not be read", 0) -} - - -static auto z_first_order = bob::extension::VariableDoc( - "z_first_order", - "array_like <float, 2D>", - "", - "" -); -PyObject* PyBobLearnEMPLDATrainer_get_z_first_order(PyBobLearnEMPLDATrainerObject* self, void*){ - BOB_TRY - //return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getZFirstOrder()); - return vector_as_list(self->cxx->getZFirstOrder()); - BOB_CATCH_MEMBER("z_first_order could not be read", 0) -} - - -/***** init_f_method *****/ -static auto init_f_method = bob::extension::VariableDoc( - "init_f_method", - "str", - "The method used for the initialization of :math:`$F$`.", - "Possible values are: ('RANDOM_F', 'BETWEEN_SCATTER')" -); -PyObject* PyBobLearnEMPLDATrainer_getFMethod(PyBobLearnEMPLDATrainerObject* self, void*) { - BOB_TRY - return Py_BuildValue("s", FMethod2string(self->cxx->getInitFMethod()).c_str()); - BOB_CATCH_MEMBER("init_f_method method could not be read", 0) -} -int PyBobLearnEMPLDATrainer_setFMethod(PyBobLearnEMPLDATrainerObject* self, PyObject* value, void*) { - BOB_TRY - - if (!PyString_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects an str", Py_TYPE(self)->tp_name, init_f_method.name()); - return -1; - } - self->cxx->setInitFMethod(string2FMethod(PyString_AS_STRING(value))); - - return 0; - BOB_CATCH_MEMBER("init_f_method method could not be set", -1) -} - - -/***** init_g_method *****/ -static auto init_g_method = bob::extension::VariableDoc( - "init_g_method", - "str", - "The method used for the initialization of :math:`$G$`.", - "Possible values are: ('RANDOM_G', 'WITHIN_SCATTER')" -); -PyObject* PyBobLearnEMPLDATrainer_getGMethod(PyBobLearnEMPLDATrainerObject* self, void*) { - BOB_TRY - return Py_BuildValue("s", GMethod2string(self->cxx->getInitGMethod()).c_str()); - BOB_CATCH_MEMBER("init_g_method method could not be read", 0) -} -int PyBobLearnEMPLDATrainer_setGMethod(PyBobLearnEMPLDATrainerObject* self, PyObject* value, void*) { - BOB_TRY - - if (!PyString_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects an str", Py_TYPE(self)->tp_name, init_g_method.name()); - return -1; - } - self->cxx->setInitGMethod(string2GMethod(PyString_AS_STRING(value))); - - return 0; - BOB_CATCH_MEMBER("init_g_method method could not be set", -1) -} - -/***** init_sigma_method *****/ -static auto init_sigma_method = bob::extension::VariableDoc( - "init_sigma_method", - "str", - "The method used for the initialization of :math:`$\\Sigma$`.", - "Possible values are: ('RANDOM_SIGMA', 'VARIANCE_G', 'CONSTANT', 'VARIANCE_DATA')" -); -PyObject* PyBobLearnEMPLDATrainer_getSigmaMethod(PyBobLearnEMPLDATrainerObject* self, void*) { - BOB_TRY - return Py_BuildValue("s", SigmaMethod2string(self->cxx->getInitSigmaMethod()).c_str()); - BOB_CATCH_MEMBER("init_sigma_method method could not be read", 0) -} -int PyBobLearnEMPLDATrainer_setSigmaMethod(PyBobLearnEMPLDATrainerObject* self, PyObject* value, void*) { - BOB_TRY - - if (!PyString_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects an str", Py_TYPE(self)->tp_name, init_sigma_method.name()); - return -1; - } - self->cxx->setInitSigmaMethod(string2SigmaMethod(PyString_AS_STRING(value))); - - return 0; - BOB_CATCH_MEMBER("init_sigma_method method could not be set", -1) -} - - -static auto use_sum_second_order = bob::extension::VariableDoc( - "use_sum_second_order", - "bool", - "Tells whether the second order statistics are stored during the training procedure, or only their sum.", - "" -); -PyObject* PyBobLearnEMPLDATrainer_getUseSumSecondOrder(PyBobLearnEMPLDATrainerObject* self, void*){ - BOB_TRY - return Py_BuildValue("O",self->cxx->getUseSumSecondOrder()?Py_True:Py_False); - BOB_CATCH_MEMBER("use_sum_second_order could not be read", 0) -} -int PyBobLearnEMPLDATrainer_setUseSumSecondOrder(PyBobLearnEMPLDATrainerObject* self, PyObject* value, void*) { - BOB_TRY - - if (!PyBool_Check(value)){ - PyErr_Format(PyExc_RuntimeError, "%s %s expects an str", Py_TYPE(self)->tp_name, use_sum_second_order.name()); - return -1; - } - self->cxx->setUseSumSecondOrder(f(value)); - - return 0; - BOB_CATCH_MEMBER("use_sum_second_order method could not be set", -1) -} - - - -static PyGetSetDef PyBobLearnEMPLDATrainer_getseters[] = { - { - z_first_order.name(), - (getter)PyBobLearnEMPLDATrainer_get_z_first_order, - 0, - z_first_order.doc(), - 0 - }, - { - z_second_order_sum.name(), - (getter)PyBobLearnEMPLDATrainer_get_z_second_order_sum, - 0, - z_second_order_sum.doc(), - 0 - }, - { - z_second_order.name(), - (getter)PyBobLearnEMPLDATrainer_get_z_second_order, - 0, - z_second_order.doc(), - 0 - }, - { - init_f_method.name(), - (getter)PyBobLearnEMPLDATrainer_getFMethod, - (setter)PyBobLearnEMPLDATrainer_setFMethod, - init_f_method.doc(), - 0 - }, - { - init_g_method.name(), - (getter)PyBobLearnEMPLDATrainer_getGMethod, - (setter)PyBobLearnEMPLDATrainer_setGMethod, - init_g_method.doc(), - 0 - }, - { - init_sigma_method.name(), - (getter)PyBobLearnEMPLDATrainer_getSigmaMethod, - (setter)PyBobLearnEMPLDATrainer_setSigmaMethod, - init_sigma_method.doc(), - 0 - }, - { - use_sum_second_order.name(), - (getter)PyBobLearnEMPLDATrainer_getUseSumSecondOrder, - (setter)PyBobLearnEMPLDATrainer_setUseSumSecondOrder, - use_sum_second_order.doc(), - 0 - }, - {0} // Sentinel -}; - - -/******************************************************************/ -/************ Functions Section ***********************************/ -/******************************************************************/ - -/*** initialize ***/ -static auto initialize = bob::extension::FunctionDoc( - "initialize", - "Initialization before the EM steps", - "", - true -) -.add_prototype("plda_base, data, [rng]") -.add_parameter("plda_base", ":py:class:`bob.learn.em.PLDABase`", "PLDAMachine Object") -.add_parameter("data", "list", "") -.add_parameter("rng", ":py:class:`bob.core.random.mt19937`", "The Mersenne Twister mt19937 random generator used for the initialization of subspaces/arrays before the EM loop."); -static PyObject* PyBobLearnEMPLDATrainer_initialize(PyBobLearnEMPLDATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = initialize.kwlist(0); - - PyBobLearnEMPLDABaseObject* plda_base = 0; - PyObject* data = 0; - PyBoostMt19937Object* rng = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!|O!", kwlist, &PyBobLearnEMPLDABase_Type, &plda_base, - &PyList_Type, &data, - &PyBoostMt19937_Type, &rng)) return 0; - - std::vector<blitz::Array<double,2> > data_vector; - if(list_as_vector(data ,data_vector)==0){ - if(rng){ - self->cxx->setRng(rng->rng); - } - - self->cxx->initialize(*plda_base->cxx, data_vector); - } - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the initialize method", 0) - - Py_RETURN_NONE; -} - - -/*** e_step ***/ -static auto e_step = bob::extension::FunctionDoc( - "e_step", - "Expectation step before the EM steps", - "", - true -) -.add_prototype("plda_base,data") -.add_parameter("plda_base", ":py:class:`bob.learn.em.PLDABase`", "PLDAMachine Object") -.add_parameter("data", "list", ""); -static PyObject* PyBobLearnEMPLDATrainer_e_step(PyBobLearnEMPLDATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = e_step.kwlist(0); - - PyBobLearnEMPLDABaseObject* plda_base = 0; - PyObject* data = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMPLDABase_Type, &plda_base, - &PyList_Type, &data)) return 0; - - std::vector<blitz::Array<double,2> > data_vector; - if(list_as_vector(data ,data_vector)==0) - self->cxx->eStep(*plda_base->cxx, data_vector); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the e_step method", 0) - - Py_RETURN_NONE; -} - - -/*** m_step ***/ -static auto m_step = bob::extension::FunctionDoc( - "m_step", - "Maximization step ", - "", - true -) -.add_prototype("plda_base,data") -.add_parameter("plda_base", ":py:class:`bob.learn.em.PLDABase`", "PLDAMachine Object") -.add_parameter("data", "list", ""); -static PyObject* PyBobLearnEMPLDATrainer_m_step(PyBobLearnEMPLDATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = m_step.kwlist(0); - - PyBobLearnEMPLDABaseObject* plda_base = 0; - PyObject* data = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMPLDABase_Type, &plda_base, - &PyList_Type, &data)) return 0; - - std::vector<blitz::Array<double,2> > data_vector; - if(list_as_vector(data ,data_vector)==0) - self->cxx->mStep(*plda_base->cxx, data_vector); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the m_step method", 0) - - Py_RETURN_NONE; -} - - -/*** finalize ***/ -static auto finalize = bob::extension::FunctionDoc( - "finalize", - "finalize before the EM steps", - "", - true -) -.add_prototype("plda_base,data") -.add_parameter("plda_base", ":py:class:`bob.learn.em.PLDABase`", "PLDAMachine Object") -.add_parameter("data", "list", ""); -static PyObject* PyBobLearnEMPLDATrainer_finalize(PyBobLearnEMPLDATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = finalize.kwlist(0); - - PyBobLearnEMPLDABaseObject* plda_base = 0; - PyObject* data = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!", kwlist, &PyBobLearnEMPLDABase_Type, &plda_base, - &PyList_Type, &data)) return 0; - - std::vector<blitz::Array<double,2> > data_vector; - if(list_as_vector(data ,data_vector)==0) - self->cxx->finalize(*plda_base->cxx, data_vector); - else - return 0; - - BOB_CATCH_MEMBER("cannot perform the finalize method", 0) - - Py_RETURN_NONE; -} - - - -/*** enroll ***/ -static auto enroll = bob::extension::FunctionDoc( - "enroll", - "Main procedure for enrolling a PLDAMachine", - "", - true -) -.add_prototype("plda_machine,data") -.add_parameter("plda_machine", ":py:class:`bob.learn.em.PLDAMachine`", "PLDAMachine Object") -.add_parameter("data", "list", ""); -static PyObject* PyBobLearnEMPLDATrainer_enroll(PyBobLearnEMPLDATrainerObject* self, PyObject* args, PyObject* kwargs) { - BOB_TRY - - /* Parses input arguments in a single shot */ - char** kwlist = enroll.kwlist(0); - - PyBobLearnEMPLDAMachineObject* plda_machine = 0; - PyBlitzArrayObject* data = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMPLDAMachine_Type, &plda_machine, - &PyBlitzArray_Converter, &data)) return 0; - - auto data_ = make_safe(data); - self->cxx->enroll(*plda_machine->cxx, *PyBlitzArrayCxx_AsBlitz<double,2>(data)); - - BOB_CATCH_MEMBER("cannot perform the enroll method", 0) - - Py_RETURN_NONE; -} - - -/*** is_similar_to ***/ -static auto is_similar_to = bob::extension::FunctionDoc( - "is_similar_to", - - "Compares this PLDATrainer with the ``other`` one to be approximately the same.", - "The optional values ``r_epsilon`` and ``a_epsilon`` refer to the " - "relative and absolute precision for the ``weights``, ``biases`` " - "and any other values internal to this machine." -) -.add_prototype("other, [r_epsilon], [a_epsilon]","output") -.add_parameter("other", ":py:class:`bob.learn.em.PLDAMachine`", "A PLDAMachine object to be compared.") -.add_parameter("r_epsilon", "float", "Relative precision.") -.add_parameter("a_epsilon", "float", "Absolute precision.") -.add_return("output","bool","True if it is similar, otherwise false."); -static PyObject* PyBobLearnEMPLDATrainer_IsSimilarTo(PyBobLearnEMPLDATrainerObject* self, PyObject* args, PyObject* kwds) { - - /* Parses input arguments in a single shot */ - char** kwlist = is_similar_to.kwlist(0); - - //PyObject* other = 0; - PyBobLearnEMPLDATrainerObject* other = 0; - double r_epsilon = 1.e-5; - double a_epsilon = 1.e-8; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|dd", kwlist, - &PyBobLearnEMPLDATrainer_Type, &other, - &r_epsilon, &a_epsilon)){ - - is_similar_to.print_usage(); - return 0; - } - - if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - - - -static PyMethodDef PyBobLearnEMPLDATrainer_methods[] = { - { - initialize.name(), - (PyCFunction)PyBobLearnEMPLDATrainer_initialize, - METH_VARARGS|METH_KEYWORDS, - initialize.doc() - }, - { - e_step.name(), - (PyCFunction)PyBobLearnEMPLDATrainer_e_step, - METH_VARARGS|METH_KEYWORDS, - e_step.doc() - }, - { - m_step.name(), - (PyCFunction)PyBobLearnEMPLDATrainer_m_step, - METH_VARARGS|METH_KEYWORDS, - m_step.doc() - }, - { - finalize.name(), - (PyCFunction)PyBobLearnEMPLDATrainer_finalize, - METH_VARARGS|METH_KEYWORDS, - finalize.doc() - }, - { - enroll.name(), - (PyCFunction)PyBobLearnEMPLDATrainer_enroll, - METH_VARARGS|METH_KEYWORDS, - enroll.doc() - }, - { - is_similar_to.name(), - (PyCFunction)PyBobLearnEMPLDATrainer_IsSimilarTo, - METH_VARARGS|METH_KEYWORDS, - is_similar_to.doc() - }, - {0} /* Sentinel */ -}; - - -/******************************************************************/ -/************ Module Section **************************************/ -/******************************************************************/ - -// Define the Gaussian type struct; will be initialized later -PyTypeObject PyBobLearnEMPLDATrainer_Type = { - PyVarObject_HEAD_INIT(0,0) - 0 -}; - -bool init_BobLearnEMPLDATrainer(PyObject* module) -{ - // initialize the type struct - PyBobLearnEMPLDATrainer_Type.tp_name = PLDATrainer_doc.name(); - PyBobLearnEMPLDATrainer_Type.tp_basicsize = sizeof(PyBobLearnEMPLDATrainerObject); - PyBobLearnEMPLDATrainer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;//Enable the class inheritance; - PyBobLearnEMPLDATrainer_Type.tp_doc = PLDATrainer_doc.doc(); - - // set the functions - PyBobLearnEMPLDATrainer_Type.tp_new = PyType_GenericNew; - PyBobLearnEMPLDATrainer_Type.tp_init = reinterpret_cast<initproc>(PyBobLearnEMPLDATrainer_init); - PyBobLearnEMPLDATrainer_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobLearnEMPLDATrainer_delete); - PyBobLearnEMPLDATrainer_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnEMPLDATrainer_RichCompare); - PyBobLearnEMPLDATrainer_Type.tp_methods = PyBobLearnEMPLDATrainer_methods; - PyBobLearnEMPLDATrainer_Type.tp_getset = PyBobLearnEMPLDATrainer_getseters; - //PyBobLearnEMPLDATrainer_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnEMPLDATrainer_compute_likelihood); - - - // check that everything is fine - if (PyType_Ready(&PyBobLearnEMPLDATrainer_Type) < 0) return false; - - // add the type to the module - Py_INCREF(&PyBobLearnEMPLDATrainer_Type); - return PyModule_AddObject(module, "PLDATrainer", (PyObject*)&PyBobLearnEMPLDATrainer_Type) >= 0; -} diff --git a/bob/learn/em/train.py b/bob/learn/em/train.py deleted file mode 100644 index e0e500ba8a2dacdc4f76ee0f5bcacbf9848cb9cd..0000000000000000000000000000000000000000 --- a/bob/learn/em/train.py +++ /dev/null @@ -1,247 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Tiago de Freitas Pereira <tiago.pereira@idiap.ch> -# Fri Feb 13 13:18:10 2015 +0200 -# -# Copyright (C) 2011-2015 Idiap Research Institute, Martigny, Switzerland -import numpy -from ._library import * -import logging -from multiprocessing.pool import ThreadPool - -logger = logging.getLogger(__name__) - - -def _set_average(trainer, trainers, machine, data, trainer_type): - """_set_average(trainer, data) -> None - - This function computes the average of the given data and sets it to the given machine. - - This function works for different types of trainers, and can be used to parallelize the training. - For some trainers, the data is returned instead of set in the trainer. - - **Parameters:** - - trainer : one of :py:class:`KMeansTrainer`, :py:class:`MAP_GMMTrainer`, :py:class:`ML_GMMTrainer`, :py:class:`ISVTrainer`, :py:class:`IVectorTrainer`, :py:class:`PLDATrainer`, :py:class:`EMPCATrainer` - The trainer to set the data to. - - trainers : [ trainer ] - The list of trainer objects that were used in the parallel training process. - All trainers must be of the same class as the ``trainer``. - - data : [ object ] - The list of data objects that should be set to the trainer. - Usually this list is generated by parallelizing the e-step of the ``trainer``. - """ - - if trainer_type == "KMeansTrainer": - # K-Means statistics - trainer.reset_accumulators(machine) - for t in trainers: - trainer.zeroeth_order_statistics = trainer.zeroeth_order_statistics + t.zeroeth_order_statistics - trainer.first_order_statistics = trainer.first_order_statistics + t.first_order_statistics - trainer.average_min_distance = trainer.average_min_distance + t.average_min_distance - - trainer.average_min_distance /= data.shape[0] - - elif trainer_type in ("ML_GMMTrainer", "MAP_GMMTrainer"): - # GMM statistics - trainer.gmm_statistics = trainers[0].gmm_statistics - for t in trainers[1:]: - trainer.gmm_statistics += t.gmm_statistics - - elif trainer_type == "IVectorTrainer": - # GMM statistics - trainer.reset_accumulators(machine) - trainer.acc_fnormij_wij = trainers[0].acc_fnormij_wij - trainer.acc_nij_wij2 = trainers[0].acc_nij_wij2 - trainer.acc_nij = trainers[0].acc_nij - trainer.acc_snormij = trainers[0].acc_snormij - - for t in trainers[1:]: - trainer.acc_fnormij_wij = trainer.acc_fnormij_wij + t.acc_fnormij_wij - trainer.acc_nij_wij2 = trainer.acc_nij_wij2 + t.acc_nij_wij2 - trainer.acc_nij = trainer.acc_nij + t.acc_nij - trainer.acc_snormij = trainer.acc_snormij + t.acc_snormij - - - else: - raise NotImplementedError("Implement Me!") - - -def _parallel_e_step(args): - """This function applies the e_step of the given trainer (first argument) on the given data (second argument). - It is called by each parallel process. - """ - trainer, machine, data = args - trainer.e_step(machine, data) - - -def train(trainer, machine, data, max_iterations=50, convergence_threshold=None, initialize=True, rng=None, check_inputs=True, pool=None, trainer_type=None): - - """ - Trains a machine given a trainer and the proper data - - **Parameters**: - trainer : one of :py:class:`KMeansTrainer`, :py:class:`MAP_GMMTrainer`, :py:class:`ML_GMMTrainer`, :py:class:`ISVTrainer`, :py:class:`IVectorTrainer`, :py:class:`PLDATrainer`, :py:class:`EMPCATrainer` - A trainer mechanism - machine : one of :py:class:`KMeansMachine`, :py:class:`GMMMachine`, :py:class:`ISVBase`, :py:class:`IVectorMachine`, :py:class:`PLDAMachine`, :py:class:`bob.learn.linear.Machine` - A container machine - data : array_like <float, 2D> - The data to be trained - max_iterations : int - The maximum number of iterations to train a machine - convergence_threshold : float - The convergence threshold to train a machine. If None, the training procedure will stop with the iterations criteria - initialize : bool - If True, runs the initialization procedure - rng : :py:class:`bob.core.random.mt19937` - The Mersenne Twister mt19937 random generator used for the initialization of subspaces/arrays before the EM loop - check_inputs: - Shallow checks in the inputs. Check for inf and NaN - pool : ``int`` or ``multiprocessing.ThreadPool`` or ``None`` - If given, the provided process pool will be used to parallelize the M-step of the - EM algorithm. You should provide a ThreadPool not a multi process Pool. If pool is - an integer, it will be used to create a ThreadPool with that many processes. - trainer_type : ``str`` or ``None`` - This is used for the parallel e_step method to see how several processes' data can - be merged into one trainer before the m_step. By default - ``trainer.__class__.__name__`` is used. This is useful if you have custom trainers - and want to use this function. - """ - if check_inputs and isinstance(data, numpy.ndarray): - sum_data = numpy.sum(data) - - if numpy.isinf(sum_data): - raise ValueError("Please, check your inputs; numpy.inf detected in `data` ") - - if numpy.isnan(sum_data): - raise ValueError("Please, check your inputs; numpy.nan detected in `data` ") - - if isinstance(pool, int): - pool = ThreadPool(pool) - - if trainer_type is None: - trainer_type = trainer.__class__.__name__ - - def _e_step(trainer, machine, data): - - # performs the e-step, possibly in parallel - if pool is None: - # use only one core - trainer.e_step(machine, data) - else: - - # use the given process pool - n_processes = pool._processes - - # Mapping references of the data - split_data = [] - offset = 0 - - step = int(len(data) // n_processes) - - for p in range(n_processes): - if p == n_processes - 1: - # take all the data in the last chunk - split_data.append(data[offset:]) - else: - split_data.append(data[offset: offset + step]) - - offset += step - - # create trainers for each process - trainers = [trainer.__class__(trainer) for p in range(n_processes)] - # no need to copy the machines - machines = [machine.__class__(machine) for p in range(n_processes)] - # call the parallel processes - pool.map(_parallel_e_step, zip(trainers, machines, split_data)) - # update the trainer with the data of the other trainers - _set_average(trainer, trainers, machine, data, trainer_type) - - # Initialization - if initialize: - if rng is not None: - trainer.initialize(machine, data, rng) - else: - trainer.initialize(machine, data) - - _e_step(trainer, machine, data) - average_output = 0 - average_output_previous = 0 - - if hasattr(trainer,"compute_likelihood"): - average_output = trainer.compute_likelihood(machine) - - for i in range(max_iterations): - logger.info("Iteration = %d/%d", i, max_iterations) - average_output_previous = average_output - trainer.m_step(machine, data) - _e_step(trainer, machine,data) - - if hasattr(trainer,"compute_likelihood"): - average_output = trainer.compute_likelihood(machine) - - if isinstance(machine, KMeansMachine): - logger.info("average euclidean distance = %f", average_output) - else: - logger.info("log likelihood = %f", average_output) - - convergence_value = abs((average_output_previous - average_output)/average_output_previous) - logger.info("convergence value = %f",convergence_value) - - #Terminates if converged (and likelihood computation is set) - if convergence_threshold is not None and convergence_value <= convergence_threshold: - break - if hasattr(trainer,"finalize"): - trainer.finalize(machine, data) - - -def train_jfa(trainer, jfa_base, data, max_iterations=10, initialize=True, rng=None): - """ - Trains a :py:class:`bob.learn.em.JFABase` given a :py:class:`bob.learn.em.JFATrainer` and the proper data - - **Parameters**: - trainer : :py:class:`bob.learn.em.JFATrainer` - A JFA trainer mechanism - jfa_base : :py:class:`bob.learn.em.JFABase` - A container machine - data : [[:py:class:`bob.learn.em.GMMStats`]] - The data to be trained - max_iterations : int - The maximum number of iterations to train a machine - initialize : bool - If True, runs the initialization procedure - rng : :py:class:`bob.core.random.mt19937` - The Mersenne Twister mt19937 random generator used for the initialization of subspaces/arrays before the EM loops - """ - - if initialize: - if rng is not None: - trainer.initialize(jfa_base, data, rng) - else: - trainer.initialize(jfa_base, data) - - # V Subspace - logger.info("V subspace estimation...") - for i in range(max_iterations): - logger.info("Iteration = %d/%d", i, max_iterations) - trainer.e_step_v(jfa_base, data) - trainer.m_step_v(jfa_base, data) - trainer.finalize_v(jfa_base, data) - - # U subspace - logger.info("U subspace estimation...") - for i in range(max_iterations): - logger.info("Iteration = %d/%d", i, max_iterations) - trainer.e_step_u(jfa_base, data) - trainer.m_step_u(jfa_base, data) - trainer.finalize_u(jfa_base, data) - - # D subspace - logger.info("D subspace estimation...") - for i in range(max_iterations): - logger.info("Iteration = %d/%d", i, max_iterations) - trainer.e_step_d(jfa_base, data) - trainer.m_step_d(jfa_base, data) - trainer.finalize_d(jfa_base, data) diff --git a/bob/learn/em/version.cpp b/bob/learn/em/version.cpp deleted file mode 100644 index 866894fb97b991c1124d6f0766684056d719a1ba..0000000000000000000000000000000000000000 --- a/bob/learn/em/version.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * @date Mon Apr 14 20:43:48 CEST 2014 - * - * @brief Binds configuration information available from bob - */ - -#include <bob.learn.em/config.h> - -#define BOB_IMPORT_VERSION -#include <bob.blitz/config.h> -#include <bob.blitz/cleanup.h> -#include <bob.core/config.h> -#include <bob.io.base/config.h> -#include <bob.sp/config.h> -#include <bob.math/config.h> -#include <bob.learn.activation/config.h> -#include <bob.learn.linear/config.h> - - -static PyObject* build_version_dictionary() { - - PyObject* retval = PyDict_New(); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - if (!dict_steal(retval, "Blitz++", blitz_version())) return 0; - if (!dict_steal(retval, "Boost", boost_version())) return 0; - if (!dict_steal(retval, "Compiler", compiler_version())) return 0; - if (!dict_steal(retval, "Python", python_version())) return 0; - if (!dict_steal(retval, "NumPy", numpy_version())) return 0; - if (!dict_steal(retval, "HDF5", hdf5_version())) return 0; - if (!dict_steal(retval, "bob.blitz", bob_blitz_version())) return 0; - if (!dict_steal(retval, "bob.core", bob_core_version())) return 0; - if (!dict_steal(retval, "bob.io.base", bob_io_base_version())) return 0; - if (!dict_steal(retval, "bob.sp", bob_sp_version())) return 0; - if (!dict_steal(retval, "bob.math", bob_math_version())) return 0; - if (!dict_steal(retval, "bob.learn.activation", bob_learn_activation_version())) return 0; - if (!dict_steal(retval, "bob.learn.linear", bob_learn_linear_version())) return 0; - - return Py_BuildValue("O", retval); -} - -static PyMethodDef module_methods[] = { - {0} /* Sentinel */ -}; - -PyDoc_STRVAR(module_docstr, -"Information about software used to compile the C++ Bob API" -); - -#if PY_VERSION_HEX >= 0x03000000 -static PyModuleDef module_definition = { - PyModuleDef_HEAD_INIT, - BOB_EXT_MODULE_NAME, - module_docstr, - -1, - module_methods, - 0, 0, 0, 0 -}; -#endif - -static PyObject* create_module (void) { - -# if PY_VERSION_HEX >= 0x03000000 - PyObject* module = PyModule_Create(&module_definition); - auto module_ = make_xsafe(module); - const char* ret = "O"; -# else - PyObject* module = Py_InitModule3(BOB_EXT_MODULE_NAME, module_methods, module_docstr); - const char* ret = "N"; -# endif - if (!module) return 0; - - /* register version numbers and constants */ - if (PyModule_AddIntConstant(module, "api", BOB_LEARN_EM_API_VERSION) < 0) return 0; - if (PyModule_AddStringConstant(module, "module", BOB_EXT_MODULE_VERSION) < 0) return 0; - - PyObject* externals = build_version_dictionary(); - if (!externals) return 0; - if (PyModule_AddObject(module, "externals", externals) < 0) return 0; - - return Py_BuildValue(ret, module); -} - -PyMODINIT_FUNC BOB_EXT_ENTRY_NAME (void) { -# if PY_VERSION_HEX >= 0x03000000 - return -# endif - create_module(); -} diff --git a/conda/meta.yaml b/conda/meta.yaml index eb5cdbab872ca7f7ed1173c78b3e7fcfb4f67abe..63afbcb92f75faeb62613c9211eed90d07a6543a 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -17,32 +17,21 @@ build: - python setup.py install --single-version-externally-managed --record record.txt requirements: - build: - - {{ compiler('c') }} - - {{ compiler('cxx') }} - - pkg-config {{ pkg_config }} - - cmake {{ cmake }} - - make {{ make }} host: - python {{ python }} - setuptools {{ setuptools }} - bob.extension - bob.blitz - - bob.core >2.0.5 - bob.io.base - bob.sp - - bob.math - bob.learn.activation - bob.learn.linear - - libblitz {{ libblitz }} - - boost {{ boost }} - numpy {{ numpy }} - dask {{ dask }} - dask-ml {{ dask_ml }} run: - python - setuptools - - boost - {{ pin_compatible('numpy') }} - {{ pin_compatible('dask') }} - {{ pin_compatible('dask-ml') }} diff --git a/develop.cfg b/develop.cfg index 40bd10aa0e2846152a12010f8c5ee123d60b95f9..8058224ef600e2139e69947bd2f99842e5fb1e75 100644 --- a/develop.cfg +++ b/develop.cfg @@ -10,11 +10,8 @@ extensions = bob.buildout auto-checkout = * develop = src/bob.extension - src/bob.blitz - src/bob.core src/bob.io.base src/bob.sp - src/bob.math src/bob.learn.activation src/bob.learn.linear . @@ -26,11 +23,8 @@ newest = false [sources] bob.extension = git https://gitlab.idiap.ch/bob/bob.extension -bob.blitz = git https://gitlab.idiap.ch/bob/bob.blitz -bob.core = git https://gitlab.idiap.ch/bob/bob.core bob.io.base = git https://gitlab.idiap.ch/bob/bob.io.base bob.sp = git https://gitlab.idiap.ch/bob/bob.sp -bob.math = git https://gitlab.idiap.ch/bob/bob.math bob.learn.activation = git https://gitlab.idiap.ch/bob/bob.learn.activation bob.learn.linear = git https://gitlab.idiap.ch/bob/bob.learn.linear diff --git a/requirements.txt b/requirements.txt index ddb7e6e216a56cd8784e952a1b15fce46553bedd..699a028be46754a7d43b80cb3e64ce9bf46cbc8d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,6 @@ setuptools bob.extension -bob.blitz -bob.core > 2.0.5 bob.io.base bob.sp -bob.math > 2 bob.learn.activation bob.learn.linear diff --git a/setup.py b/setup.py index 3528a1dcc0624d904f58acbb179f938642fa315f..732b0d949db969ed12a8ff6676e3d5115385ff5f 100644 --- a/setup.py +++ b/setup.py @@ -3,14 +3,17 @@ # Andre Anjos <andre.anjos@idiap.ch> # Mon 16 Apr 08:18:08 2012 CEST +from setuptools import dist +from setuptools import setup + +from bob.extension.utils import find_packages +from bob.extension.utils import load_requirements + bob_packages = ['bob.core', 'bob.io.base', 'bob.sp', 'bob.math', 'bob.learn.activation', 'bob.learn.linear'] +dist.Distribution(dict(setup_requires=['bob.extension>=2.0.7'] + bob_packages)) -from setuptools import setup, find_packages, dist -dist.Distribution(dict(setup_requires=['bob.extension>=2.0.7', 'bob.blitz'] + bob_packages)) -from bob.blitz.extension import Extension, Library, build_ext -from bob.extension.utils import load_requirements -build_requires = load_requirements() +install_requires = load_requirements() # Define package version version = open("version.txt").read().rstrip() @@ -27,6 +30,7 @@ setup( license='BSD', author='Andre Anjos', author_email='andre.anjos@idiap.ch', + keywords="bob, em, expectation-maximization", long_description=open('README.rst').read(), @@ -34,109 +38,17 @@ setup( include_package_data=True, zip_safe=False, - setup_requires = build_requires, - install_requires = build_requires, - - - - ext_modules = [ - Extension("bob.learn.em.version", - [ - "bob/learn/em/version.cpp", - ], - bob_packages = bob_packages, - packages = packages, - boost_modules = boost_modules, - version = version, - ), - - Library("bob.learn.em.bob_learn_em", - [ - "bob/learn/em/cpp/Gaussian.cpp", - "bob/learn/em/cpp/GMMMachine.cpp", - "bob/learn/em/cpp/GMMStats.cpp", - "bob/learn/em/cpp/IVectorMachine.cpp", - "bob/learn/em/cpp/KMeansMachine.cpp", - "bob/learn/em/cpp/LinearScoring.cpp", - "bob/learn/em/cpp/PLDAMachine.cpp", - - "bob/learn/em/cpp/FABase.cpp", - "bob/learn/em/cpp/JFABase.cpp", - "bob/learn/em/cpp/ISVBase.cpp", - "bob/learn/em/cpp/JFAMachine.cpp", - "bob/learn/em/cpp/ISVMachine.cpp", - - "bob/learn/em/cpp/FABaseTrainer.cpp", - "bob/learn/em/cpp/JFATrainer.cpp", - "bob/learn/em/cpp/ISVTrainer.cpp", - - "bob/learn/em/cpp/EMPCATrainer.cpp", - "bob/learn/em/cpp/GMMBaseTrainer.cpp", - "bob/learn/em/cpp/IVectorTrainer.cpp", - "bob/learn/em/cpp/KMeansTrainer.cpp", - "bob/learn/em/cpp/MAP_GMMTrainer.cpp", - "bob/learn/em/cpp/ML_GMMTrainer.cpp", - "bob/learn/em/cpp/PLDATrainer.cpp", - ], - bob_packages = bob_packages, - packages = packages, - boost_modules = boost_modules, - version = version, - ), - - Extension("bob.learn.em._library", - [ - "bob/learn/em/gaussian.cpp", - "bob/learn/em/gmm_stats.cpp", - "bob/learn/em/gmm_machine.cpp", - "bob/learn/em/kmeans_machine.cpp", - "bob/learn/em/kmeans_trainer.cpp", - - "bob/learn/em/ml_gmm_trainer.cpp", - "bob/learn/em/map_gmm_trainer.cpp", - - "bob/learn/em/jfa_base.cpp", - "bob/learn/em/jfa_machine.cpp", - "bob/learn/em/jfa_trainer.cpp", - - "bob/learn/em/isv_base.cpp", - "bob/learn/em/isv_machine.cpp", - "bob/learn/em/isv_trainer.cpp", - - "bob/learn/em/ivector_machine.cpp", - "bob/learn/em/ivector_trainer.cpp", - - "bob/learn/em/plda_base.cpp", - "bob/learn/em/plda_machine.cpp", - - "bob/learn/em/empca_trainer.cpp", - - "bob/learn/em/plda_trainer.cpp", - - "bob/learn/em/linear_scoring.cpp", - - "bob/learn/em/main.cpp", - ], - bob_packages = bob_packages, - packages = packages, - boost_modules = boost_modules, - version = version, - ), - ], - - cmdclass = { - 'build_ext': build_ext - }, - - classifiers = [ - 'Framework :: Bob', - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Natural Language :: English', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Topic :: Software Development :: Libraries :: Python Modules', + install_requires = install_requires, + + classifiers=[ + 'Framework :: Bob', + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: BSD License', + 'Natural Language :: English', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Topic :: Software Development :: Libraries :: Python Modules', ], - ) +)