Refactor tests to avoid sometimes-failing GMM training.

This commit is contained in:
Ryan Curtin
2018-03-22 16:45:36 -04:00
parent 52f29fcb25
commit 7a778b32f5
2 changed files with 49 additions and 85 deletions
@@ -120,55 +120,25 @@ BOOST_AUTO_TEST_CASE(HMMGenerateGaussianHMMCheckDimensionsTest)
BOOST_AUTO_TEST_CASE(HMMGenerateGMMHMMCheckDimensionsTest)
{
// Load data to train a Gaussian Mixture Model HMM model with.
std::vector<GMM> gmms(2, GMM(2, 2));
gmms[0].Weights() = arma::vec("0.3 0.7");
// N([2.25 3.10], [1.00 0.20; 0.20 0.89])
gmms[0].Component(0) = GaussianDistribution("4.25 3.10",
"1.00 0.20; 0.20 0.89");
// N([4.10 1.01], [1.00 0.00; 0.00 1.01])
gmms[0].Component(1) = GaussianDistribution("7.10 5.01",
"1.00 0.00; 0.00 1.01");
gmms[1].Weights() = arma::vec("0.20 0.80");
gmms[1].Component(0) = GaussianDistribution("-3.00 -6.12",
"1.00 0.00; 0.00 1.00");
gmms[1].Component(1) = GaussianDistribution("-4.25 -2.12",
"1.50 0.60; 0.60 1.20");
// Transition matrix.
arma::mat transMat("0.40 0.60;"
"0.60 0.40");
// Make a sequence of observations.
std::vector<arma::mat> observations(5, arma::mat(2, 50));
std::vector<arma::Row<size_t> > states(5, arma::Row<size_t>(50));
for (size_t obs = 0; obs < 5; obs++)
{
states[obs][0] = 0;
observations[obs].col(0) = gmms[0].Random();
for (size_t i = 1; i < 50; i++)
{
double randValue = (double) rand() / (double) RAND_MAX;
if (randValue <= transMat(0, states[obs][i - 1]))
states[obs][i] = 0;
else
states[obs][i] = 1;
observations[obs].col(i) = gmms[states[obs][i]].Random();
}
}
// Initialize and train a GMM HMM model.
HMMModel* h = new HMMModel(GaussianMixtureModelHMM);
h->PerformAction<InitHMMModel, std::vector<arma::mat>>(&observations);
h->PerformAction<TrainHMMModel, std::vector<arma::mat>>(&observations);
*(h->GMMHMM()) = HMM<GMM>(2, GMM(2, 2));
// Manually set the components.
h->GMMHMM()->Transition() = arma::mat("0.40 0.60; 0.60 0.40");
h->GMMHMM()->Emission().resize(2);
h->GMMHMM()->Emission()[0] = GMM(2, 2);
h->GMMHMM()->Emission()[0].Weights() = arma::vec("0.3 0.7");
h->GMMHMM()->Emission()[0].Component(0) = GaussianDistribution("4.25 3.10",
"1.00 0.20; 0.20 0.89");
h->GMMHMM()->Emission()[0].Component(1) = GaussianDistribution("7.10 5.01",
"1.00 0.00; 0.00 1.01");
h->GMMHMM()->Emission()[1] = GMM(2, 2);
h->GMMHMM()->Emission()[1].Weights() = arma::vec("0.20 0.80");
h->GMMHMM()->Emission()[1].Component(0) = GaussianDistribution("-3.00 -6.12",
"1.00 0.00; 0.00 1.00");
h->GMMHMM()->Emission()[1].Component(1) = GaussianDistribution("-4.25 -2.12",
"1.50 0.60; 0.60 1.20");
// Now that we have a trained HMM model, we can use it to generate a sequence
// of states and observations - using the hmm_generate utility.
@@ -184,16 +154,16 @@ BOOST_AUTO_TEST_CASE(HMMGenerateGMMHMMCheckDimensionsTest)
// Get the generated observation sequence. Ensure that the generated sequence
// has the correct length (as provided in the input).
arma::mat obsSeq = CLI::GetParam<arma::mat>("output");
BOOST_REQUIRE_EQUAL(obsSeq.n_cols, (size_t)length);
BOOST_REQUIRE_EQUAL(obsSeq.n_rows, (size_t)2);
BOOST_REQUIRE_EQUAL(obsSeq.n_elem, (size_t)(length*2));
BOOST_REQUIRE_EQUAL(obsSeq.n_cols, (size_t) length);
BOOST_REQUIRE_EQUAL(obsSeq.n_rows, (size_t) 2);
BOOST_REQUIRE_EQUAL(obsSeq.n_elem, (size_t) (length*2));
// Get the generated state sequence. Ensure that the generated sequence
// has the correct length (as provided in the input).
arma::Mat<size_t> stateSeq = CLI::GetParam<arma::Mat<size_t>>("state");
BOOST_REQUIRE_EQUAL(stateSeq.n_cols, (size_t)length);
BOOST_REQUIRE_EQUAL(stateSeq.n_rows, (size_t)1);
BOOST_REQUIRE_EQUAL(stateSeq.n_elem, (size_t)length);
BOOST_REQUIRE_EQUAL(stateSeq.n_cols, (size_t) length);
BOOST_REQUIRE_EQUAL(stateSeq.n_rows, (size_t) 1);
BOOST_REQUIRE_EQUAL(stateSeq.n_elem, (size_t) length);
}
BOOST_AUTO_TEST_CASE(HMMGenerateLengthPositiveTest)
@@ -106,62 +106,56 @@ BOOST_AUTO_TEST_CASE(HMMViterbiGaussianHMMCheckDimensionsTest)
BOOST_AUTO_TEST_CASE(HMMViterbiGMMHMMCheckDimensionsTest)
{
// Load data to train a Gaussian Mixture Model HMM model with.
std::vector<GMM> gmms(2, GMM(2, 2));
gmms[0].Weights() = arma::vec("0.3 0.7");
// N([2.25 3.10], [1.00 0.20; 0.20 0.89])
gmms[0].Component(0) = GaussianDistribution("4.25 3.10",
"1.00 0.20; 0.20 0.89");
// N([4.10 1.01], [1.00 0.00; 0.00 1.01])
"1.00 0.20; 0.20 0.89");
gmms[0].Component(1) = GaussianDistribution("7.10 5.01",
"1.00 0.00; 0.00 1.01");
"1.00 0.00; 0.00 1.01");
gmms[1].Weights() = arma::vec("0.20 0.80");
gmms[1].Component(0) = GaussianDistribution("-3.00 -6.12",
"1.00 0.00; 0.00 1.00");
"1.00 0.00; 0.00 1.00");
gmms[1].Component(1) = GaussianDistribution("-4.25 -2.12",
"1.50 0.60; 0.60 1.20");
"1.50 0.60; 0.60 1.20");
// Transition matrix.
arma::mat transMat("0.40 0.60;"
"0.60 0.40");
arma::mat transMat("0.40 0.60; 0.60 0.40");
// Make a sequence of observations.
std::vector<arma::mat> observations(5, arma::mat(2, 50));
std::vector<arma::Row<size_t> > states(5, arma::Row<size_t>(50));
for (size_t obs = 0; obs < 5; obs++)
// Make some observations.
arma::mat observations(2, 50);
arma::Row<size_t> states(50);
states[0] = 0;
observations.col(0) = gmms[0].Random();
for (size_t i = 1; i < 50; ++i)
{
states[obs][0] = 0;
observations[obs].col(0) = gmms[0].Random();
double randValue = (double) rand() / (double) RAND_MAX;
for (size_t i = 1; i < 50; i++)
{
double randValue = (double) rand() / (double) RAND_MAX;
if (randValue <= transMat(0, states[i - 1]))
states[i] = 0;
else
states[i] = 1;
if (randValue <= transMat(0, states[obs][i - 1]))
states[obs][i] = 0;
else
states[obs][i] = 1;
observations[obs].col(i) = gmms[states[obs][i]].Random();
}
observations.col(i) = gmms[states[i]].Random();
}
// Initialize and train a GMM HMM model.
HMMModel* h = new HMMModel(GaussianMixtureModelHMM);
h->PerformAction<InitHMMModel, std::vector<arma::mat>>(&observations);
h->PerformAction<TrainHMMModel, std::vector<arma::mat>>(&observations);
*(h->GMMHMM()) = HMM<GMM>(2, GMM(2, 2));
// Manually set the components.
h->GMMHMM()->Transition() = transMat;
h->GMMHMM()->Emission() = gmms;
// Now that we have a trained HMM model, we can use it to predict the state
// sequence for a given observation sequence - using the Viterbi algorithm.
// Load the input model to be used for inference and the sequence over which
// inference is to be performed.
SetInputParam("input_model", h);
SetInputParam("input", observations[0]);
SetInputParam("input", observations);
// Call to hmm_viterbi_main.
mlpackMain();
@@ -172,7 +166,7 @@ BOOST_AUTO_TEST_CASE(HMMViterbiGMMHMMCheckDimensionsTest)
// Output sequence length must be the same as input sequence length and
// there should only be one row (since states are single dimensional values).
BOOST_REQUIRE_EQUAL(out.n_rows, 1);
BOOST_REQUIRE_EQUAL(out.n_cols, observations[0].n_cols);
BOOST_REQUIRE_EQUAL(out.n_cols, observations.n_cols);
}
BOOST_AUTO_TEST_SUITE_END();