diff --git a/setup.py b/setup.py index a36ca6a1accd4d20ecd5ad1d1e639eb23631ca42..2caab539931285064815bee69241105e8bd441d2 100644 --- a/setup.py +++ b/setup.py @@ -63,11 +63,12 @@ setup( ), Extension("xbob.learn.mlp._library", [ + "xbob/learn/mlp/trainer.cpp", "xbob/learn/mlp/cxx/machine.cpp", "xbob/learn/mlp/cxx/cross_entropy.cpp", "xbob/learn/mlp/cxx/square_error.cpp", "xbob/learn/mlp/cxx/shuffler.cpp", - "xbob/learn/mlp/cxx/base_trainer.cpp", + "xbob/learn/mlp/cxx/trainer.cpp", "xbob/learn/mlp/cxx/backprop.cpp", "xbob/learn/mlp/cxx/rprop.cpp", "xbob/learn/mlp/shuffler.cpp", diff --git a/xbob/learn/mlp/cost.cpp b/xbob/learn/mlp/cost.cpp index 54bdbd8ece7739c81826780b67926b219c0d0322..fb200335a2bba2b7edca84be056e2ec5524462a0 100644 --- a/xbob/learn/mlp/cost.cpp +++ b/xbob/learn/mlp/cost.cpp @@ -516,7 +516,7 @@ static int PyBobLearnSquareError_init try { auto _actfun = reinterpret_cast<PyBobLearnActivationObject*>(actfun); - self->cxx = new bob::learn::mlp::SquareError(_actfun->cxx); + self->cxx.reset(new bob::learn::mlp::SquareError(_actfun->cxx)); } catch (std::exception& ex) { PyErr_SetString(PyExc_RuntimeError, ex.what()); @@ -536,8 +536,8 @@ static int PyBobLearnSquareError_init static void PyBobLearnSquareError_delete (PyBobLearnSquareErrorObject* self) { - self->parent.cxx = 0; - delete self->cxx; + self->parent.cxx.reset(); + self->cxx.reset(); Py_TYPE(&self->parent)->tp_free((PyObject*)self); } @@ -635,7 +635,7 @@ static int PyBobLearnCrossEntropyLoss_init try { auto _actfun = reinterpret_cast<PyBobLearnActivationObject*>(actfun); - self->cxx = new bob::learn::mlp::CrossEntropyLoss(_actfun->cxx); + self->cxx.reset(new bob::learn::mlp::CrossEntropyLoss(_actfun->cxx)); } catch (std::exception& ex) { PyErr_SetString(PyExc_RuntimeError, ex.what()); @@ -655,8 +655,8 @@ static int PyBobLearnCrossEntropyLoss_init static void PyBobLearnCrossEntropyLoss_delete (PyBobLearnCrossEntropyLossObject* self) { - self->parent.cxx = 0; - delete self->cxx; + self->parent.cxx.reset(); + self->cxx.reset(); Py_TYPE(&self->parent)->tp_free((PyObject*)self); } diff --git a/xbob/learn/mlp/cxx/backprop.cpp b/xbob/learn/mlp/cxx/backprop.cpp index f6b3388e7b5d5dfcf6586c4ee6e9d8c00cfb4cd3..d881769d6b8f6c1ce44511b2fe44e1b694e56571 100644 --- a/xbob/learn/mlp/cxx/backprop.cpp +++ b/xbob/learn/mlp/cxx/backprop.cpp @@ -16,7 +16,7 @@ bob::learn::mlp::BackProp::BackProp(size_t batch_size, boost::shared_ptr<bob::learn::mlp::Cost> cost): - bob::learn::mlp::BaseTrainer(batch_size, cost), + bob::learn::mlp::Trainer(batch_size, cost), m_learning_rate(0.1), m_momentum(0.0), m_prev_deriv(numberOfHiddenLayers() + 1), @@ -28,7 +28,7 @@ bob::learn::mlp::BackProp::BackProp(size_t batch_size, bob::learn::mlp::BackProp::BackProp(size_t batch_size, boost::shared_ptr<bob::learn::mlp::Cost> cost, const bob::learn::mlp::Machine& machine): - bob::learn::mlp::BaseTrainer(batch_size, cost, machine), + bob::learn::mlp::Trainer(batch_size, cost, machine), m_learning_rate(0.1), m_momentum(0.0), m_prev_deriv(numberOfHiddenLayers() + 1), @@ -40,7 +40,7 @@ bob::learn::mlp::BackProp::BackProp(size_t batch_size, bob::learn::mlp::BackProp::BackProp(size_t batch_size, boost::shared_ptr<bob::learn::mlp::Cost> cost, const bob::learn::mlp::Machine& machine, bool train_biases): - bob::learn::mlp::BaseTrainer(batch_size, cost, machine, train_biases), + bob::learn::mlp::Trainer(batch_size, cost, machine, train_biases), m_learning_rate(0.1), m_momentum(0.0), m_prev_deriv(numberOfHiddenLayers() + 1), @@ -52,7 +52,7 @@ bob::learn::mlp::BackProp::BackProp(size_t batch_size, bob::learn::mlp::BackProp::~BackProp() { } bob::learn::mlp::BackProp::BackProp(const BackProp& other): - bob::learn::mlp::BaseTrainer(other), + bob::learn::mlp::Trainer(other), m_learning_rate(other.m_learning_rate), m_momentum(other.m_momentum) { @@ -64,7 +64,7 @@ bob::learn::mlp::BackProp& bob::learn::mlp::BackProp::operator= (const bob::learn::mlp::BackProp& other) { if (this != &other) { - bob::learn::mlp::BaseTrainer::operator=(other); + bob::learn::mlp::Trainer::operator=(other); m_learning_rate = other.m_learning_rate; m_momentum = other.m_momentum; @@ -147,7 +147,7 @@ void bob::learn::mlp::BackProp::setPreviousBiasDerivative(const blitz::Array<dou void bob::learn::mlp::BackProp::initialize(const bob::learn::mlp::Machine& machine) { - bob::learn::mlp::BaseTrainer::initialize(machine); + bob::learn::mlp::Trainer::initialize(machine); const std::vector<blitz::Array<double,2> >& machine_weight = machine.getWeights(); diff --git a/xbob/learn/mlp/cxx/rprop.cpp b/xbob/learn/mlp/cxx/rprop.cpp index 1f080bfd084a57e135dd82e02ad337e46bc56392..09ff3fc655d67b4f4fb66b294eb948cd81f3a0c4 100644 --- a/xbob/learn/mlp/cxx/rprop.cpp +++ b/xbob/learn/mlp/cxx/rprop.cpp @@ -17,7 +17,7 @@ bob::learn::mlp::RProp::RProp(size_t batch_size, boost::shared_ptr<bob::learn::mlp::Cost> cost): - bob::learn::mlp::BaseTrainer(batch_size, cost), + bob::learn::mlp::Trainer(batch_size, cost), m_eta_minus(0.5), m_eta_plus(1.2), m_delta_zero(0.1), @@ -35,7 +35,7 @@ bob::learn::mlp::RProp::RProp(size_t batch_size, bob::learn::mlp::RProp::RProp(size_t batch_size, boost::shared_ptr<bob::learn::mlp::Cost> cost, const bob::learn::mlp::Machine& machine): - bob::learn::mlp::BaseTrainer(batch_size, cost, machine), + bob::learn::mlp::Trainer(batch_size, cost, machine), m_eta_minus(0.5), m_eta_plus(1.2), m_delta_zero(0.1), @@ -53,7 +53,7 @@ bob::learn::mlp::RProp::RProp(size_t batch_size, boost::shared_ptr<bob::learn::mlp::Cost> cost, const bob::learn::mlp::Machine& machine, bool train_biases): - bob::learn::mlp::BaseTrainer(batch_size, cost, machine, train_biases), + bob::learn::mlp::Trainer(batch_size, cost, machine, train_biases), m_eta_minus(0.5), m_eta_plus(1.2), m_delta_zero(0.1), @@ -70,7 +70,7 @@ bob::learn::mlp::RProp::RProp(size_t batch_size, bob::learn::mlp::RProp::~RProp() { } bob::learn::mlp::RProp::RProp(const RProp& other): - bob::learn::mlp::BaseTrainer(other), + bob::learn::mlp::Trainer(other), m_eta_minus(other.m_eta_minus), m_eta_plus(other.m_eta_plus), m_delta_zero(other.m_delta_zero), @@ -91,7 +91,7 @@ bob::learn::mlp::RProp& bob::learn::mlp::RProp::operator= (const bob::learn::mlp::RProp& other) { if (this != &other) { - bob::learn::mlp::BaseTrainer::operator=(other); + bob::learn::mlp::Trainer::operator=(other); m_eta_minus = other.m_eta_minus; m_eta_plus = other.m_eta_plus; @@ -187,7 +187,7 @@ void bob::learn::mlp::RProp::rprop_weight_update(bob::learn::mlp::Machine& machi void bob::learn::mlp::RProp::initialize(const bob::learn::mlp::Machine& machine) { - bob::learn::mlp::BaseTrainer::initialize(machine); + bob::learn::mlp::Trainer::initialize(machine); const std::vector<blitz::Array<double,2> >& machine_weight = machine.getWeights(); diff --git a/xbob/learn/mlp/cxx/base_trainer.cpp b/xbob/learn/mlp/cxx/trainer.cpp similarity index 79% rename from xbob/learn/mlp/cxx/base_trainer.cpp rename to xbob/learn/mlp/cxx/trainer.cpp index df88929d71ef0c61013055c1122c396953cfaa62..902986c5a7ad42acbebb93dd79bb16ea86cd86a3 100644 --- a/xbob/learn/mlp/cxx/base_trainer.cpp +++ b/xbob/learn/mlp/cxx/trainer.cpp @@ -11,9 +11,9 @@ #include <bob/core/check.h> #include <bob/math/linear.h> -#include <xbob.learn.mlp/base_trainer.h> +#include <xbob.learn.mlp/trainer.h> -bob::learn::mlp::BaseTrainer::BaseTrainer(size_t batch_size, +bob::learn::mlp::Trainer::Trainer(size_t batch_size, boost::shared_ptr<bob::learn::mlp::Cost> cost): m_batch_size(batch_size), m_cost(cost), @@ -31,7 +31,7 @@ bob::learn::mlp::BaseTrainer::BaseTrainer(size_t batch_size, reset(); } -bob::learn::mlp::BaseTrainer::BaseTrainer(size_t batch_size, +bob::learn::mlp::Trainer::Trainer(size_t batch_size, boost::shared_ptr<bob::learn::mlp::Cost> cost, const bob::learn::mlp::Machine& machine): m_batch_size(batch_size), @@ -46,7 +46,7 @@ bob::learn::mlp::BaseTrainer::BaseTrainer(size_t batch_size, initialize(machine); } -bob::learn::mlp::BaseTrainer::BaseTrainer(size_t batch_size, +bob::learn::mlp::Trainer::Trainer(size_t batch_size, boost::shared_ptr<bob::learn::mlp::Cost> cost, const bob::learn::mlp::Machine& machine, bool train_biases): @@ -62,9 +62,9 @@ bob::learn::mlp::BaseTrainer::BaseTrainer(size_t batch_size, initialize(machine); } -bob::learn::mlp::BaseTrainer::~BaseTrainer() { } +bob::learn::mlp::Trainer::~Trainer() { } -bob::learn::mlp::BaseTrainer::BaseTrainer(const BaseTrainer& other): +bob::learn::mlp::Trainer::Trainer(const Trainer& other): m_batch_size(other.m_batch_size), m_cost(other.m_cost), m_train_bias(other.m_train_bias), @@ -76,8 +76,8 @@ bob::learn::mlp::BaseTrainer::BaseTrainer(const BaseTrainer& other): bob::core::array::ccopy(other.m_output, m_output); } -bob::learn::mlp::BaseTrainer& bob::learn::mlp::BaseTrainer::operator= -(const bob::learn::mlp::BaseTrainer& other) { +bob::learn::mlp::Trainer& bob::learn::mlp::Trainer::operator= +(const bob::learn::mlp::Trainer& other) { if (this != &other) { m_batch_size = other.m_batch_size; @@ -93,7 +93,7 @@ bob::learn::mlp::BaseTrainer& bob::learn::mlp::BaseTrainer::operator= return *this; } -void bob::learn::mlp::BaseTrainer::setBatchSize (size_t batch_size) { +void bob::learn::mlp::Trainer::setBatchSize (size_t batch_size) { // m_output: values after the activation function // m_error: error values; @@ -108,7 +108,7 @@ void bob::learn::mlp::BaseTrainer::setBatchSize (size_t batch_size) { } } -bool bob::learn::mlp::BaseTrainer::isCompatible(const bob::learn::mlp::Machine& machine) const +bool bob::learn::mlp::Trainer::isCompatible(const bob::learn::mlp::Machine& machine) const { if (m_H != machine.numOfHiddenLayers()) return false; @@ -125,7 +125,7 @@ bool bob::learn::mlp::BaseTrainer::isCompatible(const bob::learn::mlp::Machine& return true; } -void bob::learn::mlp::BaseTrainer::forward_step(const bob::learn::mlp::Machine& machine, +void bob::learn::mlp::Trainer::forward_step(const bob::learn::mlp::Machine& machine, const blitz::Array<double,2>& input) { const std::vector<blitz::Array<double,2> >& machine_weight = machine.getWeights(); @@ -147,7 +147,7 @@ void bob::learn::mlp::BaseTrainer::forward_step(const bob::learn::mlp::Machine& } } -void bob::learn::mlp::BaseTrainer::backward_step +void bob::learn::mlp::Trainer::backward_step (const bob::learn::mlp::Machine& machine, const blitz::Array<double,2>& input, const blitz::Array<double,2>& target) { @@ -184,7 +184,7 @@ void bob::learn::mlp::BaseTrainer::backward_step } } -double bob::learn::mlp::BaseTrainer::cost +double bob::learn::mlp::Trainer::cost (const blitz::Array<double,2>& target) const { bob::core::array::assertSameShape(m_output[m_H], target); double retval = 0.0; @@ -196,14 +196,14 @@ double bob::learn::mlp::BaseTrainer::cost return retval / target.extent(0); } -double bob::learn::mlp::BaseTrainer::cost +double bob::learn::mlp::Trainer::cost (const bob::learn::mlp::Machine& machine, const blitz::Array<double,2>& input, const blitz::Array<double,2>& target) { forward_step(machine, input); return cost(target); } -void bob::learn::mlp::BaseTrainer::initialize(const bob::learn::mlp::Machine& machine) +void bob::learn::mlp::Trainer::initialize(const bob::learn::mlp::Machine& machine) { const std::vector<blitz::Array<double,2> >& machine_weight = machine.getWeights(); @@ -225,7 +225,7 @@ void bob::learn::mlp::BaseTrainer::initialize(const bob::learn::mlp::Machine& ma reset(); } -void bob::learn::mlp::BaseTrainer::setError(const std::vector<blitz::Array<double,2> >& error) { +void bob::learn::mlp::Trainer::setError(const std::vector<blitz::Array<double,2> >& error) { bob::core::array::assertSameDimensionLength(error.size(), m_error.size()); for (size_t k=0; k<error.size(); ++k) { @@ -234,9 +234,9 @@ void bob::learn::mlp::BaseTrainer::setError(const std::vector<blitz::Array<doubl } } -void bob::learn::mlp::BaseTrainer::setError(const blitz::Array<double,2>& error, const size_t id) { +void bob::learn::mlp::Trainer::setError(const blitz::Array<double,2>& error, const size_t id) { if (id >= m_error.size()) { - boost::format m("BaseTrainer: index for setting error array %lu is not on the expected range of [0, %lu]"); + boost::format m("Trainer: index for setting error array %lu is not on the expected range of [0, %lu]"); m % id % (m_error.size()-1); throw std::runtime_error(m.str()); } @@ -244,7 +244,7 @@ void bob::learn::mlp::BaseTrainer::setError(const blitz::Array<double,2>& error, m_error[id] = error; } -void bob::learn::mlp::BaseTrainer::setOutput(const std::vector<blitz::Array<double,2> >& output) { +void bob::learn::mlp::Trainer::setOutput(const std::vector<blitz::Array<double,2> >& output) { bob::core::array::assertSameDimensionLength(output.size(), m_output.size()); for (size_t k=0; k<output.size(); ++k) { @@ -253,9 +253,9 @@ void bob::learn::mlp::BaseTrainer::setOutput(const std::vector<blitz::Array<doub } } -void bob::learn::mlp::BaseTrainer::setOutput(const blitz::Array<double,2>& output, const size_t id) { +void bob::learn::mlp::Trainer::setOutput(const blitz::Array<double,2>& output, const size_t id) { if (id >= m_output.size()) { - boost::format m("BaseTrainer: index for setting output array %lu is not on the expected range of [0, %lu]"); + boost::format m("Trainer: index for setting output array %lu is not on the expected range of [0, %lu]"); m % id % (m_output.size()-1); throw std::runtime_error(m.str()); } @@ -263,7 +263,7 @@ void bob::learn::mlp::BaseTrainer::setOutput(const blitz::Array<double,2>& outpu m_output[id] = output; } -void bob::learn::mlp::BaseTrainer::setDerivatives(const std::vector<blitz::Array<double,2> >& deriv) { +void bob::learn::mlp::Trainer::setDerivatives(const std::vector<blitz::Array<double,2> >& deriv) { bob::core::array::assertSameDimensionLength(deriv.size(), m_deriv.size()); for (size_t k=0; k<deriv.size(); ++k) { @@ -272,9 +272,9 @@ void bob::learn::mlp::BaseTrainer::setDerivatives(const std::vector<blitz::Array } } -void bob::learn::mlp::BaseTrainer::setDerivative(const blitz::Array<double,2>& deriv, const size_t id) { +void bob::learn::mlp::Trainer::setDerivative(const blitz::Array<double,2>& deriv, const size_t id) { if (id >= m_deriv.size()) { - boost::format m("BaseTrainer: index for setting derivative array %lu is not on the expected range of [0, %lu]"); + boost::format m("Trainer: index for setting derivative array %lu is not on the expected range of [0, %lu]"); m % id % (m_deriv.size()-1); throw std::runtime_error(m.str()); } @@ -282,7 +282,7 @@ void bob::learn::mlp::BaseTrainer::setDerivative(const blitz::Array<double,2>& d m_deriv[id] = deriv; } -void bob::learn::mlp::BaseTrainer::setBiasDerivatives(const std::vector<blitz::Array<double,1> >& deriv_bias) { +void bob::learn::mlp::Trainer::setBiasDerivatives(const std::vector<blitz::Array<double,1> >& deriv_bias) { bob::core::array::assertSameDimensionLength(deriv_bias.size(), m_deriv_bias.size()); for (size_t k=0; k<deriv_bias.size(); ++k) { @@ -291,9 +291,9 @@ void bob::learn::mlp::BaseTrainer::setBiasDerivatives(const std::vector<blitz::A } } -void bob::learn::mlp::BaseTrainer::setBiasDerivative(const blitz::Array<double,1>& deriv_bias, const size_t id) { +void bob::learn::mlp::Trainer::setBiasDerivative(const blitz::Array<double,1>& deriv_bias, const size_t id) { if (id >= m_deriv_bias.size()) { - boost::format m("BaseTrainer: index for setting bias derivative array %lu is not on the expected range of [0, %lu]"); + boost::format m("Trainer: index for setting bias derivative array %lu is not on the expected range of [0, %lu]"); m % id % (m_deriv_bias.size()-1); throw std::runtime_error(m.str()); } @@ -301,7 +301,7 @@ void bob::learn::mlp::BaseTrainer::setBiasDerivative(const blitz::Array<double,1 m_deriv_bias[id] = deriv_bias; } -void bob::learn::mlp::BaseTrainer::reset() { +void bob::learn::mlp::Trainer::reset() { for (size_t k=0; k<(m_H + 1); ++k) { m_deriv[k] = 0.; m_deriv_bias[k] = 0.; diff --git a/xbob/learn/mlp/include/xbob.learn.mlp/api.h b/xbob/learn/mlp/include/xbob.learn.mlp/api.h index 140df1d39d143869ccc907e1d34734568f04200e..d6ac3a88cc5a02635eaf1d932de488c0dee37674 100644 --- a/xbob/learn/mlp/include/xbob.learn.mlp/api.h +++ b/xbob/learn/mlp/include/xbob.learn.mlp/api.h @@ -7,6 +7,7 @@ #define XBOB_LEARN_MLP_H #include <Python.h> +#include <boost/shared_ptr.hpp> #include <xbob.learn.mlp/config.h> #include "machine.h" @@ -14,6 +15,7 @@ #include "square_error.h" #include "cross_entropy.h" #include "shuffler.h" +#include "trainer.h" #define XBOB_LEARN_MLP_MODULE_PREFIX xbob.learn.mlp #define XBOB_LEARN_MLP_MODULE_NAME _library @@ -23,7 +25,7 @@ *******************/ /* Enum defining entries in the function table */ -enum _PyBobLearnMLP_ENUM{ +enum _PyBobLearnMLP_ENUM { PyXbobLearnMLP_APIVersion_NUM = 0, // Bindings for xbob.learn.mlp.Machine PyBobLearnMLPMachine_Type_NUM, @@ -37,6 +39,9 @@ enum _PyBobLearnMLP_ENUM{ // Bindings for xbob.learn.mlp.DataShuffler PyBobLearnDataShuffler_Type_NUM, PyBobLearnDataShuffler_Check_NUM, + // Bindings for xbob.learn.mlp.Trainer + PyBobLearnMLPTrainer_Type_NUM, + PyBobLearnMLPTrainer_Check_NUM, // Total number of C API pointers PyXbobLearnMLP_API_pointers }; @@ -47,9 +52,9 @@ enum _PyBobLearnMLP_ENUM{ #define PyXbobLearnMLP_APIVersion_TYPE int -/****************************************** +/*************************************** * Bindings for xbob.learn.mlp.Machine * - ******************************************/ + ***************************************/ typedef struct { PyObject_HEAD @@ -66,7 +71,7 @@ typedef struct { typedef struct { PyObject_HEAD - bob::learn::mlp::Cost* cxx; + boost::shared_ptr<bob::learn::mlp::Cost> cxx; } PyBobLearnCostObject; #define PyBobLearnCost_Type_TYPE PyTypeObject @@ -76,14 +81,14 @@ typedef struct { typedef struct { PyBobLearnCostObject parent; - bob::learn::mlp::SquareError* cxx; + boost::shared_ptr<bob::learn::mlp::SquareError> cxx; } PyBobLearnSquareErrorObject; #define PyBobLearnSquareError_Type_TYPE PyTypeObject typedef struct { PyBobLearnCostObject parent; - bob::learn::mlp::CrossEntropyLoss* cxx; + boost::shared_ptr<bob::learn::mlp::CrossEntropyLoss> cxx; } PyBobLearnCrossEntropyLossObject; #define PyBobLearnCrossEntropyLoss_Type_TYPE PyTypeObject @@ -98,6 +103,20 @@ typedef struct { #define PyBobLearnDataShuffler_Check_RET int #define PyBobLearnDataShuffler_Check_PROTO (PyObject* o) +/*************************************** + * Bindings for xbob.learn.mlp.Trainer * + ***************************************/ + +typedef struct { + PyObject_HEAD + bob::learn::mlp::Trainer* cxx; +} PyBobLearnMLPTrainerObject; + +#define PyBobLearnMLPTrainer_Type_TYPE PyTypeObject + +#define PyBobLearnMLPTrainer_Check_RET int +#define PyBobLearnMLPTrainer_Check_PROTO (PyObject* o) + #ifdef XBOB_LEARN_MLP_MODULE /* This section is used when compiling `xbob.learn.mlp' itself */ @@ -138,6 +157,14 @@ typedef struct { PyBobLearnDataShuffler_Check_RET PyBobLearnDataShuffler_Check PyBobLearnDataShuffler_Check_PROTO; + /*************************************** + * Bindings for xbob.learn.mlp.Trainer * + ***************************************/ + + extern PyBobLearnMLPTrainer_Type_TYPE PyBobLearnMLPTrainer_Type; + + PyBobLearnMLPTrainer_Check_RET PyBobLearnMLPTrainer_Check PyBobLearnMLPTrainer_Check_PROTO; + #else /* This section is used in modules that use `xbob.learn.mlp's' C-API */ @@ -170,9 +197,9 @@ typedef struct { # define PyXbobLearnMLP_APIVersion (*(PyXbobLearnMLP_APIVersion_TYPE *)PyXbobLearnMLP_API[PyXbobLearnMLP_APIVersion_NUM]) - /****************************************** + /*************************************** * Bindings for xbob.learn.mlp.Machine * - ******************************************/ + ***************************************/ # define PyBobLearnMLPMachine_Type (*(PyBobLearnMLPMachine_Type_TYPE *)PyXbobLearnMLP_API[PyBobLearnMLPMachine_Type_NUM]) @@ -200,6 +227,14 @@ typedef struct { # define PyBobLearnDataShuffler_Check (*(PyBobLearnDataShuffler_Check_RET (*)PyBobLearnDataShuffler_Check_PROTO) PyXbobLearnMLP_API[PyBobLearnDataShuffler_Check_NUM]) + /*************************************** + * Bindings for xbob.learn.mlp.Trainer * + ***************************************/ + +# define PyBobLearnMLPTrainer_Type (*(PyBobLearnMLPTrainer_Type_TYPE *)PyXbobLearnMLP_API[PyBobLearnMLPTrainer_Type_NUM]) + +# define PyBobLearnMLPTrainer_Check (*(PyBobLearnMLPTrainer_Check_RET (*)PyBobLearnMLPTrainer_Check_PROTO) PyXbobLearnMLP_API[PyBobLearnMLPTrainer_Check_NUM]) + # if !defined(NO_IMPORT_ARRAY) /** diff --git a/xbob/learn/mlp/include/xbob.learn.mlp/backprop.h b/xbob/learn/mlp/include/xbob.learn.mlp/backprop.h index 25c879f9d0dd67f75fa7e42ce18dfe100390f474..182db40d1661646416b2939f8712a2e4b328eb82 100644 --- a/xbob/learn/mlp/include/xbob.learn.mlp/backprop.h +++ b/xbob/learn/mlp/include/xbob.learn.mlp/backprop.h @@ -17,7 +17,7 @@ #include <boost/function.hpp> #include "machine.h" -#include "base_trainer.h" +#include "trainer.h" namespace bob { namespace learn { namespace mlp { @@ -26,7 +26,7 @@ namespace bob { namespace learn { namespace mlp { * back-propagation as defined in "Pattern Recognition and Machine Learning" * by C.M. Bishop, chapter 5. */ - class BackProp: public BaseTrainer { + class BackProp: public Trainer { public: //api diff --git a/xbob/learn/mlp/include/xbob.learn.mlp/rprop.h b/xbob/learn/mlp/include/xbob.learn.mlp/rprop.h index ad34f632ceb3f15689cc85afe57380d877b42bd4..a95c39e2a3415bfc109c5888154c82dd2326b432 100644 --- a/xbob/learn/mlp/include/xbob.learn.mlp/rprop.h +++ b/xbob/learn/mlp/include/xbob.learn.mlp/rprop.h @@ -18,7 +18,7 @@ #include <boost/function.hpp> #include "machine.h" -#include "base_trainer.h" +#include "trainer.h" namespace bob { namespace learn { namespace mlp { @@ -28,7 +28,7 @@ namespace bob { namespace learn { namespace mlp { * by Martin Riedmiller and Heinrich Braun on IEEE International Conference * on Neural Networks, pp. 586--591, 1993. */ - class RProp: public BaseTrainer { + class RProp: public Trainer { public: //api diff --git a/xbob/learn/mlp/include/xbob.learn.mlp/base_trainer.h b/xbob/learn/mlp/include/xbob.learn.mlp/trainer.h similarity index 93% rename from xbob/learn/mlp/include/xbob.learn.mlp/base_trainer.h rename to xbob/learn/mlp/include/xbob.learn.mlp/trainer.h index 221921b337f6bb26b53d66858cc900d99d3cdeec..0188842d021ce610750007a953b15dbc7b36c41e 100644 --- a/xbob/learn/mlp/include/xbob.learn.mlp/base_trainer.h +++ b/xbob/learn/mlp/include/xbob.learn.mlp/trainer.h @@ -44,12 +44,12 @@ namespace bob { namespace learn { namespace mlp { * \times a^{(l-1)}) + (\mu) \times w_{n-1} * @f] */ - class BaseTrainer { + class Trainer { public: //api /** - * @brief Initializes a new BaseTrainer trainer according to a given + * @brief Initializes a new Trainer trainer according to a given * training batch size. * * @param batch_size The number of examples passed at each iteration. If @@ -67,11 +67,10 @@ namespace bob { namespace learn { namespace mlp { * @note Good values for batch sizes are tens of samples. This may affect * the convergence. */ - BaseTrainer(size_t batch_size, - boost::shared_ptr<Cost> cost); + Trainer(size_t batch_size, boost::shared_ptr<Cost> cost); /** - * @brief Initializes a new BaseTrainer trainer according to a given + * @brief Initializes a new Trainer trainer according to a given * machine settings and a training batch size. * * @param batch_size The number of examples passed at each iteration. If @@ -88,12 +87,11 @@ namespace bob { namespace learn { namespace mlp { * @note Good values for batch sizes are tens of samples. This may affect * the convergence. */ - BaseTrainer(size_t batch_size, - boost::shared_ptr<Cost> cost, + Trainer(size_t batch_size, boost::shared_ptr<Cost> cost, const Machine& machine); /** - * @brief Initializes a new BaseTrainer trainer according to a given + * @brief Initializes a new Trainer trainer according to a given * machine settings and a training batch size. * * @param batch_size The number of examples passed at each iteration. If @@ -110,25 +108,23 @@ namespace bob { namespace learn { namespace mlp { * @note Good values for batch sizes are tens of samples. This may affect * the convergence. */ - BaseTrainer(size_t batch_size, - boost::shared_ptr<Cost> cost, - const Machine& machine, - bool train_biases); + Trainer(size_t batch_size, boost::shared_ptr<Cost> cost, + const Machine& machine, bool train_biases); /** * @brief Destructor virtualisation */ - virtual ~BaseTrainer(); + virtual ~Trainer(); /** * @brief Copy construction. */ - BaseTrainer(const BaseTrainer& other); + Trainer(const Trainer& other); /** * @brief Copy operator */ - BaseTrainer& operator=(const BaseTrainer& other); + Trainer& operator=(const Trainer& other); /** * @brief Gets the batch size diff --git a/xbob/learn/mlp/main.cpp b/xbob/learn/mlp/main.cpp index 6ba1691f4d116e8b6e6770c917a2b5ebcab79cd8..da1b2adf0ccbf7ac9c8b4ce322ab93633c3f4b10 100644 --- a/xbob/learn/mlp/main.cpp +++ b/xbob/learn/mlp/main.cpp @@ -53,6 +53,9 @@ static PyObject* create_module (void) { PyBobLearnDataShuffler_Type.tp_new = PyType_GenericNew; if (PyType_Ready(&PyBobLearnDataShuffler_Type) < 0) return 0; + PyBobLearnMLPTrainer_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&PyBobLearnMLPTrainer_Type) < 0) return 0; + # if PY_VERSION_HEX >= 0x03000000 PyObject* m = PyModule_Create(&module_definition); # else @@ -81,6 +84,9 @@ static PyObject* create_module (void) { Py_INCREF(&PyBobLearnDataShuffler_Type); if (PyModule_AddObject(m, "DataShuffler", (PyObject *)&PyBobLearnDataShuffler_Type) < 0) return 0; + Py_INCREF(&PyBobLearnMLPTrainer_Type); + if (PyModule_AddObject(m, "Trainer", (PyObject *)&PyBobLearnMLPTrainer_Type) < 0) return 0; + static void* PyXbobLearnMLP_API[PyXbobLearnMLP_API_pointers]; /* exhaustive list of C APIs */ @@ -121,6 +127,14 @@ static PyObject* create_module (void) { PyXbobLearnMLP_API[PyBobLearnDataShuffler_Check_NUM] = (void *)&PyBobLearnDataShuffler_Check; + /*************************************** + * Bindings for xbob.learn.mlp.Trainer * + ***************************************/ + + PyXbobLearnMLP_API[PyBobLearnMLPTrainer_Type_NUM] = (void *)&PyBobLearnMLPTrainer_Type; + + PyXbobLearnMLP_API[PyBobLearnMLPTrainer_Check_NUM] = (void *)&PyBobLearnMLPTrainer_Check; + #if PY_VERSION_HEX >= 0x02070000 /* defines the PyCapsule */ diff --git a/xbob/learn/mlp/trainer.cpp b/xbob/learn/mlp/trainer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a3e2a4ac0410055d60b51f5acabcb2c3922944ac --- /dev/null +++ b/xbob/learn/mlp/trainer.cpp @@ -0,0 +1,205 @@ +/** + * @author Andre Anjos <andre.anjos@idiap.ch> + * @date Tue 6 May 12:32:39 2014 CEST + * + * @brief Bindings for an MLP + * + * Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland + */ + +#define XBOB_LEARN_MLP_MODULE +#include <xbob.blitz/cppapi.h> +#include <xbob.blitz/cleanup.h> +#include <xbob.learn.mlp/api.h> +#include <structmember.h> + +/**************************************** + * Implementation of base Trainer class * + ****************************************/ + +PyDoc_STRVAR(s_trainer_str, XBOB_EXT_MODULE_PREFIX ".Trainer"); + +PyDoc_STRVAR(s_trainer_doc, +"Trainer(batch_size, cost, [trainer, [train_biases]]) -> new Trainer\n\ +Trainer(other) -> new Trainer\n\ +\n\ +The base python class for MLP trainers based on cost derivatives.\n\ +\n\ +You should use this class when you want to create your own MLP\n\ +trainers and re-use the base infrastructured provided by this\n\ +module, such as the computation of partial derivatives (using\n\ +the :py:meth:`backward_step` method).\n\ +\n\ +To create a new trainer, either pass another trainer you'd like\n\ +the parameters copied from or pass the batch-size, cost functor,\n\ +machine and a biases-training flag.\n\ +"); + +static int PyBobLearnMLPTrainer_init_discrete +(PyBobLearnMLPTrainerObject* self, PyObject* args, PyObject* kwds) { + + /* Parses input arguments in a single shot */ + static const char* const_kwlist[] = { + "batch_size", + "cost", + "machine", + "train_biases", + 0 + }; + static char** kwlist = const_cast<char**>(const_kwlist); + + Py_ssize_t batch_size = 0; + PyBobLearnCostObject* cost = 0; + PyBobLearnMLPMachineObject* machine = 0; + PyObject* train_biases = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "nO!|O!O", kwlist, + &batch_size, + &PyBobLearnCost_Type, &cost, + &PyBobLearnMLPMachine_Type, &machine, + &train_biases)) return -1; + + try { + if (machine && train_biases) { + self->cxx = new bob::learn::mlp::Trainer(batch_size, cost->cxx, + *machine->cxx, PyObject_IsTrue(train_biases)); + } + else if (machine) { + self->cxx = new bob::learn::mlp::Trainer(batch_size, cost->cxx, + *machine->cxx); + } + else if (train_biases) { + PyErr_Format(PyExc_RuntimeError, "cannot provide a flag for `train_biases' and do not provide a `machine' upon initialisation of type `%s'", Py_TYPE(self)->tp_name); + return -1; + } + else { + self->cxx = new bob::learn::mlp::Trainer(batch_size, cost->cxx); + } + } + catch (std::exception& ex) { + PyErr_SetString(PyExc_RuntimeError, ex.what()); + return -1; + } + catch (...) { + PyErr_Format(PyExc_RuntimeError, "cannot create new object of type `%s' - unknown exception thrown", Py_TYPE(self)->tp_name); + return -1; + } + + return 0; + +} + +static int PyBobLearnMLPTrainer_init_copy +(PyBobLearnMLPTrainerObject* self, PyObject* args, PyObject* kwds) { + + /* Parses input arguments in a single shot */ + static const char* const_kwlist[] = {"other", 0}; + static char** kwlist = const_cast<char**>(const_kwlist); + + PyObject* other = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, + &PyBobLearnMLPTrainer_Type, &other)) return -1; + + auto copy = reinterpret_cast<PyBobLearnMLPTrainerObject*>(other); + + try { + self->cxx = new bob::learn::mlp::Trainer(*(copy->cxx)); + } + catch (std::exception& ex) { + PyErr_SetString(PyExc_RuntimeError, ex.what()); + return -1; + } + catch (...) { + PyErr_Format(PyExc_RuntimeError, "cannot create new object of type `%s' - unknown exception thrown", Py_TYPE(self)->tp_name); + return -1; + } + + return 0; + +} + +static int PyBobLearnMLPTrainer_init(PyBobLearnMLPTrainerObject* self, + PyObject* args, PyObject* kwds) { + + Py_ssize_t nargs = (args?PyTuple_Size(args):0) + (kwds?PyDict_Size(kwds):0); + + switch (nargs) { + + case 1: + + return PyBobLearnMLPTrainer_init_copy(self, args, kwds); + + default: + + return PyBobLearnMLPTrainer_init_discrete(self, args, kwds); + } + + return -1; + +} + +static void PyBobLearnMLPTrainer_delete +(PyBobLearnMLPTrainerObject* self) { + + delete self->cxx; + Py_TYPE(self)->tp_free((PyObject*)self); + +} + +int PyBobLearnMLPTrainer_Check(PyObject* o) { + return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobLearnMLPTrainer_Type)); +} + +static PyObject* PyBobLearnMLPTrainer_new +(PyTypeObject* type, PyObject*, PyObject*) { + + /* Allocates the python object itself */ + PyBobLearnMLPTrainerObject* self = (PyBobLearnMLPTrainerObject*)type->tp_alloc(type, 0); + + self->cxx = 0; + + return reinterpret_cast<PyObject*>(self); + +} + +PyTypeObject PyBobLearnMLPTrainer_Type = { + PyVarObject_HEAD_INIT(0, 0) + s_trainer_str, /* tp_name */ + sizeof(PyBobLearnMLPTrainerObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PyBobLearnMLPTrainer_delete, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, //(reprfunc)PyBobLearnMLPTrainer_Repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, //(reprfunc)PyBobLearnMLPTrainer_Repr, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + s_trainer_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, //PyBobLearnMLPTrainer_methods, /* tp_methods */ + 0, /* tp_members */ + 0, //PyBobLearnMLPTrainer_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PyBobLearnMLPTrainer_init, /* tp_init */ + 0, /* tp_alloc */ + PyBobLearnMLPTrainer_new, /* tp_new */ +};