diff --git a/.gitignore b/.gitignore index 19b7551ff4..fbdd115098 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ build* - -*~ -.*.swp -.*.swo -*.bak src/mlpack/core/util/gitversion.hpp src/mlpack/core/util/arma_config.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e0525e18a9..b5ce3bca7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -365,7 +365,7 @@ if (UNIX) mlpack_adaboost mlpack_kfn mlpack_knn - mlpack_allkrann + mlpack_krann mlpack_cf mlpack_decision_stump mlpack_det diff --git a/HISTORY.md b/HISTORY.md index b117ee6895..a129f004e6 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -25,13 +25,16 @@ and MLPACK_VERSION_PATCH. The old names will remain in place until mlpack 3.0.0. - * Renamed mlpack_allknn and mlpack_allkfn to mlpack_knn and mlpack_kfn. The - mlpack_allknn and mlpack_allkfn programs will remain as copies until mlpack - 3.0.0. + * Renamed mlpack_allknn, mlpack_allkfn, and mlpack_allkrann to mlpack_knn, + mlpack_kfn, and mlpack_krann. The mlpack_allknn, mlpack_allkfn, and + mlpack_allkrann programs will remain as copies until mlpack 3.0.0. * Add --random_initialization option to mlpack_hmm_train, for use when no labels are provided. + * Add --kill_empty_clusters option to mlpack_kmeans and KillEmptyClusters + policy for the KMeans class (#595, #596). + ### mlpack 2.0.1 ###### 2016-02-04 * Fix CMake to properly detect when MKL is being used with Armadillo. diff --git a/src/mlpack/core.hpp b/src/mlpack/core.hpp index c0cbeea1ab..6f5c181c06 100644 --- a/src/mlpack/core.hpp +++ b/src/mlpack/core.hpp @@ -51,7 +51,6 @@ * A full list of executables is given below: * * - mlpack_adaboost - * - mlpack_allkrann * - mlpack_cf * - mlpack_decision_stump * - mlpack_det @@ -69,6 +68,7 @@ * - mlpack_kfn * - mlpack_kmeans * - mlpack_knn + * - mlpack_krann * - mlpack_lars * - mlpack_linear_regression * - mlpack_local_coordinate_coding diff --git a/src/mlpack/core/util/cli.cpp b/src/mlpack/core/util/cli.cpp index 0eaf543080..21b41fee29 100644 --- a/src/mlpack/core/util/cli.cpp +++ b/src/mlpack/core/util/cli.cpp @@ -6,16 +6,12 @@ */ #include #include -#include #include #include -#include #include "cli.hpp" #include "log.hpp" -#include "option.hpp" - using namespace mlpack; using namespace mlpack::util; @@ -100,18 +96,19 @@ CLI::~CLI() * @param alias An alias for the parameter. * @param required Indicates if parameter must be set on command line. */ -void CLI::Add(const std::string& path, - const std::string& description, - const std::string& alias, - bool required) +void CLI::Add(const std::string& identifier, + const std::string& description, + const std::string& alias, + bool required) { po::options_description& desc = CLI::GetSingleton().desc; // Must make use of boost option name syntax. - std::string progOptId = alias.length() ? path + "," + alias : path; + std::string progOptId = + alias.length() ? identifier + "," + alias : identifier; // Deal with a required alias. - AddAlias(alias, path); + AddAlias(alias, identifier); // Add the option to boost::program_options. desc.add_options()(progOptId.c_str(), description.c_str()); @@ -122,15 +119,15 @@ void CLI::Add(const std::string& path, ParamData data; data.desc = description; data.tname = ""; - data.name = path; + data.name = identifier; data.isFlag = false; data.wasPassed = false; - gmap[path] = data; + gmap[identifier] = data; // If the option is required, add it to the required options list. if (required) - GetSingleton().requiredOptions.push_front(path); + GetSingleton().requiredOptions.push_front(identifier); return; } @@ -155,8 +152,8 @@ void CLI::AddAlias(const std::string& alias, const std::string& original) * @brief Adds a flag parameter to CLI. */ void CLI::AddFlag(const std::string& identifier, - const std::string& description, - const std::string& alias) + const std::string& description, + const std::string& alias) { // Reuse functionality from Add(). Add(identifier, description, alias, false); @@ -453,36 +450,6 @@ void CLI::RemoveDuplicateFlags(po::basic_parsed_options& bpo) } } -/** - * Parses a stream for arguments - * - * @param stream The stream to be parsed. - */ -void CLI::ParseStream(std::istream& stream) -{ - po::variables_map& vmap = GetSingleton().vmap; - po::options_description& desc = GetSingleton().desc; - - // Parse the stream; place options & values into vmap. - try - { - po::store(po::parse_config_file(stream, desc), vmap); - } - catch (std::exception& ex) - { - Log::Fatal << ex.what() << std::endl; - } - - // Flush the buffer; make sure changes are propagated to vmap. - po::notify(vmap); - - UpdateGmap(); - DefaultMessages(); - RequiredOptions(); - - Timer::Start("total_time"); -} - /* Prints out the current hierarchy. */ void CLI::Print() { diff --git a/src/mlpack/core/util/cli.hpp b/src/mlpack/core/util/cli.hpp index f6ec7dcbf4..8f9cf3f1a3 100644 --- a/src/mlpack/core/util/cli.hpp +++ b/src/mlpack/core/util/cli.hpp @@ -635,13 +635,6 @@ class CLI */ static void RemoveDuplicateFlags(po::basic_parsed_options& bpo); - /** - * Parses a stream for arguments. - * - * @param stream The stream to be parsed. - */ - static void ParseStream(std::istream& stream); - /** * Print out the current hierarchy. */ @@ -673,7 +666,7 @@ class CLI //! Values of the options given by user. po::variables_map vmap; - //! Pathnames of required options. + //! Identifier names of required options. std::list requiredOptions; //! Map of global values. @@ -728,15 +721,6 @@ class CLI */ static void RequiredOptions(); - /** - * Cleans up input pathnames, rendering strings such as /foo/bar - * and foo/bar/ equivalent inputs. - * - * @param str Input string. - * @return Sanitized string. - */ - static std::string SanitizeString(const std::string& str); - /** * Parses the values given on the command line, overriding any default values. */ diff --git a/src/mlpack/core/util/cli_impl.hpp b/src/mlpack/core/util/cli_impl.hpp index 72f4be2c33..cc7c89689f 100644 --- a/src/mlpack/core/util/cli_impl.hpp +++ b/src/mlpack/core/util/cli_impl.hpp @@ -9,6 +9,7 @@ // In case it has not already been included. #include "cli.hpp" +#include "prefixedoutstream.hpp" // Include option.hpp here because it requires CLI but is also templated. #include "option.hpp" @@ -28,39 +29,65 @@ namespace mlpack { * unless the parameter is specified. */ template -void CLI::Add(const std::string& path, +void CLI::Add(const std::string& identifier, const std::string& description, const std::string& alias, bool required) { + // Temporarily define color code escape sequences. + #ifndef _WIN32 + #define BASH_RED "\033[0;31m" + #define BASH_CLEAR "\033[0m" + #else + #define BASH_RED "" + #define BASH_CLEAR "" + #endif + + // Temporary outstream object for detecting duplicate identifiers. + util::PrefixedOutStream outstr(std::cerr, + BASH_RED "[FATAL] " BASH_CLEAR, false, true /* fatal */); + + #undef BASH_RED + #undef BASH_CLEAR + + // Define identifier and alias maps. + gmap_t& gmap = GetSingleton().globalValues; + amap_t& amap = GetSingleton().aliasValues; + + // If found in current map, print fatal error and terminate the program. + if (gmap.count(identifier)) + outstr << "Parameter --" << identifier << "(-" << alias << ") " + << "is defined multiple times with same identifiers." << std::endl; + if (amap.count(alias)) + outstr << "Parameter --" << identifier << "(-" << alias << ") " + << "is defined multiple times with same alias." << std::endl; po::options_description& desc = CLI::GetSingleton().desc; // Must make use of boost syntax here. - std::string progOptId = alias.length() ? path + "," + alias : path; + std::string progOptId = + alias.length() ? identifier + "," + alias : identifier; // Add the alias, if necessary - AddAlias(alias, path); + AddAlias(alias, identifier); // Add the option to boost program_options. desc.add_options()(progOptId.c_str(), po::value(), description.c_str()); // Make sure the appropriate metadata is inserted into gmap. - gmap_t& gmap = GetSingleton().globalValues; - ParamData data; T tmp = T(); data.desc = description; - data.name = path; + data.name = identifier; data.tname = TYPENAME(T); data.value = boost::any(tmp); data.wasPassed = false; - gmap[path] = data; + gmap[identifier] = data; // If the option is required, add it to the required options list. if (required) - GetSingleton().requiredOptions.push_front(path); + GetSingleton().requiredOptions.push_front(identifier); } // We specialize this in cli.cpp. @@ -73,7 +100,7 @@ bool& CLI::GetParam(const std::string& identifier); * more or less valid value is returned. * * @tparam T The type of the parameter. - * @param identifier The full pathname of the parameter. + * @param identifier The full name of the parameter. * * @return The value of the parameter. Use CLI::CheckValue to determine if it's * valid. diff --git a/src/mlpack/methods/ann/ffn.hpp b/src/mlpack/methods/ann/ffn.hpp index 3de7252a51..b06fb1438b 100644 --- a/src/mlpack/methods/ann/ffn.hpp +++ b/src/mlpack/methods/ann/ffn.hpp @@ -22,7 +22,7 @@ namespace ann /** Artificial Neural Network. */ { * Implementation of a standard feed forward network. * * @tparam LayerTypes Contains all layer modules used to construct the network. - * @tparam OutputLayerType The outputlayer type used to evaluate the network. + * @tparam OutputLayerType The output layer type used to evaluate the network. * @tparam InitializationRuleType Rule used to initialize the weight matrix. * @tparam PerformanceFunction Performance strategy used to calculate the error. */ @@ -48,14 +48,14 @@ class FFN * be used. * * @param network Network modules used to construct the network. - * @param outputLayer Outputlayer used to evaluate the network. + * @param outputLayer Output layer used to evaluate the network. * @param predictors Input training variables. * @param responses Outputs resulting from input training variables. * @param optimizer Instantiated optimizer used to train the model. * @param initializeRule Optional instantiated InitializationRule object - * for initializing the network paramter. + * for initializing the network parameter. * @param performanceFunction Optional instantiated PerformanceFunction - * object used to claculate the error. + * object used to calculate the error. */ template FFN(LayerType &&network, @@ -96,11 +96,11 @@ class FFN * training. * * @param network Network modules used to construct the network. - * @param outputLayer Outputlayer used to evaluate the network. + * @param outputLayer Output layer used to evaluate the network. * @param initializeRule Optional instantiated InitializationRule object - * for initializing the network paramter. + * for initializing the network parameter. * @param performanceFunction Optional instantiated PerformanceFunction - * object used to claculate the error. + * object used to calculate the error. */ template FFN(LayerType &&network, @@ -408,10 +408,10 @@ private: //! Instantiated feedforward network. LayerTypes network; - //! The outputlayer used to evaluate the network + //! The output layer used to evaluate the network OutputLayerType outputLayer; - //! Performance strategy used to claculate the error. + //! Performance strategy used to calculate the error. PerformanceFunction performanceFunc; //! The current evaluation mode (training or testing). diff --git a/src/mlpack/methods/ann/rnn.hpp b/src/mlpack/methods/ann/rnn.hpp index 473f12e8f0..39789bf901 100644 --- a/src/mlpack/methods/ann/rnn.hpp +++ b/src/mlpack/methods/ann/rnn.hpp @@ -24,7 +24,7 @@ namespace ann /** Artificial Neural Network. */ { * Implementation of a standard recurrent neural network. * * @tparam LayerTypes Contains all layer modules used to construct the network. - * @tparam OutputLayerType The outputlayer type used to evaluate the network. + * @tparam OutputLayerType The output layer type used to evaluate the network. * @tparam InitializationRuleType Rule used to initialize the weight matrix. * @tparam PerformanceFunction Performance strategy used to calculate the error. */ @@ -50,14 +50,14 @@ class RNN * be used. * * @param network Network modules used to construct the network. - * @param outputLayer Outputlayer used to evaluate the network. + * @param outputLayer Output layer used to evaluate the network. * @param predictors Input training variables. * @param responses Outputs resulting from input training variables. * @param optimizer Instantiated optimizer used to train the model. * @param initializeRule Optional instantiated InitializationRule object - * for initializing the network paramter. + * for initializing the network parameter. * @param performanceFunction Optional instantiated PerformanceFunction - * object used to claculate the error. + * object used to calculate the error. */ template RNN(LayerType &&network, @@ -98,11 +98,11 @@ class RNN * training. * * @param network Network modules used to construct the network. - * @param outputLayer Outputlayer used to evaluate the network. + * @param outputLayer Output layer used to evaluate the network. * @param initializeRule Optional instantiated InitializationRule object - * for initializing the network paramter. + * for initializing the network parameter. * @param performanceFunction Optional instantiated PerformanceFunction - * object used to claculate the error. + * object used to calculate the error. */ template RNN(LayerType &&network, diff --git a/src/mlpack/methods/cf/cf_main.cpp b/src/mlpack/methods/cf/cf_main.cpp index bc46876f65..63c3dad27d 100644 --- a/src/mlpack/methods/cf/cf_main.cpp +++ b/src/mlpack/methods/cf/cf_main.cpp @@ -85,7 +85,7 @@ PARAM_FLAG("all_user_recommendations", "Generate recommendations for all " "users.", "A"); PARAM_STRING("output_file","File to save output recommendations to.", "o", ""); PARAM_INT("recommendations", "Number of recommendations to generate for each " - "query user.", "n", 5); + "query user.", "c", 5); PARAM_INT("seed", "Set the random seed (0 uses std::time(NULL)).", "s", 0); diff --git a/src/mlpack/methods/det/det_main.cpp b/src/mlpack/methods/det/det_main.cpp index 87446d5684..5b0c506709 100644 --- a/src/mlpack/methods/det/det_main.cpp +++ b/src/mlpack/methods/det/det_main.cpp @@ -133,7 +133,7 @@ int main(int argc, char *argv[]) Timer::Stop("det_training"); // Compute training set estimates, if desired. - if (CLI::GetParam("training_set_estimates_file") != "") + if (CLI::HasParam("training_set_estimates_file")) { // Compute density estimates for each point in the training set. arma::rowvec trainingDensities(trainingData.n_cols); diff --git a/src/mlpack/methods/emst/emst_main.cpp b/src/mlpack/methods/emst/emst_main.cpp index 828693e337..f6d18be704 100644 --- a/src/mlpack/methods/emst/emst_main.cpp +++ b/src/mlpack/methods/emst/emst_main.cpp @@ -34,8 +34,9 @@ PROGRAM_INFO("Fast Euclidean Minimum Spanning Tree", "This program can compute " "column corresponds to the distance between the two points."); PARAM_STRING_REQ("input_file", "Data input file.", "i"); -PARAM_STRING("output_file", "Data output file. Stored as an edge list.", "o", - "emst_output.csv"); + +PARAM_STRING("output_file", "Data output file. Stored as an edge list.", + "o", ""); PARAM_FLAG("naive", "Compute the MST using O(n^2) naive algorithm.", "n"); PARAM_INT("leaf_size", "Leaf size in the kd-tree. One-element leaves give the " "empirically best performance, but at the cost of greater memory " @@ -51,10 +52,15 @@ int main(int argc, char* argv[]) { CLI::ParseCommandLine(argc, argv); - const string dataFilename = CLI::GetParam("input_file"); + const string inputFile = CLI::GetParam("input_file"); + const string outputFile= CLI::GetParam("output_file"); + + if (CLI::HasParam("output_file")) + Log::Warn << "--output_file (-o) is not specified; no results will be " + << "saved!" << endl; arma::mat dataPoints; - data::Load(dataFilename, dataPoints, true); + data::Load(inputFile, dataPoints, true); // Do naive computation if necessary. if (CLI::GetParam("naive")) @@ -66,9 +72,8 @@ int main(int argc, char* argv[]) arma::mat naiveResults; naive.ComputeMST(naiveResults); - const string outputFilename = CLI::GetParam("output_file"); - - data::Save(outputFilename, naiveResults, true); + if (CLI::HasParam("output_file")) + data::Save(outputFile, naiveResults, true); } else { @@ -120,9 +125,7 @@ int main(int argc, char* argv[]) unmappedResults(2, i) = results(2, i); } - // Output the results. - const string outputFilename = CLI::GetParam("output_file"); - - data::Save(outputFilename, unmappedResults, true); + if (CLI::HasParam("output_file")) + data::Save(outputFile, unmappedResults, true); } } diff --git a/src/mlpack/methods/gmm/gmm_generate_main.cpp b/src/mlpack/methods/gmm/gmm_generate_main.cpp index 7fcf2e1bd2..32f35671ab 100644 --- a/src/mlpack/methods/gmm/gmm_generate_main.cpp +++ b/src/mlpack/methods/gmm/gmm_generate_main.cpp @@ -22,15 +22,17 @@ PROGRAM_INFO("GMM Sample Generator", PARAM_STRING_REQ("input_model_file", "File containing input GMM model.", "m"); PARAM_INT_REQ("samples", "Number of samples to generate.", "n"); -PARAM_STRING("output_file", "File to save output samples in.", "o", - "output.csv"); - +PARAM_STRING("output_file", "File to save output samples in.", "o", ""); PARAM_INT("seed", "Random seed. If 0, 'std::time(NULL)' is used.", "s", 0); int main(int argc, char** argv) { CLI::ParseCommandLine(argc, argv); + if (CLI::HasParam("output_file")) + Log::Warn << "--output_file (-o) is not specified;" + << "no results will be saved!" << endl; + if (CLI::GetParam("seed") == 0) mlpack::math::RandomSeed(time(NULL)); else @@ -48,5 +50,6 @@ int main(int argc, char** argv) for (size_t i = 0; i < length; ++i) samples.col(i) = gmm.Random(); - data::Save(CLI::GetParam("output_file"), samples); + if (CLI::HasParam("output_file")) + data::Save(CLI::GetParam("output_file"), samples); } diff --git a/src/mlpack/methods/gmm/gmm_probability_main.cpp b/src/mlpack/methods/gmm/gmm_probability_main.cpp index b771aa2891..15006dd468 100644 --- a/src/mlpack/methods/gmm/gmm_probability_main.cpp +++ b/src/mlpack/methods/gmm/gmm_probability_main.cpp @@ -22,18 +22,26 @@ PARAM_STRING_REQ("input_model_file", "File containing input GMM.", "m"); PARAM_STRING_REQ("input_file", "File containing points.", "i"); PARAM_STRING("output_file", "File to save calculated probabilities to.", "o", - "output.csv"); + ""); int main(int argc, char** argv) { CLI::ParseCommandLine(argc, argv); + const string inputFile = CLI::GetParam("input_file"); + const string inputModelFile = CLI::GetParam("input_model_file"); + const string outputFile = CLI::GetParam("input_model_file"); + + if (CLI::HasParam("output_file")) + Log::Warn << "--output_file (-o) is not specified;" + << "no results will be saved!" << endl; + // Get the GMM and the points. GMM gmm; - data::Load(CLI::GetParam("input_model_file"), "gmm", gmm); + data::Load(inputFile, "gmm", gmm); arma::mat dataset; - data::Load(CLI::GetParam("input_file"), dataset); + data::Load(inputModelFile, dataset); // Now calculate the probabilities. arma::rowvec probabilities(dataset.n_cols); @@ -41,5 +49,6 @@ int main(int argc, char** argv) probabilities[i] = gmm.Probability(dataset.unsafe_col(i)); // And save the result. - data::Save(CLI::GetParam("output_file"), probabilities); + if (CLI::HasParam("output_file")) + data::Save(outputFile, probabilities); } diff --git a/src/mlpack/methods/hmm/hmm_generate_main.cpp b/src/mlpack/methods/hmm/hmm_generate_main.cpp index 5240d553bc..53d45dc540 100644 --- a/src/mlpack/methods/hmm/hmm_generate_main.cpp +++ b/src/mlpack/methods/hmm/hmm_generate_main.cpp @@ -22,9 +22,8 @@ PROGRAM_INFO("Hidden Markov Model (HMM) Sequence Generator", "This " PARAM_STRING_REQ("model_file", "File containing HMM.", "m"); PARAM_INT_REQ("length", "Length of sequence to generate.", "l"); +PARAM_STRING("output_file", "File to save observation sequence to.", "o" ,""); PARAM_INT("start_state", "Starting state of sequence.", "t", 0); -PARAM_STRING("output_file", "File to save observation sequence to.", "o", - "output.csv"); PARAM_STRING("state_file", "File to save hidden state sequence to (may be left " "unspecified.", "S", ""); PARAM_INT("seed", "Random seed. If 0, 'std::time(NULL)' is used.", "s", 0); @@ -51,6 +50,8 @@ struct Generate // Load the parameters. const size_t startState = (size_t) CLI::GetParam("start_state"); const size_t length = (size_t) CLI::GetParam("length"); + const string outputFile = CLI::GetParam("output_file"); + const string sequenceFile = CLI::GetParam("state_file"); Log::Info << "Generating sequence of length " << length << "..." << endl; if (startState >= hmm.Transition().n_rows) @@ -61,12 +62,11 @@ struct Generate hmm.Generate(length, observations, sequence, startState); // Now save the output. - const string outputFile = CLI::GetParam("output_file"); - data::Save(outputFile, observations, true); + if (CLI::HasParam("output_file")) + data::Save(outputFile, observations, true); // Do we want to save the hidden sequence? - const string sequenceFile = CLI::GetParam("state_file"); - if (sequenceFile != "") + if (CLI::HasParam("state_file")) data::Save(sequenceFile, sequence, true); } }; @@ -76,6 +76,10 @@ int main(int argc, char** argv) // Parse command line options. CLI::ParseCommandLine(argc, argv); + if (CLI::HasParam("output_file")) + Log::Warn << "--output_file (-o) is not specified; no results will be " + << "saved!" << endl; + // Set random seed. if (CLI::GetParam("seed") != 0) RandomSeed((size_t) CLI::GetParam("seed")); diff --git a/src/mlpack/methods/hmm/hmm_train_main.cpp b/src/mlpack/methods/hmm/hmm_train_main.cpp index 546fb3c919..c56d46ad7b 100644 --- a/src/mlpack/methods/hmm/hmm_train_main.cpp +++ b/src/mlpack/methods/hmm/hmm_train_main.cpp @@ -45,8 +45,7 @@ PARAM_INT("gaussians", "Number of gaussians in each GMM (necessary when type is" PARAM_STRING("model_file", "Pre-existing HMM model (optional).", "m", ""); PARAM_STRING("labels_file", "Optional file of hidden states, used for " "labeled training.", "l", ""); -PARAM_STRING("output_model_file", "File to save trained HMM to.", "o", - "output_hmm.xml"); +PARAM_STRING("output_model_file", "File to save trained HMM to.", "o", ""); PARAM_INT("seed", "Random seed. If 0, 'std::time(NULL)' is used.", "s", 0); PARAM_DOUBLE("tolerance", "Tolerance of the Baum-Welch algorithm.", "T", 1e-5); PARAM_FLAG("random_initialization", "Initialize emissions and transition " @@ -88,7 +87,7 @@ struct Train << endl; vector> labelSeq; // May be empty. - if (labelsFile != "") + if (CLI::HasParam("labels_file")) { // Do we have multiple label files to load? char lineBuf[1024]; @@ -271,7 +270,7 @@ int main(int argc, char** argv) } // If we have a model file, we can autodetect the type. - if (modelFile != "") + if (CLI::HasParam("model_file")) { LoadHMMAndPerformAction(modelFile, &trainSeq); } diff --git a/src/mlpack/methods/hmm/hmm_viterbi_main.cpp b/src/mlpack/methods/hmm/hmm_viterbi_main.cpp index 2e6328b810..562c2910d9 100644 --- a/src/mlpack/methods/hmm/hmm_viterbi_main.cpp +++ b/src/mlpack/methods/hmm/hmm_viterbi_main.cpp @@ -20,8 +20,8 @@ PROGRAM_INFO("Hidden Markov Model (HMM) Viterbi State Prediction", "This " PARAM_STRING_REQ("input_file", "File containing observations,", "i"); PARAM_STRING_REQ("model_file", "File containing HMM.", "m"); -PARAM_STRING("output_file", "File to save predicted state sequence to.", "o", - "output.csv"); +PARAM_STRING("output_file", "File to save predicted state sequence to.", + "o", ""); using namespace mlpack; using namespace mlpack::hmm; @@ -40,6 +40,7 @@ struct Viterbi { // Load observations. const string inputFile = CLI::GetParam("input_file"); + const string outputFile = CLI::GetParam("output_file"); mat dataSeq; data::Load(inputFile, dataSeq, true); @@ -62,8 +63,8 @@ struct Viterbi hmm.Predict(dataSeq, sequence); // Save output. - const string outputFile = CLI::GetParam("output_file"); - data::Save(outputFile, sequence, true); + if (CLI::HasParam("output_file")) + data::Save(outputFile, sequence, true); } }; @@ -72,6 +73,10 @@ int main(int argc, char** argv) // Parse command line options. CLI::ParseCommandLine(argc, argv); + if (CLI::HasParam("output_file")) + Log::Warn << "--output_file (-o) is not specified; no results will be " + << "saved!" << endl; + const string modelFile = CLI::GetParam("model_file"); LoadHMMAndPerformAction(modelFile); } diff --git a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_main.cpp b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_main.cpp index 073c00b3c2..ec955129b7 100644 --- a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_main.cpp +++ b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_main.cpp @@ -56,10 +56,10 @@ PARAM_STRING("output_model_file", "File to save trained tree to.", "M", ""); PARAM_STRING("test_file", "File of testing data.", "T", ""); PARAM_STRING("test_labels_file", "Labels of test data.", "L", ""); -PARAM_STRING("predictions_file", "File to output label predictions for test " - "data into.", "p", ""); -PARAM_STRING("probabilities_file", "In addition to predicting labels, provide " - "prediction probabilities in this file.", "P", ""); +PARAM_STRING("predictions_file", "File to output label predictions for" + "test data into.", "p", ""); +PARAM_STRING("probabilities_file", "In addition to predicting labels, " + "provide prediction probabilities in this file.", "P", ""); PARAM_STRING("numeric_split_strategy", "The splitting strategy to use for " "numeric features: 'domingos' or 'binary'.", "N", "binary"); @@ -90,25 +90,28 @@ int main(int argc, char** argv) const string labelsFile = CLI::GetParam("labels_file"); const string inputModelFile = CLI::GetParam("input_model_file"); const string testFile = CLI::GetParam("test_file"); - const string predictionsFile = CLI::GetParam("predictions_file"); - const string probabilitiesFile = CLI::GetParam("probabilities_file"); + const string predictionsFile = + CLI::GetParam("predictions_file"); + const string probabilitiesFile = + CLI::GetParam("probabilities_file"); const string numericSplitStrategy = CLI::GetParam("numeric_split_strategy"); - if ((!predictionsFile.empty() || !probabilitiesFile.empty()) && - testFile.empty()) + if ((CLI::HasParam("predictions_file") || + CLI::HasParam("probabilities_file")) && + !CLI::HasParam("test_file")) Log::Fatal << "--test_file must be specified if --predictions_file or " << "--probabilities_file is specified." << endl; - if (trainingFile.empty() && inputModelFile.empty()) + if (!CLI::HasParam("training_file") && !CLI::HasParam("input_model_file")) Log::Fatal << "One of --training_file or --input_model_file must be " << "specified!" << endl; - if (!trainingFile.empty() && labelsFile.empty()) + if (CLI::HasParam("training_file") && !CLI::HasParam("labels_file")) Log::Fatal << "If --training_file is specified, --labels_file must be " << "specified too!" << endl; - if (trainingFile.empty() && CLI::HasParam("batch_mode")) + if (!CLI::HasParam("training_file") && CLI::HasParam("batch_mode")) Log::Warn << "--batch_mode (-b) ignored; no training set provided." << endl; if (CLI::HasParam("passes") && CLI::HasParam("batch_mode")) @@ -177,8 +180,10 @@ void PerformActions(const typename TreeType::NumericSplit& numericSplit) const string inputModelFile = CLI::GetParam("input_model_file"); const string outputModelFile = CLI::GetParam("output_model_file"); const string testFile = CLI::GetParam("test_file"); - const string predictionsFile = CLI::GetParam("predictions_file"); - const string probabilitiesFile = CLI::GetParam("probabilities_file"); + const string predictionsFile = + CLI::GetParam("predictions_file"); + const string probabilitiesFile = + CLI::GetParam("probabilities_file"); bool batchTraining = CLI::HasParam("batch_mode"); const size_t passes = (size_t) CLI::GetParam("passes"); if (passes > 1) @@ -186,7 +191,7 @@ void PerformActions(const typename TreeType::NumericSplit& numericSplit) TreeType* tree = NULL; DatasetInfo datasetInfo; - if (inputModelFile.empty()) + if (!CLI::HasParam("input_model_file")) { arma::mat trainingSet; data::Load(trainingFile, trainingSet, datasetInfo, true); @@ -216,7 +221,7 @@ void PerformActions(const typename TreeType::NumericSplit& numericSplit) tree = new TreeType(datasetInfo, 1, 1); data::Load(inputModelFile, "streamingDecisionTree", *tree, true); - if (!trainingFile.empty()) + if (CLI::HasParam("training_file")) { arma::mat trainingSet; data::Load(trainingFile, trainingSet, datasetInfo, true); @@ -244,7 +249,7 @@ void PerformActions(const typename TreeType::NumericSplit& numericSplit) } } - if (!trainingFile.empty()) + if (CLI::HasParam("training_file")) { // Get training error. arma::mat trainingSet; @@ -282,7 +287,7 @@ void PerformActions(const typename TreeType::NumericSplit& numericSplit) Log::Info << nodes << " nodes in the tree." << endl; // The tree is trained or loaded. Now do any testing if we need. - if (!testFile.empty()) + if (CLI::HasParam("test_file")) { arma::mat testSet; data::Load(testFile, testSet, datasetInfo, true); @@ -312,15 +317,15 @@ void PerformActions(const typename TreeType::NumericSplit& numericSplit) 100.0 << ")." << endl; } - if (!predictionsFile.empty()) + if (CLI::HasParam("predictions_file")) data::Save(predictionsFile, predictions); - if (!probabilitiesFile.empty()) + if (CLI::HasParam("probabilities_file")) data::Save(probabilitiesFile, probabilities); } // Check the accuracy on the training set. - if (!outputModelFile.empty()) + if (CLI::HasParam("output_model_file")) data::Save(outputModelFile, "streamingDecisionTree", *tree, true); // Clean up memory. diff --git a/src/mlpack/methods/lars/lars_main.cpp b/src/mlpack/methods/lars/lars_main.cpp index 7981ca0cb3..d9f0ae8b0c 100644 --- a/src/mlpack/methods/lars/lars_main.cpp +++ b/src/mlpack/methods/lars/lars_main.cpp @@ -51,8 +51,8 @@ PARAM_STRING("output_model_file", "File to save model to.", "M", ""); PARAM_STRING("test_file", "File containing points to regress on (test points).", "t", ""); -PARAM_STRING("output_predictions", "If --test_file is specified, this file is " - "where the predicted responses will be saved.", "o", "predictions.csv"); +PARAM_STRING("output_predictions", "If --test_file is specified, this " + "file is where the predicted responses will be saved.", "o", ""); PARAM_DOUBLE("lambda1", "Regularization parameter for l1-norm penalty.", "l", 0); @@ -95,12 +95,16 @@ int main(int argc, char* argv[]) if (!CLI::HasParam("output_predictions") && !CLI::HasParam("output_model_file")) - Log::Warn << "--output_predictions (-o) and --output_model_file (-M) are " - << "not specified; no results will be saved!" << endl; + Log::Warn << "--output_predictions (-o) and --output_model_file (-M) " + << "are not specified; no results will be saved!" << endl; if (CLI::HasParam("output_predictions") && !CLI::HasParam("test_file")) - Log::Warn << "--output_predictions (-o) specified, but --test_file (-t) is " - << "not; no results will be saved." << endl; + Log::Warn << "--output_predictions (-o) specified, but --test_file " + << "(-t) is not; no results will be saved." << endl; + + if (CLI::HasParam("test_file") && !CLI::HasParam("output_predictions")) + Log::Warn << "--test_file (-t) specified, but --output_predictions " + << "(-o) is not; no results will be saved." << endl; // Initialize the object. LARS lars(useCholesky, lambda1, lambda2); @@ -109,16 +113,16 @@ int main(int argc, char* argv[]) { // Load covariates. We can avoid LARS transposing our data by choosing to // not transpose this data. - const string matXFilename = CLI::GetParam("input_file"); + const string inputFile = CLI::GetParam("input_file"); mat matX; - data::Load(matXFilename, matX, true, false); + data::Load(inputFile, matX, true, false); // Load responses. The responses should be a one-dimensional vector, and it // seems more likely that these will be stored with one response per line // (one per row). So we should not transpose upon loading. - const string yFilename = CLI::GetParam("responses_file"); + const string responsesFile = CLI::GetParam("responses_file"); mat matY; // Will be a vector. - data::Load(yFilename, matY, true, false); + data::Load(responsesFile, matY, true, false); // Make sure y is oriented the right way. if (matY.n_rows == 1) @@ -135,16 +139,14 @@ int main(int argc, char* argv[]) } else // We must have --input_model_file. { - const string modelFile = CLI::GetParam("input_model_file"); - data::Load(modelFile, "lars_model", lars, true); + const string inputModelFile = CLI::GetParam("input_model_file"); + data::Load(inputModelFile, "lars_model", lars, true); } if (CLI::HasParam("test_file")) { Log::Info << "Regressing on test points." << endl; const string testFile = CLI::GetParam("test_file"); - const string outputPredictionsFile = - CLI::GetParam("output_predictions"); // Load test points. mat testPoints; @@ -161,7 +163,12 @@ int main(int argc, char* argv[]) lars.Predict(testPoints.t(), predictions, false); // Save test predictions. One per line, so, don't transpose on save. - data::Save(outputPredictionsFile, predictions, true, false); + if (CLI::HasParam("output_predictions")) + { + const string outputPredictionsFile = + CLI::GetParam("output_predictions"); + data::Save(outputPredictionsFile, predictions, true, false); + } } if (CLI::HasParam("output_model_file")) diff --git a/src/mlpack/methods/linear_regression/linear_regression_main.cpp b/src/mlpack/methods/linear_regression/linear_regression_main.cpp index 9f008505e9..a764ed8fb9 100644 --- a/src/mlpack/methods/linear_regression/linear_regression_main.cpp +++ b/src/mlpack/methods/linear_regression/linear_regression_main.cpp @@ -22,22 +22,23 @@ PROGRAM_INFO("Simple Linear Regression and Prediction", " another matrix X' (--test_file):\n\n" " y' = X' * b\n\n" "and these predicted responses, y', are saved to a file " - "(--output_predictions). This type of regression is related to least-angle" - " regression, which mlpack implements with the 'lars' executable."); + "(--output_predictions). This type of regression is related to " + "least-angle regression, which mlpack implements with the 'lars' " + "executable."); PARAM_STRING("training_file", "File containing training set X (regressors).", "t", ""); -PARAM_STRING("training_responses", "Optional file containing y (responses). If " - "not given, the responses are assumed to be the last row of the input " - "file.", "r", ""); +PARAM_STRING("training_responses", "Optional file containing y " + "(responses). If not given, the responses are assumed to be the last row " + "of the input file.", "r", ""); PARAM_STRING("input_model_file", "File containing existing model (parameters).", "m", ""); PARAM_STRING("output_model_file", "File to save trained model to.", "M", ""); PARAM_STRING("test_file", "File containing X' (test regressors).", "T", ""); -PARAM_STRING("output_predictions", "If --test_file is specified, this file is " - "where the predicted responses will be saved.", "p", "predictions.csv"); +PARAM_STRING("output_predictions", "If --test_file is specified, this " + "file is where the predicted responses will be saved.", "p", ""); PARAM_DOUBLE("lambda", "Tikhonov regularization for ridge regression. If 0, " "the method reduces to linear regression.", "l", 0.0); @@ -54,10 +55,12 @@ int main(int argc, char* argv[]) const string inputModelFile = CLI::GetParam("input_model_file"); const string outputModelFile = CLI::GetParam("output_model_file"); - const string outputPredictions = CLI::GetParam("output_predictions"); - const string responseName = CLI::GetParam("training_responses"); - const string testName = CLI::GetParam("test_file"); - const string trainName = CLI::GetParam("training_file"); + const string outputPredictionsFile = + CLI::GetParam("output_predictions"); + const string trainingResponsesFile = + CLI::GetParam("training_responses"); + const string testFile = CLI::GetParam("test_file"); + const string trainFile = CLI::GetParam("training_file"); const double lambda = CLI::GetParam("lambda"); mat regressors; @@ -69,16 +72,16 @@ int main(int argc, char* argv[]) bool computeModel = false; // We want to determine if an input file XOR model file were given. - if (trainName.empty()) // The user specified no input file. + if (!CLI::HasParam("training_file")) { - if (inputModelFile.empty()) // The user specified no model file; error. + if (!CLI::HasParam("input_model_file")) Log::Fatal << "You must specify either --input_file or --model_file." << endl; else // The model file was specified, no problems. computeModel = false; } // The user specified an input file but no model file, no problems. - else if (inputModelFile.empty()) + else if (!CLI::HasParam("input_model_file")) computeModel = true; // The user specified both an input file and model file. // This is ambiguous -- which model should we use? A generated one or given @@ -89,9 +92,13 @@ int main(int argc, char* argv[]) << "both." << endl; } + if (CLI::HasParam("test_file") && !CLI::HasParam("output_predictions")) + Log::Warn << "--test_file (-t) specified, but --output_predictions " + << "(-o) is not; no results will be saved." << endl; + // If they specified a model file, we also need a test file or we // have nothing to do. - if (!computeModel && testName.empty()) + if (!computeModel && !CLI::HasParam("test_file")) { Log::Fatal << "When specifying --model_file, you must also specify " << "--test_file." << endl; @@ -106,11 +113,11 @@ int main(int argc, char* argv[]) if (computeModel) { Timer::Start("load_regressors"); - data::Load(trainName, regressors, true); + data::Load(trainFile, regressors, true); Timer::Stop("load_regressors"); // Are the responses in a separate file? - if (responseName.empty()) + if (CLI::HasParam("training_responses")) { // The initial predictors for y, Nx1. responses = trans(regressors.row(regressors.n_rows - 1)); @@ -120,7 +127,7 @@ int main(int argc, char* argv[]) { // The initial predictors for y, Nx1. Timer::Start("load_responses"); - data::Load(responseName, responses, true); + data::Load(trainingResponsesFile, responses, true); Timer::Stop("load_responses"); if (responses.n_rows == 1) @@ -139,12 +146,12 @@ int main(int argc, char* argv[]) Timer::Stop("regression"); // Save the parameters. - if (!outputModelFile.empty()) + if (CLI::HasParam("output_model_file")) data::Save(outputModelFile, "linearRegressionModel", lr); } // Did we want to predict, too? - if (!testName.empty()) + if (CLI::HasParam("test_file")) { // A model file was passed in, so load it. if (!computeModel) @@ -157,14 +164,14 @@ int main(int argc, char* argv[]) // Load the test file data. arma::mat points; Timer::Start("load_test_points"); - data::Load(testName, points, true); + data::Load(testFile, points, true); Timer::Stop("load_test_points"); // Ensure that test file data has the right number of features. if ((lr.Parameters().n_elem - 1) != points.n_rows) { Log::Fatal << "The model was trained on " << lr.Parameters().n_elem - 1 - << "-dimensional data, but the test points in '" << testName + << "-dimensional data, but the test points in '" << testFile << "' are " << points.n_rows << "-dimensional!" << endl; } @@ -175,6 +182,7 @@ int main(int argc, char* argv[]) Timer::Stop("prediction"); // Save predictions. - data::Save(outputPredictions, predictions, true, false); + if (CLI::HasParam("output_predictions")) + data::Save(outputPredictionsFile, predictions, true, false); } } diff --git a/src/mlpack/methods/mvu/mvu_main.cpp b/src/mlpack/methods/mvu/mvu_main.cpp index 1cff076003..4ca10f67c2 100644 --- a/src/mlpack/methods/mvu/mvu_main.cpp +++ b/src/mlpack/methods/mvu/mvu_main.cpp @@ -18,8 +18,7 @@ PROGRAM_INFO("Maximum Variance Unfolding (MVU)", "This program implements " PARAM_STRING_REQ("input_file", "Filename of input dataset.", "i"); PARAM_INT_REQ("new_dim", "New dimensionality of dataset.", "d"); -PARAM_STRING("output_file", "Filename to save unfolded dataset to.", "o", - "output.csv"); +PARAM_STRING("output_file", "Filename to save unfolded dataset to.", "o", ""); PARAM_INT("num_neighbors", "Number of nearest neighbors to consider while " "unfolding.", "k", 5); @@ -33,16 +32,22 @@ int main(int argc, char **argv) { // Read from command line. CLI::ParseCommandLine(argc, argv); + const string inputFile = CLI::GetParam("input_file"); + const string outputFile = CLI::GetParam("output_file"); + const int newDim = CLI::GetParam("new_dim"); + const int numNeighbors = CLI::GetParam("num_neighbors"); + + if (CLI::HasParam("output_file")) + Log::Warn << "--output_file (-o) is not specified; no results will be " + << "saved!" << endl; RandomSeed(time(NULL)); // Load input dataset. - const string inputFile = CLI::GetParam("input_file"); mat data; data::Load(inputFile, data, true); // Verify that the requested dimensionality is valid. - const int newDim = CLI::GetParam("new_dim"); if (newDim <= 0 || newDim > (int) data.n_rows) { Log::Fatal << "Invalid new dimensionality (" << newDim << "). Must be " @@ -51,7 +56,6 @@ int main(int argc, char **argv) } // Verify that the number of neighbors is valid. - const int numNeighbors = CLI::GetParam("num_neighbors"); if (numNeighbors <= 0 || numNeighbors > (int) data.n_cols) { Log::Fatal << "Invalid number of neighbors (" << numNeighbors << "). Must " @@ -66,6 +70,6 @@ int main(int argc, char **argv) mvu.Unfold(newDim, numNeighbors, output); // Save results to file. - const string outputFile = CLI::GetParam("output_file"); - data::Save(outputFile, output, true); + if (CLI::HasParam("output_file")) + data::Save(outputFile, output, true); } diff --git a/src/mlpack/methods/neighbor_search/CMakeLists.txt b/src/mlpack/methods/neighbor_search/CMakeLists.txt index 6b61e1889e..4d0d44b080 100644 --- a/src/mlpack/methods/neighbor_search/CMakeLists.txt +++ b/src/mlpack/methods/neighbor_search/CMakeLists.txt @@ -33,22 +33,22 @@ add_cli_executable(knn) add_cli_executable(kfn) if (BUILD_CLI_EXECUTABLES) -# -- mlpack_knn/mlpack_kfn compatibility start -- -# Make a copy of mlpack_knn/mlpack_kfn both on Windows and *unix for -# compatibility. This should be removed by mlpack 3.0.0. -get_property(knn_loc TARGET mlpack_knn PROPERTY LOCATION) -get_filename_component(knn_ext ${knn_loc} EXT) + # -- mlpack_knn/mlpack_kfn compatibility start -- + # Make a copy of mlpack_knn/mlpack_kfn both on Windows and *unix for + # compatibility. This should be removed by mlpack 3.0.0. + get_property(knn_loc TARGET mlpack_knn PROPERTY LOCATION) + get_filename_component(knn_ext ${knn_loc} EXT) -add_custom_command(TARGET mlpack_knn POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - $ $/mlpack_allknn${knn_ext} -) + add_custom_command(TARGET mlpack_knn POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + $ $/mlpack_allknn${knn_ext} + ) -get_property(kfn_loc TARGET mlpack_kfn PROPERTY LOCATION) -get_filename_component(kfn_ext ${kfn_loc} EXT) + get_property(kfn_loc TARGET mlpack_kfn PROPERTY LOCATION) + get_filename_component(kfn_ext ${kfn_loc} EXT) -add_custom_command(TARGET mlpack_kfn POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - $ $/mlpack_allkfn${kfn_ext} -) + add_custom_command(TARGET mlpack_kfn POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + $ $/mlpack_allkfn${kfn_ext} + ) endif () diff --git a/src/mlpack/methods/pca/pca_main.cpp b/src/mlpack/methods/pca/pca_main.cpp index 6277c5b47f..8bbbedf0fc 100644 --- a/src/mlpack/methods/pca/pca_main.cpp +++ b/src/mlpack/methods/pca/pca_main.cpp @@ -22,10 +22,11 @@ PROGRAM_INFO("Principal Components Analysis", "This program performs principal " // Parameters for program. PARAM_STRING_REQ("input_file", "Input dataset to perform PCA on.", "i"); PARAM_STRING_REQ("output_file", "File to save modified dataset to.", "o"); + PARAM_INT("new_dimensionality", "Desired dimensionality of output dataset. If " "0, no dimensionality reduction is performed.", "d", 0); PARAM_DOUBLE("var_to_retain", "Amount of variance to retain; should be between " - "0 and 1. If 1, all variance is retained. Overrides -d.", "V", 0); + "0 and 1. If 1, all variance is retained. Overrides -d.", "r", 0); PARAM_FLAG("scale", "If set, the data will be scaled before running PCA, such " "that the variance of each feature is 1.", "s"); @@ -64,8 +65,8 @@ int main(int argc, char** argv) if (CLI::GetParam("var_to_retain") != 0) { if (CLI::GetParam("new_dimensionality") != 0) - Log::Warn << "New dimensionality (-d) ignored because -V was specified." - << endl; + Log::Warn << "New dimensionality (-d) ignored because --var_to_retain was" + << " specified." << endl; varRetained = p.Apply(dataset, CLI::GetParam("var_to_retain")); } diff --git a/src/mlpack/methods/perceptron/perceptron_main.cpp b/src/mlpack/methods/perceptron/perceptron_main.cpp index 28a2776bd3..3c99fc650c 100644 --- a/src/mlpack/methods/perceptron/perceptron_main.cpp +++ b/src/mlpack/methods/perceptron/perceptron_main.cpp @@ -112,21 +112,24 @@ int main(int argc, char** argv) const size_t maxIterations = (size_t) CLI::GetParam("max_iterations"); // We must either load a model or train a model. - if (inputModelFile == "" && trainingDataFile == "") + if (!CLI::HasParam("input_model_file") && !CLI::HasParam("training_file")) Log::Fatal << "Either an input model must be specified with " << "--input_model_file or training data must be given " << "(--training_file)!" << endl; // If the user isn't going to save the output model or any predictions, we // should issue a warning. - if (outputModelFile == "" && testDataFile == "") + if (!CLI::HasParam("output_model_file") && !CLI::HasParam("test_file")) Log::Warn << "Output will not be saved! (Neither --test_file nor " << "--output_model_file are specified.)" << endl; + if (CLI::HasParam("test_file") && !CLI::HasParam("output_file")) + Log::Fatal << "--output_file must be specified with --test_file" << endl; + // Now, load our model, if there is one. Perceptron<>* p = NULL; Col mappings; - if (inputModelFile != "") + if (CLI::HasParam("input_model_file")) { Log::Info << "Loading saved perceptron from model file '" << inputModelFile << "'." << endl; @@ -139,7 +142,7 @@ int main(int argc, char** argv) } // Next, load the training data and labels (if they have been given). - if (trainingDataFile != "") + if (CLI::HasParam("training_file")) { Log::Info << "Training perceptron on dataset '" << trainingDataFile; if (labelsFile != "") @@ -217,7 +220,7 @@ int main(int argc, char** argv) } // Now, the training procedure is complete. Do we have any test data? - if (testDataFile != "") + if (CLI::HasParam("test_file")) { Log::Info << "Classifying dataset '" << testDataFile << "'." << endl; mat testData; @@ -245,7 +248,7 @@ int main(int argc, char** argv) } // Lastly, do we need to save the output model? - if (outputModelFile != "") + if (CLI::HasParam("output_model_file")) { PerceptronModel pm(*p, mappings); data::Save(outputModelFile, "perceptron_model", pm); diff --git a/src/mlpack/methods/preprocess/preprocess_split_main.cpp b/src/mlpack/methods/preprocess/preprocess_split_main.cpp index 1e063db0cd..a615f37d5c 100644 --- a/src/mlpack/methods/preprocess/preprocess_split_main.cpp +++ b/src/mlpack/methods/preprocess/preprocess_split_main.cpp @@ -14,26 +14,20 @@ PROGRAM_INFO("Split Data", "This utility takes a dataset and optionally labels " "(-r) option; the default is 0.2 (20%)." "\n\n" "The program does not modify the original file, but instead makes separate " - "files to save the training and test files; you can specify the file names " - "with --training_file (-t) and --test_file (-T). If these options are not " - "specified, the program automatically names the training and test file by " - "prepending 'train_' and 'test_' to the dataset filename (which was " - "specified by --input_file)." + "files to save the training and test files; The program requires you to " + "specify the file names with --training_file (-t) and --test_file (-T)." "\n\n" "Optionally, labels can be also be split along with the data by specifying " "the --input_labels_file (-I) option. Splitting labels works the same way " "as splitting the data. The output training and test labels will be saved " "to the files specified by --training_labels_file (-l) and " - "--test_labels_file (-L), respectively. If these options are not specified," - " then the program will automatically name the training labels and test " - "labels file by prepending 'train_' and 'test_' to the labels filename " - "(which was specified by --input_labels_file)." + "--test_labels_file (-L), respectively." "\n\n" "So, a simple example where we want to split dataset.csv into " - "train_dataset.csv and test_dataset.csv with 60% of the data in the " - "training set and 40% of the dataset in the test set, we could run" + "train.csv and test.csv with 60% of the data in the training set and 40% " + "of the dataset in the test set, we could run" "\n\n" - "$ mlpack_preprocess_split -i dataset.csv -r 0.4" + "$ mlpack_preprocess_split -i dataset.csv -t train.csv -T test.csv -r 0.4" "\n\n" "If we had a dataset in dataset.csv and associated labels in labels.csv, " "and we wanted to split these into training_set.csv, training_labels.csv, " @@ -46,12 +40,12 @@ PROGRAM_INFO("Split Data", "This utility takes a dataset and optionally labels " // Define parameters for data. PARAM_STRING_REQ("input_file", "File containing data,", "i"); +PARAM_STRING_REQ("training_file", "File name to save train data", "t"); +PARAM_STRING_REQ("test_file", "File name to save test data", "T"); // Define optional parameters. PARAM_STRING("input_labels_file", "File containing labels", "I", ""); -PARAM_STRING("training_file", "File name to save train data", "t", ""); -PARAM_STRING("test_file", "File name to save test data", "T", ""); PARAM_STRING("training_labels_file", "File name to save train label", "l", ""); -PARAM_STRING("test_labels_file", "File name to save test label", "L", ""); +PARAM_STRING("test_labels_file", "File name to save test label", "L",""); // Define optional test ratio, default is 0.2 (Test 20% Train 80%) PARAM_DOUBLE("test_ratio", "Ratio of test set, if not set," @@ -67,52 +61,33 @@ int main(int argc, char** argv) CLI::ParseCommandLine(argc, argv); const string inputFile = CLI::GetParam("input_file"); const string inputLabels = CLI::GetParam("input_labels_file"); - string trainingFile = CLI::GetParam("training_file"); - string testFile = CLI::GetParam("test_file"); - string trainingLabelsFile = CLI::GetParam("training_labels_file"); - string testLabelsFile = CLI::GetParam("test_labels_file"); + const string trainingFile = CLI::GetParam("training_file"); + const string testFile = CLI::GetParam("test_file"); + const string trainingLabelsFile = CLI::GetParam("training_labels_file"); + const string testLabelsFile = CLI::GetParam("test_labels_file"); const double testRatio = CLI::GetParam("test_ratio"); - // Check on data parameters. - if (trainingFile.empty()) - { - trainingFile = "train_" + inputFile; - Log::Warn << "You did not specify --training_file, so the training set file" - << " name will be automatically set to '" << trainingFile << "'." - << endl; - } - if (testFile.empty()) - { - testFile = "test_" + inputFile; - Log::Warn << "You did not specify --test_file, so the test set file name " - << "will be automatically set to '" << testFile << "'." << endl; - } - // Check on label parameters. - if (!inputLabels.empty()) + if (CLI::HasParam("input_labels")) { if (!CLI::HasParam("training_labels_file")) { - trainingLabelsFile = "train_" + inputLabels; - Log::Warn << "You did not specify --training_labels_file, so the training" - << "set labels file name will be automatically set to '" - << trainingLabelsFile << "'." << endl; + Log::Fatal << "--training_labels_file (-l) must be specified if " + << "--input_labels (-l) is specified!" << endl; } if (!CLI::HasParam("test_labels_file")) { - testLabelsFile = "test_" + inputLabels; - Log::Warn << "You did not specify --test_labels_file, so the test set " - << "labels file name will be automatically set to '" - << testLabelsFile << "'." << endl; + Log::Fatal << "--test_labels_file (-L) must be specified if " + << "--input_labels (-I) is specified!" << endl; } } else { - if (CLI::HasParam("training_labels_file") - || CLI::HasParam("test_labels_file")) + if (CLI::HasParam("training_labels_file") || + CLI::HasParam("test_labels_file")) { Log::Fatal << "When specifying --training_labels_file or " - << "--test_labels_file, you must also specify --input_labels. " + << "--test_labels_file, you must also specify --input_labels." << endl; } } diff --git a/src/mlpack/methods/radical/radical_main.cpp b/src/mlpack/methods/radical/radical_main.cpp index 43eac6d863..5b9c7493d1 100644 --- a/src/mlpack/methods/radical/radical_main.cpp +++ b/src/mlpack/methods/radical/radical_main.cpp @@ -16,10 +16,8 @@ PROGRAM_INFO("RADICAL", "An implementation of RADICAL, a method for independent" PARAM_STRING_REQ("input_file", "Input dataset filename for ICA.", "i"); -PARAM_STRING("output_ic", "File to save independent components to.", "o", - "output_ic.csv"); -PARAM_STRING("output_unmixing", "File to save unmixing matrix to.", "u", - "output_unmixing.csv"); +PARAM_STRING_REQ("output_ic", "File to save independent components to.", "o"); +PARAM_STRING_REQ("output_unmixing", "File to save unmixing matrix to.", "u"); PARAM_DOUBLE("noise_std_dev", "Standard deviation of Gaussian noise.", "n", 0.175); diff --git a/src/mlpack/methods/rann/CMakeLists.txt b/src/mlpack/methods/rann/CMakeLists.txt index 2effb36411..906c4e65eb 100644 --- a/src/mlpack/methods/rann/CMakeLists.txt +++ b/src/mlpack/methods/rann/CMakeLists.txt @@ -30,10 +30,22 @@ set(DIR_SRCS) foreach(file ${SOURCES}) set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file}) endforeach() -# append sources (with directory name) to list of all mlpack sources (used at the parent scope) +# Append sources (with directory name) to list of all mlpack sources (used at the parent scope) set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE) +# The code to compute the rank-approximate neighbor for the given query and +# reference sets. +add_cli_executable(krann) + +if (BUILD_CLI_EXECUTABLES) + # Compatibility: retain mlpack_allkrann until mlpack 3.0.0. + get_property(krann_loc TARGET mlpack_krann PROPERTY LOCATION) + get_filename_component(krann_ext ${krann_loc} EXT) + + add_custom_command(TARGET mlpack_krann POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + $ + $/mlpack_allkrann${kfn_ext} + ) +endif () -# The code to compute the rank-approximate neighbor -# for the given query and reference sets -add_cli_executable(allkrann) diff --git a/src/mlpack/methods/rann/allkrann_main.cpp b/src/mlpack/methods/rann/krann_main.cpp similarity index 98% rename from src/mlpack/methods/rann/allkrann_main.cpp rename to src/mlpack/methods/rann/krann_main.cpp index ce6f9f1bdc..5fede8481d 100644 --- a/src/mlpack/methods/rann/allkrann_main.cpp +++ b/src/mlpack/methods/rann/krann_main.cpp @@ -2,7 +2,7 @@ * @file allkrann_main.cpp * @author Parikshit Ram * - * Implementation of the AllkRANN executable. Allows some number of standard + * Implementation of the kRANN executable. Allows some number of standard * options. */ #include @@ -18,7 +18,7 @@ using namespace mlpack::tree; using namespace mlpack::metric; // Information about the program itself. -PROGRAM_INFO("All K-Rank-Approximate-Nearest-Neighbors", +PROGRAM_INFO("K-Rank-Approximate-Nearest-Neighbors (kRANN)", "This program will calculate the k rank-approximate-nearest-neighbors of a " "set of points. You may specify a separate set of reference points and " "query points, or just a reference set which will be used as both the " @@ -73,7 +73,7 @@ PARAM_INT("seed", "Random seed (if 0, std::time(NULL) is used).", "s", 0); // Search options. PARAM_DOUBLE("tau", "The allowed rank-error in terms of the percentile of " - "the data.", "t", 5); + "the data.", "T", 5); PARAM_DOUBLE("alpha", "The desired success probability.", "a", 0.95); PARAM_FLAG("naive", "If true, sampling will be done without using a tree.", "N"); diff --git a/src/mlpack/methods/rann/ra_typedef.hpp b/src/mlpack/methods/rann/ra_typedef.hpp index 41d7e29b42..553dd047da 100644 --- a/src/mlpack/methods/rann/ra_typedef.hpp +++ b/src/mlpack/methods/rann/ra_typedef.hpp @@ -20,32 +20,55 @@ namespace mlpack { namespace neighbor { /** - * The AllkRANN class is the all-k-rank-approximate-nearest-neighbors method. - * It returns squared L2 distances (squared Euclidean distances) for each of the - * k rank-approximate nearest-neighbors. Squared distances are used because - * they are slightly faster than non-squared distances (they have one fewer call - * to sqrt()). + * The KRANN class is the k-rank-approximate-nearest-neighbors method. It + * returns L2 distances for each of the k rank-approximate nearest-neighbors. * * The approximation is controlled with two parameters (see allkrann_main.cpp) * which can be specified at search time. So the tree building is done only once * while the search can be performed multiple times with different approximation * levels. */ +typedef RASearch<> KRANN; + +/** + * The KRAFN class is the k-rank-approximate-farthest-neighbors method. It + * returns L2 distances for each of the k rank-approximate farthest-neighbors. + * + * The approximation is controlled with two parameters (see allkrann_main.cpp) + * which can be specified at search time. So the tree building is done only once + * while the search can be performed multiple times with different approximation + * levels. + */ +typedef RASearch KRAFN; + +/** + * @deprecated + * The AllkRANN class is the all-k-rank-approximate-nearest-neighbors method. It + * returns L2 distances for each of the k rank-approximate nearest-neighbors. + * + * The approximation is controlled with two parameters (see allkrann_main.cpp) + * which can be specified at search time. So the tree building is done only once + * while the search can be performed multiple times with different approximation + * levels. + * + * This typedef will be removed in mlpack 3.0.0; use the KRANN typedef instead. + */ typedef RASearch<> AllkRANN; /** + * @deprecated * The AllkRAFN class is the all-k-rank-approximate-farthest-neighbors method. - * It returns squared L2 distances (squared Euclidean distances) for each of the - * k rank-approximate farthest-neighbors. Squared distances are used because - * they are slightly faster than non-squared distances (they have one fewer - * call to sqrt()). + * It returns L2 distances for each of the k rank-approximate + * farthest-neighbors. * * The approximation is controlled with two parameters (see allkrann_main.cpp) * which can be specified at search time. So the tree building is done only once * while the search can be performed multiple times with different approximation * levels. + * + * This typedef will be removed in mlpack 3.0.0; use the KRANN typedef instead. */ -typedef RASearch AllkRAFN; +typedef RASearch<> AllkRAFN; } // namespace neighbor } // namespace mlpack diff --git a/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp b/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp index af78bd2a45..8ec43f74bd 100644 --- a/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp +++ b/src/mlpack/methods/softmax_regression/softmax_regression_main.cpp @@ -21,9 +21,9 @@ PROGRAM_INFO("Softmax Regression", "This program performs softmax regression, " "(-r), and if an intercept term is not desired in the model, the " "--no_intercept (-N) can be specified." "\n\n" - "The trained model can be saved to a file with the --output_model (-m) " + "The trained model can be saved to a file with the --output_model_file (-m) " "option. If training is not desired, but only testing is, a model can be " - "loaded with the --input_model (-i) option. At the current time, a loaded " + "loaded with the --input_model_file (-i) option. At the current time, a loaded " "model cannot be trained further, so specifying both -i and -t is not " "allowed." "\n\n" @@ -80,10 +80,10 @@ void TestPredictAcc(const string& testFile, // Build the softmax model given the parameters. template -std::unique_ptr TrainSoftmax(const string& trainingFile, - const string& labelFile, - const string& inputModelFile, - const size_t maxIterations); +unique_ptr TrainSoftmax(const string& trainingFile, + const string& labelsFile, + const string& inputModelFile, + const size_t maxIterations); int main(int argc, char** argv) { @@ -91,39 +91,39 @@ int main(int argc, char** argv) CLI::ParseCommandLine(argc, argv); - const std::string trainingFile = CLI::GetParam("training_file"); - const std::string inputModelFile = CLI::GetParam("input_model"); + const string trainingFile = CLI::GetParam("training_file"); + const string labelsFile = CLI::GetParam("labels_file"); + const string inputModelFile = CLI::GetParam("input_model_file"); + const string outputModelFile = CLI::GetParam("output_model_file"); + const string testLabelsFile = CLI::GetParam("test_labels"); + const int maxIterations = CLI::GetParam("max_iterations"); + const string predictionsFile = CLI::GetParam("predictions_file"); // One of inputFile and modelFile must be specified. - if (inputModelFile.empty() && trainingFile.empty()) - Log::Fatal << "One of --input_model or --training_file must be specified." + if (!CLI::HasParam("input_model_file") && !CLI::HasParam("training_file")) + Log::Fatal << "One of --input_model_file or --training_file must be specified." << endl; - const std::string labelFile = CLI::GetParam("labels_file"); - if (!trainingFile.empty() && labelFile.empty()) + if (CLI::HasParam("training_file") && CLI::HasParam("labels_file")) Log::Fatal << "--labels_file must be specified with --training_file!" << endl; - const int maxIterations = CLI::GetParam("max_iterations"); - if (maxIterations < 0) Log::Fatal << "Invalid value for maximum iterations (" << maxIterations << ")! Must be greater than or equal to 0." << endl; - const string outputModelFile = CLI::GetParam("output_model"); - const string testLabelsFile = CLI::GetParam("test_labels"); - const string predictionsFile = CLI::GetParam("predictions_file"); - // Make sure we have an output file of some sort. - if (outputModelFile.empty() && testLabelsFile.empty() && - predictionsFile.empty()) - Log::Warn << "None of --output_model, --test_labels, or --predictions_file " - << "are set; no results from this program will be saved." << endl; + if (!CLI::HasParam("output_model_file") && + !CLI::HasParam("test_labels") && + !CLI::HasParam("predictions_file")) + Log::Warn << "None of --output_model_file, --test_labels, or " + << "--predictions_file are set; no results from this program will be " + << "saved." << endl; using SM = regression::SoftmaxRegression<>; - std::unique_ptr sm = TrainSoftmax(trainingFile, - labelFile, + unique_ptr sm = TrainSoftmax(trainingFile, + labelsFile, inputModelFile, maxIterations); @@ -132,11 +132,9 @@ int main(int argc, char** argv) CLI::GetParam("test_labels"), sm->NumClasses(), *sm); - if (!outputModelFile.empty()) - { - data::Save(CLI::GetParam("output_model"), + if (CLI::HasParam("output_model_file")) + data::Save(CLI::GetParam("output_model_file"), "softmax_regression_model", *sm, true); - } } size_t CalculateNumberOfClasses(const size_t numClasses, @@ -144,8 +142,8 @@ size_t CalculateNumberOfClasses(const size_t numClasses, { if (numClasses == 0) { - const std::set unique_labels(std::begin(trainLabels), - std::end(trainLabels)); + const set unique_labels(begin(trainLabels), + end(trainLabels)); return unique_labels.size(); } else @@ -203,12 +201,12 @@ void TestPredictAcc(const string& testFile, if (testData.n_cols != testLabels.n_elem) { Log::Fatal << "Test data in --test_data has " << testData.n_cols - << " points, but labels in --test_labels have " << testLabels.n_elem - << " labels!" << endl; + << " points, but labels in --test_labels have " + << testLabels.n_elem << " labels!" << endl; } - std::vector bingoLabels(numClasses, 0); - std::vector labelSize(numClasses, 0); + vector bingoLabels(numClasses, 0); + vector labelSize(numClasses, 0); for (arma::uword i = 0; i != predictLabels.n_elem; ++i) { if (predictLabels(i) == testLabels(i)) @@ -234,16 +232,16 @@ void TestPredictAcc(const string& testFile, } template -std::unique_ptr TrainSoftmax(const string& trainingFile, - const string& labelFile, - const string& inputModelFile, - const size_t maxIterations) +unique_ptr TrainSoftmax(const string& trainingFile, + const string& labelsFile, + const string& inputModelFile, + const size_t maxIterations) { using namespace mlpack; using SRF = regression::SoftmaxRegressionFunction; - std::unique_ptr sm; + unique_ptr sm; if (!inputModelFile.empty()) { sm.reset(new Model(0, 0, false)); @@ -258,7 +256,7 @@ std::unique_ptr TrainSoftmax(const string& trainingFile, //load functions of mlpack do not works on windows, it will complain //"[FATAL] Unable to detect type of 'softmax_data.txt'; incorrect extension?" data::Load(trainingFile, trainData, true); - data::Load(labelFile, tmpTrainLabels, true); + data::Load(labelsFile, tmpTrainLabels, true); trainLabels = tmpTrainLabels.row(0); if (trainData.n_cols != trainLabels.n_elem) diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index 8b36a941c9..4a3d406269 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -5,7 +5,6 @@ add_executable(mlpack_test adaboost_test.cpp adam_test.cpp ada_delta_test.cpp - allkrann_search_test.cpp arma_extend_test.cpp aug_lagrangian_test.cpp cf_test.cpp @@ -30,6 +29,7 @@ add_executable(mlpack_test kfn_test.cpp kmeans_test.cpp knn_test.cpp + krann_search_test.cpp lars_test.cpp lbfgs_test.cpp lin_alg_test.cpp diff --git a/src/mlpack/tests/allkrann_search_test.cpp b/src/mlpack/tests/krann_search_test.cpp similarity index 99% rename from src/mlpack/tests/allkrann_search_test.cpp rename to src/mlpack/tests/krann_search_test.cpp index 757811a609..37e9b35bcc 100644 --- a/src/mlpack/tests/allkrann_search_test.cpp +++ b/src/mlpack/tests/krann_search_test.cpp @@ -22,9 +22,9 @@ using namespace mlpack::tree; using namespace mlpack::metric; using namespace mlpack::bound; -BOOST_AUTO_TEST_SUITE(AllkRANNTest); +BOOST_AUTO_TEST_SUITE(KRANNTest); -// Test the correctness and guarantees of AllkRANN when in naive mode. +// Test the correctness and guarantees of KRANN when in naive mode. BOOST_AUTO_TEST_CASE(NaiveGuaranteeTest) { arma::Mat neighbors; @@ -562,8 +562,8 @@ BOOST_AUTO_TEST_CASE(MoveConstructorTest) arma::mat dataset = arma::randu(3, 200); arma::mat copy(dataset); - AllkRANN moveknn(std::move(copy)); - AllkRANN knn(dataset); + KRANN moveknn(std::move(copy)); + KRANN knn(dataset); BOOST_REQUIRE_EQUAL(copy.n_elem, 0); BOOST_REQUIRE_EQUAL(moveknn.ReferenceSet().n_rows, 3); @@ -590,7 +590,7 @@ BOOST_AUTO_TEST_CASE(MoveTrainTest) arma::mat dataset = arma::randu(3, 200); // Do it in tree mode, and in naive mode. - AllkRANN knn; + KRANN knn; knn.Train(std::move(dataset)); arma::mat distances;