diff --git a/bob/learn/em/gmm_machine.cpp b/bob/learn/em/gmm_machine.cpp
index 17a76a612c97ac04fe5ad20b234b94fc9dc2ea69..4da2b778c735e31a1ea5facaee34002b46177b93 100644
--- a/bob/learn/em/gmm_machine.cpp
+++ b/bob/learn/em/gmm_machine.cpp
@@ -745,7 +745,7 @@ static PyObject* PyBobLearnEMGMMMachine_loglikelihood_(PyBobLearnEMGMMMachineObj
 /*** 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.",
+  "Accumulate the GMM statistics (:py:class:`bob.learn.em.GMMStats`) for this sample(s). Inputs are checked.",
   "",
   true
 )
@@ -781,7 +781,7 @@ static PyObject* PyBobLearnEMGMMMachine_accStatistics(PyBobLearnEMGMMMachineObje
 /*** 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.",
+  "Accumulate the GMM statistics (:py:class:`bob.learn.em.GMMStats`) for this sample(s). Inputs are NOT checked.",
   "",
   true
 )
diff --git a/bob/learn/em/isv_machine.cpp b/bob/learn/em/isv_machine.cpp
index 375bf48feb5f49edf1ec16c5128488ce88db0438..9486e7e258520a0112efc5421e4c8da0a2ca7c21 100644
--- a/bob/learn/em/isv_machine.cpp
+++ b/bob/learn/em/isv_machine.cpp
@@ -69,15 +69,15 @@ static int PyBobLearnEMISVMachine_init_hdf5(PyBobLearnEMISVMachineObject* self,
 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  
+  //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;
 }
@@ -115,7 +115,7 @@ static int PyBobLearnEMISVMachine_init(PyBobLearnEMISVMachineObject* self, PyObj
     ISVMachine_doc.print_usage();
     return -1;
   }
-  
+
   BOB_CATCH_MEMBER("cannot create ISVMachine", -1)
   return 0;
 }
@@ -173,8 +173,8 @@ static auto supervector_length = bob::extension::VariableDoc(
   "int",
 
   "Returns the supervector length.",
-  "NGaussians x NInputs: Number of Gaussian components by the feature dimensionality"
-  "@warning An exception is thrown if no Universal Background Model has been set yet."
+  "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*) {
@@ -203,17 +203,17 @@ int PyBobLearnEMISVMachine_setZ(PyBobLearnEMISVMachineObject* self, PyObject* va
     return -1;
   }
   auto o_ = make_safe(input);
-  
-  // perform check on the 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());
@@ -276,13 +276,13 @@ int PyBobLearnEMISVMachine_setISVBase(PyBobLearnEMISVMachineObject* self, PyObje
   self->cxx->setISVBase(isv_base_o->cxx);
 
   return 0;
-  BOB_CATCH_MEMBER("isv_base could not be set", -1)  
+  BOB_CATCH_MEMBER("isv_base could not be set", -1)
 }
 
 
 
 
-static PyGetSetDef PyBobLearnEMISVMachine_getseters[] = { 
+static PyGetSetDef PyBobLearnEMISVMachine_getseters[] = {
   {
    shape.name(),
    (getter)PyBobLearnEMISVMachine_getShape,
@@ -290,7 +290,7 @@ static PyGetSetDef PyBobLearnEMISVMachine_getseters[] = {
    shape.doc(),
    0
   },
-  
+
   {
    supervector_length.name(),
    (getter)PyBobLearnEMISVMachine_getSupervectorLength,
@@ -298,7 +298,7 @@ static PyGetSetDef PyBobLearnEMISVMachine_getseters[] = {
    supervector_length.doc(),
    0
   },
-  
+
   {
    isv_base.name(),
    (getter)PyBobLearnEMISVMachine_getISVBase,
@@ -343,9 +343,9 @@ static auto save = bob::extension::FunctionDoc(
 static PyObject* PyBobLearnEMISVMachine_Save(PyBobLearnEMISVMachineObject* self,  PyObject* args, PyObject* kwargs) {
 
   BOB_TRY
-  
+
   // get list of arguments
-  char** kwlist = save.kwlist(0);  
+  char** kwlist = save.kwlist(0);
   PyBobIoHDF5FileObject* hdf5;
   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0;
 
@@ -365,12 +365,12 @@ static auto load = bob::extension::FunctionDoc(
 .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);  
+
+  char** kwlist = load.kwlist(0);
   PyBobIoHDF5FileObject* hdf5;
   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, PyBobIoHDF5File_Converter, &hdf5)) return 0;
-  
-  auto hdf5_ = make_safe(hdf5);  
+
+  auto hdf5_ = make_safe(hdf5);
   self->cxx->load(*hdf5->f);
 
   BOB_CATCH_MEMBER("cannot load the data", 0)
@@ -381,7 +381,7 @@ static PyObject* PyBobLearnEMISVMachine_Load(PyBobLearnEMISVMachineObject* self,
 /*** 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`` "
@@ -406,8 +406,8 @@ static PyObject* PyBobLearnEMISVMachine_IsSimilarTo(PyBobLearnEMISVMachineObject
         &PyBobLearnEMISVMachine_Type, &other,
         &r_epsilon, &a_epsilon)){
 
-        is_similar_to.print_usage(); 
-        return 0;        
+        is_similar_to.print_usage();
+        return 0;
   }
 
   if (self->cxx->is_similar_to(*other->cxx, r_epsilon, a_epsilon))
@@ -421,7 +421,7 @@ static PyObject* PyBobLearnEMISVMachine_IsSimilarTo(PyBobLearnEMISVMachineObject
 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", 
+  "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")
@@ -435,29 +435,29 @@ static PyObject* PyBobLearnEMISVMachine_estimateX(PyBobLearnEMISVMachineObject*
   PyBobLearnEMGMMStatsObject* stats = 0;
   PyBlitzArrayObject* input           = 0;
 
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMStats_Type, &stats, 
+  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  
+
+  // 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)
@@ -469,7 +469,7 @@ static PyObject* PyBobLearnEMISVMachine_estimateX(PyBobLearnEMISVMachineObject*
 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.", 
+  "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")
@@ -483,29 +483,29 @@ static PyObject* PyBobLearnEMISVMachine_estimateUx(PyBobLearnEMISVMachineObject*
   PyBobLearnEMGMMStatsObject* stats = 0;
   PyBlitzArrayObject* input           = 0;
 
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMStats_Type, &stats, 
+  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  
+
+  // 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)
@@ -517,7 +517,7 @@ static PyObject* PyBobLearnEMISVMachine_estimateUx(PyBobLearnEMISVMachineObject*
 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")
@@ -531,30 +531,30 @@ static PyObject* PyBobLearnEMISVMachine_ForwardUx(PyBobLearnEMISVMachineObject*
   PyBobLearnEMGMMStatsObject* stats = 0;
   PyBlitzArrayObject* ux_input        = 0;
 
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&", kwlist, &PyBobLearnEMGMMStats_Type, &stats, 
+  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  
+
+  // 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)
 }
@@ -564,7 +564,7 @@ static PyObject* PyBobLearnEMISVMachine_ForwardUx(PyBobLearnEMISVMachineObject*
 static auto forward = bob::extension::FunctionDoc(
   "forward",
   "Execute the machine",
-  "", 
+  "",
   true
 )
 .add_prototype("stats")
@@ -575,7 +575,7 @@ static PyObject* PyBobLearnEMISVMachine_Forward(PyBobLearnEMISVMachineObject* se
   char** kwlist = forward.kwlist(0);
 
   PyBobLearnEMGMMStatsObject* stats = 0;
-  
+
   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", kwlist, &PyBobLearnEMGMMStats_Type, &stats))
     return 0;
 
@@ -607,14 +607,14 @@ static PyMethodDef PyBobLearnEMISVMachine_methods[] = {
     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,
diff --git a/bob/learn/em/ivector_machine.cpp b/bob/learn/em/ivector_machine.cpp
index b101be1debb3fa77b2d23399b25d6ee633ce5899..70bc5cf8c4f63c95f31b55147151b3b2702b9ced 100644
--- a/bob/learn/em/ivector_machine.cpp
+++ b/bob/learn/em/ivector_machine.cpp
@@ -15,7 +15,7 @@
 
 static auto IVectorMachine_doc = bob::extension::ClassDoc(
   BOB_EXT_MODULE_PREFIX ".IVectorMachine",
-  "Statistical model for the Total Variability training (:ref:`iVectors <ivector>`)"
+  "Statistical model for the Total Variability training (see iVectors in the user guide)"
   "",
   ""
 ).add_constructor(
diff --git a/bob/learn/em/jfa_machine.cpp b/bob/learn/em/jfa_machine.cpp
index fce093625fcd17aacd68b240e15137dcad332cf4..95ceb9766959bbd31d55e269f31bc9c2c4b1dd93 100644
--- a/bob/learn/em/jfa_machine.cpp
+++ b/bob/learn/em/jfa_machine.cpp
@@ -173,8 +173,8 @@ static auto supervector_length = bob::extension::VariableDoc(
   "int",
 
   "Returns the supervector length.",
-  "NGaussians x NInputs: Number of Gaussian components by the feature dimensionality"
-  "@warning An exception is thrown if no Universal Background Model has been set yet."
+  "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*) {
diff --git a/bob/learn/em/kmeans_trainer.cpp b/bob/learn/em/kmeans_trainer.cpp
index f06dc4279769b5a0d40c0cd798c83c3ee09b86be..bee044a484250b2512586aa4609e18c9e9af3cf2 100644
--- a/bob/learn/em/kmeans_trainer.cpp
+++ b/bob/learn/em/kmeans_trainer.cpp
@@ -42,7 +42,7 @@ static inline const std::string& IM2string(bob::learn::em::KMeansTrainer::Initia
 
 static auto KMeansTrainer_doc = bob::extension::ClassDoc(
   BOB_EXT_MODULE_PREFIX ".KMeansTrainer",
-  "Trains a KMeans clustering :ref:`k-means <kmeans>.`"
+  "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"
diff --git a/doc/py_api.rst b/doc/py_api.rst
index 9bf055af98111dd3756820595db3bdffa18a9c62..0209c755d2013f0ca94ddadc35264ef39273a658 100644
--- a/doc/py_api.rst
+++ b/doc/py_api.rst
@@ -17,21 +17,21 @@ Trainers
 ........
 
 .. autosummary::
-  
+
   bob.learn.em.KMeansTrainer
   bob.learn.em.ML_GMMTrainer
   bob.learn.em.MAP_GMMTrainer
   bob.learn.em.ISVTrainer
-  bob.learn.em.JFATrainer  
+  bob.learn.em.JFATrainer
   bob.learn.em.IVectorTrainer
   bob.learn.em.PLDATrainer
   bob.learn.em.EMPCATrainer
-  
+
 Machines
 ........
 
-.. autosummary::  
-  
+.. autosummary::
+
   bob.learn.em.KMeansMachine
   bob.learn.em.Gaussian
   bob.learn.em.GMMStats
@@ -43,7 +43,7 @@ Machines
   bob.learn.em.IVectorMachine
   bob.learn.em.PLDABase
   bob.learn.em.PLDAMachine
-  
+
 Functions
 ---------
 .. autosummary::