Commit 871c2c0d authored by André Anjos's avatar André Anjos 💬
Browse files

Increase test coverage

parent ce0f1064
......@@ -42,8 +42,8 @@ the import function:
The include directory can be discovered using
:py:func:`xbob.learn.libsvm.get_include`.
LIBSVM File Interface
----------------------
File Interface
--------------
.. cpp:type:: PyBobLearnLibsvmFileObject
......@@ -67,8 +67,8 @@ LIBSVM File Interface
Checks if the input object ``o`` is a ``PyBobLearnLibsvmFileObject``.
Returns ``1`` if it is, and ``0`` otherwise.
LIBSVM Machine Interface
------------------------
Machine Interface
-----------------
.. cpp:type:: PyBobLearnLibsvmMachineObject
......@@ -84,7 +84,99 @@ LIBSVM Machine Interface
.. cpp:member:: bob::learn::libsvm::Machine* cxx
A pointer to the C++ file implementation.
A pointer to the C++ machine implementation.
.. cpp:function:: int PyBobLearnLibsvmMachine_Check(PyObject* o)
Checks if the input object ``o`` is a ``PyBobLearnLibsvmMachineObject``.
Returns ``1`` if it is, and ``0`` otherwise.
.. cpp:function:: PyObject* PyBobLearnLibsvmMachine_NewFromMachine(bob::learn::libsvm::Machine* m)
Builds a new Python object from an existing :cpp:class:`Machine`. The
machine object ``m`` is **stolen** from the user, which should not delete it
anymore.
Trainer Interface
-----------------
.. cpp:type:: PyBobLearnLibsvmTrainerObject
The pythonic object representation for a ``bob::learn::libsvm::Trainer``
object.
.. code-block:: cpp
typedef struct {
PyObject_HEAD
bob::learn::libsvm::Trainer* cxx;
} PyBobLearnLibsvmTrainerObject
.. cpp:member:: bob::learn::libsvm::Trainer* cxx
A pointer to the C++ trainer implementation.
.. cpp:function:: int PyBobLearnLibsvmTrainer_Check(PyObject* o)
Checks if the input object ``o`` is a ``PyBobLearnLibsvmTrainerObject``.
Returns ``1`` if it is, and ``0`` otherwise.
Other Utilities
---------------
.. cpp:function:: PyObject* PyBobLearnLibsvm_MachineTypeAsString(bob::learn::libsvm::machine_t s)
Returns a Python string representing given a machine type. Returns ``NULL``
and sets an :py:class:`RuntimeError` if the enumeration provided is not
supported.
This function will return a proper :c:type:`PyStringObject` on Python 2.x
and a :c:type:`PyUnicodeObject` on Python 3.x.
.. cpp:function:: bob::learn::libsvm::machine_t PyBobLearnLibsvm_StringAsMachineType(PyObject* o)
Decodes the machine type enumeration from a pythonic string. Works with any
string type or subtype. A :py:class:`RuntimeError` is set if the string
cannot be encoded as one of the available enumerations. You must check for
:c:func:`PyErr_Occurred` after a call to this function to make sure that the
conversion was correctly performed.
.. cpp:function:: bob::learn::libsvm::machine_t PyBobLearnLibsvm_CStringAsMachineType(const char* s)
This function works the same as
:cpp:func:`PyBobLearnLibsvm_StringAsMachineType`, but accepts a C-style
string instead of a Python object as input. A :py:class:`RuntimeError` is
set if the string cannot be encoded as one of the available enumerations.
You must check for :c:func:`PyErr_Occurred` after a call to this function to
make sure that the conversion was correctly performed.
.. cpp:function:: PyObject* PyBobLearnLibsvm_KernelTypeAsString(bob::learn::libsvm::kernel_t s)
Returns a Python string representing given a kernel type. Returns ``NULL``
and sets an :py:class:`RuntimeError` if the enumeration provided is not
supported.
This function will return a proper :c:type:`PyStringObject` on Python 2.x
and a :c:type:`PyUnicodeObject` on Python 3.x.
.. cpp:function:: bob::learn::libsvm::kernel_t PyBobLearnLibsvm_StringAsKernelType(PyObject* o)
Decodes the kernel type enumeration from a pythonic string. Works with any
string type or subtype. A :py:class:`RuntimeError` is set if the string
cannot be encoded as one of the available enumerations. You must check for
:c:func:`PyErr_Occurred` after a call to this function to make sure that the
conversion was correctly performed.
.. cpp:function:: bob::learn::libsvm::kernel_t PyBobLearnLibsvm_CStringAsKernelType(const char* s)
This function works the same as
:cpp:func:`PyBobLearnLibsvm_StringAsKernelType`, but accepts a C-style
string instead of a Python object as input. A :py:class:`RuntimeError` is
set if the string cannot be encoded as one of the available enumerations.
You must check for :c:func:`PyErr_Occurred` after a call to this function to
make sure that the conversion was correctly performed.
.. include:: links.rst
......@@ -4,6 +4,24 @@
..
.. Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
.. testsetup::
import os
import numpy
import xbob.learn.libsvm
def F(m, f):
from pkg_resources import resource_filename
return resource_filename(m, os.path.join('data', f))
heart_model = F('xbob.learn.libsvm', 'heart.svmmodel')
svm = xbob.learn.libsvm.Machine(heart_model)
heart_data = F('xbob.learn.libsvm', 'heart.svmdata')
f = xbob.learn.libsvm.File(heart_data)
======================================
Support Vector Machines and Trainers
======================================
......@@ -43,28 +61,14 @@ using the application ``svm-train`` with default parameters). The ``shape``
attribute, indicates how many features a machine from this module can input and
how many it outputs (typically, just 1):
.. testsetup:: machine
import os
import xbob.learn.libsvm
import numpy
def F(m, f):
from pkg_resources import resource_filename
return resource_filename(m, os.path.join('data', f))
heart_model = F('xbob.learn.libsvm', 'heart.svmmodel')
svm = xbob.learn.libsvm.Machine(heart_model)
.. doctest:: machine
.. doctest::
>>> svm.shape
(13, 1)
To run a single example through the SVM, just use the ``()`` operator:
.. doctest:: machine
.. doctest::
>> svm(numpy.ones((13,), 'float64'))
1
......@@ -81,25 +85,7 @@ Below is a quick example: Suppose the variable ``f`` contains an object of
type :py:class:`xbob.learn.libsvm.File`. Then, you could read data (and labels)
from the file like this:
.. testsetup:: file
import os
import numpy
import xbob.learn.libsvm
def F(m, f):
from pkg_resources import resource_filename
return resource_filename('%s.test' % m, os.path.join('data', f))
heart_data = F('xbob.learn.libsvm', 'heart.svmdata')
f = xbob.learn.libsvm.File(heart_data)
heart_model = F('machine', 'heart.svmmodel')
svm = xbob.learn.libsvm.Machine(heart_model)
.. doctest:: file
.. doctest::
:options: +NORMALIZE_WHITESPACE
>>> labels, data = f.read_all()
......@@ -108,7 +94,7 @@ from the file like this:
Then you can throw the data into the ``svm`` machine you trained earlier like
this:
.. doctest:: file
.. doctest::
:options: +NORMALIZE_WHITESPACE
>>> predicted_labels = svm(data)
......@@ -122,7 +108,7 @@ training samples for the given class and the second dimension is the
dimensionality of the feature. For instance, let's consider the following
training set for a two class problem:
.. doctest:: trainer
.. doctest::
:options: +NORMALIZE_WHITESPACE
>>> pos = numpy.array([[1,-1,1], [0.5,-0.5,0.5], [0.75,-0.75,0.8]], 'float64')
......@@ -140,7 +126,7 @@ training set for a two class problem:
Then, an SVM [1]_ can be trained easily using the
:py:class:`xbob.learn.libsvm.Trainer` class.
.. doctest:: trainer
.. doctest::
:options: +NORMALIZE_WHITESPACE
>>> trainer = xbob.learn.libsvm.Trainer()
......@@ -149,22 +135,22 @@ Then, an SVM [1]_ can be trained easily using the
This returns a :py:class:`xbob.learn.libsvm.Machine` which can later be used
for classification, as explained before.
.. doctest:: trainer
.. doctest::
:options: +NORMALIZE_WHITESPACE
>>> predicted_label = machine(numpy.array([1.,-1.,1.]))
>>> print(predicted_label)
1
[1]
The `training` procedure allows setting several different options. For
instance, the default `kernel` is an `RBF`. If we would like a `linear SVM`
instead, this can be set before calling the
:py:meth:`xbob.learn.libsvm.Trainer.train` method.
.. doctest:: trainer
.. doctest::
:options: +NORMALIZE_WHITESPACE
>>> trainer.kernel_type = xbob.learn.libsvm.svm_kernel_type.LINEAR
>>> trainer.kernel_type = 'LINEAR'
Acknowledgements
......
......@@ -86,7 +86,7 @@ namespace bob { namespace learn { namespace libsvm {
double getCoef0() const { return m_param.coef0; }
void setCoef0(double v) { m_param.coef0 = v; }
double getCacheSizeInMB() const { return m_param.cache_size; }
double getCacheSizeInMb() const { return m_param.cache_size; }
void setCacheSizeInMb(double v) { m_param.cache_size = v; }
double getStopEpsilon() const { return m_param.eps; }
......
......@@ -224,7 +224,7 @@ PyObject* PyBobLearnLibsvmFile_reset(PyBobLearnLibsvmFileObject* self) {
PyDoc_STRVAR(s_good_str, "good");
PyDoc_STRVAR(s_good_doc,
"o.good() -> None\n\
"o.good() -> bool\n\
\n\
Returns if the file is in a good state for readout.\n\
It is ``True`` if the current file it has neither the\n\
......@@ -249,7 +249,7 @@ PyObject* PyBobLearnLibsvmFile_good(PyBobLearnLibsvmFileObject* self) {
PyDoc_STRVAR(s_fail_str, "fail");
PyDoc_STRVAR(s_fail_doc,
"o.fail() -> None\n\
"o.fail() -> bool\n\
\n\
Returns ``True`` if the file has a ``fail`` condition or\n\
``bad`` bit sets. It means the read operation has found a\n\
......@@ -276,7 +276,7 @@ PyObject* PyBobLearnLibsvmFile_fail(PyBobLearnLibsvmFileObject* self) {
PyDoc_STRVAR(s_eof_str, "eof");
PyDoc_STRVAR(s_eof_doc,
"o.eof() -> None\n\
"o.eof() -> bool\n\
\n\
Returns ``True`` if the file has reached its end. To start\n\
reading from the file again, you must call :py:meth:`File.reset`\n\
......
......@@ -21,7 +21,7 @@
PyDoc_STRVAR(s_svm_str, XBOB_EXT_MODULE_PREFIX ".Trainer");
PyDoc_STRVAR(s_svm_doc,
"Trainer([machine_type='C_SVC', [kernel_type='RBF', [cache_size=100, [eps=1e-3, [shrinking=True, [probability=False]]]]]]) -> new Trainer\n\
"Trainer([machine_type='C_SVC', [kernel_type='RBF', [cache_size=100, [stop_epsilon=1e-3, [shrinking=True, [probability=False]]]]]]) -> new Trainer\n\
\n\
This class emulates the behavior of the command line utility\n\
called ``svm-train``, from LIBSVM. It allows you to create a\n\
......@@ -31,31 +31,31 @@ global to all machine and kernel types. Specific parameters\n\
for specific machines or kernel types can be fine-tuned using\n\
object attributes (see help documentation).\n\
\n\
**Parameters**\n\
Parameters:\n\
\n\
machine_type, str\n\
The type of SVM to be trained. Valid options are:\n\
\n\
* ``'C_SVC'`` (the default)\n\
* ``'NU_SVC'``\n\
* ``'ONE_CLASS'`` (**unsupported**)\n\
* ``'EPSILON_SVR'`` (**unsupported** regression)\n\
* ``'NU_SVR'`` (**unsupported** regression)\n\
machine_type, str\n\
The type of SVM to be trained. Valid options are:\n\
\n\
* ``'C_SVC'`` (the default)\n\
* ``'NU_SVC'``\n\
* ``'ONE_CLASS'`` (**unsupported**)\n\
* ``'EPSILON_SVR'`` (**unsupported** regression)\n\
* ``'NU_SVR'`` (**unsupported** regression)\n\
\n\
kernel_type, str\n\
The type of kernel to deploy on this machine. Valid options are:\n\
\n\
* ``'LINEAR'``, for a linear kernel\n\
* ``'POLY'``, for a polynomial kernel\n\
* ``'RBF'``, for a radial-basis function kernel\n\
* ``'SIGMOID'``, for a sigmoidal kernel\n\
* ``'PRECOMPUTED'``, for a precomputed, user provided kernel\n\
* ``'LINEAR'``, for a linear kernel\n\
* ``'POLY'``, for a polynomial kernel\n\
* ``'RBF'``, for a radial-basis function kernel\n\
* ``'SIGMOID'``, for a sigmoidal kernel\n\
* ``'PRECOMPUTED'``, for a precomputed, user provided kernel\n\
please note this option is currently **unsupported**.\n\
\n\
cache_size, float\n\
The size of LIBSVM's internal cache, in megabytes\n\
\n\
eps, float\n\
stop_epsilon, float\n\
The epsilon value for the training stopping criterion\n\
\n\
shrinking, bool\n\
......@@ -92,7 +92,7 @@ static int PyBobLearnLibsvmTrainer_init
"machine_type",
"kernel_type",
"cache_size",
"eps",
"stop_epsilon",
"shrinking",
"probability",
0,
......@@ -102,12 +102,12 @@ static int PyBobLearnLibsvmTrainer_init
const char* machine_type = "C_SVC";
const char* kernel_type = "RBF";
double cache_size= 100;
double eps = 1e-3;
double stop_epsilon = 1e-3;
PyObject* shrinking = Py_True; ///< borrowed
PyObject* probability = Py_False; ///< borrowed
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssddOO", kwlist,
&machine_type, &kernel_type, &cache_size, &eps, &shrinking, &probability))
&machine_type, &kernel_type, &cache_size, &stop_epsilon, &shrinking, &probability))
return -1;
bob::learn::libsvm::machine_t c_machine_type =
......@@ -121,7 +121,7 @@ static int PyBobLearnLibsvmTrainer_init
try {
self->cxx = new bob::learn::libsvm::Trainer(c_machine_type, c_kernel_type,
cache_size, eps, c_shrinking, c_probability);
cache_size, stop_epsilon, c_shrinking, c_probability);
}
catch (std::exception& ex) {
PyErr_SetString(PyExc_RuntimeError, ex.what());
......@@ -156,12 +156,16 @@ static PyObject* PyBobLearnLibsvmTrainer_getMachineType
return PyBobLearnLibsvm_MachineTypeAsString(self->cxx->getMachineType());
}
static PyObject* PyBobLearnLibsvmTrainer_setMachineType
static int PyBobLearnLibsvmTrainer_setMachineType
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
auto m = PyBobLearnLibsvm_StringAsMachineType(o);
if (PyErr_Occurred()) return 0;
if (PyErr_Occurred()) return -1;
self->cxx->setMachineType(m);
Py_RETURN_NONE;
return 0;
}
PyDoc_STRVAR(s_svm_kernel_type_str, "kernel_type");
......@@ -173,17 +177,21 @@ static PyObject* PyBobLearnLibsvmTrainer_getKernelType
return PyBobLearnLibsvm_KernelTypeAsString(self->cxx->getKernelType());
}
static PyObject* PyBobLearnLibsvmTrainer_setKernelType
static int PyBobLearnLibsvmTrainer_setKernelType
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
auto m = PyBobLearnLibsvm_StringAsKernelType(o);
if (PyErr_Occurred()) return 0;
if (PyErr_Occurred()) return -1;
self->cxx->setKernelType(m);
Py_RETURN_NONE;
return 0;
}
PyDoc_STRVAR(s_degree_str, "degree");
PyDoc_STRVAR(s_degree_doc,
"The polinomial degree, only valid if the kernel is ``'POLY'``\n\
"The polinomial degree, only used if the kernel is ``'POLY'``\n\
(polynomial)");
static PyObject* PyBobLearnLibsvmTrainer_getDegree
......@@ -191,11 +199,15 @@ static PyObject* PyBobLearnLibsvmTrainer_getDegree
return Py_BuildValue("i", self->cxx->getDegree());
}
static PyObject* PyBobLearnLibsvmTrainer_setDegree
static int PyBobLearnLibsvmTrainer_setDegree
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
self->cxx->setDegree(PyNumber_AsSsize_t(o, PyExc_OverflowError));
if (PyErr_Occurred()) return 0;
Py_RETURN_NONE;
if (PyErr_Occurred()) return -1;
return 0;
}
PyDoc_STRVAR(s_gamma_str, "gamma");
......@@ -208,11 +220,15 @@ static PyObject* PyBobLearnLibsvmTrainer_getGamma
return Py_BuildValue("d", self->cxx->getGamma());
}
static PyObject* PyBobLearnLibsvmTrainer_setGamma
static int PyBobLearnLibsvmTrainer_setGamma
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
self->cxx->setGamma(PyFloat_AsDouble(o));
if (PyErr_Occurred()) return 0;
Py_RETURN_NONE;
if (PyErr_Occurred()) return -1;
return 0;
}
PyDoc_STRVAR(s_coef0_str, "coef0");
......@@ -225,11 +241,116 @@ static PyObject* PyBobLearnLibsvmTrainer_getCoef0
return Py_BuildValue("d", self->cxx->getCoef0());
}
static PyObject* PyBobLearnLibsvmTrainer_setCoef0
static int PyBobLearnLibsvmTrainer_setCoef0
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
self->cxx->setCoef0(PyFloat_AsDouble(o));
if (PyErr_Occurred()) return 0;
Py_RETURN_NONE;
if (PyErr_Occurred()) return -1;
return 0;
}
PyDoc_STRVAR(s_cache_size_str, "cache_size");
PyDoc_STRVAR(s_cache_size_doc,
"Internal cache size to be used by LIBSVM (in megabytes)");
static PyObject* PyBobLearnLibsvmTrainer_getCacheSize
(PyBobLearnLibsvmTrainerObject* self, void* /*closure*/) {
return Py_BuildValue("d", self->cxx->getCacheSizeInMb());
}
static int PyBobLearnLibsvmTrainer_setCacheSize
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
self->cxx->setCacheSizeInMb(PyFloat_AsDouble(o));
if (PyErr_Occurred()) return -1;
return 0;
}
PyDoc_STRVAR(s_stop_epsilon_str, "stop_epsilon");
PyDoc_STRVAR(s_stop_epsilon_doc,
"The epsilon used for stop training");
static PyObject* PyBobLearnLibsvmTrainer_getStopEpsilon
(PyBobLearnLibsvmTrainerObject* self, void* /*closure*/) {
return Py_BuildValue("d", self->cxx->getStopEpsilon());
}
static int PyBobLearnLibsvmTrainer_setStopEpsilon
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
self->cxx->setStopEpsilon(PyFloat_AsDouble(o));
if (PyErr_Occurred()) return -1;
return 0;
}
PyDoc_STRVAR(s_cost_str, "cost");
PyDoc_STRVAR(s_cost_doc,
"The cost value for ``C_SVC``, ``EPSILON_SVR`` or ``NU_SVR``");
static PyObject* PyBobLearnLibsvmTrainer_getCost
(PyBobLearnLibsvmTrainerObject* self, void* /*closure*/) {
return Py_BuildValue("d", self->cxx->getCost());
}
static int PyBobLearnLibsvmTrainer_setCost
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
self->cxx->setCost(PyFloat_AsDouble(o));
if (PyErr_Occurred()) return -1;
return 0;
}
PyDoc_STRVAR(s_nu_str, "nu");
PyDoc_STRVAR(s_nu_doc,
"The nu value for ``NU_SVC``, ``ONE_CLASS`` or ``NU_SVR``");
static PyObject* PyBobLearnLibsvmTrainer_getNu
(PyBobLearnLibsvmTrainerObject* self, void* /*closure*/) {
return Py_BuildValue("d", self->cxx->getNu());
}
static int PyBobLearnLibsvmTrainer_setNu
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
self->cxx->setNu(PyFloat_AsDouble(o));
if (PyErr_Occurred()) return -1;
return 0;
}
PyDoc_STRVAR(s_loss_epsilon_svr_str, "loss_epsilon_svr");
PyDoc_STRVAR(s_loss_epsilon_svr_doc,
"For ``EPSILON_SVR``, this is the :math:`\\epsilon` value\n\
on the equation");
static PyObject* PyBobLearnLibsvmTrainer_getLossEpsilonSVR
(PyBobLearnLibsvmTrainerObject* self, void* /*closure*/) {
return Py_BuildValue("d", self->cxx->getLossEpsilonSVR());
}
static int PyBobLearnLibsvmTrainer_setLossEpsilonSVR
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
self->cxx->setLossEpsilonSVR(PyFloat_AsDouble(o));
if (PyErr_Occurred()) return -1;
return 0;
}
PyDoc_STRVAR(s_probability_str, "probability");
......@@ -243,11 +364,15 @@ static PyObject* PyBobLearnLibsvmTrainer_getSupportsProbability
Py_RETURN_FALSE;
}
static PyObject* PyBobLearnLibsvmTrainer_setSupportsProbability
static int PyBobLearnLibsvmTrainer_setSupportsProbability
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
if (PyObject_IsTrue(o)) self->cxx->setProbabilityEstimates(true);
else self->cxx->setProbabilityEstimates(false);
Py_RETURN_NONE;
return 0;
}
PyDoc_STRVAR(s_shrinking_str, "shrinking");
......@@ -260,11 +385,15 @@ static PyObject* PyBobLearnLibsvmTrainer_getShrinking
Py_RETURN_FALSE;
}
static PyObject* PyBobLearnLibsvmTrainer_setShrinking
static int PyBobLearnLibsvmTrainer_setShrinking
(PyBobLearnLibsvmTrainerObject* self, PyObject* o, void* /*closure*/) {
if (!o) {
PyErr_SetString(PyExc_TypeError, "cannot delete attribute");
return -1;
}
if (PyObject_IsTrue(o)) self->cxx->setUseShrinking(true);
else self->cxx->setUseShrinking(false);
Py_RETURN_NONE;
return 0;
}
static PyGetSetDef PyBobLearnLibsvmTrainer_getseters[] = {
......@@ -303,6 +432,41 @@ static PyGetSetDef PyBobLearnLibsvmTrainer_getseters[] = {
s_coef0_doc,
0
},
{
s_cache_size_str,
(getter)PyBobLearnLibsvmTrainer_getCacheSize,
(setter)PyBobLearnLibsvmTrainer_setCacheSize,
s_cache_size_doc,
0
},
{
s_stop_epsilon_str,
(getter)PyBobLearnLibsvmTrainer_getStopEpsilon,
(setter)PyBobLearnLibsvmTrainer_setStopEpsilon,
s_stop_epsilon_doc,
0
},
{
s_cost_str,