diff --git a/bob/learn/misc/ML_gmm_trainer.cpp b/bob/learn/misc/ML_gmm_trainer.cpp index b0b2379fe9cc85692c69f701b7eb56700b30b93a..f9a45980127c59c9b489308cc692501b54cbc254 100644 --- a/bob/learn/misc/ML_gmm_trainer.cpp +++ b/bob/learn/misc/ML_gmm_trainer.cpp @@ -13,8 +13,6 @@ /************ 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 of the expectation-maximisation algorithm for a GMM Machine." diff --git a/bob/learn/misc/cpp/PLDAMachine.cpp b/bob/learn/misc/cpp/PLDAMachine.cpp index 0009dafc1206b2c8beb08ef36a2f658ddc66a0be..4193c85591b799e718dd93fdafb7707ab6d8650e 100644 --- a/bob/learn/misc/cpp/PLDAMachine.cpp +++ b/bob/learn/misc/cpp/PLDAMachine.cpp @@ -807,22 +807,22 @@ void bob::learn::misc::PLDAMachine::clearMaps() m_cache_loglike_constterm.clear(); } -void bob::learn::misc::PLDAMachine::forward(const blitz::Array<double,1>& sample, double& score) const +double bob::learn::misc::PLDAMachine::forward(const blitz::Array<double,1>& sample) { - forward_(sample,score); + return forward_(sample); } -void bob::learn::misc::PLDAMachine::forward_(const blitz::Array<double,1>& sample, double& score) const +double bob::learn::misc::PLDAMachine::forward_(const blitz::Array<double,1>& sample) { // Computes the log likelihood ratio - score = computeLogLikelihood(sample, true) - // match + return computeLogLikelihood(sample, true) - // match (computeLogLikelihood(sample, false) + m_loglikelihood); // no match } -void bob::learn::misc::PLDAMachine::forward(const blitz::Array<double,2>& samples, double& score) const +double bob::learn::misc::PLDAMachine::forward(const blitz::Array<double,2>& samples) { // Computes the log likelihood ratio - score = computeLogLikelihood(samples, true) - // match + return computeLogLikelihood(samples, true) - // match (computeLogLikelihood(samples, false) + m_loglikelihood); // no match } diff --git a/bob/learn/misc/include/bob.learn.misc/PLDAMachine.h b/bob/learn/misc/include/bob.learn.misc/PLDAMachine.h index ad935f0a386a4f136f0bff59af0ceeb2ddd9ce83..c75085781480758c75ff3652470cf595afef6da5 100644 --- a/bob/learn/misc/include/bob.learn.misc/PLDAMachine.h +++ b/bob/learn/misc/include/bob.learn.misc/PLDAMachine.h @@ -641,9 +641,9 @@ class PLDAMachine /** * @brief Computes a log likelihood ratio from a 1D or 2D blitz::Array */ - void forward(const blitz::Array<double,1>& sample, double& score) const; - void forward_(const blitz::Array<double,1>& sample, double& score) const; - void forward(const blitz::Array<double,2>& samples, double& score) const; + 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: diff --git a/bob/learn/misc/plda_base.cpp b/bob/learn/misc/plda_base.cpp index 32f0f6f8be6b2db30ac64b299157a82a823a5dee..11c893cc44dc1b325a841871a2a6fed8073d6be4 100644 --- a/bob/learn/misc/plda_base.cpp +++ b/bob/learn/misc/plda_base.cpp @@ -120,7 +120,7 @@ static int PyBobLearnMiscPLDABase_init(PyBobLearnMiscPLDABaseObject* self, PyObj // 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; @@ -382,6 +382,62 @@ static PyObject* PyBobLearnMiscPLDABase_getLogDetSigma(PyBobLearnMiscPLDABaseObj } +/***** variance_threshold *****/ +static auto variance_threshold = bob::extension::VariableDoc( + "variance_threshold", + "double", + "", + "" +); +static PyObject* PyBobLearnMiscPLDABase_getVarianceThreshold(PyBobLearnMiscPLDABaseObject* 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 PyBobLearnMiscPLDABase_setVarianceThreshold(PyBobLearnMiscPLDABaseObject* self, PyObject* value, void*){ + BOB_TRY + + if (!PyNumber_Check(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* PyBobLearnMiscPLDABase_getSigma(PyBobLearnMiscPLDABaseObject* self, PyObject* args, PyObject* kwargs) { + BOB_TRY + return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getSigma()); + BOB_CATCH_MEMBER("sigma could not be read", 0) +} +int PyBobLearnMiscPLDABase_setSigma(PyBobLearnMiscPLDABaseObject* 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 PyBobLearnMiscPLDABase_getseters[] = { { shape.name(), @@ -460,7 +516,20 @@ static PyGetSetDef PyBobLearnMiscPLDABase_getseters[] = { __logdet_sigma__.doc(), 0 }, - + { + sigma.name(), + (getter)PyBobLearnMiscPLDABase_getSigma, + (setter)PyBobLearnMiscPLDABase_setSigma, + sigma.doc(), + 0 + }, + { + variance_threshold.name(), + (getter)PyBobLearnMiscPLDABase_getVarianceThreshold, + (setter)PyBobLearnMiscPLDABase_setVarianceThreshold, + variance_threshold.doc(), + 0 + }, {0} // Sentinel }; @@ -598,9 +667,9 @@ static PyObject* PyBobLearnMiscPLDABase_resize(PyBobLearnMiscPLDABaseObject* sel } -/***** gamma *****/ -static auto gamma_var = bob::extension::FunctionDoc( - "gamma", +/***** 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, @@ -612,13 +681,13 @@ static auto gamma_var = bob::extension::FunctionDoc( static PyObject* PyBobLearnMiscPLDABase_getGamma(PyBobLearnMiscPLDABaseObject* self, PyObject* args, PyObject* kwargs) { BOB_TRY - char** kwlist = gamma_var.kwlist(0); + char** kwlist = get_gamma.kwlist(0); int i = 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) Py_RETURN_NONE; return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getGamma(i)); - BOB_CATCH_MEMBER("`gamma` could not be read", 0) + BOB_CATCH_MEMBER("`get_gamma` could not be read", 0) } @@ -915,10 +984,10 @@ static PyMethodDef PyBobLearnMiscPLDABase_methods[] = { resize.doc() }, { - gamma_var.name(), + get_gamma.name(), (PyCFunction)PyBobLearnMiscPLDABase_getGamma, METH_VARARGS|METH_KEYWORDS, - gamma_var.doc() + get_gamma.doc() }, { has_gamma.name(), diff --git a/bob/learn/misc/plda_machine.cpp b/bob/learn/misc/plda_machine.cpp index 386b080a23c7ab4e7edc89104c2fd73f41fcaaed..6bfdf0b8b307f46af6022473e858f71c1a16d885 100644 --- a/bob/learn/misc/plda_machine.cpp +++ b/bob/learn/misc/plda_machine.cpp @@ -13,6 +13,8 @@ /************ 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", @@ -181,7 +183,7 @@ static auto n_samples = bob::extension::VariableDoc( ); static PyObject* PyBobLearnMiscPLDAMachine_getNSamples(PyBobLearnMiscPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { BOB_TRY - return Py_BuildValue("d",self->cxx->getNSamples()); + return Py_BuildValue("i",self->cxx->getNSamples()); BOB_CATCH_MEMBER("n_samples could not be read", 0) } int PyBobLearnMiscPLDAMachine_setNSamples(PyBobLearnMiscPLDAMachineObject* self, PyObject* value, void*){ @@ -228,6 +230,99 @@ int PyBobLearnMiscPLDAMachine_setWSumXitBetaXi(PyBobLearnMiscPLDAMachineObject* return 0; } + +/***** plda_base *****/ +static auto plda_base = bob::extension::VariableDoc( + "plda_base", + ":py:class:`bob.learn.misc.PLDABase`", + "The PLDABase attached to this machine", + "" +); +PyObject* PyBobLearnMiscPLDAMachine_getPLDABase(PyBobLearnMiscPLDAMachineObject* self, void*){ + BOB_TRY + + boost::shared_ptr<bob::learn::misc::PLDABase> plda_base_o = self->cxx->getPLDABase(); + + //Allocating the correspondent python object + PyBobLearnMiscPLDABaseObject* retval = + (PyBobLearnMiscPLDABaseObject*)PyBobLearnMiscPLDABase_Type.tp_alloc(&PyBobLearnMiscPLDABase_Type, 0); + retval->cxx = plda_base_o; + + return Py_BuildValue("O",retval); + BOB_CATCH_MEMBER("plda_base could not be read", 0) +} +int PyBobLearnMiscPLDAMachine_setPLDABase(PyBobLearnMiscPLDAMachineObject* self, PyObject* value, void*){ + BOB_TRY + + if (!PyBobLearnMiscPLDABase_Check(value)){ + PyErr_Format(PyExc_RuntimeError, "%s %s expects a :py:class:`bob.learn.misc.PLDABase`", Py_TYPE(self)->tp_name, plda_base.name()); + return -1; + } + + PyBobLearnMiscPLDABaseObject* plda_base_o = 0; + PyArg_Parse(value, "O!", &PyBobLearnMiscPLDABase_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* PyBobLearnMiscPLDAMachine_getWeightedSum(PyBobLearnMiscPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { + BOB_TRY + return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getWeightedSum()); + BOB_CATCH_MEMBER("weighted_sum could not be read", 0) +} +int PyBobLearnMiscPLDAMachine_setWeightedSum(PyBobLearnMiscPLDAMachineObject* 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", + "double", + "", + "" +); +static PyObject* PyBobLearnMiscPLDAMachine_getLogLikelihood(PyBobLearnMiscPLDAMachineObject* 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 PyBobLearnMiscPLDAMachine_setLogLikelihood(PyBobLearnMiscPLDAMachineObject* self, PyObject* value, void*){ + BOB_TRY + + if (!PyNumber_Check(value)){ + PyErr_Format(PyExc_RuntimeError, "%s %s expects an double", 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 PyBobLearnMiscPLDAMachine_getseters[] = { { shape.name(), @@ -250,6 +345,27 @@ static PyGetSetDef PyBobLearnMiscPLDAMachine_getseters[] = { w_sum_xit_beta_xi.doc(), 0 }, + { + plda_base.name(), + (getter)PyBobLearnMiscPLDAMachine_getPLDABase, + (setter)PyBobLearnMiscPLDAMachine_setPLDABase, + plda_base.doc(), + 0 + }, + { + weighted_sum.name(), + (getter)PyBobLearnMiscPLDAMachine_getWeightedSum, + (setter)PyBobLearnMiscPLDAMachine_setWeightedSum, + weighted_sum.doc(), + 0 + }, + { + log_likelihood.name(), + (getter)PyBobLearnMiscPLDAMachine_getLogLikelihood, + (setter)PyBobLearnMiscPLDAMachine_setLogLikelihood, + log_likelihood.doc(), + 0 + }, {0} // Sentinel }; @@ -344,9 +460,9 @@ static PyObject* PyBobLearnMiscPLDAMachine_IsSimilarTo(PyBobLearnMiscPLDAMachine } -/***** gamma *****/ -static auto gamma_var = bob::extension::FunctionDoc( - "gamma", +/***** 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, @@ -358,13 +474,13 @@ static auto gamma_var = bob::extension::FunctionDoc( static PyObject* PyBobLearnMiscPLDAMachine_getGamma(PyBobLearnMiscPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { BOB_TRY - char** kwlist = gamma_var.kwlist(0); + char** kwlist = get_gamma.kwlist(0); int i = 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &i)) Py_RETURN_NONE; return PyBlitzArrayCxx_AsConstNumpy(self->cxx->getGamma(i)); - BOB_CATCH_MEMBER("`gamma` could not be read", 0) + BOB_CATCH_MEMBER("`get_gamma` could not be read", 0) } @@ -511,29 +627,70 @@ static PyObject* PyBobLearnMiscPLDAMachine_clearMaps(PyBobLearnMiscPLDAMachineOb /***** 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,use_enrolled_samples","output") +.add_prototype("sample,with_enrolled_samples","output") .add_parameter("sample", "array_like <float, 1D>", "Sample") -.add_parameter("use_enrolled_samples", "bool", "") +.add_parameter("with_enrolled_samples", "bool", "") .add_return("output","double","The log-likelihood"); static PyObject* PyBobLearnMiscPLDAMachine_computeLogLikelihood(PyBobLearnMiscPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { BOB_TRY char** kwlist = compute_log_likelihood.kwlist(0); + + PyBlitzArrayObject* samples; + PyObject* with_enrolled_samples = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!", kwlist, )) Py_RETURN_NONE; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|O!", kwlist, &PyBlitzArray_Converter, &samples, + &PyBool_Type, &with_enrolled_samples)) Py_RETURN_NONE; + auto samples_ = make_safe(samples); - return Py_BuildValue("d",self->cxx->getLogLikeConstTerm(i)); + blitz::Array<double,2> blitz_test = *PyBlitzArrayCxx_AsBlitz<double,2>(samples); - BOB_CATCH_MEMBER("`get_log_like_const_term` could not be read", 0) + //There are 2 methods in C++, one <double,1> and the another <double,2> + if (blitz_test.extent(1)==0) + 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) } -*/ + + +/***** forward *****/ +static auto forward = bob::extension::FunctionDoc( + "forward", + "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>", "Sample") +.add_return("output","double","The log-likelihood ratio"); +static PyObject* PyBobLearnMiscPLDAMachine_forward(PyBobLearnMiscPLDAMachineObject* self, PyObject* args, PyObject* kwargs) { + BOB_TRY + + char** kwlist = forward.kwlist(0); + + PyBlitzArrayObject* samples; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, &PyBlitzArray_Converter, &samples)) Py_RETURN_NONE; + auto samples_ = make_safe(samples); + blitz::Array<double,2> blitz_test = *PyBlitzArrayCxx_AsBlitz<double,2>(samples); + + //There are 2 methods in C++, one <double,1> and the another <double,2> + if (blitz_test.extent(1)==0) + 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("`forward` could not be read", 0) +} + static PyMethodDef PyBobLearnMiscPLDAMachine_methods[] = { { @@ -555,10 +712,10 @@ static PyMethodDef PyBobLearnMiscPLDAMachine_methods[] = { is_similar_to.doc() }, { - gamma_var.name(), + get_gamma.name(), (PyCFunction)PyBobLearnMiscPLDAMachine_getGamma, METH_VARARGS|METH_KEYWORDS, - gamma_var.doc() + get_gamma.doc() }, { has_gamma.name(), @@ -583,7 +740,7 @@ static PyMethodDef PyBobLearnMiscPLDAMachine_methods[] = { (PyCFunction)PyBobLearnMiscPLDAMachine_getAddLogLikeConstTerm, METH_VARARGS|METH_KEYWORDS, get_add_log_like_const_term.doc() - }, + }, { get_log_like_const_term.name(), (PyCFunction)PyBobLearnMiscPLDAMachine_getLogLikeConstTerm, @@ -596,6 +753,12 @@ static PyMethodDef PyBobLearnMiscPLDAMachine_methods[] = { METH_NOARGS, clear_maps.doc() }, + { + compute_log_likelihood.name(), + (PyCFunction)PyBobLearnMiscPLDAMachine_computeLogLikelihood, + METH_VARARGS|METH_KEYWORDS, + compute_log_likelihood.doc() + }, {0} /* Sentinel */ }; @@ -625,7 +788,7 @@ bool init_BobLearnMiscPLDAMachine(PyObject* module) PyBobLearnMiscPLDAMachine_Type.tp_richcompare = reinterpret_cast<richcmpfunc>(PyBobLearnMiscPLDAMachine_RichCompare); PyBobLearnMiscPLDAMachine_Type.tp_methods = PyBobLearnMiscPLDAMachine_methods; PyBobLearnMiscPLDAMachine_Type.tp_getset = PyBobLearnMiscPLDAMachine_getseters; - //PyBobLearnMiscPLDAMachine_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnMiscPLDAMachine_forward); + PyBobLearnMiscPLDAMachine_Type.tp_call = reinterpret_cast<ternaryfunc>(PyBobLearnMiscPLDAMachine_forward); // check that everything is fine diff --git a/bob/learn/misc/test_plda.py b/bob/learn/misc/test_plda.py index 1b90c1d44ab2879238e26b0231e90453fa8cf482..37f9c331de13bf3812cc4e46ba6a5d1605ba2379 100644 --- a/bob/learn/misc/test_plda.py +++ b/bob/learn/misc/test_plda.py @@ -8,12 +8,11 @@ """Tests PLDA machine """ +import numpy import os import tempfile -import math -import numpy -import numpy.linalg import nose.tools +import math import bob.io.base @@ -100,30 +99,30 @@ def compute_loglike_constterm(F, G, sigma, a): def compute_log_likelihood_point_estimate(observation, mu, F, G, sigma, hi, wij): """ This function computes p(x_{ij} | h_{i}, w_{ij}, \Theta), which is given by - N_{x}[\mu + Fh_{i} + Gw_{ij} + epsilon_{ij}, \Sigma], N_{x} being a - Gaussian distribution. As it returns the corresponding log likelihood, - this is given by the sum of the following three terms: - C1 = -dim_d/2 log(2pi) - C2 = -1/2 log(det(\Sigma)) - C3 = -1/2 (x_{ij}-\mu-Fh_{i}-Gw_{ij})^{T}\Sigma^{-1}(x_{ij}-\mu-Fh_{i}-Gw_{ij}) + N_{x}[\mu + Fh_{i} + Gw_{ij} + epsilon_{ij}, \Sigma], N_{x} being a + Gaussian distribution. As it returns the corresponding log likelihood, + this is given by the sum of the following three terms: + C1 = -dim_d/2 log(2pi) + C2 = -1/2 log(det(\Sigma)) + C3 = -1/2 (x_{ij}-\mu-Fh_{i}-Gw_{ij})^{T}\Sigma^{-1}(x_{ij}-\mu-Fh_{i}-Gw_{ij}) """ ### Pre-computes some of the constants dim_d = observation.shape[0] # A scalar - log_2pi = numpy.log(2. * numpy.pi); # A scalar - C1 = -(dim_d / 2.) * log_2pi; # A scalar - C2 = -(1. / 2.) * numpy.sum( numpy.log(sigma) ); # (dim_d, 1) + log_2pi = numpy.log(2. * numpy.pi) # A scalar + C1 = -(dim_d / 2.) * log_2pi # A scalar + C2 = -(1. / 2.) * numpy.sum( numpy.log(sigma) ) # (dim_d, 1) ### Subtract the identity and session components from the observed vector. - session_plus_identity = numpy.dot(F, hi) + numpy.dot(G, wij); - normalised_observation = numpy.reshape(observation - mu - session_plus_identity, (dim_d,1)); + session_plus_identity = numpy.dot(F, hi) + numpy.dot(G, wij) + normalised_observation = numpy.reshape(observation - mu - session_plus_identity, (dim_d,1)) ### Now calculate C3 - sigma_inverse = numpy.reshape(1. / sigma, (dim_d,1)); # (dim_d, 1) - C3 = -(1. / 2.) * numpy.sum(normalised_observation * sigma_inverse * normalised_observation); + sigma_inverse = numpy.reshape(1. / sigma, (dim_d,1)) # (dim_d, 1) + C3 = -(1. / 2.) * numpy.sum(normalised_observation * sigma_inverse * normalised_observation) ### Returns the log likelihood - log_likelihood = C1 + C2 + C3; - return (log_likelihood); + log_likelihood = C1 + C2 + C3 + return (log_likelihood) def compute_log_likelihood(observations, mu, F, G, sigma): @@ -178,7 +177,6 @@ def compute_log_likelihood(observations, mu, F, G, sigma): def test_plda_basemachine(): - # Data used for performing the tests sigma = numpy.ndarray(C_dim_d, 'float64') sigma.fill(0.01) @@ -211,27 +209,27 @@ def test_plda_basemachine(): -0.000000012993151, 0.999999999999996], 'float64').reshape(C_dim_f, C_dim_f) # Constructor tests - m = PLDABase() - assert m.dim_d == 0 - assert m.dim_f == 0 - assert m.dim_g == 0 - del m + #m = PLDABase() + #assert m.dim_d == 0 + #assert m.dim_f == 0 + #assert m.dim_g == 0 + #del m m = PLDABase(C_dim_d, C_dim_f, C_dim_g) - assert m.dim_d == C_dim_d - assert m.dim_f == C_dim_f - assert m.dim_g == C_dim_g + assert m.shape[0] == C_dim_d + assert m.shape[1] == C_dim_f + assert m.shape[2] == C_dim_g assert abs(m.variance_threshold - 0.) < 1e-10 del m m = PLDABase(C_dim_d, C_dim_f, C_dim_g, 1e-2) - assert m.dim_d == C_dim_d - assert m.dim_f == C_dim_f - assert m.dim_g == C_dim_g + assert m.shape[0] == C_dim_d + assert m.shape[1] == C_dim_f + assert m.shape[2] == C_dim_g assert abs(m.variance_threshold - 1e-2) < 1e-10 del m # Defines base machine - m = PLDABase() - m.resize(C_dim_d, C_dim_f, C_dim_g) + m = PLDABase(C_dim_d, C_dim_f, C_dim_g) + #m.resize(C_dim_d, C_dim_f, C_dim_g) # Sets the current mu, F, G and sigma m.mu = mu m.f = C_F @@ -368,7 +366,10 @@ def test_plda_basemachine_loglikelihood_pointestimate(): m.g = C_G m.sigma = sigma - assert equals(m.compute_log_likelihood_point_estimate(xij, hi, wij), compute_log_likelihood_point_estimate(xij, mu, C_F, C_G, sigma, hi, wij), 1e-6) + #assert equals(m.compute_log_likelihood_point_estimate(xij, hi, wij), compute_log_likelihood_point_estimate(xij, mu, C_F, C_G, sigma, hi, wij), 1e-6) + log_likelihood_point_estimate = m.compute_log_likelihood_point_estimate(xij, hi, wij) + log_likelihood_point_estimate_python = compute_log_likelihood_point_estimate(xij, mu, C_F, C_G, sigma, hi, wij) + assert equals(log_likelihood_point_estimate, log_likelihood_point_estimate_python, 1e-6) def test_plda_machine(): @@ -390,15 +391,15 @@ def test_plda_machine(): # Test constructors and dim getters m = PLDAMachine(mb) - assert m.dim_d == C_dim_d - assert m.dim_f == C_dim_f - assert m.dim_g == C_dim_g + assert m.shape[0] == C_dim_d + assert m.shape[1]== C_dim_f + assert m.shape[2] == C_dim_g - m0 = PLDAMachine() - m0.plda_base = mb - assert m0.dim_d == C_dim_d - assert m0.dim_f == C_dim_f - assert m0.dim_g == C_dim_g + m0 = PLDAMachine(mb) + #m0.plda_base = mb + assert m0.shape[0] == C_dim_d + assert m0.shape[1] == C_dim_f + assert m0.shape[2] == C_dim_g # Defines machine n_samples = 2 @@ -441,13 +442,13 @@ def test_plda_machine(): assert (m_loaded.has_log_like_const_term(3)) is False # Check exceptions - m_loaded2 = PLDAMachine() - m_loaded2.load(bob.io.base.HDF5File(filename)) - nose.tools.assert_raises(RuntimeError, getattr, m_loaded2, 'dim_d') - nose.tools.assert_raises(RuntimeError, getattr, m_loaded2, 'dim_f') - nose.tools.assert_raises(RuntimeError, getattr, m_loaded2, 'dim_g') - nose.tools.assert_raises(RuntimeError, m_loaded2.forward, [1.]) - nose.tools.assert_raises(RuntimeError, m_loaded2.compute_log_likelihood, [1.]) + #m_loaded2 = PLDAMachine(bob.io.base.HDF5File(filename)) + #m_loaded2.load(bob.io.base.HDF5File(filename)) + #nose.tools.assert_raises(RuntimeError, getattr, m_loaded2, 'shape') + #nose.tools.assert_raises(RuntimeError, getattr, m_loaded2, 'dim_f') + #nose.tools.assert_raises(RuntimeError, getattr, m_loaded2, 'dim_g') + #nose.tools.assert_raises(RuntimeError, m_loaded2.forward, [1.]) + #nose.tools.assert_raises(RuntimeError, m_loaded2.compute_log_likelihood, [1.]) # Clean-up os.unlink(filename) @@ -487,11 +488,11 @@ def test_plda_machine_log_likelihood_Python(): ar2_s = numpy.vstack([ar2_e, ar2_p]) m.log_likelihood = m.compute_log_likelihood(ar2_e, False) llr = m.compute_log_likelihood(ar2_s, True) - (m.compute_log_likelihood(ar2_s, False) + m.log_likelihood) - assert abs(m.forward(ar2_s) - llr) < 1e-10 + assert abs(m(ar2_s) - llr) < 1e-10 ar2_p2d = numpy.random.randn(3,C_dim_d) ar2_s2d = numpy.vstack([ar2_e, ar2_p2d]) llr2d = m.compute_log_likelihood(ar2_s2d, True) - (m.compute_log_likelihood(ar2_s2d, False) + m.log_likelihood) - assert abs(m.forward(ar2_s2d) - llr2d) < 1e-10 + assert abs(m(ar2_s2d) - llr2d) < 1e-10 def test_plda_machine_log_likelihood_Prince():