[mlpack-svn] r15902 - mlpack/trunk/src/mlpack/methods/gmm
fastlab-svn at coffeetalk-1.cc.gatech.edu
fastlab-svn at coffeetalk-1.cc.gatech.edu
Wed Oct 2 17:32:33 EDT 2013
Author: rcurtin
Date: Wed Oct 2 17:32:33 2013
New Revision: 15902
Log:
Refactor EMFit<> so that the covariance constraint is a template parameter, and
update other components accordingly.
Added:
mlpack/trunk/src/mlpack/methods/gmm/no_constraint.hpp
mlpack/trunk/src/mlpack/methods/gmm/positive_definite_covariance.hpp
Modified:
mlpack/trunk/src/mlpack/methods/gmm/CMakeLists.txt
mlpack/trunk/src/mlpack/methods/gmm/em_fit.hpp
mlpack/trunk/src/mlpack/methods/gmm/em_fit_impl.hpp
mlpack/trunk/src/mlpack/methods/gmm/gmm_main.cpp
Modified: mlpack/trunk/src/mlpack/methods/gmm/CMakeLists.txt
==============================================================================
--- mlpack/trunk/src/mlpack/methods/gmm/CMakeLists.txt (original)
+++ mlpack/trunk/src/mlpack/methods/gmm/CMakeLists.txt Wed Oct 2 17:32:33 2013
@@ -3,7 +3,9 @@
set(SOURCES
gmm.hpp
gmm_impl.hpp
+ no_constraint.hpp
phi.hpp
+ positive_definite_covariance.hpp
em_fit.hpp
em_fit_impl.hpp
)
Modified: mlpack/trunk/src/mlpack/methods/gmm/em_fit.hpp
==============================================================================
--- mlpack/trunk/src/mlpack/methods/gmm/em_fit.hpp (original)
+++ mlpack/trunk/src/mlpack/methods/gmm/em_fit.hpp Wed Oct 2 17:32:33 2013
@@ -12,6 +12,8 @@
// Default clustering mechanism.
#include <mlpack/methods/kmeans/kmeans.hpp>
+// Default covariance matrix constraint.
+#include "positive_definite_covariance.hpp"
namespace mlpack {
namespace gmm {
@@ -29,7 +31,8 @@
* This method should create 'clusters' clusters, and return the assignment of
* each point to a cluster.
*/
-template<typename InitialClusteringType = kmeans::KMeans<> >
+template<typename InitialClusteringType = kmeans::KMeans<>,
+ typename CovarianceConstraintPolicy = PositiveDefiniteCovariance>
class EMFit
{
public:
@@ -52,8 +55,8 @@
*/
EMFit(const size_t maxIterations = 300,
const double tolerance = 1e-10,
- const bool forcePositive = true,
- InitialClusteringType clusterer = InitialClusteringType());
+ InitialClusteringType clusterer = InitialClusteringType(),
+ CovarianceConstraintPolicy constraint = CovarianceConstraintPolicy());
/**
* Fit the observations to a Gaussian mixture model (GMM) using the EM
@@ -93,6 +96,11 @@
//! Modify the clusterer.
InitialClusteringType& Clusterer() { return clusterer; }
+ //! Get the covariance constraint policy class.
+ const CovarianceConstraintPolicy& Constraint() const { return constraint; }
+ //! Modify the covariance constraint policy class.
+ CovarianceConstraintPolicy& Constraint() { return constraint; }
+
//! Get the maximum number of iterations of the EM algorithm.
size_t MaxIterations() const { return maxIterations; }
//! Modify the maximum number of iterations of the EM algorithm.
@@ -103,13 +111,6 @@
//! Modify the tolerance for the convergence of the EM algorithm.
double& Tolerance() { return tolerance; }
- //! Get whether or not the covariance matrices are forced to be positive
- //! definite.
- bool ForcePositive() const { return forcePositive; }
- //! Modify whether or not the covariance matrices are forced to be positive
- //! definite.
- bool& ForcePositive() { return forcePositive; }
-
private:
/**
* Run the clusterer, and then turn the cluster assignments into Gaussians.
@@ -145,10 +146,10 @@
size_t maxIterations;
//! Tolerance for convergence of EM.
double tolerance;
- //! Whether or not to force positive definiteness of covariance matrices.
- bool forcePositive;
//! Object which will perform the clustering.
InitialClusteringType clusterer;
+ //! Object which applies constraints to the covariance matrix.
+ CovarianceConstraintPolicy constraint;
};
}; // namespace gmm
Modified: mlpack/trunk/src/mlpack/methods/gmm/em_fit_impl.hpp
==============================================================================
--- mlpack/trunk/src/mlpack/methods/gmm/em_fit_impl.hpp (original)
+++ mlpack/trunk/src/mlpack/methods/gmm/em_fit_impl.hpp Wed Oct 2 17:32:33 2013
@@ -17,22 +17,24 @@
namespace gmm {
//! Constructor.
-template<typename InitialClusteringType>
-EMFit<InitialClusteringType>::EMFit(const size_t maxIterations,
- const double tolerance,
- const bool forcePositive,
- InitialClusteringType clusterer) :
+template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
+EMFit<InitialClusteringType, CovarianceConstraintPolicy>::EMFit(
+ const size_t maxIterations,
+ const double tolerance,
+ InitialClusteringType clusterer,
+ CovarianceConstraintPolicy constraint) :
maxIterations(maxIterations),
tolerance(tolerance),
- forcePositive(forcePositive),
- clusterer(clusterer)
+ clusterer(clusterer),
+ constraint(constraint)
{ /* Nothing to do. */ }
-template<typename InitialClusteringType>
-void EMFit<InitialClusteringType>::Estimate(const arma::mat& observations,
- std::vector<arma::vec>& means,
- std::vector<arma::mat>& covariances,
- arma::vec& weights)
+template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
+void EMFit<InitialClusteringType, CovarianceConstraintPolicy>::Estimate(
+ const arma::mat& observations,
+ std::vector<arma::vec>& means,
+ std::vector<arma::mat>& covariances,
+ arma::vec& weights)
{
InitialClustering(observations, means, covariances, weights);
@@ -94,19 +96,8 @@
if (probRowSums[i] != 0.0)
covariances[i] = (tmp * trans(tmpB)) / probRowSums[i];
- // Ensure positive-definiteness. TODO: make this more efficient.
- if (forcePositive && det(covariances[i]) <= 1e-50)
- {
- Log::Debug << "Covariance matrix " << i << " is not positive definite. "
- << "Adding perturbation." << std::endl;
-
- double perturbation = 1e-30;
- while (det(covariances[i]) <= 1e-50)
- {
- covariances[i].diag() += perturbation;
- perturbation *= 10; // Slow, but we don't want to add too much.
- }
- }
+ // Apply covariance constraint.
+ constraint.ApplyConstraint(covariances[i]);
}
// Calculate the new values for omega using the updated conditional
@@ -121,12 +112,13 @@
}
}
-template<typename InitialClusteringType>
-void EMFit<InitialClusteringType>::Estimate(const arma::mat& observations,
- const arma::vec& probabilities,
- std::vector<arma::vec>& means,
- std::vector<arma::mat>& covariances,
- arma::vec& weights)
+template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
+void EMFit<InitialClusteringType, CovarianceConstraintPolicy>::Estimate(
+ const arma::mat& observations,
+ const arma::vec& probabilities,
+ std::vector<arma::vec>& means,
+ std::vector<arma::mat>& covariances,
+ arma::vec& weights)
{
InitialClustering(observations, means, covariances, weights);
@@ -189,19 +181,8 @@
covariances[i] = (tmp * trans(tmpB)) / probRowSums[i];
- // Ensure positive-definiteness. TODO: make this more efficient.
- if (forcePositive && det(covariances[i]) <= 1e-50)
- {
- Log::Debug << "Covariance matrix " << i << " is not positive definite. "
- << "Adding perturbation." << std::endl;
-
- double perturbation = 1e-30;
- while (det(covariances[i]) <= 1e-50)
- {
- covariances[i].diag() += perturbation;
- perturbation *= 10; // Slow, but we don't want to add too much.
- }
- }
+ // Apply covariance constraint.
+ constraint.ApplyConstraint(covariances[i]);
}
// Calculate the new values for omega using the updated conditional
@@ -216,12 +197,12 @@
}
}
-template<typename InitialClusteringType>
-void EMFit<InitialClusteringType>::InitialClustering(
- const arma::mat& observations,
- std::vector<arma::vec>& means,
- std::vector<arma::mat>& covariances,
- arma::vec& weights)
+template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
+void EMFit<InitialClusteringType, CovarianceConstraintPolicy>::
+InitialClustering(const arma::mat& observations,
+ std::vector<arma::vec>& means,
+ std::vector<arma::mat>& covariances,
+ arma::vec& weights)
{
// Assignments from clustering.
arma::Col<size_t> assignments;
@@ -272,27 +253,16 @@
{
covariances[i] /= (weights[i] > 1) ? weights[i] : 1;
- // Ensure positive-definiteness. TODO: make this more efficient.
- if (forcePositive && det(covariances[i]) <= 1e-50)
- {
- Log::Debug << "Covariance matrix " << i << " is not positive definite. "
- << "Adding perturbation." << std::endl;
-
- double perturbation = 1e-50;
- while (det(covariances[i]) <= 1e-50)
- {
- covariances[i].diag() += perturbation;
- perturbation *= 10; // Slow, but we don't want to add too much.
- }
- }
+ // Apply constraints to covariance matrix.
+ constraint.ApplyConstraint(covariances[i]);
}
// Finally, normalize weights.
weights /= accu(weights);
}
-template<typename InitialClusteringType>
-double EMFit<InitialClusteringType>::LogLikelihood(
+template<typename InitialClusteringType, typename CovarianceConstraintPolicy>
+double EMFit<InitialClusteringType, CovarianceConstraintPolicy>::LogLikelihood(
const arma::mat& observations,
const std::vector<arma::vec>& means,
const std::vector<arma::mat>& covariances,
Modified: mlpack/trunk/src/mlpack/methods/gmm/gmm_main.cpp
==============================================================================
--- mlpack/trunk/src/mlpack/methods/gmm/gmm_main.cpp (original)
+++ mlpack/trunk/src/mlpack/methods/gmm/gmm_main.cpp Wed Oct 2 17:32:33 2013
@@ -7,6 +7,7 @@
#include <mlpack/core.hpp>
#include "gmm.hpp"
+#include "no_constraint.hpp"
#include <mlpack/methods/kmeans/refined_start.hpp>
@@ -14,6 +15,7 @@
using namespace mlpack::gmm;
using namespace mlpack::util;
using namespace mlpack::kmeans;
+using namespace std;
PROGRAM_INFO("Gaussian Mixture Model (GMM) Training",
"This program takes a parametric estimate of a Gaussian mixture model (GMM)"
@@ -73,7 +75,7 @@
math::RandomSeed((size_t) std::time(NULL));
arma::mat dataPoints;
- data::Load(CLI::GetParam<std::string>("input_file"), dataPoints,
+ data::Load(CLI::GetParam<string>("input_file"), dataPoints,
true);
const int gaussians = CLI::GetParam<int>("gaussians");
@@ -121,35 +123,74 @@
KMeansType k(1000, 1.0, metric::SquaredEuclideanDistance(),
RefinedStart(samplings, percentage));
- EMFit<KMeansType> em(maxIterations, tolerance, forcePositive, k);
-
- GMM<EMFit<KMeansType> > gmm(size_t(gaussians), dataPoints.n_rows, em);
-
- // Compute the parameters of the model using the EM algorithm.
- Timer::Start("em");
- likelihood = gmm.Estimate(dataPoints, CLI::GetParam<int>("trials"));
- Timer::Stop("em");
-
- // Save results.
- gmm.Save(CLI::GetParam<std::string>("output_file"));
+ // Depending on the value of 'forcePositive', we have to use different
+ // types.
+ if (forcePositive)
+ {
+ EMFit<KMeansType> em(maxIterations, tolerance, k);
+
+ GMM<EMFit<KMeansType> > gmm(size_t(gaussians), dataPoints.n_rows, em);
+
+ // Compute the parameters of the model using the EM algorithm.
+ Timer::Start("em");
+ likelihood = gmm.Estimate(dataPoints, CLI::GetParam<int>("trials"));
+ Timer::Stop("em");
+
+ // Save results.
+ gmm.Save(CLI::GetParam<string>("output_file"));
+ }
+ else
+ {
+ EMFit<KMeansType, NoConstraint> em(maxIterations, tolerance, k);
+
+ GMM<EMFit<KMeansType, NoConstraint> > gmm(size_t(gaussians),
+ dataPoints.n_rows, em);
+
+ // Compute the parameters of the model using the EM algorithm.
+ Timer::Start("em");
+ likelihood = gmm.Estimate(dataPoints, CLI::GetParam<int>("trials"));
+ Timer::Stop("em");
+
+ // Save results.
+ gmm.Save(CLI::GetParam<string>("output_file"));
+ }
}
else
{
- EMFit<> em(maxIterations, tolerance, forcePositive);
-
- // Calculate mixture of Gaussians.
- GMM<> gmm(size_t(gaussians), dataPoints.n_rows, em);
-
- // Compute the parameters of the model using the EM algorithm.
- Timer::Start("em");
- likelihood = gmm.Estimate(dataPoints, CLI::GetParam<int>("trials"));
- Timer::Stop("em");
-
- // Save results.
- gmm.Save(CLI::GetParam<std::string>("output_file"));
+ // Depending on the value of forcePositive, we have to use different types.
+ if (forcePositive)
+ {
+ EMFit<> em(maxIterations, tolerance);
+
+ // Calculate mixture of Gaussians.
+ GMM<> gmm(size_t(gaussians), dataPoints.n_rows, em);
+
+ // Compute the parameters of the model using the EM algorithm.
+ Timer::Start("em");
+ likelihood = gmm.Estimate(dataPoints, CLI::GetParam<int>("trials"));
+ Timer::Stop("em");
+
+ // Save results.
+ gmm.Save(CLI::GetParam<string>("output_file"));
+ }
+ else
+ {
+ // Use no constraints on the covariance matrix.
+ EMFit<KMeans<>, NoConstraint> em(maxIterations, tolerance);
+
+ // Calculate mixture of Gaussians.
+ GMM<EMFit<KMeans<>, NoConstraint> > gmm(size_t(gaussians),
+ dataPoints.n_rows, em);
+
+ // Compute the parameters of the model using the EM algorithm.
+ Timer::Start("em");
+ likelihood = gmm.Estimate(dataPoints, CLI::GetParam<int>("trials"));
+ Timer::Stop("em");
+
+ // Save results.
+ gmm.Save(CLI::GetParam<string>("output_file"));
+ }
}
Log::Info << "Log-likelihood of estimate: " << likelihood << ".\n";
-
-
}
Added: mlpack/trunk/src/mlpack/methods/gmm/no_constraint.hpp
==============================================================================
--- (empty file)
+++ mlpack/trunk/src/mlpack/methods/gmm/no_constraint.hpp Wed Oct 2 17:32:33 2013
@@ -0,0 +1,30 @@
+/**
+ * @file no_constraint.hpp
+ * @author Ryan Curtin
+ *
+ * No constraint on the covariance matrix.
+ */
+#ifndef __MLPACK_METHODS_GMM_NO_CONSTRAINT_HPP
+#define __MLPACK_METHODS_GMM_NO_CONSTRAINT_HPP
+
+#include <mlpack/core.hpp>
+
+namespace mlpack {
+namespace gmm {
+
+/**
+ * This class enforces no constraint on the covariance matrix. It's faster this
+ * way, although depending on your situation you may end up with a
+ * non-invertible covariance matrix.
+ */
+class NoConstraint
+{
+ public:
+ //! Do nothing, and do not modify the covariance matrix.
+ void ApplyConstraint(const arma::mat& /* covariance */) { }
+};
+
+}; // namespace gmm
+}; // namespace mlpack
+
+#endif
Added: mlpack/trunk/src/mlpack/methods/gmm/positive_definite_covariance.hpp
==============================================================================
--- (empty file)
+++ mlpack/trunk/src/mlpack/methods/gmm/positive_definite_covariance.hpp Wed Oct 2 17:32:33 2013
@@ -0,0 +1,45 @@
+/**
+ * @file positive_definite_covariance.hpp
+ * @author Ryan Curtin
+ *
+ * Restricts a covariance matrix to being positive definite.
+ */
+#ifndef __MLPACK_METHODS_GMM_POSITIVE_DEFINITE_COVARIANCE_HPP
+#define __MLPACK_METHODS_GMM_POSITIVE_DEFINITE_COVARIANCE_HPP
+
+namespace mlpack {
+namespace gmm {
+
+/**
+ * Given a covariance matrix, force the matrix to be positive definite.
+ */
+class PositiveDefiniteCovariance
+{
+ public:
+ /**
+ * Apply the positive definiteness constraint to the given covariance matrix.
+ *
+ * @param covariance Covariance matrix.
+ */
+ static void ApplyConstraint(arma::mat& covariance)
+ {
+ // TODO: make this more efficient.
+ if (det(covariance) <= 1e-50)
+ {
+ Log::Debug << "Covariance matrix is not positive definite. Adding "
+ << "perturbation." << std::endl;
+
+ double perturbation = 1e-30;
+ while (det(covariance) <= 1e-50)
+ {
+ covariance.diag() += perturbation;
+ perturbation *= 10;
+ }
+ }
+ }
+};
+
+}; // namespace gmm
+}; // namespace mlpack
+
+#endif
More information about the mlpack-svn
mailing list