Merge pull request #1899 from Yashwants19/gmm-test

Add GMM test for command-line and python bindings
This commit is contained in:
Ryan Curtin
2019-07-06 16:25:40 -04:00
committed by GitHub
5 changed files with 650 additions and 1 deletions
@@ -145,12 +145,18 @@ static void mlpackMain()
"number of Gaussians must be positive");
const int gaussians = CLI::GetParam<int>("gaussians");
RequireParamValue<int>("trials", [](int x) { return x > 0; }, true,
"trials must be greater than 0");
ReportIgnoredParam({{ "diagonal_covariance", true }}, "no_force_positive");
RequireAtLeastOnePassed({ "output_model" }, false, "no model will be saved");
RequireParamValue<double>("noise", [](double x) { return x >= 0.0; }, true,
"variance of noise must be greater than or equal to 0");
RequireParamValue<int>("max_iterations", [](int x) { return x >= 0; }, true,
"max_iterations must be greater than or equal to 0");
arma::mat dataPoints = std::move(CLI::GetParam<arma::mat>("input"));
// Do we need to add noise to the dataset?
+4 -1
View File
@@ -122,6 +122,9 @@ add_executable(mlpack_test
main_tests/det_test.cpp
main_tests/decision_tree_test.cpp
main_tests/decision_stump_test.cpp
main_tests/gmm_generate_test.cpp
main_tests/gmm_probability_test.cpp
main_tests/gmm_train_test.cpp
main_tests/fastmks_test.cpp
main_tests/kde_test.cpp
main_tests/linear_regression_test.cpp
@@ -186,7 +189,7 @@ set(parallel_tests
"SVDIncrementalTest;SVDBatchTest;"
"LocalCoordinateCodingTest;FeedForwardNetworkTest;SparseAutoencoderTest;"
"GMMTest;CFTest;ConvolutionalNetworkTest;HMMTest;LARSTest;"
"LogisticRegressionTest;"
"LogisticRegressionTest;GmmTrainMainTest;"
"LinearSVMTest")
# Add tests to the testing framework
@@ -0,0 +1,78 @@
/**
* @file gmm_generate_test.cpp
* @author Yashwant Singh
*
* Test mlpackMain() of gmm_generate_main.cpp.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#define BINDING_TYPE BINDING_TYPE_TEST
static const std::string testName = "GmmGenerate";
#include <mlpack/core.hpp>
#include <mlpack/core/util/mlpack_main.hpp>
#include <mlpack/methods/gmm/gmm_generate_main.cpp>
#include "test_helper.hpp"
#include <boost/test/unit_test.hpp>
#include "../test_tools.hpp"
using namespace mlpack;
struct GmmGenerateTestFixture
{
public:
GmmGenerateTestFixture()
{
// Cache in the options for this program.
CLI::RestoreSettings(testName);
}
~GmmGenerateTestFixture()
{
// Clear the settings.
CLI::ClearSettings();
}
};
BOOST_FIXTURE_TEST_SUITE(GmmGenerateMainTest, GmmGenerateTestFixture);
// Checking that Samples must greater than 0.
BOOST_AUTO_TEST_CASE(GmmGenerateSamplesTest)
{
arma::mat inputData(5, 10, arma::fill::randu);
GMM gmm(1, 5);
gmm.Train(inputData, 5);
SetInputParam("input_model", &gmm);
Log::Fatal.ignoreInput = true;
SetInputParam("samples", 0); // Invalid
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
// Checking dimensionality of output.
BOOST_AUTO_TEST_CASE(GmmGenerateDimensionality)
{
arma::mat inputData(5, 10, arma::fill::randu);
GMM gmm(1, 5);
gmm.Train(inputData, 5);
SetInputParam("input_model", &gmm);
SetInputParam("samples", (int) 10);
mlpackMain();
arma::mat output = std::move(CLI::GetParam<arma::mat>("output"));
BOOST_REQUIRE_EQUAL(output.n_rows, gmm.Dimensionality());
BOOST_REQUIRE_EQUAL(output.n_cols, (int) 10);
}
BOOST_AUTO_TEST_SUITE_END();
@@ -0,0 +1,72 @@
/**
* @file gmm_probability_test.cpp
* @author Yashwant Singh
*
* Test mlpackMain() of gmm_probability_main.cpp.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#define BINDING_TYPE BINDING_TYPE_TEST
static const std::string testName = "GmmProbability";
#include <mlpack/core.hpp>
#include <mlpack/core/util/mlpack_main.hpp>
#include <mlpack/methods/gmm/gmm_probability_main.cpp>
#include "test_helper.hpp"
#include <boost/test/unit_test.hpp>
using namespace mlpack;
struct GmmProbabilityTestFixture
{
public:
GmmProbabilityTestFixture()
{
// Cache in the options for this program.
CLI::RestoreSettings(testName);
}
~GmmProbabilityTestFixture()
{
// Clear the settings.
CLI::ClearSettings();
}
};
void ResetGmmProbabilitySetting()
{
CLI::ClearSettings();
CLI::RestoreSettings(testName);
}
BOOST_FIXTURE_TEST_SUITE(GmmProbabilityMainTest, GmmProbabilityTestFixture);
// Checking the input and output dimensionality.
BOOST_AUTO_TEST_CASE(GmmProbabilityDimensionality)
{
arma::mat inputData(5, 10, arma::fill::randu);
GMM gmm(1, 5);
gmm.Train(std::move(inputData), 5);
arma::mat inputPoints(5, 5, arma::fill::randu);
SetInputParam("input", std::move(inputPoints));
SetInputParam("input_model", &gmm);
mlpackMain();
BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("output").n_cols, 5);
BOOST_REQUIRE_EQUAL(CLI::GetParam<arma::mat>("output").n_rows, 1);
}
BOOST_AUTO_TEST_SUITE_END();
@@ -0,0 +1,490 @@
/**
* @file gmm_train_test.cpp
* @author Yashwant Singh
*
* Test mlpackMain() of gmm_train_main.cpp.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include<string>
#define BINDING_TYPE BINDING_TYPE_TEST
static const std::string testName = "GmmTrain";
#include <mlpack/core.hpp>
#include <mlpack/core/util/mlpack_main.hpp>
#include "test_helper.hpp"
#include <mlpack/methods/gmm/gmm_train_main.cpp>
#include <boost/test/unit_test.hpp>
#include "../test_tools.hpp"
using namespace mlpack;
struct GmmTrainTestFixture
{
public:
GmmTrainTestFixture()
{
// Cache in the options for this program.
CLI::RestoreSettings(testName);
}
~GmmTrainTestFixture()
{
// Clear the settings.
bindings::tests::CleanMemory();
CLI::ClearSettings();
}
};
void ResetGmmTrainSetting()
{
CLI::ClearSettings();
CLI::RestoreSettings(testName);
}
BOOST_FIXTURE_TEST_SUITE(GmmTrainMainTest, GmmTrainTestFixture);
// To check if the gaussian is positive or not.
BOOST_AUTO_TEST_CASE(GmmTrainValidGaussianTest)
{
arma::mat inputData(5, 10, arma::fill::randu);
SetInputParam("input", std::move(inputData));
SetInputParam("gaussians", 0); // Invalid
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* To check if the number of gaussians in the output model is same as
* that of input gaussian parameter or not.
**/
BOOST_AUTO_TEST_CASE(GmmTrainOutputModelGaussianTest)
{
arma::mat inputData(5, 10, arma::fill::randu);
SetInputParam("input", std::move(inputData));
SetInputParam("gaussians", (int) 2);
SetInputParam("trials", (int) 2);
mlpackMain();
GMM* gmm = CLI::GetParam<GMM*>("output_model");
BOOST_REQUIRE_EQUAL(gmm->Gaussians(), (int) 2);
}
// Max iterations must be positive.
BOOST_AUTO_TEST_CASE(GmmTrainMaxIterationsTest)
{
arma::mat inputData(5, 10, arma::fill::randu);
SetInputParam("input", std::move(inputData));
SetInputParam("gaussians", (int) 2);
SetInputParam("trials", (int) 1);
SetInputParam("max_iterations", (int)-1); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
// Ensure that Trials must be greater than 0.
BOOST_AUTO_TEST_CASE(GmmTrainPositiveTrialsTest)
{
arma::mat inputData(5, 10, arma::fill::randu);
SetInputParam("input", std::move(inputData));
SetInputParam("gaussians", (int) 2);
SetInputParam("trials", (int) 0); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
// Checking that percentage is between 0 and 1.
BOOST_AUTO_TEST_CASE(RefinedStartPercentageTest)
{
arma::mat inputData(5, 10, arma::fill::randu);
SetInputParam("input", std::move(inputData));
SetInputParam("refined_start", true);
Log::Fatal.ignoreInput = true;
SetInputParam("percentage", (double) 2.0); // Invalid
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
SetInputParam("percentage", (double) -1.0); // Invalid
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
// Samplings must be positive.
BOOST_AUTO_TEST_CASE(GmmTrainSamplings)
{
arma::mat inputData(5, 10, arma::fill::randu);
SetInputParam("input", std::move(inputData));
SetInputParam("refined_start", true);
SetInputParam("samplings", (int) 0); // Invalid
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
// Number of gaussians in the model trained from input model.
BOOST_AUTO_TEST_CASE(GmmTrainNumberOfGaussian)
{
arma::mat inputData(5, 10, arma::fill::randu);
SetInputParam("input", inputData);
SetInputParam("gaussians", (int) 2);
mlpackMain();
GMM* gmm = CLI::GetParam<GMM*>("output_model");
SetInputParam("input_model", gmm);
CLI::GetSingleton().Parameters()["input"].wasPassed = false;
SetInputParam("input", std::move(inputData));
mlpackMain();
GMM* gmm1 = CLI::GetParam<GMM*>("output_model");
BOOST_REQUIRE_EQUAL(gmm1->Gaussians(), (int) 2);
}
// Making sure that enabling no_force_positive doesn't crash.
BOOST_AUTO_TEST_CASE(GmmTrainNoForcePositiveTest)
{
arma::mat inputData(5, 10, arma::fill::randu);
SetInputParam("input", inputData);
SetInputParam("gaussians", (int) 1);
SetInputParam("no_force_positive", true);
mlpackMain();
GMM* gmm = CLI::GetParam<GMM*>("output_model");
SetInputParam("input_model", gmm);
CLI::GetSingleton().Parameters()["input"].wasPassed = false;
SetInputParam("input", std::move(inputData));
mlpackMain();
GMM* gmm1 = CLI::GetParam<GMM*>("output_model");
BOOST_REQUIRE_EQUAL(gmm1->Gaussians(), (int) 1);
}
// Ensure that Noise affects the final result.
BOOST_AUTO_TEST_CASE(GmmTrainNoiseTest)
{
arma::mat inputData;
if (!data::Load("data_3d_mixed.txt", inputData))
BOOST_FAIL("Unable to load train dataset data_3d_mixed.txt!");
SetInputParam("input", inputData);
SetInputParam("gaussians", (int) 2);
SetInputParam("noise", (double) 0.0);
size_t seed = std::time(NULL);
mlpack::math::randGen.seed((uint32_t) seed);
srand((unsigned int) seed);
arma::arma_rng::set_seed(seed);
mlpackMain();
GMM* gmm = CLI::GetParam<GMM*>("output_model");
ResetGmmTrainSetting();
SetInputParam("input", std::move(inputData));
SetInputParam("gaussians", (int) 2);
SetInputParam("noise", (double) 100.0);
mlpack::math::randGen.seed((uint32_t) seed);
srand((unsigned int) seed);
arma::arma_rng::set_seed(seed);
mlpackMain();
GMM* gmm1 = CLI::GetParam<GMM*>("output_model");
arma::uvec sortedIndices = sort_index(gmm->Weights());
for (size_t k = 0; k < sortedIndices.n_elem; k++)
{
BOOST_REQUIRE(arma::norm(gmm->Component(sortedIndices[k]).Mean() -
gmm1->Component(sortedIndices[k]).Mean()) > 1e-50 ||
arma::norm(gmm->Component(sortedIndices[k]).Covariance() -
gmm1->Component(sortedIndices[k]).Covariance()) > 1e-50);
}
}
// Ensure that Trials affects the final result.
BOOST_AUTO_TEST_CASE(GmmTrainTrialsTest)
{
arma::mat inputData(5, 250, arma::fill::randu);
SetInputParam("input", inputData);
SetInputParam("gaussians", (int) 3);
SetInputParam("trials", (int) 1);
SetInputParam("max_iterations", (int) 500);
size_t seed = std::time(NULL);
mlpack::math::randGen.seed((uint32_t) seed);
srand((unsigned int) seed);
arma::arma_rng::set_seed(seed);
mlpackMain();
GMM* gmm = CLI::GetParam<GMM*>("output_model");
ResetGmmTrainSetting();
SetInputParam("input", std::move(inputData));
SetInputParam("gaussians", (int) 3);
SetInputParam("max_iterations", (int) 500);
SetInputParam("trials", (int) 500);
mlpack::math::randGen.seed((uint32_t) seed);
srand((unsigned int) seed);
arma::arma_rng::set_seed(seed);
mlpackMain();
GMM* gmm1 = CLI::GetParam<GMM*>("output_model");
arma::uvec sortedIndices = sort_index(gmm->Weights());
for (size_t k = 0; k < sortedIndices.n_elem; k++)
{
BOOST_REQUIRE(arma::norm(gmm->Component(sortedIndices[k]).Mean() -
gmm1->Component(sortedIndices[k]).Mean()) > 1e-50 ||
arma::norm(gmm->Component(sortedIndices[k]).Covariance() -
gmm1->Component(sortedIndices[k]).Covariance()) > 1e-50);
}
}
// Ensure that Percentage affects the final result when refined_start is true.
BOOST_AUTO_TEST_CASE(GmmTrainPercentageTest)
{
arma::mat inputData;
if (!data::Load("data_3d_mixed.txt", inputData))
BOOST_FAIL("Unable to load train dataset data_3d_mixed.txt!");
SetInputParam("input", inputData);
SetInputParam("gaussians", (int) 2);
SetInputParam("refined_start", true);
SetInputParam("percentage", (double) 0.01);
SetInputParam("samplings", (int) 1000);
size_t seed = std::time(NULL);
mlpack::math::randGen.seed((uint32_t) seed);
srand((unsigned int) seed);
arma::arma_rng::set_seed(seed);
mlpackMain();
GMM* gmm = CLI::GetParam<GMM*>("output_model");
ResetGmmTrainSetting();
SetInputParam("input", std::move(inputData));
SetInputParam("gaussians", (int) 2);
SetInputParam("refined_start", true);
SetInputParam("percentage", (double) 0.45);
SetInputParam("samplings", (int) 1000);
mlpack::math::randGen.seed((uint32_t) seed);
srand((unsigned int) seed);
arma::arma_rng::set_seed(seed);
mlpackMain();
GMM* gmm1 = CLI::GetParam<GMM*>("output_model");
arma::uvec sortedIndices = sort_index(gmm->Weights());
for (size_t k = 0; k < sortedIndices.n_elem; k++)
{
BOOST_REQUIRE(arma::norm(gmm->Component(sortedIndices[k]).Mean() -
gmm1->Component(sortedIndices[k]).Mean()) > 1e-50 ||
arma::norm(gmm->Component(sortedIndices[k]).Covariance() -
gmm1->Component(sortedIndices[k]).Covariance()) > 1e-50);
}
}
// Ensure that Sampling affects the final result when refined_start is true.
BOOST_AUTO_TEST_CASE(GmmTrainSamplingsTest)
{
arma::mat inputData;
if (!data::Load("data_3d_mixed.txt", inputData))
BOOST_FAIL("Unable to load train dataset data_3d_mixed.txt!");
SetInputParam("input", inputData);
SetInputParam("gaussians", (int) 8);
SetInputParam("refined_start", true);
SetInputParam("trials", (int) 2);
SetInputParam("samplings", (int) 10);
size_t seed = std::time(NULL);
mlpack::math::randGen.seed((uint32_t) seed);
srand((unsigned int) seed);
arma::arma_rng::set_seed(seed);
mlpackMain();
GMM* gmm = CLI::GetParam<GMM*>("output_model");
ResetGmmTrainSetting();
SetInputParam("input", std::move(inputData));
SetInputParam("gaussians", (int) 8);
SetInputParam("refined_start", true);
SetInputParam("trials", (int) 2);
SetInputParam("samplings", (int) 5000);
mlpack::math::randGen.seed((uint32_t) seed);
srand((unsigned int) seed);
arma::arma_rng::set_seed(seed);
mlpackMain();
GMM* gmm1 = CLI::GetParam<GMM*>("output_model");
arma::uvec sortedIndices = sort_index(gmm->Weights());
for (size_t k = 0; k < sortedIndices.n_elem; k++)
{
BOOST_REQUIRE(arma::norm(gmm->Component(sortedIndices[k]).Mean() -
gmm1->Component(sortedIndices[k]).Mean()) > 1e-50 ||
arma::norm(gmm->Component(sortedIndices[k]).Covariance() -
gmm1->Component(sortedIndices[k]).Covariance()) > 1e-50);
}
}
// Ensure that tolerance affects the final result.
BOOST_AUTO_TEST_CASE(GmmTrainToleranceTest)
{
arma::mat inputData;
if (!data::Load("data_3d_mixed.txt", inputData))
BOOST_FAIL("Unable to load train dataset data_3d_mixed.txt!");
SetInputParam("input", inputData);
SetInputParam("gaussians", (int) 2);
SetInputParam("tolerance", (double) 1e-8);
size_t seed = std::time(NULL);
mlpack::math::randGen.seed((uint32_t) seed);
srand((unsigned int) seed);
arma::arma_rng::set_seed(seed);
mlpackMain();
GMM* gmm = CLI::GetParam<GMM*>("output_model");
ResetGmmTrainSetting();
SetInputParam("input", std::move(inputData));
SetInputParam("gaussians", (int) 2);
SetInputParam("tolerance", (double) 10);
mlpack::math::randGen.seed((uint32_t) seed);
srand((unsigned int) seed);
arma::arma_rng::set_seed(seed);
mlpackMain();
GMM* gmm1 = CLI::GetParam<GMM*>("output_model");
arma::uvec sortedIndices = sort_index(gmm->Weights());
for (size_t k = 0; k < sortedIndices.n_elem; k++)
{
BOOST_REQUIRE(arma::norm(gmm->Component(sortedIndices[k]).Mean() -
gmm1->Component(sortedIndices[k]).Mean()) > 1e-50 ||
arma::norm(gmm->Component(sortedIndices[k]).Covariance() -
gmm1->Component(sortedIndices[k]).Covariance()) > 1e-50);
}
}
// Ensure that saved model can be used again.
BOOST_AUTO_TEST_CASE(GmmTrainModelReuseTest)
{
arma::mat inputData(5, 10, arma::fill::randu);
SetInputParam("input", inputData);
SetInputParam("gaussians", (int) 2);
mlpackMain();
GMM* gmm = CLI::GetParam<GMM*>("output_model");
SetInputParam("input_model", gmm);
CLI::GetSingleton().Parameters()["input"].wasPassed = false;
SetInputParam("input", inputData);
mlpackMain();
GMM* gmm1 = CLI::GetParam<GMM*>("output_model");
SetInputParam("input_model", gmm1);
CLI::GetSingleton().Parameters()["input"].wasPassed = false;
SetInputParam("input", std::move(inputData));
mlpackMain();
GMM* gmm2 = CLI::GetParam<GMM*>("output_model");
BOOST_REQUIRE_EQUAL(gmm1, gmm2);
}
// Ensure that Gmm's covariances are diagonal when diagonal_covariance is true.
BOOST_AUTO_TEST_CASE(GmmTrainDiagCovariance)
{
arma::mat inputData(5, 10, arma::fill::randu);
SetInputParam("input", std::move(inputData));
SetInputParam("gaussians", (int) 2);
SetInputParam("diagonal_covariance", true);
mlpackMain();
GMM* gmm = CLI::GetParam<GMM*>("output_model");
arma::uvec sortedIndices = sort_index(gmm->Weights());
for (size_t k = 0; k < sortedIndices.n_elem; k++)
{
arma::mat diagCov(gmm->Component(sortedIndices[k]).Covariance());
for (size_t i = 0; i < diagCov.n_rows; i++)
for (size_t j = 0; j < diagCov.n_cols; j++)
if (i != j && diagCov(i, j) != (double) 0)
BOOST_FAIL("Covariance Are Not Diagonal");
}
}
BOOST_AUTO_TEST_SUITE_END();