First attempt to approach the issue bob.bio.base#106

In this issue I'm:

1. Removing the loading and saving functions via HDF5 in the C++ and in
the python API (not sure if it's really necessary to remove from the C
level)

2. Implemented the methods `to_dict` and `from_dict` for the activation
functions

3. Test cases
parent 9b9dec5e
Pipeline #32409 passed with stage
in 20 minutes and 1 second
......@@ -9,6 +9,7 @@ from ._library import *
from . import version
from .version import module as __version__
from .version import api as __api_version__
from .activation import *
def get_config():
"""Returns a string containing the configuration information.
......
......@@ -424,73 +424,6 @@ static PyObject* PyBobLearnActivation_UniqueIdentifier
return Py_BuildValue("s", self->cxx->unique_identifier().c_str());
}
PyDoc_STRVAR(s_load_str, "load");
PyDoc_STRVAR(s_load_doc,
"o.load(f) -> None\n\
\n\
Loads itself from a :py:class:`bob.io.base.HDF5File`\n\
\n\
");
static PyObject* PyBobLearnActivation_Load(PyBobLearnActivationObject* self,
PyObject* f) {
if (!PyBobIoHDF5File_Check(f)) {
PyErr_Format(PyExc_TypeError, "`%s' cannot load itself from `%s', only from an HDF5 file", Py_TYPE(self)->tp_name, Py_TYPE(f)->tp_name);
return 0;
}
auto h5f = reinterpret_cast<PyBobIoHDF5FileObject*>(f);
try {
self->cxx->load(*h5f->f);
}
catch (std::exception& e) {
PyErr_SetString(PyExc_RuntimeError, e.what());
return 0;
}
catch (...) {
PyErr_Format(PyExc_RuntimeError, "cannot read data from file `%s' (at group `%s'): unknown exception caught", h5f->f->filename().c_str(),
h5f->f->cwd().c_str());
return 0;
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(s_save_str, "save");
PyDoc_STRVAR(s_save_doc,
"o.save(f) -> None\n\
\n\
Saves itself to a :py:class:`bob.io.base.HDF5File`\n\
\n\
");
static PyObject* PyBobLearnActivation_Save
(PyBobLearnActivationObject* self, PyObject* f) {
if (!PyBobIoHDF5File_Check(f)) {
PyErr_Format(PyExc_TypeError, "`%s' cannot write itself to `%s', only to an HDF5 file", Py_TYPE(self)->tp_name, Py_TYPE(f)->tp_name);
return 0;
}
auto h5f = reinterpret_cast<PyBobIoHDF5FileObject*>(f);
try {
self->cxx->save(*h5f->f);
}
catch (std::exception& e) {
PyErr_SetString(PyExc_RuntimeError, e.what());
return 0;
}
catch (...) {
PyErr_Format(PyExc_RuntimeError, "cannot write data to file `%s' (at group `%s'): unknown exception caught", h5f->f->filename().c_str(),
h5f->f->cwd().c_str());
return 0;
}
Py_RETURN_NONE;
}
static PyMethodDef PyBobLearnActivation_methods[] = {
{
......@@ -517,18 +450,6 @@ static PyMethodDef PyBobLearnActivation_methods[] = {
METH_NOARGS,
s_unique_id_doc
},
{
s_load_str,
(PyCFunction)PyBobLearnActivation_Load,
METH_O,
s_load_doc
},
{
s_save_str,
(PyCFunction)PyBobLearnActivation_Save,
METH_O,
s_save_doc
},
{0} /* Sentinel */
};
......
#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
# Tiago de Freitas Pereira <tiago.pereira@idiap.ch>
from ._library import (
Activation as _Activation_C,
Logistic as _Logistic_C,
HyperbolicTangent as _HyperbolicTangent_C,
Identity as _Identity_C,
Linear as _Linear_C,
MultipliedHyperbolicTangent as _MultipliedHyperbolicTangent_C,
)
class Activation(_Activation_C):
def to_dict(self):
"""
Dumps its content to a :py:class:`dict`
"""
return {"id": self.unique_identifier()}
def from_dict(input_dict):
"""
Loads itself from a python dict :py:class:`dict`
"""
pass
class Logistic(_Logistic_C, Activation):
pass
class HyperbolicTangent(_HyperbolicTangent_C, Activation):
pass
class Identity(_Identity_C, Activation):
pass
class Linear(_Linear_C, Activation):
def to_dict(self):
return {"id": self.unique_identifier(), "C": self.C}
@staticmethod
def from_dict(input_dict):
"""
Loads itself from a python dict :py:class:`dict`
"""
if "C" in input_dict:
C = float(input_dict["C"])
return Linear(C=C)
else:
raise ValueError("Missing parameter `C` in `input_dict`")
class MultipliedHyperbolicTangent(_MultipliedHyperbolicTangent_C, Activation):
def to_dict(self):
return {"id": self.unique_identifier(), "C": self.C, "M": self.M}
@staticmethod
def from_dict(input_dict):
"""
Loads itself from a python dict :py:class:`dict`
"""
if "C" in input_dict:
C = float(input_dict["C"])
else:
raise ValueError("Missing parameter `C` in `input_dict`")
if "M" in input_dict:
M = float(input_dict["M"])
else:
raise ValueError("Missing parameter `M` in `input_dict`")
return MultipliedHyperbolicTangent(C=C, M=M)
......@@ -16,11 +16,6 @@ boost::shared_ptr<bob::learn::activation::ActivationRegistry> bob::learn::activa
return s_instance;
}
boost::shared_ptr<bob::learn::activation::Activation> bob::learn::activation::load_activation(bob::io::base::HDF5File& f) {
auto make = ActivationRegistry::instance()->find(f.read<std::string>("id"));
return make(f);
}
boost::shared_ptr<bob::learn::activation::Activation> bob::learn::activation::make_deprecated_activation(uint32_t e) {
switch(e) {
case 0:
......@@ -99,11 +94,11 @@ bob::learn::activation::activation_factory_t bob::learn::activation::ActivationR
*/
template <typename T> struct register_activation {
static boost::shared_ptr<bob::learn::activation::Activation> factory (bob::io::base::HDF5File& f) {
static boost::shared_ptr<bob::learn::activation::Activation> factory () {
auto retval = boost::make_shared<T>();
retval->load(f);
return retval;
}
register_activation() {
T obj;
......
......@@ -40,16 +40,6 @@ namespace bob { namespace learn { namespace activation {
*/
virtual double f_prime_from_f (double a) const =0;
/**
* Saves itself to an HDF5File
*/
virtual void save(bob::io::base::HDF5File& f) const { f.set("id", unique_identifier()); }
/**
* Loads itself from an HDF5File
*/
virtual void load(bob::io::base::HDF5File& f) {}
/**
* Returns a unique identifier, used by this class in connection to the
* Activation registry.
......@@ -66,12 +56,8 @@ namespace bob { namespace learn { namespace activation {
/**
* Generic interface for Activation object factories
*/
typedef boost::shared_ptr<Activation> (*activation_factory_t) (bob::io::base::HDF5File& f);
typedef boost::shared_ptr<Activation> (*activation_factory_t) ();
/**
* Loads an activation function from file using the new API
*/
boost::shared_ptr<Activation> load_activation(bob::io::base::HDF5File& f);
/**
* Loads an activation function using the old API
......@@ -110,8 +96,6 @@ namespace bob { namespace learn { namespace activation {
virtual double f_prime (double z) const { return m_C; }
virtual double f_prime_from_f (double a) const { return m_C; }
double C() const { return m_C; }
virtual void save(bob::io::base::HDF5File& f) const { Activation::save(f); f.set("C", m_C); }
virtual void load(bob::io::base::HDF5File& f) { m_C = f.read<double>("C"); }
virtual std::string unique_identifier() const { return "bob.learn.activation.Activation.Linear"; }
virtual std::string str() const { return (boost::format("f(z) = %.5e * z") % m_C).str(); }
......@@ -149,8 +133,6 @@ namespace bob { namespace learn { namespace activation {
virtual double f_prime_from_f (double a) const { return m_C * m_M * (1. - std::pow(a/m_C,2)); }
double C() const { return m_C; }
double M() const { return m_M; }
virtual void save(bob::io::base::HDF5File& f) const { Activation::save(f); f.set("C", m_C); f.set("M", m_C); }
virtual void load(bob::io::base::HDF5File& f) {m_C = f.read<double>("C"); m_M = f.read<double>("M"); }
virtual std::string unique_identifier() const { return "bob.learn.activation.Activation.MultipliedHyperbolicTangent"; }
virtual std::string str() const { return (boost::format("f(z) = %.5e * tanh(%.5e * z)") % m_C % m_M).str(); }
......
......@@ -321,3 +321,40 @@ def test_4d_ndarray():
assert is_close(op.f(x), Y_f.flat[k])
assert is_close(op.f_prime(x), Y_f_prime.flat[k])
assert is_close(op.f_prime_from_f(x), Y_f_prime_from_f.flat[k])
def test_to_dict():
logistic = Logistic()
assert logistic.to_dict()["id"] == "bob.learn.activation.Activation.Logistic"
hyperbolic_tangent = HyperbolicTangent()
assert hyperbolic_tangent.to_dict()["id"] == "bob.learn.activation.Activation.HyperbolicTangent"
identity = Identity()
assert identity.to_dict()["id"] == "bob.learn.activation.Activation.Identity"
linear = Linear()
assert linear.to_dict()["id"] == "bob.learn.activation.Activation.Linear"
assert linear.to_dict()["C"] == 1
multiplied_hyperbolic_tangent = MultipliedHyperbolicTangent()
assert multiplied_hyperbolic_tangent.to_dict()["id"] == "bob.learn.activation.Activation.MultipliedHyperbolicTangent"
assert multiplied_hyperbolic_tangent.to_dict()["C"] == 1.
assert multiplied_hyperbolic_tangent.to_dict()["M"] == 1.
def test_from_dict():
input_dict = {"id": "bob.learn.activation.Activation.Linear",
"C": 2.}
linear = Linear.from_dict(input_dict)
assert linear.C == 2
input_dict = {"id": "bob.learn.activation.Activation.MultipliedHyperbolicTangent",
"C": 2.,
"M": 3.}
multiplied_hyperbolic_tangent = MultipliedHyperbolicTangent.from_dict(input_dict)
assert multiplied_hyperbolic_tangent.C == 2.
assert multiplied_hyperbolic_tangent.M == 3.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment