diff --git a/src/mlpack/tests/main_tests/hmm_generate_test.cpp b/src/mlpack/tests/main_tests/hmm_generate_test.cpp index d1a99c5dbb..73a7e6cddd 100644 --- a/src/mlpack/tests/main_tests/hmm_generate_test.cpp +++ b/src/mlpack/tests/main_tests/hmm_generate_test.cpp @@ -44,29 +44,36 @@ BOOST_FIXTURE_TEST_SUITE(HMMGenerateMainTest, HMMGenerateTestFixture); BOOST_AUTO_TEST_CASE(HMMGenerateDiscreteHMMCheckDimensionsTest) { - // Train an HMM - HMMModel* h = new HMMModel(DiscreteHMM); - // Load data + // Load data to train a discrete HMM model with. arma::mat inp; data::Load("obs1.csv", inp); std::vector trainSeq = {inp}; - // Init + + // Initialize and train a discrete HMM model. + HMMModel* h = new HMMModel(DiscreteHMM); h->PerformAction>(&trainSeq); - // Train h->PerformAction>(&trainSeq); - // Set the params for the hmm_generate invocation + // 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. + // Load the input model to be used for inference and the length of sequence + // to be generated. int length = 3; SetInputParam("model", h); SetInputParam("length", length); + // Call to hmm_generate_main. mlpackMain(); + // Get the generated observation sequence. Ensure that the generated sequence + // has the correct length (as provided in the input). arma::mat obsSeq = CLI::GetParam("output"); BOOST_REQUIRE_EQUAL(obsSeq.n_cols, (size_t)length); BOOST_REQUIRE_EQUAL(obsSeq.n_rows, (size_t)1); BOOST_REQUIRE_EQUAL(obsSeq.n_elem, (size_t)length); + // Get the generated state sequence. Ensure that the generated sequence + // has the correct length (as provided in the input). arma::Mat stateSeq = CLI::GetParam>("state"); BOOST_REQUIRE_EQUAL(stateSeq.n_cols, (size_t)length); BOOST_REQUIRE_EQUAL(stateSeq.n_rows, (size_t)1); @@ -75,29 +82,36 @@ BOOST_AUTO_TEST_CASE(HMMGenerateDiscreteHMMCheckDimensionsTest) BOOST_AUTO_TEST_CASE(HMMGenerateGaussianHMMCheckDimensionsTest) { - // Train an HMM - HMMModel* h = new HMMModel(GaussianHMM); - // Load data + // Load data to train a gaussian HMM model with. arma::mat inp; data::Load("obs1.csv", inp); std::vector trainSeq = {inp}; - // Init + + // Initialize and train a gaussian HMM model. + HMMModel* h = new HMMModel(GaussianHMM); h->PerformAction>(&trainSeq); - // Train h->PerformAction>(&trainSeq); - // Set the params for the hmm_generate invocation + // 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. + // Load the input model to be used for inference and the length of sequence + // to be generated. int length = 3; SetInputParam("model", h); SetInputParam("length", length); + // Call to hmm_generate_main. mlpackMain(); + // Get the generated observation sequence. Ensure that the generated sequence + // has the correct length (as provided in the input). arma::mat obsSeq = CLI::GetParam("output"); BOOST_REQUIRE_EQUAL(obsSeq.n_cols, (size_t)length); BOOST_REQUIRE_EQUAL(obsSeq.n_rows, (size_t)1); BOOST_REQUIRE_EQUAL(obsSeq.n_elem, (size_t)length); + // Get the generated state sequence. Ensure that the generated sequence + // has the correct length (as provided in the input). arma::Mat stateSeq = CLI::GetParam>("state"); BOOST_REQUIRE_EQUAL(stateSeq.n_cols, (size_t)length); BOOST_REQUIRE_EQUAL(stateSeq.n_rows, (size_t)1); @@ -106,9 +120,7 @@ BOOST_AUTO_TEST_CASE(HMMGenerateGaussianHMMCheckDimensionsTest) BOOST_AUTO_TEST_CASE(HMMGenerateGMMHMMCheckDimensionsTest) { - // Train an HMM - HMMModel* h = new HMMModel(GaussianMixtureModelHMM); - // Load data + // Load data to train a Gaussian Mixture Model HMM model with. std::vector gmms(2, GMM(2, 2)); gmms[0].Weights() = arma::vec("0.3 0.7"); @@ -152,23 +164,32 @@ BOOST_AUTO_TEST_CASE(HMMGenerateGMMHMMCheckDimensionsTest) observations[obs].col(i) = gmms[states[obs][i]].Random(); } } - // Init + + // Initialize and train a GMM HMM model. + HMMModel* h = new HMMModel(GaussianMixtureModelHMM); h->PerformAction>(&observations); - // Train h->PerformAction>(&observations); - // Set the params for the hmm_generate invocation + // 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. + // Load the input model to be used for inference and the length of sequence + // to be generated. int length = 3; SetInputParam("model", h); SetInputParam("length", length); + // Call to hmm_generate_main mlpackMain(); + // Get the generated observation sequence. Ensure that the generated sequence + // has the correct length (as provided in the input). arma::mat obsSeq = CLI::GetParam("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)); + // Get the generated state sequence. Ensure that the generated sequence + // has the correct length (as provided in the input). arma::Mat stateSeq = CLI::GetParam>("state"); BOOST_REQUIRE_EQUAL(stateSeq.n_cols, (size_t)length); BOOST_REQUIRE_EQUAL(stateSeq.n_rows, (size_t)1); @@ -177,18 +198,19 @@ BOOST_AUTO_TEST_CASE(HMMGenerateGMMHMMCheckDimensionsTest) BOOST_AUTO_TEST_CASE(HMMGenerateLengthPositiveTest) { - // Train an HMM - HMMModel* h = new HMMModel(DiscreteHMM); - // Load data + // Load data to train a Gaussian Mixture Model HMM model with. arma::mat inp; data::Load("obs1.csv", inp); std::vector trainSeq = {inp}; - // Init + + // Initialize and train a HMM model. + HMMModel* h = new HMMModel(DiscreteHMM); h->PerformAction>(&trainSeq); - // Train h->PerformAction>(&trainSeq); // Set the params for the hmm_generate invocation + // Note that the length is negative - we expect that a runtime error will be + // raised in the call to hmm_generate_main int length = -3; // Invalid SetInputParam("model", h); SetInputParam("length", length); @@ -200,17 +222,19 @@ BOOST_AUTO_TEST_CASE(HMMGenerateLengthPositiveTest) BOOST_AUTO_TEST_CASE(HMMGenerateValidStartStateTest) { - // Train an HMM - HMMModel* h = new HMMModel(DiscreteHMM); - // Load data + // Load data to train a Gaussian Mixture Model HMM model with. arma::mat inp; data::Load("obs1.csv", inp); std::vector trainSeq = {inp}; - // Init + + // Initialize and train a HMM model. + HMMModel* h = new HMMModel(DiscreteHMM); h->PerformAction>(&trainSeq); - // Train h->PerformAction>(&trainSeq); + // Set the params for the hmm_generate invocation + // Note that the start state is invalid - we expect that a runtime error will + // be raised in the call to hmm_generate_main int length = 3; int startState = 2; // Invalid SetInputParam("model", h); diff --git a/src/mlpack/tests/main_tests/hmm_loglik_test.cpp b/src/mlpack/tests/main_tests/hmm_loglik_test.cpp index 582e7b0ce6..133e3c7b93 100644 --- a/src/mlpack/tests/main_tests/hmm_loglik_test.cpp +++ b/src/mlpack/tests/main_tests/hmm_loglik_test.cpp @@ -44,15 +44,14 @@ BOOST_FIXTURE_TEST_SUITE(HMMLoglikMainTest, HMMLoglikTestFixture); BOOST_AUTO_TEST_CASE(HMMLoglikOutputNegativeTest) { - // Create an HMMModel - HMMModel* h = new HMMModel(DiscreteHMM); - // Load data + // Load data to train a discrete HMM model with. arma::mat inp; data::Load("obs1.csv", inp); std::vector trainSeq = {inp}; - // Init HMMModel + + // Initialize and train an HMM model. + HMMModel* h = new HMMModel(DiscreteHMM); h->PerformAction>(&trainSeq); - // Train HMMModel h->PerformAction>(&trainSeq); @@ -63,6 +62,8 @@ BOOST_AUTO_TEST_CASE(HMMLoglikOutputNegativeTest) mlpackMain(); double loglik = CLI::GetParam("log_likelihood"); + + // Since the log of a probability <= 0 ... BOOST_REQUIRE(loglik <= 0); } diff --git a/src/mlpack/tests/main_tests/hmm_test_utils.hpp b/src/mlpack/tests/main_tests/hmm_test_utils.hpp index 934f1506a7..cf9d06fcc5 100644 --- a/src/mlpack/tests/main_tests/hmm_test_utils.hpp +++ b/src/mlpack/tests/main_tests/hmm_test_utils.hpp @@ -4,7 +4,8 @@ * * Structs for initializing and training HMMs (either of Discrete, Gaussian or * GMM HMMs). These structs are passed as template parameters to the - * PerformAction function of an HMMModel object. + * PerformAction function of an HMMModel object. These structs have been adapted + * from the structs in mlpack/methods/hmm/hmm_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 @@ -154,7 +155,7 @@ struct TrainHMMModel template static void Apply(HMMType& hmm, vector* trainSeq) { - // For now, perform unsupervised (Baum-Welch) training + // For now, perform unsupervised (Baum-Welch) training. hmm.Train(*trainSeq); } }; diff --git a/src/mlpack/tests/main_tests/hmm_viterbi_test.cpp b/src/mlpack/tests/main_tests/hmm_viterbi_test.cpp index 6093e514cd..7b8dec4905 100644 --- a/src/mlpack/tests/main_tests/hmm_viterbi_test.cpp +++ b/src/mlpack/tests/main_tests/hmm_viterbi_test.cpp @@ -44,59 +44,69 @@ BOOST_FIXTURE_TEST_SUITE(HMMViterbiMainTest, HMMViterbiTestFixture); BOOST_AUTO_TEST_CASE(HMMViterbiDiscreteHMMCheckDimensionsTest) { -// Train an HMM - HMMModel* h = new HMMModel(DiscreteHMM); - // Load data + // Load data to train a discrete HMM model with. arma::mat inp; data::Load("obs1.csv", inp); std::vector trainSeq = {inp}; - // Init + + // Initialize and train a discrete HMM model. + HMMModel* h = new HMMModel(DiscreteHMM); h->PerformAction>(&trainSeq); - // Train h->PerformAction>(&trainSeq); - // Set the params for the hmm_viterbi invocation + // 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", inp); + // Call to hmm_viterbi_main. mlpackMain(); + // Get the output of viterbi inference. arma::Mat out = CLI::GetParam >("output"); + // 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, inp.n_cols); } BOOST_AUTO_TEST_CASE(HMMViterbiGaussianHMMCheckDimensionsTest) { - // Train an HMM - HMMModel* h = new HMMModel(GaussianHMM); - // Load data + // Load data to train a gaussian HMM model with. arma::mat inp; data::Load("obs1.csv", inp); std::vector trainSeq = {inp}; - // Init + + // Initialize and train a gaussian HMM model. + HMMModel* h = new HMMModel(GaussianHMM); h->PerformAction>(&trainSeq); - // Train h->PerformAction>(&trainSeq); - // Set the params for the hmm_viterbi invocation + // 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", inp); + // Call to hmm_viterbi_main. mlpackMain(); + // Get the output of viterbi inference. arma::Mat out = CLI::GetParam >("output"); + // 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, inp.n_cols); } BOOST_AUTO_TEST_CASE(HMMViterbiGMMHMMCheckDimensionsTest) { - // Train an HMM - HMMModel* h = new HMMModel(GaussianMixtureModelHMM); - // Load data + // Load data to train a Gaussian Mixture Model HMM model with. std::vector gmms(2, GMM(2, 2)); gmms[0].Weights() = arma::vec("0.3 0.7"); @@ -140,19 +150,27 @@ BOOST_AUTO_TEST_CASE(HMMViterbiGMMHMMCheckDimensionsTest) observations[obs].col(i) = gmms[states[obs][i]].Random(); } } - // Init + + // Initialize and train a GMM HMM model. + HMMModel* h = new HMMModel(GaussianMixtureModelHMM); h->PerformAction>(&observations); - // Train h->PerformAction>(&observations); - // Set the params for the hmm_viterbi invocation + // 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]); + // Call to hmm_viterbi_main. mlpackMain(); + // Get the output of viterbi inference. arma::Mat out = CLI::GetParam >("output"); + // 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); }