From 6c21b8ca4e48bc81a4f931d8fa7012e519ec746d Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 21 Jul 2020 18:28:45 -0400 Subject: [PATCH 001/253] Use 0 to numClasses - 1, not 1 to numClasses. --- .../negative_log_likelihood_impl.hpp | 10 ++-- src/mlpack/tests/ann_layer_test.cpp | 50 +++++++++---------- src/mlpack/tests/callback_test.cpp | 4 +- .../tests/convolutional_network_test.cpp | 10 ++-- src/mlpack/tests/feedforward_network_test.cpp | 30 +++++++---- src/mlpack/tests/recurrent_network_test.cpp | 14 +++--- 6 files changed, 63 insertions(+), 55 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp b/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp index f9020a582f..2b7dcb9fe3 100644 --- a/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp @@ -35,11 +35,10 @@ NegativeLogLikelihood::Forward( ElemType output = 0; for (size_t i = 0; i < input.n_cols; ++i) { - size_t currentTarget = target(i) - 1; - Log::Assert(currentTarget >= 0 && currentTarget < input.n_rows, + Log::Assert(target(i) >= 0 && target(i) < input.n_rows, "Target class out of range."); - output -= input(currentTarget, i); + output -= input(target(i), i); } return output; @@ -55,11 +54,10 @@ void NegativeLogLikelihood::Backward( output = arma::zeros(input.n_rows, input.n_cols); for (size_t i = 0; i < input.n_cols; ++i) { - size_t currentTarget = target(i) - 1; - Log::Assert(currentTarget >= 0 && currentTarget < input.n_rows, + Log::Assert(target(i) >= 0 && target(i) < input.n_rows, "Target class out of range."); - output(currentTarget, i) = -1; + output(target(i), i) = -1; } } diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 8cd06e56f5..3bba999878 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(GradientAddLayerTest) GradientFunction() { input = arma::randu(10, 1); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -422,7 +422,7 @@ BOOST_AUTO_TEST_CASE(GradientLinearLayerTest) GradientFunction() { input = arma::randu(10, 1); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -498,7 +498,7 @@ BOOST_AUTO_TEST_CASE(GradientNoisyLinearLayerTest) GradientFunction() { input = arma::randu(10, 1); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -602,7 +602,7 @@ BOOST_AUTO_TEST_CASE(GradientLinearNoBiasLayerTest) GradientFunction() { input = arma::randu(10, 1); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -648,7 +648,7 @@ BOOST_AUTO_TEST_CASE(JacobianNegativeLogLikelihoodLayerTest) init.Initialize(input, inputElements, 1); arma::mat target(1, 1); - target(0) = math::RandInt(1, inputElements - 1); + target(0) = math::RandInt(0, inputElements - 2); double error = JacobianPerformanceTest(module, input, target); BOOST_REQUIRE_LE(error, 1e-5); @@ -704,7 +704,7 @@ BOOST_AUTO_TEST_CASE(GradientFlexibleReLULayerTest) GradientFunction() { input = arma::randu(2, 1); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, RandomInitialization>( NegativeLogLikelihood<>(), RandomInitialization(0.1, 0.5)); @@ -883,7 +883,7 @@ BOOST_AUTO_TEST_CASE(LSTMRrhoTest) { const size_t rho = 5; arma::cube input = arma::randu(1, 1, 5); - arma::cube target = arma::ones(1, 1, 5); + arma::cube target = arma::zeros(1, 1, 5); RandomInitialization init(0.5, 0.5); // Create model with user defined rho parameter. @@ -924,7 +924,7 @@ BOOST_AUTO_TEST_CASE(GradientLSTMLayerTest) GradientFunction() { input = arma::randu(1, 1, 5); - target.ones(1, 1, 5); + target.zeros(1, 1, 5); const size_t rho = 5; model = new RNN >(rho); @@ -988,7 +988,7 @@ BOOST_AUTO_TEST_CASE(FastLSTMRrhoTest) { const size_t rho = 5; arma::cube input = arma::randu(1, 1, 5); - arma::cube target = arma::ones(1, 1, 5); + arma::cube target = arma::zeros(1, 1, 5); RandomInitialization init(0.5, 0.5); // Create model with user defined rho parameter. @@ -1029,7 +1029,7 @@ BOOST_AUTO_TEST_CASE(GradientFastLSTMLayerTest) GradientFunction() { input = arma::randu(1, 1, 5); - target = arma::ones(1, 1, 5); + target = arma::zeros(1, 1, 5); const size_t rho = 5; model = new RNN >(rho); @@ -1298,7 +1298,7 @@ BOOST_AUTO_TEST_CASE(GradientGRULayerTest) GradientFunction() { input = arma::randu(1, 1, 5); - target = arma::ones(1, 1, 5); + target = arma::zeros(1, 1, 5); const size_t rho = 5; model = new RNN >(rho); @@ -1537,7 +1537,7 @@ BOOST_AUTO_TEST_CASE(GradientConcatLayerTest) GradientFunction() { input = arma::randu(10, 1); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -1606,7 +1606,7 @@ BOOST_AUTO_TEST_CASE(GradientConcatenateLayerTest) GradientFunction() { input = arma::randu(10, 1); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -1961,7 +1961,7 @@ BOOST_AUTO_TEST_CASE(GradientBatchNormTest) { input = arma::randn(32, 2048); arma::mat target; - target.ones(1, 2048); + target.zeros(1, 2048); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -2037,7 +2037,7 @@ BOOST_AUTO_TEST_CASE(GradientVirtualBatchNormTest) input = arma::randn(5, 256); arma::mat referenceBatch = arma::mat(input.memptr(), input.n_rows, 16); arma::mat target; - target.ones(1, 256); + target.zeros(1, 256); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -2099,7 +2099,7 @@ BOOST_AUTO_TEST_CASE(MiniBatchDiscriminationTest) { input = arma::randn(5, 4); arma::mat target; - target.ones(1, 4); + target.zeros(1, 4); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -2278,7 +2278,7 @@ BOOST_AUTO_TEST_CASE(GradientTransposedConvolutionLayerTest) GradientFunction() { input = arma::linspace(0, 35, 36); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, RandomInitialization>(); model->Predictors() = input; @@ -2395,7 +2395,7 @@ BOOST_AUTO_TEST_CASE(GradientAtrousConvolutionLayerTest) GradientFunction() { input = arma::linspace(0, 35, 36); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, RandomInitialization>(); model->Predictors() = input; @@ -2578,7 +2578,7 @@ BOOST_AUTO_TEST_CASE(GradientLayerNormTest) { input = arma::randn(10, 256); arma::mat target; - target.ones(1, 256); + target.zeros(1, 256); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -2899,7 +2899,7 @@ BOOST_AUTO_TEST_CASE(GradientReparametrizationLayerTest) GradientFunction() { input = arma::randu(10, 1); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -2943,7 +2943,7 @@ BOOST_AUTO_TEST_CASE(GradientReparametrizationLayerBetaTest) GradientFunction() { input = arma::randu(10, 2); - target = arma::mat("1 1"); + target = arma::mat("0 0"); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -3099,7 +3099,7 @@ BOOST_AUTO_TEST_CASE(GradientHighwayLayerTest) GradientFunction() { input = arma::randu(5, 1); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -3151,7 +3151,7 @@ BOOST_AUTO_TEST_CASE(GradientSequentialLayerTest) GradientFunction() { input = arma::randu(10, 1); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -3202,7 +3202,7 @@ BOOST_AUTO_TEST_CASE(GradientWeightNormLayerTest) GradientFunction() { input = arma::randu(10, 1); - target = arma::mat("1"); + target = arma::mat("0"); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; @@ -4037,7 +4037,7 @@ BOOST_AUTO_TEST_CASE(GradientBatchNormWithMiniBatchesTest) { input = arma::randn(16, 1024); arma::mat target; - target.ones(1, 1024); + target.zeros(1, 1024); model = new FFN, NguyenWidrowInitialization>(); model->Predictors() = input; diff --git a/src/mlpack/tests/callback_test.cpp b/src/mlpack/tests/callback_test.cpp index a62ede95a8..6483a11890 100644 --- a/src/mlpack/tests/callback_test.cpp +++ b/src/mlpack/tests/callback_test.cpp @@ -92,7 +92,7 @@ BOOST_AUTO_TEST_CASE(RNNCallbackTest) { const size_t rho = 5; arma::cube input = arma::randu(1, 1, 5); - arma::cube target = arma::ones(1, 1, 5); + arma::cube target = arma::zeros(1, 1, 5); RandomInitialization init(0.5, 0.5); // Create model with user defined rho parameter. @@ -118,7 +118,7 @@ BOOST_AUTO_TEST_CASE(RNNWithOptimizerCallbackTest) { const size_t rho = 5; arma::cube input = arma::randu(1, 1, 5); - arma::cube target = arma::ones(1, 1, 5); + arma::cube target = arma::zeros(1, 1, 5); RandomInitialization init(0.5, 0.5); // Create model with user defined rho parameter. diff --git a/src/mlpack/tests/convolutional_network_test.cpp b/src/mlpack/tests/convolutional_network_test.cpp index 39a7e161c3..c266e2b28b 100644 --- a/src/mlpack/tests/convolutional_network_test.cpp +++ b/src/mlpack/tests/convolutional_network_test.cpp @@ -47,13 +47,13 @@ BOOST_AUTO_TEST_CASE(VanillaNetworkTest) { if (i < nPoints / 2) { - // Assign label "1" to all samples with digit = 4 - Y(i) = 1; + // Assign label "0" to all samples with digit = 4 + Y(i) = 0; } else { - // Assign label "2" to all samples with digit = 9 - Y(i) = 2; + // Assign label "1" to all samples with digit = 9 + Y(i) = 1; } } @@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(VanillaNetworkTest) for (size_t i = 0; i < predictionTemp.n_cols; ++i) { prediction(i) = arma::as_scalar(arma::find( - arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1; + arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)); } size_t correct = arma::accu(prediction == Y); diff --git a/src/mlpack/tests/feedforward_network_test.cpp b/src/mlpack/tests/feedforward_network_test.cpp index 47842204e6..c853962f10 100644 --- a/src/mlpack/tests/feedforward_network_test.cpp +++ b/src/mlpack/tests/feedforward_network_test.cpp @@ -52,7 +52,7 @@ void TestNetwork(ModelType& model, for (size_t i = 0; i < predictionTemp.n_cols; ++i) { prediction(i) = arma::as_scalar(arma::find( - arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1; + arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)); } size_t correct = arma::accu(prediction == testLabels); @@ -71,12 +71,14 @@ BOOST_AUTO_TEST_CASE(VanillaNetworkTest) arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); + trainLabels -= 1; // Labels should be from 0 to numClasses - 1. arma::mat testData; data::Load("thyroid_test.csv", testData, true); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); + testLabels -= 1; // Labels should be from 0 to numClasses - 1. /* * Construct a feed forward network with trainData.n_rows input nodes, @@ -120,7 +122,6 @@ BOOST_AUTO_TEST_CASE(VanillaNetworkTest) arma::mat labels = arma::zeros(1, dataset.n_cols); labels.submat(0, labels.n_cols / 2, 0, labels.n_cols - 1).fill(1); - labels += 1; FFN > model1; model1.Add >(dataset.n_rows, 10); @@ -142,7 +143,6 @@ BOOST_AUTO_TEST_CASE(ForwardBackwardTest) arma::mat labels = arma::zeros(1, dataset.n_cols); labels.submat(0, labels.n_cols / 2, 0, labels.n_cols - 1).fill(1); - labels += 1; FFN > model; model.Add >(dataset.n_rows, 50); @@ -189,7 +189,7 @@ BOOST_AUTO_TEST_CASE(ForwardBackwardTest) for (size_t i = 0; i < currentResuls.n_cols; ++i) { prediction(i) = arma::as_scalar(arma::find( - arma::max(currentResuls.col(i)) == currentResuls.col(i), 1)) + 1; + arma::max(currentResuls.col(i)) == currentResuls.col(i), 1)); } size_t correct = arma::accu(prediction == currentLabels); @@ -218,12 +218,14 @@ BOOST_AUTO_TEST_CASE(DropoutNetworkTest) arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); + trainLabels -= 1; // Labels should be from 0 to numClasses - 1. arma::mat testData; data::Load("thyroid_test.csv", testData, true); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); + testLabels -= 1; // Labels should be from 0 to numClasses - 1. /* * Construct a feed forward network with trainData.n_rows input nodes, @@ -269,7 +271,6 @@ BOOST_AUTO_TEST_CASE(DropoutNetworkTest) arma::mat labels = arma::zeros(1, dataset.n_cols); labels.submat(0, labels.n_cols / 2, 0, labels.n_cols - 1).fill(1); - labels += 1; FFN > model1; model1.Add >(dataset.n_rows, 10); @@ -295,7 +296,6 @@ BOOST_AUTO_TEST_CASE(HighwayNetworkTest) arma::mat labels = arma::zeros(1, dataset.n_cols); labels.submat(0, labels.n_cols / 2, 0, labels.n_cols - 1).fill(1); - labels += 1; FFN > model; model.Add >(dataset.n_rows, 10); @@ -319,12 +319,14 @@ BOOST_AUTO_TEST_CASE(DropConnectNetworkTest) arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); + trainLabels -= 1; // The range should be between 0 and numClasses - 1. arma::mat testData; data::Load("thyroid_test.csv", testData, true); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); + testLabels -= 1; // The range should be between 0 and numClasses - 1. /* * Construct a feed forward network with trainData.n_rows input nodes, @@ -370,7 +372,6 @@ BOOST_AUTO_TEST_CASE(DropConnectNetworkTest) arma::mat labels = arma::zeros(1, dataset.n_cols); labels.submat(0, labels.n_cols / 2, 0, labels.n_cols - 1).fill(1); - labels += 1; FFN > model1; model1.Add >(dataset.n_rows, 10); @@ -408,12 +409,14 @@ BOOST_AUTO_TEST_CASE(SerializationTest) arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); + trainLabels -= 1; // The labels should be between 0 and numClasses - 1. arma::mat testData; data::Load("thyroid_test.csv", testData, true); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); + testLabels -= 1; // The labels should be between 0 and numClasses - 1. // Vanilla neural net with logistic activation function. // Because 92% of the patients are not hyperthyroid the neural @@ -457,12 +460,14 @@ BOOST_AUTO_TEST_CASE(CustomLayerTest) arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); + trainLabels -= 1; // The labels should be between 0 and numClasses - 1. arma::mat testData; data::Load("thyroid_test.csv", testData, true); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); + testLabels -= 1; // The labels should be between 0 and numClasses - 1. FFN, RandomInitialization, CustomLayer<> > model; model.Add >(trainData.n_rows, 8); @@ -536,12 +541,14 @@ BOOST_AUTO_TEST_CASE(FFNTrainReturnObjective) arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); + trainLabels -= 1; // The labels should be between 0 and numClasses. arma::mat testData; data::Load("thyroid_test.csv", testData, true); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); + testLabels -= 1; // The labels should be between 0 and numClasses. // Vanilla neural net with logistic activation function. // Because 92% of the patients are not hyperthyroid the neural @@ -606,12 +613,14 @@ BOOST_AUTO_TEST_CASE(OptimizerTest) arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); + trainLabels -= 1; // The labels should be between 0 and numClasses. arma::mat testData; data::Load("thyroid_test.csv", testData, true); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); + testLabels -= 1; // The labels should be between 0 and numClasses. FFN, RandomInitialization, CustomLayer<> > model; model.Add >(trainData.n_rows, 8); @@ -634,11 +643,12 @@ BOOST_AUTO_TEST_CASE(RBFNetworkTest) arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); + trainLabels -= 1; // The labels should be between 0 and numClasses. arma::mat trainLabels1 = arma::zeros(3, trainData.n_cols); for (size_t i = 0; i < trainData.n_cols; i++) { - trainLabels1.col(i).row((trainLabels(i) - 1)) = 1; + trainLabels1.col(i).row(trainLabels(i)) = 1; } arma::mat testData; @@ -646,6 +656,7 @@ BOOST_AUTO_TEST_CASE(RBFNetworkTest) arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); + testLabels -= 1; // The labels should be between 0 and numClasses. /* * Construct a feed forward network with trainData.n_rows input nodes, @@ -681,7 +692,7 @@ BOOST_AUTO_TEST_CASE(RBFNetworkTest) } arma::mat labels = arma::zeros(1, dataset.n_cols); - labels.submat(0, labels.n_cols / 2, 0, labels.n_cols - 1).fill(1); + labels.submat(0, labels.n_cols / 2, 0, labels.n_cols - 1).fill(0); arma::mat labels1 = arma::zeros(2, dataset.n_cols); @@ -689,7 +700,6 @@ BOOST_AUTO_TEST_CASE(RBFNetworkTest) { labels1.col(i).row(labels(i)) = 1; } - labels += 1; arma::mat centroids1; arma::Row assignments; diff --git a/src/mlpack/tests/recurrent_network_test.cpp b/src/mlpack/tests/recurrent_network_test.cpp index 1bef406e26..4bd9fa25e1 100644 --- a/src/mlpack/tests/recurrent_network_test.cpp +++ b/src/mlpack/tests/recurrent_network_test.cpp @@ -93,7 +93,7 @@ BOOST_AUTO_TEST_CASE(SequenceClassificationBRNNTest) for (size_t i = 0; i < labelsTemp.n_cols; ++i) { const int value = arma::as_scalar(arma::find( - arma::max(labelsTemp.col(i)) == labelsTemp.col(i), 1)) + 1; + arma::max(labelsTemp.col(i)) == labelsTemp.col(i), 1)); labels.tube(0, i).fill(value); } @@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE(SequenceClassificationTest) for (size_t i = 0; i < labelsTemp.n_cols; ++i) { const int value = arma::as_scalar(arma::find( - arma::max(labelsTemp.col(i)) == labelsTemp.col(i), 1)) + 1; + arma::max(labelsTemp.col(i)) == labelsTemp.col(i), 1)); labels.tube(0, i).fill(value); } @@ -212,10 +212,10 @@ BOOST_AUTO_TEST_CASE(SequenceClassificationTest) { const int predictionValue = arma::as_scalar(arma::find( arma::max(prediction.slice(rho - 1).col(i)) == - prediction.slice(rho - 1).col(i), 1) + 1); + prediction.slice(rho - 1).col(i), 1)); const int targetValue = arma::as_scalar(arma::find( - arma::max(labelsTemp.col(i)) == labelsTemp.col(i), 1)) + 1; + arma::max(labelsTemp.col(i)) == labelsTemp.col(i), 1)); if (predictionValue == targetValue) { @@ -1452,15 +1452,15 @@ BOOST_AUTO_TEST_CASE(LargeRhoValueRnnTest) { const auto strLen = strlen(line); // Responses for NegativeLogLikelihood should be - // non-one-hot-encoded class IDs (from 1 to num_classes). + // non-one-hot-encoded class IDs (from 0 to num_classes - 1). MatType result(1, 1, strLen, arma::fill::zeros); // The response is the *next* letter in the sequence. for (size_t i = 0; i < strLen - 1; ++i) { - result.at(0, 0, i) = static_cast(line[i + 1]) + 1.0; + result.at(0, 0, i) = static_cast(line[i + 1]); } // The final response is empty, so we set it to class 0. - result.at(0, 0, strLen - 1) = 1.0; + result.at(0, 0, strLen - 1) = 0.0; return result; }; From c84a4e510b98a17d8883b928871f315cb30b4cd7 Mon Sep 17 00:00:00 2001 From: iamshnoo Date: Tue, 11 Aug 2020 01:01:45 +0530 Subject: [PATCH 002/253] Pixel Shuffle layer. Commit 1. --- src/mlpack/methods/ann/layer/CMakeLists.txt | 2 + src/mlpack/methods/ann/layer/layer.hpp | 1 + src/mlpack/methods/ann/layer/layer_types.hpp | 2 + .../methods/ann/layer/pixel_shuffle.hpp | 179 ++++++++++++++++++ .../methods/ann/layer/pixel_shuffle_impl.hpp | 144 ++++++++++++++ src/mlpack/tests/ann_layer_test.cpp | 74 ++++++++ 6 files changed, 402 insertions(+) create mode 100644 src/mlpack/methods/ann/layer/pixel_shuffle.hpp create mode 100644 src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp diff --git a/src/mlpack/methods/ann/layer/CMakeLists.txt b/src/mlpack/methods/ann/layer/CMakeLists.txt index c3ae086c87..b4034f580c 100644 --- a/src/mlpack/methods/ann/layer/CMakeLists.txt +++ b/src/mlpack/methods/ann/layer/CMakeLists.txt @@ -79,6 +79,8 @@ set(SOURCES noisylinear_impl.hpp parametric_relu.hpp parametric_relu_impl.hpp + pixel_shuffle.hpp + pixel_shuffle_impl.hpp recurrent.hpp recurrent_impl.hpp recurrent_attention.hpp diff --git a/src/mlpack/methods/ann/layer/layer.hpp b/src/mlpack/methods/ann/layer/layer.hpp index 8e8e00691e..6673411616 100644 --- a/src/mlpack/methods/ann/layer/layer.hpp +++ b/src/mlpack/methods/ann/layer/layer.hpp @@ -55,6 +55,7 @@ #include "noisylinear.hpp" #include "padding.hpp" #include "parametric_relu.hpp" +#include "pixel_shuffle.hpp" #include "recurrent_attention.hpp" #include "recurrent.hpp" #include "reinforce_normal.hpp" diff --git a/src/mlpack/methods/ann/layer/layer_types.hpp b/src/mlpack/methods/ann/layer/layer_types.hpp index 0f52a24df7..9e8dd0ce36 100644 --- a/src/mlpack/methods/ann/layer/layer_types.hpp +++ b/src/mlpack/methods/ann/layer/layer_types.hpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -272,6 +273,7 @@ using LayerTypes = boost::variant< NoisyLinear*, Padding*, PReLU*, + PixelShuffle*, Softmax*, TransposedConvolution, NaiveConvolution, diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle.hpp new file mode 100644 index 0000000000..27dea9ba38 --- /dev/null +++ b/src/mlpack/methods/ann/layer/pixel_shuffle.hpp @@ -0,0 +1,179 @@ +/** + * @file methods/ann/layer/pixel_shuffle.hpp + * @author Anjishnu Mukherjee + * + * Definition of the PixelShuffle class. + * + * 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. + */ +#ifndef MLPACK_METHODS_ANN_LAYER_PIXEL_SHUFFLE_HPP +#define MLPACK_METHODS_ANN_LAYER_PIXEL_SHUFFLE_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * Implementation of the PixelShuffle layer. + * + * For more information, refer to the following paper, + * + * @code + * @article{Shi16, + * author = {Wenzhe Shi, Jose Caballero,Ferenc Huszár, Johannes Totz, + * Andrew P. Aitken, Rob Bishop, Daniel Rueckert, Zehan Wang}, + * title = {Real-Time Single Image and Video Super-Resolution Using an + * Efficient Sub-Pixel Convolutional Neural Network}, + * journal = {CoRR}, + * volume = {abs/1609.05158}, + * year = {2016}, + * url = {https://arxiv.org/abs/1609.05158}, + * eprint = {1609.05158}, + * } + * @endcode + * + * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + * @tparam OutputDataType Type of the output data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + */ +template < + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +class PixelShuffle +{ + public: + //! Create the PixelShuffle object. + PixelShuffle(); + /** + * Create the PixelShuffle object using the specified parameters. + * The number of input channels should be an integral multiple of the square + * of the upscale factor. + * + * @param upscaleFactor The scaling factor for Pixel Shuffle. + * @param height The height of each input image. + * @param width The width of each input image. + * @param size The number of channels of each input image. + */ + PixelShuffle( size_t upscaleFactor, + size_t height, + size_t width, + size_t size); + + /** + * Ordinary feed forward pass of the PixelShuffle layer. + * + * @param input Input data used for evaluating the specified function. + * @param output Resulting output activation. + */ + template + void Forward(const arma::Mat& input, arma::Mat& output); + + /** + * Ordinary feed backward pass of the PixelShuffle layer. + * + * @param * (input) The propagated input activation. + * @param gy The backpropagated error. + * @param g The calculated gradient. + */ + template + void Backward(const arma::Mat& input, + const arma::Mat& gy, + arma::Mat& g); + + //! Get the output parameter. + OutputDataType const& OutputParameter() const { return outputParameter; } + //! Modify the output parameter. + OutputDataType& OutputParameter() { return outputParameter; } + + //! Get the delta. + OutputDataType const& Delta() const { return delta; } + //! Modify the delta. + OutputDataType& Delta() { return delta; } + + //! Get the upscale factor. + size_t UpscaleFactor() const { return upscaleFactor; } + + //! Modify the upscale factor. + size_t& UpscaleFactor() { return upscaleFactor; } + + //! Get the input image height. + size_t InputHeight() const { return height; } + + //! Modify the input image height. + size_t& InputHeight() { return height; } + + //! Get the input image width. + size_t InputWidth() const { return width; } + + //! Modify the input image width. + size_t& InputWidth() { return width; } + + //! Get the number of input channels. + size_t InputChannels() const { return size; } + + //! Modify the number of input channels. + size_t& InputChannels() { return size; } + + //! Get the output image height. + size_t OutputHeight() const { return outputHeight; } + + //! Get the output image width. + size_t OutputWidth() const { return outputWidth; } + + //! Get the number of output channels. + size_t OutputChannels() const { return sizeOut; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const unsigned int /* version */); + + private: + //! Locally-stored delta object. + OutputDataType delta; + + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! The scaling factor for Pixel Shuffle. + size_t upscaleFactor; + + //! The height of each input image. + size_t height; + + //! The width of each input image. + size_t width; + + //! The number of channels of each input image. + size_t size; + + //! The number of images in the batch. + size_t batchSize; + + //! The height of each output image. + size_t outputHeight; + + //! The width of each output image. + size_t outputWidth; + + //! The number of channels of each output image. + size_t sizeOut; + + //! A boolean used to do some internal calculations once initially. + bool reset; +}; // class PixelShuffle + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "pixel_shuffle_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp new file mode 100644 index 0000000000..cfbd4287b9 --- /dev/null +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -0,0 +1,144 @@ +/** + * @file methods/ann/layer/pixel_shuffle_impl.hpp + * @author Anjishnu Mukherjee + * + * Implementation of the PixelShuffle class. + * + * 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. + */ +#ifndef MLPACK_METHODS_ANN_LAYER_PIXEL_SHUFFLE_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_PIXEL_SHUFFLE_IMPL_HPP + +// In case it hasn't yet been included. +#include "pixel_shuffle.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +PixelShuffle::PixelShuffle() : + upscaleFactor(0), + height(0), + width(0), + size(0), + reset(false) +{ + // Nothing to do here. +} + +template +PixelShuffle::PixelShuffle( + size_t upscaleFactor, + size_t height, + size_t width, + size_t size) : + upscaleFactor(upscaleFactor), + height(height), + width(width), + size(size), + reset(false) +{ + // Nothing to do here. +} + +template +template +void PixelShuffle::Forward( + const arma::Mat& input, arma::Mat& output) +{ + if(!reset) + { + batchSize = input.n_cols; + sizeOut = size / std::pow(upscaleFactor, 2); + outputHeight = height * upscaleFactor; + outputWidth = width * upscaleFactor; + reset = true; + } + output.zeros(outputHeight * outputWidth * sizeOut, batchSize); + for(size_t n = 0; n < batchSize; n++) + { + arma::mat inputImage = input.col(n); + arma::mat outputImage = output.col(n); + arma::cube inputTemp(const_cast(inputImage).memptr(), height, + width, size, false, false); + arma::cube outputTemp(const_cast(outputImage).memptr(), + outputHeight, outputWidth, sizeOut, false, false); + + for (size_t c = 0; c < sizeOut ; c++) + { + for (size_t h = 0; h < outputHeight; h++) + { + for (size_t w = 0; w < outputWidth; w++) + { + size_t height_index = h / upscaleFactor; + size_t width_index = w / upscaleFactor; + size_t channel_index = (upscaleFactor * (h % upscaleFactor)) + + (w % upscaleFactor) + (c * std::pow(upscaleFactor, 2)); + outputTemp(w, h, c) = inputTemp(width_index, height_index, + channel_index); + } + } + } + output.col(n) = outputImage; + } +} + +template +template +void PixelShuffle::Backward( + const arma::Mat& input, const arma::Mat& gy, arma::Mat& g) +{ + g.zeros(arma::size(input)); + for(size_t n = 0; n < batchSize; n++) + { + arma::mat gyImage = gy.col(n); + arma::mat gImage = g.col(n); + arma::cube gyTemp(const_cast(gyImage).memptr(), outputHeight, + outputWidth, sizeOut, false, false); + arma::cube gTemp(const_cast(gImage).memptr(), height, width, + size, false, false); + + for (size_t c = 0; c < sizeOut ; c++) + { + for (size_t h = 0; h < outputHeight; h++) + { + for (size_t w = 0; w < outputWidth; w++) + { + size_t height_index = h / upscaleFactor; + size_t width_index = w / upscaleFactor; + size_t channel_index = (upscaleFactor * (h % upscaleFactor)) + + (w % upscaleFactor) + (c * std::pow(upscaleFactor, 2)); + gTemp(width_index, height_index, channel_index) = gyTemp(w, h, c); + } + } + } + + g.col(n) = gImage; + } +} + +template +template +void PixelShuffle::serialize( + Archive& ar, + const unsigned int /* version */) +{ + ar & BOOST_SERIALIZATION_NVP(delta); + ar & BOOST_SERIALIZATION_NVP(outputParameter); + ar & BOOST_SERIALIZATION_NVP(upscaleFactor); + ar & BOOST_SERIALIZATION_NVP(height); + ar & BOOST_SERIALIZATION_NVP(width); + ar & BOOST_SERIALIZATION_NVP(size); + ar & BOOST_SERIALIZATION_NVP(batchSize); + ar & BOOST_SERIALIZATION_NVP(outputHeight); + ar & BOOST_SERIALIZATION_NVP(outputWidth); + ar & BOOST_SERIALIZATION_NVP(sizeOut); +} + +} // namespace ann +} // namespace mlpack + +#endif diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 29e16273b8..38fec13c05 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -4186,3 +4186,77 @@ TEST_CASE("BatchNormDeterministicTest", "[ANNLayerTest]") // The model should switch to training mode for predicting. REQUIRE(boost::get*>(module.Model()[0])->Deterministic() == 0); } + +/** + * Simple Test for PixelShuffle layer. + */ +TEST_CASE("PixelShuffleLayerTest", "[ANNLayerTest]") +{ + arma::mat input, output, gy, g, outputExpected, gExpected; + PixelShuffle<> module(2, 2, 2, 4); + + // Input is a batch of 2 images, each of size (2,2) and having 4 channels. + input << 1 << 3 << 2 << 4 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 + << 0 << 0 << arma::endr << 5 << 7 << 6 << 8 << 0 << 0 << 0 << 0 << 0 << 0 + << 0 << 0 << 0 << 0 << 0 << 0 << arma::endr; + + gy << 1 << 5 << 9 << 13 << 2 << 6 << 10 << 14 << 3 << 7 << 11 << 15 << 4 << 8 + << 12 << 16 << arma::endr << 17 << 21 << 25 << 29 << 18 << 22 << 26 << 30 + << 19 << 23 << 27 << 31 << 20 << 24 << 28 << 32 << arma::endr; + + // Calculated using torch.nn.PixelShuffle(). + outputExpected << 1 << 0 << 3 << 0 << 0 << 0 << 0 << 0 << 2 << 0 << 4 << 0 + << 0 << 0 << 0 << 0 << arma::endr << 5 << 0 << 7 << 0 << 0 << 0 << 0 << 0 + << 6 << 0 << 8 << 0 << 0 << 0 << 0 << 0 << arma::endr; + gExpected << 1 << 9 << 3 << 11 << 5 << 13 << 7 << 15 << 2 << 10 << 4 << 12 + << 6 << 14 << 8 << 16 << arma::endr << 17 << 25 << 19 << 27 << 21 << 29 + << 23 << 31 << 18 << 26 << 20 << 28 << 22 << 30 << 24 << 32 << arma::endr; + + input = input.t(); + outputExpected = outputExpected.t(); + gy = gy.t(); + gExpected = gExpected.t(); + + // Check the Forward pass of the layer. + module.Forward(input, output); + CheckMatrices(output, outputExpected); + + // Check the Backward pass of the layer. + module.Backward(input, gy, g); + CheckMatrices(g, gExpected); +} + +/** + * Test that the function that can access the parameters of the + * PixelShuffle layer works. + */ +TEST_CASE("PixelShuffleLayerParametersTest", "[ANNLayerTest]") +{ + // Create the layer using the empty constructor. + PixelShuffle<> layer; + + // Set the different input parameters of the layer. + layer.UpscaleFactor() = 2; + layer.InputHeight() = 2; + layer.InputWidth() = 2; + layer.InputChannels() = 4; + + // Make sure we can get the parameters successfully. + REQUIRE(layer.UpscaleFactor() == 2); + REQUIRE(layer.InputHeight() == 2); + REQUIRE(layer.InputWidth() == 2); + REQUIRE(layer.InputChannels() == 4); + + arma::mat input, output; + // Input is a batch of 2 images, each of size (2,2) and having 4 channels. + input << 1 << 3 << 2 << 4 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 + << 0 << 0 << arma::endr << 5 << 7 << 6 << 8 << 0 << 0 << 0 << 0 << 0 << 0 + << 0 << 0 << 0 << 0 << 0 << 0 << arma::endr; + input = input.t(); + layer.Forward(input, output); + + // Check whether output parameters are returned correctly. + REQUIRE(layer.OutputHeight() == 4 ); + REQUIRE(layer.OutputWidth() == 4); + REQUIRE(layer.OutputChannels() == 1); +} From 64dd26145a1b1c02593c105a10e2622d1aa33634 Mon Sep 17 00:00:00 2001 From: iamshnoo Date: Fri, 14 Aug 2020 19:08:50 +0530 Subject: [PATCH 003/253] Fix style issues. --- src/mlpack/methods/ann/layer/pixel_shuffle.hpp | 10 +++++----- src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle.hpp index 27dea9ba38..2fda7cf5f4 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle.hpp @@ -60,10 +60,10 @@ class PixelShuffle * @param width The width of each input image. * @param size The number of channels of each input image. */ - PixelShuffle( size_t upscaleFactor, - size_t height, - size_t width, - size_t size); + PixelShuffle(size_t upscaleFactor, + size_t height, + size_t width, + size_t size); /** * Ordinary feed forward pass of the PixelShuffle layer. @@ -77,7 +77,7 @@ class PixelShuffle /** * Ordinary feed backward pass of the PixelShuffle layer. * - * @param * (input) The propagated input activation. + * @param input The propagated input activation. * @param gy The backpropagated error. * @param g The calculated gradient. */ diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp index cfbd4287b9..3ca2852074 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -49,7 +49,7 @@ template void PixelShuffle::Forward( const arma::Mat& input, arma::Mat& output) { - if(!reset) + if (!reset) { batchSize = input.n_cols; sizeOut = size / std::pow(upscaleFactor, 2); @@ -58,7 +58,7 @@ void PixelShuffle::Forward( reset = true; } output.zeros(outputHeight * outputWidth * sizeOut, batchSize); - for(size_t n = 0; n < batchSize; n++) + for (size_t n = 0; n < batchSize; n++) { arma::mat inputImage = input.col(n); arma::mat outputImage = output.col(n); @@ -92,7 +92,7 @@ void PixelShuffle::Backward( const arma::Mat& input, const arma::Mat& gy, arma::Mat& g) { g.zeros(arma::size(input)); - for(size_t n = 0; n < batchSize; n++) + for (size_t n = 0; n < batchSize; n++) { arma::mat gyImage = gy.col(n); arma::mat gImage = g.col(n); From 5da525cde653ee3ed2bd5c4c979bdacdbd9b7959 Mon Sep 17 00:00:00 2001 From: iamshnoo Date: Fri, 14 Aug 2020 23:49:48 +0530 Subject: [PATCH 004/253] Fix consistency issue for constructor format. --- src/mlpack/methods/ann/layer/pixel_shuffle.hpp | 8 ++++---- src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle.hpp index 2fda7cf5f4..c62b0f0ecb 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle.hpp @@ -60,10 +60,10 @@ class PixelShuffle * @param width The width of each input image. * @param size The number of channels of each input image. */ - PixelShuffle(size_t upscaleFactor, - size_t height, - size_t width, - size_t size); + PixelShuffle(const size_t upscaleFactor, + const size_t height, + const size_t width, + const size_t size); /** * Ordinary feed forward pass of the PixelShuffle layer. diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp index 3ca2852074..d65a0c456d 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -31,10 +31,10 @@ PixelShuffle::PixelShuffle() : template PixelShuffle::PixelShuffle( - size_t upscaleFactor, - size_t height, - size_t width, - size_t size) : + const size_t upscaleFactor, + const size_t height, + const size_t width, + const size_t size) : upscaleFactor(upscaleFactor), height(height), width(width), From 438cc009898dad31326636af9f3d47d908ced4af Mon Sep 17 00:00:00 2001 From: iamshnoo Date: Tue, 25 Aug 2020 11:47:28 +0530 Subject: [PATCH 005/253] Use suggestions from code review. --- .../methods/ann/layer/pixel_shuffle_impl.hpp | 1 - src/mlpack/tests/ann_layer_test.cpp | 56 ++++++++++++++----- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp index d65a0c456d..31d137eb59 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -115,7 +115,6 @@ void PixelShuffle::Backward( } } } - g.col(n) = gImage; } } diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index c3c0b11edc..a1ed47db97 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -4302,38 +4302,64 @@ TEST_CASE("TransposedConvolutionWeightInitializationTest", "[ANNLayerTest]") */ TEST_CASE("PixelShuffleLayerTest", "[ANNLayerTest]") { - arma::mat input, output, gy, g, outputExpected, gExpected; - PixelShuffle<> module(2, 2, 2, 4); + arma::mat input1, output1, gy1, g1, outputExpected1, gExpected1; + arma::mat input2, output2, gy2, g2, outputExpected2, gExpected2; + PixelShuffle<> module1(2, 2, 2, 4); + PixelShuffle<> module2(2, 2, 2, 4); + + // Input is a single image, of size (2,2) and having 4 channels. + input1 << 1 << 3 << 2 << 4 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 + << 0 << 0 << arma::endr; + gy1 << 1 << 5 << 9 << 13 << 2 << 6 << 10 << 14 << 3 << 7 << 11 << 15 << 4 << 8 + << 12 << 16 << arma::endr; + + // Calculated using torch.nn.PixelShuffle(). + outputExpected1 << 1 << 0 << 3 << 0 << 0 << 0 << 0 << 0 << 2 << 0 << 4 << 0 + << 0 << 0 << 0 << 0 << arma::endr; + gExpected1 << 1 << 9 << 3 << 11 << 5 << 13 << 7 << 15 << 2 << 10 << 4 << 12 + << 6 << 14 << 8 << 16 << arma::endr; + + input1 = input1.t(); + outputExpected1 = outputExpected1.t(); + gy1 = gy1.t(); + gExpected1 = gExpected1.t(); + + // Check the Forward pass of the layer. + module1.Forward(input1, output1); + CheckMatrices(output1, outputExpected1); + + // Check the Backward pass of the layer. + module1.Backward(input1, gy1, g1); + CheckMatrices(g1, gExpected1); // Input is a batch of 2 images, each of size (2,2) and having 4 channels. - input << 1 << 3 << 2 << 4 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 + input2 << 1 << 3 << 2 << 4 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << arma::endr << 5 << 7 << 6 << 8 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << arma::endr; - - gy << 1 << 5 << 9 << 13 << 2 << 6 << 10 << 14 << 3 << 7 << 11 << 15 << 4 << 8 + gy2 << 1 << 5 << 9 << 13 << 2 << 6 << 10 << 14 << 3 << 7 << 11 << 15 << 4 << 8 << 12 << 16 << arma::endr << 17 << 21 << 25 << 29 << 18 << 22 << 26 << 30 << 19 << 23 << 27 << 31 << 20 << 24 << 28 << 32 << arma::endr; // Calculated using torch.nn.PixelShuffle(). - outputExpected << 1 << 0 << 3 << 0 << 0 << 0 << 0 << 0 << 2 << 0 << 4 << 0 + outputExpected2 << 1 << 0 << 3 << 0 << 0 << 0 << 0 << 0 << 2 << 0 << 4 << 0 << 0 << 0 << 0 << 0 << arma::endr << 5 << 0 << 7 << 0 << 0 << 0 << 0 << 0 << 6 << 0 << 8 << 0 << 0 << 0 << 0 << 0 << arma::endr; - gExpected << 1 << 9 << 3 << 11 << 5 << 13 << 7 << 15 << 2 << 10 << 4 << 12 + gExpected2 << 1 << 9 << 3 << 11 << 5 << 13 << 7 << 15 << 2 << 10 << 4 << 12 << 6 << 14 << 8 << 16 << arma::endr << 17 << 25 << 19 << 27 << 21 << 29 << 23 << 31 << 18 << 26 << 20 << 28 << 22 << 30 << 24 << 32 << arma::endr; - input = input.t(); - outputExpected = outputExpected.t(); - gy = gy.t(); - gExpected = gExpected.t(); + input2 = input2.t(); + outputExpected2 = outputExpected2.t(); + gy2 = gy2.t(); + gExpected2 = gExpected2.t(); // Check the Forward pass of the layer. - module.Forward(input, output); - CheckMatrices(output, outputExpected); + module2.Forward(input2, output2); + CheckMatrices(output2, outputExpected2); // Check the Backward pass of the layer. - module.Backward(input, gy, g); - CheckMatrices(g, gExpected); + module2.Backward(input2, gy2, g2); + CheckMatrices(g2, gExpected2); } /** From c6cd6b860c3e56c76c2df9abe0bfe17c3bf7d1e1 Mon Sep 17 00:00:00 2001 From: iamshnoo Date: Tue, 25 Aug 2020 16:25:52 +0530 Subject: [PATCH 006/253] FIx static analysis issue. --- src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp index 31d137eb59..796ee54071 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -24,6 +24,10 @@ PixelShuffle::PixelShuffle() : height(0), width(0), size(0), + batchSize(0), + outputHeight(0), + outputWidth(0), + sizeOut(0), reset(false) { // Nothing to do here. @@ -39,6 +43,10 @@ PixelShuffle::PixelShuffle( height(height), width(width), size(size), + batchSize(0), + outputHeight(0), + outputWidth(0), + sizeOut(0), reset(false) { // Nothing to do here. From cbb151000528700e9c57933030fc71e4c0803b70 Mon Sep 17 00:00:00 2001 From: iamshnoo Date: Wed, 26 Aug 2020 09:46:37 +0530 Subject: [PATCH 007/253] Update HISTORY.md for Pixel Shuffle layer. --- HISTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index c04b2aeca1..ba5bb0b194 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,7 @@ ### mlpack ?.?.? ###### ????-??-?? + * Added Pixel Shuffle layer (#2563). + * Force CMake to show error when it didn't find Python/modules (#2568). * Refactor `ProgramInfo()` to separate out all the different From 123635533c9daa596651e11ade8093df6f18df8f Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Mon, 30 Nov 2020 19:53:13 +0530 Subject: [PATCH 008/253] Added template to data::Split --- src/mlpack/core/data/split_data.hpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 42b7e03b3a..bbc503e385 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -169,6 +169,7 @@ void StratifiedSplit(const arma::Mat& input, * testData, trainLabel, testLabel, 0.3); * @endcode * + * @tparam LabelsType Type of input labels. It must be arma::Mat or arma::row. * @param input Input dataset to split. * @param inputLabel Input labels to split. * @param trainData Matrix to store training data into. @@ -179,13 +180,15 @@ void StratifiedSplit(const arma::Mat& input, * @param shuffleData If true, the sample order is shuffled; otherwise, each * sample is visited in linear order. (Default true.) */ -template +template::value || + arma::is_Mat_only::value> > void Split(const arma::Mat& input, - const arma::Row& inputLabel, + const LabelsType& inputLabel, arma::Mat& trainData, arma::Mat& testData, - arma::Row& trainLabel, - arma::Row& testLabel, + LabelsType& trainLabel, + LabelsType& testLabel, const double testRatio, const bool shuffleData = true) { @@ -295,6 +298,7 @@ void Split(const arma::Mat& input, * auto splitResult = Split(input, label, 0.2); * @endcode * + * @tparam LabelsType Type of input labels. It must be arma::Mat or arma::row. * @param input Input dataset to split. * @param inputLabel Input labels to split. * @param testRatio Percentage of dataset to use for test set (between 0 and 1). @@ -306,18 +310,20 @@ void Split(const arma::Mat& input, * @return std::tuple containing trainData (arma::Mat), testData * (arma::Mat), trainLabel (arma::Row), and testLabel (arma::Row). */ -template -std::tuple, arma::Mat, arma::Row, arma::Row> +template::value || + arma::is_Mat_only::value> > +std::tuple, arma::Mat, LabelsType, LabelsType> Split(const arma::Mat& input, - const arma::Row& inputLabel, + const LabelsType& inputLabel, const double testRatio, const bool shuffleData = true, const bool stratifyData = false) { arma::Mat trainData; arma::Mat testData; - arma::Row trainLabel; - arma::Row testLabel; + LabelsType trainLabel; + LabelsType testLabel; if (stratifyData) { From cc4e5f4839a7e96e9391d40566c0cb177c3928c4 Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Mon, 30 Nov 2020 21:13:31 +0530 Subject: [PATCH 009/253] Added support for field matrices --- src/mlpack/core/data/split_data.hpp | 222 ++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index bbc503e385..02395ad432 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -374,6 +374,228 @@ Split(const arma::Mat& input, std::move(testData)); } +/** + * Given an input dataset and labels, split into a training set and test set. + * Example usage below. This overload places the split dataset into the four + * output parameters given (trainData, testData, trainLabel, and testLabel). + * + * NOTE: Here FieldType could be arma::field or arma::field + * + * @code + * arma::field input = loadData(); + * arma::field label = loadLabel(); + * arma::field trainData; + * arma::field testData; + * arma::field trainLabel; + * arma::field testLabel; + * math::RandomSeed(100); // Set the seed if you like. + * + * // Split the dataset into a training and test set, with 30% of the data being + * // held out for the test set. + * Split(input, label, trainData, + * testData, trainLabel, testLabel, 0.3); + * @endcode + * + * @param input Input dataset to split. + * @param inputLabel Input labels to split. + * @param trainData FieldType to store training data into. + * @param testData FieldType test data into. + * @param trainLabel Field vector to store training labels into. + * @param testLabel Field vector to store test labels into. + * @param testRatio Percentage of dataset to use for test set (between 0 and 1). + * @param shuffleData If true, the sample order is shuffled; otherwise, each + * sample is visited in linear order. (Default true.) + */ +template ::value || + arma::is_Mat_only::value>> +void Split(FieldType& input, + arma::field& inputLabel, + FieldType& trainData, + arma::field& trainLabels, + FieldType& testData, + arma::field& testLabels, + const double testRatio, + const bool shuffleData = true) +{ + const size_t testSize = static_cast(input.n_cols * testRatio); + const size_t trainSize = input.n_cols - testSize; + + trainData.set_size(1, trainSize); + testData.set_size(1, testSize); + + arma::uvec order = arma::linspace(0, input.n_cols - 1, + input.n_cols); + if (shuffleData) + order = arma::shuffle(order); + + if (trainSize > 0) + { + trainLabels.set_size(1, trainSize); + + for (size_t i = 0; i < trainSize; i++) + trainData[i] = input(0, order(i)); + + for (size_t i = 0; i < trainSize; i++) + trainLabels(0, i) = inputLabel[i]; + } + + if (testSize <= input.n_cols) + { + for (size_t i = trainSize; i < input.n_cols - 1; i++) + testData[i - trainSize] = input(0, order(i)); + + testLabels.set_size(1, testSize); + for (size_t i = trainSize; i < input.n_cols; i++) + testLabels(0, i - trainSize) = inputLabel[i]; + } +} + +/** + * Given an input dataset, split into a training set and test set. + * Example usage below. This overload places the split dataset into the two + * output parameters given (trainData, testData). + * + * NOTE: Here FieldType could be arma::field or arma::field + * + * @code + * arma::field input = loadData(); + * arma::field trainData; + * arma::field testData; + * math::RandomSeed(100); // Set the seed if you like. + * + * // Split the dataset into a training and test set, with 30% of the data being + * // held out for the test set. + * Split(input, trainData, testData, 0.3); + * @endcode + * + * @param input Input dataset to split. + * @param trainData FieldType to store training data into. + * @param testData FieldType test data into. + * @param testRatio Percentage of dataset to use for test set (between 0 and 1). + * @param shuffleData If true, the sample order is shuffled; otherwise, each + * sample is visited in linear order. (Default true). + */ +template ::value || + arma::is_Mat_only::value>> +void Split(const FieldType& input, + FieldType& trainData, + FieldType& testData, + const double testRatio, + const bool shuffleData = true) +{ + const size_t testSize = static_cast(input.n_cols * testRatio); + const size_t trainSize = input.n_cols - testSize; + + trainData.set_size(1, trainSize); + testData.set_size(1, testSize); + + arma::uvec order = arma::linspace(0, input.n_cols - 1, + input.n_cols); + if (shuffleData) + order = arma::shuffle(order); + + if (trainSize > 0) + { + for (size_t i = 0; i < trainSize; i++) + trainData[i] = input(0, order(i)); + } + + if (testSize <= input.n_cols) + { + for (size_t i = trainSize; i < input.n_cols - 1; i++) + testData[i - trainSize] = input(0, order(i)); + } +} + +/** + * Given an input dataset and labels, split into a training set and test set. + * Example usage below. This overload returns the split dataset as a std::tuple + * with four elements: an FieldType containing the training data, an + * FieldType containing the test data, an arma::field containing the + * training labels, and an arma::field containing the test labels. + * + * NOTE: Here FieldType could be arma::field or arma::field + * + * @code + * arma::field input = loadData(); + * arma::field label = loadLabel(); + * auto splitResult = Split(input, label, 0.2); + * @endcode + * + * @param input Input dataset to split. + * @param inputLabel Input labels to split. + * @param testRatio Percentage of dataset to use for test set (between 0 and 1). + * @param shuffleData If true, the sample order is shuffled; otherwise, each + * sample is visited in linear order. (Default true). + * @return std::tuple containing trainData (FieldType), testData + * (FieldType), trainLabel (arma::field), and + * testLabel (arma::field). + */ +template ::value || + arma::is_Mat_only::value>> +std::tuple +Split(FieldType& input, + arma::field& inputLabel, + const double testRatio, + const bool shuffleData = true) +{ + FieldType trainData; + FieldType testData; + arma::field trainLabel; + arma::field testLabel; + + Split(input, inputLabel, trainData, testData, trainLabel, testLabel, + testRatio, shuffleData); + + return std::make_tuple(std::move(trainData), + std::move(testData), + std::move(trainLabel), + std::move(testLabel)); +} + +/** + * Given an input dataset, split into a training set and test set. + * Example usage below. This overload returns the split dataset as a std::tuple + * with two elements: an FieldType containing the training data and an + * FieldType containing the test data. + * + * NOTE: Here FieldType could be arma::field or arma::field + * + * @code + * arma::field input = loadData(); + * auto splitResult = Split(input, 0.2); + * @endcode + * + * @param input Input dataset to split. + * @param testRatio Percentage of dataset to use for test set (between 0 and 1). + * @param shuffleData If true, the sample order is shuffled; otherwise, each + * sample is visited in linear order. (Default true). + * @return std::tuple containing trainData (FieldType) + * and testData (FieldType). + */ +template ::value || + arma::is_Mat_only::value>> +std::tuple +Split(const FieldType& input, + const double testRatio, + const bool shuffleData = true) +{ + FieldType trainData; + FieldType testData; + Split(input, trainData, testData, testRatio, shuffleData); + + return std::make_tuple(std::move(trainData), + std::move(testData)); +} + } // namespace data } // namespace mlpack From e401c65c67a87547bed663225470875930f12693 Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Mon, 30 Nov 2020 22:32:17 +0530 Subject: [PATCH 010/253] Test for field type in data::Split --- src/mlpack/tests/split_data_test.cpp | 24 ++++++++++++++++++++++++ src/mlpack/tests/test_catch_tools.hpp | 15 +++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index 8de9d5f66b..996c6ccfa4 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -121,6 +121,30 @@ TEST_CASE("SplitDataResultMat", "[SplitDataTest]") CheckMatrices(input, concat); } +TEST_CASE("SplitDataResultField", "[SplitDataTest]") +{ + field input(1, 2); + + mat matA(2, 10); + mat matB(2, 10); + + size_t count = 0; // Counter for unique sequential values. + matA.imbue([&count]() { return ++count; }); + matB.imbue([&count]() { return ++count; }); + + input(0, 0) = matA; + input(0, 1) = matB; + + const auto value = Split(input, 0.5, false); + REQUIRE(std::get<0>(value).n_cols == 1); // Train data. + REQUIRE(std::get<1>(value).n_cols == 1); // Test data. + + field concat = {std::get<0>(value)(0), std::get<1>(value)(0)}; + // Order matters here. + CheckFields(input, concat); +} + + TEST_CASE("ZeroRatioSplitData", "[SplitDataTest]") { mat input(2, 10); diff --git a/src/mlpack/tests/test_catch_tools.hpp b/src/mlpack/tests/test_catch_tools.hpp index 1bac310ddc..7b34cfc150 100644 --- a/src/mlpack/tests/test_catch_tools.hpp +++ b/src/mlpack/tests/test_catch_tools.hpp @@ -50,6 +50,21 @@ inline void CheckMatrices(const arma::Mat& a, REQUIRE(a[i] == b[i]); } +template ::value>> +// Check the values of two field types +inline void CheckFields(const FieldType& a, + const FieldType& b) +{ + REQUIRE(a.n_rows == b.n_rows); + REQUIRE(a.n_cols == b.n_cols); + + for (size_t i = 0; i < a.n_slices; ++i) + CheckMatrices(a(i), b(i)); +} + + // Check the values of two cubes. inline void CheckMatrices(const arma::cube& a, const arma::cube& b, From 5b10897d762382444efa64b2dd874328e480b7a3 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 8 Dec 2020 17:04:11 -0500 Subject: [PATCH 011/253] Clean up description and use Authors@R. --- src/mlpack/bindings/R/mlpack/DESCRIPTION.in | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mlpack/bindings/R/mlpack/DESCRIPTION.in b/src/mlpack/bindings/R/mlpack/DESCRIPTION.in index 9183f6bb62..dc583f0dd9 100644 --- a/src/mlpack/bindings/R/mlpack/DESCRIPTION.in +++ b/src/mlpack/bindings/R/mlpack/DESCRIPTION.in @@ -2,11 +2,11 @@ Package: mlpack Title: 'Rcpp' Integration for the 'mlpack' Library Version: @PACKAGE_VERSION@ Date: @PACKAGE_DATE@ -Author: mlpack Team -Maintainer: Ryan Curtin -Description: 'mlpack' is a fast, flexible machine learning library, written - in C++, that aims to provide fast, extensible implementations of - cutting-edge machine learning algorithms. +Authors@R: @AUTHORS_R@ +Description: A fast, flexible machine learning library, written in C++, that + aims to provide fast, extensible implementations of cutting-edge + machine learning algorithms. See also Curtin et al. (2018) + . SystemRequirements: A C++11 compiler. Versions 4.8.*, 4.9.* or later of GCC will be fine. License: BSD_3_clause + file LICENSE From 724402337d43086fa3ed2b52abf6e34be218af2d Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 8 Dec 2020 17:04:26 -0500 Subject: [PATCH 012/253] Use CMake to extract Authors@R list. --- src/mlpack/bindings/R/CMakeLists.txt | 84 ++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/src/mlpack/bindings/R/CMakeLists.txt b/src/mlpack/bindings/R/CMakeLists.txt index a6e8ee16e1..23a4c69139 100644 --- a/src/mlpack/bindings/R/CMakeLists.txt +++ b/src/mlpack/bindings/R/CMakeLists.txt @@ -87,6 +87,90 @@ if (BUILD_R_BINDINGS) string(TIMESTAMP PACKAGE_DATE "%Y-%m-%d") + # We need to generate an Authors@R list using every single contributor in + # COPYRIGHT.txt. That takes a little bit of processing. + file(READ "${CMAKE_SOURCE_DIR}/COPYRIGHT.txt" COPYRIGHT_TXT_CONTENTS) + string(REGEX MATCHALL " Copyright [0-9-]*, ([^\n]*)\n" CONTRIBUTORS_LIST + "${COPYRIGHT_TXT_CONTENTS}") + + # These are the authors meant to be listed as 'authors' and not + # 'contributors'. If you contributed specifically to the R bindings, you + # should probably be listed here, so if you're not, open a PR to fix it! :) + set(SPECIAL_AUTHORS "Yashwant Singh Parihar" "Ryan Curtin" "Dirk Eddelbuettel" + "James Balamuta") + + string(CONCAT AUTHORS_R "c(\n" + " person(\"Yashwant\", \"Singh Parihar\", " + "email = \"yashwantsingh.sngh@gmail.com\", " + "role = c(\"aut\", \"ctb\", \"cph\")),\n" + " person(\"Ryan\", \"Curtin\", email = \"ryan@ratml.org\", " + "role = c(\"aut\", \"ctb\", \"cph\", \"cre\")),\n" + " person(\"Dirk\", \"Eddelbuettel\", email = \"edd@debian.org\", " + "role = c(\"aut\", \"ctb\", \"cph\")),\n" + " person(\"James\", \"Balamuta\", " + "email = \"james.balamuta@gmail.com\", " + "role = c(\"aut\", \"ctb\", \"cph\")),") + foreach (CONTRIBUTOR_LINE ${CONTRIBUTORS_LIST}) + # Strip 'Copyright XXXX-YYYY, '. + string(REGEX REPLACE "^ Copyright [0-9-]*, (.*)\n$" "\\1" + CONTRIBUTOR_FILTERED "${CONTRIBUTOR_LINE}") + + # Extract the email if it exists. + string(REGEX MATCH "^[^<]*<(.*)>.*$" HAS_EMAIL "${CONTRIBUTOR_FILTERED}") + + # The first name is just the first space-delimited word. (That may not + # always be right, but we have no way to know what is a first name and last + # name and therefore must assume.) + string(REGEX REPLACE "^([^ ]*) .*$" "\\1" CONTRIBUTOR_FIRST_NAME + "${CONTRIBUTOR_FILTERED}") + + # Extracting the last name is just the rest of the tokens, but the regex is + # different depending on whether we managed to get an email. + if (HAS_EMAIL) + string(REGEX REPLACE "^[^<]*<(.*)>.*$" "\\1" CONTRIBUTOR_EMAIL + "${CONTRIBUTOR_FILTERED}") + string(REGEX MATCH "^[^ ]* (.*) <.*$" CONTRIBUTOR_LAST_NAME + "${CONTRIBUTOR_FILTERED}") + if (NOT CONTRIBUTOR_LAST_NAME) + set (CONTRIBUTOR_LAST_NAME "") + else () + string(REGEX REPLACE "^[^ ]* (.*) <.*$" "\\1" CONTRIBUTOR_LAST_NAME + "${CONTRIBUTOR_FILTERED}") + endif () + + # Skip anyone already listed as an author. + if ("${CONTRIBUTOR_FIRST_NAME} ${CONTRIBUTOR_LAST_NAME}" IN_LIST + SPECIAL_AUTHORS) + continue() + endif () + + string(CONCAT AUTHORS_R "${AUTHORS_R}\n " + "person(\"${CONTRIBUTOR_FIRST_NAME}\", \"${CONTRIBUTOR_LAST_NAME}\", " + "email = \"${CONTRIBUTOR_EMAIL}\", role = c(\"ctb\", \"cph\")),") + + else () + # No email is available. So just get the last name. + string(REGEX MATCH "^[^ ]* (.*)$" CONTRIBUTOR_LAST_NAME + "${CONTRIBUTOR_FILTERED}") + if (NOT CONTRIBUTOR_LAST_NAME) + set (CONTRIBUTOR_LAST_NAME "") + endif () + + # Skip anyone already listed as an author. + if ("${CONTRIBUTOR_FIRST_NAME} ${CONTRIBUTOR_LAST_NAME}" IN_LIST + SPECIAL_AUTHORS) + continue() + endif () + + string(CONCAT AUTHORS_R "${AUTHORS_R}\n " + "person(\"${CONTRIBUTOR_FIRST_NAME}\", \"${CONTRIBUTOR_LAST_NAME}\", " + "role = c(\"ctb\", \"cph\")),") + endif () + endforeach () + # We also have to remove the final comma... + string(REGEX REPLACE ",$" "" AUTHORS_R_OUT "${AUTHORS_R}") + set(AUTHORS_R "${AUTHORS_R_OUT})") + configure_file(${CMAKE_SOURCE_DIR}/src/mlpack/bindings/R/mlpack/DESCRIPTION.in ${CMAKE_CURRENT_BINARY_DIR}/mlpack/DESCRIPTION @ONLY) From 91a7ca1d3068456393d8073df783c2e3e386f2f5 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 8 Dec 2020 17:14:54 -0500 Subject: [PATCH 013/253] Oops, set last name correctly for no-email contributors. --- src/mlpack/bindings/R/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mlpack/bindings/R/CMakeLists.txt b/src/mlpack/bindings/R/CMakeLists.txt index 23a4c69139..d2c5b46dea 100644 --- a/src/mlpack/bindings/R/CMakeLists.txt +++ b/src/mlpack/bindings/R/CMakeLists.txt @@ -154,6 +154,9 @@ if (BUILD_R_BINDINGS) "${CONTRIBUTOR_FILTERED}") if (NOT CONTRIBUTOR_LAST_NAME) set (CONTRIBUTOR_LAST_NAME "") + else () + string(REGEX REPLACE "^[^ ]* (.*)$" "\\1" CONTRIBUTOR_LAST_NAME + "${CONTRIBUTOR_FILTERED}") endif () # Skip anyone already listed as an author. From 040721affc4b83adbe9cc39c1bf00e17c08ce03f Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 11 Dec 2020 17:35:51 -0500 Subject: [PATCH 014/253] floor()ing an int isn't necessary. --- src/mlpack/core/util/prefixedoutstream_impl.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mlpack/core/util/prefixedoutstream_impl.hpp b/src/mlpack/core/util/prefixedoutstream_impl.hpp index 601c81c4fc..3cb9eea353 100644 --- a/src/mlpack/core/util/prefixedoutstream_impl.hpp +++ b/src/mlpack/core/util/prefixedoutstream_impl.hpp @@ -178,8 +178,7 @@ PrefixedOutStream::BaseLogic(const T& val) if (maxVal == 0.0) maxVal = 1; - int maxLog = log10(maxVal); - maxLog = (maxLog > 0) ? floor(maxLog) + 1 : 1; + const int maxLog = int(log10(maxVal)) + 1; const int padding = 4; convert.width(convert.precision() + maxLog + padding); printVal.raw_print(convert); From d64a0ae52bdaa1dda917f89651fea76360d39166 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 11 Dec 2020 17:36:57 -0500 Subject: [PATCH 015/253] Fix types to match available log() overloads. --- src/mlpack/methods/gmm/em_fit_impl.hpp | 2 +- src/mlpack/methods/hmm/hmm_impl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/gmm/em_fit_impl.hpp b/src/mlpack/methods/gmm/em_fit_impl.hpp index 6b4168bf2d..7f1a4eafd7 100644 --- a/src/mlpack/methods/gmm/em_fit_impl.hpp +++ b/src/mlpack/methods/gmm/em_fit_impl.hpp @@ -156,7 +156,7 @@ Estimate(const arma::mat& observations, // Calculate the new values for omega using the updated conditional // probabilities. - weights = arma::exp(probRowSums - log(observations.n_cols)); + weights = arma::exp(probRowSums - log(1.0 * observations.n_cols)); // Update values of l; calculate new log-likelihood. lOld = l; diff --git a/src/mlpack/methods/hmm/hmm_impl.hpp b/src/mlpack/methods/hmm/hmm_impl.hpp index 8e4d8a2b2f..ac75389a9e 100644 --- a/src/mlpack/methods/hmm/hmm_impl.hpp +++ b/src/mlpack/methods/hmm/hmm_impl.hpp @@ -193,7 +193,7 @@ double HMM::Train(const std::vector& dataSeq) // Normalize the new initial probabilities. if (dataSeq.size() > 1) - logInitial = newLogInitial - log(dataSeq.size()); + logInitial = newLogInitial - log(1.0 * dataSeq.size()); else logInitial = newLogInitial; From 2c0e1745808ddbbbfe685881ca8538b86647b29b Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 11 Dec 2020 17:37:39 -0500 Subject: [PATCH 016/253] Cleaner patch: use std::log() instead. --- src/mlpack/methods/gmm/em_fit_impl.hpp | 2 +- src/mlpack/methods/hmm/hmm_impl.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/gmm/em_fit_impl.hpp b/src/mlpack/methods/gmm/em_fit_impl.hpp index 7f1a4eafd7..c8d8b6ca9e 100644 --- a/src/mlpack/methods/gmm/em_fit_impl.hpp +++ b/src/mlpack/methods/gmm/em_fit_impl.hpp @@ -156,7 +156,7 @@ Estimate(const arma::mat& observations, // Calculate the new values for omega using the updated conditional // probabilities. - weights = arma::exp(probRowSums - log(1.0 * observations.n_cols)); + weights = arma::exp(probRowSums - std::log(observations.n_cols)); // Update values of l; calculate new log-likelihood. lOld = l; diff --git a/src/mlpack/methods/hmm/hmm_impl.hpp b/src/mlpack/methods/hmm/hmm_impl.hpp index ac75389a9e..74688a1273 100644 --- a/src/mlpack/methods/hmm/hmm_impl.hpp +++ b/src/mlpack/methods/hmm/hmm_impl.hpp @@ -193,7 +193,7 @@ double HMM::Train(const std::vector& dataSeq) // Normalize the new initial probabilities. if (dataSeq.size() > 1) - logInitial = newLogInitial - log(1.0 * dataSeq.size()); + logInitial = newLogInitial - std::log(dataSeq.size()); else logInitial = newLogInitial; From 817ed61bb040c82a286355dceeaa3866e7ae0d27 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 11 Dec 2020 18:01:08 -0500 Subject: [PATCH 017/253] Fix duplicate names that happen to live in the same namespace. --- src/mlpack/methods/rann/ra_model.hpp | 44 +++++++++--------- src/mlpack/methods/rann/ra_model_impl.hpp | 54 +++++++++++------------ src/mlpack/methods/rann/ra_search.hpp | 2 +- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/mlpack/methods/rann/ra_model.hpp b/src/mlpack/methods/rann/ra_model.hpp index ed32d4a352..cadc6ad46d 100644 --- a/src/mlpack/methods/rann/ra_model.hpp +++ b/src/mlpack/methods/rann/ra_model.hpp @@ -37,10 +37,10 @@ using RAType = RASearch; /** - * MonoSearchVisitor executes a monochromatic neighbor search on the given + * RAMonoSearchVisitor executes a monochromatic neighbor search on the given * RAType. We don't make any difference for different instantiation of RAType. */ -class MonoSearchVisitor : public boost::static_visitor +class RAMonoSearchVisitor : public boost::static_visitor { private: //! Number of neighbors to search for. @@ -55,10 +55,10 @@ class MonoSearchVisitor : public boost::static_visitor template void operator()(RAType* ra) const; - //! Construct the MonoSearchVisitor object with the given parameters. - MonoSearchVisitor(const size_t k, - arma::Mat& neighbors, - arma::mat& distances) : + //! Construct the RAMonoSearchVisitor object with the given parameters. + RAMonoSearchVisitor(const size_t k, + arma::Mat& neighbors, + arma::mat& distances) : k(k), neighbors(neighbors), distances(distances) @@ -66,13 +66,13 @@ class MonoSearchVisitor : public boost::static_visitor }; /** - * BiSearchVisitor executes a bichromatic neighbor search on the given RAType. + * RABiSearchVisitor executes a bichromatic neighbor search on the given RAType. * We use template specialization to differentiate those tree types types that * accept leafSize as a parameter. In these cases, before doing neighbor search * a query tree with proper leafSize is built from the querySet. */ template -class BiSearchVisitor : public boost::static_visitor +class RABiSearchVisitor : public boost::static_visitor { private: //! The query set for the bichromatic search. @@ -109,22 +109,22 @@ class BiSearchVisitor : public boost::static_visitor //! Bichromatic search on the given RAType specialized for octrees. void operator()(RATypeT* ra) const; - //! Construct the BiSearchVisitor. - BiSearchVisitor(const arma::mat& querySet, - const size_t k, - arma::Mat& neighbors, - arma::mat& distances, - const size_t leafSize); + //! Construct the RABiSearchVisitor. + RABiSearchVisitor(const arma::mat& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t leafSize); }; /** - * TrainVisitor sets the reference set to a new reference set on the given + * RATrainVisitor sets the reference set to a new reference set on the given * RAType. We use template specialization to differentiate those trees that * accept leafSize as a parameter. In these cases, a reference tree with proper * leafSize is built from the referenceSet. */ template -class TrainVisitor : public boost::static_visitor +class RATrainVisitor : public boost::static_visitor { private: //! The reference set to use for training. @@ -155,10 +155,10 @@ class TrainVisitor : public boost::static_visitor //! Train on the given RAType specialized for Octrees. void operator()(RATypeT* ra) const; - //! Construct the TrainVisitor object with the given reference set, leafSize + //! Construct the RATrainVisitor object with the given reference set, leafSize //! for BinarySpaceTrees. - TrainVisitor(arma::mat&& referenceSet, - const size_t leafSize); + RATrainVisitor(arma::mat&& referenceSet, + const size_t leafSize); }; /** @@ -228,7 +228,7 @@ class SingleModeVisitor : public boost::static_visitor /** * Exposes the referenceSet of the given RAType. */ -class ReferenceSetVisitor : public boost::static_visitor +class RAReferenceSetVisitor : public boost::static_visitor { public: //! Return the reference set. @@ -237,9 +237,9 @@ class ReferenceSetVisitor : public boost::static_visitor }; /** - * DeleteVisitor deletes the give RAType Instance. + * RADeleteVisitor deletes the give RAType Instance. */ -class DeleteVisitor : public boost::static_visitor +class RADeleteVisitor : public boost::static_visitor { public: //! Delete the RAType Object. diff --git a/src/mlpack/methods/rann/ra_model_impl.hpp b/src/mlpack/methods/rann/ra_model_impl.hpp index 3b27bfa2d6..e66b3b268a 100644 --- a/src/mlpack/methods/rann/ra_model_impl.hpp +++ b/src/mlpack/methods/rann/ra_model_impl.hpp @@ -21,7 +21,7 @@ namespace neighbor { //! Monochromatic search for the given RAType instance. template -void MonoSearchVisitor::operator()(RAType* ra) const +void RAMonoSearchVisitor::operator()(RAType* ra) const { if (ra) return ra->Search(k, neighbors, distances); @@ -30,11 +30,11 @@ void MonoSearchVisitor::operator()(RAType* ra) const //! Save the parameters for the rank-approximate search. template -BiSearchVisitor::BiSearchVisitor(const arma::mat& querySet, - const size_t k, - arma::Mat& neighbors, - arma::mat& distances, - const size_t leafSize) : +RABiSearchVisitor::RABiSearchVisitor(const arma::mat& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t leafSize) : querySet(querySet), k(k), neighbors(neighbors), @@ -47,7 +47,7 @@ template template class TreeType> -void BiSearchVisitor::operator()(RATypeT* ra) const +void RABiSearchVisitor::operator()(RATypeT* ra) const { if (ra) return ra->Search(querySet, k, neighbors, distances); @@ -56,7 +56,7 @@ void BiSearchVisitor::operator()(RATypeT* ra) const //! Bichromatic search on the given RAType specialized for KDTrees. template -void BiSearchVisitor::operator()(RATypeT* ra) const +void RABiSearchVisitor::operator()(RATypeT* ra) const { if (ra) return SearchLeaf(ra); @@ -65,7 +65,7 @@ void BiSearchVisitor::operator()(RATypeT* ra) const //! Bichromatic search on the given RAType specialized for Octrees. template -void BiSearchVisitor::operator()(RATypeT* ra) const +void RABiSearchVisitor::operator()(RATypeT* ra) const { if (ra) return SearchLeaf(ra); @@ -75,7 +75,7 @@ void BiSearchVisitor::operator()(RATypeT* ra) const //! Bichromatic search on the given RAType considering the leafSize. template template -void BiSearchVisitor::SearchLeaf(RAType* ra) const +void RABiSearchVisitor::SearchLeaf(RAType* ra) const { if (!ra->Naive() && !ra->SingleMode()) { @@ -110,8 +110,8 @@ void BiSearchVisitor::SearchLeaf(RAType* ra) const //! Save parameters for the Train. template -TrainVisitor::TrainVisitor(arma::mat&& referenceSet, - const size_t leafSize) : +RATrainVisitor::RATrainVisitor(arma::mat&& referenceSet, + const size_t leafSize) : referenceSet(std::move(referenceSet)), leafSize(leafSize) {}; @@ -121,7 +121,7 @@ template template class TreeType> -void TrainVisitor::operator()(RATypeT* ra) const +void RATrainVisitor::operator()(RATypeT* ra) const { if (ra) return ra->Train(std::move(referenceSet)); @@ -130,7 +130,7 @@ void TrainVisitor::operator()(RATypeT* ra) const //! Train on the given RAType specialized for KDTrees. template -void TrainVisitor::operator()(RATypeT* ra) const +void RATrainVisitor::operator()(RATypeT* ra) const { if (ra) return TrainLeaf(ra); @@ -139,7 +139,7 @@ void TrainVisitor::operator()(RATypeT* ra) const //! Train on the given RAType specialized for Octrees. template -void TrainVisitor::operator()(RATypeT* ra) const +void RATrainVisitor::operator()(RATypeT* ra) const { if (ra) return TrainLeaf(ra); @@ -149,7 +149,7 @@ void TrainVisitor::operator()(RATypeT* ra) const //! Train on the given RAType considering the leafSize. template template -void TrainVisitor::TrainLeaf(RAType* ra) const +void RATrainVisitor::TrainLeaf(RAType* ra) const { // Build tree, if necessary if (ra->Naive()) @@ -226,7 +226,7 @@ bool& SingleModeVisitor::operator()(RAType* ra) const //! Exposes the referenceSet of the given RAType. template -const arma::mat& ReferenceSetVisitor::operator()(RAType* ra) const +const arma::mat& RAReferenceSetVisitor::operator()(RAType* ra) const { if (ra) return ra->ReferenceSet(); @@ -244,7 +244,7 @@ bool& NaiveVisitor::operator()(RAType* ra) const //! For cleaning memory template -void DeleteVisitor::operator()(RSType* rs) const +void RADeleteVisitor::operator()(RSType* rs) const { if (rs) delete rs; @@ -292,7 +292,7 @@ template RAModel& RAModel::operator=(const RAModel& other) { // Clear current model. - boost::apply_visitor(DeleteVisitor(), raSearch); + boost::apply_visitor(RADeleteVisitor(), raSearch); treeType = other.treeType; leafSize = other.leafSize; @@ -306,7 +306,7 @@ RAModel& RAModel::operator=(const RAModel& other) template RAModel& RAModel::operator=(RAModel&& other) { - boost::apply_visitor(DeleteVisitor(), raSearch); + boost::apply_visitor(RADeleteVisitor(), raSearch); treeType = other.treeType; leafSize = other.leafSize; @@ -327,7 +327,7 @@ RAModel& RAModel::operator=(RAModel&& other) template RAModel::~RAModel() { - boost::apply_visitor(DeleteVisitor(), raSearch); + boost::apply_visitor(RADeleteVisitor(), raSearch); } template @@ -342,7 +342,7 @@ void RAModel::serialize(Archive& ar, // This should never happen, but just in case, be clean with memory. if (cereal::is_loading()) { - boost::apply_visitor(DeleteVisitor(), raSearch); + boost::apply_visitor(RADeleteVisitor(), raSearch); } // We only need to serialize one of the kRANN objects. @@ -352,7 +352,7 @@ void RAModel::serialize(Archive& ar, template const arma::mat& RAModel::Dataset() const { - return boost::apply_visitor(ReferenceSetVisitor(), raSearch); + return boost::apply_visitor(RAReferenceSetVisitor(), raSearch); } template @@ -489,7 +489,7 @@ void RAModel::BuildModel(arma::mat&& referenceSet, } // Clean memory, if necessary. - boost::apply_visitor(DeleteVisitor(), raSearch); + boost::apply_visitor(RADeleteVisitor(), raSearch); this->leafSize = leafSize; @@ -538,7 +538,7 @@ void RAModel::BuildModel(arma::mat&& referenceSet, break; } - TrainVisitor tn(std::move(referenceSet), leafSize); + RATrainVisitor tn(std::move(referenceSet), leafSize); boost::apply_visitor(tn, raSearch); if (!naive) @@ -567,7 +567,7 @@ void RAModel::Search(arma::mat&& querySet, Log::Info << "brute-force (naive) rank-approximate search..."; Log::Info << std::endl; - BiSearchVisitor search(querySet, k, neighbors, distances, + RABiSearchVisitor search(querySet, k, neighbors, distances, leafSize); boost::apply_visitor(search, raSearch); } @@ -586,7 +586,7 @@ void RAModel::Search(const size_t k, Log::Info << "brute-force (naive) rank-approximate search..."; Log::Info << std::endl; - MonoSearchVisitor search(k, neighbors, distances); + RAMonoSearchVisitor search(k, neighbors, distances); boost::apply_visitor(search, raSearch); } diff --git a/src/mlpack/methods/rann/ra_search.hpp b/src/mlpack/methods/rann/ra_search.hpp index da3f61c48d..2dd91baf68 100644 --- a/src/mlpack/methods/rann/ra_search.hpp +++ b/src/mlpack/methods/rann/ra_search.hpp @@ -395,7 +395,7 @@ class RASearch //! For access to mappings when building models. template - friend class TrainVisitor; + friend class RATrainVisitor; }; // class RASearch } // namespace neighbor From eb46d8610e3337086bb42016d5df44cd835a6588 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sun, 13 Dec 2020 18:01:06 -0500 Subject: [PATCH 018/253] Hardcode LICENSE file. --- src/mlpack/bindings/R/CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/mlpack/bindings/R/CMakeLists.txt b/src/mlpack/bindings/R/CMakeLists.txt index d2c5b46dea..830833b614 100644 --- a/src/mlpack/bindings/R/CMakeLists.txt +++ b/src/mlpack/bindings/R/CMakeLists.txt @@ -224,7 +224,7 @@ if (BUILD_R_BINDINGS) ) set(LICENSE_SOURCES - "${CMAKE_SOURCE_DIR}/LICENSE.txt" + "${CMAKE_CURRENT_SOURCE_DIR}/mlpack/LICENSE" ) add_custom_target(r_copy ALL) @@ -276,10 +276,6 @@ if (BUILD_R_BINDINGS) COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${LICENSE_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/mlpack) - add_custom_command(TARGET r_copy PRE_BUILD - COMMAND ${CMAKE_COMMAND} ARGS -E rename - "${CMAKE_CURRENT_BINARY_DIR}/mlpack/LICENSE.txt" - "${CMAKE_CURRENT_BINARY_DIR}/mlpack/LICENSE") # This file will take care of multiple definition of functions in .cpp files. add_custom_command(TARGET r_copy PRE_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E touch From 8a38ffd33137056df395159d771cd602c7931e63 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 15 Dec 2020 18:58:27 -0500 Subject: [PATCH 019/253] Add forward declaration. --- src/mlpack/methods/rann/ra_search.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/rann/ra_search.hpp b/src/mlpack/methods/rann/ra_search.hpp index 2dd91baf68..3e7147f54f 100644 --- a/src/mlpack/methods/rann/ra_search.hpp +++ b/src/mlpack/methods/rann/ra_search.hpp @@ -40,7 +40,7 @@ namespace neighbor { // Forward declaration. template -class TrainVisitor; +class RATrainVisitor; /** * The RASearch class: This class provides a generic manner to perform From fa1b299afc1dc74e7c1c47b572b5658ec0449b02 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 15 Dec 2020 22:23:15 -0500 Subject: [PATCH 020/253] Fix incorrect merge. --- .../ann/loss_functions/negative_log_likelihood_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp b/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp index f4e85dcd2b..1eace1d772 100644 --- a/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/negative_log_likelihood_impl.hpp @@ -38,7 +38,7 @@ NegativeLogLikelihood::Forward( Log::Assert(target(i) >= 0 && target(i) < prediction.n_rows, "Target class out of range."); - output -= input(target(i), i); + output -= prediction(target(i), i); } return output; @@ -57,7 +57,7 @@ void NegativeLogLikelihood::Backward( Log::Assert(target(i) >= 0 && target(i) < prediction.n_rows, "Target class out of range."); - output(target(i), i) = -1; + loss(target(i), i) = -1; } } From 85c3bbc1dd5482a9e2b6f6434eef02dd465c1eb5 Mon Sep 17 00:00:00 2001 From: Anmol2001 <54476451+Anmol2001@users.noreply.github.com> Date: Wed, 16 Dec 2020 13:37:33 +0530 Subject: [PATCH 021/253] Update pca_impl.hpp --- src/mlpack/methods/pca/pca_impl.hpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/pca/pca_impl.hpp b/src/mlpack/methods/pca/pca_impl.hpp index 360586360a..2373128320 100644 --- a/src/mlpack/methods/pca/pca_impl.hpp +++ b/src/mlpack/methods/pca/pca_impl.hpp @@ -61,7 +61,8 @@ void PCA::Apply(const arma::mat& data, /** * Apply Principal Component Analysis to the provided data set. - * + * It creates matrix to store eigenvectors and + that matrix need not to be passed in paramteres * @param data - Data matrix * @param transformedData - Data with PCA applied * @param eigVal - contains eigen values in a column vector @@ -74,6 +75,20 @@ void PCA::Apply(const arma::mat& data, arma::mat eigvec; Apply(data, transformedData, eigVal, eigvec); } + /*This is another Overload of apply with only 2 parameteres(data & transformed data) + and it will create eigval and eigvec and store the corresponding values in them + as the source of information are first 2 parameters only. + * @param data - Data matrix + * @param transformedData - Data with PCA applied + */ +template +void PCA::Apply(const arma::mat& data, + arma::mat& transformedData) +{ + arma::mat eigvec; + arma::vec eigVal; + Apply(data, transformedData, eigVal, eigvec); +} /** * Use PCA for dimensionality reduction on the given dataset. This will save From de930500247c682dd9a45d8476f8420e09a1b63b Mon Sep 17 00:00:00 2001 From: Anmol2001 <54476451+Anmol2001@users.noreply.github.com> Date: Wed, 16 Dec 2020 13:40:14 +0530 Subject: [PATCH 022/253] Update pca.hpp --- src/mlpack/methods/pca/pca.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mlpack/methods/pca/pca.hpp b/src/mlpack/methods/pca/pca.hpp index 594cb47344..ae973f27cb 100644 --- a/src/mlpack/methods/pca/pca.hpp +++ b/src/mlpack/methods/pca/pca.hpp @@ -68,6 +68,14 @@ class PCA void Apply(const arma::mat& data, arma::mat& transformedData, arma::vec& eigVal); +/** + * Apply Principal Component Analysis to the provided data set. It is safe + * to pass the same matrix reference for both data and transformedData. + * @param data Data matrix. + * @param transformedData Matrix to store results of PCA in. + */ + void Apply(const arma::mat& data, + arma::mat& transformedData); /** * Use PCA for dimensionality reduction on the given dataset. This will save From 42ab241eb9beca2051128e58481b5dbc9291fb94 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Wed, 16 Dec 2020 19:13:20 -0500 Subject: [PATCH 023/253] Make sure all state values are set to zero on reset. This will avoid unnecessary reallocations with Armadillo 10. --- .../methods/ann/layer/fast_lstm_impl.hpp | 39 ++++++----------- src/mlpack/methods/ann/layer/lstm_impl.hpp | 43 +++++++------------ 2 files changed, 29 insertions(+), 53 deletions(-) diff --git a/src/mlpack/methods/ann/layer/fast_lstm_impl.hpp b/src/mlpack/methods/ann/layer/fast_lstm_impl.hpp index 752b132ae4..c72416bdeb 100644 --- a/src/mlpack/methods/ann/layer/fast_lstm_impl.hpp +++ b/src/mlpack/methods/ann/layer/fast_lstm_impl.hpp @@ -163,33 +163,20 @@ void FastLSTM::ResetCell(const size_t size) gradientStep = batchSize * size - 1; const size_t rhoBatchSize = size * batchSize; - if (gate.is_empty() || gate.n_cols != rhoBatchSize) - { - gate.set_size(4 * outSize, rhoBatchSize); - gateActivation.set_size(outSize * 3, rhoBatchSize); - stateActivation.set_size(outSize, rhoBatchSize); - cellActivation.set_size(outSize, rhoBatchSize); - prevError.set_size(4 * outSize, batchSize); - if (prevOutput.is_empty()) - { - prevOutput = arma::zeros(outSize, batchSize); - cell = arma::zeros(outSize, size * batchSize); - cellActivationError = arma::zeros(outSize, batchSize); - outParameter = arma::zeros( - outSize, (size + 1) * batchSize); - } - else - { - // To preserve the leading zeros, recreate the object according to given - // size specifications, while preserving the elements as well as the - // layout of the elements. - prevOutput.resize(outSize, batchSize); - cell.resize(outSize, size * batchSize); - cellActivationError.resize(outSize, batchSize); - outParameter.resize(outSize, (size + 1) * batchSize); - } - } + // Make sure all of the matrices we use to store state are at least as large + // as we need. + gate.set_size(4 * outSize, rhoBatchSize); + gateActivation.set_size(outSize * 3, rhoBatchSize); + stateActivation.set_size(outSize, rhoBatchSize); + cellActivation.set_size(outSize, rhoBatchSize); + prevError.set_size(4 * outSize, batchSize); + + // Reset stored state to zeros. + prevOutput.zeros(outSize, batchSize); + cell.zeros(outSize, size * batchSize); + cellActivationError.zeros(outSize, batchSize); + outParameter.zeros(outSize, (size + 1) * batchSize); } template diff --git a/src/mlpack/methods/ann/layer/lstm_impl.hpp b/src/mlpack/methods/ann/layer/lstm_impl.hpp index b1bd784194..c0aa5797be 100644 --- a/src/mlpack/methods/ann/layer/lstm_impl.hpp +++ b/src/mlpack/methods/ann/layer/lstm_impl.hpp @@ -145,36 +145,25 @@ void LSTM::ResetCell(const size_t size) gradientStep = batchSize * size - 1; const size_t rhoBatchSize = size * batchSize; - if (inputGate.is_empty() || inputGate.n_cols < rhoBatchSize) - { - inputGate.set_size(outSize, rhoBatchSize); - forgetGate.set_size(outSize, rhoBatchSize); - hiddenLayer.set_size(outSize, rhoBatchSize); - outputGate.set_size(outSize, rhoBatchSize); - inputGateActivation.set_size(outSize, rhoBatchSize); - forgetGateActivation.set_size(outSize, rhoBatchSize); - outputGateActivation.set_size(outSize, rhoBatchSize); - hiddenLayerActivation.set_size(outSize, rhoBatchSize); + // Make sure all of the different matrices we will use to hold parameters are + // at least as large as we need. + inputGate.set_size(outSize, rhoBatchSize); + forgetGate.set_size(outSize, rhoBatchSize); + hiddenLayer.set_size(outSize, rhoBatchSize); + outputGate.set_size(outSize, rhoBatchSize); - cellActivation.set_size(outSize, rhoBatchSize); - prevError.set_size(4 * outSize, batchSize); + inputGateActivation.set_size(outSize, rhoBatchSize); + forgetGateActivation.set_size(outSize, rhoBatchSize); + outputGateActivation.set_size(outSize, rhoBatchSize); + hiddenLayerActivation.set_size(outSize, rhoBatchSize); - if (cell.is_empty()) - { - cell = arma::zeros(outSize, size * batchSize); - outParameter = arma::zeros( - outSize, (size + 1) * batchSize); - } - else - { - // To preserve the leading zeros, recreate the object according to given - // size specifications, while preserving the elements as well as the - // layout of the elements. - cell.resize(outSize, size * batchSize); - outParameter.resize(outSize, (size + 1) * batchSize); - } - } + cellActivation.set_size(outSize, rhoBatchSize); + prevError.set_size(4 * outSize, batchSize); + + // Now reset recurrent values to 0. + cell.zeros(outSize, size * batchSize); + outParameter.zeros(outSize, (size + 1) * batchSize); } template From 3b9c05ed65c79a2f139972943d89360295150740 Mon Sep 17 00:00:00 2001 From: Anmolpreet Singh <54476451+Anmol2001@users.noreply.github.com> Date: Fri, 18 Dec 2020 23:22:13 +0530 Subject: [PATCH 024/253] Update src/mlpack/methods/pca/pca.hpp Co-authored-by: Marcus Edel --- src/mlpack/methods/pca/pca.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/pca/pca.hpp b/src/mlpack/methods/pca/pca.hpp index ae973f27cb..feae5322a5 100644 --- a/src/mlpack/methods/pca/pca.hpp +++ b/src/mlpack/methods/pca/pca.hpp @@ -68,7 +68,7 @@ class PCA void Apply(const arma::mat& data, arma::mat& transformedData, arma::vec& eigVal); -/** + /** * Apply Principal Component Analysis to the provided data set. It is safe * to pass the same matrix reference for both data and transformedData. * @param data Data matrix. From 8890f43c515f7cf83da80b2e4751e83b335875f2 Mon Sep 17 00:00:00 2001 From: Anmolpreet Singh <54476451+Anmol2001@users.noreply.github.com> Date: Sun, 20 Dec 2020 13:09:11 +0530 Subject: [PATCH 025/253] Update pca_impl.hpp made some minor style changes as suggested by @zoq --- src/mlpack/methods/pca/pca_impl.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/pca/pca_impl.hpp b/src/mlpack/methods/pca/pca_impl.hpp index 2373128320..ce2ecedc66 100644 --- a/src/mlpack/methods/pca/pca_impl.hpp +++ b/src/mlpack/methods/pca/pca_impl.hpp @@ -61,8 +61,7 @@ void PCA::Apply(const arma::mat& data, /** * Apply Principal Component Analysis to the provided data set. - * It creates matrix to store eigenvectors and - that matrix need not to be passed in paramteres + * * @param data - Data matrix * @param transformedData - Data with PCA applied * @param eigVal - contains eigen values in a column vector @@ -75,9 +74,12 @@ void PCA::Apply(const arma::mat& data, arma::mat eigvec; Apply(data, transformedData, eigVal, eigvec); } - /*This is another Overload of apply with only 2 parameteres(data & transformed data) - and it will create eigval and eigvec and store the corresponding values in them - as the source of information are first 2 parameters only. + +/** + * This is another Overload of apply with only 2 parameteres(data & transformed data) + * and it will create eigval and eigvec and store the corresponding values in them + * as the source of information are first 2 parameters only. + * * @param data - Data matrix * @param transformedData - Data with PCA applied */ From e46a7476d0d558128d85b0620e122fbdf4c2aca6 Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Thu, 24 Dec 2020 22:54:18 +0530 Subject: [PATCH 026/253] Added Copy and Move constructors to Multiply Layers --- .../methods/ann/layer/multiply_constant.hpp | 12 +++ .../ann/layer/multiply_constant_impl.hpp | 40 +++++++++ .../methods/ann/layer/multiply_merge.hpp | 12 +++ .../methods/ann/layer/multiply_merge_impl.hpp | 60 ++++++++++++++ src/mlpack/methods/ann/rnn_impl.hpp | 4 +- src/mlpack/tests/ann_layer_test.cpp | 83 +++++++++++++++++++ 6 files changed, 209 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/multiply_constant.hpp b/src/mlpack/methods/ann/layer/multiply_constant.hpp index 5817d26fbf..a9a32a19ac 100644 --- a/src/mlpack/methods/ann/layer/multiply_constant.hpp +++ b/src/mlpack/methods/ann/layer/multiply_constant.hpp @@ -39,6 +39,18 @@ class MultiplyConstant */ MultiplyConstant(const double scalar = 1.0); + //! Copy Constructor + MultiplyConstant(const MultiplyConstant& layer); + + //! Move Constructor + MultiplyConstant(MultiplyConstant&& layer); + + //! Copy assignment operator + MultiplyConstant& operator=(const MultiplyConstant& layer); + + //! Move assignment operator + MultiplyConstant& operator=(MultiplyConstant&& layer); + /** * Ordinary feed forward pass of a neural network. Multiply the input with the * specified constant scalar value. diff --git a/src/mlpack/methods/ann/layer/multiply_constant_impl.hpp b/src/mlpack/methods/ann/layer/multiply_constant_impl.hpp index 7b8cf13e0c..4c02fbd1fa 100644 --- a/src/mlpack/methods/ann/layer/multiply_constant_impl.hpp +++ b/src/mlpack/methods/ann/layer/multiply_constant_impl.hpp @@ -26,6 +26,46 @@ MultiplyConstant::MultiplyConstant( // Nothing to do here. } +template +MultiplyConstant::MultiplyConstant( + const MultiplyConstant& layer) : + scalar(layer.scalar) +{ + // Nothing to do here. +} + +template +MultiplyConstant::MultiplyConstant( + MultiplyConstant&& layer) : + scalar(std::move(layer.scalar)) +{ + // Nothing to do here. +} + +template +MultiplyConstant& +MultiplyConstant::operator=( + const MultiplyConstant& layer) +{ + if (this != &layer) + { + scalar = layer.scalar; + } + return *this; +} + +template +MultiplyConstant& +MultiplyConstant::operator=( + MultiplyConstant&& layer) +{ + if (this != &layer) + { + scalar = std::move(layer.scalar); + } + return *this; +} + template template void MultiplyConstant::Forward( diff --git a/src/mlpack/methods/ann/layer/multiply_merge.hpp b/src/mlpack/methods/ann/layer/multiply_merge.hpp index f459ab2f81..94e4169d52 100644 --- a/src/mlpack/methods/ann/layer/multiply_merge.hpp +++ b/src/mlpack/methods/ann/layer/multiply_merge.hpp @@ -50,6 +50,18 @@ class MultiplyMerge */ MultiplyMerge(const bool model = false, const bool run = true); + //! Copy Constructor + MultiplyMerge(const MultiplyMerge& layer); + + //! Move Constructor + MultiplyMerge(MultiplyMerge&& layer); + + //! Copy assignment operator + MultiplyMerge& operator=(const MultiplyMerge& layer); + + //! Move assignment operator + MultiplyMerge& operator=(MultiplyMerge&& layer); + //! Destructor to release allocated memory. ~MultiplyMerge(); diff --git a/src/mlpack/methods/ann/layer/multiply_merge_impl.hpp b/src/mlpack/methods/ann/layer/multiply_merge_impl.hpp index ee4c8ed917..29cd111482 100644 --- a/src/mlpack/methods/ann/layer/multiply_merge_impl.hpp +++ b/src/mlpack/methods/ann/layer/multiply_merge_impl.hpp @@ -32,6 +32,66 @@ MultiplyMerge::MultiplyMerge( // Nothing to do here. } +template +MultiplyMerge::MultiplyMerge( + const MultiplyMerge& layer) : + model(layer.model), + run(layer.run), + ownsLayer(layer.ownsLayer), + network(layer.network), + weights(layer.weights) +{ + // Nothing to do here. +} + +template +MultiplyMerge::MultiplyMerge( + MultiplyMerge&& layer) : + model(std::move(layer.model)), + run(std::move(layer.run)), + ownsLayer(std::move(layer.ownsLayer)), + network(std::move(layer.network)), + weights(std::move(layer.weights)) +{ + // Nothing to do here. +} + +template +MultiplyMerge& +MultiplyMerge::operator=( + const MultiplyMerge& layer) +{ + if (this != &layer) + { + model = layer.model; + run = layer.run; + ownsLayer = layer.ownsLayer; + network = layer.network; + weights = layer.weights; + } + return *this; +} + +template +MultiplyMerge& +MultiplyMerge::operator=( + MultiplyMerge&& layer) +{ + if (this != &layer) + { + model = std::move(layer.model); + run = std::move(layer.run); + ownsLayer = std::move(layer.ownsLayer); + network = std::move(layer.network); + weights = std::move(layer.weights); + } + return *this; +} + template MultiplyMerge::~MultiplyMerge() diff --git a/src/mlpack/methods/ann/rnn_impl.hpp b/src/mlpack/methods/ann/rnn_impl.hpp index 75749982f5..d734778bef 100644 --- a/src/mlpack/methods/ann/rnn_impl.hpp +++ b/src/mlpack/methods/ann/rnn_impl.hpp @@ -85,10 +85,10 @@ RNN::RNN( targetSize(std::move(network.targetSize)), reset(std::move(network.reset)), single(std::move(network.single)), + network(std::move(network.network)), parameter(std::move(network.parameter)), numFunctions(std::move(network.numFunctions)), - deterministic(std::move(network.deterministic)), - network(std::move(network.network)) + deterministic(std::move(network.deterministic)) { // Nothing to do here. } diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 5471f4be7d..fd718d63ee 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -897,6 +897,39 @@ TEST_CASE("JacobianMultiplyConstantLayerTest", "[ANNLayerTest]") } } +/** + * Check whether copying and moving network with MultiplyConstant is working or + * not. + */ +TEST_CASE("CheckCopyMoveMultiplyConstantTest", "[ANNLayerTest]") +{ + arma::mat input(2, 1000); + input.randu(); + + arma::mat output1; + arma::mat output2; + arma::mat output3; + arma::mat output4; + + MultiplyConstant<> *module1 = new MultiplyConstant<>(3.0); + module1->Forward(input, output1); + + MultiplyConstant<> module2 = *module1; + delete module1; + + module2.Forward(input, output2); + CheckMatrices(output1, output2); + + MultiplyConstant<> *module3 = new MultiplyConstant<>(3.0); + module3->Forward(input, output3); + + MultiplyConstant<> module4(std::move(*module3)); + delete module3; + + module4.Forward(input, output4); + CheckMatrices(output3, output4); +} + /** * Jacobian HardTanH module test. */ @@ -2600,6 +2633,56 @@ TEST_CASE("SimpleMultiplyMergeLayerTest", "[ANNLayerTest]") } } +/** + * Check whether copying and moving network with MultiplyMerge is working or + * not. + */ +TEST_CASE("CheckCopyMoveMultiplyMergeTest", "[ANNLayerTest]") +{ + arma::mat input(10, 1); + input.randu(); + + arma::mat output1; + arma::mat output2; + arma::mat output3; + arma::mat output4; + + const size_t numMergeModules = math::RandInt(2, 10); + + MultiplyMerge<> *module1 = new MultiplyMerge<>(true, false); + for (size_t m = 0; m < numMergeModules; ++m) + { + IdentityLayer<> identityLayer; + identityLayer.Forward(input, identityLayer.OutputParameter()); + + module1->Add >(identityLayer); + } + + module1->Forward(input, output1); + + MultiplyMerge<> module2 = *module1; + delete module1; + + module2.Forward(input, output2); + CheckMatrices(output1, output2); + + MultiplyMerge<> *module3 = new MultiplyMerge<>(true, false); + for (size_t m = 0; m < numMergeModules; ++m) + { + IdentityLayer<> identityLayer; + identityLayer.Forward(input, identityLayer.OutputParameter()); + + module3->Add >(identityLayer); + } + module3->Forward(input, output3); + + MultiplyMerge<> module4(std::move(*module3)); + delete module3; + + module4.Forward(input, output4); + CheckMatrices(output3, output4); +} + /** * Simple Atrous Convolution layer test. */ From 266ae6e27b0d72fa547d3cde4a67d0937a781fb5 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Mon, 28 Dec 2020 13:50:06 +0530 Subject: [PATCH 027/253] added no_sanity_checks option to python bindings --- src/mlpack/bindings/python/mlpack/io.pxd | 1 + src/mlpack/bindings/python/mlpack/io_util.hpp | 10 ++++++++++ src/mlpack/bindings/python/print_pyx.cpp | 17 ++++++++++++++++- src/mlpack/bindings/python/py_option.hpp | 4 ++-- src/mlpack/core/util/mlpack_main.hpp | 2 ++ 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/mlpack/bindings/python/mlpack/io.pxd b/src/mlpack/bindings/python/mlpack/io.pxd index 91d696d011..4a3a838d4c 100644 --- a/src/mlpack/bindings/python/mlpack/io.pxd +++ b/src/mlpack/bindings/python/mlpack/io.pxd @@ -50,3 +50,4 @@ cdef extern from "" \ void DisableBacktrace() nogil except + void ResetTimers() nogil except + void EnableTimers() nogil except + + void SanityCheck[T](T&) nogil except + diff --git a/src/mlpack/bindings/python/mlpack/io_util.hpp b/src/mlpack/bindings/python/mlpack/io_util.hpp index 3a69b06d2d..d2a8bdd4de 100644 --- a/src/mlpack/bindings/python/mlpack/io_util.hpp +++ b/src/mlpack/bindings/python/mlpack/io_util.hpp @@ -163,6 +163,16 @@ inline void EnableTimers() Timer::EnableTiming(); } +/** + * Sanity Check. + */ +template +inline void SanityCheck(T& matrix) +{ + if (matrix.has_nan()) + Log::Fatal << "The input matrix has nan values" << std::endl; +} + } // namespace util } // namespace mlpack diff --git a/src/mlpack/bindings/python/print_pyx.cpp b/src/mlpack/bindings/python/print_pyx.cpp index 87a412346b..4d5bca23e9 100644 --- a/src/mlpack/bindings/python/print_pyx.cpp +++ b/src/mlpack/bindings/python/print_pyx.cpp @@ -78,7 +78,7 @@ void PrintPYX(const util::BindingDetails& doc, cout << "from io cimport SetParam, SetParamPtr, SetParamWithInfo, " << "GetParamPtr" << endl; cout << "from io cimport EnableVerbose, DisableVerbose, DisableBacktrace, " - << "ResetTimers, EnableTimers" << endl; + << "ResetTimers, EnableTimers, SanityCheck" << endl; cout << "from matrix_utils import to_matrix, to_matrix_with_info" << endl; cout << "from serialization cimport SerializeIn, SerializeOut" << endl; cout << endl; @@ -206,6 +206,17 @@ void PrintPYX(const util::BindingDetails& doc, << "\'bool'!\")" << endl; cout << endl; + // Determine whether or not we have to do a sanity check. + cout << " if isinstance(no_sanity_checks, bool):" << endl; + cout << " if no_sanity_checks:" << endl; + cout << " SetParam[cbool]( 'no_sanity_checks', " + << "no_sanity_checks)" << endl; + cout << " IO.SetPassed( 'no_sanity_checks')" << endl; + cout << " else:" << endl; + cout << " raise TypeError(" <<"\"'no_sanity_checks\' must have type " + << "\'bool'!\")" << endl; + cout << endl; + // Do any input processing. for (size_t i = 0; i < inputOptions.size(); ++i) { @@ -224,6 +235,10 @@ void PrintPYX(const util::BindingDetails& doc, cout << " IO.SetPassed( '" << d.name << "')" << endl; } + // Before calling mlpackMain(), we do a sanity check if needed. + cout << " if not IO.GetParam[cbool]( 'no_sanity_checks'):" << endl; + cout << " SanityCheck[arma.Mat[double]](IO.GetParam[arma.Mat[double]]( 'training'))" << endl; + // Call the method. cout << " # Call the mlpack program." << endl; cout << " mlpackMain()" << endl; diff --git a/src/mlpack/bindings/python/py_option.hpp b/src/mlpack/bindings/python/py_option.hpp index 98b9f91844..dfad0926aa 100644 --- a/src/mlpack/bindings/python/py_option.hpp +++ b/src/mlpack/bindings/python/py_option.hpp @@ -64,8 +64,8 @@ class PyOption data.required = required; data.input = input; data.loaded = false; - // Only "verbose" and "copy_all_inputs" will be persistent. - if (identifier == "verbose" || identifier == "copy_all_inputs") + // Only "verbose", "copy_all_inputs" and "no_sanity_checks" will be persistent. + if (identifier == "verbose" || identifier == "copy_all_inputs" || identifier == "no_sanity_checks") data.persistent = true; else data.persistent = false; diff --git a/src/mlpack/core/util/mlpack_main.hpp b/src/mlpack/core/util/mlpack_main.hpp index 06f6f8b060..2e2bf6fed0 100644 --- a/src/mlpack/core/util/mlpack_main.hpp +++ b/src/mlpack/core/util/mlpack_main.hpp @@ -230,6 +230,8 @@ PARAM_FLAG("copy_all_inputs", "If specified, all input parameters will be deep" " copied before the method is run. This is useful for debugging problems " "where the input parameters are being modified by the algorithm, but can " "slow down the code.", ""); +PARAM_FLAG("no_sanity_checks", "If specified, the input matrix is checked for" + " nan values.", ""); // Nothing else needs to be defined---the binding will use mlpackMain() as-is. From 41a4cf0caa74862242bd050f79beaae144dcdd98 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 28 Dec 2020 18:22:45 -0500 Subject: [PATCH 028/253] Add missing LICENSE file. --- src/mlpack/bindings/R/mlpack/LICENSE | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/mlpack/bindings/R/mlpack/LICENSE diff --git a/src/mlpack/bindings/R/mlpack/LICENSE b/src/mlpack/bindings/R/mlpack/LICENSE new file mode 100644 index 0000000000..774e59e170 --- /dev/null +++ b/src/mlpack/bindings/R/mlpack/LICENSE @@ -0,0 +1,3 @@ +YEAR: 2020 +COPYRIGHT HOLDER: mlpack Team +ORGANIZATION: mlpack From f1368e25fb1779b6d865daa2956463bf3629a198 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Tue, 29 Dec 2020 14:11:22 +0530 Subject: [PATCH 029/253] made no_sanity_checks more general --- src/mlpack/bindings/python/mlpack/io.pxd | 2 +- src/mlpack/bindings/python/mlpack/io_util.hpp | 26 ++++++++++++++++--- src/mlpack/bindings/python/print_pyx.cpp | 4 +-- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/mlpack/bindings/python/mlpack/io.pxd b/src/mlpack/bindings/python/mlpack/io.pxd index 4a3a838d4c..b7e77dd82d 100644 --- a/src/mlpack/bindings/python/mlpack/io.pxd +++ b/src/mlpack/bindings/python/mlpack/io.pxd @@ -50,4 +50,4 @@ cdef extern from "" \ void DisableBacktrace() nogil except + void ResetTimers() nogil except + void EnableTimers() nogil except + - void SanityCheck[T](T&) nogil except + + void SanityChecks() nogil except + diff --git a/src/mlpack/bindings/python/mlpack/io_util.hpp b/src/mlpack/bindings/python/mlpack/io_util.hpp index d2a8bdd4de..dd4755cc77 100644 --- a/src/mlpack/bindings/python/mlpack/io_util.hpp +++ b/src/mlpack/bindings/python/mlpack/io_util.hpp @@ -166,11 +166,29 @@ inline void EnableTimers() /** * Sanity Check. */ -template -inline void SanityCheck(T& matrix) +void SanityChecks() { - if (matrix.has_nan()) - Log::Fatal << "The input matrix has nan values" << std::endl; + std::map::iterator itr; + for (itr = IO::Parameters().begin(); itr != IO::Parameters().end(); ++itr) + { + std::string paramName = itr->first; + std::string paramType = itr->second.cppType; + if (paramType == "arma::mat") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has nan values." << std::endl; + } + else if (paramType == "arma::colvec") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has nan values." << std::endl; + } + else if (paramType == "arma::rowvec") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has nan values." << std::endl; + } + } } } // namespace util diff --git a/src/mlpack/bindings/python/print_pyx.cpp b/src/mlpack/bindings/python/print_pyx.cpp index 4d5bca23e9..562212ee4e 100644 --- a/src/mlpack/bindings/python/print_pyx.cpp +++ b/src/mlpack/bindings/python/print_pyx.cpp @@ -78,7 +78,7 @@ void PrintPYX(const util::BindingDetails& doc, cout << "from io cimport SetParam, SetParamPtr, SetParamWithInfo, " << "GetParamPtr" << endl; cout << "from io cimport EnableVerbose, DisableVerbose, DisableBacktrace, " - << "ResetTimers, EnableTimers, SanityCheck" << endl; + << "ResetTimers, EnableTimers, SanityChecks" << endl; cout << "from matrix_utils import to_matrix, to_matrix_with_info" << endl; cout << "from serialization cimport SerializeIn, SerializeOut" << endl; cout << endl; @@ -237,7 +237,7 @@ void PrintPYX(const util::BindingDetails& doc, // Before calling mlpackMain(), we do a sanity check if needed. cout << " if not IO.GetParam[cbool]( 'no_sanity_checks'):" << endl; - cout << " SanityCheck[arma.Mat[double]](IO.GetParam[arma.Mat[double]]( 'training'))" << endl; + cout << " SanityChecks()" << endl; // Call the method. cout << " # Call the mlpack program." << endl; From 6ef1ecac3ac37dc5bafd490a2aea00a39e1c11a5 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Thu, 31 Dec 2020 20:44:56 +0530 Subject: [PATCH 030/253] added arma::Mat and categorical data --- src/mlpack/bindings/python/mlpack/io.pxd | 2 +- src/mlpack/bindings/python/mlpack/io_util.hpp | 24 +++++++++++++++++-- src/mlpack/bindings/python/print_pyx.cpp | 4 ++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/mlpack/bindings/python/mlpack/io.pxd b/src/mlpack/bindings/python/mlpack/io.pxd index b7e77dd82d..b7c2d5937a 100644 --- a/src/mlpack/bindings/python/mlpack/io.pxd +++ b/src/mlpack/bindings/python/mlpack/io.pxd @@ -50,4 +50,4 @@ cdef extern from "" \ void DisableBacktrace() nogil except + void ResetTimers() nogil except + void EnableTimers() nogil except + - void SanityChecks() nogil except + + void SanityCheck() nogil except + diff --git a/src/mlpack/bindings/python/mlpack/io_util.hpp b/src/mlpack/bindings/python/mlpack/io_util.hpp index dd4755cc77..8722b90833 100644 --- a/src/mlpack/bindings/python/mlpack/io_util.hpp +++ b/src/mlpack/bindings/python/mlpack/io_util.hpp @@ -15,7 +15,7 @@ #include #include - +#include namespace mlpack { namespace util { @@ -166,7 +166,7 @@ inline void EnableTimers() /** * Sanity Check. */ -void SanityChecks() +void SanityCheck() { std::map::iterator itr; for (itr = IO::Parameters().begin(); itr != IO::Parameters().end(); ++itr) @@ -178,16 +178,36 @@ void SanityChecks() if (IO::GetParam>(paramName).has_nan()) Log::Fatal << "The input " << paramName << " has nan values." << std::endl; } + else if (paramType == "arma::Mat") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has nan values." << std::endl; + } else if (paramType == "arma::colvec") { if (IO::GetParam>(paramName).has_nan()) Log::Fatal << "The input " << paramName << " has nan values." << std::endl; } + else if (paramType == "arma::Col") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has nan values." << std::endl; + } else if (paramType == "arma::rowvec") { if (IO::GetParam>(paramName).has_nan()) Log::Fatal << "The input " << paramName << " has nan values." << std::endl; } + else if (paramType == "arma::Row") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has nan values." << std::endl; + } + else if (paramType == "std::tuple") + { + if (std::get<1>(IO::GetParam>(paramName)).has_nan()) + Log::Fatal << "The input " << paramName << " has nan values." << std::endl; + } } } diff --git a/src/mlpack/bindings/python/print_pyx.cpp b/src/mlpack/bindings/python/print_pyx.cpp index 562212ee4e..7487f86eda 100644 --- a/src/mlpack/bindings/python/print_pyx.cpp +++ b/src/mlpack/bindings/python/print_pyx.cpp @@ -78,7 +78,7 @@ void PrintPYX(const util::BindingDetails& doc, cout << "from io cimport SetParam, SetParamPtr, SetParamWithInfo, " << "GetParamPtr" << endl; cout << "from io cimport EnableVerbose, DisableVerbose, DisableBacktrace, " - << "ResetTimers, EnableTimers, SanityChecks" << endl; + << "ResetTimers, EnableTimers, SanityCheck" << endl; cout << "from matrix_utils import to_matrix, to_matrix_with_info" << endl; cout << "from serialization cimport SerializeIn, SerializeOut" << endl; cout << endl; @@ -237,7 +237,7 @@ void PrintPYX(const util::BindingDetails& doc, // Before calling mlpackMain(), we do a sanity check if needed. cout << " if not IO.GetParam[cbool]( 'no_sanity_checks'):" << endl; - cout << " SanityChecks()" << endl; + cout << " SanityCheck()" << endl; // Call the method. cout << " # Call the mlpack program." << endl; From 22f59329614725bf5754d6c7ebd7cf7f50be041e Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Thu, 31 Dec 2020 21:09:57 +0530 Subject: [PATCH 031/253] moved SanityCheck() to IO class and changed no_sanity_checks to check_input_matrices --- src/mlpack/bindings/python/mlpack/io_util.hpp | 48 ------------------- src/mlpack/bindings/python/print_pyx.cpp | 20 ++++---- src/mlpack/bindings/python/py_option.hpp | 2 +- src/mlpack/core/util/io.cpp | 46 ++++++++++++++++++ src/mlpack/core/util/io.hpp | 5 ++ src/mlpack/core/util/mlpack_main.hpp | 4 +- 6 files changed, 64 insertions(+), 61 deletions(-) diff --git a/src/mlpack/bindings/python/mlpack/io_util.hpp b/src/mlpack/bindings/python/mlpack/io_util.hpp index 8722b90833..bf2ab0ee05 100644 --- a/src/mlpack/bindings/python/mlpack/io_util.hpp +++ b/src/mlpack/bindings/python/mlpack/io_util.hpp @@ -163,54 +163,6 @@ inline void EnableTimers() Timer::EnableTiming(); } -/** - * Sanity Check. - */ -void SanityCheck() -{ - std::map::iterator itr; - for (itr = IO::Parameters().begin(); itr != IO::Parameters().end(); ++itr) - { - std::string paramName = itr->first; - std::string paramType = itr->second.cppType; - if (paramType == "arma::mat") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has nan values." << std::endl; - } - else if (paramType == "arma::Mat") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has nan values." << std::endl; - } - else if (paramType == "arma::colvec") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has nan values." << std::endl; - } - else if (paramType == "arma::Col") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has nan values." << std::endl; - } - else if (paramType == "arma::rowvec") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has nan values." << std::endl; - } - else if (paramType == "arma::Row") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has nan values." << std::endl; - } - else if (paramType == "std::tuple") - { - if (std::get<1>(IO::GetParam>(paramName)).has_nan()) - Log::Fatal << "The input " << paramName << " has nan values." << std::endl; - } - } -} - } // namespace util } // namespace mlpack diff --git a/src/mlpack/bindings/python/print_pyx.cpp b/src/mlpack/bindings/python/print_pyx.cpp index 7487f86eda..7fa76f6b90 100644 --- a/src/mlpack/bindings/python/print_pyx.cpp +++ b/src/mlpack/bindings/python/print_pyx.cpp @@ -78,7 +78,7 @@ void PrintPYX(const util::BindingDetails& doc, cout << "from io cimport SetParam, SetParamPtr, SetParamWithInfo, " << "GetParamPtr" << endl; cout << "from io cimport EnableVerbose, DisableVerbose, DisableBacktrace, " - << "ResetTimers, EnableTimers, SanityCheck" << endl; + << "ResetTimers, EnableTimers" << endl; cout << "from matrix_utils import to_matrix, to_matrix_with_info" << endl; cout << "from serialization cimport SerializeIn, SerializeOut" << endl; cout << endl; @@ -206,14 +206,14 @@ void PrintPYX(const util::BindingDetails& doc, << "\'bool'!\")" << endl; cout << endl; - // Determine whether or not we have to do a sanity check. - cout << " if isinstance(no_sanity_checks, bool):" << endl; - cout << " if no_sanity_checks:" << endl; - cout << " SetParam[cbool]( 'no_sanity_checks', " - << "no_sanity_checks)" << endl; - cout << " IO.SetPassed( 'no_sanity_checks')" << endl; + // Determine whether or not we have to check input matrices for NaN values. + cout << " if isinstance(check_input_matrices, bool):" << endl; + cout << " if check_input_matrices:" << endl; + cout << " SetParam[cbool]( 'check_input_matrices', " + << "check_input_matrices)" << endl; + cout << " IO.SetPassed( 'check_input_matrices')" << endl; cout << " else:" << endl; - cout << " raise TypeError(" <<"\"'no_sanity_checks\' must have type " + cout << " raise TypeError(" <<"\"'check_input_matrices\' must have type " << "\'bool'!\")" << endl; cout << endl; @@ -236,8 +236,8 @@ void PrintPYX(const util::BindingDetails& doc, } // Before calling mlpackMain(), we do a sanity check if needed. - cout << " if not IO.GetParam[cbool]( 'no_sanity_checks'):" << endl; - cout << " SanityCheck()" << endl; + cout << " if IO.GetParam[cbool]( 'check_input_matrices'):" << endl; + cout << " IO.SanityCheck()" << endl; // Call the method. cout << " # Call the mlpack program." << endl; diff --git a/src/mlpack/bindings/python/py_option.hpp b/src/mlpack/bindings/python/py_option.hpp index dfad0926aa..f6a544e65b 100644 --- a/src/mlpack/bindings/python/py_option.hpp +++ b/src/mlpack/bindings/python/py_option.hpp @@ -65,7 +65,7 @@ class PyOption data.input = input; data.loaded = false; // Only "verbose", "copy_all_inputs" and "no_sanity_checks" will be persistent. - if (identifier == "verbose" || identifier == "copy_all_inputs" || identifier == "no_sanity_checks") + if (identifier == "verbose" || identifier == "copy_all_inputs" || identifier == "check_input_matrices") data.persistent = true; else data.persistent = false; diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index 0c8703c406..f4ed2862ca 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -267,3 +267,49 @@ void IO::ClearSettings() GetSingleton().aliases = persistentAliases; GetSingleton().functionMap = persistentFunctions; } + +void IO::SanityCheck() +{ + std::map::iterator itr; + for (itr = IO::Parameters().begin(); itr != IO::Parameters().end(); ++itr) + { + std::string paramName = itr->first; + std::string paramType = itr->second.cppType; + if (paramType == "arma::mat") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + } + else if (paramType == "arma::Mat") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + } + else if (paramType == "arma::colvec") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + } + else if (paramType == "arma::Col") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + } + else if (paramType == "arma::rowvec") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + } + else if (paramType == "arma::Row") + { + if (IO::GetParam>(paramName).has_nan()) + Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + } + else if (paramType == "std::tuple") + { + if (std::get<1>(IO::GetParam>(paramName)).has_nan()) + Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + } + } +} + diff --git a/src/mlpack/core/util/io.hpp b/src/mlpack/core/util/io.hpp index 427142c897..d927c3b917 100644 --- a/src/mlpack/core/util/io.hpp +++ b/src/mlpack/core/util/io.hpp @@ -285,6 +285,11 @@ class IO */ static void ClearSettings(); + /** + * Checks all input matrices for NaN values, if found throws an exception. + */ + static void SanityCheck(); + private: //! Convenience map from alias values to names. std::map aliases; diff --git a/src/mlpack/core/util/mlpack_main.hpp b/src/mlpack/core/util/mlpack_main.hpp index 2e2bf6fed0..0d65513225 100644 --- a/src/mlpack/core/util/mlpack_main.hpp +++ b/src/mlpack/core/util/mlpack_main.hpp @@ -230,8 +230,8 @@ PARAM_FLAG("copy_all_inputs", "If specified, all input parameters will be deep" " copied before the method is run. This is useful for debugging problems " "where the input parameters are being modified by the algorithm, but can " "slow down the code.", ""); -PARAM_FLAG("no_sanity_checks", "If specified, the input matrix is checked for" - " nan values.", ""); +PARAM_FLAG("check_input_matrices", "If specified, the input matrix is checked for" + " NaN values; an exception is thrown if any are found.", ""); // Nothing else needs to be defined---the binding will use mlpackMain() as-is. From 124d39d7e894af56b91b6ae8129d3ecdf6f7718b Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Thu, 31 Dec 2020 21:14:52 +0530 Subject: [PATCH 032/253] changed comments --- src/mlpack/bindings/python/print_pyx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/bindings/python/print_pyx.cpp b/src/mlpack/bindings/python/print_pyx.cpp index 7fa76f6b90..5f22d0759c 100644 --- a/src/mlpack/bindings/python/print_pyx.cpp +++ b/src/mlpack/bindings/python/print_pyx.cpp @@ -235,7 +235,7 @@ void PrintPYX(const util::BindingDetails& doc, cout << " IO.SetPassed( '" << d.name << "')" << endl; } - // Before calling mlpackMain(), we do a sanity check if needed. + // Before calling mlpackMain(), we check input matrices for NaN values if needed. cout << " if IO.GetParam[cbool]( 'check_input_matrices'):" << endl; cout << " IO.SanityCheck()" << endl; From e5bfb40c23c4fbada1d1805410087fa94c1123e4 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Thu, 31 Dec 2020 22:31:59 +0530 Subject: [PATCH 033/253] wrapped function with Cython --- src/mlpack/bindings/python/mlpack/io.pxd | 4 +++- src/mlpack/bindings/python/print_pyx.cpp | 2 +- src/mlpack/core/util/io.cpp | 3 ++- src/mlpack/core/util/io.hpp | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mlpack/bindings/python/mlpack/io.pxd b/src/mlpack/bindings/python/mlpack/io.pxd index b7c2d5937a..be260d1913 100644 --- a/src/mlpack/bindings/python/mlpack/io.pxd +++ b/src/mlpack/bindings/python/mlpack/io.pxd @@ -38,6 +38,9 @@ cdef extern from "" namespace "mlpack" nogil: @staticmethod void ClearSettings() nogil except + + @staticmethod + void SanityChecks() nogil except + + cdef extern from "" \ namespace "mlpack::util" nogil: void SetParam[T](string, T&) nogil except + @@ -50,4 +53,3 @@ cdef extern from "" \ void DisableBacktrace() nogil except + void ResetTimers() nogil except + void EnableTimers() nogil except + - void SanityCheck() nogil except + diff --git a/src/mlpack/bindings/python/print_pyx.cpp b/src/mlpack/bindings/python/print_pyx.cpp index 5f22d0759c..b79c9501c5 100644 --- a/src/mlpack/bindings/python/print_pyx.cpp +++ b/src/mlpack/bindings/python/print_pyx.cpp @@ -237,7 +237,7 @@ void PrintPYX(const util::BindingDetails& doc, // Before calling mlpackMain(), we check input matrices for NaN values if needed. cout << " if IO.GetParam[cbool]( 'check_input_matrices'):" << endl; - cout << " IO.SanityCheck()" << endl; + cout << " IO.SanityChecks()" << endl; // Call the method. cout << " # Call the mlpack program." << endl; diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index f4ed2862ca..24591285dc 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -268,9 +268,10 @@ void IO::ClearSettings() GetSingleton().functionMap = persistentFunctions; } -void IO::SanityCheck() +void IO::SanityChecks() { std::map::iterator itr; + for (itr = IO::Parameters().begin(); itr != IO::Parameters().end(); ++itr) { std::string paramName = itr->first; diff --git a/src/mlpack/core/util/io.hpp b/src/mlpack/core/util/io.hpp index d927c3b917..3bb9b24f1b 100644 --- a/src/mlpack/core/util/io.hpp +++ b/src/mlpack/core/util/io.hpp @@ -288,7 +288,7 @@ class IO /** * Checks all input matrices for NaN values, if found throws an exception. */ - static void SanityCheck(); + static void SanityChecks(); private: //! Convenience map from alias values to names. From c3ff8d3e621d3e0535945f979d680a30a2e8413a Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Thu, 31 Dec 2020 23:58:40 +0530 Subject: [PATCH 034/253] indentation removed --- src/mlpack/bindings/python/mlpack/io.pxd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/bindings/python/mlpack/io.pxd b/src/mlpack/bindings/python/mlpack/io.pxd index be260d1913..7517c4e4cc 100644 --- a/src/mlpack/bindings/python/mlpack/io.pxd +++ b/src/mlpack/bindings/python/mlpack/io.pxd @@ -38,8 +38,8 @@ cdef extern from "" namespace "mlpack" nogil: @staticmethod void ClearSettings() nogil except + - @staticmethod - void SanityChecks() nogil except + + @staticmethod + void SanityChecks() nogil except + cdef extern from "" \ namespace "mlpack::util" nogil: From ee889c79c29728de27065183bc8d0e9beb83d569 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Sat, 2 Jan 2021 12:48:40 +0530 Subject: [PATCH 035/253] removed iostream --- src/mlpack/bindings/python/mlpack/io_util.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/bindings/python/mlpack/io_util.hpp b/src/mlpack/bindings/python/mlpack/io_util.hpp index bf2ab0ee05..3a69b06d2d 100644 --- a/src/mlpack/bindings/python/mlpack/io_util.hpp +++ b/src/mlpack/bindings/python/mlpack/io_util.hpp @@ -15,7 +15,7 @@ #include #include -#include + namespace mlpack { namespace util { From 8a8f0eaeca13ef9fcaa2cb29e44964d2369c9402 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Sat, 2 Jan 2021 12:51:27 +0530 Subject: [PATCH 036/253] changed name from SanityChecks() to CheckInputMatrices() --- src/mlpack/bindings/python/print_pyx.cpp | 2 +- src/mlpack/core/util/io.cpp | 2 +- src/mlpack/core/util/io.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/bindings/python/print_pyx.cpp b/src/mlpack/bindings/python/print_pyx.cpp index b79c9501c5..5248b6b0be 100644 --- a/src/mlpack/bindings/python/print_pyx.cpp +++ b/src/mlpack/bindings/python/print_pyx.cpp @@ -237,7 +237,7 @@ void PrintPYX(const util::BindingDetails& doc, // Before calling mlpackMain(), we check input matrices for NaN values if needed. cout << " if IO.GetParam[cbool]( 'check_input_matrices'):" << endl; - cout << " IO.SanityChecks()" << endl; + cout << " IO.CheckInputMatrices()" << endl; // Call the method. cout << " # Call the mlpack program." << endl; diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index 24591285dc..fc2e310e4b 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -268,7 +268,7 @@ void IO::ClearSettings() GetSingleton().functionMap = persistentFunctions; } -void IO::SanityChecks() +void IO::CheckInputMatrices() { std::map::iterator itr; diff --git a/src/mlpack/core/util/io.hpp b/src/mlpack/core/util/io.hpp index 3bb9b24f1b..d4f5cc7a17 100644 --- a/src/mlpack/core/util/io.hpp +++ b/src/mlpack/core/util/io.hpp @@ -288,7 +288,7 @@ class IO /** * Checks all input matrices for NaN values, if found throws an exception. */ - static void SanityChecks(); + static void CheckInputMatrices(); private: //! Convenience map from alias values to names. From 62c9f50e5c945952606a61cee9a947bbd3d43aa6 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Sat, 2 Jan 2021 13:03:57 +0530 Subject: [PATCH 037/253] made single block in print_pyx.cpp --- src/mlpack/bindings/python/print_pyx.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/mlpack/bindings/python/print_pyx.cpp b/src/mlpack/bindings/python/print_pyx.cpp index 5248b6b0be..6853c969da 100644 --- a/src/mlpack/bindings/python/print_pyx.cpp +++ b/src/mlpack/bindings/python/print_pyx.cpp @@ -206,17 +206,6 @@ void PrintPYX(const util::BindingDetails& doc, << "\'bool'!\")" << endl; cout << endl; - // Determine whether or not we have to check input matrices for NaN values. - cout << " if isinstance(check_input_matrices, bool):" << endl; - cout << " if check_input_matrices:" << endl; - cout << " SetParam[cbool]( 'check_input_matrices', " - << "check_input_matrices)" << endl; - cout << " IO.SetPassed( 'check_input_matrices')" << endl; - cout << " else:" << endl; - cout << " raise TypeError(" <<"\"'check_input_matrices\' must have type " - << "\'bool'!\")" << endl; - cout << endl; - // Do any input processing. for (size_t i = 0; i < inputOptions.size(); ++i) { @@ -235,8 +224,14 @@ void PrintPYX(const util::BindingDetails& doc, cout << " IO.SetPassed( '" << d.name << "')" << endl; } + // Checking the type of check_input_matrices parameter. + cout << " if not isinstance(check_input_matrices, bool):" << endl; + cout << " raise TypeError(" <<"\"'check_input_matrices\' must have type " + << "\'bool'!\")" << endl; + cout << endl; + // Before calling mlpackMain(), we check input matrices for NaN values if needed. - cout << " if IO.GetParam[cbool]( 'check_input_matrices'):" << endl; + cout << " if check_input_matrices:" << endl; cout << " IO.CheckInputMatrices()" << endl; // Call the method. From be82a0d85ce714d8c865125b8a1d24b080478161 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Sat, 2 Jan 2021 13:15:28 +0530 Subject: [PATCH 038/253] reduced num of chars per line in io.cpp --- src/mlpack/core/util/io.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index fc2e310e4b..4e1771e705 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -270,46 +270,48 @@ void IO::ClearSettings() void IO::CheckInputMatrices() { + typedef typename std::tuple TupleType; std::map::iterator itr; for (itr = IO::Parameters().begin(); itr != IO::Parameters().end(); ++itr) { std::string paramName = itr->first; std::string paramType = itr->second.cppType; + std::string errMsg = "The input " + paramName + " has NaN values."; if (paramType == "arma::mat") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + Log::Fatal << errMsg << std::endl; } else if (paramType == "arma::Mat") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + Log::Fatal << errMsg << std::endl; } else if (paramType == "arma::colvec") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + Log::Fatal << errMsg << std::endl; } else if (paramType == "arma::Col") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + Log::Fatal << errMsg << std::endl; } else if (paramType == "arma::rowvec") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + Log::Fatal << errMsg << std::endl; } else if (paramType == "arma::Row") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + Log::Fatal << errMsg << std::endl; } else if (paramType == "std::tuple") { - if (std::get<1>(IO::GetParam>(paramName)).has_nan()) - Log::Fatal << "The input " << paramName << " has NaN values." << std::endl; + if (std::get<1>(IO::GetParam(paramName)).has_nan()) + Log::Fatal << errMsg << std::endl; } } } From 990ef5347ad1aff53e3587e59efcb1ea272db868 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Sat, 2 Jan 2021 13:20:02 +0530 Subject: [PATCH 039/253] reduced num of chars per line in py_option.hpp --- src/mlpack/bindings/python/py_option.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mlpack/bindings/python/py_option.hpp b/src/mlpack/bindings/python/py_option.hpp index f6a544e65b..0a62afc709 100644 --- a/src/mlpack/bindings/python/py_option.hpp +++ b/src/mlpack/bindings/python/py_option.hpp @@ -64,8 +64,10 @@ class PyOption data.required = required; data.input = input; data.loaded = false; - // Only "verbose", "copy_all_inputs" and "no_sanity_checks" will be persistent. - if (identifier == "verbose" || identifier == "copy_all_inputs" || identifier == "check_input_matrices") + // Only "verbose", "copy_all_inputs" and "check_input_matrices" + // will be persistent. + if (identifier == "verbose" || identifier == "copy_all_inputs" || + identifier == "check_input_matrices") data.persistent = true; else data.persistent = false; From 7d6a2093dd07108f65ff5f76801b8a6736c9f4ee Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Sat, 2 Jan 2021 15:05:16 +0530 Subject: [PATCH 040/253] changed function name while wrapping --- src/mlpack/bindings/python/mlpack/io.pxd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/bindings/python/mlpack/io.pxd b/src/mlpack/bindings/python/mlpack/io.pxd index 7517c4e4cc..67961d59c9 100644 --- a/src/mlpack/bindings/python/mlpack/io.pxd +++ b/src/mlpack/bindings/python/mlpack/io.pxd @@ -39,7 +39,7 @@ cdef extern from "" namespace "mlpack" nogil: void ClearSettings() nogil except + @staticmethod - void SanityChecks() nogil except + + void CheckInputMatrices() nogil except + cdef extern from "" \ namespace "mlpack::util" nogil: From 49f53e67f8c18e66a1396f02ec15af605a126f05 Mon Sep 17 00:00:00 2001 From: Ayush Date: Sat, 2 Jan 2021 20:06:53 +0530 Subject: [PATCH 041/253] WeightSize function for multihead_attention, multiply_constant and multiply_merge --- .../methods/ann/layer/multihead_attention.hpp | 3 +++ .../ann/layer/multihead_attention_impl.hpp | 2 +- .../methods/ann/layer/multiply_constant.hpp | 3 +++ src/mlpack/methods/ann/layer/multiply_merge.hpp | 3 +++ src/mlpack/tests/ann_visitor_test.cpp | 16 ++++++++++++++++ 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/multihead_attention.hpp b/src/mlpack/methods/ann/layer/multihead_attention.hpp index ec079d197d..0c2713c0e8 100644 --- a/src/mlpack/methods/ann/layer/multihead_attention.hpp +++ b/src/mlpack/methods/ann/layer/multihead_attention.hpp @@ -120,6 +120,9 @@ class MultiheadAttention const arma::Mat& error, arma::Mat& gradient); + //! Get the size of the weights. + size_t WeightSize() const { return (4 * (embedDim + 1) * embedDim); } + /** * Serialize the layer. */ diff --git a/src/mlpack/methods/ann/layer/multihead_attention_impl.hpp b/src/mlpack/methods/ann/layer/multihead_attention_impl.hpp index d2da8788e9..3d687d93af 100644 --- a/src/mlpack/methods/ann/layer/multihead_attention_impl.hpp +++ b/src/mlpack/methods/ann/layer/multihead_attention_impl.hpp @@ -54,7 +54,7 @@ MultiheadAttention( } headDim = embedDim / numHeads; - weights.set_size(4 * (embedDim + 1) * embedDim, 1); + weights.set_size(WeightSize(), 1); } template MultiheadAttentionLayer = new MultiheadAttention<>(randomtgtSeqLen, + randomsrcSeqLen, randomembedDim, randomnumHeads); + + CheckCorrectnessOfWeightSize(MultiheadAttentionLayer); +} From bc5fc040cbd3daa1f09e2ed11e5eb1834eeb7c52 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sun, 3 Jan 2021 16:50:35 -0500 Subject: [PATCH 042/253] First attempt at a solution. --- src/mlpack/bindings/python/CMakeLists.txt | 10 ++++++++-- src/mlpack/bindings/python/PythonInstall.cmake | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/mlpack/bindings/python/CMakeLists.txt b/src/mlpack/bindings/python/CMakeLists.txt index 65490997c3..c36a026590 100644 --- a/src/mlpack/bindings/python/CMakeLists.txt +++ b/src/mlpack/bindings/python/CMakeLists.txt @@ -214,14 +214,20 @@ add_custom_command(TARGET python POST_BUILD add_dependencies(python python_configured) # Configure installation script file. +if (NOT PYTHON_INSTALL_PREFIX) + set(PYTHON_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") +endif () + execute_process(COMMAND ${PYTHON_EXECUTABLE} - "${CMAKE_CURRENT_SOURCE_DIR}/print_python_version.py" "${CMAKE_INSTALL_PREFIX}" + "${CMAKE_CURRENT_SOURCE_DIR}/print_python_version.py" + "${PYTHON_INSTALL_PREFIX}" OUTPUT_VARIABLE CMAKE_PYTHON_PATH) string(STRIP "${CMAKE_PYTHON_PATH}" CMAKE_PYTHON_PATH) install(CODE "set(ENV{PYTHONPATH} ${CMAKE_PYTHON_PATH})") install(CODE "set(PYTHON_EXECUTABLE \"${PYTHON_EXECUTABLE}\")") install(CODE "set(CMAKE_BINARY_DIR \"${CMAKE_BINARY_DIR}\")") -install(CODE "set(CMAKE_INSTALL_PREFIX \"${CMAKE_INSTALL_PREFIX}\")") + +install(CODE "set(PYTHON_INSTALL_PREFIX \"${PYTHON_INSTALL_PREFIX}\")") install(CODE "execute_process(COMMAND mkdir -p $ENV{DESTDIR}${CMAKE_PYTHON_PATH})") install(SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/PythonInstall.cmake") diff --git a/src/mlpack/bindings/python/PythonInstall.cmake b/src/mlpack/bindings/python/PythonInstall.cmake index 881b48344a..6e25fb926e 100644 --- a/src/mlpack/bindings/python/PythonInstall.cmake +++ b/src/mlpack/bindings/python/PythonInstall.cmake @@ -5,13 +5,13 @@ if (DEFINED ENV{DESTDIR}) execute_process(COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/setup.py" install - --prefix=${CMAKE_INSTALL_PREFIX} --root=$ENV{DESTDIR} + --prefix=${PYTHON_INSTALL_PREFIX} --root=$ENV{DESTDIR} WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/" RESULT_VARIABLE setup_res) else () execute_process(COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/setup.py" install - --prefix=${CMAKE_INSTALL_PREFIX} + --prefix=${PYTHON_INSTALL_PREFIX} WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/mlpack/bindings/python/" RESULT_VARIABLE setup_res) endif () From c8c7e6594d9abb3411b45e52d4910250084c2bd8 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sun, 3 Jan 2021 20:38:52 -0500 Subject: [PATCH 043/253] Update documentation for new CMake option. --- HISTORY.md | 3 +++ README.md | 1 + doc/guide/build.hpp | 1 + 3 files changed, 5 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 7529a3ee86..9bb5fc29ff 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -13,6 +13,9 @@ * Add finalizers to Julia binding model types to fix memory handling (#2756). + * Add `PYTHON_INSTALL_PREFIX` CMake option to specify installation root for + Python bindings. + ### mlpack 3.4.2 ###### 2020-10-26 * Added Mean Absolute Percentage Error. diff --git a/README.md b/README.md index 610e4f6d33..bb8ba1be6c 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,7 @@ Options are specified with the -D flag. The allowed options include: BUILD_CLI_EXECUTABLES=(ON/OFF): whether or not to build command-line programs BUILD_PYTHON_BINDINGS=(ON/OFF): whether or not to build Python bindings PYTHON_EXECUTABLE=(/path/to/python_version): Path to specific Python executable + PYTHON_INSTALL_PREFIX=(/path/to/python/): Path to root of Python installation BUILD_JULIA_BINDINGS=(ON/OFF): whether or not to build Julia bindings JULIA_EXECUTABLE=(/path/to/julia): Path to specific Julia executable BUILD_GO_BINDINGS=(ON/OFF): whether or not to build Go bindings diff --git a/doc/guide/build.hpp b/doc/guide/build.hpp index a7b5d149ad..d889652e81 100644 --- a/doc/guide/build.hpp +++ b/doc/guide/build.hpp @@ -190,6 +190,7 @@ The full list of options mlpack allows: - BUILD_WITH_COVERAGE=(ON/OFF): Build with support for code coverage tools (gcc only) (default OFF) - PYTHON_EXECUTABLE=(/path/to/python_version): Path to specific Python executable + - PYTHON_INSTALL_PREFIX=(/path/to/python/): Path to root of Python installation - JULIA_EXECUTABLE=(/path/to/julia): Path to specific Julia executable - BUILD_MARKDOWN_BINDINGS=(ON/OFF): Build Markdown bindings for website documentation (default OFF) From c3307b2ad91f354e727145d9479563834671ca48 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 5 Jan 2021 13:01:08 -0500 Subject: [PATCH 044/253] Remove use of boost::visitor in NSModel. --- .../methods/neighbor_search/kfn_main.cpp | 4 +- .../methods/neighbor_search/knn_main.cpp | 3 +- .../neighbor_search/neighbor_search.hpp | 13 +- .../methods/neighbor_search/ns_model.hpp | 517 ++++++++------ .../methods/neighbor_search/ns_model_impl.hpp | 651 ++++++++++-------- src/mlpack/tests/aknn_test.cpp | 16 +- src/mlpack/tests/knn_test.cpp | 44 +- 7 files changed, 687 insertions(+), 561 deletions(-) diff --git a/src/mlpack/methods/neighbor_search/kfn_main.cpp b/src/mlpack/methods/neighbor_search/kfn_main.cpp index 73b9dbd64f..65f3083d56 100644 --- a/src/mlpack/methods/neighbor_search/kfn_main.cpp +++ b/src/mlpack/methods/neighbor_search/kfn_main.cpp @@ -237,14 +237,14 @@ static void mlpackMain() kfn->TreeType() = tree; kfn->RandomBasis() = randomBasis; + kfn->LeafSize() = size_t(lsInt); Log::Info << "Using reference data from " << IO::GetPrintableParam("reference") << "." << endl; arma::mat referenceSet = std::move(IO::GetParam("reference")); - kfn->BuildModel(std::move(referenceSet), size_t(lsInt), searchMode, - epsilon); + kfn->BuildModel(std::move(referenceSet), searchMode, epsilon); } else { diff --git a/src/mlpack/methods/neighbor_search/knn_main.cpp b/src/mlpack/methods/neighbor_search/knn_main.cpp index 9f643ecd61..87ca2203b0 100644 --- a/src/mlpack/methods/neighbor_search/knn_main.cpp +++ b/src/mlpack/methods/neighbor_search/knn_main.cpp @@ -261,8 +261,7 @@ static void mlpackMain() arma::mat referenceSet = std::move(IO::GetParam("reference")); - knn->BuildModel(std::move(referenceSet), size_t(lsInt), searchMode, - epsilon); + knn->BuildModel(std::move(referenceSet), searchMode, epsilon); } else { diff --git a/src/mlpack/methods/neighbor_search/neighbor_search.hpp b/src/mlpack/methods/neighbor_search/neighbor_search.hpp index 1475970af6..2476e0484a 100644 --- a/src/mlpack/methods/neighbor_search/neighbor_search.hpp +++ b/src/mlpack/methods/neighbor_search/neighbor_search.hpp @@ -31,8 +31,13 @@ namespace mlpack { namespace neighbor { // Forward declaration. -template -class TrainVisitor; +template class TreeType, + template class DualTreeTraversalType, + template class SingleTreeTraversalType> +class LeafSizeNSWrapper; //! NeighborSearchMode represents the different neighbor search modes available. enum NeighborSearchMode @@ -359,8 +364,8 @@ class NeighborSearch bool treeNeedsReset; //! The NSModel class should have access to internal members. - template - friend class TrainVisitor; + friend class LeafSizeNSWrapper; }; // class NeighborSearch } // namespace neighbor diff --git a/src/mlpack/methods/neighbor_search/ns_model.hpp b/src/mlpack/methods/neighbor_search/ns_model.hpp index 981d0f9be9..c88b6226cd 100644 --- a/src/mlpack/methods/neighbor_search/ns_model.hpp +++ b/src/mlpack/methods/neighbor_search/ns_model.hpp @@ -4,8 +4,9 @@ * * This is a model for nearest or furthest neighbor search. It is useful in * that it provides an easy way to serialize a model, abstracts away the - * different types of trees, and also reflects the NeighborSearch API and - * automatically directs to the right tree type. + * different types of trees, and also (roughly) reflects the NeighborSearch API and + * automatically directs to the right tree type. It is meant to be used by the + * knn and kfn bindings. * * 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 @@ -20,218 +21,302 @@ #include #include #include -#include #include "neighbor_search.hpp" namespace mlpack { namespace neighbor { /** - * Alias template for euclidean neighbor search. + * NSWrapperBase is a base wrapper class for holding all NeighborSearch types + * supported by NSModel. All NeighborSearch type wrappers inherit from this + * class, allowing a simple interface via inheritance for all the different + * types we want to support. + */ +class NSWrapperBase +{ + public: + //! Create the NSWrapperBase object. The base class does not hold anything, + //! so this constructor does not do anything. + NSWrapperBase() { } + + //! Create a new NSWrapperBase that is the same as this one. This function + //! will properly handle polymorphism. + virtual NSWrapperBase* Clone() const = 0; + + //! Destruct the NSWrapperBase (nothing to do). + virtual ~NSWrapperBase() { }; + + //! Return a reference to the dataset. + virtual const arma::mat& Dataset() const = 0; + + //! Get the search mode. + virtual NeighborSearchMode SearchMode() const = 0; + //! Modify the search modem + virtual NeighborSearchMode& SearchMode() = 0; + + //! Get the approximation parameter epsilon. + virtual double Epsilon() const = 0; + //! Modify the approximation parameter epsilon. + virtual double& Epsilon() = 0; + + //! Train the NeighborSearch model with the given parameters. + virtual void Train(arma::mat&& referenceSet, + const size_t leafSize, + const double tau, + const double rho) = 0; + + //! Perform bichromatic neighbor search (i.e. search with a separate query + //! set). + virtual void Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t leafSize, + const double rho) = 0; + + //! Perform monochromatic neighbor search (i.e. use the reference set as the + //! query set). + virtual void Search(const size_t k, + arma::Mat& neighbors, + arma::mat& distances) = 0; +}; + +/** + * NSWrapper is a wrapper class for most NeighborSearch types. */ template class TreeType> -using NSType = NeighborSearch, - arma::mat>::template DualTreeTraverser>; - -/** - * MonoSearchVisitor executes a monochromatic neighbor search on the given - * NSType. We don't make any difference for different instantiations of NSType. - */ -class MonoSearchVisitor : public boost::static_visitor + typename TreeMatType> class TreeType, + template class DualTreeTraversalType = + TreeType, + arma::mat>::template DualTreeTraverser, + template class SingleTreeTraversalType = + TreeType, + arma::mat>::template SingleTreeTraverser> +class NSWrapper : public NSWrapperBase { - private: - //! Number of neighbors to search for. - const size_t k; - //! Result matrix for neighbors. - arma::Mat& neighbors; - //! Result matrix for distances. - arma::mat& distances; - public: - //! Perform monochromatic nearest neighbor search. - template - void operator()(NSType* ns) const; + //! Construct the NSWrapper object, initializing the internally-held + //! NeighborSearch object. + NSWrapper(const NeighborSearchMode searchMode, + const double epsilon) : + ns(searchMode, epsilon) + { + // Nothing else to do. + } - //! Construct the MonoSearchVisitor object with the given parameters. - MonoSearchVisitor(const size_t k, - arma::Mat& neighbors, - arma::mat& distances) : - k(k), - neighbors(neighbors), - distances(distances) - {}; + //! Delete the NSWrapper object. + virtual ~NSWrapper() { } + + //! Create a copy of this NSWrapper object. This correctly handles + //! polymorphism. + virtual NSWrapper* Clone() const { return new NSWrapper(*this); } + + //! Get a reference to the reference set. + const arma::mat& Dataset() const { return ns.ReferenceSet(); } + + //! Get the search mode. + NeighborSearchMode SearchMode() const { return ns.SearchMode(); } + //! Modify the search mode. + NeighborSearchMode& SearchMode() { return ns.SearchMode(); } + + //! Get epsilon, the approximation parameter. + double Epsilon() const { return ns.Epsilon(); } + //! Modify epsilon, the approximation parameter. + double& Epsilon() { return ns.Epsilon(); } + + //! Train the model with the given options. For NSWrapper, we ignore the + //! extra parameters. + virtual void Train(arma::mat&& referenceSet, + const size_t /* leafSize */, + const double /* tau */, + const double /* rho */); + + //! Perform bichromatic neighbor search (i.e. search with a separate query + //! set). For NSWrapper, we ignore the extra parameters. + virtual void Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t /* leafSize */, + const double /* rho */); + + //! Perform monochromatic neighbor search (i.e. use the reference set as the + //! query set). + virtual void Search(const size_t k, + arma::Mat& neighbors, + arma::mat& distances); + + //! Serialize the NeighborSearch model. + template + void serialize(Archive& ar, const uint32_t /* version */) + { + ar(CEREAL_NVP(ns)); + } + + protected: + // Convenience typedef for the neighbor search type held by this class. + typedef NeighborSearch NSType; + + //! The instantiated NeighborSearch object that we are wrapping. + NSType ns; }; /** - * BiSearchVisitor executes a bichromatic neighbor search on the given NSType. - * We use template specialization to differentiate those tree types that - * accept leafSize as a parameter. In these cases, before doing neighbor search, - * a query tree with proper leafSize is built from the querySet. + * LeafSizeNSWrapper wraps any NeighborSearch types that take a leaf size for + * tree construction. The implementations of Train() and Search() take the leaf + * size into account. + */ +template class TreeType, + template class DualTreeTraversalType = + TreeType, + arma::mat>::template DualTreeTraverser, + template class SingleTreeTraversalType = + TreeType, + arma::mat>::template SingleTreeTraverser> +class LeafSizeNSWrapper : + public NSWrapper +{ + public: + //! Construct the LeafSizeNSWrapper by delegating to the NSWrapper + //! constructor. + LeafSizeNSWrapper(const NeighborSearchMode searchMode, + const double epsilon) : + NSWrapper(searchMode, epsilon) + { + // Nothing to do. + } + + //! Delete the LeafSizeNSWrapper. + virtual ~LeafSizeNSWrapper() { } + + //! Return a copy of the LeafSizeNSWrapper. + virtual LeafSizeNSWrapper* Clone() const + { + return new LeafSizeNSWrapper(*this); + } + + //! Train a model with the given parameters. This overload uses leafSize but + //! ignores the other parameters. + virtual void Train(arma::mat&& referenceSet, + const size_t leafSize, + const double /* tau */, + const double /* rho */); + + //! Perform bichromatic search (e.g. search with a separate query set). This + //! overload uses the leaf size, but ignores the other parameters. + virtual void Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t leafSize, + const double /* rho */); + + //! Serialize the NeighborSearch model. + template + void serialize(Archive& ar, const uint32_t /* version */) + { + ar(CEREAL_NVP(ns)); + } + + protected: + using NSWrapper::ns; +}; + +/** + * The SpillNSWrapper class wraps the NeighborSearch class when the spill tree + * is used. */ template -class BiSearchVisitor : public boost::static_visitor -{ - private: - //! The query set for the bichromatic search. - const arma::mat& querySet; - //! The number of neighbors to search for. - const size_t k; - //! The result matrix for neighbors. - arma::Mat& neighbors; - //! The result matrix for distances. - arma::mat& distances; - //! The number of points in a leaf (for BinarySpaceTrees). - const size_t leafSize; - //! Overlapping size (for spill trees). - const double tau; - //! Balance threshold (for spill trees). - const double rho; - - //! Bichromatic neighbor search on the given NSType considering the leafSize. - template - void SearchLeaf(NSType* ns) const; - - public: - //! Alias template necessary for visual c++ compiler. - template class TreeType> - using NSTypeT = NSType; - - //! Default Bichromatic neighbor search on the given NSType instance. - template class TreeType> - void operator()(NSTypeT* ns) const; - - //! Bichromatic neighbor search on the given NSType specialized for KDTrees. - void operator()(NSTypeT* ns) const; - - //! Bichromatic neighbor search on the given NSType specialized for BallTrees. - void operator()(NSTypeT* ns) const; - - //! Bichromatic neighbor search specialized for SPTrees. - void operator()(SpillKNN* ns) const; - - //! Bichromatic neighbor search specialized for octrees. - void operator()(NSTypeT* ns) const; - - //! Construct the BiSearchVisitor. - BiSearchVisitor(const arma::mat& querySet, - const size_t k, - arma::Mat& neighbors, - arma::mat& distances, - const size_t leafSize, - const double tau, - const double rho); -}; - -/** - * TrainVisitor sets the reference set to a new reference set on the given - * NSType. We use template specialization to differentiate those tree types that - * accept leafSize as a parameter. In these cases, a reference tree with proper - * leafSize is built from the referenceSet. - */ -template -class TrainVisitor : public boost::static_visitor -{ - private: - //! The reference set to use for training. - arma::mat&& referenceSet; - //! The leaf size, used only by BinarySpaceTree. - size_t leafSize; - //! Overlapping size (for spill trees). - const double tau; - //! Balance threshold (for spill trees). - const double rho; - - //! Train on the given NSType considering the leafSize. - template - void TrainLeaf(NSType* ns) const; - - public: - //! Alias template necessary for visual c++ compiler. - template class TreeType> - using NSTypeT = NSType; - - //! Default Train on the given NSType instance. - template class TreeType> - void operator()(NSTypeT* ns) const; - - //! Train on the given NSType specialized for KDTrees. - void operator()(NSTypeT* ns) const; - - //! Train on the given NSType specialized for BallTrees. - void operator()(NSTypeT* ns) const; - - //! Train specialized for SPTrees. - void operator()(SpillKNN* ns) const; - - //! Train specialized for octrees. - void operator()(NSTypeT* ns) const; - - //! Construct the TrainVisitor object with the given reference set, leafSize - //! for BinarySpaceTrees, and tau and rho for spill trees. - TrainVisitor(arma::mat&& referenceSet, - const size_t leafSize, - const double tau, - const double rho); -}; - -/** - * SearchModeVisitor exposes the SearchMode() method of the given NSType. - */ -class SearchModeVisitor : public boost::static_visitor +class SpillNSWrapper : + public NSWrapper< + SortPolicy, + tree::SPTree, + tree::SPTree, + arma::mat>::template DefeatistDualTreeTraverser, + tree::SPTree, + arma::mat>::template DefeatistSingleTreeTraverser> { public: - //! Return the search mode. - template - NeighborSearchMode& operator()(NSType* ns) const; -}; + //! Construct the SpillNSWrapper. + SpillNSWrapper(const NeighborSearchMode searchMode, + const double epsilon) : + NSWrapper< + SortPolicy, + tree::SPTree, + tree::SPTree, + arma::mat>::template DefeatistDualTreeTraverser, + tree::SPTree, + arma::mat>::template DefeatistSingleTreeTraverser>( + searchMode, epsilon) + { + // Nothing to do. + } -/** - * EpsilonVisitor exposes the Epsilon method of the given NSType. - */ -class EpsilonVisitor : public boost::static_visitor -{ - public: - //! Return epsilon, the approximation parameter. - template - double& operator()(NSType *ns) const; -}; + //! Destruct the SpillNSWrapper. + virtual ~SpillNSWrapper() { } -/** - * ReferenceSetVisitor exposes the referenceSet of the given NSType. - */ -class ReferenceSetVisitor : public boost::static_visitor -{ - public: - //! Return the reference set. - template - const arma::mat& operator()(NSType *ns) const; -}; + //! Return a copy of the SpillNSWrapper. + virtual SpillNSWrapper* Clone() const { return new SpillNSWrapper(*this); } -/** - * DeleteVisitor deletes the given NSType instance. - */ -class DeleteVisitor : public boost::static_visitor -{ - public: - //! Delete the NSType object. - template - void operator()(NSType *ns) const; + //! Train the model using the given parameters. + virtual void Train(arma::mat&& referenceSet, + const size_t leafSize, + const double tau, + const double rho); + + //! Perform bichromatic search (i.e. search with a different query set) using + //! the given parameters. + virtual void Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t leafSize, + const double rho); + + //! Serialize the NeighborSearch model. + template + void serialize(Archive& ar, const uint32_t /* version */) + { + ar(CEREAL_NVP(ns)); + } + + protected: + using NSWrapper< + SortPolicy, + tree::SPTree, + tree::SPTree, + arma::mat>::template DefeatistDualTreeTraverser, + tree::SPTree, + arma::mat>::template DefeatistSingleTreeTraverser>::ns; }; /** @@ -272,39 +357,20 @@ class NSModel //! Tree type considered for neighbor search. TreeTypes treeType; - //! For tree types that accept the maxLeafSize parameter. - size_t leafSize; - - //! Overlapping size (for spill trees). - double tau; - //! Balance threshold (for spill trees). - double rho; - //! If true, random projections are used. bool randomBasis; //! This is the random projection matrix; only used if randomBasis is true. arma::mat q; + size_t leafSize; + double tau; + double rho; + /** - * nSearch holds an instance of the NeigborSearch class for the current + * nSearch holds an instance of the NeighborSearch class for the current * treeType. It is initialized every time BuildModel is executed. - * We access to the contained value through the visitor classes defined above. */ - boost::variant*, - NSType*, - NSType*, - NSType*, - NSType*, - NSType*, - NSType*, - NSType*, - NSType*, - NSType*, - NSType*, - NSType*, - SpillKNN*, - NSType*, - NSType*> nSearch; + NSWrapperBase* nSearch; public: /** @@ -359,22 +425,22 @@ class NSModel NeighborSearchMode SearchMode() const; NeighborSearchMode& SearchMode(); - //! Expose Epsilon. - double Epsilon() const; - double& Epsilon(); - - //! Expose leafSize. + //! Expose LeafSize. size_t LeafSize() const { return leafSize; } size_t& LeafSize() { return leafSize; } - //! Expose tau. + //! Expose Tau. double Tau() const { return tau; } double& Tau() { return tau; } - //! Expose rho. + //! Expose Rho. double Rho() const { return rho; } double& Rho() { return rho; } + //! Expose Epsilon. + double Epsilon() const; + double& Epsilon(); + //! Expose treeType. TreeTypes TreeType() const { return treeType; } TreeTypes& TreeType() { return treeType; } @@ -383,9 +449,12 @@ class NSModel bool RandomBasis() const { return randomBasis; } bool& RandomBasis() { return randomBasis; } + //! Initialize the model type. (This does not perform any training.) + void InitializeModel(const NeighborSearchMode searchMode, + const double epsilon); + //! Build the reference tree. void BuildModel(arma::mat&& referenceSet, - const size_t leafSize, const NeighborSearchMode searchMode, const double epsilon = 0); diff --git a/src/mlpack/methods/neighbor_search/ns_model_impl.hpp b/src/mlpack/methods/neighbor_search/ns_model_impl.hpp index 8c90aa9ec8..319fb652af 100644 --- a/src/mlpack/methods/neighbor_search/ns_model_impl.hpp +++ b/src/mlpack/methods/neighbor_search/ns_model_impl.hpp @@ -21,107 +21,121 @@ namespace mlpack { namespace neighbor { -//! Monochromatic neighbor search on the given NSType instance. -template -void MonoSearchVisitor::operator()(NSType *ns) const -{ - if (ns) - return ns->Search(k, neighbors, distances); - throw std::runtime_error("no neighbor search model initialized"); -} - -//! Save parameters for bichromatic neighbor search. -template -BiSearchVisitor::BiSearchVisitor(const arma::mat& querySet, - const size_t k, - arma::Mat& neighbors, - arma::mat& distances, - const size_t leafSize, - const double tau, - const double rho) : - querySet(querySet), - k(k), - neighbors(neighbors), - distances(distances), - leafSize(leafSize), - tau(tau), - rho(rho) -{} - -//! Default Bichromatic neighbor search on the given NSType instance. -template -template class TreeType> -void BiSearchVisitor::operator()(NSTypeT* ns) const + typename TreeMatType> class TreeType, + template class DualTreeTraversalType, + template class SingleTreeTraversalType> +void NSWrapper< + SortPolicy, TreeType, DualTreeTraversalType, SingleTreeTraversalType +>::Train(arma::mat&& referenceSet, + const size_t /* leafSize */, + const double /* tau */, + const double /* rho */) { - if (ns) - return ns->Search(querySet, k, neighbors, distances); - throw std::runtime_error("no neighbor search model initialized"); + ns.Train(std::move(referenceSet)); } -//! Bichromatic neighbor search on the given NSType specialized for KDTrees. -template -void BiSearchVisitor::operator()(NSTypeT* ns) const +//! Perform bichromatic neighbor search (i.e. search with a separate query +//! set). For NSWrapper, we ignore the extra parameters. +template class TreeType, + template class DualTreeTraversalType, + template class SingleTreeTraversalType> +void NSWrapper< + SortPolicy, TreeType, DualTreeTraversalType, SingleTreeTraversalType +>::Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t /* leafSize */, + const double /* rho */) { - if (ns) - return SearchLeaf(ns); - throw std::runtime_error("no neighbor search model initialized"); + ns.Search(std::move(querySet), k, neighbors, distances); } -//! Bichromatic neighbor search on the given NSType specialized for BallTrees. -template -void BiSearchVisitor::operator()(NSTypeT* ns) const +//! Perform monochromatic neighbor search (i.e. use the reference set as the +//! query set). +template class TreeType, + template class DualTreeTraversalType, + template class SingleTreeTraversalType> +void NSWrapper< + SortPolicy, TreeType, DualTreeTraversalType, SingleTreeTraversalType +>::Search(const size_t k, + arma::Mat& neighbors, + arma::mat& distances) { - if (ns) - return SearchLeaf(ns); - throw std::runtime_error("no neighbor search model initialized"); + ns.Search(k, neighbors, distances); } -//! Bichromatic neighbor search specialized for SPTrees. -template -void BiSearchVisitor::operator()(SpillKNN* ns) const +//! Train a model with the given parameters. This overload uses leafSize but +//! ignores the other parameters. +template class TreeType, + template class DualTreeTraversalType, + template class SingleTreeTraversalType> +void LeafSizeNSWrapper< + SortPolicy, TreeType, DualTreeTraversalType, SingleTreeTraversalType +>::Train(arma::mat&& referenceSet, + const size_t leafSize, + const double /* tau */, + const double /* rho */) { - if (ns) + if (ns.SearchMode() == NAIVE_MODE) { - if (ns->SearchMode() == DUAL_TREE_MODE) - { - // For Dual Tree Search on SpillTrees, the queryTree must be built with - // non overlapping (tau = 0). - typename SpillKNN::Tree queryTree(std::move(querySet), 0 /* tau*/, - leafSize, rho); - ns->Search(queryTree, k, neighbors, distances); - } - else - ns->Search(querySet, k, neighbors, distances); + ns.Train(std::move(referenceSet)); } else - throw std::runtime_error("no neighbor search model initialized"); -} - -//! Bichromatic neighbor search specialized for octrees. -template -void BiSearchVisitor::operator()(NSTypeT* ns) const -{ - if (ns) - return SearchLeaf(ns); - throw std::runtime_error("no neighbor search model initialized"); -} - -//! Bichromatic neighbor search on the given NSType considering the leafSize. -template -template -void BiSearchVisitor::SearchLeaf(NSType* ns) const -{ - if (ns->SearchMode() == DUAL_TREE_MODE) { + // Build the tree with the specified leaf size. + std::vector oldFromNewReferences; + typename decltype(ns)::Tree referenceTree(std::move(referenceSet), + oldFromNewReferences, leafSize); + ns.Train(std::move(referenceTree)); + ns.oldFromNewReferences = std::move(oldFromNewReferences); + } +} + +//! Perform bichromatic search (e.g. search with a separate query set). This +//! overload uses the leaf size, but ignores the other parameters. +template class TreeType, + template class DualTreeTraversalType, + template class SingleTreeTraversalType> +void LeafSizeNSWrapper< + SortPolicy, TreeType, DualTreeTraversalType, SingleTreeTraversalType +>::Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t leafSize, + const double /* rho */) +{ + if (ns.SearchMode() == DUAL_TREE_MODE) + { + // We actually have to do the mapping of query points ourselves, since the + // NeighborSearch class does not provide a way for us to specify the leaf + // size when building the query tree. (Therefore we must also build the + // query tree manually.) std::vector oldFromNewQueries; - typename NSType::Tree queryTree(std::move(querySet), oldFromNewQueries, - leafSize); + typename decltype(ns)::Tree queryTree(std::move(querySet), + oldFromNewQueries, leafSize); arma::Mat neighborsOut; arma::mat distancesOut; - ns->Search(queryTree, k, neighborsOut, distancesOut); + ns.Search(queryTree, k, neighborsOut, distancesOut); // Unmap the query points. distances.set_size(distancesOut.n_rows, distancesOut.n_cols); @@ -133,131 +147,47 @@ void BiSearchVisitor::SearchLeaf(NSType* ns) const } } else - ns->Search(querySet, k, neighbors, distances); + { + ns.Search(querySet, k, neighbors, distances); + } } -//! Save parameters for Train. +//! Train the model using the given parameters. template -TrainVisitor::TrainVisitor(arma::mat&& referenceSet, +void SpillNSWrapper::Train(arma::mat&& referenceSet, const size_t leafSize, const double tau, - const double rho) : - referenceSet(std::move(referenceSet)), - leafSize(leafSize), - tau(tau), - rho(rho) -{} - -//! Default Train on the given NSType instance. -template -template class TreeType> -void TrainVisitor::operator()(NSTypeT* ns) const + const double rho) { - if (ns) - return ns->Train(std::move(referenceSet)); - throw std::runtime_error("no neighbor search model initialized"); + typename decltype(ns)::Tree tree(std::move(referenceSet), tau, leafSize, + rho); + ns.Train(std::move(tree)); } -//! Train on the given NSType specialized for KDTrees. +//! Perform bichromatic search (i.e. search with a different query set) using +//! the given parameters. template -void TrainVisitor::operator()(NSTypeT* ns) const +void SpillNSWrapper::Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t leafSize, + const double rho) { - if (ns) - return TrainLeaf(ns); - throw std::runtime_error("no neighbor search model initialized"); -} - -//! Train on the given NSType specialized for BallTrees. -template -void TrainVisitor::operator()(NSTypeT* ns) const -{ - if (ns) - return TrainLeaf(ns); - throw std::runtime_error("no neighbor search model initialized"); -} - -//! Train specialized for SPTrees. -template -void TrainVisitor::operator()(SpillKNN* ns) const -{ - if (ns) + if (ns.SearchMode() == DUAL_TREE_MODE) { - if (ns->SearchMode() == NAIVE_MODE) - ns->Train(std::move(referenceSet)); - else - { - typename SpillKNN::Tree tree(std::move(referenceSet), tau, leafSize, rho); - ns->Train(std::move(tree)); - } + // For Dual Tree Search on SpillTrees, the queryTree must be built with + // non overlapping (tau = 0). + typename decltype(ns)::Tree queryTree(std::move(querySet), 0 /* tau */, + leafSize, rho); + ns.Search(queryTree, k, neighbors, distances); } - else - throw std::runtime_error("no neighbor search model initialized"); -} - -//! Train specialized for Octrees. -template -void TrainVisitor::operator()(NSTypeT* ns) const -{ - if (ns) - return TrainLeaf(ns); - throw std::runtime_error("no neighbor search model initialized"); -} - -//! Train on the given NSType considering the leafSize. -template -template -void TrainVisitor::TrainLeaf(NSType* ns) const -{ - if (ns->SearchMode() == NAIVE_MODE) - ns->Train(std::move(referenceSet)); else { - std::vector oldFromNewReferences; - typename NSType::Tree referenceTree(std::move(referenceSet), - oldFromNewReferences, leafSize); - ns->Train(std::move(referenceTree)); - // Set the mappings. - ns->oldFromNewReferences = std::move(oldFromNewReferences); + ns.Search(querySet, k, neighbors, distances); } } -//! Return the search mode. -template -NeighborSearchMode& SearchModeVisitor::operator()(NSType* ns) const -{ - if (ns) - return ns->SearchMode(); - throw std::runtime_error("no neighbor search model initialized"); -} - -//! Expose the Epsilon method of the given NSType. -template -double& EpsilonVisitor::operator()(NSType* ns) const -{ - if (ns) - return ns->Epsilon(); - throw std::runtime_error("no neighbor search model initialized"); -} - -//! Expose the referenceSet of the given NSType. -template -const arma::mat& ReferenceSetVisitor::operator()(NSType* ns) const -{ - if (ns) - return ns->ReferenceSet(); - throw std::runtime_error("no neighbor search model initialized"); -} - -//! Clean memory, if necessary. -template -void DeleteVisitor::operator()(NSType* ns) const -{ - if (ns) - delete ns; -} - /** * Initialize the NSModel with the given type and whether or not a random * basis should be used. @@ -265,10 +195,11 @@ void DeleteVisitor::operator()(NSType* ns) const template NSModel::NSModel(TreeTypes treeType, bool randomBasis) : treeType(treeType), + randomBasis(randomBasis), leafSize(20), - tau(0), + tau(0.0), rho(0.7), - randomBasis(randomBasis) + nSearch(NULL) { // Nothing to do. } @@ -276,12 +207,12 @@ NSModel::NSModel(TreeTypes treeType, bool randomBasis) : template NSModel::NSModel(const NSModel& other) : treeType(other.treeType), + randomBasis(other.randomBasis), + q(other.q), leafSize(other.leafSize), tau(other.tau), rho(other.rho), - randomBasis(other.randomBasis), - q(other.q), - nSearch(other.nSearch) + nSearch(other.nSearch->Clone()) { // Nothing to do. } @@ -289,34 +220,37 @@ NSModel::NSModel(const NSModel& other) : template NSModel::NSModel(NSModel&& other) : treeType(other.treeType), + randomBasis(other.randomBasis), + q(std::move(other.q)), leafSize(other.leafSize), tau(other.tau), rho(other.rho), - randomBasis(other.randomBasis), - q(std::move(other.q)), nSearch(other.nSearch) { // Reset parameters of the other model. other.treeType = TreeTypes::KD_TREE; - other.leafSize = 20; - other.tau = 0; - other.rho = 0.7; other.randomBasis = false; - other.nSearch = decltype(other.nSearch)(); + other.leafSize = 20; + other.tau = 0.0; + other.rho = 0.7; + other.nSearch = NULL; } template NSModel& NSModel::operator=(const NSModel& other) { - boost::apply_visitor(DeleteVisitor(), nSearch); + if (this != &other) + { + delete nSearch; - treeType = other.treeType; - leafSize = other.leafSize; - tau = other.tau; - rho = other.rho; - randomBasis = other.randomBasis; - q = other.q; - nSearch = other.nSearch; + treeType = other.treeType; + randomBasis = other.randomBasis; + q = other.q; + leafSize = other.leafSize; + tau = other.tau; + rho = other.rho; + nSearch = other.nSearch->Clone(); + } return *this; } @@ -324,24 +258,26 @@ NSModel& NSModel::operator=(const NSModel& other) template NSModel& NSModel::operator=(NSModel&& other) { - boost::apply_visitor(DeleteVisitor(), nSearch); + if (this != &other) + { + delete nSearch; - treeType = other.treeType; - leafSize = other.leafSize; - tau = other.tau; - rho = other.rho; - randomBasis = other.randomBasis; - q = std::move(other.q); - // Copy the pointer and type. - nSearch = other.nSearch; + treeType = other.treeType; + randomBasis = other.randomBasis; + q = std::move(other.q); + leafSize = other.leafSize; + tau = other.tau; + rho = other.rho; + nSearch = other.nSearch; - // Reset parameters of the other model. - other.treeType = TreeTypes::KD_TREE; - other.leafSize = 20; - other.tau = 0; - other.rho = 0.7; - other.randomBasis = false; - other.nSearch = decltype(other.nSearch)(); + // Reset parameters of the other model. + other.treeType = TreeTypes::KD_TREE; + other.randomBasis = false; + other.leafSize = 20; + other.tau = 0.0; + other.rho = 0.7; + other.nSearch = NULL; + } return *this; } @@ -350,7 +286,7 @@ NSModel& NSModel::operator=(NSModel&& other) template NSModel::~NSModel() { - boost::apply_visitor(DeleteVisitor(), nSearch); + delete nSearch; } //! Serialize the kNN model. @@ -359,60 +295,236 @@ template void NSModel::serialize(Archive& ar, const uint32_t /* version */) { ar(CEREAL_NVP(treeType)); + ar(CEREAL_NVP(randomBasis)); + ar(CEREAL_NVP(q)); ar(CEREAL_NVP(leafSize)); ar(CEREAL_NVP(tau)); ar(CEREAL_NVP(rho)); - ar(CEREAL_NVP(randomBasis)); - ar(CEREAL_NVP(q)); // This should never happen, but just in case, be clean with memory. if (cereal::is_loading()) - boost::apply_visitor(DeleteVisitor(), nSearch); + InitializeModel(DUAL_TREE_MODE, 0.0); // Values will be overwritten. - ar(CEREAL_VARIANT_POINTER(nSearch)); + // Avoid polymorphic serialization by explicitly serializing the correct type. + switch (treeType) + { + case KD_TREE: + { + LeafSizeNSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case COVER_TREE: + { + NSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case R_TREE: + { + NSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case R_STAR_TREE: + { + NSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case BALL_TREE: + { + LeafSizeNSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case X_TREE: + { + NSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case HILBERT_R_TREE: + { + NSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case R_PLUS_TREE: + { + NSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case R_PLUS_PLUS_TREE: + { + NSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case SPILL_TREE: + { + SpillNSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case VP_TREE: + { + NSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case RP_TREE: + { + NSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case MAX_RP_TREE: + { + NSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case UB_TREE: + { + NSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case OCTREE: + { + LeafSizeNSWrapper& typedSearch = + dynamic_cast&>(*nSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + } } //! Expose the dataset. template const arma::mat& NSModel::Dataset() const { - return boost::apply_visitor(ReferenceSetVisitor(), nSearch); + return nSearch->Dataset(); } //! Access the search mode. template NeighborSearchMode NSModel::SearchMode() const { - return boost::apply_visitor(SearchModeVisitor(), nSearch); + return nSearch->SearchMode(); } //! Modify the search mode. template NeighborSearchMode& NSModel::SearchMode() { - return boost::apply_visitor(SearchModeVisitor(), nSearch); + return nSearch->SearchMode(); } template double NSModel::Epsilon() const { - return boost::apply_visitor(EpsilonVisitor(), nSearch); + return nSearch->Epsilon(); } template double& NSModel::Epsilon() { - return boost::apply_visitor(EpsilonVisitor(), nSearch); + return nSearch->Epsilon(); +} + +//! Initialize a model given the tree type. (No training happens here.) +template +void NSModel::InitializeModel(const NeighborSearchMode searchMode, + const double epsilon) +{ + // Clear existing memory. + if (nSearch) + delete nSearch; + + switch (treeType) + { + case KD_TREE: + nSearch = new LeafSizeNSWrapper(searchMode, + epsilon); + break; + case COVER_TREE: + nSearch = new NSWrapper(searchMode, + epsilon); + break; + case R_TREE: + nSearch = new NSWrapper(searchMode, epsilon); + break; + case R_STAR_TREE: + nSearch = new NSWrapper(searchMode, epsilon); + break; + case BALL_TREE: + nSearch = new LeafSizeNSWrapper(searchMode, + epsilon); + break; + case X_TREE: + nSearch = new NSWrapper(searchMode, epsilon); + break; + case HILBERT_R_TREE: + nSearch = new NSWrapper(searchMode, + epsilon); + break; + case R_PLUS_TREE: + nSearch = new NSWrapper(searchMode, epsilon); + break; + case R_PLUS_PLUS_TREE: + nSearch = new NSWrapper(searchMode, + epsilon); + break; + case VP_TREE: + nSearch = new NSWrapper(searchMode, epsilon); + break; + case RP_TREE: + nSearch = new NSWrapper(searchMode, epsilon); + break; + case MAX_RP_TREE: + nSearch = new NSWrapper(searchMode, epsilon); + break; + case SPILL_TREE: + nSearch = new SpillNSWrapper(searchMode, epsilon); + break; + case UB_TREE: + nSearch = new NSWrapper(searchMode, epsilon); + break; + case OCTREE: + nSearch = new LeafSizeNSWrapper(searchMode, + epsilon); + break; + } + } //! Build the reference tree. template void NSModel::BuildModel(arma::mat&& referenceSet, - const size_t leafSize, const NeighborSearchMode searchMode, const double epsilon) { - this->leafSize = leafSize; // Initialize random basis if necessary. if (randomBasis) { @@ -445,9 +557,6 @@ void NSModel::BuildModel(arma::mat&& referenceSet, } } - // Clean memory, if necessary. - boost::apply_visitor(DeleteVisitor(), nSearch); - // Do we need to modify the reference set? if (randomBasis) referenceSet = q * referenceSet; @@ -458,59 +567,8 @@ void NSModel::BuildModel(arma::mat&& referenceSet, Log::Info << "Building reference tree..." << std::endl; } - switch (treeType) - { - case KD_TREE: - nSearch = new NSType(searchMode, epsilon); - break; - case COVER_TREE: - nSearch = new NSType(searchMode, - epsilon); - break; - case R_TREE: - nSearch = new NSType(searchMode, epsilon); - break; - case R_STAR_TREE: - nSearch = new NSType(searchMode, epsilon); - break; - case BALL_TREE: - nSearch = new NSType(searchMode, epsilon); - break; - case X_TREE: - nSearch = new NSType(searchMode, epsilon); - break; - case HILBERT_R_TREE: - nSearch = new NSType(searchMode, epsilon); - break; - case R_PLUS_TREE: - nSearch = new NSType(searchMode, epsilon); - break; - case R_PLUS_PLUS_TREE: - nSearch = new NSType(searchMode, - epsilon); - break; - case VP_TREE: - nSearch = new NSType(searchMode, epsilon); - break; - case RP_TREE: - nSearch = new NSType(searchMode, epsilon); - break; - case MAX_RP_TREE: - nSearch = new NSType(searchMode, epsilon); - break; - case SPILL_TREE: - nSearch = new SpillKNN(searchMode, epsilon); - break; - case UB_TREE: - nSearch = new NSType(searchMode, epsilon); - break; - case OCTREE: - nSearch = new NSType(searchMode, epsilon); - break; - } - - TrainVisitor tn(std::move(referenceSet), leafSize, tau, rho); - boost::apply_visitor(tn, nSearch); + InitializeModel(searchMode, epsilon); + nSearch->Train(std::move(referenceSet), leafSize, tau, rho); if (searchMode != NAIVE_MODE) { @@ -549,9 +607,7 @@ void NSModel::Search(arma::mat&& querySet, break; } - BiSearchVisitor search(querySet, k, neighbors, distances, - leafSize, tau, rho); - boost::apply_visitor(search, nSearch); + nSearch->Search(std::move(querySet), k, neighbors, distances, leafSize, rho); } //! Perform neighbor search. @@ -583,8 +639,7 @@ void NSModel::Search(const size_t k, Log::Info << "Maximum of " << Epsilon() * 100 << "% relative error." << std::endl; - MonoSearchVisitor search(k, neighbors, distances); - boost::apply_visitor(search, nSearch); + nSearch->Search(k, neighbors, distances); } //! Get the name of the tree type. diff --git a/src/mlpack/tests/aknn_test.cpp b/src/mlpack/tests/aknn_test.cpp index 37b5e820da..9358b57de7 100644 --- a/src/mlpack/tests/aknn_test.cpp +++ b/src/mlpack/tests/aknn_test.cpp @@ -370,14 +370,13 @@ TEST_CASE("AKNNModelTest", "[AKNNTest]") // We only have std::move() constructors so make a copy of our data. arma::mat referenceCopy(referenceData); arma::mat queryCopy(queryData); + models[i].LeafSize() = 20; if (j == 0) - models[i].BuildModel(std::move(referenceCopy), 20, DUAL_TREE_MODE, - 0.05); + models[i].BuildModel(std::move(referenceCopy), DUAL_TREE_MODE, 0.05); if (j == 1) - models[i].BuildModel(std::move(referenceCopy), 20, - SINGLE_TREE_MODE, 0.05); + models[i].BuildModel(std::move(referenceCopy), SINGLE_TREE_MODE, 0.05); if (j == 2) - models[i].BuildModel(std::move(referenceCopy), 20, NAIVE_MODE); + models[i].BuildModel(std::move(referenceCopy), NAIVE_MODE); arma::Mat neighborsApprox; arma::mat distancesApprox; @@ -448,12 +447,11 @@ TEST_CASE("AKNNModelMonochromaticTest", "[AKNNTest]") { // We only have a std::move() constructor... so copy the data. arma::mat referenceCopy(referenceData); + models[i].LeafSize() = 20; if (j == 0) - models[i].BuildModel(std::move(referenceCopy), 20, DUAL_TREE_MODE, - 0.05); + models[i].BuildModel(std::move(referenceCopy), DUAL_TREE_MODE, 0.05); if (j == 1) - models[i].BuildModel(std::move(referenceCopy), 20, - SINGLE_TREE_MODE, 0.05); + models[i].BuildModel(std::move(referenceCopy), SINGLE_TREE_MODE, 0.05); arma::Mat neighborsApprox; arma::mat distancesApprox; diff --git a/src/mlpack/tests/knn_test.cpp b/src/mlpack/tests/knn_test.cpp index 7e84700843..31f1daf056 100644 --- a/src/mlpack/tests/knn_test.cpp +++ b/src/mlpack/tests/knn_test.cpp @@ -1112,28 +1112,28 @@ TEST_CASE("KNNModelTest", "[KNNTest]") // We only have std::move() constructors so make a copy of our data. arma::mat referenceCopy(referenceData); arma::mat queryCopy(queryData); + models[i].LeafSize() = 20; if (j == 0) - models[i].BuildModel(std::move(referenceCopy), 20, DUAL_TREE_MODE); + models[i].BuildModel(std::move(referenceCopy), DUAL_TREE_MODE); if (j == 1) - models[i].BuildModel(std::move(referenceCopy), 20, - SINGLE_TREE_MODE); + models[i].BuildModel(std::move(referenceCopy), SINGLE_TREE_MODE); if (j == 2) - models[i].BuildModel(std::move(referenceCopy), 20, NAIVE_MODE); + models[i].BuildModel(std::move(referenceCopy), NAIVE_MODE); arma::Mat neighbors; arma::mat distances; models[i].Search(std::move(queryCopy), 3, neighbors, distances); - REQUIRE(neighbors.n_rows ==baselineNeighbors.n_rows); - REQUIRE(neighbors.n_cols ==baselineNeighbors.n_cols); - REQUIRE(neighbors.n_elem ==baselineNeighbors.n_elem); - REQUIRE(distances.n_rows ==baselineDistances.n_rows); - REQUIRE(distances.n_cols ==baselineDistances.n_cols); - REQUIRE(distances.n_elem ==baselineDistances.n_elem); + REQUIRE(neighbors.n_rows == baselineNeighbors.n_rows); + REQUIRE(neighbors.n_cols == baselineNeighbors.n_cols); + REQUIRE(neighbors.n_elem == baselineNeighbors.n_elem); + REQUIRE(distances.n_rows == baselineDistances.n_rows); + REQUIRE(distances.n_cols == baselineDistances.n_cols); + REQUIRE(distances.n_elem == baselineDistances.n_elem); for (size_t k = 0; k < distances.n_elem; ++k) { - REQUIRE(neighbors[k] ==baselineNeighbors[k]); + REQUIRE(neighbors[k] == baselineNeighbors[k]); if (std::abs(baselineDistances[k]) < 1e-5) REQUIRE(distances[k] == Approx(0.0).margin(1e-7)); else @@ -1194,28 +1194,28 @@ TEST_CASE("KNNModelMonochromaticTest", "[KNNTest]") { // We only have a std::move() constructor... so copy the data. arma::mat referenceCopy(referenceData); + models[i].LeafSize() = 20; if (j == 0) - models[i].BuildModel(std::move(referenceCopy), 20, DUAL_TREE_MODE); + models[i].BuildModel(std::move(referenceCopy), DUAL_TREE_MODE); if (j == 1) - models[i].BuildModel(std::move(referenceCopy), 20, - SINGLE_TREE_MODE); + models[i].BuildModel(std::move(referenceCopy), SINGLE_TREE_MODE); if (j == 2) - models[i].BuildModel(std::move(referenceCopy), 20, NAIVE_MODE); + models[i].BuildModel(std::move(referenceCopy), NAIVE_MODE); arma::Mat neighbors; arma::mat distances; models[i].Search(3, neighbors, distances); - REQUIRE(neighbors.n_rows ==baselineNeighbors.n_rows); - REQUIRE(neighbors.n_cols ==baselineNeighbors.n_cols); - REQUIRE(neighbors.n_elem ==baselineNeighbors.n_elem); - REQUIRE(distances.n_rows ==baselineDistances.n_rows); - REQUIRE(distances.n_cols ==baselineDistances.n_cols); - REQUIRE(distances.n_elem ==baselineDistances.n_elem); + REQUIRE(neighbors.n_rows == baselineNeighbors.n_rows); + REQUIRE(neighbors.n_cols == baselineNeighbors.n_cols); + REQUIRE(neighbors.n_elem == baselineNeighbors.n_elem); + REQUIRE(distances.n_rows == baselineDistances.n_rows); + REQUIRE(distances.n_cols == baselineDistances.n_cols); + REQUIRE(distances.n_elem == baselineDistances.n_elem); for (size_t k = 0; k < distances.n_elem; ++k) { - REQUIRE(neighbors[k] ==baselineNeighbors[k]); + REQUIRE(neighbors[k] == baselineNeighbors[k]); if (std::abs(baselineDistances[k]) < 1e-5) REQUIRE(distances[k] == Approx(0.0).margin(1e-7)); else From 8462fc20bde74dba00c2c7145a26875e141ca2cb Mon Sep 17 00:00:00 2001 From: Anmolpreet Singh <54476451+Anmol2001@users.noreply.github.com> Date: Wed, 6 Jan 2021 00:29:22 +0530 Subject: [PATCH 045/253] updated method description --- src/mlpack/methods/pca/pca_impl.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mlpack/methods/pca/pca_impl.hpp b/src/mlpack/methods/pca/pca_impl.hpp index ce2ecedc66..a122cd7159 100644 --- a/src/mlpack/methods/pca/pca_impl.hpp +++ b/src/mlpack/methods/pca/pca_impl.hpp @@ -76,9 +76,7 @@ void PCA::Apply(const arma::mat& data, } /** - * This is another Overload of apply with only 2 parameteres(data & transformed data) - * and it will create eigval and eigvec and store the corresponding values in them - * as the source of information are first 2 parameters only. + * Apply Principal Component Analysis to the provided data set. * * @param data - Data matrix * @param transformedData - Data with PCA applied From 116c534a2b57a778a02b07bb7736206f2ba14858 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 5 Jan 2021 14:45:06 -0500 Subject: [PATCH 046/253] Fix missing parenthesis. --- src/mlpack/bindings/R/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/bindings/R/CMakeLists.txt b/src/mlpack/bindings/R/CMakeLists.txt index a6e8ee16e1..13f171140d 100644 --- a/src/mlpack/bindings/R/CMakeLists.txt +++ b/src/mlpack/bindings/R/CMakeLists.txt @@ -230,7 +230,7 @@ if (BUILD_R_BINDINGS) install(CODE "execute_process( COMMAND R CMD INSTALL mlpack_${PACKAGE_VERSION}.tar.gz - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})" ) add_dependencies(R r_build) From 43c62e830a60361e3ff41fb233aa2fe2c539a664 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 5 Jan 2021 14:45:28 -0500 Subject: [PATCH 047/253] Update issue number. --- HISTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index 9bb5fc29ff..918c95a59f 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -14,7 +14,7 @@ * Add finalizers to Julia binding model types to fix memory handling (#2756). * Add `PYTHON_INSTALL_PREFIX` CMake option to specify installation root for - Python bindings. + Python bindings (#2797). ### mlpack 3.4.2 ###### 2020-10-26 From b89af6ef324403b1c7c36abe13e6f721922061af Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Wed, 6 Jan 2021 10:25:39 +0530 Subject: [PATCH 048/253] Update src/mlpack/tests/test_catch_tools.hpp Co-authored-by: Ryan Curtin --- src/mlpack/tests/test_catch_tools.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/tests/test_catch_tools.hpp b/src/mlpack/tests/test_catch_tools.hpp index 7b34cfc150..dfd0577b19 100644 --- a/src/mlpack/tests/test_catch_tools.hpp +++ b/src/mlpack/tests/test_catch_tools.hpp @@ -64,7 +64,6 @@ inline void CheckFields(const FieldType& a, CheckMatrices(a(i), b(i)); } - // Check the values of two cubes. inline void CheckMatrices(const arma::cube& a, const arma::cube& b, From d50af3ee7bb2529638c6b22cee5bc6e4bdb3123f Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Wed, 6 Jan 2021 12:47:22 +0530 Subject: [PATCH 049/253] Added documentation for template parameter --- src/mlpack/core/data/split_data.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 02395ad432..8a50ceeaf3 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -169,6 +169,7 @@ void StratifiedSplit(const arma::Mat& input, * testData, trainLabel, testLabel, 0.3); * @endcode * + * @tparam T Type of the elements of the input matrix. * @tparam LabelsType Type of input labels. It must be arma::Mat or arma::row. * @param input Input dataset to split. * @param inputLabel Input labels to split. @@ -298,6 +299,7 @@ void Split(const arma::Mat& input, * auto splitResult = Split(input, label, 0.2); * @endcode * + * @tparam T Type of the elements of the input matrix. * @tparam LabelsType Type of input labels. It must be arma::Mat or arma::row. * @param input Input dataset to split. * @param inputLabel Input labels to split. From fe6facd9b47c3b7c06f5d7b010208c3ad7174ea1 Mon Sep 17 00:00:00 2001 From: ayushsingh11 <30299945+ayushsingh11@users.noreply.github.com> Date: Sat, 9 Jan 2021 11:44:55 +0530 Subject: [PATCH 050/253] Minor Fix - Removed redundant () --- src/mlpack/methods/ann/layer/multihead_attention.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/multihead_attention.hpp b/src/mlpack/methods/ann/layer/multihead_attention.hpp index 0c2713c0e8..0d7506ea51 100644 --- a/src/mlpack/methods/ann/layer/multihead_attention.hpp +++ b/src/mlpack/methods/ann/layer/multihead_attention.hpp @@ -121,7 +121,7 @@ class MultiheadAttention arma::Mat& gradient); //! Get the size of the weights. - size_t WeightSize() const { return (4 * (embedDim + 1) * embedDim); } + size_t WeightSize() const { return 4 * (embedDim + 1) * embedDim; } /** * Serialize the layer. From 2b1778ab7aa5221a976d81dce6b8ca3a524459e3 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sat, 9 Jan 2021 21:48:21 -0500 Subject: [PATCH 051/253] Clarify comments. --- src/mlpack/methods/neighbor_search/ns_model.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/neighbor_search/ns_model.hpp b/src/mlpack/methods/neighbor_search/ns_model.hpp index c88b6226cd..b13918fa7d 100644 --- a/src/mlpack/methods/neighbor_search/ns_model.hpp +++ b/src/mlpack/methods/neighbor_search/ns_model.hpp @@ -4,9 +4,9 @@ * * This is a model for nearest or furthest neighbor search. It is useful in * that it provides an easy way to serialize a model, abstracts away the - * different types of trees, and also (roughly) reflects the NeighborSearch API and - * automatically directs to the right tree type. It is meant to be used by the - * knn and kfn bindings. + * different types of trees, and also (roughly) reflects the NeighborSearch API + * and automatically directs to the right tree type. It is meant to be used by + * the knn and kfn bindings. * * 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 From f0e570f5b4901dc0584f570f3170b7c19692e77b Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sat, 9 Jan 2021 21:48:46 -0500 Subject: [PATCH 052/253] Refactor RAModel to not use boost::visitor. --- src/mlpack/methods/rann/CMakeLists.txt | 1 + src/mlpack/methods/rann/krann_main.cpp | 39 +- src/mlpack/methods/rann/ra_model.cpp | 234 ++++++++ src/mlpack/methods/rann/ra_model.hpp | 474 +++++++-------- src/mlpack/methods/rann/ra_model_impl.hpp | 662 ++++----------------- src/mlpack/methods/rann/ra_search.hpp | 9 +- src/mlpack/tests/krann_search_test.cpp | 44 +- src/mlpack/tests/main_tests/krann_test.cpp | 42 +- 8 files changed, 650 insertions(+), 855 deletions(-) create mode 100644 src/mlpack/methods/rann/ra_model.cpp diff --git a/src/mlpack/methods/rann/CMakeLists.txt b/src/mlpack/methods/rann/CMakeLists.txt index 99e838b459..42a70dbc26 100644 --- a/src/mlpack/methods/rann/CMakeLists.txt +++ b/src/mlpack/methods/rann/CMakeLists.txt @@ -23,6 +23,7 @@ set(SOURCES # model ra_model.hpp ra_model_impl.hpp + ra_model.cpp ) # add directory name to sources diff --git a/src/mlpack/methods/rann/krann_main.cpp b/src/mlpack/methods/rann/krann_main.cpp index 9d830f5fff..0ed34fd0f2 100644 --- a/src/mlpack/methods/rann/krann_main.cpp +++ b/src/mlpack/methods/rann/krann_main.cpp @@ -25,9 +25,6 @@ using namespace mlpack::tree; using namespace mlpack::metric; using namespace mlpack::util; -// Convenience typedef. -typedef RAModel RANNModel; - // Program Name. BINDING_NAME("K-Rank-Approximate-Nearest-Neighbors (kRANN)"); @@ -86,8 +83,8 @@ PARAM_MATRIX_OUT("distances", "Matrix to output distances into.", "d"); PARAM_UMATRIX_OUT("neighbors", "Matrix to output neighbors into.", "n"); // The option exists to load or save models. -PARAM_MODEL_IN(RANNModel, "input_model", "Pre-trained kNN model.", "m"); -PARAM_MODEL_OUT(RANNModel, "output_model", "If specified, the kNN model will be" +PARAM_MODEL_IN(RAModel, "input_model", "Pre-trained kNN model.", "m"); +PARAM_MODEL_OUT(RAModel, "output_model", "If specified, the kNN model will be" " output here.", "M"); // The user may specify a query file of query points and a number of nearest @@ -170,12 +167,12 @@ static void mlpackMain() "alpha must be in range [0.0, 1.0]"); // We either have to load the reference data, or we have to load the model. - RANNModel* rann; + RAModel* rann; const bool naive = IO::HasParam("naive"); const bool singleMode = IO::HasParam("single_mode"); if (IO::HasParam("reference")) { - rann = new RANNModel(); + rann = new RAModel(); // Get all the parameters. const string treeType = IO::GetParam("tree_type"); @@ -184,27 +181,27 @@ static void mlpackMain() "unknown tree type"); const bool randomBasis = IO::HasParam("random_basis"); - RANNModel::TreeTypes tree = RANNModel::KD_TREE; + RAModel::TreeTypes tree = RAModel::KD_TREE; if (treeType == "kd") - tree = RANNModel::KD_TREE; + tree = RAModel::KD_TREE; else if (treeType == "cover") - tree = RANNModel::COVER_TREE; + tree = RAModel::COVER_TREE; else if (treeType == "r") - tree = RANNModel::R_TREE; + tree = RAModel::R_TREE; else if (treeType == "r-star") - tree = RANNModel::R_STAR_TREE; + tree = RAModel::R_STAR_TREE; else if (treeType == "x") - tree = RANNModel::X_TREE; + tree = RAModel::X_TREE; else if (treeType == "hilbert-r") - tree = RANNModel::HILBERT_R_TREE; + tree = RAModel::HILBERT_R_TREE; else if (treeType == "r-plus") - tree = RANNModel::R_PLUS_TREE; + tree = RAModel::R_PLUS_TREE; else if (treeType == "r-plus-plus") - tree = RANNModel::R_PLUS_PLUS_TREE; + tree = RAModel::R_PLUS_PLUS_TREE; else if (treeType == "ub") - tree = RANNModel::UB_TREE; + tree = RAModel::UB_TREE; else if (treeType == "oct") - tree = RANNModel::OCTREE; + tree = RAModel::OCTREE; rann->TreeType() = tree; rann->RandomBasis() = randomBasis; @@ -218,10 +215,10 @@ static void mlpackMain() else { // Load the model from file. - rann = IO::GetParam("input_model"); + rann = IO::GetParam("input_model"); Log::Info << "Using rank-approximate kNN model from '" - << IO::GetPrintableParam("input_model") << "' (trained on " + << IO::GetPrintableParam("input_model") << "' (trained on " << rann->Dataset().n_rows << "x" << rann->Dataset().n_cols << " dataset)." << endl; @@ -285,5 +282,5 @@ static void mlpackMain() } // Save the output model. - IO::GetParam("output_model") = rann; + IO::GetParam("output_model") = rann; } diff --git a/src/mlpack/methods/rann/ra_model.cpp b/src/mlpack/methods/rann/ra_model.cpp new file mode 100644 index 0000000000..a6a997a22c --- /dev/null +++ b/src/mlpack/methods/rann/ra_model.cpp @@ -0,0 +1,234 @@ +/** + * @file methods/rann/ra_model.cpp + * @author Ryan Curtin + * + * Implementation of the RAModel class. + * + * 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 "ra_model.hpp" +#include + +namespace mlpack { +namespace neighbor { + +RAModel::RAModel(const TreeTypes treeType, const bool randomBasis) : + treeType(treeType), + leafSize(20), + randomBasis(randomBasis), + raSearch(NULL) +{ + // Nothing to do. +} + +// Copy constructor. +RAModel::RAModel(const RAModel& other) : + treeType(other.treeType), + leafSize(other.leafSize), + randomBasis(other.randomBasis), + q(other.q), + raSearch(other.raSearch->Clone()) +{ + // Nothing to do. +} + +// Move constructor. +RAModel::RAModel(RAModel&& other) : + treeType(other.treeType), + leafSize(other.leafSize), + randomBasis(other.randomBasis), + q(std::move(other.q)), + raSearch(std::move(other.raSearch)) +{ + // Clear other model. + other.treeType = TreeTypes::KD_TREE; + other.leafSize = 20; + other.randomBasis = false; +} + +// Copy operator. +RAModel& RAModel::operator=(const RAModel& other) +{ + if (this != &other) + { + // Clear current model. + delete raSearch; + + treeType = other.treeType; + leafSize = other.leafSize; + randomBasis = other.randomBasis; + q = other.q; + raSearch = other.raSearch->Clone(); + } + + return *this; +} + +RAModel& RAModel::operator=(RAModel&& other) +{ + if (this != &other) + { + // Clear current model. + delete raSearch; + + treeType = other.treeType; + leafSize = other.leafSize; + randomBasis = other.randomBasis; + q = std::move(other.q); + raSearch = std::move(other.raSearch); + + // Reset other model. + other.treeType = TreeTypes::KD_TREE; + other.leafSize = 20; + other.randomBasis = false; + } + + return *this; +} + +// Clean memory, if necessary +RAModel::~RAModel() +{ + delete raSearch; +} + +void RAModel::BuildModel(arma::mat&& referenceSet, + const size_t leafSize, + const bool naive, + const bool singleMode) +{ + // Initialize random basis, if necessary. + if (randomBasis) + { + Log::Info << "Creating random basis..." << std::endl; + math::RandomBasis(q, referenceSet.n_rows); + } + + // Clean memory, if necessary. + delete raSearch; + + this->leafSize = leafSize; + + if (randomBasis) + referenceSet = q * referenceSet; + + if (!naive) + { + Timer::Start("tree_building"); + Log::Info << "Building reference tree..." << std::endl; + } + + switch (treeType) + { + case KD_TREE: + raSearch = new LeafSizeRAWrapper(naive, singleMode); + break; + case COVER_TREE: + raSearch = new RAWrapper(naive, singleMode); + break; + case R_TREE: + raSearch = new RAWrapper(naive, singleMode); + break; + case R_STAR_TREE: + raSearch = new RAWrapper(naive, singleMode); + break; + case X_TREE: + raSearch = new RAWrapper(naive, singleMode); + break; + case HILBERT_R_TREE: + raSearch = new RAWrapper(naive, singleMode); + break; + case R_PLUS_TREE: + raSearch = new RAWrapper(naive, singleMode); + break; + case R_PLUS_PLUS_TREE: + raSearch = new RAWrapper(naive, singleMode); + break; + case UB_TREE: + raSearch = new RAWrapper(naive, singleMode); + break; + case OCTREE: + raSearch = new LeafSizeRAWrapper(naive, singleMode); + break; + } + + raSearch->Train(std::move(referenceSet), leafSize); + + if (!naive) + { + Timer::Stop("tree_building"); + Log::Info << "Tree built." << std::endl; + } +} + +void RAModel::Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances) +{ + // Apply the random basis if necessary. + if (randomBasis) + querySet = q * querySet; + + Log::Info << "Searching for " << k << " approximate nearest neighbors with "; + if (!Naive() && !SingleMode()) + Log::Info << "dual-tree rank-approximate " << TreeName() << " search..."; + else if (!Naive()) + Log::Info << "single-tree rank-approximate " << TreeName() << " search..."; + else + Log::Info << "brute-force (naive) rank-approximate search..."; + Log::Info << std::endl; + + raSearch->Search(std::move(querySet), k, neighbors, distances, leafSize); +} + +void RAModel::Search(const size_t k, + arma::Mat& neighbors, + arma::mat& distances) +{ + Log::Info << "Searching for " << k << " approximate nearest neighbors with "; + if (!Naive() && !SingleMode()) + Log::Info << "dual-tree rank-approximate " << TreeName() << " search..."; + else if (!Naive()) + Log::Info << "single-tree rank-approximate " << TreeName() << " search..."; + else + Log::Info << "brute-force (naive) rank-approximate search..."; + Log::Info << std::endl; + + raSearch->Search(k, neighbors, distances); +} + +std::string RAModel::TreeName() const +{ + switch (treeType) + { + case KD_TREE: + return "kd-tree"; + case COVER_TREE: + return "cover tree"; + case R_TREE: + return "R tree"; + case R_STAR_TREE: + return "R* tree"; + case X_TREE: + return "X tree"; + case HILBERT_R_TREE: + return "Hilbert R tree"; + case R_PLUS_TREE: + return "R+ tree"; + case R_PLUS_PLUS_TREE: + return "R++ tree"; + case UB_TREE: + return "UB tree"; + case OCTREE: + return "octree"; + default: + return "unknown tree"; + } +} + +} // namespace neighbor +} // namespace mlpack diff --git a/src/mlpack/methods/rann/ra_model.hpp b/src/mlpack/methods/rann/ra_model.hpp index ed32d4a352..afe42bf3da 100644 --- a/src/mlpack/methods/rann/ra_model.hpp +++ b/src/mlpack/methods/rann/ra_model.hpp @@ -25,238 +25,228 @@ namespace mlpack { namespace neighbor { /** - * Alias template for RASearch + * RAWrapperBase is a base wrapper class for holding all RASearch types + * supported by RAModel. All RASearch type wrappers inherit from this class, + * allowing a simple interface via inheritance for all the different types we + * want to support. */ -template& neighbors, + arma::mat& distances, + const size_t leafSize) = 0; + + //! Perform monochromatic rank-approximate nearest neighbor search (i.e. a + //! search with the reference set as the query set). + virtual void Search(const size_t k, + arma::Mat& neighbors, + arma::mat& distances) = 0; +}; + +/** + * RAWrapper is a wrapper class for most RASearch types. + */ +template class TreeType> -using RAType = RASearch; - -/** - * MonoSearchVisitor executes a monochromatic neighbor search on the given - * RAType. We don't make any difference for different instantiation of RAType. - */ -class MonoSearchVisitor : public boost::static_visitor +class RAWrapper : public RAWrapperBase { - private: - //! Number of neighbors to search for. - const size_t k; - //! Result matrix for neighbors. - arma::Mat& neighbors; - //! Result matrix for distances. - arma::mat& distances; - public: - //! Perform monochromatic nearest neighbor search. - template - void operator()(RAType* ra) const; + //! Construct the RAWrapper object, initializing the internally-held RASearch + //! object. + RAWrapper(const bool singleMode, const bool naive) : + ra(singleMode, naive) + { + // Nothing else to do. + } - //! Construct the MonoSearchVisitor object with the given parameters. - MonoSearchVisitor(const size_t k, - arma::Mat& neighbors, - arma::mat& distances) : - k(k), - neighbors(neighbors), - distances(distances) - {}; + //! Delete the RAWrapper object. + virtual ~RAWrapper() { } + + //! Create a copy of this RAWrapper object. This correctly handles + //! polymorphism. + virtual RAWrapper* Clone() const { return new RAWrapper(*this); } + + //! Get a reference to the reference set. + const arma::mat& Dataset() const { return ra.ReferenceSet(); } + + //! Get the single sample limit. + size_t SingleSampleLimit() const { return ra.SingleSampleLimit(); } + //! Modify the single sample limit. + size_t& SingleSampleLimit() { return ra.SingleSampleLimit(); } + + //! Get whether to do exact search at the first leaf. + bool FirstLeafExact() const { return ra.FirstLeafExact(); } + //! Modify whether to do exact search at the first leaf. + bool& FirstLeafExact() { return ra.FirstLeafExact(); } + + //! Get whether to do sampling at leaves. + bool SampleAtLeaves() const { return ra.SampleAtLeaves(); } + //! Modify whether to do sampling at leaves. + bool& SampleAtLeaves() { return ra.SampleAtLeaves(); } + + //! Get the value of alpha. + double Alpha() const { return ra.Alpha(); } + //! Modify the value of alpha. + double& Alpha() { return ra.Alpha(); } + + //! Get the value of tau. + double Tau() const { return ra.Tau(); } + //! Modify the value of tau. + double& Tau() { return ra.Tau(); } + + //! Get whether single-tree search is being used. + bool SingleMode() const { return ra.SingleMode(); } + //! Modify whether single-tree search is being used. + bool& SingleMode() { return ra.SingleMode(); } + + //! Get whether naive search is being used. + bool Naive() const { return ra.Naive(); } + //! Modify whether naive search is being used. + bool& Naive() { return ra.Naive(); } + + //! Train the model. For RAWrapper, we ignore the leaf size. + virtual void Train(arma::mat&& referenceSet, + const size_t /* leafSize */); + + //! Perform bichromatic neighbor search (i.e. search with a separate query + //! set). For RAWrapper, we ignore the leaf size. + virtual void Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t /* leafSize */); + + //! Perform monochromatic neighbor search (i.e. search where the reference set + //! is used as the query set). + virtual void Search(const size_t k, + arma::Mat& neighbors, + arma::mat& distances); + + //! Serialize the RASearch model. + template + void serialize(Archive& ar, const uint32_t /* version */) + { + ar(CEREAL_NVP(ra)); + } + + protected: + typedef RASearch RAType; + + //! The instantiated RASearch object that we are wrapping. + RAType ra; }; /** - * BiSearchVisitor executes a bichromatic neighbor search on the given RAType. - * We use template specialization to differentiate those tree types types that - * accept leafSize as a parameter. In these cases, before doing neighbor search - * a query tree with proper leafSize is built from the querySet. + * LeafSizeRAWrapper wraps any RASearch type that needs to be able to take the + * leaf size into account when building trees. The implementations of Train() + * and bichromatic Search() take this leaf size into account. */ -template -class BiSearchVisitor : public boost::static_visitor -{ - private: - //! The query set for the bichromatic search. - const arma::mat& querySet; - //! The number of neighbors to search for. - const size_t k; - //! The results matrix for neighbors. - arma::Mat& neighbors; - //! The result matrix for distances. - arma::mat& distances; - //! The number of points in a leaf (for BinarySpaceTrees). - const size_t leafSize; - - //! Bichromatic neighbor search on the given RAType considering leafSize. - template - void SearchLeaf(RAType* ra) const; - - public: - //! Alias template necessary for visual c++ compiler. - template class TreeType> - using RATypeT = RAType; - - //! Default Bichromatic neighbor search on the given RAType instance. - template class TreeType> - void operator()(RATypeT* ra) const; - - //! Bichromatic search on the given RAType specialized for KDTrees. - void operator()(RATypeT* ra) const; - - //! Bichromatic search on the given RAType specialized for octrees. - void operator()(RATypeT* ra) const; - - //! Construct the BiSearchVisitor. - BiSearchVisitor(const arma::mat& querySet, - const size_t k, - arma::Mat& neighbors, - arma::mat& distances, - const size_t leafSize); -}; - -/** - * TrainVisitor sets the reference set to a new reference set on the given - * RAType. We use template specialization to differentiate those trees that - * accept leafSize as a parameter. In these cases, a reference tree with proper - * leafSize is built from the referenceSet. - */ -template -class TrainVisitor : public boost::static_visitor -{ - private: - //! The reference set to use for training. - arma::mat&& referenceSet; - //! The leaf size, used only by BinarySpaceTree. - size_t leafSize; - - //! Train on the given RAType considering the leafSize. - template - void TrainLeaf(RAType* ra) const; - - public: - //! Alias template necessary for visual c++ compiler. - template class TreeType> - using RATypeT = RAType; - - //! Default Train on the given RAType instance. - template class TreeType> - void operator()(RATypeT* ra) const; - - //! Train on the given RAType specialized for KDTrees. - void operator()(RATypeT* ra) const; - - //! Train on the given RAType specialized for Octrees. - void operator()(RATypeT* ra) const; - - //! Construct the TrainVisitor object with the given reference set, leafSize - //! for BinarySpaceTrees. - TrainVisitor(arma::mat&& referenceSet, - const size_t leafSize); -}; - -/** - * Exposes the SingleSampleLimit() method of the given RAType. - */ -class SingleSampleLimitVisitor : public boost::static_visitor +template class TreeType> +class LeafSizeRAWrapper : public RAWrapper { public: - template - size_t& operator()(RAType* ra) const; -}; + //! Construct the LeafSizeRAWrapper by delegating to the RAWrapper + //! constructor. + LeafSizeRAWrapper(const bool singleMode, const bool naive) : + RAWrapper(singleMode, naive) + { + // Nothing else to do. + } -/** - * Exposes the FirstLeafExact() method of the given RAType. - */ -class FirstLeafExactVisitor : public boost::static_visitor -{ - public: - template - bool& operator()(RAType* ra) const; -}; + //! Delete the LeafSizeRAWrapper. + virtual ~LeafSizeRAWrapper() { } -/** - * Exposes the SampleAtLeaves() method of the given RAType. - */ -class SampleAtLeavesVisitor : public boost::static_visitor -{ - public: - //! Return SampleAtLeaves (whether or not sampling is done at leaves). - template - bool& operator()(RAType *) const; -}; + //! Return a copy of the LeafSizeRAWrapper. + virtual LeafSizeRAWrapper* Clone() const + { + return new LeafSizeRAWrapper(*this); + } -/** - * Exposes the Alpha() method of the given RAType. - */ -class AlphaVisitor : public boost::static_visitor -{ - public: - //! Return Alpha parameter. - template - double& operator()(RAType* ra) const; -}; + //! Train a model with the given parameters. This overload uses leafSize. + virtual void Train(arma::mat&& referenceSet, + const size_t leafSize); -/** - * Exposes the Tau() method of the given RAType. - */ -class TauVisitor : public boost::static_visitor -{ - public: - //! Get a reference to the Tau parameter. - template - double& operator()(RAType* ra) const; -}; + //! Perform bichromatic search (e.g. search with a separate query set). This + //! overload takes the leaf size into account to build the query tree. + virtual void Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t leafSize); -/** - * Exposes the SingleMode() method of the given RAType. - */ -class SingleModeVisitor : public boost::static_visitor -{ - public: - //! Get a reference to the SingleMode parameter of the given RASearch object. - template - bool& operator()(RAType* ra) const; -}; + //! Serialize the RASearch model. + template + void serialize(Archive& ar, const uint32_t /* version */) + { + ar(CEREAL_NVP(ra)); + } -/** - * Exposes the referenceSet of the given RAType. - */ -class ReferenceSetVisitor : public boost::static_visitor -{ - public: - //! Return the reference set. - template - const arma::mat& operator()(RAType* ra) const; -}; - -/** - * DeleteVisitor deletes the give RAType Instance. - */ -class DeleteVisitor : public boost::static_visitor -{ - public: - //! Delete the RAType Object. - template void operator()(RAType* ra) const; -}; - -/** - * NaiveVisitor exposes the Naive() method of the given RAType. - */ -class NaiveVisitor : public boost::static_visitor -{ - public: - /** - * Get a reference to the naive parameter of the given RASearch object. - */ - template - bool& operator()(RAType* ra) const; + protected: + using RAWrapper::ra; }; /** @@ -264,10 +254,7 @@ class NaiveVisitor : public boost::static_visitor * away the TreeType parameter and allowing it to be specified at runtime in * this class. This class is written for the sake of the 'allkrann' program, * but is not necessarily restricted to that use. - * - * @param SortPolicy Sorting policy for neighbor searching (see RASearch). */ -template class RAModel { public: @@ -301,16 +288,7 @@ class RAModel arma::mat q; //! The rank-approximate model. - boost::variant*, - RAType*, - RAType*, - RAType*, - RAType*, - RAType*, - RAType*, - RAType*, - RAType*, - RAType*> raSearch; + RAWrapperBase* raSearch; public: /** @@ -355,58 +333,58 @@ class RAModel void serialize(Archive& ar, const uint32_t /* version */); //! Expose the dataset. - const arma::mat& Dataset() const; + const arma::mat& Dataset() const { return raSearch->Dataset(); } //! Get whether or not single-tree search is being used. - bool SingleMode() const; + bool SingleMode() const { return raSearch->SingleMode(); } //! Modify whether or not single-tree search is being used. - bool& SingleMode(); + bool& SingleMode() { return raSearch->SingleMode(); } //! Get whether or not naive search is being used. - bool Naive() const; + bool Naive() const { return raSearch->Naive(); } //! Modify whether or not naive search is being used. - bool& Naive(); + bool& Naive() { return raSearch->Naive(); } //! Get the rank-approximation in percentile of the data. - double Tau() const; + double Tau() const { return raSearch->Tau(); } //! Modify the rank-approximation in percentile of the data. - double& Tau(); + double& Tau() { return raSearch->Tau(); } //! Get the desired success probability. - double Alpha() const; + double Alpha() const { return raSearch->Alpha(); } //! Modify the desired success probability. - double& Alpha(); + double& Alpha() { return raSearch->Alpha(); } //! Get whether or not sampling is done at the leaves. - bool SampleAtLeaves() const; + bool SampleAtLeaves() const { return raSearch->SampleAtLeaves(); } //! Modify whether or not sampling is done at the leaves. - bool& SampleAtLeaves(); + bool& SampleAtLeaves() { return raSearch->SampleAtLeaves(); } //! Get whether or not we traverse to the first leaf without approximation. - bool FirstLeafExact() const; + bool FirstLeafExact() const { return raSearch->FirstLeafExact(); } //! Modify whether or not we traverse to the first leaf without approximation. - bool& FirstLeafExact(); + bool& FirstLeafExact() { return raSearch->FirstLeafExact(); } //! Get the limit on the size of a node that can be approximated. - size_t SingleSampleLimit() const; + size_t SingleSampleLimit() const { return raSearch->SingleSampleLimit(); } //! Modify the limit on the size of a node that can be approximation. - size_t& SingleSampleLimit(); + size_t& SingleSampleLimit() { return raSearch->SingleSampleLimit(); } //! Get the leaf size (only relevant when the kd-tree is used). - size_t LeafSize() const; + size_t LeafSize() const { return leafSize; } //! Modify the leaf size (only relevant when the kd-tree is used). - size_t& LeafSize(); + size_t& LeafSize() { return leafSize; } //! Get the type of tree being used. - TreeTypes TreeType() const; + TreeTypes TreeType() const { return treeType; } //! Modify the type of tree being used. - TreeTypes& TreeType(); + TreeTypes& TreeType() { return treeType; } //! Get whether or not a random basis is being used. - bool RandomBasis() const; + bool RandomBasis() const { return randomBasis; } //! Modify whether or not a random basis is being used. Be sure to rebuild //! the model using BuildModel(). - bool& RandomBasis(); + bool& RandomBasis() { return randomBasis; } //! Build the reference tree. void BuildModel(arma::mat&& referenceSet, diff --git a/src/mlpack/methods/rann/ra_model_impl.hpp b/src/mlpack/methods/rann/ra_model_impl.hpp index 3b27bfa2d6..6955bd9f46 100644 --- a/src/mlpack/methods/rann/ra_model_impl.hpp +++ b/src/mlpack/methods/rann/ra_model_impl.hpp @@ -19,78 +19,87 @@ namespace mlpack { namespace neighbor { -//! Monochromatic search for the given RAType instance. -template -void MonoSearchVisitor::operator()(RAType* ra) const -{ - if (ra) - return ra->Search(k, neighbors, distances); - throw std::runtime_error("no rank-approximate model initialized"); -} - -//! Save the parameters for the rank-approximate search. -template -BiSearchVisitor::BiSearchVisitor(const arma::mat& querySet, - const size_t k, - arma::Mat& neighbors, - arma::mat& distances, - const size_t leafSize) : - querySet(querySet), - k(k), - neighbors(neighbors), - distances(distances), - leafSize(leafSize) -{}; - -//! Default Bichromatic search on the given RAType instance. -template template class TreeType> -void BiSearchVisitor::operator()(RATypeT* ra) const +void RAWrapper::Train(arma::mat&& referenceSet, + const size_t /* leafSize */) { - if (ra) - return ra->Search(querySet, k, neighbors, distances); - throw std::runtime_error("no rank-approximate model initialized"); + ra.Train(std::move(referenceSet)); } -//! Bichromatic search on the given RAType specialized for KDTrees. -template -void BiSearchVisitor::operator()(RATypeT* ra) const +template class TreeType> +void RAWrapper::Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t /* leafSize */) { - if (ra) - return SearchLeaf(ra); - throw std::runtime_error("no rank-approximate search model initialized"); + ra.Search(querySet, k, neighbors, distances); } -//! Bichromatic search on the given RAType specialized for Octrees. -template -void BiSearchVisitor::operator()(RATypeT* ra) const +template class TreeType> +void RAWrapper::Search(const size_t k, + arma::Mat& neighbors, + arma::mat& distances) { - if (ra) - return SearchLeaf(ra); - throw std::runtime_error("no rank-approximate search model initialized"); + ra.Search(k, neighbors, distances); } -//! Bichromatic search on the given RAType considering the leafSize. -template -template -void BiSearchVisitor::SearchLeaf(RAType* ra) const +template class TreeType> +void LeafSizeRAWrapper::Train(arma::mat&& referenceSet, + const size_t leafSize) { - if (!ra->Naive() && !ra->SingleMode()) + // Build tree, if necessary. + if (ra.Naive()) { - // Build a second tree and search + ra.Train(std::move(referenceSet)); + } + else + { + std::vector oldFromNewReferences; + typename decltype(ra)::Tree* tree = + new typename decltype(ra)::Tree(std::move(referenceSet), + oldFromNewReferences, + leafSize); + ra.Train(tree); + + // Give the model ownership of the tree and the mappings. + ra.treeOwner = true; + ra.oldFromNewReferences = std::move(oldFromNewReferences); + } +} + +template class TreeType> +void LeafSizeRAWrapper::Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t leafSize) +{ + if (!ra.Naive() && !ra.SingleMode()) + { + // Build a second tree and search, taking the leaf size into account. Timer::Start("tree_building"); Log::Info << "Building query tree...."<< std::endl; std::vector oldFromNewQueries; - typename RAType::Tree queryTree(std::move(querySet), oldFromNewQueries, - leafSize); - Log::Info << "Tree Built." << std::endl; + typename decltype(ra)::Tree queryTree(std::move(querySet), + oldFromNewQueries, + leafSize); + Log::Info << "Tree built." << std::endl; Timer::Stop("tree_building"); arma::Mat neighborsOut; arma::mat distancesOut; - ra->Search(&queryTree, k, neighborsOut, distancesOut); + ra.Search(&queryTree, k, neighborsOut, distancesOut); // Unmap the query points. distances.set_size(distancesOut.n_rows, distancesOut.n_cols); @@ -104,236 +113,12 @@ void BiSearchVisitor::SearchLeaf(RAType* ra) const else { // Search without building a second tree. - ra->Search(querySet, k, neighbors, distances); + ra.Search(querySet, k, neighbors, distances); } } -//! Save parameters for the Train. -template -TrainVisitor::TrainVisitor(arma::mat&& referenceSet, - const size_t leafSize) : - referenceSet(std::move(referenceSet)), - leafSize(leafSize) -{}; - -//! Default Train on the given RAType instance. -template -template class TreeType> -void TrainVisitor::operator()(RATypeT* ra) const -{ - if (ra) - return ra->Train(std::move(referenceSet)); - throw std::runtime_error("no rank-approximate search model initialized"); -} - -//! Train on the given RAType specialized for KDTrees. -template -void TrainVisitor::operator()(RATypeT* ra) const -{ - if (ra) - return TrainLeaf(ra); - throw std::runtime_error("no rank-approximate search model initialized"); -} - -//! Train on the given RAType specialized for Octrees. -template -void TrainVisitor::operator()(RATypeT* ra) const -{ - if (ra) - return TrainLeaf(ra); - throw std::runtime_error("no rank-approximate search model is initialized"); -} - -//! Train on the given RAType considering the leafSize. -template -template -void TrainVisitor::TrainLeaf(RAType* ra) const -{ - // Build tree, if necessary - if (ra->Naive()) - { - ra->Train(std::move(referenceSet)); - } - else - { - std::vector oldFromNewReferences; - typename RAType::Tree* tree = - new typename RAType::Tree(std::move(referenceSet), oldFromNewReferences, - leafSize); - ra->Train(tree); - - // Give the model ownership of the tree and the mappings. - ra->treeOwner = true; - ra->oldFromNewReferences = std::move(oldFromNewReferences); - } -} - -//! Exposes the SingleSampleLimit() method of the given RAType. -template -size_t& SingleSampleLimitVisitor::operator()(RAType* ra) const -{ - if (ra) - return ra->SingleSampleLimit(); - throw std::runtime_error("no rank-approximate search model is initialized"); -} - -//! Exposes the FirstLeafExact() method of the given RAType. -template -bool& FirstLeafExactVisitor::operator()(RAType* ra) const -{ - if (ra) - return ra->FirstLeafExact(); - throw std::runtime_error("no rank-approximate search model is initialized"); -} - -//! Exposes the SampleAtLeaves() method of the given RAType. -template -bool& SampleAtLeavesVisitor::operator()(RAType* ra) const -{ - if (ra) - return ra->SampleAtLeaves(); - throw std::runtime_error("no rank-approximate search model is initialized"); -} - -//! Exposes the Alpha() method of the given RAType instance. -template -double& AlphaVisitor::operator()(RAType* ra) const -{ - if (ra) - return ra->Alpha(); - throw std::runtime_error("no rank-approximate model is initialized"); -} - -//! Exposes the Tau() method of the given RAType instance. -template -double& TauVisitor::operator()(RAType* ra) const -{ - if (ra) - return ra->Tau(); - throw std::runtime_error("no rank-approximate model is initialized"); -} - -//! Exposes the SingleMode() method of the given RAType. -template -bool& SingleModeVisitor::operator()(RAType* ra) const -{ - if (ra) - return ra->SingleMode(); - throw std::runtime_error("no rank-approximate model is initialized"); -} - -//! Exposes the referenceSet of the given RAType. -template -const arma::mat& ReferenceSetVisitor::operator()(RAType* ra) const -{ - if (ra) - return ra->ReferenceSet(); - throw std::runtime_error("no rank-approximate model is initialized"); -} - -//! Exposes the Naive() method of the given RAType instance. -template -bool& NaiveVisitor::operator()(RAType* ra) const -{ - if (ra) - return ra->Naive(); - throw std::runtime_error("no rank-approximate search model is initialized"); -} - -//! For cleaning memory -template -void DeleteVisitor::operator()(RSType* rs) const -{ - if (rs) - delete rs; -} - -template -RAModel::RAModel(const TreeTypes treeType, const bool randomBasis) : - treeType(treeType), - leafSize(20), - randomBasis(randomBasis) -{ - // Nothing to do. -} - -// Copy constructor. -template -RAModel::RAModel(const RAModel& other) : - treeType(other.treeType), - leafSize(other.leafSize), - randomBasis(other.randomBasis), - q(other.q), - raSearch(other.raSearch) -{ - // Nothing to do. -} - -// Move constructor. -template -RAModel::RAModel(RAModel&& other) : - treeType(other.treeType), - leafSize(other.leafSize), - randomBasis(other.randomBasis), - q(std::move(other.q)), - raSearch(std::move(other.raSearch)) -{ - // Clear other model. - other.treeType = TreeTypes::KD_TREE; - other.leafSize = 20; - other.randomBasis = false; - other.raSearch = decltype(other.raSearch)(); -} - -// Copy operator. -template -RAModel& RAModel::operator=(const RAModel& other) -{ - // Clear current model. - boost::apply_visitor(DeleteVisitor(), raSearch); - - treeType = other.treeType; - leafSize = other.leafSize; - randomBasis = other.randomBasis; - q = other.q; - raSearch = other.raSearch; - - return *this; -} - -template -RAModel& RAModel::operator=(RAModel&& other) -{ - boost::apply_visitor(DeleteVisitor(), raSearch); - - treeType = other.treeType; - leafSize = other.leafSize; - randomBasis = other.randomBasis; - q = std::move(other.q); - raSearch = std::move(other.raSearch); - - // Reset other model. - other.treeType = TreeTypes::KD_TREE; - other.leafSize = 20; - other.randomBasis = false; - other.raSearch = decltype(other.raSearch)(); - - return *this; -} - -// Clean memory, if necessary -template -RAModel::~RAModel() -{ - boost::apply_visitor(DeleteVisitor(), raSearch); -} - -template template -void RAModel::serialize(Archive& ar, - const uint32_t /* version */) +void RAModel::serialize(Archive& ar, const uint32_t /* version */) { ar(CEREAL_NVP(treeType)); ar(CEREAL_NVP(randomBasis)); @@ -342,281 +127,82 @@ void RAModel::serialize(Archive& ar, // This should never happen, but just in case, be clean with memory. if (cereal::is_loading()) { - boost::apply_visitor(DeleteVisitor(), raSearch); - } - - // We only need to serialize one of the kRANN objects. - ar(CEREAL_VARIANT_POINTER(raSearch)); -} - -template -const arma::mat& RAModel::Dataset() const -{ - return boost::apply_visitor(ReferenceSetVisitor(), raSearch); -} - -template -bool RAModel::Naive() const -{ - return boost::apply_visitor(NaiveVisitor(), raSearch); -} - -template -bool& RAModel::Naive() -{ - return boost::apply_visitor(NaiveVisitor(), raSearch); -} - -template -bool RAModel::SingleMode() const -{ - return boost::apply_visitor(SingleModeVisitor(), raSearch); -} - -template -bool& RAModel::SingleMode() -{ - return boost::apply_visitor(SingleModeVisitor(), raSearch); -} - -template -double RAModel::Tau() const -{ - return boost::apply_visitor(TauVisitor(), raSearch); -} - -template -double& RAModel::Tau() -{ - return boost::apply_visitor(TauVisitor(), raSearch); -} - -template -double RAModel::Alpha() const -{ - return boost::apply_visitor(AlphaVisitor(), raSearch); -} - -template -double& RAModel::Alpha() -{ - return boost::apply_visitor(AlphaVisitor(), raSearch); -} - -template -bool RAModel::SampleAtLeaves() const -{ - return boost::apply_visitor(SampleAtLeavesVisitor(), raSearch); -} - -template -bool& RAModel::SampleAtLeaves() -{ - return boost::apply_visitor(SampleAtLeavesVisitor(), raSearch); -} - -template -bool RAModel::FirstLeafExact() const -{ - return boost::apply_visitor(FirstLeafExactVisitor(), raSearch); -} - -template -bool& RAModel::FirstLeafExact() -{ - return boost::apply_visitor(FirstLeafExactVisitor(), raSearch); -} - -template -size_t RAModel::SingleSampleLimit() const -{ - return boost::apply_visitor(SingleSampleLimitVisitor(), raSearch); -} - -template -size_t& RAModel::SingleSampleLimit() -{ - return boost::apply_visitor(SingleSampleLimitVisitor(), raSearch); -} - -template -size_t RAModel::LeafSize() const -{ - return leafSize; -} - -template -size_t& RAModel::LeafSize() -{ - return leafSize; -} - -template -typename RAModel::TreeTypes RAModel::TreeType() const -{ - return treeType; -} - -template -typename RAModel::TreeTypes& RAModel::TreeType() -{ - return treeType; -} - -template -bool RAModel::RandomBasis() const -{ - return randomBasis; -} - -template -bool& RAModel::RandomBasis() -{ - return randomBasis; -} - -template -void RAModel::BuildModel(arma::mat&& referenceSet, - const size_t leafSize, - const bool naive, - const bool singleMode) -{ - // Initialize random basis, if necessary. - if (randomBasis) - { - Log::Info << "Creating random basis..." << std::endl; - math::RandomBasis(q, referenceSet.n_rows); - } - - // Clean memory, if necessary. - boost::apply_visitor(DeleteVisitor(), raSearch); - - this->leafSize = leafSize; - - if (randomBasis) - referenceSet = q * referenceSet; - - if (!naive) - { - Timer::Start("tree_building"); - Log::Info << "Building reference tree..." << std::endl; + delete raSearch; } + // Avoid polymorphic serialization by explicitly serializing the correct type. switch (treeType) { case KD_TREE: - raSearch = new RAType(naive, singleMode); - break; + { + LeafSizeRAWrapper& typedSearch = + dynamic_cast&>(*raSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } case COVER_TREE: - raSearch = new RAType(naive, - singleMode); - break; + { + RAWrapper& typedSearch = + dynamic_cast&>(*raSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } case R_TREE: - raSearch = new RAType(naive, singleMode); - break; + { + RAWrapper& typedSearch = + dynamic_cast&>(*raSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } case R_STAR_TREE: - raSearch = new RAType(naive, singleMode); - break; + { + RAWrapper& typedSearch = + dynamic_cast&>(*raSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } case X_TREE: - raSearch = new RAType(naive, singleMode); - break; + { + RAWrapper& typedSearch = + dynamic_cast&>(*raSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } case HILBERT_R_TREE: - raSearch = new RAType(naive, singleMode); - break; + { + RAWrapper& typedSearch = + dynamic_cast&>(*raSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } case R_PLUS_TREE: - raSearch = new RAType(naive, singleMode); - break; + { + RAWrapper& typedSearch = + dynamic_cast&>(*raSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } case R_PLUS_PLUS_TREE: - raSearch = new RAType(naive, - singleMode); - break; + { + RAWrapper& typedSearch = + dynamic_cast&>(*raSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } case UB_TREE: - raSearch = new RAType(naive, singleMode); - break; + { + RAWrapper& typedSearch = + dynamic_cast&>(*raSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } case OCTREE: - raSearch = new RAType(naive, singleMode); - break; - } - - TrainVisitor tn(std::move(referenceSet), leafSize); - boost::apply_visitor(tn, raSearch); - - if (!naive) - { - Timer::Stop("tree_building"); - Log::Info << "Tree built." << std::endl; - } -} - -template -void RAModel::Search(arma::mat&& querySet, - const size_t k, - arma::Mat& neighbors, - arma::mat& distances) -{ - // Apply the random basis if necessary. - if (randomBasis) - querySet = q * querySet; - - Log::Info << "Searching for " << k << " approximate nearest neighbors with "; - if (!Naive() && !SingleMode()) - Log::Info << "dual-tree rank-approximate " << TreeName() << " search..."; - else if (!Naive()) - Log::Info << "single-tree rank-approximate " << TreeName() << " search..."; - else - Log::Info << "brute-force (naive) rank-approximate search..."; - Log::Info << std::endl; - - BiSearchVisitor search(querySet, k, neighbors, distances, - leafSize); - boost::apply_visitor(search, raSearch); -} - -template -void RAModel::Search(const size_t k, - arma::Mat& neighbors, - arma::mat& distances) -{ - Log::Info << "Searching for " << k << " approximate nearest neighbors with "; - if (!Naive() && !SingleMode()) - Log::Info << "dual-tree rank-approximate " << TreeName() << " search..."; - else if (!Naive()) - Log::Info << "single-tree rank-approximate " << TreeName() << " search..."; - else - Log::Info << "brute-force (naive) rank-approximate search..."; - Log::Info << std::endl; - - MonoSearchVisitor search(k, neighbors, distances); - boost::apply_visitor(search, raSearch); -} - -template -std::string RAModel::TreeName() const -{ - switch (treeType) - { - case KD_TREE: - return "kd-tree"; - case COVER_TREE: - return "cover tree"; - case R_TREE: - return "R tree"; - case R_STAR_TREE: - return "R* tree"; - case X_TREE: - return "X tree"; - case HILBERT_R_TREE: - return "Hilbert R tree"; - case R_PLUS_TREE: - return "R+ tree"; - case R_PLUS_PLUS_TREE: - return "R++ tree"; - case UB_TREE: - return "UB tree"; - case OCTREE: - return "octree"; - default: - return "unknown tree"; + { + LeafSizeRAWrapper& typedSearch = + dynamic_cast&>(*raSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } } } diff --git a/src/mlpack/methods/rann/ra_search.hpp b/src/mlpack/methods/rann/ra_search.hpp index da3f61c48d..634260c213 100644 --- a/src/mlpack/methods/rann/ra_search.hpp +++ b/src/mlpack/methods/rann/ra_search.hpp @@ -39,8 +39,10 @@ namespace mlpack { namespace neighbor { // Forward declaration. -template -class TrainVisitor; +template class TreeType> +class LeafSizeRAWrapper; /** * The RASearch class: This class provides a generic manner to perform @@ -394,8 +396,7 @@ class RASearch MetricType metric; //! For access to mappings when building models. - template - friend class TrainVisitor; + friend class LeafSizeRAWrapper; }; // class RASearch } // namespace neighbor diff --git a/src/mlpack/tests/krann_search_test.cpp b/src/mlpack/tests/krann_search_test.cpp index 4efa022776..411e08a025 100644 --- a/src/mlpack/tests/krann_search_test.cpp +++ b/src/mlpack/tests/krann_search_test.cpp @@ -620,34 +620,32 @@ TEST_CASE("RAModelTest", "[KRANNTest]") { // Ensure that we can build an RAModel and get correct // results. - typedef RAModel KNNModel; - arma::mat queryData, referenceData; data::Load("rann_test_r_3_900.csv", referenceData, true); data::Load("rann_test_q_3_100.csv", queryData, true); // Build all the possible models. - KNNModel models[20]; - models[0] = KNNModel(KNNModel::TreeTypes::KD_TREE, false); - models[1] = KNNModel(KNNModel::TreeTypes::KD_TREE, true); - models[2] = KNNModel(KNNModel::TreeTypes::COVER_TREE, false); - models[3] = KNNModel(KNNModel::TreeTypes::COVER_TREE, true); - models[4] = KNNModel(KNNModel::TreeTypes::R_TREE, false); - models[5] = KNNModel(KNNModel::TreeTypes::R_TREE, true); - models[6] = KNNModel(KNNModel::TreeTypes::R_STAR_TREE, false); - models[7] = KNNModel(KNNModel::TreeTypes::R_STAR_TREE, true); - models[8] = KNNModel(KNNModel::TreeTypes::X_TREE, false); - models[9] = KNNModel(KNNModel::TreeTypes::X_TREE, true); - models[10] = KNNModel(KNNModel::TreeTypes::HILBERT_R_TREE, false); - models[11] = KNNModel(KNNModel::TreeTypes::HILBERT_R_TREE, true); - models[12] = KNNModel(KNNModel::TreeTypes::R_PLUS_TREE, false); - models[13] = KNNModel(KNNModel::TreeTypes::R_PLUS_TREE, true); - models[14] = KNNModel(KNNModel::TreeTypes::R_PLUS_PLUS_TREE, false); - models[15] = KNNModel(KNNModel::TreeTypes::R_PLUS_PLUS_TREE, true); - models[16] = KNNModel(KNNModel::TreeTypes::UB_TREE, false); - models[17] = KNNModel(KNNModel::TreeTypes::UB_TREE, true); - models[18] = KNNModel(KNNModel::TreeTypes::OCTREE, false); - models[19] = KNNModel(KNNModel::TreeTypes::OCTREE, true); + RAModel models[20]; + models[0] = RAModel(RAModel::TreeTypes::KD_TREE, false); + models[1] = RAModel(RAModel::TreeTypes::KD_TREE, true); + models[2] = RAModel(RAModel::TreeTypes::COVER_TREE, false); + models[3] = RAModel(RAModel::TreeTypes::COVER_TREE, true); + models[4] = RAModel(RAModel::TreeTypes::R_TREE, false); + models[5] = RAModel(RAModel::TreeTypes::R_TREE, true); + models[6] = RAModel(RAModel::TreeTypes::R_STAR_TREE, false); + models[7] = RAModel(RAModel::TreeTypes::R_STAR_TREE, true); + models[8] = RAModel(RAModel::TreeTypes::X_TREE, false); + models[9] = RAModel(RAModel::TreeTypes::X_TREE, true); + models[10] = RAModel(RAModel::TreeTypes::HILBERT_R_TREE, false); + models[11] = RAModel(RAModel::TreeTypes::HILBERT_R_TREE, true); + models[12] = RAModel(RAModel::TreeTypes::R_PLUS_TREE, false); + models[13] = RAModel(RAModel::TreeTypes::R_PLUS_TREE, true); + models[14] = RAModel(RAModel::TreeTypes::R_PLUS_PLUS_TREE, false); + models[15] = RAModel(RAModel::TreeTypes::R_PLUS_PLUS_TREE, true); + models[16] = RAModel(RAModel::TreeTypes::UB_TREE, false); + models[17] = RAModel(RAModel::TreeTypes::UB_TREE, true); + models[18] = RAModel(RAModel::TreeTypes::OCTREE, false); + models[19] = RAModel(RAModel::TreeTypes::OCTREE, true); arma::Mat qrRanks; data::Load("rann_test_qr_ranks.csv", qrRanks, true, false); // No transpose. diff --git a/src/mlpack/tests/main_tests/krann_test.cpp b/src/mlpack/tests/main_tests/krann_test.cpp index b61044f104..57cb0905d6 100644 --- a/src/mlpack/tests/main_tests/krann_test.cpp +++ b/src/mlpack/tests/main_tests/krann_test.cpp @@ -192,7 +192,7 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNRefModelTest", // Input pre-trained model. SetInputParam("input_model", - std::move(IO::GetParam("output_model"))); + std::move(IO::GetParam("output_model"))); Log::Fatal.ignoreInput = true; REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error); @@ -285,10 +285,10 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNModelReuseTest", arma::Mat neighbors; arma::mat distances; - RANNModel* output_model; + RAModel* output_model; neighbors = std::move(IO::GetParam>("neighbors")); distances = std::move(IO::GetParam("distances")); - output_model = std::move(IO::GetParam("output_model")); + output_model = std::move(IO::GetParam("output_model")); // Reset passed parameters. IO::GetSingleton().Parameters()["reference"].wasPassed = false; @@ -324,8 +324,8 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentLeafSizes", mlpack::math::FixedRandomSeed(); mlpackMain(); - RANNModel* output_model; - output_model = std::move(IO::GetParam("output_model")); + RAModel* output_model; + output_model = std::move(IO::GetParam("output_model")); // Reset passed parameters. IO::GetSingleton().Parameters()["reference"].wasPassed = false; @@ -341,7 +341,7 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentLeafSizes", // Check that initial output matrices and the output matrices using // saved model are equal. CHECK(output_model->LeafSize() == (int) 1); - CHECK(IO::GetParam("output_model")->LeafSize() == (int) 10); + CHECK(IO::GetParam("output_model")->LeafSize() == (int) 10); delete output_model; } @@ -361,8 +361,8 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentTau", mlpack::math::FixedRandomSeed(); mlpackMain(); - RANNModel* output_model; - output_model = std::move(IO::GetParam("output_model")); + RAModel* output_model; + output_model = std::move(IO::GetParam("output_model")); // Reset the passed parameters. IO::GetSingleton().Parameters()["reference"].wasPassed = false; @@ -378,7 +378,7 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentTau", // Check that initial output matrices and the output matrices using // saved model are equal CHECK(output_model->Tau() == (double) 5); - CHECK(IO::GetParam("output_model")->Tau() == + CHECK(IO::GetParam("output_model")->Tau() == (double) 10); delete output_model; } @@ -399,8 +399,8 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentAlpha", mlpack::math::FixedRandomSeed(); mlpackMain(); - RANNModel* output_model; - output_model = std::move(IO::GetParam("output_model")); + RAModel* output_model; + output_model = std::move(IO::GetParam("output_model")); // Reset the passed parameters. IO::GetSingleton().Parameters()["reference"].wasPassed = false; @@ -416,7 +416,7 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentAlpha", // Check that initial output matrices and the output matrices using // saved model are equal CHECK(output_model->Alpha() == (double) 0.95); - CHECK(IO::GetParam("output_model")->Alpha() == + CHECK(IO::GetParam("output_model")->Alpha() == (double) 0.80); delete output_model; } @@ -437,8 +437,8 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentTreeType", mlpack::math::FixedRandomSeed(); mlpackMain(); - RANNModel* output_model; - output_model = std::move(IO::GetParam("output_model")); + RAModel* output_model; + output_model = std::move(IO::GetParam("output_model")); // Reset the passed parameters. IO::GetSingleton().Parameters()["reference"].wasPassed = false; @@ -455,7 +455,7 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentTreeType", // saved model are equal const bool check = output_model->TreeType() == 0; CHECK(check == true); - CHECK(IO::GetParam("output_model")->TreeType() == + CHECK(IO::GetParam("output_model")->TreeType() == 8); delete output_model; } @@ -476,8 +476,8 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentSingleSampleLimit", mlpack::math::FixedRandomSeed(); mlpackMain(); - RANNModel* output_model; - output_model = std::move(IO::GetParam("output_model")); + RAModel* output_model; + output_model = std::move(IO::GetParam("output_model")); // Reset passed parameters. IO::GetSingleton().Parameters()["reference"].wasPassed = false; @@ -492,7 +492,7 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentSingleSampleLimit", // Check that initial output matrices and the output matrices using // saved model are equal. - CHECK(IO::GetParam("output_model")->SingleSampleLimit() == + CHECK(IO::GetParam("output_model")->SingleSampleLimit() == (int) 15); CHECK(output_model->SingleSampleLimit() == (int) 20); delete output_model; @@ -514,8 +514,8 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentSampleAtLeaves", mlpack::math::FixedRandomSeed(); mlpackMain(); - RANNModel* output_model; - output_model = std::move(IO::GetParam("output_model")); + RAModel* output_model; + output_model = std::move(IO::GetParam("output_model")); // Reset passed parameters. IO::GetSingleton().Parameters()["reference"].wasPassed = false; @@ -530,7 +530,7 @@ TEST_CASE_METHOD(KRANNTestFixture, "KRANNDifferentSampleAtLeaves", // Check that initial output matrices and the output matrices using // saved model are equal. - CHECK(IO::GetParam("output_model")->SampleAtLeaves() == + CHECK(IO::GetParam("output_model")->SampleAtLeaves() == (bool) true); CHECK(output_model->SampleAtLeaves() == (bool) false); delete output_model; From aeaf7528bead4d352c0bb9ca5aa9f99b845ffcbd Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sat, 9 Jan 2021 21:49:02 -0500 Subject: [PATCH 053/253] Remove boost::visitor header. --- src/mlpack/methods/rann/ra_model.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/methods/rann/ra_model.hpp b/src/mlpack/methods/rann/ra_model.hpp index afe42bf3da..8ed91a9c9b 100644 --- a/src/mlpack/methods/rann/ra_model.hpp +++ b/src/mlpack/methods/rann/ra_model.hpp @@ -18,7 +18,6 @@ #include #include #include -#include #include "ra_search.hpp" namespace mlpack { From dcac51194eae04b31ce5c6b7b5adc3204ee40933 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sat, 9 Jan 2021 22:10:04 -0500 Subject: [PATCH 054/253] Partial work on RSModel. --- src/mlpack/methods/range_search/rs_model.hpp | 347 +++++++++--------- .../methods/range_search/rs_model_impl.hpp | 257 ++++--------- 2 files changed, 238 insertions(+), 366 deletions(-) diff --git a/src/mlpack/methods/range_search/rs_model.hpp b/src/mlpack/methods/range_search/rs_model.hpp index ab71f20a21..bf1f6b98f4 100644 --- a/src/mlpack/methods/range_search/rs_model.hpp +++ b/src/mlpack/methods/range_search/rs_model.hpp @@ -27,189 +27,183 @@ namespace mlpack { namespace range { /** - * Alias template for Range Search. + * RSWrapperBase is a base wrapper class for holding all RangeSearch types + * supported by RSModel. All RangeSearch type wrappers inherit from this class, + * allowing a simple interface via inheritance for all the different types we + * want to support. + */ +class RSWrapperBase +{ + public: + //! Create the RSWrapperBase object. The base class does not hold anything, + //! so this constructor does nothing. + RSWrapperBase() { } + + //! Create a new RSWrapperBase that is the same as this one. This function + //! will properly handle polymorphism. + virtual RSWrapperBase* Clone() const = 0; + + //! Destruct the RSWrapperBase (nothing to do). + virtual ~RSWrapperBase() { } + + //! Get the dataset. + const arma::mat& Dataset() const = 0; + + //! Get whether single-tree search is being used. + bool SingleMode() const = 0; + //! Modify whether single-tree search is being used. + bool& SingleMode() = 0; + + //! Get whether naive search is being used. + bool Naive() const = 0; + //! Modify whether naive search is being used. + bool& Naive() = 0; + + //! Train the model (build the reference tree if needed). + virtual void Train(arma::mat&& referenceSet, + const size_t leafSize) = 0; + + //! Perform bichromatic range search (i.e. a search with a separate query + //! set). + virtual void Search(arma::mat&& querySet, + const math::Range& range, + std::vector>& neighbors, + std::vector>& distances, + const size_t leafSize) = 0; + + //! Perform monochromatic range search (i.e. a search with the reference set + //! as the query set). + virtual void Search(const math::Range& range, + std::vector>& neighbors, + std::vector>& distances) = 0; +}; + +/** + * RSWrapper is a wrapper class for most RangeSearch types. */ template class TreeType> -using RSType = RangeSearch; - -/** - * MonoSearchVisitor executes a monochromatic range search on the given - * RSType. Range Search is performed on the reference set itself, no querySet. - */ -class MonoSearchVisitor : public boost::static_visitor +class RSWrapper : public RSWrapperBase { - private: - //! The range to search for. - const math::Range& range; - //! Output neighbors. - std::vector>& neighbors; - //! Output distances. - std::vector>& distances; - public: - //! Perform monochromatic search with the given RangeSearch object. - template - void operator()(RSType* rs) const; + //! Create the RSWrapper object. + RSWrapper(const bool singleMode, const bool naive) : + ra(singleMode, naive) + { + // Nothing else to do. + } - //! Construct the MonoSearchVisitor with the given parameters. - MonoSearchVisitor(const math::Range& range, - std::vector>& neighbors, - std::vector>& distances): - range(range), - neighbors(neighbors), - distances(distances) - {}; + //! Create a new RSWrapper that is the same as this one. This function + //! will properly handle polymorphism. + virtual RSWrapper* Clone() const { return new RSWrapper(*this); } + + //! Destruct the RSWrapper (nothing to do). + virtual ~RSWrapper() { } + + //! Get the dataset. + const arma::mat& Dataset() const { return rs.ReferenceSet(); } + + //! Get whether single-tree search is being used. + bool SingleMode() const { return rs.SingleMode(); } + //! Modify whether single-tree search is being used. + bool& SingleMode() { return rs.SingleMode(); } + + //! Get whether naive search is being used. + bool Naive() const { return rs.Naive(); } + //! Modify whether naive search is being used. + bool& Naive() { return rs.Naive(); } + + //! Train the model (build the reference tree if needed). This ignores the + //! leaf size. + virtual void Train(arma::mat&& referenceSet, + const size_t /* leafSize */); + + //! Perform bichromatic range search (i.e. a search with a separate query + //! set). This ignores the leaf size. + virtual void Search(arma::mat&& querySet, + const math::Range& range, + std::vector>& neighbors, + std::vector>& distances, + const size_t /* leafSize */); + + //! Perform monochromatic range search (i.e. a search with the reference set + //! as the query set). + virtual void Search(const math::Range& range, + std::vector>& neighbors, + std::vector>& distances); + + //! Serialize the RangeSearch model. + template + void serialize(Archive& ar, const uint32_t /* version */) + { + ar(CEREAL_NVP(rs)); + } + + protected: + typedef RangeSearch RSType; + + //! The instantiated RangeSearch object that we are wrapping. + RSType rs; }; /** - * BiSearchVisitor executes a bichromatic range search on the given RSType. - * We use template specialization to differentiate those tree types that - * accept leafSize as a parameter. In these cases, before doing range search, - * a query tree with proper leafSize is built from the querySet. + * LeafSizeRSWrapper wraps any RangeSearch type that needs to be able to take + * the leaf size into account when building trees. The implementations of + * Train() and bichromatic Search() take this leaf size into account. */ -class BiSearchVisitor : public boost::static_visitor +template class TreeType> +class LeafSizeRSWrapper : public RSWrapper { - private: - //! The query set for the bichromatic search. - const arma::mat& querySet; - //! Range to search neighbours for. - const math::Range& range; - //! The result vector for neighbors. - std::vector>& neighbors; - //! The result vector for distances. - std::vector>& distances; - //! The number of points in a leaf (for BinarySpaceTrees). - const size_t leafSize; - - //! Bichromatic range search on the given RSType considering the leafSize. - template - void SearchLeaf(RSType* rs) const; - public: - //! Alias template necessary for visual c++ compiler. - template class TreeType> - using RSTypeT = RSType; + //! Construct the LeafSizeRSWrapper by delegating to the RSWrapper + //! constructor. + LeafSizeRSWrapper(const bool singleMode, const bool naive) : + RSWrapper(singleMode, naive) + { + // Nothing else to do. + } - //! Default Bichromatic range search on the given RSType instance. - template class TreeType> - void operator()(RSTypeT* rs) const; + //! Delete the LeafSizeRSWrapper. + virtual ~LeafSizeRSWrapper() { } - //! Bichromatic range search on the given RSType specialized for KDTrees. - void operator()(RSTypeT* rs) const; + //! Return a copy of the LeafSizeRSWrapper. + virtual LeafSizeRSWrapper* Clone() const + { + return new LeafSizeRSWrapper(*this); + } - //! Bichromatic range search on the given RSType specialized for BallTrees. - void operator()(RSTypeT* rs) const; + //! Train a model with the given parameters. This overload uses leafSize. + virtual void Train(arma::mat&& referenceSet, + const size_t leafSize); - //! Bichromatic range search specialized for octrees. - void operator()(RSTypeT* rs) const; + //! Perform bichromatic search (e.g. search with a separate query set). This + //! overload takes the leaf size into account when building the query tree. + virtual void Search(arma::mat&& querySet, + const size_t k, + arma::Mat& neighbors, + arma::mat& distances, + const size_t leafSize); - //! Construct the BiSearchVisitor. - BiSearchVisitor(const arma::mat& querySet, - const math::Range& range, - std::vector>& neighbors, - std::vector>& distances, - const size_t leafSize); + //! Serialize the RangeSearch model. + template + void serialize(Archive& ar, const uint32_t /* version */) + { + ar(CEREAL_NVP(rs)); + } + + protected: + using RSWrapper::rs; }; /** - * TrainVisitor sets the reference set to a new reference set on the given - * RSType. We use template specialization to differentiate those tree types that - * accept leafSize as a parameter. In these cases, a reference tree with proper - * leafSize is built from the referenceSet. + * The RSModel class provides an abstraction for the RangeSearch class, + * abstracting away the TreeType parameter and allowing it to be specified at + * runtime. This class is written for the sake of the `range_search` binding, + * but is not necessarily restricted to that usage. */ -class TrainVisitor : public boost::static_visitor -{ - private: - //! The reference set to use for training. - arma::mat&& referenceSet; - //! The leaf size, used only by BinarySpaceTree. - size_t leafSize; - //! Train on the given RsType considering the leafSize. - template - void TrainLeaf(RSType* rs) const; - - public: - //! Alias template necessary for visual c++ compiler. - template class TreeType> - using RSTypeT = RSType; - - //! Default Train on the given RSType instance. - template class TreeType> - void operator()(RSTypeT* rs) const; - - //! Train on the given RSType specialized for KDTrees. - void operator()(RSTypeT* rs) const; - - //! Train on the given RSType specialized for BallTrees. - void operator()(RSTypeT* rs) const; - - //! Train specialized for octrees. - void operator()(RSTypeT* rs) const; - - //! Construct the TrainVisitor object with the given reference set, leafSize - TrainVisitor(arma::mat&& referenceSet, - const size_t leafSize); -}; - -/** - * ReferenceSetVisitor exposes the referenceSet of the given RSType. - */ -class ReferenceSetVisitor : public boost::static_visitor -{ - public: - //! Return the reference set. - template - const arma::mat& operator()(RSType* rs) const; -}; - -/** - * DeleteVisitor deletes the given RSType instance. - */ -class DeleteVisitor : public boost::static_visitor -{ - public: - //! Delete the RSType object. - template - void operator()(RSType* rs) const; -}; - -/** - * SingleModeVisitor exposes the SingleMode() method of the given RSType. - */ -class SingleModeVisitor : public boost::static_visitor -{ - public: - /** - * Get a reference to the singleMode parameter of the given RangeSeach - * object. - */ - template - bool& operator()(RSType* rs) const; -}; - -/** - * NaiveVisitor exposes the Naive() method of the given RSType. - */ -class NaiveVisitor : public boost::static_visitor -{ - public: - /** - * Get a reference to the naive parameter of the given RangeSearch object. - */ - template - bool& operator()(RSType* rs) const; -}; - class RSModel { public: @@ -232,7 +226,10 @@ class RSModel }; private: + //! The type of tree we are using. TreeTypes treeType; + //! (Only used for some tree types.) The leaf size to use when building a + //! tree. size_t leafSize; //! If true, we randomly project the data into a new basis before search. @@ -243,22 +240,8 @@ class RSModel /** * rSearch holds an instance of the RangeSearch class for the current * treeType. It is initialized every time BuildModel is executed. - * We access to the contained value through the visitor classes defined above. */ - boost::variant*, - RSType*, - RSType*, - RSType*, - RSType*, - RSType*, - RSType*, - RSType*, - RSType*, - RSType*, - RSType*, - RSType*, - RSType*, - RSType*> rSearch; + RSWrapperBase* rSearch; public: /** @@ -304,17 +287,17 @@ class RSModel void serialize(Archive& ar, const uint32_t /* version */); //! Expose the dataset. - const arma::mat& Dataset() const; + const arma::mat& Dataset() const { return rSearch->Dataset(); } //! Get whether the model is in single-tree search mode. - bool SingleMode() const; + bool SingleMode() const { return rSearch->SingleMode(); } //! Modify whether the model is in single-tree search mode. - bool& SingleMode(); + bool& SingleMode() { return rSearch->SingleMode(); } //! Get whether the model is in naive search mode. - bool Naive() const; + bool Naive() const { return rSearch->Naive(); } //! Modify whether the model is in naive search mode. - bool& Naive(); + bool& Naive() { return rSearch->Naive(); } //! Get the leaf size (applicable to everything but the cover tree). size_t LeafSize() const { return leafSize; } @@ -390,7 +373,7 @@ class RSModel } // namespace range } // namespace mlpack -// Include implementation (of serialize() and inline functions). +// Include implementation (of serialize() and templated wrapper classes). #include "rs_model_impl.hpp" #endif diff --git a/src/mlpack/methods/range_search/rs_model_impl.hpp b/src/mlpack/methods/range_search/rs_model_impl.hpp index ea94903104..983029c4fb 100644 --- a/src/mlpack/methods/range_search/rs_model_impl.hpp +++ b/src/mlpack/methods/range_search/rs_model_impl.hpp @@ -24,27 +24,28 @@ namespace range { * Initialize the RSModel with the given tree type and whether or not a random * basis should be used. */ -inline RSModel::RSModel(TreeTypes treeType, bool randomBasis) : +RSModel::RSModel(TreeTypes treeType, bool randomBasis) : treeType(treeType), leafSize(0), - randomBasis(randomBasis) + randomBasis(randomBasis), + rSearch(NULL) { // Nothing to do. } // Copy constructor. -inline RSModel::RSModel(const RSModel& other) : +RSModel::RSModel(const RSModel& other) : treeType(other.treeType), leafSize(other.leafSize), randomBasis(other.randomBasis), q(other.q), - rSearch(other.rSearch) + rSearch(other.rSearch->Clone()) { // Nothing to do. } // Move constructor. -inline RSModel::RSModel(RSModel&& other) : +RSModel::RSModel(RSModel&& other) : treeType(other.treeType), leafSize(other.leafSize), randomBasis(other.randomBasis), @@ -55,32 +56,56 @@ inline RSModel::RSModel(RSModel&& other) : other.treeType = TreeTypes::KD_TREE; other.leafSize = 0; other.randomBasis = false; - other.rSearch = decltype(other.rSearch)(); } -inline RSModel& RSModel::operator=(RSModel other) +// Copy operator. +RSModel& RSModel::operator=(const RSModel& other) { - boost::apply_visitor(DeleteVisitor(), rSearch); + if (this != &other) + { + delete rSearch; - treeType = other.treeType; - leafSize = other.leafSize; - randomBasis = other.randomBasis; - q = std::move(other.q); - rSearch = std::move(other.rSearch); + treeType = other.treeType; + leafSize = other.leafSize; + randomBasis = other.randomBasis; + q = other.q; + rSearch = other.rSearch->Clone(); + } + + return *this; +} + +// Move operator. +RSModel& RSModel::operator=(RSModel&& other) +{ + if (this != &other) + { + delete rSearch; + + treeType = other.treeType; + leafSize = other.leafSize; + randomBasis = other.randomBasis; + q = std::move(other.q); + rSearch = std::move(other.rSearch); + + other.treeType = TreeTypes::KD_TREE; + other.leafSize = 0; + other.randomBasis = false; + } return *this; } // Clean memory, if necessary. -inline RSModel::~RSModel() +RSModel::~RSModel() { - boost::apply_visitor(DeleteVisitor(), rSearch); + delete rSearch; } -inline void RSModel::BuildModel(arma::mat&& referenceSet, - const size_t leafSize, - const bool naive, - const bool singleMode) +void RSModel::BuildModel(arma::mat&& referenceSet, + const size_t leafSize, + const bool naive, + const bool singleMode) { // Initialize random basis if necessary. if (randomBasis) @@ -92,7 +117,7 @@ inline void RSModel::BuildModel(arma::mat&& referenceSet, this->leafSize = leafSize; // Clean memory, if necessary. - boost::apply_visitor(DeleteVisitor(), rSearch); + delete rSearch; // Do we need to modify the reference set? if (randomBasis) @@ -107,64 +132,63 @@ inline void RSModel::BuildModel(arma::mat&& referenceSet, switch (treeType) { case KD_TREE: - rSearch = new RSType (naive, singleMode); + rSearch = new LeafSizeRSWrapper(naive, singleMode); break; case COVER_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new RSWrapper(naive, singleMode); break; case R_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new RSWrapper(naive, singleMode); break; case R_STAR_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new RSWrapper(naive, singleMode); break; case BALL_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new LeafSizeRSWrapper(naive, singleMode); break; case X_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new RSWrapper(naive, singleMode); break; case HILBERT_R_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new RSWrapper(naive, singleMode); break; case R_PLUS_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new RSWrapper(naive, singleMode); break; case R_PLUS_PLUS_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new RSWrapper(naive, singleMode); break; case VP_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new RSWrapper(naive, singleMode); break; case RP_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new RSWrapper(naive, singleMode); break; case MAX_RP_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new RSWrapper(naive, singleMode); break; case UB_TREE: - rSearch = new RSType(naive, singleMode); + rSearch = new RSWrapper(naive, singleMode); break; case OCTREE: - rSearch = new RSType(naive, singleMode); + rSearch = new LeafSizeRSWrapper(naive, singleMode); break; } - TrainVisitor tn(std::move(referenceSet), leafSize); - boost::apply_visitor(tn, rSearch); + rSearch->Train(std::move(referenceSet), leafSize); if (!naive) { @@ -174,10 +198,10 @@ inline void RSModel::BuildModel(arma::mat&& referenceSet, } // Perform range search. -inline void RSModel::Search(arma::mat&& querySet, - const math::Range& range, - std::vector>& neighbors, - std::vector>& distances) +void RSModel::Search(arma::mat&& querySet, + const math::Range& range, + std::vector>& neighbors, + std::vector>& distances) { // We may need to map the query set randomly. if (randomBasis) @@ -192,16 +216,13 @@ inline void RSModel::Search(arma::mat&& querySet, else Log::Info << "brute-force (naive) search..." << std::endl; - - BiSearchVisitor search(querySet, range, neighbors, distances, - leafSize); - boost::apply_visitor(search, rSearch); + rSearch->Search(std::move(querySet), range, neighbors, distances, leafSize); } // Perform range search (monochromatic case). -inline void RSModel::Search(const math::Range& range, - std::vector>& neighbors, - std::vector>& distances) +void RSModel::Search(const math::Range& range, + std::vector>& neighbors, + std::vector>& distances) { Log::Info << "Search for points in the range [" << range.Lo() << ", " << range.Hi() << "] with "; @@ -212,12 +233,11 @@ inline void RSModel::Search(const math::Range& range, else Log::Info << "brute-force (naive) search..." << std::endl; - MonoSearchVisitor search(range, neighbors, distances); - boost::apply_visitor(search, rSearch); + rSearch->Search(range, neighbors, distances); } // Get the name of the tree type. -inline std::string RSModel::TreeName() const +std::string RSModel::TreeName() const { switch (treeType) { @@ -255,34 +275,11 @@ inline std::string RSModel::TreeName() const } // Clean memory. -inline void RSModel::CleanMemory() +void RSModel::CleanMemory() { - boost::apply_visitor(DeleteVisitor(), rSearch); + delete rSearch; } -//! Monochromatic range search on the given RSType instance. -template -void MonoSearchVisitor::operator()(RSType* rs) const -{ - if (rs) - return rs->Search(range, neighbors, distances); - throw std::runtime_error("no range search model initialized"); -} - -//! Save parameters for bichromatic range search. -inline BiSearchVisitor::BiSearchVisitor( - const arma::mat& querySet, - const math::Range& range, - std::vector>& neighbors, - std::vector>& distances, - const size_t leafSize) : - querySet(querySet), - range(range), - neighbors(neighbors), - distances(distances), - leafSize(leafSize) -{} - //! Default Bichromatic range search on the given RSType instance. template* rs) const throw std::runtime_error("no range search model initialized"); } -//! Bichromatic range search on the given RSType specialized for KDTrees. -inline void BiSearchVisitor::operator()(RSTypeT* rs) const -{ - if (rs) - return SearchLeaf(rs); - throw std::runtime_error("no range search model initialized"); -} - -//! Bichromatic range search on the given RSType specialized for BallTrees. -inline void BiSearchVisitor::operator()(RSTypeT* rs) const -{ - if (rs) - return SearchLeaf(rs); - throw std::runtime_error("no range search model initialized"); -} - -//! Bichromatic range search specialized for Ocrees. -inline void BiSearchVisitor::operator()(RSTypeT* rs) const -{ - if (rs) - return SearchLeaf(rs); - throw std::runtime_error("no range search model initialized"); -} - //! Bichromatic range search on the given RSType considering the leafSize. template void BiSearchVisitor::SearchLeaf(RSType* rs) const @@ -368,30 +341,6 @@ void TrainVisitor::operator()(RSTypeT* rs) const throw std::runtime_error("no range search model initialized"); } -//! Train on the given RSType specialized for KDTrees. -inline void TrainVisitor::operator()(RSTypeT* rs) const -{ - if (rs) - return TrainLeaf(rs); - throw std::runtime_error("no range search model initialized"); -} - -//! Train on the given RSType specialized for BallTrees. -inline void TrainVisitor::operator()(RSTypeT* rs) const -{ - if (rs) - return TrainLeaf(rs); - throw std::runtime_error("no range search model initialized"); -} - -//! Train specialized for Octrees. -inline void TrainVisitor::operator()(RSTypeT* rs) const -{ - if (rs) - return TrainLeaf(rs); - throw std::runtime_error("no range search model initialized"); -} - //! Train on the given RSType considering the leafSize. template void TrainVisitor::TrainLeaf(RSType* rs) const @@ -412,41 +361,6 @@ void TrainVisitor::TrainLeaf(RSType* rs) const } } -//! Expose the referenceSet of the given RSType. -template -const arma::mat& ReferenceSetVisitor::operator()(RSType* rs) const -{ - if (rs) - return rs->ReferenceSet(); - throw std::runtime_error("no range search model initialized"); -} - -//! For cleaning memory -template -void DeleteVisitor::operator()(RSType* rs) const -{ - if (rs) - delete rs; -} - -//! Return whether single mode enabled -template -bool& SingleModeVisitor::operator()(RSType* rs) const -{ - if (rs) - return rs->SingleMode(); - throw std::runtime_error("no range search model initialized"); -} - -//! Exposes Naive() function of given RSType -template -bool& NaiveVisitor::operator()(RSType* rs) const -{ - if (rs) - return rs->Naive(); - throw std::runtime_error("no range search model initialized"); -} - // Serialize the model. template void RSModel::serialize(Archive& ar, const uint32_t /* version */) @@ -457,37 +371,12 @@ void RSModel::serialize(Archive& ar, const uint32_t /* version */) // This should never happen, but just in case... if (cereal::is_loading()) - boost::apply_visitor(DeleteVisitor(), rSearch); + delete rSearch; // We'll only need to serialize one of the model objects, based on the type. ar(CEREAL_VARIANT_POINTER(rSearch)); } -inline const arma::mat& RSModel::Dataset() const -{ - return boost::apply_visitor(ReferenceSetVisitor(), rSearch); -} - -inline bool RSModel::SingleMode() const -{ - return boost::apply_visitor(SingleModeVisitor(), rSearch); -} - -inline bool& RSModel::SingleMode() -{ - return boost::apply_visitor(SingleModeVisitor(), rSearch); -} - -inline bool RSModel::Naive() const -{ - return boost::apply_visitor(NaiveVisitor(), rSearch); -} - -inline bool& RSModel::Naive() -{ - return boost::apply_visitor(NaiveVisitor(), rSearch); -} - } // namespace range } // namespace mlpack From 0cb7e6427312a64f1b65fcd241015242b2b58f7b Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sun, 10 Jan 2021 11:13:24 -0500 Subject: [PATCH 055/253] Remove boost::visitor from RSModel. --- .../methods/range_search/CMakeLists.txt | 1 + .../methods/range_search/range_search.hpp | 7 +- src/mlpack/methods/range_search/rs_model.cpp | 280 ++++++++++ src/mlpack/methods/range_search/rs_model.hpp | 64 +-- .../methods/range_search/rs_model_impl.hpp | 487 +++++++----------- 5 files changed, 495 insertions(+), 344 deletions(-) create mode 100644 src/mlpack/methods/range_search/rs_model.cpp diff --git a/src/mlpack/methods/range_search/CMakeLists.txt b/src/mlpack/methods/range_search/CMakeLists.txt index 0a1912b6b4..8a0ff5925f 100644 --- a/src/mlpack/methods/range_search/CMakeLists.txt +++ b/src/mlpack/methods/range_search/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCES range_search_stat.hpp rs_model.hpp rs_model_impl.hpp + rs_model.cpp ) # Add directory name to sources. diff --git a/src/mlpack/methods/range_search/range_search.hpp b/src/mlpack/methods/range_search/range_search.hpp index 06575005ac..257401d064 100644 --- a/src/mlpack/methods/range_search/range_search.hpp +++ b/src/mlpack/methods/range_search/range_search.hpp @@ -22,7 +22,10 @@ namespace mlpack { namespace range /** Range-search routines. */ { //! Forward declaration. -class TrainVisitor; +template class TreeType> +class LeafSizeRSWrapper; /** * The RangeSearch class is a template class for performing range searches. It @@ -310,7 +313,7 @@ class RangeSearch size_t scores; //! For access to mappings when building models. - friend class TrainVisitor; + friend class LeafSizeRSWrapper; }; } // namespace range diff --git a/src/mlpack/methods/range_search/rs_model.cpp b/src/mlpack/methods/range_search/rs_model.cpp new file mode 100644 index 0000000000..fdf3cd2128 --- /dev/null +++ b/src/mlpack/methods/range_search/rs_model.cpp @@ -0,0 +1,280 @@ +/** + * @file methods/range_search/rs_model_impl.hpp + * @author Ryan Curtin + * + * Implementation of serialize() and inline functions for RSModel. + * + * 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 "rs_model.hpp" + +#include + +namespace mlpack { +namespace range { + +/** + * Initialize the RSModel with the given tree type and whether or not a random + * basis should be used. + */ +RSModel::RSModel(TreeTypes treeType, bool randomBasis) : + treeType(treeType), + leafSize(0), + randomBasis(randomBasis), + rSearch(NULL) +{ + // Nothing to do. +} + +// Copy constructor. +RSModel::RSModel(const RSModel& other) : + treeType(other.treeType), + leafSize(other.leafSize), + randomBasis(other.randomBasis), + q(other.q), + rSearch(other.rSearch->Clone()) +{ + // Nothing to do. +} + +// Move constructor. +RSModel::RSModel(RSModel&& other) : + treeType(other.treeType), + leafSize(other.leafSize), + randomBasis(other.randomBasis), + q(std::move(other.q)), + rSearch(std::move(other.rSearch)) +{ + // Reset other model. + other.treeType = TreeTypes::KD_TREE; + other.leafSize = 0; + other.randomBasis = false; +} + +// Copy operator. +RSModel& RSModel::operator=(const RSModel& other) +{ + if (this != &other) + { + delete rSearch; + + treeType = other.treeType; + leafSize = other.leafSize; + randomBasis = other.randomBasis; + q = other.q; + rSearch = other.rSearch->Clone(); + } + + return *this; +} + +// Move operator. +RSModel& RSModel::operator=(RSModel&& other) +{ + if (this != &other) + { + delete rSearch; + + treeType = other.treeType; + leafSize = other.leafSize; + randomBasis = other.randomBasis; + q = std::move(other.q); + rSearch = std::move(other.rSearch); + + other.treeType = TreeTypes::KD_TREE; + other.leafSize = 0; + other.randomBasis = false; + } + + return *this; +} + +// Clean memory, if necessary. +RSModel::~RSModel() +{ + delete rSearch; +} + +void RSModel::BuildModel(arma::mat&& referenceSet, + const size_t leafSize, + const bool naive, + const bool singleMode) +{ + // Initialize random basis if necessary. + if (randomBasis) + { + Log::Info << "Creating random basis..." << std::endl; + math::RandomBasis(q, referenceSet.n_rows); + } + + this->leafSize = leafSize; + + // Clean memory, if necessary. + delete rSearch; + + // Do we need to modify the reference set? + if (randomBasis) + referenceSet = q * referenceSet; + + if (!naive) + { + Timer::Start("tree_building"); + Log::Info << "Building reference tree..." << std::endl; + } + + switch (treeType) + { + case KD_TREE: + rSearch = new LeafSizeRSWrapper(naive, singleMode); + break; + + case COVER_TREE: + rSearch = new RSWrapper(naive, singleMode); + break; + + case R_TREE: + rSearch = new RSWrapper(naive, singleMode); + break; + + case R_STAR_TREE: + rSearch = new RSWrapper(naive, singleMode); + break; + + case BALL_TREE: + rSearch = new LeafSizeRSWrapper(naive, singleMode); + break; + + case X_TREE: + rSearch = new RSWrapper(naive, singleMode); + break; + + case HILBERT_R_TREE: + rSearch = new RSWrapper(naive, singleMode); + break; + + case R_PLUS_TREE: + rSearch = new RSWrapper(naive, singleMode); + break; + + case R_PLUS_PLUS_TREE: + rSearch = new RSWrapper(naive, singleMode); + break; + + case VP_TREE: + rSearch = new RSWrapper(naive, singleMode); + break; + + case RP_TREE: + rSearch = new RSWrapper(naive, singleMode); + break; + + case MAX_RP_TREE: + rSearch = new RSWrapper(naive, singleMode); + break; + + case UB_TREE: + rSearch = new RSWrapper(naive, singleMode); + break; + + case OCTREE: + rSearch = new LeafSizeRSWrapper(naive, singleMode); + break; + } + + rSearch->Train(std::move(referenceSet), leafSize); + + if (!naive) + { + Timer::Stop("tree_building"); + Log::Info << "Tree built." << std::endl; + } +} + +// Perform range search. +void RSModel::Search(arma::mat&& querySet, + const math::Range& range, + std::vector>& neighbors, + std::vector>& distances) +{ + // We may need to map the query set randomly. + if (randomBasis) + querySet = q * querySet; + + Log::Info << "Search for points in the range [" << range.Lo() << ", " + << range.Hi() << "] with "; + if (!Naive() && !SingleMode()) + Log::Info << "dual-tree " << TreeName() << " search..." << std::endl; + else if (!Naive()) + Log::Info << "single-tree " << TreeName() << " search..." << std::endl; + else + Log::Info << "brute-force (naive) search..." << std::endl; + + rSearch->Search(std::move(querySet), range, neighbors, distances, leafSize); +} + +// Perform range search (monochromatic case). +void RSModel::Search(const math::Range& range, + std::vector>& neighbors, + std::vector>& distances) +{ + Log::Info << "Search for points in the range [" << range.Lo() << ", " + << range.Hi() << "] with "; + if (!Naive() && !SingleMode()) + Log::Info << "dual-tree " << TreeName() << " search..." << std::endl; + else if (!Naive()) + Log::Info << "single-tree " << TreeName() << " search..." << std::endl; + else + Log::Info << "brute-force (naive) search..." << std::endl; + + rSearch->Search(range, neighbors, distances); +} + +// Get the name of the tree type. +std::string RSModel::TreeName() const +{ + switch (treeType) + { + case KD_TREE: + return "kd-tree"; + case COVER_TREE: + return "cover tree"; + case R_TREE: + return "R tree"; + case R_STAR_TREE: + return "R* tree"; + case BALL_TREE: + return "ball tree"; + case X_TREE: + return "X tree"; + case HILBERT_R_TREE: + return "Hilbert R tree"; + case R_PLUS_TREE: + return "R+ tree"; + case R_PLUS_PLUS_TREE: + return "R++ tree"; + case VP_TREE: + return "vantage point tree"; + case RP_TREE: + return "random projection tree (mean split)"; + case MAX_RP_TREE: + return "random projection tree (max split)"; + case UB_TREE: + return "UB tree"; + case OCTREE: + return "octree"; + default: + return "unknown tree"; + } +} + +// Clean memory. +void RSModel::CleanMemory() +{ + delete rSearch; +} + +} // namespace range +} // namespace mlpack diff --git a/src/mlpack/methods/range_search/rs_model.hpp b/src/mlpack/methods/range_search/rs_model.hpp index bf1f6b98f4..12638c2836 100644 --- a/src/mlpack/methods/range_search/rs_model.hpp +++ b/src/mlpack/methods/range_search/rs_model.hpp @@ -19,7 +19,6 @@ #include #include #include -#include #include "range_search.hpp" @@ -47,17 +46,17 @@ class RSWrapperBase virtual ~RSWrapperBase() { } //! Get the dataset. - const arma::mat& Dataset() const = 0; + virtual const arma::mat& Dataset() const = 0; //! Get whether single-tree search is being used. - bool SingleMode() const = 0; + virtual bool SingleMode() const = 0; //! Modify whether single-tree search is being used. - bool& SingleMode() = 0; + virtual bool& SingleMode() = 0; //! Get whether naive search is being used. - bool Naive() const = 0; + virtual bool Naive() const = 0; //! Modify whether naive search is being used. - bool& Naive() = 0; + virtual bool& Naive() = 0; //! Train the model (build the reference tree if needed). virtual void Train(arma::mat&& referenceSet, @@ -89,7 +88,7 @@ class RSWrapper : public RSWrapperBase public: //! Create the RSWrapper object. RSWrapper(const bool singleMode, const bool naive) : - ra(singleMode, naive) + rs(singleMode, naive) { // Nothing else to do. } @@ -182,9 +181,9 @@ class LeafSizeRSWrapper : public RSWrapper //! Perform bichromatic search (e.g. search with a separate query set). This //! overload takes the leaf size into account when building the query tree. virtual void Search(arma::mat&& querySet, - const size_t k, - arma::Mat& neighbors, - arma::mat& distances, + const math::Range& range, + std::vector>& neighbors, + std::vector>& distances, const size_t leafSize); //! Serialize the RangeSearch model. @@ -225,25 +224,6 @@ class RSModel OCTREE }; - private: - //! The type of tree we are using. - TreeTypes treeType; - //! (Only used for some tree types.) The leaf size to use when building a - //! tree. - size_t leafSize; - - //! If true, we randomly project the data into a new basis before search. - bool randomBasis; - //! Random projection matrix. - arma::mat q; - - /** - * rSearch holds an instance of the RangeSearch class for the current - * treeType. It is initialized every time BuildModel is executed. - */ - RSWrapperBase* rSearch; - - public: /** * Initialize the RSModel with the given type and whether or not a random * basis should be used. @@ -271,11 +251,16 @@ class RSModel /** * Copy the given RSModel. * - * Use std::move to pass in the model if the old copy is no longer needed. + * @param other RSModel to copy. + */ + RSModel& operator=(const RSModel& other); + + /** + * Take ownership of the given RSModel's data. * * @param other RSModel to copy. */ - RSModel& operator=(RSModel other); + RSModel& operator=(RSModel&& other); /** * Clean memory, if necessary. @@ -358,6 +343,23 @@ class RSModel std::vector>& distances); private: + //! The type of tree we are using. + TreeTypes treeType; + //! (Only used for some tree types.) The leaf size to use when building a + //! tree. + size_t leafSize; + + //! If true, we randomly project the data into a new basis before search. + bool randomBasis; + //! Random projection matrix. + arma::mat q; + + /** + * rSearch holds an instance of the RangeSearch class for the current + * treeType. It is initialized every time BuildModel is executed. + */ + RSWrapperBase* rSearch; + /** * Return a string representing the name of the tree. This is used for * logging output. diff --git a/src/mlpack/methods/range_search/rs_model_impl.hpp b/src/mlpack/methods/range_search/rs_model_impl.hpp index 983029c4fb..2df060f977 100644 --- a/src/mlpack/methods/range_search/rs_model_impl.hpp +++ b/src/mlpack/methods/range_search/rs_model_impl.hpp @@ -20,295 +20,87 @@ namespace mlpack { namespace range { -/** - * Initialize the RSModel with the given tree type and whether or not a random - * basis should be used. - */ -RSModel::RSModel(TreeTypes treeType, bool randomBasis) : - treeType(treeType), - leafSize(0), - randomBasis(randomBasis), - rSearch(NULL) -{ - // Nothing to do. -} - -// Copy constructor. -RSModel::RSModel(const RSModel& other) : - treeType(other.treeType), - leafSize(other.leafSize), - randomBasis(other.randomBasis), - q(other.q), - rSearch(other.rSearch->Clone()) -{ - // Nothing to do. -} - -// Move constructor. -RSModel::RSModel(RSModel&& other) : - treeType(other.treeType), - leafSize(other.leafSize), - randomBasis(other.randomBasis), - q(std::move(other.q)), - rSearch(std::move(other.rSearch)) -{ - // Reset other model. - other.treeType = TreeTypes::KD_TREE; - other.leafSize = 0; - other.randomBasis = false; -} - -// Copy operator. -RSModel& RSModel::operator=(const RSModel& other) -{ - if (this != &other) - { - delete rSearch; - - treeType = other.treeType; - leafSize = other.leafSize; - randomBasis = other.randomBasis; - q = other.q; - rSearch = other.rSearch->Clone(); - } - - return *this; -} - -// Move operator. -RSModel& RSModel::operator=(RSModel&& other) -{ - if (this != &other) - { - delete rSearch; - - treeType = other.treeType; - leafSize = other.leafSize; - randomBasis = other.randomBasis; - q = std::move(other.q); - rSearch = std::move(other.rSearch); - - other.treeType = TreeTypes::KD_TREE; - other.leafSize = 0; - other.randomBasis = false; - } - - return *this; -} - -// Clean memory, if necessary. -RSModel::~RSModel() -{ - delete rSearch; -} - -void RSModel::BuildModel(arma::mat&& referenceSet, - const size_t leafSize, - const bool naive, - const bool singleMode) -{ - // Initialize random basis if necessary. - if (randomBasis) - { - Log::Info << "Creating random basis..." << std::endl; - math::RandomBasis(q, referenceSet.n_rows); - } - - this->leafSize = leafSize; - - // Clean memory, if necessary. - delete rSearch; - - // Do we need to modify the reference set? - if (randomBasis) - referenceSet = q * referenceSet; - - if (!naive) - { - Timer::Start("tree_building"); - Log::Info << "Building reference tree..." << std::endl; - } - - switch (treeType) - { - case KD_TREE: - rSearch = new LeafSizeRSWrapper(naive, singleMode); - break; - - case COVER_TREE: - rSearch = new RSWrapper(naive, singleMode); - break; - - case R_TREE: - rSearch = new RSWrapper(naive, singleMode); - break; - - case R_STAR_TREE: - rSearch = new RSWrapper(naive, singleMode); - break; - - case BALL_TREE: - rSearch = new LeafSizeRSWrapper(naive, singleMode); - break; - - case X_TREE: - rSearch = new RSWrapper(naive, singleMode); - break; - - case HILBERT_R_TREE: - rSearch = new RSWrapper(naive, singleMode); - break; - - case R_PLUS_TREE: - rSearch = new RSWrapper(naive, singleMode); - break; - - case R_PLUS_PLUS_TREE: - rSearch = new RSWrapper(naive, singleMode); - break; - - case VP_TREE: - rSearch = new RSWrapper(naive, singleMode); - break; - - case RP_TREE: - rSearch = new RSWrapper(naive, singleMode); - break; - - case MAX_RP_TREE: - rSearch = new RSWrapper(naive, singleMode); - break; - - case UB_TREE: - rSearch = new RSWrapper(naive, singleMode); - break; - - case OCTREE: - rSearch = new LeafSizeRSWrapper(naive, singleMode); - break; - } - - rSearch->Train(std::move(referenceSet), leafSize); - - if (!naive) - { - Timer::Stop("tree_building"); - Log::Info << "Tree built." << std::endl; - } -} - -// Perform range search. -void RSModel::Search(arma::mat&& querySet, - const math::Range& range, - std::vector>& neighbors, - std::vector>& distances) -{ - // We may need to map the query set randomly. - if (randomBasis) - querySet = q * querySet; - - Log::Info << "Search for points in the range [" << range.Lo() << ", " - << range.Hi() << "] with "; - if (!Naive() && !SingleMode()) - Log::Info << "dual-tree " << TreeName() << " search..." << std::endl; - else if (!Naive()) - Log::Info << "single-tree " << TreeName() << " search..." << std::endl; - else - Log::Info << "brute-force (naive) search..." << std::endl; - - rSearch->Search(std::move(querySet), range, neighbors, distances, leafSize); -} - -// Perform range search (monochromatic case). -void RSModel::Search(const math::Range& range, - std::vector>& neighbors, - std::vector>& distances) -{ - Log::Info << "Search for points in the range [" << range.Lo() << ", " - << range.Hi() << "] with "; - if (!Naive() && !SingleMode()) - Log::Info << "dual-tree " << TreeName() << " search..." << std::endl; - else if (!Naive()) - Log::Info << "single-tree " << TreeName() << " search..." << std::endl; - else - Log::Info << "brute-force (naive) search..." << std::endl; - - rSearch->Search(range, neighbors, distances); -} - -// Get the name of the tree type. -std::string RSModel::TreeName() const -{ - switch (treeType) - { - case KD_TREE: - return "kd-tree"; - case COVER_TREE: - return "cover tree"; - case R_TREE: - return "R tree"; - case R_STAR_TREE: - return "R* tree"; - case BALL_TREE: - return "ball tree"; - case X_TREE: - return "X tree"; - case HILBERT_R_TREE: - return "Hilbert R tree"; - case R_PLUS_TREE: - return "R+ tree"; - case R_PLUS_PLUS_TREE: - return "R++ tree"; - case VP_TREE: - return "vantage point tree"; - case RP_TREE: - return "random projection tree (mean split)"; - case MAX_RP_TREE: - return "random projection tree (max split)"; - case UB_TREE: - return "UB tree"; - case OCTREE: - return "octree"; - default: - return "unknown tree"; - } -} - -// Clean memory. -void RSModel::CleanMemory() -{ - delete rSearch; -} - -//! Default Bichromatic range search on the given RSType instance. template class TreeType> -void BiSearchVisitor::operator()(RSTypeT* rs) const +void RSWrapper::Train(arma::mat&& referenceSet, + const size_t /* leafSize */) { - if (rs) - return rs->Search(querySet, range, neighbors, distances); - throw std::runtime_error("no range search model initialized"); + rs.Train(std::move(referenceSet)); } -//! Bichromatic range search on the given RSType considering the leafSize. -template -void BiSearchVisitor::SearchLeaf(RSType* rs) const +template class TreeType> +void RSWrapper::Search(arma::mat&& querySet, + const math::Range& range, + std::vector>& neighbors, + std::vector>& distances, + const size_t /* leafSize */) { - if (!rs->Naive() && !rs->SingleMode()) + rs.Search(std::move(querySet), range, neighbors, distances); +} + +template class TreeType> +void RSWrapper::Search(const math::Range& range, + std::vector>& neighbors, + std::vector>& distances) +{ + rs.Search(range, neighbors, distances); +} + +template class TreeType> +void LeafSizeRSWrapper::Train(arma::mat&& referenceSet, + const size_t leafSize) +{ + if (rs.Naive()) + { + rs.Train(std::move(referenceSet)); + } + else + { + std::vector oldFromNewReferences; + typename decltype(rs)::Tree* tree = + new typename decltype(rs)::Tree(std::move(referenceSet), + oldFromNewReferences, + leafSize); + rs.Train(tree); + + // Give the model ownership of the tree and the mappings. + rs.treeOwner = true; + rs.oldFromNewReferences = std::move(oldFromNewReferences); + } +} + +template class TreeType> +void LeafSizeRSWrapper::Search( + arma::mat&& querySet, + const math::Range& range, + std::vector>& neighbors, + std::vector>& distances, + const size_t leafSize) +{ + if (!rs.Naive() && !rs.SingleMode()) { // Build a second tree and search. Timer::Start("tree_building"); Log::Info << "Building query tree..." << std::endl; std::vector oldFromNewQueries; - typename RSType::Tree queryTree(std::move(querySet), oldFromNewQueries, - leafSize); + typename decltype(rs)::Tree queryTree(std::move(querySet), + oldFromNewQueries, + leafSize); Log::Info << "Tree built." << std::endl; Timer::Stop("tree_building"); std::vector> neighborsOut; std::vector> distancesOut; - rs->Search(&queryTree, range, neighborsOut, distancesOut); + rs.Search(&queryTree, range, neighborsOut, distancesOut); // Remap the query points. neighbors.resize(queryTree.Dataset().n_cols); @@ -319,45 +111,9 @@ void BiSearchVisitor::SearchLeaf(RSType* rs) const distances[oldFromNewQueries[i]] = distancesOut[i]; } } - else - rs->Search(querySet, range, neighbors, distances); -} - -//! Save parameters for Train. -inline TrainVisitor::TrainVisitor(arma::mat&& referenceSet, - const size_t leafSize) : - referenceSet(std::move(referenceSet)), - leafSize(leafSize) -{} - -//! Default Train on the given RSType instance. -template class TreeType> -void TrainVisitor::operator()(RSTypeT* rs) const -{ - if (rs) - return rs->Train(std::move(referenceSet)); - throw std::runtime_error("no range search model initialized"); -} - -//! Train on the given RSType considering the leafSize. -template -void TrainVisitor::TrainLeaf(RSType* rs) const -{ - if (rs->Naive()) - rs->Train(std::move(referenceSet)); else { - std::vector oldFromNewReferences; - typename RSType::Tree* tree = - new typename RSType::Tree(std::move(referenceSet), oldFromNewReferences, - leafSize); - rs->Train(tree); - - // Give the model ownership of the tree and the mappings. - rs->treeOwner = true; - rs->oldFromNewReferences = std::move(oldFromNewReferences); + rs.Search(std::move(querySet), range, neighbors, distances); } } @@ -373,8 +129,117 @@ void RSModel::serialize(Archive& ar, const uint32_t /* version */) if (cereal::is_loading()) delete rSearch; - // We'll only need to serialize one of the model objects, based on the type. - ar(CEREAL_VARIANT_POINTER(rSearch)); + // Avoid polymorphic serialization by explicitly serializing the correct type. + switch (treeType) + { + case KD_TREE: + { + LeafSizeRSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case COVER_TREE: + { + RSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + + case R_TREE: + { + RSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + + case R_STAR_TREE: + { + RSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + + case BALL_TREE: + { + LeafSizeRSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case X_TREE: + { + RSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + + case HILBERT_R_TREE: + { + RSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + + case R_PLUS_TREE: + { + RSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + + case R_PLUS_PLUS_TREE: + { + RSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + + case VP_TREE: + { + RSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + + case RP_TREE: + { + RSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + + case MAX_RP_TREE: + { + RSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case UB_TREE: + { + RSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + case OCTREE: + { + LeafSizeRSWrapper& typedSearch = + dynamic_cast&>(*rSearch); + ar(CEREAL_NVP(typedSearch)); + break; + } + } } } // namespace range From c83c6421cf37c74118183e7231d0b00e0faef685 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sun, 10 Jan 2021 12:22:29 -0500 Subject: [PATCH 056/253] Fix name of file in comment. --- src/mlpack/methods/range_search/rs_model.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/range_search/rs_model.cpp b/src/mlpack/methods/range_search/rs_model.cpp index fdf3cd2128..807a347ee4 100644 --- a/src/mlpack/methods/range_search/rs_model.cpp +++ b/src/mlpack/methods/range_search/rs_model.cpp @@ -1,5 +1,5 @@ /** - * @file methods/range_search/rs_model_impl.hpp + * @file methods/range_search/rs_model.cpp * @author Ryan Curtin * * Implementation of serialize() and inline functions for RSModel. From f216b9b3ef3ff259f0d6fdcf0759efae56d594bc Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sun, 10 Jan 2021 13:05:14 -0500 Subject: [PATCH 057/253] Remove boost::visitor from KDEModel. --- src/mlpack/methods/kde/CMakeLists.txt | 1 + src/mlpack/methods/kde/kde_model.cpp | 312 ++++++++++ src/mlpack/methods/kde/kde_model.hpp | 464 +++++---------- src/mlpack/methods/kde/kde_model_impl.hpp | 673 ++++------------------ 4 files changed, 572 insertions(+), 878 deletions(-) create mode 100644 src/mlpack/methods/kde/kde_model.cpp diff --git a/src/mlpack/methods/kde/CMakeLists.txt b/src/mlpack/methods/kde/CMakeLists.txt index 31dacaee43..81bee212e3 100644 --- a/src/mlpack/methods/kde/CMakeLists.txt +++ b/src/mlpack/methods/kde/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCES kde_stat.hpp kde_model.hpp kde_model_impl.hpp + kde_model.cpp ) # Add directory name to sources. diff --git a/src/mlpack/methods/kde/kde_model.cpp b/src/mlpack/methods/kde/kde_model.cpp new file mode 100644 index 0000000000..552f1b4058 --- /dev/null +++ b/src/mlpack/methods/kde/kde_model.cpp @@ -0,0 +1,312 @@ +/** + * @file methods/kde/kde_model.cpp + * @author Roberto Hueso + * + * Implementation of KDE Model. + * + * 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 "kde_model.hpp" + +namespace mlpack { +namespace kde { + +//! Initialize the KDEModel with the given parameters. +KDEModel::KDEModel(const double bandwidth, + const double relError, + const double absError, + const KernelTypes kernelType, + const TreeTypes treeType, + const bool monteCarlo, + const double mcProb, + const size_t initialSampleSize, + const double mcEntryCoef, + const double mcBreakCoef) : + bandwidth(bandwidth), + relError(relError), + absError(absError), + kernelType(kernelType), + treeType(treeType), + monteCarlo(monteCarlo), + mcProb(mcProb), + initialSampleSize(initialSampleSize), + mcEntryCoef(mcEntryCoef), + mcBreakCoef(mcBreakCoef), + kdeModel(NULL) +{ + // Nothing to do. +} + +// Copy constructor. +KDEModel::KDEModel(const KDEModel& other) : + bandwidth(other.bandwidth), + relError(other.relError), + absError(other.absError), + kernelType(other.kernelType), + treeType(other.treeType), + monteCarlo(other.monteCarlo), + mcProb(other.mcProb), + initialSampleSize(other.initialSampleSize), + mcEntryCoef(other.mcEntryCoef), + mcBreakCoef(other.mcBreakCoef), + kdeModel(other.kdeModel->Clone()) +{ + // Nothing to do. +} + +// Move constructor. +KDEModel::KDEModel(KDEModel&& other) : + bandwidth(other.bandwidth), + relError(other.relError), + absError(other.absError), + kernelType(other.kernelType), + treeType(other.treeType), + monteCarlo(other.monteCarlo), + mcProb(other.mcProb), + initialSampleSize(other.initialSampleSize), + mcEntryCoef(other.mcEntryCoef), + mcBreakCoef(other.mcBreakCoef), + kdeModel(std::move(other.kdeModel)) +{ + // Reset other model. + other.bandwidth = 1.0; + other.relError = KDEDefaultParams::relError; + other.absError = KDEDefaultParams::absError; + other.kernelType = KernelTypes::GAUSSIAN_KERNEL; + other.treeType = TreeTypes::KD_TREE; + other.monteCarlo = KDEDefaultParams::monteCarlo; + other.mcProb = KDEDefaultParams::mcProb; + other.initialSampleSize = KDEDefaultParams::initialSampleSize; + other.mcEntryCoef = KDEDefaultParams::mcEntryCoef; + other.mcBreakCoef = KDEDefaultParams::mcBreakCoef; +} + +KDEModel& KDEModel::operator=(const KDEModel& other) +{ + if (this != &other) + { + delete kdeModel; + + bandwidth = other.bandwidth; + relError = other.relError; + absError = other.absError; + kernelType = other.kernelType; + treeType = other.treeType; + monteCarlo = other.monteCarlo; + mcProb = other.mcProb; + initialSampleSize = other.initialSampleSize; + mcEntryCoef = other.mcEntryCoef; + mcBreakCoef = other.mcBreakCoef; + kdeModel = other.kdeModel->Clone(); + } + + return *this; +} + +KDEModel& KDEModel::operator=(KDEModel&& other) +{ + if (this != &other) + { + delete kdeModel; + + bandwidth = other.bandwidth; + relError = other.relError; + absError = other.absError; + kernelType = other.kernelType; + treeType = other.treeType; + monteCarlo = other.monteCarlo; + mcProb = other.mcProb; + initialSampleSize = other.initialSampleSize; + mcEntryCoef = other.mcEntryCoef; + mcBreakCoef = other.mcBreakCoef; + kdeModel = std::move(other.kdeModel); + + // Reset other model. + other.bandwidth = 1.0; + other.relError = KDEDefaultParams::relError; + other.absError = KDEDefaultParams::absError; + other.kernelType = KernelTypes::GAUSSIAN_KERNEL; + other.treeType = TreeTypes::KD_TREE; + other.monteCarlo = KDEDefaultParams::monteCarlo; + other.mcProb = KDEDefaultParams::mcProb; + other.initialSampleSize = KDEDefaultParams::initialSampleSize; + other.mcEntryCoef = KDEDefaultParams::mcEntryCoef; + other.mcBreakCoef = KDEDefaultParams::mcBreakCoef; + } + + return *this; +} + +// Clean memory. +KDEModel::~KDEModel() +{ + delete kdeModel; +} + +template class TreeType> +KDEWrapperBase* BuildModelHelper(const KDEModel::KernelTypes kernelType, + const double relError, + const double absError, + const double bandwidth) +{ + switch (kernelType) + { + case KDEModel::GAUSSIAN_KERNEL: + return new KDEWrapper( + relError, absError, kernel::GaussianKernel(bandwidth)); + + case KDEModel::EPANECHNIKOV_KERNEL: + return new KDEWrapper( + relError, absError, kernel::EpanechnikovKernel(bandwidth)); + + case KDEModel::LAPLACIAN_KERNEL: + return new KDEWrapper( + relError, absError, kernel::LaplacianKernel(bandwidth)); + + case KDEModel::SPHERICAL_KERNEL: + return new KDEWrapper( + relError, absError, kernel::SphericalKernel(bandwidth)); + + case KDEModel::TRIANGULAR_KERNEL: + return new KDEWrapper( + relError, absError, kernel::TriangularKernel(bandwidth)); + } + + // This should never happen. + return NULL; +} + +void KDEModel::BuildModel(arma::mat&& referenceSet) +{ + // Clean memory, if necessary. + delete kdeModel; + + // Build the actual model. + switch (treeType) + { + case KD_TREE: + kdeModel = BuildModelHelper(kernelType, relError, absError, + bandwidth); + break; + + case BALL_TREE: + kdeModel = BuildModelHelper(kernelType, relError, + absError, bandwidth); + break; + + case COVER_TREE: + kdeModel = BuildModelHelper(kernelType, relError, + absError, bandwidth); + break; + + case OCTREE: + kdeModel = BuildModelHelper(kernelType, relError, absError, + bandwidth); + break; + + case R_TREE: + kdeModel = BuildModelHelper(kernelType, relError, absError, + bandwidth); + break; + } + + // Set whether to use Monte Carlo estimations or not. + kdeModel->MonteCarlo() = monteCarlo; + + // Set Monte Carlo probability. + kdeModel->MCProb(mcProb); + + // Set Monte Carlo initial sample size. + kdeModel->MCInitialSampleSize() = initialSampleSize; + + // Set Monte Carlo entry coefficient. + kdeModel->MCEntryCoef(mcEntryCoef); + + // Set Monte Carlo break coefficient. + kdeModel->MCBreakCoef(mcBreakCoef); + + // Train the model. + kdeModel->Train(std::move(referenceSet)); +} + +// Perform bichromatic evaluation. +void KDEModel::Evaluate(arma::mat&& querySet, arma::vec& estimates) +{ + kdeModel->Evaluate(std::move(querySet), estimates); +} + +// Perform monochromatic evaluation. +void KDEModel::Evaluate(arma::vec& estimates) +{ + kdeModel->Evaluate(estimates); +} + +// Clean memory. +void KDEModel::CleanMemory() +{ + delete kdeModel; +} + +// Modify model kernel bandwidth. +void KDEModel::Bandwidth(const double newBandwidth) +{ + bandwidth = newBandwidth; + kdeModel->Bandwidth(bandwidth); +} + +// Modify model relative error tolerance. +void KDEModel::RelativeError(const double newRelError) +{ + relError = newRelError; + kdeModel->RelativeError(relError); +} + +// Modify model absolute error tolerance. +void KDEModel::AbsoluteError(const double newAbsError) +{ + absError = newAbsError; + kdeModel->AbsoluteError(absError); +} + +// Modify whether Monte Carlo estimations will be used. +void KDEModel::MonteCarlo(const bool newMonteCarlo) +{ + monteCarlo = newMonteCarlo; + kdeModel->MonteCarlo() = monteCarlo; +} + +// Modify model Monte Carlo probability. +void KDEModel::MCProbability(const double newMCProb) +{ + mcProb = newMCProb; + kdeModel->MCProb(mcProb); +} + +// Modify model Monte Carlo initial sample size. +void KDEModel::MCInitialSampleSize(const size_t newSampleSize) +{ + initialSampleSize = newSampleSize; + kdeModel->MCInitialSampleSize() = initialSampleSize; +} + +// Modify model Monte Carlo entry coefficient. +void KDEModel::MCEntryCoefficient(const double newEntryCoef) +{ + mcEntryCoef = newEntryCoef; + kdeModel->MCEntryCoef(mcEntryCoef); +} + +// Modify model Monte Carlo break coefficient. +void KDEModel::MCBreakCoefficient(const double newBreakCoef) +{ + mcBreakCoef = newBreakCoef; + kdeModel->MCBreakCoef(mcBreakCoef); +} + +} // namespace kde +} // namespace mlpack diff --git a/src/mlpack/methods/kde/kde_model.hpp b/src/mlpack/methods/kde/kde_model.hpp index 220213ba5e..c2f93ba181 100644 --- a/src/mlpack/methods/kde/kde_model.hpp +++ b/src/mlpack/methods/kde/kde_model.hpp @@ -22,28 +22,11 @@ #include // Remaining includes. -#include #include "kde.hpp" namespace mlpack { namespace kde { -//! Alias template. -template class TreeType> -using KDEType = KDE::template DualTreeTraverser, - TreeType::template SingleTreeTraverser>; - /** * KernelNormalizer holds a set of methods to normalize estimations applying * in each case the appropiate kernel normalizer function. @@ -81,284 +64,168 @@ class KernelNormalizer }; /** - * DualMonoKDE computes a Kernel Density Estimation on the given KDEType. - * It performs a monochromatic KDE. + * KDEWrapperBase is a base wrapper class for holding all KDE types supported by + * KDEModel. All KDE type wrappers inheirt from this class, allowing a simple + * interface via inheritance for all the different types we want to support. */ -class DualMonoKDE : public boost::static_visitor +class KDEWrapperBase { - private: - //! Vector to store the KDE results. - arma::vec& estimations; - public: - //! Alias template necessary for Visual C++ compiler. - template class TreeType> - using KDETypeT = KDEType; + //! Create the KDEWrapperBase object. The base class does not hold anything, + //! so this constructor does nothing. + KDEWrapperBase() { } - //! Default DualMonoKDE on some KDEType. - template class TreeType> - void operator()(KDETypeT* kde) const; + //! Create a new KDEWrapperBase that is the same as this one. This function + //! will properly handle polymorphism. + virtual KDEWrapperBase* Clone() const = 0; - // TODO Implement specific cases where a leaf size can be selected. + //! Destruct the KDEWrapperBase (nothing to do). + virtual ~KDEWrapperBase() { } - //! DualMonoKDE constructor. - DualMonoKDE(arma::vec& estimations); + //! Modify the bandwidth of the kernel. + virtual void Bandwidth(const double bw) = 0; + + //! Modify the relative error tolerance. + virtual void RelativeError(const double relError) = 0; + + //! Modify the absolute error tolerance. + virtual void AbsoluteError(const double absError) = 0; + + //! Get whether Monte Carlo search is being used. + virtual bool MonteCarlo() const = 0; + //! Modify whether Monte Carlo search is being used. + virtual bool& MonteCarlo() = 0; + + //! Modify the Monte Carlo probability. + virtual void MCProb(const double mcProb) = 0; + + //! Get the Monte Carlo sample size. + virtual size_t MCInitialSampleSize() const = 0; + //! Modify the Monte Carlo sample size. + virtual size_t& MCInitialSampleSize() = 0; + + //! Modify the Monte Carlo entry coefficient. + virtual void MCEntryCoef(const double entryCoef) = 0; + + //! Modify the Monte Carlo break coefficient. + virtual void MCBreakCoef(const double breakCoef) = 0; + + //! Get the search mode. + virtual KDEMode Mode() const = 0; + //! Modify the search mode. + virtual KDEMode& Mode() = 0; + + //! Train the model (build the tree). + virtual void Train(arma::mat&& referenceSet) = 0; + + //! Perform bichromatic KDE (i.e. KDE with a separate query set). + virtual void Evaluate(arma::mat&& querySet, + arma::vec& estimates) = 0; + + //! Perform monochromatic KDE (i.e. with the reference set as the query set). + virtual void Evaluate(arma::vec& estimates) = 0; }; /** - * DualBiKDE computes a Kernel Density Estimation on the given KDEType. - * It performs a bichromatic KDE. + * KDEWrapper is a wrapper class for all KDE types supported by KDEModel. It + * can be extended with new child classes if new functionality for certain types + * is needed. */ -class DualBiKDE : public boost::static_visitor +template class TreeType> +class KDEWrapper : public KDEWrapperBase { - private: - //! Query set dimensionality. - const size_t dimension; - - //! The query set for the KDE. - const arma::mat& querySet; - - //! Vector to store the KDE results. - arma::vec& estimations; - public: - //! Alias template necessary for Visual C++ compiler. - template class TreeType> - using KDETypeT = KDEType; + //! Create the KDEWrapper object, initializing the internally-held KDE object. + KDEWrapper(const double relError, + const double absError, + const KernelType& kernel) : + kde(relError, absError, kernel) + { + // Nothing left to do. + } - //! Default DualBiKDE on some KDEType. - template class TreeType> - void operator()(KDETypeT* kde) const; + //! Create a new KDEWrapper that is the same as this one. This function + //! will properly handle polymorphism. + virtual KDEWrapper* Clone() const { return new KDEWrapper(*this); } - // TODO Implement specific cases where a leaf size can be selected. + //! Destruct the KDEWrapper (nothing to do). + virtual ~KDEWrapper() { } - //! DualBiKDE constructor. Takes ownership of the given querySet. - DualBiKDE(arma::mat&& querySet, arma::vec& estimations); + //! Modify the bandwidth of the kernel. + virtual void Bandwidth(const double bw) { kde.Kernel() = KernelType(bw); } + + //! Modify the relative error tolerance. + virtual void RelativeError(const double eps) { kde.RelativeError(eps); } + + //! Modify the absolute error tolerance. + virtual void AbsoluteError(const double eps) { kde.AbsoluteError(eps); } + + //! Get whether Monte Carlo search is being used. + virtual bool MonteCarlo() const { return kde.MonteCarlo(); } + //! Modify whether Monte Carlo search is being used. + virtual bool& MonteCarlo() { return kde.MonteCarlo(); } + + //! Modify the Monte Carlo probability. + virtual void MCProb(const double mcProb) { kde.MCProb(mcProb); } + + //! Get the Monte Carlo sample size. + virtual size_t MCInitialSampleSize() const + { + return kde.MCInitialSampleSize(); + } + //! Modify the Monte Carlo sample size. + virtual size_t& MCInitialSampleSize() + { + return kde.MCInitialSampleSize(); + } + + //! Modify the Monte Carlo entry coefficient. + virtual void MCEntryCoef(const double e) { kde.MCEntryCoef(e); } + + //! Modify the Monte Carlo break coefficient. + virtual void MCBreakCoef(const double b) { kde.MCBreakCoef(b); } + + //! Get the search mode. + virtual KDEMode Mode() const { return kde.Mode(); } + //! Modify the search mode. + virtual KDEMode& Mode() { return kde.Mode(); } + + //! Train the model (build the tree). + virtual void Train(arma::mat&& referenceSet); + + //! Perform bichromatic KDE (i.e. KDE with a separate query set). + virtual void Evaluate(arma::mat&& querySet, + arma::vec& estimates); + + //! Perform monochromatic KDE (i.e. with the reference set as the query set). + virtual void Evaluate(arma::vec& estimates); + + //! Serialize the KDE model. + template + void serialize(Archive& ar, const uint32_t /* version */) + { + ar(CEREAL_NVP(kde)); + } + + protected: + typedef KDE KDEType; + + //! The instantiated KDE object that we are wrapping. + KDEType kde; }; /** - * TrainVisitor trains a given KDEType using a reference set. + * The KDEModel provides an abstraction for the KDE class, abstracting away the + * KernelType and TreeType parameters and allowing those to be specified at + * runtime. This class is written for the sake of the `kde` binding, but it is + * not necessarily restricted to that usage. */ -class TrainVisitor : public boost::static_visitor -{ - private: - //! The reference set used for training. - arma::mat&& referenceSet; - - public: - //! Default TrainVisitor on some KDEType. - template class TreeType> - void operator()(KDEType* kde) const; - - // TODO Implement specific cases where a leaf size can be selected. - - //! TrainVisitor constructor. Takes ownership of the given referenceSet. - TrainVisitor(arma::mat&& referenceSet); -}; - -/** - * BandwidthVisitor modifies the bandwidth of a KDEType kernel. - */ -class BandwidthVisitor : public boost::static_visitor -{ - private: - //! Relative error tolerance. - const double bandwidth; - - public: - //! Default BandwidthVisitor on some KDEType. - template class TreeType> - void operator()(KDEType* kde) const; - - //! BandwidthVisitor constructor. - BandwidthVisitor(const double bandwidth); -}; - -/** - * RelErrorVisitor modifies relative error tolerance for a KDEType. - */ -class RelErrorVisitor : public boost::static_visitor -{ - private: - //! Relative error tolerance. - const double relError; - - public: - //! Default RelErrorVisitor on some KDEType. - template class TreeType> - void operator()(KDEType* kde) const; - - //! RelErrorVisitor constructor. - RelErrorVisitor(const double relError); -}; - -/** - * AbsErrorVisitor modifies absolute error tolerance for a KDEType. - */ -class AbsErrorVisitor : public boost::static_visitor -{ - private: - //! Absolute error tolerance. - const double absError; - - public: - //! Default AbsErrorVisitor on some KDEType. - template class TreeType> - void operator()(KDEType* kde) const; - - //! AbsErrorVisitor constructor. - AbsErrorVisitor(const double absError); -}; - -/** - * MonteCarloVisitor activates or deactivates Monte Carlo for a given KDEType. - */ -class MonteCarloVisitor : public boost::static_visitor -{ - private: - //! Whether to use Monte Carlo estimations or not. - const bool monteCarlo; - - public: - //! Default MonteCarloVisitor on some KDEType. - template class TreeType> - void operator()(KDEType* kde) const; - - //! MonteCarloVisitor constructor. - MonteCarloVisitor(const bool monteCarlo); -}; - -/** - * MCProbabilityVisitor sets the Monte Carlo probability for a given KDEType. - */ -class MCProbabilityVisitor : public boost::static_visitor -{ - private: - //! Monte Carlo probability. - const double probability; - - public: - //! Default MCProbabilityVisitor on some KDEType. - template class TreeType> - void operator()(KDEType* kde) const; - - //! MCProbabilityVisitor constructor. - MCProbabilityVisitor(const double probability); -}; - -/** - * MCSampleSizeVisitor sets the Monte Carlo intial sample size for a given - * KDEType. - */ -class MCSampleSizeVisitor : public boost::static_visitor -{ - private: - //! Monte Carlo sample size. - const size_t sampleSize; - - public: - //! Default MCSampleSizeVisitor on some KDEType. - template class TreeType> - void operator()(KDEType* kde) const; - - //! MCSampleSizeVisitor constructor. - MCSampleSizeVisitor(const size_t sampleSize); -}; - -/** - * MCEntryCoefVisitor sets the Monte Carlo entry coefficient. - */ -class MCEntryCoefVisitor : public boost::static_visitor -{ - private: - //! Monte Carlo entry coefficient. - const double entryCoef; - - public: - //! Default MCEntryCoefVisitor on some KDEType. - template class TreeType> - void operator()(KDEType* kde) const; - - //! MCEntryCoefVisitor constructor. - MCEntryCoefVisitor(const double entryCoef); -}; - -/** - * MCBreakCoefVisitor sets the Monte Carlo break coefficient. - */ -class MCBreakCoefVisitor : public boost::static_visitor -{ - private: - //! Monte Carlo break coefficient. - const double breakCoef; - - public: - //! Default MCBreakCoefVisitor on some KDEType. - template class TreeType> - void operator()(KDEType* kde) const; - - //! MCBreakCoefVisitor constructor. - MCBreakCoefVisitor(const double breakCoef); -}; - -/** - * ModeVisitor exposes the Mode() method of the KDEType. - */ -class ModeVisitor : public boost::static_visitor -{ - public: - //! Return mode of KDEType instance. - template - KDEMode& operator()(KDEType* kde) const; -}; - -class DeleteVisitor : public boost::static_visitor -{ - public: - //! Delete KDEType instance. - template - void operator()(KDEType* kde) const; -}; - class KDEModel { public: @@ -413,34 +280,10 @@ class KDEModel double mcBreakCoef; /** - * kdeModel holds an instance of each possible combination of KernelType and - * TreeType. It is initialized using BuildModel. + * kdeModel holds whatever KDE type we are using. It is initialized using the + * `BuildModel()` method. */ - boost::variant*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*, - KDEType*> kdeModel; + KDEWrapperBase* kdeModel; public: /** @@ -487,11 +330,16 @@ class KDEModel /** * Copy the given model. * - * Use std::move if the object to copy is no longer needed. - * * @param other KDEModel to copy. */ - KDEModel& operator=(KDEModel other); + KDEModel& operator=(const KDEModel& other); + + /** + * Take ownership of the contents of the given model. + * + * @param other KDEModel to take ownership of. + */ + KDEModel& operator=(KDEModel&& other); //! Destroy the KDEModel object. ~KDEModel(); @@ -561,10 +409,10 @@ class KDEModel void MCBreakCoefficient(const double newBreakCoef); //! Get the mode of the model. - KDEMode Mode() const; + KDEMode Mode() const { return kdeModel->Mode(); } //! Modify the mode of the model. - KDEMode& Mode(); + KDEMode& Mode() { return kdeModel->Mode(); } /** * Build the KDE model with the given parameters and then trains it with the diff --git a/src/mlpack/methods/kde/kde_model_impl.hpp b/src/mlpack/methods/kde/kde_model_impl.hpp index 4b59e7657a..bc00f1d50b 100644 --- a/src/mlpack/methods/kde/kde_model_impl.hpp +++ b/src/mlpack/methods/kde/kde_model_impl.hpp @@ -18,521 +18,96 @@ namespace mlpack { namespace kde { -//! Initialize the KDEModel with the given parameters. -inline KDEModel::KDEModel(const double bandwidth, - const double relError, - const double absError, - const KernelTypes kernelType, - const TreeTypes treeType, - const bool monteCarlo, - const double mcProb, - const size_t initialSampleSize, - const double mcEntryCoef, - const double mcBreakCoef) : - bandwidth(bandwidth), - relError(relError), - absError(absError), - kernelType(kernelType), - treeType(treeType), - monteCarlo(monteCarlo), - mcProb(mcProb), - initialSampleSize(initialSampleSize), - mcEntryCoef(mcEntryCoef), - mcBreakCoef(mcBreakCoef) -{ - // Nothing to do. -} - -// Copy constructor. -inline KDEModel::KDEModel(const KDEModel& other) : - bandwidth(other.bandwidth), - relError(other.relError), - absError(other.absError), - kernelType(other.kernelType), - treeType(other.treeType), - monteCarlo(other.monteCarlo), - mcProb(other.mcProb), - initialSampleSize(other.initialSampleSize), - mcEntryCoef(other.mcEntryCoef), - mcBreakCoef(other.mcBreakCoef) -{ - // Nothing to do. -} - -// Move constructor. -inline KDEModel::KDEModel(KDEModel&& other) : - bandwidth(other.bandwidth), - relError(other.relError), - absError(other.absError), - kernelType(other.kernelType), - treeType(other.treeType), - monteCarlo(other.monteCarlo), - mcProb(other.mcProb), - initialSampleSize(other.initialSampleSize), - mcEntryCoef(other.mcEntryCoef), - mcBreakCoef(other.mcBreakCoef), - kdeModel(std::move(other.kdeModel)) -{ - // Reset other model. - other.bandwidth = 1.0; - other.relError = KDEDefaultParams::relError; - other.absError = KDEDefaultParams::absError; - other.kernelType = KernelTypes::GAUSSIAN_KERNEL; - other.treeType = TreeTypes::KD_TREE; - other.monteCarlo = KDEDefaultParams::monteCarlo; - other.mcProb = KDEDefaultParams::mcProb; - other.initialSampleSize = KDEDefaultParams::initialSampleSize; - other.mcEntryCoef = KDEDefaultParams::mcEntryCoef; - other.mcBreakCoef = KDEDefaultParams::mcBreakCoef; - other.kdeModel = decltype(other.kdeModel)(); -} - -inline KDEModel& KDEModel::operator=(KDEModel other) -{ - boost::apply_visitor(DeleteVisitor(), kdeModel); - bandwidth = other.bandwidth; - relError = other.relError; - absError = other.absError; - kernelType = other.kernelType; - treeType = other.treeType; - monteCarlo = other.monteCarlo; - mcProb = other.mcProb; - initialSampleSize = other.initialSampleSize; - mcEntryCoef = other.mcEntryCoef; - mcBreakCoef = other.mcBreakCoef; - kdeModel = std::move(other.kdeModel); - return *this; -} - -// Clean memory. -inline KDEModel::~KDEModel() -{ - boost::apply_visitor(DeleteVisitor(), kdeModel); -} - -inline void KDEModel::BuildModel(arma::mat&& referenceSet) -{ - // Clean memory, if necessary. - boost::apply_visitor(DeleteVisitor(), kdeModel); - - // Build the actual model. - if (kernelType == GAUSSIAN_KERNEL && treeType == KD_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::GaussianKernel(bandwidth)); - } - else if (kernelType == GAUSSIAN_KERNEL && treeType == BALL_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::GaussianKernel(bandwidth)); - } - else if (kernelType == GAUSSIAN_KERNEL && treeType == COVER_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::GaussianKernel(bandwidth)); - } - else if (kernelType == GAUSSIAN_KERNEL && treeType == OCTREE) - { - kdeModel = new KDEType - (relError, absError, kernel::GaussianKernel(bandwidth)); - } - else if (kernelType == GAUSSIAN_KERNEL && treeType == R_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::GaussianKernel(bandwidth)); - } - else if (kernelType == EPANECHNIKOV_KERNEL && treeType == KD_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::EpanechnikovKernel(bandwidth)); - } - else if (kernelType == EPANECHNIKOV_KERNEL && treeType == BALL_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::EpanechnikovKernel(bandwidth)); - } - else if (kernelType == EPANECHNIKOV_KERNEL && treeType == COVER_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::EpanechnikovKernel(bandwidth)); - } - else if (kernelType == EPANECHNIKOV_KERNEL && treeType == OCTREE) - { - kdeModel = new KDEType - (relError, absError, kernel::EpanechnikovKernel(bandwidth)); - } - else if (kernelType == EPANECHNIKOV_KERNEL && treeType == R_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::EpanechnikovKernel(bandwidth)); - } - else if (kernelType == LAPLACIAN_KERNEL && treeType == KD_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::LaplacianKernel(bandwidth)); - } - else if (kernelType == LAPLACIAN_KERNEL && treeType == BALL_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::LaplacianKernel(bandwidth)); - } - else if (kernelType == LAPLACIAN_KERNEL && treeType == COVER_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::LaplacianKernel(bandwidth)); - } - else if (kernelType == LAPLACIAN_KERNEL && treeType == OCTREE) - { - kdeModel = new KDEType - (relError, absError, kernel::LaplacianKernel(bandwidth)); - } - else if (kernelType == LAPLACIAN_KERNEL && treeType == R_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::LaplacianKernel(bandwidth)); - } - else if (kernelType == SPHERICAL_KERNEL && treeType == KD_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::SphericalKernel(bandwidth)); - } - else if (kernelType == SPHERICAL_KERNEL && treeType == BALL_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::SphericalKernel(bandwidth)); - } - else if (kernelType == SPHERICAL_KERNEL && treeType == COVER_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::SphericalKernel(bandwidth)); - } - else if (kernelType == SPHERICAL_KERNEL && treeType == OCTREE) - { - kdeModel = new KDEType - (relError, absError, kernel::SphericalKernel(bandwidth)); - } - else if (kernelType == SPHERICAL_KERNEL && treeType == R_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::SphericalKernel(bandwidth)); - } - else if (kernelType == TRIANGULAR_KERNEL && treeType == KD_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::TriangularKernel(bandwidth)); - } - else if (kernelType == TRIANGULAR_KERNEL && treeType == BALL_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::TriangularKernel(bandwidth)); - } - else if (kernelType == TRIANGULAR_KERNEL && treeType == COVER_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::TriangularKernel(bandwidth)); - } - else if (kernelType == TRIANGULAR_KERNEL && treeType == OCTREE) - { - kdeModel = new KDEType - (relError, absError, kernel::TriangularKernel(bandwidth)); - } - else if (kernelType == TRIANGULAR_KERNEL && treeType == R_TREE) - { - kdeModel = new KDEType - (relError, absError, kernel::TriangularKernel(bandwidth)); - } - - // Set whether to use Monte Carlo estimations or not. - MonteCarloVisitor MCVisitor(monteCarlo); - boost::apply_visitor(MCVisitor, kdeModel); - - // Set Monte Carlo probability. - MCProbabilityVisitor probabilityVisitor(mcProb); - boost::apply_visitor(probabilityVisitor, kdeModel); - - // Set Monte Carlo initial sample size. - MCSampleSizeVisitor sampleSizeVisitor(initialSampleSize); - boost::apply_visitor(sampleSizeVisitor, kdeModel); - - // Set Monte Carlo entry coefficient. - MCEntryCoefVisitor entryCoefficientVisitor(mcEntryCoef); - boost::apply_visitor(entryCoefficientVisitor, kdeModel); - - // Set Monte Carlo break coefficient. - MCBreakCoefVisitor breakCoefficientVisitor(mcBreakCoef); - boost::apply_visitor(breakCoefficientVisitor, kdeModel); - - // Train the model. - TrainVisitor train(std::move(referenceSet)); - boost::apply_visitor(train, kdeModel); -} - -// Perform bichromatic evaluation. -inline void KDEModel::Evaluate(arma::mat&& querySet, arma::vec& estimations) -{ - Log::Info << "Evaluating KDE..." << std::endl; - DualBiKDE eval(std::move(querySet), estimations); - boost::apply_visitor(eval, kdeModel); -} - -// Perform monochromatic evaluation. -inline void KDEModel::Evaluate(arma::vec& estimations) -{ - Log::Info << "Evaluating KDE..." << std::endl; - DualMonoKDE eval(estimations); - boost::apply_visitor(eval, kdeModel); -} - -// Clean memory. -inline void KDEModel::CleanMemory() -{ - boost::apply_visitor(DeleteVisitor(), kdeModel); -} - -// Parameters for KDE evaluation. -DualMonoKDE::DualMonoKDE(arma::vec& estimations): - estimations(estimations) -{} - -// Default KDE evaluation. +//! Train the model (build the tree). template class TreeType> -void DualMonoKDE::operator()(KDETypeT* kde) const +void KDEWrapper::Train(arma::mat&& referenceSet) { - if (kde) + kde.Train(std::move(referenceSet)); +} + +//! Perform bichromatic KDE (i.e. KDE with a separate query set). +template class TreeType> +void KDEWrapper::Evaluate(arma::mat&& querySet, + arma::vec& estimates) +{ + const size_t dimension = querySet.n_rows; + kde.Evaluate(std::move(querySet), estimates); + KernelNormalizer::ApplyNormalizer(kde.Kernel(), + dimension, + estimates); +} + +//! Perform monochromatic KDE (i.e. with the reference set as the query set). +template class TreeType> +void KDEWrapper::Evaluate(arma::vec& estimates) +{ + kde.Evaluate(estimates); + const size_t dimension = kde.ReferenceTree()->Dataset().n_rows; + KernelNormalizer::ApplyNormalizer(kde.Kernel(), + dimension, + estimates); +} + +template class TreeType, + typename Archive> +void SerializationHelper(Archive& ar, + KDEWrapperBase* kdeModel, + const KDEModel::KernelTypes kernelType) +{ + switch (kernelType) { - kde->Evaluate(estimations); - const size_t dimension = (kde->ReferenceTree())->Dataset().n_rows; - KernelNormalizer::ApplyNormalizer(kde->Kernel(), - dimension, - estimations); + case KDEModel::GAUSSIAN_KERNEL: + { + KDEWrapper& typedModel = + dynamic_cast&>(*kdeModel); + ar(CEREAL_NVP(typedModel)); + break; + } + case KDEModel::EPANECHNIKOV_KERNEL: + { + KDEWrapper& typedModel = + dynamic_cast&>(*kdeModel); + ar(CEREAL_NVP(typedModel)); + break; + } + case KDEModel::LAPLACIAN_KERNEL: + { + KDEWrapper& typedModel = + dynamic_cast&>(*kdeModel); + ar(CEREAL_NVP(typedModel)); + break; + } + case KDEModel::SPHERICAL_KERNEL: + { + KDEWrapper& typedModel = + dynamic_cast&>(*kdeModel); + ar(CEREAL_NVP(typedModel)); + break; + } + case KDEModel::TRIANGULAR_KERNEL: + { + KDEWrapper& typedModel = + dynamic_cast&>(*kdeModel); + ar(CEREAL_NVP(typedModel)); + break; + } } - else - { - throw std::runtime_error("no KDE model initialized"); - } -} - -// Parameters for KDE evaluation. -DualBiKDE::DualBiKDE(arma::mat&& querySet, arma::vec& estimations): - dimension(querySet.n_rows), - querySet(std::move(querySet)), - estimations(estimations) -{} - -// Default KDE evaluation. -template class TreeType> -void DualBiKDE::operator()(KDETypeT* kde) const -{ - if (kde) - { - kde->Evaluate(std::move(querySet), estimations); - KernelNormalizer::ApplyNormalizer(kde->Kernel(), - dimension, - estimations); - } - else - { - throw std::runtime_error("no KDE model initialized"); - } -} - -// Parameters for Train. -TrainVisitor::TrainVisitor(arma::mat&& referenceSet) : - referenceSet(std::move(referenceSet)) -{} - -// Default Train. -template class TreeType> -void TrainVisitor::operator()(KDEType* kde) const -{ - Log::Info << "Training KDE model..." << std::endl; - if (kde) - kde->Train(std::move(referenceSet)); - else - throw std::runtime_error("no KDE model initialized"); -} - -// Modify kernel bandwidth. -BandwidthVisitor::BandwidthVisitor(const double bandwidth) : - bandwidth(bandwidth) -{} - -// Default modify kernel bandwidth. -template class TreeType> -void BandwidthVisitor::operator()(KDEType* kde) const -{ - if (kde) - kde->Kernel() = KernelType(bandwidth); - else - throw std::runtime_error("no KDE model initialized"); -} - -// Modify relative error tolerance. -RelErrorVisitor::RelErrorVisitor(const double relError) : - relError(relError) -{} - -// Default modify relative error tolerance. -template class TreeType> -void RelErrorVisitor::operator()(KDEType* kde) const -{ - if (kde) - kde->RelativeError(relError); - else - throw std::runtime_error("no KDE model initialized"); -} - -// Modify absolute error tolerance. -AbsErrorVisitor::AbsErrorVisitor(const double absError) : - absError(absError) -{} - -// Default modify absolute error tolerance. -template class TreeType> -void AbsErrorVisitor::operator()(KDEType* kde) const -{ - if (kde) - kde->AbsoluteError(absError); - else - throw std::runtime_error("no KDE model initialized"); -} - -// Activate or deactivate Monte Carlo. -MonteCarloVisitor::MonteCarloVisitor(const bool monteCarlo) : - monteCarlo(monteCarlo) -{} - -// Default activate or deactivate Monte Carlo. -template class TreeType> -void MonteCarloVisitor::operator()(KDEType* kde) const -{ - if (kde) - kde->MonteCarlo() = monteCarlo; - else - throw std::runtime_error("no KDE model initialized"); -} - -// Set Monte Carlo probability. -MCProbabilityVisitor::MCProbabilityVisitor(const double probability) : - probability(probability) -{} - -// Default probability for Monte Carlo. -template class TreeType> -void MCProbabilityVisitor::operator()(KDEType* kde) const -{ - if (kde) - kde->MCProb(probability); - else - throw std::runtime_error("no KDE model initialized"); -} - -// Set Monte Carlo sample size. -MCSampleSizeVisitor::MCSampleSizeVisitor(const size_t sampleSize) : - sampleSize(sampleSize) -{} - -// Default sample size for Monte Carlo. -template class TreeType> -void MCSampleSizeVisitor::operator()(KDEType* kde) const -{ - if (kde) - kde->MCInitialSampleSize() = sampleSize; - else - throw std::runtime_error("no KDE model initialized"); -} - -// Set Monte Carlo entry coefficient. -MCEntryCoefVisitor::MCEntryCoefVisitor(const double entryCoef) : - entryCoef(entryCoef) -{} - -// Default entry coefficient for Monte Carlo. -template class TreeType> -void MCEntryCoefVisitor::operator()(KDEType* kde) const -{ - if (kde) - kde->MCEntryCoef(entryCoef); - else - throw std::runtime_error("no KDE model initialized"); -} - -// Set Monte Carlo break coefficient. -MCBreakCoefVisitor::MCBreakCoefVisitor(const double breakCoef) : - breakCoef(breakCoef) -{} - -// Default break coefficient for Monte Carlo. -template class TreeType> -void MCBreakCoefVisitor::operator()(KDEType* kde) const -{ - if (kde) - kde->MCBreakCoef(breakCoef); - else - throw std::runtime_error("no KDE model initialized"); -} - -// Delete model. -template -void DeleteVisitor::operator()(KDEType* kde) const -{ - if (kde) - delete kde; -} - -// Mode of model. -template -KDEMode& ModeVisitor::operator()(KDEType* kde) const -{ - if (kde) - return kde->Mode(); - else - throw std::runtime_error("no KDE model initialized"); -} - -// Get mode of model. -KDEMode KDEModel::Mode() const -{ - return boost::apply_visitor(ModeVisitor(), kdeModel); -} - -// Modify mode of model. -KDEMode& KDEModel::Mode() -{ - return boost::apply_visitor(ModeVisitor(), kdeModel); } // Serialize the model. @@ -560,73 +135,31 @@ void KDEModel::serialize(Archive& ar, const uint32_t /* version */) } if (cereal::is_loading()) - boost::apply_visitor(DeleteVisitor(), kdeModel); + delete kdeModel; - ar(CEREAL_VARIANT_POINTER(kdeModel)); -} + // Avoid polymorphism in serialization by serializing directly by the type. + switch (treeType) + { + case KD_TREE: + SerializationHelper(ar, kdeModel, kernelType); + break; -// Modify model kernel bandwidth. -void KDEModel::Bandwidth(const double newBandwidth) -{ - bandwidth = newBandwidth; - BandwidthVisitor bandwidthVisitor(newBandwidth); - boost::apply_visitor(bandwidthVisitor, kdeModel); -} + case BALL_TREE: + SerializationHelper(ar, kdeModel, kernelType); + break; -// Modify model relative error tolerance. -void KDEModel::RelativeError(const double newRelError) -{ - relError = newRelError; - RelErrorVisitor relErrorVisitor(newRelError); - boost::apply_visitor(relErrorVisitor, kdeModel); -} + case COVER_TREE: + SerializationHelper(ar, kdeModel, kernelType); + break; -// Modify model absolute error tolerance. -void KDEModel::AbsoluteError(const double newAbsError) -{ - absError = newAbsError; - AbsErrorVisitor absErrorVisitor(newAbsError); - boost::apply_visitor(absErrorVisitor, kdeModel); -} + case OCTREE: + SerializationHelper(ar, kdeModel, kernelType); + break; -// Modify whether Monte Carlo estimations will be used. -void KDEModel::MonteCarlo(const bool newMonteCarlo) -{ - monteCarlo = newMonteCarlo; - MonteCarloVisitor monteCarloVisitor(newMonteCarlo); - boost::apply_visitor(monteCarloVisitor, kdeModel); -} - -// Modify model Monte Carlo probability. -void KDEModel::MCProbability(const double newMCProb) -{ - mcProb = newMCProb; - MCProbabilityVisitor mcProbVisitor(newMCProb); - boost::apply_visitor(mcProbVisitor, kdeModel); -} - -// Modify model Monte Carlo initial sample size. -void KDEModel::MCInitialSampleSize(const size_t newSampleSize) -{ - initialSampleSize = newSampleSize; - MCSampleSizeVisitor mcSampleSizeVisitor(newSampleSize); - boost::apply_visitor(mcSampleSizeVisitor, kdeModel); -} - -// Modify model Monte Carlo entry coefficient. -void KDEModel::MCEntryCoefficient(const double newEntryCoef) -{ - mcEntryCoef = newEntryCoef; - MCEntryCoefVisitor mcEntryCoefVisitor(newEntryCoef); - boost::apply_visitor(mcEntryCoefVisitor, kdeModel); -} - -// Modify model Monte Carlo break coefficient. -void KDEModel::MCBreakCoefficient(const double newBreakCoef) -{ - mcBreakCoef = newBreakCoef; - MCBreakCoefVisitor mcBreakCoefVisitor(newBreakCoef); - boost::apply_visitor(mcBreakCoefVisitor, kdeModel); + case R_TREE: + SerializationHelper(ar, kdeModel, kernelType); + break; + } } } // namespace kde From 47c340bf1fe511ec5f900057ce92eacb6f4949cd Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 11 Jan 2021 09:44:44 -0500 Subject: [PATCH 058/253] Fix serialization initialization. --- src/mlpack/methods/kde/kde_model.cpp | 33 +++++++----- src/mlpack/methods/kde/kde_model.hpp | 5 ++ src/mlpack/methods/kde/kde_model_impl.hpp | 2 +- src/mlpack/methods/range_search/rs_model.cpp | 51 ++++++++++--------- src/mlpack/methods/range_search/rs_model.hpp | 5 ++ .../methods/range_search/rs_model_impl.hpp | 2 +- src/mlpack/methods/rann/ra_model.cpp | 49 ++++++++++-------- src/mlpack/methods/rann/ra_model.hpp | 3 ++ src/mlpack/methods/rann/ra_model_impl.hpp | 4 +- 9 files changed, 90 insertions(+), 64 deletions(-) diff --git a/src/mlpack/methods/kde/kde_model.cpp b/src/mlpack/methods/kde/kde_model.cpp index 552f1b4058..7a78c78df5 100644 --- a/src/mlpack/methods/kde/kde_model.cpp +++ b/src/mlpack/methods/kde/kde_model.cpp @@ -149,10 +149,10 @@ KDEModel::~KDEModel() template class TreeType> -KDEWrapperBase* BuildModelHelper(const KDEModel::KernelTypes kernelType, - const double relError, - const double absError, - const double bandwidth) +KDEWrapperBase* InitializeModelHelper(const KDEModel::KernelTypes kernelType, + const double relError, + const double absError, + const double bandwidth) { switch (kernelType) { @@ -181,7 +181,7 @@ KDEWrapperBase* BuildModelHelper(const KDEModel::KernelTypes kernelType, return NULL; } -void KDEModel::BuildModel(arma::mat&& referenceSet) +void KDEModel::InitializeModel() { // Clean memory, if necessary. delete kdeModel; @@ -190,30 +190,35 @@ void KDEModel::BuildModel(arma::mat&& referenceSet) switch (treeType) { case KD_TREE: - kdeModel = BuildModelHelper(kernelType, relError, absError, - bandwidth); + kdeModel = InitializeModelHelper(kernelType, relError, + absError, bandwidth); break; case BALL_TREE: - kdeModel = BuildModelHelper(kernelType, relError, + kdeModel = InitializeModelHelper(kernelType, relError, absError, bandwidth); break; case COVER_TREE: - kdeModel = BuildModelHelper(kernelType, relError, - absError, bandwidth); + kdeModel = InitializeModelHelper(kernelType, + relError, absError, bandwidth); break; case OCTREE: - kdeModel = BuildModelHelper(kernelType, relError, absError, - bandwidth); + kdeModel = InitializeModelHelper(kernelType, relError, + absError, bandwidth); break; case R_TREE: - kdeModel = BuildModelHelper(kernelType, relError, absError, - bandwidth); + kdeModel = InitializeModelHelper(kernelType, relError, + absError, bandwidth); break; } +} + +void KDEModel::BuildModel(arma::mat&& referenceSet) +{ + InitializeModel(); // Set whether to use Monte Carlo estimations or not. kdeModel->MonteCarlo() = monteCarlo; diff --git a/src/mlpack/methods/kde/kde_model.hpp b/src/mlpack/methods/kde/kde_model.hpp index c2f93ba181..48b06c6382 100644 --- a/src/mlpack/methods/kde/kde_model.hpp +++ b/src/mlpack/methods/kde/kde_model.hpp @@ -414,6 +414,11 @@ class KDEModel //! Modify the mode of the model. KDEMode& Mode() { return kdeModel->Mode(); } + /** + * Initialize the KDE model. + */ + void InitializeModel(); + /** * Build the KDE model with the given parameters and then trains it with the * given reference data. diff --git a/src/mlpack/methods/kde/kde_model_impl.hpp b/src/mlpack/methods/kde/kde_model_impl.hpp index bc00f1d50b..325b071cb3 100644 --- a/src/mlpack/methods/kde/kde_model_impl.hpp +++ b/src/mlpack/methods/kde/kde_model_impl.hpp @@ -135,7 +135,7 @@ void KDEModel::serialize(Archive& ar, const uint32_t /* version */) } if (cereal::is_loading()) - delete kdeModel; + InitializeModel(); // Values will be overwritten. // Avoid polymorphism in serialization by serializing directly by the type. switch (treeType) diff --git a/src/mlpack/methods/range_search/rs_model.cpp b/src/mlpack/methods/range_search/rs_model.cpp index 807a347ee4..33308cee35 100644 --- a/src/mlpack/methods/range_search/rs_model.cpp +++ b/src/mlpack/methods/range_search/rs_model.cpp @@ -98,33 +98,11 @@ RSModel::~RSModel() delete rSearch; } -void RSModel::BuildModel(arma::mat&& referenceSet, - const size_t leafSize, - const bool naive, - const bool singleMode) +void RSModel::InitializeModel(const bool naive, const bool singleMode) { - // Initialize random basis if necessary. - if (randomBasis) - { - Log::Info << "Creating random basis..." << std::endl; - math::RandomBasis(q, referenceSet.n_rows); - } - - this->leafSize = leafSize; - // Clean memory, if necessary. delete rSearch; - // Do we need to modify the reference set? - if (randomBasis) - referenceSet = q * referenceSet; - - if (!naive) - { - Timer::Start("tree_building"); - Log::Info << "Building reference tree..." << std::endl; - } - switch (treeType) { case KD_TREE: @@ -183,6 +161,33 @@ void RSModel::BuildModel(arma::mat&& referenceSet, rSearch = new LeafSizeRSWrapper(naive, singleMode); break; } +} + +void RSModel::BuildModel(arma::mat&& referenceSet, + const size_t leafSize, + const bool naive, + const bool singleMode) +{ + // Initialize random basis if necessary. + if (randomBasis) + { + Log::Info << "Creating random basis..." << std::endl; + math::RandomBasis(q, referenceSet.n_rows); + } + + this->leafSize = leafSize; + + // Do we need to modify the reference set? + if (randomBasis) + referenceSet = q * referenceSet; + + if (!naive) + { + Timer::Start("tree_building"); + Log::Info << "Building reference tree..." << std::endl; + } + + InitializeModel(naive, singleMode); rSearch->Train(std::move(referenceSet), leafSize); diff --git a/src/mlpack/methods/range_search/rs_model.hpp b/src/mlpack/methods/range_search/rs_model.hpp index 12638c2836..430274cd9b 100644 --- a/src/mlpack/methods/range_search/rs_model.hpp +++ b/src/mlpack/methods/range_search/rs_model.hpp @@ -300,6 +300,11 @@ class RSModel //! been built). bool& RandomBasis() { return randomBasis; } + /** + * Allocate the memory for the range search model. + */ + void InitializeModel(const bool naive, const bool singleMode); + /** * Build the reference tree on the given dataset with the given parameters. * This takes possession of the reference set to avoid a copy. diff --git a/src/mlpack/methods/range_search/rs_model_impl.hpp b/src/mlpack/methods/range_search/rs_model_impl.hpp index 2df060f977..a59180e1b2 100644 --- a/src/mlpack/methods/range_search/rs_model_impl.hpp +++ b/src/mlpack/methods/range_search/rs_model_impl.hpp @@ -127,7 +127,7 @@ void RSModel::serialize(Archive& ar, const uint32_t /* version */) // This should never happen, but just in case... if (cereal::is_loading()) - delete rSearch; + InitializeModel(false, false); // Values will be overwritten. // Avoid polymorphic serialization by explicitly serializing the correct type. switch (treeType) diff --git a/src/mlpack/methods/rann/ra_model.cpp b/src/mlpack/methods/rann/ra_model.cpp index a6a997a22c..6342acf6b4 100644 --- a/src/mlpack/methods/rann/ra_model.cpp +++ b/src/mlpack/methods/rann/ra_model.cpp @@ -95,32 +95,11 @@ RAModel::~RAModel() delete raSearch; } -void RAModel::BuildModel(arma::mat&& referenceSet, - const size_t leafSize, - const bool naive, - const bool singleMode) +void RAModel::InitializeModel(const bool naive, const bool singleMode) { - // Initialize random basis, if necessary. - if (randomBasis) - { - Log::Info << "Creating random basis..." << std::endl; - math::RandomBasis(q, referenceSet.n_rows); - } - // Clean memory, if necessary. delete raSearch; - this->leafSize = leafSize; - - if (randomBasis) - referenceSet = q * referenceSet; - - if (!naive) - { - Timer::Start("tree_building"); - Log::Info << "Building reference tree..." << std::endl; - } - switch (treeType) { case KD_TREE: @@ -154,6 +133,32 @@ void RAModel::BuildModel(arma::mat&& referenceSet, raSearch = new LeafSizeRAWrapper(naive, singleMode); break; } +} + +void RAModel::BuildModel(arma::mat&& referenceSet, + const size_t leafSize, + const bool naive, + const bool singleMode) +{ + // Initialize random basis, if necessary. + if (randomBasis) + { + Log::Info << "Creating random basis..." << std::endl; + math::RandomBasis(q, referenceSet.n_rows); + } + + this->leafSize = leafSize; + + if (randomBasis) + referenceSet = q * referenceSet; + + if (!naive) + { + Timer::Start("tree_building"); + Log::Info << "Building reference tree..." << std::endl; + } + + InitializeModel(naive, singleMode); raSearch->Train(std::move(referenceSet), leafSize); diff --git a/src/mlpack/methods/rann/ra_model.hpp b/src/mlpack/methods/rann/ra_model.hpp index 8ed91a9c9b..572d599a0d 100644 --- a/src/mlpack/methods/rann/ra_model.hpp +++ b/src/mlpack/methods/rann/ra_model.hpp @@ -385,6 +385,9 @@ class RAModel //! the model using BuildModel(). bool& RandomBasis() { return randomBasis; } + //! Initialize the model's memory. + void InitializeModel(const bool naive, const bool singleMode); + //! Build the reference tree. void BuildModel(arma::mat&& referenceSet, const size_t leafSize, diff --git a/src/mlpack/methods/rann/ra_model_impl.hpp b/src/mlpack/methods/rann/ra_model_impl.hpp index 6955bd9f46..c986c4570c 100644 --- a/src/mlpack/methods/rann/ra_model_impl.hpp +++ b/src/mlpack/methods/rann/ra_model_impl.hpp @@ -126,9 +126,7 @@ void RAModel::serialize(Archive& ar, const uint32_t /* version */) // This should never happen, but just in case, be clean with memory. if (cereal::is_loading()) - { - delete raSearch; - } + InitializeModel(false, false); // Values will be overwritten. // Avoid polymorphic serialization by explicitly serializing the correct type. switch (treeType) From 06950dd1b581a9f6968e12d1e0e217b1ffa91620 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 11 Jan 2021 09:45:18 -0500 Subject: [PATCH 059/253] Remove boost::visitor from mlpack::cf. --- src/mlpack/methods/cf/CMakeLists.txt | 1 + src/mlpack/methods/cf/cf_main.cpp | 437 ++++++++------------- src/mlpack/methods/cf/cf_model.cpp | 207 ++++++++++ src/mlpack/methods/cf/cf_model.hpp | 325 +++++++++------- src/mlpack/methods/cf/cf_model_impl.hpp | 496 ++++++++++++++++-------- src/mlpack/tests/main_tests/cf_test.cpp | 63 ++- 6 files changed, 925 insertions(+), 604 deletions(-) create mode 100644 src/mlpack/methods/cf/cf_model.cpp diff --git a/src/mlpack/methods/cf/CMakeLists.txt b/src/mlpack/methods/cf/CMakeLists.txt index a7c552ae28..c59a4f12ed 100644 --- a/src/mlpack/methods/cf/CMakeLists.txt +++ b/src/mlpack/methods/cf/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES cf_impl.hpp cf_model.hpp cf_model_impl.hpp + cf_model.cpp svd_wrapper.hpp svd_wrapper_impl.hpp ) diff --git a/src/mlpack/methods/cf/cf_main.cpp b/src/mlpack/methods/cf/cf_main.cpp index 760ddf107d..f4aa8e14b7 100644 --- a/src/mlpack/methods/cf/cf_main.cpp +++ b/src/mlpack/methods/cf/cf_main.cpp @@ -194,279 +194,6 @@ PARAM_STRING_IN("interpolation", "Algorithm used for weight interpolation.", PARAM_STRING_IN("neighbor_search", "Algorithm used for neighbor search.", "S", "euclidean"); -template -void ComputeRecommendations(CFModel* cf, - const size_t numRecs, - arma::Mat& recommendations) -{ - // Reading users. - if (IO::HasParam("query")) - { - // User matrix. - arma::Mat users = - std::move(IO::GetParam>("query")); - if (users.n_rows > 1) - users = users.t(); - if (users.n_rows > 1) - Log::Fatal << "List of query users must be one-dimensional!" - << std::endl; - - Log::Info << "Generating recommendations for " - << users.n_elem << " users." - << endl; - - cf->GetRecommendations - (numRecs, recommendations, users.row(0).t()); - } - else - { - Log::Info << "Generating recommendations for all users." << endl; - cf->GetRecommendations - (numRecs, recommendations); - } -} - -template -void ComputeRecommendations(CFModel* cf, - const size_t numRecs, - arma::Mat& recommendations) -{ - // Verify the Interpolation algorithms. - RequireParamInSet("interpolation", { "average", - "regression", "similarity" }, true, "unknown interpolation algorithm"); - - // Taking Interpolation Alternatives - const string interpolationAlgorithm = IO::GetParam("interpolation"); - - // Determining the Interpolation Algorithm - if (interpolationAlgorithm == "average") - { - ComputeRecommendations - (cf, numRecs, recommendations); - } - else if (interpolationAlgorithm == "regression") - { - ComputeRecommendations - (cf, numRecs, recommendations); - } - else if (interpolationAlgorithm == "similarity") - { - ComputeRecommendations - (cf, numRecs, recommendations); - } -} - -void ComputeRecommendations(CFModel* cf, - const size_t numRecs, - arma::Mat& recommendations) -{ - // Verifying the Neighbor Search algorithms - RequireParamInSet("neighbor_search", { "cosine", - "euclidean", "pearson" }, true, "unknown neighbor search algorithm"); - - // Taking Neighbor Search alternatives - const string neighborSearchAlgorithm = IO::GetParam - ("neighbor_search"); - - - // Determining the Neighbor Search Algorithms - if (neighborSearchAlgorithm == "cosine") - { - ComputeRecommendations(cf, numRecs, recommendations); - } - else if (neighborSearchAlgorithm == "euclidean") - { - ComputeRecommendations(cf, numRecs, recommendations); - } - else if (neighborSearchAlgorithm == "pearson") - { - ComputeRecommendations(cf, numRecs, recommendations); - } -} - -template -void ComputeRMSE(CFModel* cf) -{ - // Now, compute each test point. - arma::mat testData = std::move(IO::GetParam("test")); - - // Assemble the combination matrix to get RMSE value. - arma::Mat combinations(2, testData.n_cols); - for (size_t i = 0; i < testData.n_cols; ++i) - { - combinations(0, i) = size_t(testData(0, i)); - combinations(1, i) = size_t(testData(1, i)); - } - - // Now compute the RMSE. - arma::vec predictions; - cf->Predict - (combinations, predictions); - - // Compute the root of the sum of the squared errors, divide by the number of - // points to get the RMSE. It turns out this is just the L2-norm divided by - // the square root of the number of points, if we interpret the predictions - // and the true values as vectors. - const double rmse = arma::norm(predictions - testData.row(2).t(), 2) / - std::sqrt((double) testData.n_cols); - - Log::Info << "RMSE is " << rmse << "." << endl; -} - -template -void ComputeRMSE(CFModel* cf) -{ - // Verifying the Interpolation algorithms - RequireParamInSet("interpolation", { "average", - "regression", "similarity" }, true, "unknown interpolation algorithm"); - - // Taking Interpolation Alternatives - const string interpolationAlgorithm = IO::GetParam("interpolation"); - - if (interpolationAlgorithm == "average") - { - ComputeRMSE(cf); - } - else if (interpolationAlgorithm == "regression") - { - ComputeRMSE(cf); - } - else if (interpolationAlgorithm == "similarity") - { - ComputeRMSE(cf); - } -} - -void ComputeRMSE(CFModel* cf) -{ - // Verifying the Neighbor Search algorithms - RequireParamInSet("neighbor_search", { "cosine", - "euclidean", "pearson" }, true, "unknown neighbor search algorithm"); - - // Taking Neighbor Search alternatives - const string neighborSearchAlgorithm = IO::GetParam - ("neighbor_search"); - - if (neighborSearchAlgorithm == "cosine") - { - ComputeRMSE(cf); - } - else if (neighborSearchAlgorithm == "euclidean") - { - ComputeRMSE(cf); - } - else if (neighborSearchAlgorithm == "pearson") - { - ComputeRMSE(cf); - } -} - -void PerformAction(CFModel* c) -{ - if (IO::HasParam("query") || IO::HasParam("all_user_recommendations")) - { - // Get parameters for generating recommendations. - const size_t numRecs = (size_t) IO::GetParam("recommendations"); - - // Get the recommendations. - arma::Mat recommendations; - ComputeRecommendations(c, numRecs, recommendations); - - // Save the output. - IO::GetParam>("output") = recommendations; - } - - if (IO::HasParam("test")) - ComputeRMSE(c); - - IO::GetParam("output_model") = c; -} - -template -void PerformAction(arma::mat& dataset, - const size_t rank, - const size_t maxIterations, - const double minResidue) -{ - const size_t neighborhood = (size_t) IO::GetParam("neighborhood"); - - // Make sure the normalization strategy is valid. - RequireParamInSet("normalization", { "overall_mean", "item_mean", - "user_mean", "z_score", "none" }, true, "unknown normalization type"); - - CFModel* c = new CFModel(); - - const string normalizationType = IO::GetParam("normalization"); - - c->template Train(dataset, neighborhood, rank, - maxIterations, minResidue, IO::HasParam("iteration_only_termination"), - normalizationType); - - try - { - PerformAction(c); - } - catch (std::exception& e) - { - // Clean the memory before throwing completely. - delete c; - throw; - } -} - -void AssembleFactorizerType(const std::string& algorithm, - arma::mat& dataset, - const size_t rank) -{ - const size_t maxIterations = (size_t) IO::GetParam("max_iterations"); - const double minResidue = IO::GetParam("min_residue"); - - if (algorithm == "NMF") - { - PerformAction(dataset, rank, maxIterations, minResidue); - } - else if (algorithm == "BatchSVD") - { - PerformAction(dataset, rank, maxIterations, minResidue); - } - else if (algorithm == "SVDIncompleteIncremental") - { - PerformAction(dataset, rank, maxIterations, - minResidue); - } - else if (algorithm == "SVDCompleteIncremental") - { - PerformAction(dataset, rank, maxIterations, minResidue); - } - else if (algorithm == "RegSVD") - { - ReportIgnoredParam("min_residue", "Regularized SVD terminates only " - "when max_iterations is reached"); - PerformAction(dataset, rank, maxIterations, minResidue); - } - else if (algorithm == "RandSVD") - { - ReportIgnoredParam("min_residue", "Randomized SVD terminates only " - "when max_iterations is reached"); - PerformAction(dataset, rank, maxIterations, - minResidue); - } - else if (algorithm == "BiasSVD") - { - ReportIgnoredParam("min_residue", "Bias SVD terminates only " - "when max_iterations is reached"); - PerformAction(dataset, rank, maxIterations, minResidue); - } - else if (algorithm == "SVDPP") - { - ReportIgnoredParam("min_residue", "SVD++ terminates only " - "when max_iterations is reached"); - PerformAction(dataset, rank, maxIterations, minResidue); - } -} - static void mlpackMain() { if (IO::GetParam("seed") == 0) @@ -496,6 +223,7 @@ static void mlpackMain() "recommendations must be positive"); // Either load from a model, or train a model. + CFModel* cf; if (IO::HasParam("training")) { // Train a model. @@ -523,23 +251,174 @@ static void mlpackMain() // Get parameters. const size_t rank = (size_t) IO::GetParam("rank"); + cf = new CFModel(); + // Perform decomposition to prepare for recommendations. Log::Info << "Performing CF matrix decomposition on dataset..." << endl; const string algo = IO::GetParam("algorithm"); + if (algo == "NMF") + { + cf->DecompositionType() = CFModel::NMF; + } + else if (algo == "BatchSVD") + { + cf->DecompositionType() = CFModel::BATCH_SVD; + } + else if (algo == "SVDIncompleteIncremental") + { + cf->DecompositionType() = CFModel::SVD_INCOMPLETE; + } + else if (algo == "SVDCompleteIncremental") + { + cf->DecompositionType() = CFModel::SVD_COMPLETE; + } + else if (algo == "RegSVD") + { + ReportIgnoredParam("min_residue", "Regularized SVD terminates only " + "when max_iterations is reached"); + cf->DecompositionType() = CFModel::REG_SVD; + } + else if (algo == "RandSVD") + { + ReportIgnoredParam("min_residue", "Randomized SVD terminates only " + "when max_iterations is reached"); + cf->DecompositionType() = CFModel::RANDOMIZED_SVD; + } + else if (algo == "BiasSVD") + { + ReportIgnoredParam("min_residue", "Bias SVD terminates only " + "when max_iterations is reached"); + cf->DecompositionType() = CFModel::BIAS_SVD; + } + else if (algo == "SVDPP") + { + ReportIgnoredParam("min_residue", "SVD++ terminates only " + "when max_iterations is reached"); + cf->DecompositionType() = CFModel::SVD_PLUS_PLUS; + } // Perform the factorization and do whatever the user wanted. - AssembleFactorizerType(algo, dataset, rank); + const size_t neighborhood = (size_t) IO::GetParam("neighborhood"); + + // Make sure the normalization strategy is valid. + RequireParamInSet("normalization", { "overall_mean", "item_mean", + "user_mean", "z_score", "none" }, true, "unknown normalization type"); + + const string normalizationType = IO::GetParam("normalization"); + if (normalizationType == "none") + cf->NormalizationType() = CFModel::NO_NORMALIZATION; + else if (normalizationType == "item_mean") + cf->NormalizationType() = CFModel::ITEM_MEAN_NORMALIZATION; + else if (normalizationType == "user_mean") + cf->NormalizationType() = CFModel::USER_MEAN_NORMALIZATION; + else if (normalizationType == "overall_mean") + cf->NormalizationType() = CFModel::OVERALL_MEAN_NORMALIZATION; + else if (normalizationType == "z_score") + cf->NormalizationType() = CFModel::Z_SCORE_NORMALIZATION; + + cf->Train(dataset, + neighborhood, + rank, + size_t(IO::GetParam("max_iterations")), + IO::GetParam("min_residue"), + IO::HasParam("iteration_only_termination")); } else { // Load from a model after validating parameters. - RequireAtLeastOnePassed({ "query", "all_user_recommendations", - "test" }, true); + RequireAtLeastOnePassed({ "query", "all_user_recommendations", "test" }, + true); // Load an input model. - CFModel* c = std::move(IO::GetParam("input_model")); - - PerformAction(c); + cf = std::move(IO::GetParam("input_model")); } + + // Get the types of the neighbor search method and the interpolation. (These + // may or may not be used.) + NeighborSearchTypes nsType; + RequireParamInSet("neighbor_search", { "cosine", + "euclidean", "pearson" }, true, "unknown neighbor search algorithm"); + if (IO::GetParam("neighbor_search") == "cosine") + nsType = COSINE_SEARCH; + else if (IO::GetParam("neighbor_search") == "euclidean") + nsType = EUCLIDEAN_SEARCH; + else if (IO::GetParam("neighbor_search") == "pearson") + nsType = PEARSON_SEARCH; + + InterpolationTypes interpolationType; + RequireParamInSet("interpolation", { "average", + "regression", "similarity" }, true, "unknown interpolation algorithm"); + if (IO::GetParam("interpolation") == "average") + interpolationType = AVERAGE_INTERPOLATION; + else if (IO::GetParam("interpolation") == "regression") + interpolationType = REGRESSION_INTERPOLATION; + else if (IO::GetParam("interpolation") == "similarity") + interpolationType = SIMILARITY_INTERPOLATION; + + if (IO::HasParam("query") || IO::HasParam("all_user_recommendations")) + { + // Get parameters for generating recommendations. + const size_t numRecs = (size_t) IO::GetParam("recommendations"); + + // Get the recommendations. + arma::Mat recommendations; + + // Reading users. + if (IO::HasParam("query")) + { + // User matrix. + arma::Mat users = + std::move(IO::GetParam>("query")); + if (users.n_rows > 1) + users = users.t(); + if (users.n_rows > 1) + Log::Fatal << "List of query users must be one-dimensional!" + << std::endl; + + Log::Info << "Generating recommendations for " << users.n_elem + << " users." << endl; + + cf->GetRecommendations(nsType, interpolationType, numRecs, + recommendations, users.row(0).t()); + } + else + { + Log::Info << "Generating recommendations for all users." << endl; + cf->GetRecommendations(nsType, interpolationType, numRecs, + recommendations); + } + + // Save the output. + IO::GetParam>("output") = recommendations; + } + + if (IO::HasParam("test")) + { + // Now, compute each test point. + arma::mat testData = std::move(IO::GetParam("test")); + + // Assemble the combination matrix to get RMSE value. + arma::Mat combinations(2, testData.n_cols); + for (size_t i = 0; i < testData.n_cols; ++i) + { + combinations(0, i) = size_t(testData(0, i)); + combinations(1, i) = size_t(testData(1, i)); + } + + // Now compute the RMSE. + arma::vec predictions; + cf->Predict(nsType, interpolationType, combinations, predictions); + + // Compute the root of the sum of the squared errors, divide by the number + // of points to get the RMSE. It turns out this is just the L2-norm divided + // by the square root of the number of points, if we interpret the + // predictions and the true values as vectors. + const double rmse = arma::norm(predictions - testData.row(2).t(), 2) / + std::sqrt((double) testData.n_cols); + + Log::Info << "RMSE is " << rmse << "." << endl; + } + + IO::GetParam("output_model") = cf; } diff --git a/src/mlpack/methods/cf/cf_model.cpp b/src/mlpack/methods/cf/cf_model.cpp new file mode 100644 index 0000000000..226edcf1be --- /dev/null +++ b/src/mlpack/methods/cf/cf_model.cpp @@ -0,0 +1,207 @@ +/** + * @file methods/cf/cf_model_impl.hpp + * @author Wenhao Huang + * + * A serializable CF model, used by the main program. + * + * 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 "cf_model.hpp" + +namespace mlpack { +namespace cf { + +CFModel::CFModel() : + decompositionType(NMF), + normalizationType(NO_NORMALIZATION), + cf(NULL) +{ + // Nothing else to do. +} + +CFModel::CFModel(const CFModel& other) : + decompositionType(other.decompositionType), + normalizationType(other.normalizationType), + cf(other.cf->Clone()) +{ + // Nothing else to do. +} + +CFModel::CFModel(CFModel&& other) : + decompositionType(other.decompositionType), + normalizationType(other.normalizationType), + cf(std::move(other.cf)) +{ + // Reset properties of the other one. + other.decompositionType = NMF; + other.normalizationType = NO_NORMALIZATION; +} + +CFModel& CFModel::operator=(const CFModel& other) +{ + if (this != &other) + { + decompositionType = other.decompositionType; + normalizationType = other.normalizationType; + cf = other.cf->Clone(); + } + + return *this; +} + +CFModel& CFModel::operator=(CFModel&& other) +{ + if (this != &other) + { + decompositionType = other.decompositionType; + normalizationType = other.normalizationType; + cf = std::move(other.cf); + + // Reset the other object. + other.decompositionType = NMF; + other.normalizationType = NO_NORMALIZATION; + } + + return *this; +} + +CFModel::~CFModel() +{ + delete cf; +} + +template +CFWrapperBase* TrainHelper(const DecompositionPolicy& decomposition, + const CFModel::NormalizationTypes normalizationType, + const arma::mat& data, + const size_t numUsersForSimilarity, + const size_t rank, + const size_t maxIterations, + const double minResidue, + const bool mit) +{ + switch (normalizationType) + { + case CFModel::NO_NORMALIZATION: + return new CFWrapper(data, + decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, + mit); + break; + + case CFModel::ITEM_MEAN_NORMALIZATION: + return new CFWrapper(data, + decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, + mit); + break; + + case CFModel::USER_MEAN_NORMALIZATION: + return new CFWrapper(data, + decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, + mit); + break; + + case CFModel::OVERALL_MEAN_NORMALIZATION: + return new CFWrapper(data, + decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, + mit); + break; + + case CFModel::Z_SCORE_NORMALIZATION: + return new CFWrapper(data, + decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, + mit); + break; + } + + // This shouldn't ever happen. + return NULL; +} + +void CFModel::Train(const arma::mat& data, + const size_t numUsersForSimilarity, + const size_t rank, + const size_t maxIterations, + const double minResidue, + const bool mit) +{ + // Delete the current CFType object, if there is one. + delete cf; + + switch (decompositionType) + { + case NMF: + cf = TrainHelper(NMFPolicy(), normalizationType, data, + numUsersForSimilarity, rank, maxIterations, minResidue, mit); + break; + + case BATCH_SVD: + cf = TrainHelper(BatchSVDPolicy(), normalizationType, data, + numUsersForSimilarity, rank, maxIterations, minResidue, mit); + break; + + case RANDOMIZED_SVD: + cf = TrainHelper(RandomizedSVDPolicy(), normalizationType, data, + numUsersForSimilarity, rank, maxIterations, minResidue, mit); + break; + + case REG_SVD: + cf = TrainHelper(RegSVDPolicy(), normalizationType, data, + numUsersForSimilarity, rank, maxIterations, minResidue, mit); + break; + + case SVD_COMPLETE: + cf = TrainHelper(SVDCompletePolicy(), normalizationType, data, + numUsersForSimilarity, rank, maxIterations, minResidue, mit); + break; + + case SVD_INCOMPLETE: + cf = TrainHelper(SVDIncompletePolicy(), normalizationType, data, + numUsersForSimilarity, rank, maxIterations, minResidue, mit); + break; + + case BIAS_SVD: + cf = TrainHelper(BiasSVDPolicy(), normalizationType, data, + numUsersForSimilarity, rank, maxIterations, minResidue, mit); + break; + + case SVD_PLUS_PLUS: + cf = TrainHelper(SVDPlusPlusPolicy(), normalizationType, data, + numUsersForSimilarity, rank, maxIterations, minResidue, mit); + break; + } +} + +//! Make predictions. +void CFModel::Predict(const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const arma::Mat& combinations, + arma::vec& predictions) +{ + cf->Predict(nsType, interpolationType, combinations, predictions); +} + +//! Compute recommendations for queried users. +void CFModel::GetRecommendations(const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const size_t numRecs, + arma::Mat& recommendations, + const arma::Col& users) +{ + cf->GetRecommendations(nsType, interpolationType, numRecs, recommendations, + users); +} + +//! Compute recommendations for all users. +void CFModel::GetRecommendations(const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const size_t numRecs, + arma::Mat& recommendations) +{ + cf->GetRecommendations(nsType, interpolationType, numRecs, recommendations); +} + +} // namespace cf +} // namespace mlpack diff --git a/src/mlpack/methods/cf/cf_model.hpp b/src/mlpack/methods/cf/cf_model.hpp index 93ff371a02..354f8b51b5 100644 --- a/src/mlpack/methods/cf/cf_model.hpp +++ b/src/mlpack/methods/cf/cf_model.hpp @@ -14,105 +14,146 @@ #define MLPACK_METHODS_CF_CF_MODEL_HPP #include -#include #include "cf.hpp" -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - namespace mlpack { namespace cf { /** - * DeleteVisitor deletes the CFType<> object which is pointed to by the - * variable cf in class CFModel. + * NeighborSearchTypes contains the set of NeighborSearchPolicy classes that are + * usable by CFModel at prediction time. */ -class DeleteVisitor : public boost::static_visitor +enum NeighborSearchTypes { - public: - //! Delete CFType object. - template - void operator()(CFType* c) const; + COSINE_SEARCH, + EUCLIDEAN_SEARCH, + PEARSON_SEARCH }; /** - * GetValueVisitor returns the pointer which points to the CFType object. + * InterpolationTypes contains the set of InterpolationPolicy classes that are + * usable by CFModel at prediction time. */ -class GetValueVisitor : public boost::static_visitor +enum InterpolationTypes { - public: - //! Return stored pointer as void* type. - template - void* operator()(CFType* c) const; + AVERAGE_INTERPOLATION, + REGRESSION_INTERPOLATION, + SIMILARITY_INTERPOLATION }; /** - * PredictVisitor uses the CFType object to make predictions on the given - * combinations of users and items. + * The CFWrapperBase class provides a unified interface that can be used by the + * CFModel class to interact with all different CF types at runtime. All CF + * wrapper types inherit from this base class. */ -template -class PredictVisitor : public boost::static_visitor +class CFWrapperBase { - private: - //! User/item combinations to predict. - const arma::Mat& combinations; - //! Predicted ratings for each user/item combination. - arma::vec& predictions; - public: - //! Predict ratings for each user-item combination. - template - void operator()(CFType* c) const; + //! Create the object. The base class has nothing to hold. + CFWrapperBase() { } - //! Visitor constructor. - PredictVisitor(const arma::Mat& combinations, - arma::vec& predictions); + //! Make a copy of the object. + virtual CFWrapperBase* Clone() const = 0; + + //! Delete the object. + virtual ~CFWrapperBase() { } + + //! Compute predictions for users. + virtual void Predict(const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const arma::Mat& combinations, + arma::vec& predictions) = 0; + + //! Compute recommendations for all users. + virtual void GetRecommendations( + const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const size_t numRecs, + arma::Mat& recommendations) = 0; + + //! Compute recommendations. + virtual void GetRecommendations( + const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const size_t numRecs, + arma::Mat& recommendations, + const arma::Col& users) = 0; }; /** - * RecommendationVisitor uses the CFType object to get recommendations for the - * given users. + * The CFWrapper class wraps the functionality of all CF types. If special + * handling is needed for a future CF type, this class can be extended. */ -template -class RecommendationVisitor : public boost::static_visitor +template +class CFWrapper : public CFWrapperBase { - private: - //! Number of Recommendations. - const size_t numRecs; - //! Recommendations matrix to save recommendations. - arma::Mat& recommendations; - //! Users for which recommendations are to be generated. - const arma::Col& users; - //! Whether users are given. - const bool usersGiven; + protected: + typedef CFType CFModelType; public: - //! Visitor constructor. - RecommendationVisitor(const size_t numRecs, - arma::Mat& recommendations, - const arma::Col& users, - const bool usersGiven); + //! Create the CFWrapper object, using default parameters to initialize the + //! held CF object. + CFWrapper() { } - //! Generates the given number of recommendations. - template - void operator()(CFType* c) const; + //! Create the CFWrapper object, initializing the held CF object. + CFWrapper(const arma::mat& data, + const DecompositionPolicy& decomposition, + const size_t numUsersForSimilarity, + const size_t rank, + const size_t maxIterations, + const size_t minResidue, + const bool mit) : + cf(data, + decomposition, + numUsersForSimilarity, + rank, + maxIterations, + minResidue, + mit) + { + // Nothing else to do. + } + + //! Clone the CFWrapper object. This handles polymorphism correctly. + virtual CFWrapper* Clone() const { return new CFWrapper(*this); } + + //! Destroy the CFWrapper object. + virtual ~CFWrapper() { } + + //! Get the CFType object. + CFModelType& CF() { return cf; } + + //! Compute predictions for users. + virtual void Predict(const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const arma::Mat& combinations, + arma::vec& predictions); + + //! Compute recommendations for all users. + virtual void GetRecommendations( + const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const size_t numRecs, + arma::Mat& recommendations); + + //! Compute recommendations. + virtual void GetRecommendations( + const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const size_t numRecs, + arma::Mat& recommendations, + const arma::Col& users); + + //! Serialize the model. + template + void serialize(Archive& ar, const uint32_t /* version */) + { + ar(CEREAL_NVP(cf)); + } + + protected: + //! This is the CF object that we are wrapping. + CFModelType cf; }; /** @@ -120,98 +161,110 @@ class RecommendationVisitor : public boost::static_visitor */ class CFModel { + public: + enum DecompositionTypes + { + NMF, + BATCH_SVD, + RANDOMIZED_SVD, + REG_SVD, + SVD_COMPLETE, + SVD_INCOMPLETE, + BIAS_SVD, + SVD_PLUS_PLUS + }; + + enum NormalizationTypes + { + NO_NORMALIZATION, + ITEM_MEAN_NORMALIZATION, + USER_MEAN_NORMALIZATION, + OVERALL_MEAN_NORMALIZATION, + Z_SCORE_NORMALIZATION + }; + private: + //! The current decomposition policy type. + DecompositionTypes decompositionType; + //! The current normalization policy type. + NormalizationTypes normalizationType; + /** * cf holds an instance of the CFType class for the current * decompositionPolicy and normalizationType. It is initialized every time - * Train() is executed. We access to the contained value through the visitor - * classes defined above. + * Train() is executed. */ - boost::variant*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*, - CFType*> cf; + CFWrapperBase* cf; public: //! Create an empty CF model. - CFModel() { } + CFModel(); + + //! Create a CF model by copying the given model. + CFModel(const CFModel& other); + + //! Create a CF model by taking ownership of the data of the other model. + CFModel(CFModel&& other); + + //! Make this CF model a copy of the other model. + CFModel& operator=(const CFModel& other); + + //! Make this CF model take ownership of the data of the other model. + CFModel& operator=(CFModel&& other); //! Clean up memory. ~CFModel(); - //! Get the pointer to CFType<> object. - template - const CFType* CFPtr() const; + //! Get the CFWrapperBase object. (Be careful!) + CFWrapperBase* CF() const { return cf; } + + //! Get the decomposition type. + const DecompositionTypes& DecompositionType() const + { + return decompositionType; + } + //! Set the decomposition type. + DecompositionTypes& DecompositionType() + { + return decompositionType; + } + + //! Get the normalization type. + const NormalizationTypes& NormalizationType() const + { + return normalizationType; + } + //! Set the normalization type. + NormalizationTypes& NormalizationType() + { + return normalizationType; + } //! Train the model. - template - void Train(const MatType& data, + void Train(const arma::mat& data, const size_t numUsersForSimilarity, const size_t rank, const size_t maxIterations, const double minResidue, - const bool mit, - const std::string& normalizationType = "none"); + const bool mit); //! Make predictions. - template - void Predict(const arma::Mat& combinations, + void Predict(const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const arma::Mat& combinations, arma::vec& predictions); //! Compute recommendations for query users. - template - void GetRecommendations(const size_t numRecs, + void GetRecommendations(const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const size_t numRecs, arma::Mat& recommendations, const arma::Col& users); //! Compute recommendations for all users. - template - void GetRecommendations(const size_t numRecs, + void GetRecommendations(const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const size_t numRecs, arma::Mat& recommendations); //! Serialize the model. diff --git a/src/mlpack/methods/cf/cf_model_impl.hpp b/src/mlpack/methods/cf/cf_model_impl.hpp index 6df3491e59..fa2634a823 100644 --- a/src/mlpack/methods/cf/cf_model_impl.hpp +++ b/src/mlpack/methods/cf/cf_model_impl.hpp @@ -14,204 +14,364 @@ #include "cf_model.hpp" -#include -#include -#include -#include -#include +#include "interpolation_policies/average_interpolation.hpp" +#include "interpolation_policies/regression_interpolation.hpp" +#include "interpolation_policies/similarity_interpolation.hpp" -using namespace mlpack::cf; +#include "neighbor_search_policies/cosine_search.hpp" +#include "neighbor_search_policies/lmetric_search.hpp" +#include "neighbor_search_policies/pearson_search.hpp" -template -void DeleteVisitor:: -operator()(CFType* c) const +#include "decomposition_policies/batch_svd_method.hpp" +#include "decomposition_policies/bias_svd_method.hpp" +#include "decomposition_policies/nmf_method.hpp" +#include "decomposition_policies/randomized_svd_method.hpp" +#include "decomposition_policies/regularized_svd_method.hpp" +#include "decomposition_policies/svd_complete_method.hpp" +#include "decomposition_policies/svd_incomplete_method.hpp" +#include "decomposition_policies/svdplusplus_method.hpp" + +#include "normalization/no_normalization.hpp" +#include "normalization/overall_mean_normalization.hpp" +#include "normalization/user_mean_normalization.hpp" +#include "normalization/item_mean_normalization.hpp" +#include "normalization/z_score_normalization.hpp" + +namespace mlpack { +namespace cf { + +template +void PredictHelper(CFType& cf, + const InterpolationTypes interpolationType, + const arma::Mat& combinations, + arma::vec& predictions) { - if (c) - delete c; -} - -template -void* GetValueVisitor:: -operator()(CFType* c) const -{ - if (!c) - throw std::runtime_error("no cf model initialized"); - - return (void*) c; -} - -template -PredictVisitor::PredictVisitor( - const arma::Mat& combinations, - arma::vec& predictions) : - combinations(combinations), - predictions(predictions) -{ } - -template -template -void PredictVisitor - ::operator()(CFType* c) const -{ - if (!c) + switch (interpolationType) { - throw std::runtime_error("no cf model initialized"); - return; - } + case AVERAGE_INTERPOLATION: + cf.template Predict(combinations, predictions); + break; - c->template Predict(combinations, predictions); -} + case REGRESSION_INTERPOLATION: + cf.template Predict(combinations, predictions); + break; -template -RecommendationVisitor - ::RecommendationVisitor( - const size_t numRecs, - arma::Mat& recommendations, - const arma::Col& users, - const bool usersGiven) : - numRecs(numRecs), - recommendations(recommendations), - users(users), - usersGiven(usersGiven) -{ } - -template -template -void RecommendationVisitor - ::operator()(CFType* c) const -{ - if (!c) - { - throw std::runtime_error("no cf model initialized"); - return; - } - - if (usersGiven) - c->template GetRecommendations - (numRecs, recommendations, users); - else - c->template GetRecommendations - (numRecs, recommendations); -} - -CFModel::~CFModel() -{ - boost::apply_visitor(DeleteVisitor(), cf); -} - -template -void CFModel::Train(const MatType& data, - const size_t numUsersForSimilarity, - const size_t rank, - const size_t maxIterations, - const double minResidue, - const bool mit, - const std::string& normalization) -{ - // Delete the current CFType object, if there is one. - boost::apply_visitor(DeleteVisitor(), cf); - - // Instantiate a new CFType object. - DecompositionPolicy decomposition; - if (normalization == "overall_mean") - { - cf = new CFType(data, - decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, - mit); - } - else if (normalization == "item_mean") - { - cf = new CFType(data, - decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, - mit); - } - else if (normalization == "user_mean") - { - cf = new CFType(data, - decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, - mit); - } - else if (normalization == "z_score") - { - cf = new CFType(data, - decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, - mit); - } - else if (normalization == "none") - { - cf = new CFType(data, - decomposition, numUsersForSimilarity, rank, maxIterations, minResidue, - mit); - } - else - { - throw std::runtime_error("Unsupported normalization algorithm." - " It should be one of none, overall_mean, " - "item_mean, user_mean or z_score"); + case SIMILARITY_INTERPOLATION: + cf.template Predict(combinations, predictions); + break; } } //! Make predictions. -template -void CFModel::Predict(const arma::Mat& combinations, - arma::vec& predictions) +template +void CFWrapper::Predict( + const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const arma::Mat& combinations, + arma::vec& predictions) { - PredictVisitor - predict(combinations, predictions); - boost::apply_visitor(predict, cf); + switch (nsType) + { + case COSINE_SEARCH: + PredictHelper(cf, interpolationType, combinations, + predictions); + break; + + case EUCLIDEAN_SEARCH: + PredictHelper(cf, interpolationType, combinations, + predictions); + break; + + case PEARSON_SEARCH: + PredictHelper(cf, interpolationType, combinations, + predictions); + break; + } +} + +template +void GetRecommendationsHelper( + CFType& cf, + const InterpolationTypes interpolationType, + const size_t numRecs, + arma::Mat& recommendations, + const arma::Col& users) +{ + switch (interpolationType) + { + case AVERAGE_INTERPOLATION: + cf.template GetRecommendations( + numRecs, recommendations, users); + break; + + case REGRESSION_INTERPOLATION: + cf.template GetRecommendations( + numRecs, recommendations, users); + break; + + case SIMILARITY_INTERPOLATION: + cf.template GetRecommendations( + numRecs, recommendations, users); + break; + } } //! Compute recommendations for queried users. -template -void CFModel::GetRecommendations(const size_t numRecs, - arma::Mat& recommendations, - const arma::Col& users) +template +void CFWrapper::GetRecommendations( + const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const size_t numRecs, + arma::Mat& recommendations, + const arma::Col& users) { - RecommendationVisitor - recommendation(numRecs, recommendations, users, true); - boost::apply_visitor(recommendation, cf); + switch (nsType) + { + case COSINE_SEARCH: + GetRecommendationsHelper(cf, interpolationType, numRecs, + recommendations, users); + break; + + case EUCLIDEAN_SEARCH: + GetRecommendationsHelper(cf, interpolationType, numRecs, + recommendations, users); + break; + + case PEARSON_SEARCH: + GetRecommendationsHelper(cf, interpolationType, numRecs, + recommendations, users); + break; + } +} + +template +void GetRecommendationsHelper( + CFType& cf, + const InterpolationTypes interpolationType, + const size_t numRecs, + arma::Mat& recommendations) +{ + switch (interpolationType) + { + case AVERAGE_INTERPOLATION: + cf.template GetRecommendations( + numRecs, recommendations); + break; + + case REGRESSION_INTERPOLATION: + cf.template GetRecommendations( + numRecs, recommendations); + break; + + case SIMILARITY_INTERPOLATION: + cf.template GetRecommendations( + numRecs, recommendations); + break; + } } //! Compute recommendations for all users. -template -void CFModel::GetRecommendations(const size_t numRecs, - arma::Mat& recommendations) +template +void CFWrapper::GetRecommendations( + const NeighborSearchTypes nsType, + const InterpolationTypes interpolationType, + const size_t numRecs, + arma::Mat& recommendations) { - arma::Col users; - RecommendationVisitor - recommendation(numRecs, recommendations, users, false); - boost::apply_visitor(recommendation, cf); + switch (nsType) + { + case COSINE_SEARCH: + GetRecommendationsHelper(cf, interpolationType, numRecs, + recommendations); + break; + + case EUCLIDEAN_SEARCH: + GetRecommendationsHelper(cf, interpolationType, numRecs, + recommendations); + break; + + case PEARSON_SEARCH: + GetRecommendationsHelper(cf, interpolationType, numRecs, + recommendations); + break; + } } -template -const CFType* CFModel::CFPtr() const +template +CFWrapperBase* InitializeModelHelper( + CFModel::NormalizationTypes normalizationType) { - void* pointer = boost::apply_visitor(GetValueVisitor(), cf); - return (CFType*) pointer; + switch (normalizationType) + { + case CFModel::NO_NORMALIZATION: + return new CFWrapper(); + + case CFModel::ITEM_MEAN_NORMALIZATION: + return new CFWrapper(); + + case CFModel::USER_MEAN_NORMALIZATION: + return new CFWrapper(); + + case CFModel::OVERALL_MEAN_NORMALIZATION: + return new CFWrapper(); + + case CFModel::Z_SCORE_NORMALIZATION: + return new CFWrapper(); + } + + // This shouldn't ever happen. + return NULL; +} + +inline CFWrapperBase* InitializeModel( + CFModel::DecompositionTypes decompositionType, + CFModel::NormalizationTypes normalizationType) +{ + switch (decompositionType) + { + case CFModel::NMF: + return InitializeModelHelper(normalizationType); + + case CFModel::BATCH_SVD: + return InitializeModelHelper(normalizationType); + + case CFModel::RANDOMIZED_SVD: + return InitializeModelHelper(normalizationType); + + case CFModel::REG_SVD: + return InitializeModelHelper(normalizationType); + + case CFModel::SVD_COMPLETE: + return InitializeModelHelper(normalizationType); + + case CFModel::SVD_INCOMPLETE: + return InitializeModelHelper(normalizationType); + + case CFModel::BIAS_SVD: + return InitializeModelHelper(normalizationType); + + case CFModel::SVD_PLUS_PLUS: + return InitializeModelHelper(normalizationType); + } + + // This shouldn't ever happen. + return NULL; +}; + +template +void SerializeHelper(Archive& ar, + CFWrapperBase* cf, + CFModel::NormalizationTypes normalizationType) +{ + switch (normalizationType) + { + case CFModel::NO_NORMALIZATION: + { + CFWrapper& typedModel = + dynamic_cast&>(*cf); + ar(CEREAL_NVP(typedModel)); + break; + } + + case CFModel::ITEM_MEAN_NORMALIZATION: + { + CFWrapper& typedModel = + dynamic_cast&>(*cf); + ar(CEREAL_NVP(typedModel)); + break; + } + + case CFModel::USER_MEAN_NORMALIZATION: + { + CFWrapper& typedModel = + dynamic_cast&>(*cf); + ar(CEREAL_NVP(typedModel)); + break; + } + + case CFModel::OVERALL_MEAN_NORMALIZATION: + { + CFWrapper& typedModel = + dynamic_cast&>(*cf); + ar(CEREAL_NVP(typedModel)); + break; + } + + case CFModel::Z_SCORE_NORMALIZATION: + { + CFWrapper& typedModel = + dynamic_cast&>(*cf); + ar(CEREAL_NVP(typedModel)); + break; + } + } } template void CFModel::serialize(Archive& ar, const uint32_t /* version */) { + ar(CEREAL_NVP(decompositionType)); + ar(CEREAL_NVP(normalizationType)); + // This should never happen, but just in case, be clean with memory. if (cereal::is_loading()) - boost::apply_visitor(DeleteVisitor(), cf); + { + delete cf; + cf = InitializeModel(decompositionType, normalizationType); + } - ar(CEREAL_VARIANT_POINTER(cf)); + // Avoid polymorphic serialization by determining the type directly. + switch (decompositionType) + { + case NMF: + SerializeHelper(ar, cf, normalizationType); + break; + + case BATCH_SVD: + SerializeHelper(ar, cf, normalizationType); + break; + + case RANDOMIZED_SVD: + SerializeHelper(ar, cf, normalizationType); + break; + + case REG_SVD: + SerializeHelper(ar, cf, normalizationType); + break; + + case SVD_COMPLETE: + SerializeHelper(ar, cf, normalizationType); + break; + + case SVD_INCOMPLETE: + SerializeHelper(ar, cf, normalizationType); + break; + + case BIAS_SVD: + SerializeHelper(ar, cf, normalizationType); + break; + + case SVD_PLUS_PLUS: + SerializeHelper(ar, cf, normalizationType); + break; + } } +} // namespace cf +} // namespace mlpack + #endif diff --git a/src/mlpack/tests/main_tests/cf_test.cpp b/src/mlpack/tests/main_tests/cf_test.cpp index b136d9b730..da1c8c77fc 100644 --- a/src/mlpack/tests/main_tests/cf_test.cpp +++ b/src/mlpack/tests/main_tests/cf_test.cpp @@ -213,13 +213,13 @@ TEST_CASE_METHOD(CFTestFixture, "CFModelReuseTest", IO::GetSingleton().Parameters()["algorithm"].wasPassed = false; // Reuse the model to get recommendations. - int recommendations = 3; - const int querySize = 7; + size_t recommendations = 3; + const size_t querySize = 7; Mat query = arma::linspace>(0, querySize - 1, querySize); SetInputParam("query", std::move(query)); - SetInputParam("recommendations", recommendations); + SetInputParam("recommendations", int(recommendations)); SetInputParam("input_model", std::move(IO::GetParam("output_model"))); @@ -261,18 +261,21 @@ TEST_CASE_METHOD(CFTestFixture, "CFRankTest", { mat dataset; data::Load("GroupLensSmall.csv", dataset); - int rank = 7; + size_t rank = 7; SetInputParam("training", std::move(dataset)); - SetInputParam("rank", rank); + SetInputParam("rank", int(rank)); SetInputParam("max_iterations", int(10)); SetInputParam("algorithm", std::string("NMF")); mlpackMain(); const CFModel* outputModel = IO::GetParam("output_model"); + CFType& cf = + dynamic_cast&>(*(outputModel->CF())).CF(); - REQUIRE(outputModel->template CFPtr()->Rank() == rank); + REQUIRE(cf.Rank() == rank); } /** @@ -295,10 +298,13 @@ TEST_CASE_METHOD(CFTestFixture, "CFMinResidueTest", mlpack::math::FixedRandomSeed(); mlpackMain(); - outputModel = IO::GetParam("output_model"); + outputModel = IO::GetParam("output_model"); // By default the main program use NMFPolicy. - const mat w1 = outputModel->template CFPtr()->Decomposition().W(); - const mat h1 = outputModel->template CFPtr()->Decomposition().H(); + CFType& cf = + dynamic_cast&>(*(outputModel->CF())).CF(); + const mat w1 = cf.Decomposition().W(); + const mat h1 = cf.Decomposition().H(); ResetSettings(); @@ -314,15 +320,18 @@ TEST_CASE_METHOD(CFTestFixture, "CFMinResidueTest", outputModel = IO::GetParam("output_model"); // By default the main program use NMFPolicy. - const mat w2 = outputModel->template CFPtr()->Decomposition().W(); - const mat h2 = outputModel->template CFPtr()->Decomposition().H(); + CFType& cf2 = + dynamic_cast&>(*(outputModel->CF())).CF(); + const mat w2 = cf2.Decomposition().W(); + const mat h2 = cf2.Decomposition().H(); // The resulting matrices should be different. REQUIRE((arma::norm(w1 - w2) > 1e-5 || arma::norm(h1 - h2) > 1e-5)); } /** - * Test that itertaion_only_termination is used. + * Test that iteration_only_termination is used. */ TEST_CASE_METHOD(CFTestFixture, "CFIterationOnlyTerminationTest", "[CFMainTest][BindingTests]") @@ -341,10 +350,13 @@ TEST_CASE_METHOD(CFTestFixture, "CFIterationOnlyTerminationTest", mlpack::math::FixedRandomSeed(); mlpackMain(); - outputModel = IO::GetParam("output_model"); + outputModel = IO::GetParam("output_model"); // By default, the main program use NMFPolicy. - const mat w1 = outputModel->template CFPtr()->Decomposition().W(); - const mat h1 = outputModel->template CFPtr()->Decomposition().H(); + CFType& cf = + dynamic_cast&>(*(outputModel->CF())).CF(); + const mat w1 = cf.Decomposition().W(); + const mat h1 = cf.Decomposition().H(); ResetSettings(); @@ -359,8 +371,11 @@ TEST_CASE_METHOD(CFTestFixture, "CFIterationOnlyTerminationTest", outputModel = IO::GetParam("output_model"); // By default, the main program use NMFPolicy. - const mat w2 = outputModel->template CFPtr()->Decomposition().W(); - const mat h2 = outputModel->template CFPtr()->Decomposition().H(); + CFType& cf2 = + dynamic_cast&>(*(outputModel->CF())).CF(); + const mat w2 = cf2.Decomposition().W(); + const mat h2 = cf2.Decomposition().H(); // The resulting matrices should be different. REQUIRE((arma::norm(w1 - w2) > 1e-5 || arma::norm(h1 - h2) > 1e-5)); @@ -387,8 +402,11 @@ TEST_CASE_METHOD(CFTestFixture, "CFMaxIterationsTest", outputModel = IO::GetParam("output_model"); // By default, the main program use NMFPolicy. - const mat w1 = outputModel->template CFPtr()->Decomposition().W(); - const mat h1 = outputModel->template CFPtr()->Decomposition().H(); + CFType& cf = + dynamic_cast&>(*(outputModel->CF())).CF(); + const mat w1 = cf.Decomposition().W(); + const mat h1 = cf.Decomposition().H(); ResetSettings(); @@ -403,8 +421,11 @@ TEST_CASE_METHOD(CFTestFixture, "CFMaxIterationsTest", outputModel = IO::GetParam("output_model"); // By default the main program use NMFPolicy. - const mat w2 = outputModel->template CFPtr()->Decomposition().W(); - const mat h2 = outputModel->template CFPtr()->Decomposition().H(); + CFType& cf2 = + dynamic_cast&>(*(outputModel->CF())).CF(); + const mat w2 = cf2.Decomposition().W(); + const mat h2 = cf2.Decomposition().H(); // The resulting matrices should be different. REQUIRE((arma::norm(w1 - w2) > 1e-5 || arma::norm(h1 - h2) > 1e-5)); From 3ffbfcb4d5b8d0cd4f2e09a100c9d445af246240 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 11 Jan 2021 10:55:47 -0500 Subject: [PATCH 060/253] Fix warning. --- src/mlpack/methods/cf/cf_main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/cf/cf_main.cpp b/src/mlpack/methods/cf/cf_main.cpp index f4aa8e14b7..ce083c8c4a 100644 --- a/src/mlpack/methods/cf/cf_main.cpp +++ b/src/mlpack/methods/cf/cf_main.cpp @@ -343,7 +343,7 @@ static void mlpackMain() nsType = COSINE_SEARCH; else if (IO::GetParam("neighbor_search") == "euclidean") nsType = EUCLIDEAN_SEARCH; - else if (IO::GetParam("neighbor_search") == "pearson") + else // if (IO::GetParam("neighbor_search") == "pearson") nsType = PEARSON_SEARCH; InterpolationTypes interpolationType; @@ -353,7 +353,7 @@ static void mlpackMain() interpolationType = AVERAGE_INTERPOLATION; else if (IO::GetParam("interpolation") == "regression") interpolationType = REGRESSION_INTERPOLATION; - else if (IO::GetParam("interpolation") == "similarity") + else // if (IO::GetParam("interpolation") == "similarity") interpolationType = SIMILARITY_INTERPOLATION; if (IO::HasParam("query") || IO::HasParam("all_user_recommendations")) From 38d000059afb3e9a3d13e23b3d67b0acd3dfda6e Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 11 Jan 2021 11:08:24 -0500 Subject: [PATCH 061/253] Update history. --- HISTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 7529a3ee86..a5e2fd7732 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -13,6 +13,9 @@ * Add finalizers to Julia binding model types to fix memory handling (#2756). + * Removed `boost::visitor` from model classes for `knn`, `kfn`, `cf`, + `range_search`, `krann`, and `kde` bindings (#2803). + ### mlpack 3.4.2 ###### 2020-10-26 * Added Mean Absolute Percentage Error. From e2a0ac48fae1a1c63b2f4662d64dabcac664aa24 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 11 Jan 2021 11:08:38 -0500 Subject: [PATCH 062/253] Oh, also, it's a new year. --- COPYRIGHT.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index a3581e1d03..d2d177da71 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -7,7 +7,7 @@ Source: Files: * Copyright: - Copyright 2008-2020, Ryan Curtin + Copyright 2008-2021, Ryan Curtin Copyright 2008-2013, Bill March Copyright 2008-2012, Dongryeol Lee Copyright 2008-2013, Nishant Mehta From cd48b339d31a5451e7a77669e0523a44c1b26368 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 11 Jan 2021 17:43:20 -0500 Subject: [PATCH 063/253] Use CMake to automatically configure LICENSE file. --- src/mlpack/bindings/R/CMakeLists.txt | 36 +++++++++---------- .../bindings/R/mlpack/{LICENSE => LICENSE.in} | 2 +- 2 files changed, 18 insertions(+), 20 deletions(-) rename src/mlpack/bindings/R/mlpack/{LICENSE => LICENSE.in} (69%) diff --git a/src/mlpack/bindings/R/CMakeLists.txt b/src/mlpack/bindings/R/CMakeLists.txt index 830833b614..7352b92918 100644 --- a/src/mlpack/bindings/R/CMakeLists.txt +++ b/src/mlpack/bindings/R/CMakeLists.txt @@ -223,9 +223,11 @@ if (BUILD_R_BINDINGS) "${CMAKE_CURRENT_SOURCE_DIR}/mlpack/tests/testthat.R" ) - set(LICENSE_SOURCES - "${CMAKE_CURRENT_SOURCE_DIR}/mlpack/LICENSE" - ) + # Configure the license file. + string(TIMESTAMP LICENSE_YEAR "%Y") + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/mlpack/LICENSE.in" + "${CMAKE_CURRENT_BINARY_DIR}/mlpack/LICENSE") + add_custom_target(r_copy ALL) # First we have to create all the required directories for copy. @@ -247,22 +249,22 @@ if (BUILD_R_BINDINGS) # Copy all necessary files for building package. foreach(cpp_file ${CPP_SOURCES}) - add_custom_command(TARGET r_copy PRE_BUILD - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different - ${cpp_file} - ${CMAKE_CURRENT_BINARY_DIR}/mlpack/src/) + add_custom_command(TARGET r_copy PRE_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different + ${cpp_file} + ${CMAKE_CURRENT_BINARY_DIR}/mlpack/src/) endforeach() foreach(r_file ${R_SOURCES}) - add_custom_command(TARGET r_copy PRE_BUILD - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different - ${r_file} - ${CMAKE_CURRENT_BINARY_DIR}/mlpack/R/) + add_custom_command(TARGET r_copy PRE_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different + ${r_file} + ${CMAKE_CURRENT_BINARY_DIR}/mlpack/R/) endforeach() foreach(bindings_file ${BINDINGS_SOURCES}) - add_custom_command(TARGET r_copy PRE_BUILD - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different - ${bindings_file} - ${CMAKE_CURRENT_BINARY_DIR}/mlpack/src/mlpack/bindings/R) + add_custom_command(TARGET r_copy PRE_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different + ${bindings_file} + ${CMAKE_CURRENT_BINARY_DIR}/mlpack/src/mlpack/bindings/R) endforeach() add_custom_command(TARGET r_copy PRE_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different @@ -272,10 +274,6 @@ if (BUILD_R_BINDINGS) COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${R_TESTS_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/mlpack/tests) - add_custom_command(TARGET r_copy PRE_BUILD - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different - ${LICENSE_SOURCES} - ${CMAKE_CURRENT_BINARY_DIR}/mlpack) # This file will take care of multiple definition of functions in .cpp files. add_custom_command(TARGET r_copy PRE_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E touch diff --git a/src/mlpack/bindings/R/mlpack/LICENSE b/src/mlpack/bindings/R/mlpack/LICENSE.in similarity index 69% rename from src/mlpack/bindings/R/mlpack/LICENSE rename to src/mlpack/bindings/R/mlpack/LICENSE.in index 774e59e170..188ac6207d 100644 --- a/src/mlpack/bindings/R/mlpack/LICENSE +++ b/src/mlpack/bindings/R/mlpack/LICENSE.in @@ -1,3 +1,3 @@ -YEAR: 2020 +YEAR: ${LICENSE_YEAR} COPYRIGHT HOLDER: mlpack Team ORGANIZATION: mlpack From 33fb5d255fd400f1b1b181afdbc30e83df7e2f39 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 12 Jan 2021 08:59:28 -0500 Subject: [PATCH 064/253] Try to work around static code analysis issues. --- src/mlpack/methods/rann/ra_model_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/rann/ra_model_impl.hpp b/src/mlpack/methods/rann/ra_model_impl.hpp index e66b3b268a..443964b91a 100644 --- a/src/mlpack/methods/rann/ra_model_impl.hpp +++ b/src/mlpack/methods/rann/ra_model_impl.hpp @@ -83,8 +83,8 @@ void RABiSearchVisitor::SearchLeaf(RAType* ra) const Timer::Start("tree_building"); Log::Info << "Building query tree...."<< std::endl; std::vector oldFromNewQueries; - typename RAType::Tree queryTree(std::move(querySet), oldFromNewQueries, - leafSize); + typedef typename RAType::Tree TreeType + TreeType queryTree(std::move(querySet), oldFromNewQueries, leafSize); Log::Info << "Tree Built." << std::endl; Timer::Stop("tree_building"); From aeb0f49e9f66282065c6c2b1a2b4e91b16419e6a Mon Sep 17 00:00:00 2001 From: Nippun Sharma Date: Tue, 12 Jan 2021 20:10:18 +0530 Subject: [PATCH 065/253] added inf functionality and tests --- .../python/tests/test_python_binding.py | 32 +++++++++++++++ src/mlpack/core/util/io.cpp | 39 +++++++++++++++---- src/mlpack/core/util/io.hpp | 2 +- src/mlpack/core/util/mlpack_main.hpp | 2 +- 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/mlpack/bindings/python/tests/test_python_binding.py b/src/mlpack/bindings/python/tests/test_python_binding.py index 4d8206b16c..82ddf3dc88 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding.py +++ b/src/mlpack/bindings/python/tests/test_python_binding.py @@ -1336,5 +1336,37 @@ class TestPythonBinding(unittest.TestCase): self.assertEqual(output2['model_bw_out'], 20.0) self.assertEqual(output3['model_bw_out'], 20.0) + def testCheckInputMatricesNaN(self): + """ + Checks that an exception is thrown if the input matrix contains + NaN values. + """ + x = np.random.rand(100, 5) + x[0][0] = np.nan + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + matrix_in=x, + check_input_matrices=True)) + + def testCheckInputMatricesInf(self): + """ + Checks that an exception is thrown if the input matrix contains + inf values. + """ + x = np.random.rand(100, 5) + x[0][0] = np.inf + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + matrix_in=x, + check_input_matrices=True)) + if __name__ == '__main__': unittest.main() diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index 4e1771e705..25d800a89d 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -277,41 +277,64 @@ void IO::CheckInputMatrices() { std::string paramName = itr->first; std::string paramType = itr->second.cppType; - std::string errMsg = "The input " + paramName + " has NaN values."; + std::string errMsg1 = "The input " + paramName + " has NaN values."; + std::string errMsg2 = "The input " + paramName + " has inf values."; + if (paramType == "arma::mat") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg << std::endl; + Log::Fatal << errMsg1 << std::endl; + + if (IO::GetParam>(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "arma::Mat") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg << std::endl; + Log::Fatal << errMsg1 << std::endl; + + if (IO::GetParam>(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "arma::colvec") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg << std::endl; + Log::Fatal << errMsg1 << std::endl; + + if (IO::GetParam>(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "arma::Col") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg << std::endl; + Log::Fatal << errMsg1 << std::endl; + + if (IO::GetParam>(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "arma::rowvec") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg << std::endl; + Log::Fatal << errMsg1 << std::endl; + + if (IO::GetParam>(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "arma::Row") { if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg << std::endl; + Log::Fatal << errMsg1 << std::endl; + + if (IO::GetParam>(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "std::tuple") { if (std::get<1>(IO::GetParam(paramName)).has_nan()) - Log::Fatal << errMsg << std::endl; + Log::Fatal << errMsg1 << std::endl; + + if (std::get<1>(IO::GetParam(paramName)).has_inf()) + Log::Fatal << errMsg2 << std::endl; } } } diff --git a/src/mlpack/core/util/io.hpp b/src/mlpack/core/util/io.hpp index d4f5cc7a17..a435fc0121 100644 --- a/src/mlpack/core/util/io.hpp +++ b/src/mlpack/core/util/io.hpp @@ -286,7 +286,7 @@ class IO static void ClearSettings(); /** - * Checks all input matrices for NaN values, if found throws an exception. + * Checks all input matrices for NaN and inf values, if found throws an exception. */ static void CheckInputMatrices(); diff --git a/src/mlpack/core/util/mlpack_main.hpp b/src/mlpack/core/util/mlpack_main.hpp index 0d65513225..34f8689e1a 100644 --- a/src/mlpack/core/util/mlpack_main.hpp +++ b/src/mlpack/core/util/mlpack_main.hpp @@ -231,7 +231,7 @@ PARAM_FLAG("copy_all_inputs", "If specified, all input parameters will be deep" "where the input parameters are being modified by the algorithm, but can " "slow down the code.", ""); PARAM_FLAG("check_input_matrices", "If specified, the input matrix is checked for" - " NaN values; an exception is thrown if any are found.", ""); + " NaN and inf values; an exception is thrown if any are found.", ""); // Nothing else needs to be defined---the binding will use mlpackMain() as-is. From bfff19e88dea9eb903b4b5508b8d8b00f96782a4 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Wed, 13 Jan 2021 00:34:48 +0530 Subject: [PATCH 066/253] fixed indentations, random indices in tests, changed comments --- src/mlpack/bindings/python/py_option.hpp | 2 +- .../python/tests/test_python_binding.py | 8 +++++-- src/mlpack/core/util/io.cpp | 24 +++++++++---------- src/mlpack/core/util/io.hpp | 2 +- 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/mlpack/bindings/python/py_option.hpp b/src/mlpack/bindings/python/py_option.hpp index 0a62afc709..b3d8519f84 100644 --- a/src/mlpack/bindings/python/py_option.hpp +++ b/src/mlpack/bindings/python/py_option.hpp @@ -65,7 +65,7 @@ class PyOption data.input = input; data.loaded = false; // Only "verbose", "copy_all_inputs" and "check_input_matrices" - // will be persistent. + // will be persistent. if (identifier == "verbose" || identifier == "copy_all_inputs" || identifier == "check_input_matrices") data.persistent = true; diff --git a/src/mlpack/bindings/python/tests/test_python_binding.py b/src/mlpack/bindings/python/tests/test_python_binding.py index 82ddf3dc88..f6beffa483 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding.py +++ b/src/mlpack/bindings/python/tests/test_python_binding.py @@ -1342,7 +1342,9 @@ class TestPythonBinding(unittest.TestCase): NaN values. """ x = np.random.rand(100, 5) - x[0][0] = np.nan + a = np.random.randint(low=0, high=100) + b = np.random.randint(low=0, high=5) + x[a][b] = np.nan self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, @@ -1358,7 +1360,9 @@ class TestPythonBinding(unittest.TestCase): inf values. """ x = np.random.rand(100, 5) - x[0][0] = np.inf + a = np.random.randint(low=0, high=100) + b = np.random.randint(low=0, high=5) + x[a][b] = np.inf self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index 25d800a89d..9de3825595 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -293,48 +293,48 @@ void IO::CheckInputMatrices() if (IO::GetParam>(paramName).has_nan()) Log::Fatal << errMsg1 << std::endl; - if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; + if (IO::GetParam>(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "arma::colvec") { if (IO::GetParam>(paramName).has_nan()) Log::Fatal << errMsg1 << std::endl; - if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; + if (IO::GetParam>(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "arma::Col") { if (IO::GetParam>(paramName).has_nan()) Log::Fatal << errMsg1 << std::endl; - if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; + if (IO::GetParam>(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "arma::rowvec") { if (IO::GetParam>(paramName).has_nan()) Log::Fatal << errMsg1 << std::endl; - if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; + if (IO::GetParam>(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "arma::Row") { if (IO::GetParam>(paramName).has_nan()) Log::Fatal << errMsg1 << std::endl; - if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; + if (IO::GetParam>(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "std::tuple") { if (std::get<1>(IO::GetParam(paramName)).has_nan()) Log::Fatal << errMsg1 << std::endl; - if (std::get<1>(IO::GetParam(paramName)).has_inf()) - Log::Fatal << errMsg2 << std::endl; + if (std::get<1>(IO::GetParam(paramName)).has_inf()) + Log::Fatal << errMsg2 << std::endl; } } } diff --git a/src/mlpack/core/util/io.hpp b/src/mlpack/core/util/io.hpp index a435fc0121..dbe75da481 100644 --- a/src/mlpack/core/util/io.hpp +++ b/src/mlpack/core/util/io.hpp @@ -286,7 +286,7 @@ class IO static void ClearSettings(); /** - * Checks all input matrices for NaN and inf values, if found throws an exception. + * Checks all input matrices for NaN and inf values, exits if found any. */ static void CheckInputMatrices(); From 7056aebcdf8dac50aeba1004154761190d7640df Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Wed, 13 Jan 2021 00:38:25 +0530 Subject: [PATCH 067/253] fixed indent --- src/mlpack/core/util/io.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index 9de3825595..fcd6a002e2 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -286,7 +286,7 @@ void IO::CheckInputMatrices() Log::Fatal << errMsg1 << std::endl; if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; + Log::Fatal << errMsg2 << std::endl; } else if (paramType == "arma::Mat") { From 4de66bbf0ad0cdb4a7a82ad7e7e6f8eef728d7e6 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 12 Jan 2021 20:22:00 -0500 Subject: [PATCH 068/253] Um, right, C++ needs semicolons... --- src/mlpack/methods/rann/ra_model_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/rann/ra_model_impl.hpp b/src/mlpack/methods/rann/ra_model_impl.hpp index 443964b91a..30bed21c01 100644 --- a/src/mlpack/methods/rann/ra_model_impl.hpp +++ b/src/mlpack/methods/rann/ra_model_impl.hpp @@ -83,7 +83,7 @@ void RABiSearchVisitor::SearchLeaf(RAType* ra) const Timer::Start("tree_building"); Log::Info << "Building query tree...."<< std::endl; std::vector oldFromNewQueries; - typedef typename RAType::Tree TreeType + typedef typename RAType::Tree TreeType; TreeType queryTree(std::move(querySet), oldFromNewQueries, leafSize); Log::Info << "Tree Built." << std::endl; Timer::Stop("tree_building"); From f385522a5218fb644fced6ca164e137b098ab77e Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Tue, 12 Jan 2021 20:25:42 -0500 Subject: [PATCH 069/253] Update src/mlpack/bindings/R/CMakeLists.txt Co-authored-by: Yashwant Singh Parihar --- src/mlpack/bindings/R/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/bindings/R/CMakeLists.txt b/src/mlpack/bindings/R/CMakeLists.txt index 13f171140d..f5f6907159 100644 --- a/src/mlpack/bindings/R/CMakeLists.txt +++ b/src/mlpack/bindings/R/CMakeLists.txt @@ -229,7 +229,7 @@ if (BUILD_R_BINDINGS) # Installation script for the packagae. install(CODE "execute_process( - COMMAND R CMD INSTALL mlpack_${PACKAGE_VERSION}.tar.gz + COMMAND ${R_EXECUTABLE} CMD INSTALL mlpack_${PACKAGE_VERSION}.tar.gz WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})" ) From 5e0a3472cd4e9ae012026a37f31caa50d02e1f93 Mon Sep 17 00:00:00 2001 From: Nippun Sharma Date: Wed, 13 Jan 2021 12:05:12 +0530 Subject: [PATCH 070/253] added templated utility function --- src/mlpack/core/util/io.cpp | 58 ++++---------------------------- src/mlpack/core/util/io.hpp | 8 +++++ src/mlpack/core/util/io_impl.hpp | 13 +++++++ 3 files changed, 28 insertions(+), 51 deletions(-) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index fcd6a002e2..2f1b4792ad 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -277,65 +277,21 @@ void IO::CheckInputMatrices() { std::string paramName = itr->first; std::string paramType = itr->second.cppType; - std::string errMsg1 = "The input " + paramName + " has NaN values."; - std::string errMsg2 = "The input " + paramName + " has inf values."; if (paramType == "arma::mat") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg1 << std::endl; - - if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; - } + IO::CheckInputMatrix>(paramName); else if (paramType == "arma::Mat") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg1 << std::endl; - - if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; - } + IO::CheckInputMatrix>(paramName); else if (paramType == "arma::colvec") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg1 << std::endl; - - if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; - } + IO::CheckInputMatrix>(paramName); else if (paramType == "arma::Col") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg1 << std::endl; - - if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; - } + IO::CheckInputMatrix>(paramName); else if (paramType == "arma::rowvec") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg1 << std::endl; - - if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; - } + IO::CheckInputMatrix>(paramName); else if (paramType == "arma::Row") - { - if (IO::GetParam>(paramName).has_nan()) - Log::Fatal << errMsg1 << std::endl; - - if (IO::GetParam>(paramName).has_inf()) - Log::Fatal << errMsg2 << std::endl; - } + IO::CheckInputMatrix>(paramName); else if (paramType == "std::tuple") - { - if (std::get<1>(IO::GetParam(paramName)).has_nan()) - Log::Fatal << errMsg1 << std::endl; - - if (std::get<1>(IO::GetParam(paramName)).has_inf()) - Log::Fatal << errMsg2 << std::endl; - } + IO::CheckInputMatrix(paramName); } } diff --git a/src/mlpack/core/util/io.hpp b/src/mlpack/core/util/io.hpp index dbe75da481..0633fd8c5d 100644 --- a/src/mlpack/core/util/io.hpp +++ b/src/mlpack/core/util/io.hpp @@ -285,6 +285,14 @@ class IO */ static void ClearSettings(); + /** + * Utility function for CheckInputMatrices(). + * + * @param matrix Matrix to check for NaN or Inf values. + */ + template + static void CheckInputMatrix(T& matrix); + /** * Checks all input matrices for NaN and inf values, exits if found any. */ diff --git a/src/mlpack/core/util/io_impl.hpp b/src/mlpack/core/util/io_impl.hpp index feb892325c..e40d5824dc 100644 --- a/src/mlpack/core/util/io_impl.hpp +++ b/src/mlpack/core/util/io_impl.hpp @@ -145,6 +145,19 @@ T& IO::GetRawParam(const std::string& identifier) } } +template +void CheckInputMatrix(const std::string paramName) +{ + std::string errMsg1 = "The input " + paramName + " has NaN values."; + std::string errMsg2 = "The input " + paramName + " has inf values."; + + if (IO::GetParam(paramName).has_nan()) + Log::Fatal << errMsg1 << std::endl; + + if (IO::GetParam(paramName).has_inf()) + Log::Fatal << errMsg2 << std::endl; +} + } // namespace mlpack #endif From dc398bfb6418e045bfa84040c812b57a881e6712 Mon Sep 17 00:00:00 2001 From: Nippun Sharma Date: Wed, 13 Jan 2021 12:11:51 +0530 Subject: [PATCH 071/253] fixing errors --- src/mlpack/core/util/io.hpp | 4 ++-- src/mlpack/core/util/io_impl.hpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mlpack/core/util/io.hpp b/src/mlpack/core/util/io.hpp index 0633fd8c5d..26571659d4 100644 --- a/src/mlpack/core/util/io.hpp +++ b/src/mlpack/core/util/io.hpp @@ -288,10 +288,10 @@ class IO /** * Utility function for CheckInputMatrices(). * - * @param matrix Matrix to check for NaN or Inf values. + * @param identifier Name of the parameter in question. */ template - static void CheckInputMatrix(T& matrix); + static void CheckInputMatrix(const std::string& identifier); /** * Checks all input matrices for NaN and inf values, exits if found any. diff --git a/src/mlpack/core/util/io_impl.hpp b/src/mlpack/core/util/io_impl.hpp index e40d5824dc..59a68418c3 100644 --- a/src/mlpack/core/util/io_impl.hpp +++ b/src/mlpack/core/util/io_impl.hpp @@ -146,15 +146,15 @@ T& IO::GetRawParam(const std::string& identifier) } template -void CheckInputMatrix(const std::string paramName) +void CheckInputMatrix(const std::string& identifier) { - std::string errMsg1 = "The input " + paramName + " has NaN values."; - std::string errMsg2 = "The input " + paramName + " has inf values."; + std::string errMsg1 = "The input " + identifier + " has NaN values."; + std::string errMsg2 = "The input " + identifier + " has inf values."; - if (IO::GetParam(paramName).has_nan()) + if (IO::GetParam(identifier).has_nan()) Log::Fatal << errMsg1 << std::endl; - if (IO::GetParam(paramName).has_inf()) + if (IO::GetParam(identifier).has_inf()) Log::Fatal << errMsg2 << std::endl; } From 6ad120aa6e04cad6fc0cbf958042e998dbcb307e Mon Sep 17 00:00:00 2001 From: Nippun Sharma Date: Wed, 13 Jan 2021 17:38:39 +0530 Subject: [PATCH 072/253] added CheckInputMatrix() to reduce code block in CheckInputMatrices() --- src/mlpack/core/util/io.cpp | 17 +++++++++++++++++ src/mlpack/core/util/io.hpp | 16 ++++++++-------- src/mlpack/core/util/io_impl.hpp | 7 +++---- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index 2f1b4792ad..8998f331bb 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -268,6 +268,23 @@ void IO::ClearSettings() GetSingleton().functionMap = persistentFunctions; } +// For handling std::tuple +// seperately. +template<> +void IO::CheckInputMatrix>( + const std::string& identifier) +{ + typedef typename std::tuple TupleType; + + std::string errMsg1 = "The input " + identifier + " has NaN values."; + std::string errMsg2 = "The input " + identifier + " has inf values."; + + if (std::get<1>(IO::GetParam(identifier)).has_nan()) + Log::Fatal << errMsg1 << std::endl; + if (std::get<1>(IO::GetParam(identifier)).has_inf()) + Log::Fatal << errMsg2 << std::endl; +} + void IO::CheckInputMatrices() { typedef typename std::tuple TupleType; diff --git a/src/mlpack/core/util/io.hpp b/src/mlpack/core/util/io.hpp index 26571659d4..5189695abe 100644 --- a/src/mlpack/core/util/io.hpp +++ b/src/mlpack/core/util/io.hpp @@ -219,6 +219,14 @@ class IO template static T& GetRawParam(const std::string& identifier); + /** + * Utility function for CheckInputMatrices(). + * + * @param identifier Name of the parameter in question. + */ + template + static void CheckInputMatrix(const std::string& identifier); + /** * Given two (matrix) parameters, ensure that the first is an in-place copy of * the second. This will generally do nothing (as the bindings already do @@ -285,14 +293,6 @@ class IO */ static void ClearSettings(); - /** - * Utility function for CheckInputMatrices(). - * - * @param identifier Name of the parameter in question. - */ - template - static void CheckInputMatrix(const std::string& identifier); - /** * Checks all input matrices for NaN and inf values, exits if found any. */ diff --git a/src/mlpack/core/util/io_impl.hpp b/src/mlpack/core/util/io_impl.hpp index 59a68418c3..f54aaa4eab 100644 --- a/src/mlpack/core/util/io_impl.hpp +++ b/src/mlpack/core/util/io_impl.hpp @@ -146,15 +146,14 @@ T& IO::GetRawParam(const std::string& identifier) } template -void CheckInputMatrix(const std::string& identifier) +void IO::CheckInputMatrix(const std::string& identifier) { std::string errMsg1 = "The input " + identifier + " has NaN values."; std::string errMsg2 = "The input " + identifier + " has inf values."; - if (IO::GetParam(identifier).has_nan()) + if (GetParam(identifier).has_nan()) Log::Fatal << errMsg1 << std::endl; - - if (IO::GetParam(identifier).has_inf()) + if (GetParam(identifier).has_inf()) Log::Fatal << errMsg2 << std::endl; } From 04dee7ee870c3cae86fe4baa0ac058de736e75b3 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Wed, 13 Jan 2021 18:23:07 +0530 Subject: [PATCH 073/253] fix errors --- src/mlpack/core/util/io.cpp | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index 8998f331bb..d36b287a4e 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -268,23 +268,6 @@ void IO::ClearSettings() GetSingleton().functionMap = persistentFunctions; } -// For handling std::tuple -// seperately. -template<> -void IO::CheckInputMatrix>( - const std::string& identifier) -{ - typedef typename std::tuple TupleType; - - std::string errMsg1 = "The input " + identifier + " has NaN values."; - std::string errMsg2 = "The input " + identifier + " has inf values."; - - if (std::get<1>(IO::GetParam(identifier)).has_nan()) - Log::Fatal << errMsg1 << std::endl; - if (std::get<1>(IO::GetParam(identifier)).has_inf()) - Log::Fatal << errMsg2 << std::endl; -} - void IO::CheckInputMatrices() { typedef typename std::tuple TupleType; @@ -308,7 +291,15 @@ void IO::CheckInputMatrices() else if (paramType == "arma::Row") IO::CheckInputMatrix>(paramName); else if (paramType == "std::tuple") - IO::CheckInputMatrix(paramName); + { + std::string errMsg1 = "The input " + paramName + " has NaN values."; + std::string errMsg2 = "The input " + paramName + " has inf values."; + + if (std::get<1>(GetParam(paramName)).has_nan()) + Log::Fatal << errMsg1 << std::endl; + if (std::get<1>(GetParam(paramName)).has_inf()) + Log::Fatal << errMsg2 << std::endl; + } } } From 448b1010dae820e1602f0125c5e8cf1ab33bfbea Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Wed, 13 Jan 2021 21:58:34 +0100 Subject: [PATCH 074/253] Minor style improvement. --- src/mlpack/methods/pca/pca_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/pca/pca_impl.hpp b/src/mlpack/methods/pca/pca_impl.hpp index a122cd7159..f469933c14 100644 --- a/src/mlpack/methods/pca/pca_impl.hpp +++ b/src/mlpack/methods/pca/pca_impl.hpp @@ -78,8 +78,8 @@ void PCA::Apply(const arma::mat& data, /** * Apply Principal Component Analysis to the provided data set. * - * @param data - Data matrix - * @param transformedData - Data with PCA applied + * @param data - Data matrix. + * @param transformedData Data with PCA applied. */ template void PCA::Apply(const arma::mat& data, From c8227266bf5c0fc83e6098bee8e76874d0b282d5 Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Thu, 14 Jan 2021 14:24:34 -0500 Subject: [PATCH 075/253] add move assignment operator --- .../methods/adaboost/adaboost_model.cpp | 39 ++++++++++++++----- .../methods/adaboost/adaboost_model.hpp | 3 ++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/mlpack/methods/adaboost/adaboost_model.cpp b/src/mlpack/methods/adaboost/adaboost_model.cpp index a48659b4bd..d71b857d74 100644 --- a/src/mlpack/methods/adaboost/adaboost_model.cpp +++ b/src/mlpack/methods/adaboost/adaboost_model.cpp @@ -72,19 +72,40 @@ AdaBoostModel::AdaBoostModel(AdaBoostModel&& other) : //! Copy assignment operator. AdaBoostModel& AdaBoostModel::operator=(const AdaBoostModel& other) { - mappings = other.mappings; - weakLearnerType = other.weakLearnerType; + if (this != &other) + { + mappings = other.mappings; + weakLearnerType = other.weakLearnerType; - delete dsBoost; - dsBoost = (other.dsBoost == NULL) ? NULL : - new AdaBoost(*other.dsBoost); + delete dsBoost; + dsBoost = (other.dsBoost == NULL) ? NULL : + new AdaBoost(*other.dsBoost); - delete pBoost; - pBoost = (other.pBoost == NULL) ? NULL : - new AdaBoost>(*other.pBoost); + delete pBoost; + pBoost = (other.pBoost == NULL) ? NULL : + new AdaBoost>(*other.pBoost); - dimensionality = other.dimensionality; + dimensionality = other.dimensionality; + } + return *this; +} +//! Move assignment operator. +AdaBoostModel& AdaBoostModel::operator=(AdaBoostModel&& other) +{ + if (this != &other) + { + mappings = std::move(other.mappings); + weakLearnerType = other.weakLearnerType; + + dsBoost = other.dsBoost; + other.dsBoost = nullptr; + + pBoost = other.pBoost; + other.pBoost = nullptr; + + dimensionality = other.dimensionality; + } return *this; } diff --git a/src/mlpack/methods/adaboost/adaboost_model.hpp b/src/mlpack/methods/adaboost/adaboost_model.hpp index e8dcac3a82..36743c4e18 100644 --- a/src/mlpack/methods/adaboost/adaboost_model.hpp +++ b/src/mlpack/methods/adaboost/adaboost_model.hpp @@ -61,6 +61,9 @@ class AdaBoostModel //! Copy assignment operator. AdaBoostModel& operator=(const AdaBoostModel& other); + //! Move assignment operator. + AdaBoostModel& operator=(AdaBoostModel&& other); + //! Clean up memory. ~AdaBoostModel(); From b442b8c33c3794c0840ab9a810ef16d63c1893fb Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Fri, 15 Jan 2021 00:17:30 -0500 Subject: [PATCH 076/253] add move assignment for hrectbound --- src/mlpack/core/tree/hrectbound.hpp | 4 +++ src/mlpack/core/tree/hrectbound_impl.hpp | 31 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/mlpack/core/tree/hrectbound.hpp b/src/mlpack/core/tree/hrectbound.hpp index 1d15fe6582..31186f621d 100644 --- a/src/mlpack/core/tree/hrectbound.hpp +++ b/src/mlpack/core/tree/hrectbound.hpp @@ -73,12 +73,16 @@ class HRectBound //! Copy constructor; necessary to prevent memory leaks. HRectBound(const HRectBound& other); + //! Same as copy constructor; necessary to prevent memory leaks. HRectBound& operator=(const HRectBound& other); //! Move constructor: take possession of another bound's information. HRectBound(HRectBound&& other); + //! Move assignment operator + HRectBound& operator=(HRectBound&& other); + //! Destructor: clean up memory. ~HRectBound(); diff --git a/src/mlpack/core/tree/hrectbound_impl.hpp b/src/mlpack/core/tree/hrectbound_impl.hpp index 2b73eb020a..26132e50a5 100644 --- a/src/mlpack/core/tree/hrectbound_impl.hpp +++ b/src/mlpack/core/tree/hrectbound_impl.hpp @@ -103,6 +103,37 @@ inline HRectBound::HRectBound( other.minWidth = 0.0; } +/** + * Move assignment operator + */ +template +inline HRectBound< + MetricType, + ElemType>& HRectBound::operator=(HRectBound&& other) +{ + if (this != &other) + { + if (dim != other.Dim()) + { + // Reallocation is necessary. + if (bounds) + delete[] bounds; + + dim = other.Dim(); + bounds = new math::RangeType[dim]; + } + + // Now move each of the bound values. + // cannot move the bound pointer because there are no accessor method to the bound pointer + for (size_t i = 0; i < dim; ++i) + bounds[i] = std::move(other[i]); + + minWidth = std::move(other.MinWidth()); + } + return *this; +} + /** * Destructor: clean up memory. */ From 8eab8c47df197d9e02c17f60ec4626651c8db72f Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Fri, 15 Jan 2021 00:22:27 -0500 Subject: [PATCH 077/253] fix hrectbound move assignment --- src/mlpack/core/tree/hrectbound_impl.hpp | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/mlpack/core/tree/hrectbound_impl.hpp b/src/mlpack/core/tree/hrectbound_impl.hpp index 26132e50a5..45d4b81a76 100644 --- a/src/mlpack/core/tree/hrectbound_impl.hpp +++ b/src/mlpack/core/tree/hrectbound_impl.hpp @@ -114,22 +114,12 @@ inline HRectBound< { if (this != &other) { - if (dim != other.Dim()) - { - // Reallocation is necessary. - if (bounds) - delete[] bounds; - - dim = other.Dim(); - bounds = new math::RangeType[dim]; - } - - // Now move each of the bound values. - // cannot move the bound pointer because there are no accessor method to the bound pointer - for (size_t i = 0; i < dim; ++i) - bounds[i] = std::move(other[i]); - - minWidth = std::move(other.MinWidth()); + bounds = other.bounds; + minWidth = other.minWidth; + dim = other.dim; + other.dim = 0; + other.bounds = nullptr; + other.minWidth = 0.0; } return *this; } From 30e98ec05a814ecc2bc1c7d26759f880b41693d1 Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Fri, 15 Jan 2021 00:27:02 -0500 Subject: [PATCH 078/253] ball bound move assignment operator --- src/mlpack/core/tree/ballbound.hpp | 3 +++ src/mlpack/core/tree/ballbound_impl.hpp | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/mlpack/core/tree/ballbound.hpp b/src/mlpack/core/tree/ballbound.hpp index 0d6633f7ca..e1a8674f03 100644 --- a/src/mlpack/core/tree/ballbound.hpp +++ b/src/mlpack/core/tree/ballbound.hpp @@ -81,6 +81,9 @@ class BallBound //! Move constructor: take possession of another bound. BallBound(BallBound&& other); + //! Move assignment operator. + BallBound& operator=(BallBound&& other); + //! Destructor to release allocated memory. ~BallBound(); diff --git a/src/mlpack/core/tree/ballbound_impl.hpp b/src/mlpack/core/tree/ballbound_impl.hpp index 59ef8bffc3..d1e5af2c06 100644 --- a/src/mlpack/core/tree/ballbound_impl.hpp +++ b/src/mlpack/core/tree/ballbound_impl.hpp @@ -92,6 +92,22 @@ BallBound::BallBound(BallBound&& other) : other.ownsMetric = false; } +//! Move assignment operator. +template +BallBound& BallBound::operator=( + BallBound&& other) +{ + radius = other.radius, + center = std::move(other.center), + metric = other.metric, + ownsMetric = other.ownsMetric + + other.radius = 0.0; + other.center = VecType(); + other.metric = nullptr; + other.ownsMetric = false; +} + //! Destructor to release allocated memory. template BallBound::~BallBound() From 4abbb39aec00dd178b1119e9cc84c9702f7192bb Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Fri, 15 Jan 2021 00:31:14 -0500 Subject: [PATCH 079/253] add move assignment operator and fix static code check --- src/mlpack/core/tree/hollow_ball_bound.hpp | 3 ++ .../core/tree/hollow_ball_bound_impl.hpp | 41 +++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/mlpack/core/tree/hollow_ball_bound.hpp b/src/mlpack/core/tree/hollow_ball_bound.hpp index d8b65dcf87..d699eab693 100644 --- a/src/mlpack/core/tree/hollow_ball_bound.hpp +++ b/src/mlpack/core/tree/hollow_ball_bound.hpp @@ -86,6 +86,9 @@ class HollowBallBound //! Move constructor: take possession of another bound. HollowBallBound(HollowBallBound&& other); + //! Move assignment operator. + HollowBallBound& operator=(HollowBallBound&& other); + //! Destructor to release allocated memory. ~HollowBallBound(); diff --git a/src/mlpack/core/tree/hollow_ball_bound_impl.hpp b/src/mlpack/core/tree/hollow_ball_bound_impl.hpp index b8446ec350..8ccd06225c 100644 --- a/src/mlpack/core/tree/hollow_ball_bound_impl.hpp +++ b/src/mlpack/core/tree/hollow_ball_bound_impl.hpp @@ -80,15 +80,17 @@ template HollowBallBound& HollowBallBound:: operator=(const HollowBallBound& other) { - if (ownsMetric) - delete metric; - - radii = other.radii; - center = other.center; - hollowCenter = other.hollowCenter; - metric = other.metric; - ownsMetric = false; + if (this != &other) + { + if (ownsMetric) + delete metric; + radii = other.radii; + center = other.center; + hollowCenter = other.hollowCenter; + metric = other.metric; + ownsMetric = false; + } return *this; } @@ -111,6 +113,29 @@ HollowBallBound::HollowBallBound( other.ownsMetric = false; } +//! Move assignment operator. +template +HollowBallBound& HollowBallBound:: +operator=(HollowBallBound&& other) +{ + if (this != &other) + { + radii = other.radii; + center = std::move(other.center); + hollowCenter = std::move(other.hollowCenter); + metric = other.metric; + ownsMetric = other.ownsMetric; + + other.radii.Hi() = 0.0; + other.radii.Lo() = 0.0; + other.center = arma::Col(); + other.hollowCenter = arma::Col(); + other.metric = nullptr; + other.ownsMetric = false; + } + return *this; +} + //! Destructor to release allocated memory. template HollowBallBound::~HollowBallBound() From f02eb1464137f02733fc42bdd9d904e933c6d9f5 Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Fri, 15 Jan 2021 08:58:19 -0500 Subject: [PATCH 080/253] fix error --- src/mlpack/core/tree/ballbound_impl.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mlpack/core/tree/ballbound_impl.hpp b/src/mlpack/core/tree/ballbound_impl.hpp index d1e5af2c06..5722fb854a 100644 --- a/src/mlpack/core/tree/ballbound_impl.hpp +++ b/src/mlpack/core/tree/ballbound_impl.hpp @@ -97,10 +97,10 @@ template BallBound& BallBound::operator=( BallBound&& other) { - radius = other.radius, - center = std::move(other.center), - metric = other.metric, - ownsMetric = other.ownsMetric + radius = other.radius; + center = std::move(other.center); + metric = other.metric; + ownsMetric = other.ownsMetric; other.radius = 0.0; other.center = VecType(); From cd42db9f0aea1c2e9c33dbed4bcbc310fe6fdefd Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Fri, 15 Jan 2021 21:54:14 -0500 Subject: [PATCH 081/253] continue fixing static code check --- .../rectangle_tree/discrete_hilbert_value.hpp | 8 ++ .../discrete_hilbert_value_impl.hpp | 21 +++++ .../simple_residue_termination.hpp | 10 ++- .../svd_complete_incremental_learning.hpp | 4 +- .../svd_incomplete_incremental_learning.hpp | 2 +- src/mlpack/methods/fastmks/fastmks.hpp | 5 ++ src/mlpack/methods/fastmks/fastmks_impl.hpp | 29 ++++++ src/mlpack/methods/fastmks/fastmks_model.cpp | 90 ++++++++++++------- src/mlpack/methods/fastmks/fastmks_model.hpp | 3 + src/mlpack/methods/hmm/hmm_model.hpp | 14 +++ .../methods/range_search/range_search.hpp | 14 ++- .../range_search/range_search_impl.hpp | 77 ++++++++++++---- 12 files changed, 219 insertions(+), 58 deletions(-) diff --git a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp index 405188a4f6..32bb94ece9 100644 --- a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp +++ b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp @@ -182,6 +182,14 @@ class DiscreteHilbertValue */ DiscreteHilbertValue& operator=(const DiscreteHilbertValue& val); + /** + * Move the local Hilbert object. + * + * @param val The DiscreteHilbertValue object from which the dataset + * will be copied. + */ + DiscreteHilbertValue& operator=(DiscreteHilbertValue&& val); + /** * Nullify the localHilbertValues pointer in order to prevent an invalid free. */ diff --git a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp index c4baa38a90..48ad8557f7 100644 --- a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp @@ -450,6 +450,27 @@ operator=(const DiscreteHilbertValue& val) return *this; } +template +DiscreteHilbertValue& DiscreteHilbertValue:: +operator=(DiscreteHilbertValue&& other) +{ + if (this != &other) + { + localHilbertValues = other.localHilbertValues; + ownsLocalHilbertValues = other.ownsLocalHilbertValues; + numValues = other.numValues; + valueToInsert = other.valueToInsert; + ownsValueToInsert = other.ownsValueToInsert; + + other.localHilbertValues = nullptr; + other.ownsLocalHilbertValues = false; + other.numValues = 0; + other.valueToInsert = nullptr; + other.ownsValueToInsert = false; + } + return *this; +} + template void DiscreteHilbertValue::NullifyData() { diff --git a/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp b/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp index 970b24289f..81893f4fa3 100644 --- a/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp +++ b/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp @@ -41,7 +41,15 @@ class SimpleResidueTermination */ SimpleResidueTermination(const double minResidue = 1e-5, const size_t maxIterations = 10000) - : minResidue(minResidue), maxIterations(maxIterations) { } + : minResidue(minResidue), + maxIterations(maxIterations), + residue(0.0), + iteration(0), + nm(0), + normOld(0) + { + // Nothing to do here. + } /** * Initializes the termination policy before stating the factorization. diff --git a/src/mlpack/methods/amf/update_rules/svd_complete_incremental_learning.hpp b/src/mlpack/methods/amf/update_rules/svd_complete_incremental_learning.hpp index 4ab1c0d610..37b7ab8c0a 100644 --- a/src/mlpack/methods/amf/update_rules/svd_complete_incremental_learning.hpp +++ b/src/mlpack/methods/amf/update_rules/svd_complete_incremental_learning.hpp @@ -56,7 +56,7 @@ class SVDCompleteIncrementalLearning SVDCompleteIncrementalLearning(double u = 0.0001, double kw = 0, double kh = 0) - : u(u), kw(kw), kh(kh) + : u(u), kw(kw), kh(kh), currentUserIndex(0), currentItemIndex(0) { // Nothing to do. } @@ -172,7 +172,7 @@ class SVDCompleteIncrementalLearning SVDCompleteIncrementalLearning(double u = 0.01, double kw = 0, double kh = 0) - : u(u), kw(kw), kh(kh), it(NULL) + : u(u), kw(kw), kh(kh), it(NULL), m(0), n(0), isStart(false) {} ~SVDCompleteIncrementalLearning() diff --git a/src/mlpack/methods/amf/update_rules/svd_incomplete_incremental_learning.hpp b/src/mlpack/methods/amf/update_rules/svd_incomplete_incremental_learning.hpp index 0082824129..9880ea2945 100644 --- a/src/mlpack/methods/amf/update_rules/svd_incomplete_incremental_learning.hpp +++ b/src/mlpack/methods/amf/update_rules/svd_incomplete_incremental_learning.hpp @@ -53,7 +53,7 @@ class SVDIncompleteIncrementalLearning SVDIncompleteIncrementalLearning(double u = 0.001, double kw = 0, double kh = 0) - : u(u), kw(kw), kh(kh) + : u(u), kw(kw), kh(kh), currentUserIndex(0) { // Nothing to do. } diff --git a/src/mlpack/methods/fastmks/fastmks.hpp b/src/mlpack/methods/fastmks/fastmks.hpp index 93d234d541..ea2057b0b9 100644 --- a/src/mlpack/methods/fastmks/fastmks.hpp +++ b/src/mlpack/methods/fastmks/fastmks.hpp @@ -163,6 +163,11 @@ class FastMKS */ FastMKS& operator=(const FastMKS& other); + /** + * Move assignment operator. + */ + FastMKS& operator=(FastMKS&& other); + //! Destructor for the FastMKS object. ~FastMKS(); diff --git a/src/mlpack/methods/fastmks/fastmks_impl.hpp b/src/mlpack/methods/fastmks/fastmks_impl.hpp index 660617fdb0..3b2d12eaae 100644 --- a/src/mlpack/methods/fastmks/fastmks_impl.hpp +++ b/src/mlpack/methods/fastmks/fastmks_impl.hpp @@ -250,6 +250,35 @@ FastMKS::operator=(const FastMKS& other) naive = other.naive; } +template class TreeType> +FastMKS& +FastMKS::operator=(FastMKS&& other) +{ + if (this != &other) + { + referenceSet = other.referenceSet; + referenceTree = other.referenceTree; + treeOwner = other.treeOwner; + setOwner = other.setOwner; + singleMode = other.singleMode; + naive = other.naive; + metric = std::move(other.metric); + + // Clear information from the other. + other.referenceSet = nullptr; + other.referenceTree = nullptr; + other.treeOwner = false; + other.setOwner = false; + other.singleMode = false; + other.naive = false; + } + return *this; +} + template(*other.linear); - if (other.polynomial) - polynomial = new FastMKS(*other.polynomial); - if (other.cosine) - cosine = new FastMKS(*other.cosine); - if (other.gaussian) - gaussian = new FastMKS(*other.gaussian); - if (other.epan) - epan = new FastMKS(*other.epan); - if (other.triangular) - triangular = new FastMKS(*other.triangular); - if (other.hyptan) - hyptan = new FastMKS(*other.hyptan); + kernelType = other.kernelType; + if (other.linear) + linear = new FastMKS(*other.linear); + if (other.polynomial) + polynomial = new FastMKS(*other.polynomial); + if (other.cosine) + cosine = new FastMKS(*other.cosine); + if (other.gaussian) + gaussian = new FastMKS(*other.gaussian); + if (other.epan) + epan = new FastMKS(*other.epan); + if (other.triangular) + triangular = new FastMKS(*other.triangular); + if (other.hyptan) + hyptan = new FastMKS(*other.hyptan); + } + return *this; +} +FastMKSModel& FastMKSModel::operator=(FastMKSModel&& other) +{ + if (this != &other) + { + kernelType = other.kernelType; + linear = other.linear; + polynomial = other.polynomial; + cosine = other.cosine; + gaussian = other.gaussian; + epan = other.epan; + triangular = other.triangular; + hyptan = other.hyptan; + + // Clear other object. + other.kernelType = KernelTypes::LINEAR_KERNEL; + other.linear = nullptr; + other.polynomial = nullptr; + other.cosine = nullptr; + other.gaussian = nullptr; + other.epan = nullptr; + other.triangular = nullptr; + other.hyptan = nullptr; + } return *this; } diff --git a/src/mlpack/methods/fastmks/fastmks_model.hpp b/src/mlpack/methods/fastmks/fastmks_model.hpp index e84eee0c28..0b7568c641 100644 --- a/src/mlpack/methods/fastmks/fastmks_model.hpp +++ b/src/mlpack/methods/fastmks/fastmks_model.hpp @@ -60,6 +60,9 @@ class FastMKSModel //! Copy assignment operator. FastMKSModel& operator=(const FastMKSModel& other); + //! Move assignment operator. + FastMKSModel& operator=(FastMKSModel&& other); + /** * Clean memory. */ diff --git a/src/mlpack/methods/hmm/hmm_model.hpp b/src/mlpack/methods/hmm/hmm_model.hpp index 41a7fd406b..0a2bce384b 100644 --- a/src/mlpack/methods/hmm/hmm_model.hpp +++ b/src/mlpack/methods/hmm/hmm_model.hpp @@ -129,6 +129,20 @@ class HMMModel return *this; } + //! Move assignment operator. + HMMModel& operator=(HMMModel&& other) + { + if (this != &other) + { + type = other.type; + discreteHMM = other.discreteHMM; + gaussianHMM = other.gaussianHMM; + gmmHMM = other.gmmHMM; + diagGMMHMM = other.diagGMMHMM; + } + return *this; + } + //! Clean memory. ~HMMModel() { diff --git a/src/mlpack/methods/range_search/range_search.hpp b/src/mlpack/methods/range_search/range_search.hpp index 06575005ac..98de888a69 100644 --- a/src/mlpack/methods/range_search/range_search.hpp +++ b/src/mlpack/methods/range_search/range_search.hpp @@ -122,12 +122,18 @@ class RangeSearch RangeSearch(RangeSearch&& other); /** - * Copy the given RangeSearch model. - * Use std::move to pass in the model if the old copy is no longer needed. - * + * Deep copy the given RangeSearch model. + * * @param other RangeSearch model to copy. */ - RangeSearch& operator=(RangeSearch other); + RangeSearch& operator=(const RangeSearch& other); + + /** + * Move the given RangeSearch model. + * + * @param other RangeSearch model to move. + */ + RangeSearch& operator=(RangeSearch&& other); /** * Destroy the RangeSearch object. If trees were created, they will be diff --git a/src/mlpack/methods/range_search/range_search_impl.hpp b/src/mlpack/methods/range_search/range_search_impl.hpp index 298aae995e..2652d47c89 100644 --- a/src/mlpack/methods/range_search/range_search_impl.hpp +++ b/src/mlpack/methods/range_search/range_search_impl.hpp @@ -169,25 +169,61 @@ template class TreeType> RangeSearch& -RangeSearch::operator=(RangeSearch other) +RangeSearch::operator=(const RangeSearch& other) { - // Clean memory first. - if (treeOwner) - delete referenceTree; - if (naive) - delete referenceSet; + if (this != &other) + { + oldFromNewReferences = other.oldFromNewReferences; + referenceTree = other.referenceTree ? new Tree(*other.referenceTree) : nullptr; + referenceSet = other.referenceTree ? &referenceTree->Dataset() : + new MatType(*other.referenceSet); + treeOwner = other.referenceTree; + naive = other.naive; + singleMode = other.singleMode; + metric = other.metric; + baseCases = other.baseCases; + scores = other.scores; + } + return *this; +} - // Move the other model. - oldFromNewReferences = std::move(other.oldFromNewReferences); - referenceTree = other.referenceTree; - referenceSet = other.referenceSet; - treeOwner = other.treeOwner; - naive = other.naive; - singleMode = other.singleMode; - metric = std::move(other.metric); - baseCases = other.baseCases; - scores = other.scores; +template class TreeType> +RangeSearch& +RangeSearch::operator=(RangeSearch&& other) +{ + if (this != &other) + { + // Clean memory first. + if (treeOwner) + delete referenceTree; + if (naive) + delete referenceSet; + // Move the other model. + oldFromNewReferences = std::move(other.oldFromNewReferences); + referenceTree = other.referenceTree; + referenceSet = other.referenceSet; + treeOwner = other.treeOwner; + naive = other.naive; + singleMode = other.singleMode; + metric = std::move(other.metric); + baseCases = other.baseCases; + scores = other.scores; + + // Clear other object. + other.referenceTree = nullptr; + other.referenceSet = nullptr; + other.treeOwner = false; + other.naive = false; + other.singleMode = false; + other.baseCases = 0; + other.scores = 0; + + } return *this; } @@ -254,12 +290,15 @@ void RangeSearch::Train( throw std::invalid_argument("cannot train on given reference tree when " "naive search (without trees) is desired"); + // Can only train when passed argument `referenceTree` is not nullptr if (treeOwner && referenceTree) + { delete this->referenceTree; - this->referenceTree = referenceTree; - this->referenceSet = &referenceTree->Dataset(); - treeOwner = false; + this->referenceTree = referenceTree; + this->referenceSet = &referenceTree->Dataset(); + treeOwner = false; + } } template Date: Sun, 17 Jan 2021 00:48:22 -0500 Subject: [PATCH 082/253] fix static code check 17/1 --- .../hoeffding_trees/hoeffding_tree.hpp | 21 ++++ .../hoeffding_trees/hoeffding_tree_impl.hpp | 111 ++++++++++++++++++ .../hoeffding_trees/hoeffding_tree_model.cpp | 78 ++++++------ src/mlpack/methods/kde/kde.hpp | 9 +- src/mlpack/methods/kde/kde_impl.hpp | 104 ++++++++++++---- 5 files changed, 264 insertions(+), 59 deletions(-) diff --git a/src/mlpack/methods/hoeffding_trees/hoeffding_tree.hpp b/src/mlpack/methods/hoeffding_trees/hoeffding_tree.hpp index 488048f4e6..b58d97a423 100644 --- a/src/mlpack/methods/hoeffding_trees/hoeffding_tree.hpp +++ b/src/mlpack/methods/hoeffding_trees/hoeffding_tree.hpp @@ -155,6 +155,27 @@ class HoeffdingTree */ HoeffdingTree(const HoeffdingTree& other); + /** + * Move another tree. + * + * @param other Tree to move. + */ + HoeffdingTree(HoeffdingTree&& other); + + /** + * Copy assignment operator. + * + * @param other Tree to copy. + */ + HoeffdingTree& operator=(const HoeffdingTree& other); + + /** + * Move assignment operator. + * + * @param other Tree to move. + */ + HoeffdingTree& operator=(HoeffdingTree&& other); + /** * Clean up memory. */ diff --git a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp index e6172f8324..f7e8bdd830 100644 --- a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp +++ b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp @@ -224,6 +224,117 @@ HoeffdingTree:: } } +// Move constructor. +template class NumericSplitType, + template class CategoricalSplitType> +HoeffdingTree:: + HoeffdingTree(HoeffdingTree&& other) : + numericSplits(std::move(other.numericSplits)), + categoricalSplits(std::move(other.categoricalSplits)), + dimensionMappings(other.dimensionMappings), + ownsMappings(true), + numSamples(other.numSamples), + numClasses(other.numClasses), + maxSamples(other.maxSamples), + checkInterval(other.checkInterval), + minSamples(other.minSamples), + datasetInfo(other.datasetInfo), + ownsInfo(true), + successProbability(other.successProbability), + splitDimension(other.splitDimension), + majorityClass(other.majorityClass), + majorityProbability(other.majorityProbability), + categoricalSplit(std::move(other.categoricalSplit)), + numericSplit(std::move(other.numericSplit)) +{ + // Remove pointers. + other.dimensionMappings = nullptr; + other.datasetInfo = nullptr; +} + +// Copy assignment operator. +template class NumericSplitType, + template class CategoricalSplitType> +HoeffdingTree& + HoeffdingTree:: + operator=(const HoeffdingTree& other) : +{ + if (this != &other) + { + numericSplits = other.numericSplits; + categoricalSplits = other.categoricalSplits; + dimensionMappings = new std::unordered_map>(*other.dimensionMappings); + ownsMappings = true; + numSamples = other.numSamples; + numClasses = other.numClasses; + maxSamples = other.maxSamples; + checkInterval = other.checkInterval; + minSamples = other.minSamples; + datasetInfo = new data::DatasetInfo(*other.datasetInfo); + ownsInfo = true; + successProbability = other.successProbability; + splitDimension = other.splitDimension; + majorityClass = other.majorityClass; + majorityProbability = other.majorityProbability; + categoricalSplit = other.categoricalSplit; + numericSplit = other.numericSplit; + + // Copy each of the children. + for (size_t i = 0; i < other.children.size(); ++i) + { + children.push_back(new HoeffdingTree(*other.children[i])); + + // Delete copied datasetInfo and dimension mappings. + delete children[i]->datasetInfo; + children[i]->datasetInfo = this->datasetInfo; + children[i]->ownsInfo = false; + + delete children[i]->dimensionMappings; + children[i]->dimensionMappings = this->dimensionMappings; + children[i]->ownsMappings = false; + } + } + return *this; +} + +// Move assignment operator. +template class NumericSplitType, + template class CategoricalSplitType> +HoeffdingTree& + HoeffdingTree:: + operator=(HoeffdingTree&& other) : +{ + if (this != &other) + { + numericSplits = std::move(other.numericSplits); + categoricalSplits = std::move(other.categoricalSplits); + dimensionMappings = other.dimensionMappings; + ownsMappings = true; + numSamples = other.numSamples; + numClasses = other.numClasses; + maxSamples = other.maxSamples; + checkInterval = other.checkInterval; + minSamples = other.minSamples; + datasetInfo = other.datasetInfo; + ownsInfo = true; + successProbability = other.successProbability; + splitDimension = other.splitDimension; + majorityClass = other.majorityClass; + majorityProbability = other.majorityProbability; + categoricalSplit = std::move(other.categoricalSplit); + numericSplit = std::move(other.numericSplit); + // Remove pointers. + other.dimensionMappings = nullptr; + other.datasetInfo = nullptr; + } + return *this; +} + + template class NumericSplitType, template class CategoricalSplitType> diff --git a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.cpp b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.cpp index d35970dd5b..2dfe857edf 100644 --- a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.cpp +++ b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_model.cpp @@ -62,53 +62,57 @@ HoeffdingTreeModel::HoeffdingTreeModel(HoeffdingTreeModel&& other) : HoeffdingTreeModel& HoeffdingTreeModel::operator=( const HoeffdingTreeModel& other) { - // Clear this model. - delete giniHoeffdingTree; - delete giniBinaryTree; - delete infoHoeffdingTree; - delete infoBinaryTree; + if (this != &other) + { + // Clear this model. + delete giniHoeffdingTree; + delete giniBinaryTree; + delete infoHoeffdingTree; + delete infoBinaryTree; - giniHoeffdingTree = NULL; - giniBinaryTree = NULL; - infoHoeffdingTree = NULL; - infoBinaryTree = NULL; - - // Create the right tree. - type = other.type; - if (other.giniHoeffdingTree && (type == GINI_HOEFFDING)) - giniHoeffdingTree = new GiniHoeffdingTreeType(*other.giniHoeffdingTree); - else if (other.giniBinaryTree && (type == GINI_BINARY)) - giniBinaryTree = new GiniBinaryTreeType(*other.giniBinaryTree); - else if (other.infoHoeffdingTree && (type == INFO_HOEFFDING)) - infoHoeffdingTree = new InfoHoeffdingTreeType(*other.infoHoeffdingTree); - else if (other.infoBinaryTree && (type == INFO_BINARY)) - infoBinaryTree = new InfoBinaryTreeType(*other.infoBinaryTree); + giniHoeffdingTree = NULL; + giniBinaryTree = NULL; + infoHoeffdingTree = NULL; + infoBinaryTree = NULL; + // Create the right tree. + type = other.type; + if (other.giniHoeffdingTree && (type == GINI_HOEFFDING)) + giniHoeffdingTree = new GiniHoeffdingTreeType(*other.giniHoeffdingTree); + else if (other.giniBinaryTree && (type == GINI_BINARY)) + giniBinaryTree = new GiniBinaryTreeType(*other.giniBinaryTree); + else if (other.infoHoeffdingTree && (type == INFO_HOEFFDING)) + infoHoeffdingTree = new InfoHoeffdingTreeType(*other.infoHoeffdingTree); + else if (other.infoBinaryTree && (type == INFO_BINARY)) + infoBinaryTree = new InfoBinaryTreeType(*other.infoBinaryTree); + } return *this; } // Move operator. HoeffdingTreeModel& HoeffdingTreeModel::operator=(HoeffdingTreeModel&& other) { - // Clear this model. - delete giniHoeffdingTree; - delete giniBinaryTree; - delete infoHoeffdingTree; - delete infoBinaryTree; + if (this != &other) + { + // Clear this model. + delete giniHoeffdingTree; + delete giniBinaryTree; + delete infoHoeffdingTree; + delete infoBinaryTree; - type = other.type; - giniHoeffdingTree = other.giniHoeffdingTree; - giniBinaryTree = other.giniBinaryTree; - infoHoeffdingTree = other.infoHoeffdingTree; - infoBinaryTree = other.infoBinaryTree; - - // Clear the other model. - other.type = GINI_HOEFFDING; - other.giniHoeffdingTree = NULL; - other.giniBinaryTree = NULL; - other.infoHoeffdingTree = NULL; - other.infoBinaryTree = NULL; + type = other.type; + giniHoeffdingTree = other.giniHoeffdingTree; + giniBinaryTree = other.giniBinaryTree; + infoHoeffdingTree = other.infoHoeffdingTree; + infoBinaryTree = other.infoBinaryTree; + // Clear the other model. + other.type = GINI_HOEFFDING; + other.giniHoeffdingTree = NULL; + other.giniBinaryTree = NULL; + other.infoHoeffdingTree = NULL; + other.infoBinaryTree = NULL; + } return *this; } diff --git a/src/mlpack/methods/kde/kde.hpp b/src/mlpack/methods/kde/kde.hpp index 448d32dd84..8885c2e894 100644 --- a/src/mlpack/methods/kde/kde.hpp +++ b/src/mlpack/methods/kde/kde.hpp @@ -140,11 +140,16 @@ class KDE /** * Copy a KDE model. * - * Use std::move if the object to copy is no longer needed. + * @param other KDE model to copy. + */ + KDE& operator=(const KDE& other); + + /** + * Move a KDE model. * * @param other KDE model to copy. */ - KDE& operator=(KDE other); + KDE& operator=(KDE&& other); /** * Destroy the KDE object. If this object created any trees, they will be diff --git a/src/mlpack/methods/kde/kde_impl.hpp b/src/mlpack/methods/kde/kde_impl.hpp index b48190e686..054c02119d 100644 --- a/src/mlpack/methods/kde/kde_impl.hpp +++ b/src/mlpack/methods/kde/kde_impl.hpp @@ -190,31 +190,95 @@ KDE:: -operator=(KDE other) +operator=(const KDE& other) { - // Clean memory. - if (ownsReferenceTree) + if (this != &other) { - delete referenceTree; - delete oldFromNewReferences; + // Clean memory. + if (ownsReferenceTree) + { + delete referenceTree; + delete oldFromNewReferences; + } + kernel = KernelType(other.kernel); + metric = MetricType(other.metric); + relError = other.relError; + absError = other.absError; + ownsReferenceTree = other.ownsReferenceTree; + trained = other.trained; + mode = other.mode; + monteCarlo = other.monteCarlo; + mcProb = other.mcProb; + initialSampleSize = other.initialSampleSize; + mcEntryCoef = other.mcEntryCoef; + mcBreakCoef = other.mcBreakCoef; + if (trained) + { + if (ownsReferenceTree) + { + oldFromNewReferences = + new std::vector(*other.oldFromNewReferences); + referenceTree = new Tree(*other.referenceTree); + } + else + { + oldFromNewReferences = other.oldFromNewReferences; + referenceTree = other.referenceTree; + } + } } + return *this; +} - // Move the other object. - this->kernel = std::move(other.kernel); - this->metric = std::move(other.metric); - this->referenceTree = std::move(other.referenceTree); - this->oldFromNewReferences = std::move(other.oldFromNewReferences); - this->relError = other.relError; - this->absError = other.absError; - this->ownsReferenceTree = other.ownsReferenceTree; - this->trained = other.trained; - this->mode = other.mode; - this->monteCarlo = other.monteCarlo; - this->mcProb = other.mcProb; - this->initialSampleSize = other.initialSampleSize; - this->mcEntryCoef = other.mcEntryCoef; - this->mcBreakCoef = other.mcBreakCoef; +template class TreeType, + template class DualTreeTraversalType, + template class SingleTreeTraversalType> +KDE& +KDE:: +operator=(KDE&& other) +{ + if (this != &other) + { + // Clean memory. + if (ownsReferenceTree) + { + delete referenceTree; + delete oldFromNewReferences; + } + // Move the other object. + this->kernel = std::move(other.kernel); + this->metric = std::move(other.metric); + // TODO: This should be: this->referenceTree = other.referenceTree; + this->referenceTree = std::move(other.referenceTree); + // TODO: This should be: this->oldFromNewReferences = other.oldFromNewReferences; + this->oldFromNewReferences = std::move(other.oldFromNewReferences); + this->relError = other.relError; + this->absError = other.absError; + this->ownsReferenceTree = other.ownsReferenceTree; + this->trained = other.trained; + this->mode = other.mode; + this->monteCarlo = other.monteCarlo; + this->mcProb = other.mcProb; + this->initialSampleSize = other.initialSampleSize; + this->mcEntryCoef = other.mcEntryCoef; + this->mcBreakCoef = other.mcBreakCoef; + } return *this; } From 568ce1f15681645600b6e102a033c9d047f3fb4d Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Sun, 17 Jan 2021 14:54:02 -0500 Subject: [PATCH 083/253] finish fixing static code check --- .../complete_incremental_termination.hpp | 3 +- .../incomplete_incremental_termination.hpp | 3 +- .../ann/layer/recurrent_attention_impl.hpp | 3 +- .../ann/layer/reinforce_normal_impl.hpp | 2 +- .../hoeffding_trees/hoeffding_tree_impl.hpp | 4 +-- .../kmeans/dual_tree_kmeans_rules_impl.hpp | 3 +- .../methods/preprocess/scaling_model.hpp | 3 ++ .../methods/preprocess/scaling_model_impl.hpp | 32 ++++++++++++++++++- .../q_networks/categorical_dqn.hpp | 2 +- 9 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/mlpack/methods/amf/termination_policies/complete_incremental_termination.hpp b/src/mlpack/methods/amf/termination_policies/complete_incremental_termination.hpp index e3a030836d..bdd02d7fec 100644 --- a/src/mlpack/methods/amf/termination_policies/complete_incremental_termination.hpp +++ b/src/mlpack/methods/amf/termination_policies/complete_incremental_termination.hpp @@ -36,7 +36,8 @@ class CompleteIncrementalTermination */ CompleteIncrementalTermination( TerminationPolicy tPolicy = TerminationPolicy()) : - tPolicy(tPolicy) { } + tPolicy(tPolicy), incrementalIndex(0), iteration(0) + { /** Nothing to do here. */ } /** * Initializes the termination policy before stating the factorization. diff --git a/src/mlpack/methods/amf/termination_policies/incomplete_incremental_termination.hpp b/src/mlpack/methods/amf/termination_policies/incomplete_incremental_termination.hpp index 62b112b061..d01fdfd4c5 100644 --- a/src/mlpack/methods/amf/termination_policies/incomplete_incremental_termination.hpp +++ b/src/mlpack/methods/amf/termination_policies/incomplete_incremental_termination.hpp @@ -35,7 +35,8 @@ class IncompleteIncrementalTermination */ IncompleteIncrementalTermination( TerminationPolicy tPolicy = TerminationPolicy()) : - tPolicy(tPolicy) { } + tPolicy(tPolicy), incrementalIndex(0), iteration(0) + { /** Nothing to do here. */ } /** * Initializes the termination policy before stating the factorization. diff --git a/src/mlpack/methods/ann/layer/recurrent_attention_impl.hpp b/src/mlpack/methods/ann/layer/recurrent_attention_impl.hpp index 4cdb912756..dcc60055d5 100644 --- a/src/mlpack/methods/ann/layer/recurrent_attention_impl.hpp +++ b/src/mlpack/methods/ann/layer/recurrent_attention_impl.hpp @@ -31,7 +31,8 @@ RecurrentAttention::RecurrentAttention() : rho(0), forwardStep(0), backwardStep(0), - deterministic(false) + deterministic(false), + outSize(0) { // Nothing to do. } diff --git a/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp b/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp index 67eebf107d..b3c2fd700b 100644 --- a/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp +++ b/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp @@ -21,7 +21,7 @@ namespace ann /** Artificial Neural Network. */ { template ReinforceNormal::ReinforceNormal( - const double stdev) : stdev(stdev) + const double stdev) : stdev(stdev), reward(0.0), deterministic(false) { // Nothing to do here. } diff --git a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp index f7e8bdd830..3535f9558b 100644 --- a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp +++ b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp @@ -259,7 +259,7 @@ template class CategoricalSplitType> HoeffdingTree& HoeffdingTree:: - operator=(const HoeffdingTree& other) : + operator=(const HoeffdingTree& other) { if (this != &other) { @@ -306,7 +306,7 @@ template class CategoricalSplitType> HoeffdingTree& HoeffdingTree:: - operator=(HoeffdingTree&& other) : + operator=(HoeffdingTree&& other) { if (this != &other) { diff --git a/src/mlpack/methods/kmeans/dual_tree_kmeans_rules_impl.hpp b/src/mlpack/methods/kmeans/dual_tree_kmeans_rules_impl.hpp index 6f180c2e99..5e08f88a28 100644 --- a/src/mlpack/methods/kmeans/dual_tree_kmeans_rules_impl.hpp +++ b/src/mlpack/methods/kmeans/dual_tree_kmeans_rules_impl.hpp @@ -40,7 +40,8 @@ DualTreeKMeansRules::DualTreeKMeansRules( baseCases(0), scores(0), lastQueryIndex(dataset.n_cols), - lastReferenceIndex(centroids.n_cols) + lastReferenceIndex(centroids.n_cols), + lastBaseCase(0.0) { // We must set the traversal info last query and reference node pointers to // something that is both invalid (i.e. not a tree node) and not NULL. We'll diff --git a/src/mlpack/methods/preprocess/scaling_model.hpp b/src/mlpack/methods/preprocess/scaling_model.hpp index 87693cc796..a5d7082658 100644 --- a/src/mlpack/methods/preprocess/scaling_model.hpp +++ b/src/mlpack/methods/preprocess/scaling_model.hpp @@ -65,6 +65,9 @@ class ScalingModel //! Copy assignment operator. ScalingModel& operator=(const ScalingModel& other); + //! Move assignment operator. + ScalingModel& operator=(ScalingModel&& other); + //! Clean up memory. ~ScalingModel(); diff --git a/src/mlpack/methods/preprocess/scaling_model_impl.hpp b/src/mlpack/methods/preprocess/scaling_model_impl.hpp index dd918de9d9..6da36e6f49 100644 --- a/src/mlpack/methods/preprocess/scaling_model_impl.hpp +++ b/src/mlpack/methods/preprocess/scaling_model_impl.hpp @@ -84,7 +84,7 @@ ScalingModel::ScalingModel(ScalingModel&& other) : } //! Copy assignment operator. -ScalingModel& ScalingModel::operator= (const ScalingModel& other) +ScalingModel& ScalingModel::operator=(const ScalingModel& other) { if (this == &other) { @@ -123,6 +123,36 @@ ScalingModel& ScalingModel::operator= (const ScalingModel& other) return *this; } +//! Move assignment operator. +ScalingModel& ScalingModel::operator=(ScalingModel&& other) +{ + if (this != &other) + { + scalerType = other.scalerType; + minmaxscale = other.minmaxscale; + maxabsscale = other.maxabsscale; + meanscale = other.meanscale; + standardscale = other.standardscale; + pcascale = other.pcascale; + zcascale = other.zcascale; + minValue = other.minValue; + maxValue = other.maxValue; + epsilon = other.epsilon; + + other.scalerType = 0; + other.minmaxscale = nullptr; + other.maxabsscale = nullptr; + other.meanscale = nullptr; + other.standardscale = nullptr; + other.pcascale = nullptr; + other.zcascale = nullptr; + other.minValue = 0; + other.maxValue = 1; + other.epsilon = 0.00005; + } + return *this; +} + ScalingModel::~ScalingModel() { delete minmaxscale; diff --git a/src/mlpack/methods/reinforcement_learning/q_networks/categorical_dqn.hpp b/src/mlpack/methods/reinforcement_learning/q_networks/categorical_dqn.hpp index b52110d744..82ce15e77e 100644 --- a/src/mlpack/methods/reinforcement_learning/q_networks/categorical_dqn.hpp +++ b/src/mlpack/methods/reinforcement_learning/q_networks/categorical_dqn.hpp @@ -53,7 +53,7 @@ class CategoricalDQN /** * Default constructor. */ - CategoricalDQN() : network(), isNoisy(false) + CategoricalDQN() : network(), isNoisy(false), atomSize(0), vMin(0.0), vMax(0.0) { /* Nothing to do here. */ } /** From f7b5537aa790c6ba4ebc540976000032bdefb5fb Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Mon, 18 Jan 2021 09:57:30 +0530 Subject: [PATCH 084/253] Added Hinge Loss Skeleton --- .../methods/ann/loss_functions/CMakeLists.txt | 26 ++--- .../methods/ann/loss_functions/hinge_loss.hpp | 102 ++++++++++++++++++ .../ann/loss_functions/hinge_loss_impl.hpp | 65 +++++++++++ 3 files changed, 181 insertions(+), 12 deletions(-) create mode 100644 src/mlpack/methods/ann/loss_functions/hinge_loss.hpp create mode 100644 src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp diff --git a/src/mlpack/methods/ann/loss_functions/CMakeLists.txt b/src/mlpack/methods/ann/loss_functions/CMakeLists.txt index 70b570e0ff..12d9d1718a 100644 --- a/src/mlpack/methods/ann/loss_functions/CMakeLists.txt +++ b/src/mlpack/methods/ann/loss_functions/CMakeLists.txt @@ -9,24 +9,32 @@ set(SOURCES dice_loss_impl.hpp earth_mover_distance.hpp earth_mover_distance_impl.hpp + empty_loss.hpp + empty_loss_impl.hpp huber_loss.hpp huber_loss_impl.hpp + hinge_embedding_loss.hpp + hinge_embedding_loss_impl.hpp + hinge_loss.hpp + hinge_loss_impl.hpp kl_divergence.hpp kl_divergence_impl.hpp - margin_ranking_loss.hpp - margin_ranking_loss_impl.hpp - mean_bias_error.hpp - mean_bias_error_impl.hpp l1_loss.hpp l1_loss_impl.hpp + log_cosh_loss.hpp + log_cosh_loss_impl.hpp + margin_ranking_loss.hpp + margin_ranking_loss_impl.hpp + mean_absolute_percentage_error.hpp + mean_absolute_percentage_error_impl.hpp + mean_bias_error.hpp + mean_bias_error_impl.hpp mean_squared_error.hpp mean_squared_error_impl.hpp mean_squared_logarithmic_error.hpp mean_squared_logarithmic_error_impl.hpp negative_log_likelihood.hpp negative_log_likelihood_impl.hpp - log_cosh_loss.hpp - log_cosh_loss_impl.hpp poisson_nll_loss.hpp poisson_nll_loss_impl.hpp reconstruction_loss.hpp @@ -35,12 +43,6 @@ set(SOURCES sigmoid_cross_entropy_error_impl.hpp soft_margin_loss.hpp soft_margin_loss_impl.hpp - hinge_embedding_loss.hpp - hinge_embedding_loss_impl.hpp - empty_loss.hpp - empty_loss_impl.hpp - mean_absolute_percentage_error.hpp - mean_absolute_percentage_error_impl.hpp triplet_margin_loss.hpp triplet_margin_loss_impl.hpp ) diff --git a/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp b/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp new file mode 100644 index 0000000000..e43ec9d862 --- /dev/null +++ b/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp @@ -0,0 +1,102 @@ +/** + * @file methods/ann/loss_functions/hinge_loss.hpp + * @author Anush Kini + * + * Definition of the Hinge Loss Function. + * + * 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. + */ + +#ifndef MLPACK_METHODS_ANN_LOSS_FUNCTION_HINGE_LOSS_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_HINGE_LOSS_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * Computes the hinge loss between y_true and y_pred. Expects y_true to be + * either -1 or 1. If y_true is either 0 or 1, a temporary conversion is made to + * calculate the loss. + * + * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + * @tparam OutputDataType Type of the output data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + */ +template < + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +class HingeLoss +{ + public: + /** + * Create HingeLoss object. + * @param reduction Specifies the reduction to apply to the output. If false, + * 'mean' reduction is used, where sum of the output will be + * divided by the number of elements in the output. If + * true, 'sum' reduction is used and the output will be + * summed. It is set to true by default. + */ + HingeLoss(const bool reduction = true); + + /** + * Computes the Hinge loss function. + * + * @param prediction Prediction used for evaluating the specified loss + * function. + * @param target Target data to compare with. + */ + template + typename PredictionType::elem_type Forward(const PredictionType& prediction, + const TargetType& target); + + /** + * Ordinary feed backward pass of a neural network. + * + * @param prediction Prediction used for evaluating the specified loss + * function. + * @param target The target vector. + * @param loss The calculated error. + */ + template + void Backward(const PredictionType& prediction, + const TargetType& target, + LossType& loss); + + //! Get the output parameter. + OutputDataType& OutputParameter() const { return outputParameter; } + //! Modify the output parameter. + OutputDataType& OutputParameter() { return outputParameter; } + + //! Get the type of reduction used. + bool Reduction() const { return reduction; } + //! Modify the type of reduction used. + bool& Reduction() { return reduction; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const uint32_t /* version */); + + private: + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! The boolean value that tells if reduction is sum or mean. + bool reduction; +}; // class HingeLoss + +} // namespace ann +} // namespace mlpack + +// include implementation +#include "hinge_loss_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp new file mode 100644 index 0000000000..8cb74192c7 --- /dev/null +++ b/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp @@ -0,0 +1,65 @@ +/** + * @file methods/ann/loss_functions/hinge_loss_impl.hpp + * @author Anush Kini + * + * Implementation of the Hinge loss function. + * + * 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. + */ + +#ifndef MLPACK_METHODS_ANN_LOSS_FUNCTION_HINGE_LOSS_IMPL_HPP +#define MLPACK_METHODS_ANN_LOSS_FUNCTION_HINGE_LOSS_IMPL_HPP + +// In case it hasn't yet been included. +#include "hinge_loss.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +HingeLoss::HingeLoss(const bool reduction): + reduction(reduction) +{ + // Nothing to do here. +} + +template +template +typename PredictionType::elem_type +HingeLoss::Forward( + const PredictionType& prediction, + const TargetType& target) +{ + TargetType temp = target - (target == 0); + TargetType temp_zeros.zeros(target.size()); + + PredictionType loss = arma::mean(arma::max(1 - prediction % temp, temp_zeros), 1); + typename PredictionType::elem_type lossSum = arma::accu(loss); + + if (reduction) + return lossSum; + + return lossSum / loss.n_elem; +} + +template +template +void HingeEmbeddingLoss::Backward( + const PredictionType& prediction, + const TargetType& target, + LossType& loss) +{ + TargetType temp = target - (target == 0); + loss = (prediction < 1 / temp) % -temp; +} + + + + +} // namespace ann +} // namespace mlpack + +#endif From a21a52dec17fdfa516cf4803fcd3a1c1ef8ce60d Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Mon, 18 Jan 2021 10:00:32 +0530 Subject: [PATCH 085/253] Style fixes --- src/mlpack/methods/ann/layer/multiply_constant.hpp | 8 ++++---- src/mlpack/methods/ann/layer/multiply_merge.hpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mlpack/methods/ann/layer/multiply_constant.hpp b/src/mlpack/methods/ann/layer/multiply_constant.hpp index a9a32a19ac..32fad5b5b3 100644 --- a/src/mlpack/methods/ann/layer/multiply_constant.hpp +++ b/src/mlpack/methods/ann/layer/multiply_constant.hpp @@ -39,16 +39,16 @@ class MultiplyConstant */ MultiplyConstant(const double scalar = 1.0); - //! Copy Constructor + //! Copy Constructor. MultiplyConstant(const MultiplyConstant& layer); - //! Move Constructor + //! Move Constructor. MultiplyConstant(MultiplyConstant&& layer); - //! Copy assignment operator + //! Copy assignment operator. MultiplyConstant& operator=(const MultiplyConstant& layer); - //! Move assignment operator + //! Move assignment operator. MultiplyConstant& operator=(MultiplyConstant&& layer); /** diff --git a/src/mlpack/methods/ann/layer/multiply_merge.hpp b/src/mlpack/methods/ann/layer/multiply_merge.hpp index 94e4169d52..1ac73a0bbd 100644 --- a/src/mlpack/methods/ann/layer/multiply_merge.hpp +++ b/src/mlpack/methods/ann/layer/multiply_merge.hpp @@ -50,16 +50,16 @@ class MultiplyMerge */ MultiplyMerge(const bool model = false, const bool run = true); - //! Copy Constructor + //! Copy Constructor. MultiplyMerge(const MultiplyMerge& layer); - //! Move Constructor + //! Move Constructor. MultiplyMerge(MultiplyMerge&& layer); - //! Copy assignment operator + //! Copy assignment operator. MultiplyMerge& operator=(const MultiplyMerge& layer); - //! Move assignment operator + //! Move assignment operator. MultiplyMerge& operator=(MultiplyMerge&& layer); //! Destructor to release allocated memory. From e4fb279689f66ffd1ade7ff9d565cee59839ca98 Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Mon, 18 Jan 2021 19:14:24 +0530 Subject: [PATCH 086/253] Added an implementation of hinge loss --- .../ann/loss_functions/hinge_loss_impl.hpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp index 8cb74192c7..0d6729b5b5 100644 --- a/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp @@ -36,7 +36,8 @@ HingeLoss::Forward( TargetType temp = target - (target == 0); TargetType temp_zeros.zeros(target.size()); - PredictionType loss = arma::mean(arma::max(1 - prediction % temp, temp_zeros), 1); + PredictionType loss = arma::max(1 - prediction % temp, temp_zeros); + typename PredictionType::elem_type lossSum = arma::accu(loss); if (reduction) @@ -53,11 +54,20 @@ void HingeEmbeddingLoss::Backward( LossType& loss) { TargetType temp = target - (target == 0); - loss = (prediction < 1 / temp) % -temp; + loss = (prediction < (1 / temp)) % -temp; + + if (!reduction) + loss /= target.n_elem; } - - +template +template +void HingeEmbeddingLoss::serialize( + Archive& ar, + const uint32_t /* version */) +{ + ar(CEREAL_NVP(reduction)); +} } // namespace ann } // namespace mlpack From 151ca758abed17013287ea5a360acaecf94b66db Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Mon, 18 Jan 2021 16:59:24 -0500 Subject: [PATCH 087/253] fix static error 1/18 --- src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp | 2 +- src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp | 2 +- src/mlpack/methods/kmeans/dual_tree_kmeans_rules_impl.hpp | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp b/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp index b3c2fd700b..2c985dff6d 100644 --- a/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp +++ b/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp @@ -34,7 +34,7 @@ void ReinforceNormal::Forward( if (!deterministic) { // Multiply by standard deviations and re-center the means to the mean. - output = arma::randn >(input.n_rows, input.n_cols) * + output = arma::randn>(input.n_rows, input.n_cols) * stdev + input; moduleInputParameter.push_back(input); diff --git a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp index 3535f9558b..5e31358621 100644 --- a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp +++ b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp @@ -452,7 +452,7 @@ void HoeffdingTree< delete dimensionMappings; const CategoricalSplitType categoricalSplitIn(0, 0); - const NumericSplitType& numericSplitIn(0); + const NumericSplitType numericSplitIn(0); dimensionMappings = new std::unordered_map>(); diff --git a/src/mlpack/methods/kmeans/dual_tree_kmeans_rules_impl.hpp b/src/mlpack/methods/kmeans/dual_tree_kmeans_rules_impl.hpp index 5e08f88a28..2d1a66fe12 100644 --- a/src/mlpack/methods/kmeans/dual_tree_kmeans_rules_impl.hpp +++ b/src/mlpack/methods/kmeans/dual_tree_kmeans_rules_impl.hpp @@ -157,8 +157,7 @@ inline double DualTreeKMeansRules::Score( traversalInfo.LastQueryNode()->MinimumBoundDistance(); const double lastRefDescDist = traversalInfo.LastReferenceNode()->MinimumBoundDistance(); - adjustedScore = lastScore + lastQueryDescDist; - adjustedScore = lastScore + lastRefDescDist; + adjustedScore = lastScore + lastQueryDescDist + lastRefDescDist; } // Assemble an adjusted score. For nearest neighbor search, this adjusted From 0008893ef70f92b4589aa739f7097627f0cf2f89 Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Mon, 18 Jan 2021 22:28:24 -0500 Subject: [PATCH 088/253] fix static error --- src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp b/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp index 2c985dff6d..be4803b6c6 100644 --- a/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp +++ b/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp @@ -34,8 +34,12 @@ void ReinforceNormal::Forward( if (!deterministic) { // Multiply by standard deviations and re-center the means to the mean. - output = arma::randn>(input.n_rows, input.n_cols) * - stdev + input; + arma::Mat output(input.n_rows, input.n_cols); + + output = output.randn() * stdev + input; + + // output = arma::randn>(input.n_rows, input.n_cols) * + // stdev + input; moduleInputParameter.push_back(input); } From 2e208af07573ba04ed9215db77704d2d6bab6f25 Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Tue, 19 Jan 2021 01:41:09 -0500 Subject: [PATCH 089/253] fix static code 1/19 --- src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp b/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp index be4803b6c6..74de3d93d4 100644 --- a/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp +++ b/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp @@ -34,9 +34,7 @@ void ReinforceNormal::Forward( if (!deterministic) { // Multiply by standard deviations and re-center the means to the mean. - arma::Mat output(input.n_rows, input.n_cols); - - output = output.randn() * stdev + input; + output = output.randn(input.n_rows, input.n_cols) * stdev + input; // output = arma::randn>(input.n_rows, input.n_cols) * // stdev + input; From 772b95ffb73e498cfab97c2c78d8ec06ca8c3884 Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Tue, 19 Jan 2021 12:40:38 +0530 Subject: [PATCH 090/253] Added hinge loss implementation --- src/mlpack/methods/ann/loss_functions/hinge_loss.hpp | 2 +- src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp b/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp index e43ec9d862..a9c2563b9e 100644 --- a/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp @@ -64,7 +64,7 @@ class HingeLoss * @param target The target vector. * @param loss The calculated error. */ - template + template void Backward(const PredictionType& prediction, const TargetType& target, LossType& loss); diff --git a/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp index 0d6729b5b5..85fb07cb88 100644 --- a/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp @@ -34,7 +34,7 @@ HingeLoss::Forward( const TargetType& target) { TargetType temp = target - (target == 0); - TargetType temp_zeros.zeros(target.size()); + TargetType temp_zeros(size(target), arma::fill::zeros); PredictionType loss = arma::max(1 - prediction % temp, temp_zeros); @@ -48,7 +48,7 @@ HingeLoss::Forward( template template -void HingeEmbeddingLoss::Backward( +void HingeLoss::Backward( const PredictionType& prediction, const TargetType& target, LossType& loss) @@ -62,7 +62,7 @@ void HingeEmbeddingLoss::Backward( template template -void HingeEmbeddingLoss::serialize( +void HingeLoss::serialize( Archive& ar, const uint32_t /* version */) { From 472e8a4d01186b8733dbf3168cdc2d6d5879e7a7 Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Tue, 19 Jan 2021 09:40:42 -0500 Subject: [PATCH 091/253] finishing up --- src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp b/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp index 74de3d93d4..c2f92df476 100644 --- a/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp +++ b/src/mlpack/methods/ann/layer/reinforce_normal_impl.hpp @@ -35,9 +35,6 @@ void ReinforceNormal::Forward( { // Multiply by standard deviations and re-center the means to the mean. output = output.randn(input.n_rows, input.n_cols) * stdev + input; - - // output = arma::randn>(input.n_rows, input.n_cols) * - // stdev + input; moduleInputParameter.push_back(input); } From b17bc76a3a47ca920b4a16ccd6c43d9d353b24c8 Mon Sep 17 00:00:00 2001 From: Alex Nguyen <60036798+rxng8@users.noreply.github.com> Date: Wed, 20 Jan 2021 17:00:40 -0500 Subject: [PATCH 092/253] Update src/mlpack/core/tree/hrectbound_impl.hpp Co-authored-by: Marcus Edel --- src/mlpack/core/tree/hrectbound_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/core/tree/hrectbound_impl.hpp b/src/mlpack/core/tree/hrectbound_impl.hpp index 45d4b81a76..a1259a677c 100644 --- a/src/mlpack/core/tree/hrectbound_impl.hpp +++ b/src/mlpack/core/tree/hrectbound_impl.hpp @@ -104,7 +104,7 @@ inline HRectBound::HRectBound( } /** - * Move assignment operator + * Move assignment operator. */ template inline HRectBound< From 947fc2b83cbdf9b199ed73a70a58cb105e521065 Mon Sep 17 00:00:00 2001 From: Alex Nguyen <60036798+rxng8@users.noreply.github.com> Date: Wed, 20 Jan 2021 17:00:47 -0500 Subject: [PATCH 093/253] Update src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp Co-authored-by: Marcus Edel --- src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp index 32bb94ece9..c6cc5bb586 100644 --- a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp +++ b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp @@ -182,7 +182,7 @@ class DiscreteHilbertValue */ DiscreteHilbertValue& operator=(const DiscreteHilbertValue& val); - /** + /** * Move the local Hilbert object. * * @param val The DiscreteHilbertValue object from which the dataset From 7bf86ac51bb68f1e0221bed8264f50a219f2ea9b Mon Sep 17 00:00:00 2001 From: Alex Nguyen <60036798+rxng8@users.noreply.github.com> Date: Wed, 20 Jan 2021 17:01:15 -0500 Subject: [PATCH 094/253] Update src/mlpack/methods/range_search/range_search_impl.hpp Co-authored-by: Marcus Edel --- src/mlpack/methods/range_search/range_search_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/range_search/range_search_impl.hpp b/src/mlpack/methods/range_search/range_search_impl.hpp index 2652d47c89..03f90b3057 100644 --- a/src/mlpack/methods/range_search/range_search_impl.hpp +++ b/src/mlpack/methods/range_search/range_search_impl.hpp @@ -290,7 +290,7 @@ void RangeSearch::Train( throw std::invalid_argument("cannot train on given reference tree when " "naive search (without trees) is desired"); - // Can only train when passed argument `referenceTree` is not nullptr + // Can only train when passed argument `referenceTree` is not nullptr. if (treeOwner && referenceTree) { delete this->referenceTree; From 880471defbf4a9c4df53757ecf47ffb92bb9ad9f Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Wed, 20 Jan 2021 19:19:03 -0500 Subject: [PATCH 095/253] change val to other --- .../core/tree/rectangle_tree/discrete_hilbert_value.hpp | 8 ++++---- .../tree/rectangle_tree/discrete_hilbert_value_impl.hpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp index c6cc5bb586..a21dd1af3d 100644 --- a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp +++ b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value.hpp @@ -177,18 +177,18 @@ class DiscreteHilbertValue /** * Copy the local Hilbert value's pointer. * - * @param val The DiscreteHilbertValue object from which the dataset + * @param other The DiscreteHilbertValue object from which the dataset * will be copied. */ - DiscreteHilbertValue& operator=(const DiscreteHilbertValue& val); + DiscreteHilbertValue& operator=(const DiscreteHilbertValue& other); /** * Move the local Hilbert object. * - * @param val The DiscreteHilbertValue object from which the dataset + * @param other The DiscreteHilbertValue object from which the dataset * will be copied. */ - DiscreteHilbertValue& operator=(DiscreteHilbertValue&& val); + DiscreteHilbertValue& operator=(DiscreteHilbertValue&& other); /** * Nullify the localHilbertValues pointer in order to prevent an invalid free. diff --git a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp index 48ad8557f7..bd3c9cb87e 100644 --- a/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp +++ b/src/mlpack/core/tree/rectangle_tree/discrete_hilbert_value_impl.hpp @@ -434,18 +434,18 @@ RemoveNode(TreeType* node, const size_t nodeIndex) template DiscreteHilbertValue& DiscreteHilbertValue:: -operator=(const DiscreteHilbertValue& val) +operator=(const DiscreteHilbertValue& other) { - if (this == &val) + if (this == &other) return *this; if (ownsLocalHilbertValues) delete localHilbertValues; localHilbertValues = const_cast* > - (val.LocalHilbertValues()); + (other.LocalHilbertValues()); ownsLocalHilbertValues = false; - numValues = val.NumValues(); + numValues = other.NumValues(); return *this; } From 2fbb7cdcb1087b4e9363a8e526c0209c92d2e935 Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Thu, 21 Jan 2021 11:24:12 +0530 Subject: [PATCH 096/253] Added Test for Hinge Loss Function --- src/mlpack/tests/loss_functions_test.cpp | 73 ++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/src/mlpack/tests/loss_functions_test.cpp b/src/mlpack/tests/loss_functions_test.cpp index 5a208984dd..b5ab0c155a 100644 --- a/src/mlpack/tests/loss_functions_test.cpp +++ b/src/mlpack/tests/loss_functions_test.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -955,3 +956,75 @@ TEST_CASE("TripletMarginLossTest") REQUIRE(arma::accu(output) == -12); REQUIRE(output.n_elem == 1); } + +/** + * Simple test for the Hinge loss function. + */ +TEST_CASE("HingeLossTest", "[LossFunctionsTest]") +{ + arma::mat input, target, target_b, output; + double loss, loss_b; + HingeLoss<> module1; + HingeLoss<> module2(false); + + // Test the Forward function. Loss should be 0 if input = target. + input = arma::ones(10, 1); + target = arma::ones(10, 1); + loss = module1.Forward(input, target); + REQUIRE(loss == 0); + + // Test the Backward function for input = target. + module1.Backward(input, target, output); + for (double el : output) + { + // For input = target we should get 0.0 everywhere. + REQUIRE(el == Approx(0.0).epsilon(1e-5)); + } + + REQUIRE(output.n_rows == input.n_rows); + REQUIRE(output.n_cols == input.n_cols); + + input = {{0.90599973, -0.33040298, 0.07123354}, + {0.71988434, 0.49657596, 0.39873373}, + {-0.57646927, 0.3951491 , -0.1003365}, + {0.12528634, 0.68122971, 0.85448826}}; + + target = {{-1, -1, 1}, + {-1, 1, 1}, + {1, -1, -1}, + {1, -1, -1}}; + + // Binary labels for target + target_b = {{0, 0, 1}, + {0, 1, 1}, + {1, 0, 0}, + {1, 0, 0}}; + + // Test for binary labels as target. + loss = module1.Forward(input, target); + loss_b = module1.Forward(input, target_b); + + // Loss should be same due to internal conversion of binary labels. + REQUIRE(loss == loss_b); + + // Test for sum reduction. + // Test the Forward function. + loss = module1.Forward(input, target); + REQUIRE(loss == Approx(14.61065).epsilon(1e-3)); + + // Test the Backward function + module1.Backward(input, target, output); + REQUIRE(arma::accu(output) == Approx(-5).epsilon(1e-3)); + REQUIRE(output.n_rows == input.n_rows); + REQUIRE(output.n_cols == input.n_cols); + + // Test for mean reduction. + loss = module2.Forward(input, target); + REQUIRE(loss == Approx(1.21755).epsilon(1e-3)); + + // Test the Backward function. + module2.Backward(input, target, output); + REQUIRE(arma::accu(output) == Approx(-0.41667).epsilon(1e-3)); + REQUIRE(output.n_rows == input.n_rows); + REQUIRE(output.n_cols == input.n_cols); +} From 67ee79d51a3a7fa79c3b20b9b32919630c8d6830 Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Thu, 21 Jan 2021 18:53:09 +0530 Subject: [PATCH 097/253] Minor comment addition --- src/mlpack/tests/loss_functions_test.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlpack/tests/loss_functions_test.cpp b/src/mlpack/tests/loss_functions_test.cpp index b5ab0c155a..82e7c76db8 100644 --- a/src/mlpack/tests/loss_functions_test.cpp +++ b/src/mlpack/tests/loss_functions_test.cpp @@ -994,7 +994,7 @@ TEST_CASE("HingeLossTest", "[LossFunctionsTest]") {1, -1, -1}, {1, -1, -1}}; - // Binary labels for target + // Binary labels for target. target_b = {{0, 0, 1}, {0, 1, 1}, {1, 0, 0}, @@ -1019,6 +1019,7 @@ TEST_CASE("HingeLossTest", "[LossFunctionsTest]") REQUIRE(output.n_cols == input.n_cols); // Test for mean reduction. + // Test for the Forward function. loss = module2.Forward(input, target); REQUIRE(loss == Approx(1.21755).epsilon(1e-3)); From d81f60ca931a4652fcba9c395eb0bd5e5ad2d859 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 21 Jan 2021 09:48:15 -0500 Subject: [PATCH 098/253] Add k-means++ initialization. --- src/mlpack/methods/kmeans/CMakeLists.txt | 1 + src/mlpack/methods/kmeans/kmeans_main.cpp | 31 ++++-- .../kmeans_plus_plus_initialization.hpp | 102 ++++++++++++++++++ src/mlpack/tests/kmeans_test.cpp | 66 ++++++++++++ src/mlpack/tests/main.cpp | 4 +- 5 files changed, 194 insertions(+), 10 deletions(-) create mode 100644 src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp diff --git a/src/mlpack/methods/kmeans/CMakeLists.txt b/src/mlpack/methods/kmeans/CMakeLists.txt index 1dbbbba626..6782ed2f66 100644 --- a/src/mlpack/methods/kmeans/CMakeLists.txt +++ b/src/mlpack/methods/kmeans/CMakeLists.txt @@ -14,6 +14,7 @@ set(SOURCES kill_empty_clusters.hpp kmeans.hpp kmeans_impl.hpp + kmeans_plus_plus_initialization.hpp max_variance_new_cluster.hpp max_variance_new_cluster_impl.hpp naive_kmeans.hpp diff --git a/src/mlpack/methods/kmeans/kmeans_main.cpp b/src/mlpack/methods/kmeans/kmeans_main.cpp index 4c7a689aec..1f0833e9da 100644 --- a/src/mlpack/methods/kmeans/kmeans_main.cpp +++ b/src/mlpack/methods/kmeans/kmeans_main.cpp @@ -17,6 +17,7 @@ #include "allow_empty_clusters.hpp" #include "kill_empty_clusters.hpp" #include "refined_start.hpp" +#include "kmeans_plus_plus_initialization.hpp" #include "elkan_kmeans.hpp" #include "hamerly_kmeans.hpp" #include "pelleg_moore_kmeans.hpp" @@ -44,14 +45,17 @@ BINDING_LONG_DESC( " the point furthest from the centroid of the cluster with maximum variance" " is taken to fill that cluster." "\n\n" - "Optionally, the Bradley and Fayyad approach (\"Refining initial points for" - " k-means clustering\", 1998) can be used to select initial points by " - "specifying the " + PRINT_PARAM_STRING("refined_start") + " parameter. " - "This approach works by taking random samplings of the dataset; to specify " - "the number of samplings, the " + PRINT_PARAM_STRING("samplings") + - " parameter is used, and to specify the percentage of the dataset to be " - "used in each sample, the " + PRINT_PARAM_STRING("percentage") + - " parameter is used (it should be a value between 0.0 and 1.0)." + "Optionally, the strategy to choose initial centroids can be specified. " + "The k-means++ algorithm can be used to choose initial centroids with " + "the " + PRINT_PARAM_STRING("kmeans_plus_plus") + " parameter. The " + "Bradley and Fayyad approach (\"Refining initial points for k-means " + "clustering\", 1998) can be used to select initial points by specifying " + "the " + PRINT_PARAM_STRING("refined_start") + " parameter. This approach " + "works by taking random samplings of the dataset; to specify the number of " + "samplings, the " + PRINT_PARAM_STRING("samplings") + " parameter is used, " + "and to specify the percentage of the dataset to be used in each sample, " + "the " + PRINT_PARAM_STRING("percentage") + " parameter is used (it should " + "be a value between 0.0 and 1.0)." "\n\n" "There are several options available for the algorithm used for each Lloyd " "iteration, specified with the " + PRINT_PARAM_STRING("algorithm") + " " @@ -102,6 +106,7 @@ BINDING_EXAMPLE( // See also... BINDING_SEE_ALSO("K-Means tutorial", "@doxygen/kmtutorial.html"); BINDING_SEE_ALSO("@dbscan", "#dbscan"); +BINDING_SEE_ALSO("k-means++", "https://en.wikipedia.org/wiki/K-means%2B%2B"); BINDING_SEE_ALSO("Using the triangle inequality to accelerate k-means (pdf)", "http://www.aaai.org/Papers/ICML/2003/ICML03-022.pdf"); BINDING_SEE_ALSO("Making k-means even faster (pdf)", @@ -147,6 +152,8 @@ PARAM_INT_IN("samplings", "Number of samplings to perform for refined start " "(use when --refined_start is specified).", "S", 100); PARAM_DOUBLE_IN("percentage", "Percentage of dataset to use for each refined " "start sampling (use when --refined_start is specified).", "p", 0.02); +PARAM_FLAG("kmeans_plus_plus", "Use the k-means++ initialization strategy to " + "choose initial points.", "K"); PARAM_STRING_IN("algorithm", "Algorithm to use for the Lloyd iteration " "('naive', 'pelleg-moore', 'elkan', 'hamerly', 'dualtree', or " @@ -176,6 +183,9 @@ static void mlpackMain() else math::RandomSeed((size_t) std::time(NULL)); + util::RequireOnlyOnePassed({ "refined_start", "kmeans_plus_plus" }, true, + "Only one initialization strategy can be specified!"); + // Now, start building the KMeans type that we'll be using. Start with the // initial partition policy. The call to FindEmptyClusterPolicy<> results in // a call to RunKMeans<> and the algorithm is completed. @@ -191,6 +201,11 @@ static void mlpackMain() FindEmptyClusterPolicy(RefinedStart(samplings, percentage)); } + else if (IO::HasParam("kmeans_plus_plus")) + { + FindEmptyClusterPolicy( + KMeansPlusPlusInitialization()); + } else { FindEmptyClusterPolicy(SampleInitialization()); diff --git a/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp b/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp new file mode 100644 index 0000000000..23164ec231 --- /dev/null +++ b/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp @@ -0,0 +1,102 @@ +/** + * @file kmeans_plus_plus_initialization.hpp + * @author Ryan Curtin + * + * This file implements the k-means++ initialization strategy. + */ +#ifndef KMEANS_PLUS_PLUS_INITIALIZATION_HPP +#define KMEANS_PLUS_PLUS_INITIALIZATION_HPP + +#include + +/** + * This class implements the k-means++ initialization, as described in the + * following paper: + * + * @code + * @inproceedings{arthur2007k, + * title={k-means++: The advantages of careful seeding}, + * author={Arthur, David and Vassilvitskii, Sergei}, + * booktitle={Proceedings of the Eighteenth Annual ACM-SIAM Symposium on + * Discrete Algorithms (SODA '07)}, + * pages={1027--1035}, + * year={2007}, + * organization={Society for Industrial and Applied Mathematics} + * } + * @endcode + * + * In accordance with mlpack's InitialPartitionPolicy template type, we only + * need to implement a constructor and a method to compute the initial + * centroids. + */ +class KMeansPlusPlusInitialization +{ + public: + //! Empty constructor, required by the InitialPartitionPolicy type definition. + KMeansPlusPlusInitialization() { } + + /** + * Initialize the centroids matrix by randomly sampling points from the data + * matrix. + * + * @param data Dataset. + * @param clusters Number of clusters. + * @param centroids Matrix to put initial centroids into. + */ + template + inline static void Cluster(const MatType& data, + const size_t clusters, + arma::mat& centroids) + { + centroids.set_size(data.n_rows, clusters); + + // We'll sample our first point fully randomly. + size_t firstPoint = mlpack::math::RandInt(0, data.n_cols); + centroids.col(0) = data.col(firstPoint); + + // Utility variable. + arma::vec distribution(data.n_cols); + + // Now, sample other points... + for (size_t i = 1; i < clusters; ++i) + { + // We must compute the CDF for sampling... this depends on the computation + // of the minimum distance between each point and its closest + // already-chosen centroid. + // + // This computation is ripe for speedup with trees! I am not sure exactly + // how much we would need to approximate, but I think it could be done + // without breaking the O(log k)-competitive guarantee (I think). + for (size_t p = 0; p < data.n_cols; ++p) + { + double minDistance = std::numeric_limits::max(); + for (size_t j = 0; j < i; ++j) + { + const double distance = + mlpack::metric::SquaredEuclideanDistance::Evaluate(data.col(p), + centroids.col(j)); + minDistance = std::min(distance, minDistance); + } + + distribution[p] = minDistance; + } + + // Next normalize the distribution (actually technically we could avoid + // this.) + distribution /= arma::accu(distribution); + + // Turn it into a CDF for convenience... + for (size_t j = 1; j < distribution.n_elem; ++j) + distribution[j] += distribution[j - 1]; + + // Sample a point... + const double sampleValue = mlpack::math::Random(); + double* elem = std::lower_bound(distribution.begin(), distribution.end(), + sampleValue); + size_t position = (size_t) (elem - distribution.begin()) / sizeof(double); + centroids.col(i) = data.col(position); + } + } +}; + +#endif diff --git a/src/mlpack/tests/kmeans_test.cpp b/src/mlpack/tests/kmeans_test.cpp index 5d4bae2abf..ef14467b74 100644 --- a/src/mlpack/tests/kmeans_test.cpp +++ b/src/mlpack/tests/kmeans_test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -486,6 +487,71 @@ TEST_CASE("RefinedStartTest", "[KMeansTest]") REQUIRE(distortion < 14000.0); } +/** + * Test that the k-means++ initialization strategy returns decent initial + * cluster estimates. + */ +TEST_CASE("KMeansPlusPlusTest", "[KMeansTest]") +{ + // Our dataset will be five Gaussians of largely varying numbers of points and + // we expect that the refined starting policy should return good guesses at + // what these Gaussians are. + arma::mat data(3, 3000); + data.randn(); + + // First Gaussian: 10000 points, centered at (0, 0, 0). + // Second Gaussian: 2000 points, centered at (5, 0, -2). + // Third Gaussian: 5000 points, centered at (-2, -2, -2). + // Fourth Gaussian: 1000 points, centered at (-6, 8, 8). + // Fifth Gaussian: 12000 points, centered at (1, 6, 1). + arma::mat centroids(" 0 5 -2 -6 1;" + " 0 0 -2 8 6;" + " 0 -2 -2 8 1"); + + for (size_t i = 1000; i < 1200; ++i) + data.col(i) += centroids.col(1); + for (size_t i = 1200; i < 1700; ++i) + data.col(i) += centroids.col(2); + for (size_t i = 1700; i < 1800; ++i) + data.col(i) += centroids.col(3); + for (size_t i = 1800; i < 3000; ++i) + data.col(i) += centroids.col(4); + + KMeansPlusPlusInitialization k; + arma::mat resultingCentroids; + k.Cluster(data, 5, resultingCentroids); + + // Calculate resulting assignments. + arma::Row assignments(data.n_cols); + for (size_t i = 0; i < data.n_cols; ++i) + { + double bestDist = DBL_MAX; + for (size_t j = 0; j < 5; ++j) + { + const double dist = metric::EuclideanDistance::Evaluate(data.col(i), + resultingCentroids.col(j)); + if (dist < bestDist) + { + bestDist = dist; + assignments[i] = j; + } + } + } + + // Calculate sum of distances from centroid means. + double distortion = 0; + for (size_t i = 0; i < 3000; ++i) + distortion += metric::EuclideanDistance::Evaluate(data.col(i), + resultingCentroids.col(assignments[i])); + + // Using k-means++, the distance for this dataset is usually around + // 10000. Regular k-means is between 10000 and 30000 (I think the 10000 + // figure is a corner case which actually does not give good clusters), and + // random initial starts give distortion around 22000. So we'll require that + // our distortion is less than 12000. + REQUIRE(distortion < 12000.0); +} + #ifdef ARMA_HAS_SPMAT /** * Make sure sparse k-means works okay. diff --git a/src/mlpack/tests/main.cpp b/src/mlpack/tests/main.cpp index 3267ae850d..44ae40d641 100644 --- a/src/mlpack/tests/main.cpp +++ b/src/mlpack/tests/main.cpp @@ -22,8 +22,8 @@ int main(int argc, char** argv) * each run. This is good for ensuring that a test's tolerance is sufficient * across many different runs. */ - // size_t seed = std::time(NULL); - // mlpack::math::RandomSeed(seed); + size_t seed = std::time(NULL); + mlpack::math::RandomSeed(seed); #ifndef TEST_VERBOSE #ifdef DEBUG mlpack::Log::Debug.ignoreInput = true; From 295d24b42e1ea5b3544c321c858040b48c95ce65 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 21 Jan 2021 09:50:32 -0500 Subject: [PATCH 099/253] Update HISTORY. --- HISTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 7529a3ee86..c5b118476e 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -13,6 +13,8 @@ * Add finalizers to Julia binding model types to fix memory handling (#2756). + * Add k-means++ initialization strategy (#2813). + ### mlpack 3.4.2 ###### 2020-10-26 * Added Mean Absolute Percentage Error. From 2ea6d50b6da6b222f9e5190a4d8f4b2af4d7d0e5 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 21 Jan 2021 18:36:56 -0500 Subject: [PATCH 100/253] Apply suggestions from code review Co-authored-by: Marcus Edel --- src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp b/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp index 23164ec231..c4e074e4f7 100644 --- a/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp +++ b/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp @@ -1,5 +1,5 @@ /** - * @file kmeans_plus_plus_initialization.hpp + * @file methods/kmeans/kmeans_plus_plus_initialization.hpp * @author Ryan Curtin * * This file implements the k-means++ initialization strategy. @@ -82,7 +82,7 @@ class KMeansPlusPlusInitialization } // Next normalize the distribution (actually technically we could avoid - // this.) + // this). distribution /= arma::accu(distribution); // Turn it into a CDF for convenience... From 1d90bf817d757406a3141deb4da9abae104abc0e Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 21 Jan 2021 18:38:02 -0500 Subject: [PATCH 101/253] Update header guard macro name. --- src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp b/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp index c4e074e4f7..ae63ee80c5 100644 --- a/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp +++ b/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp @@ -4,8 +4,8 @@ * * This file implements the k-means++ initialization strategy. */ -#ifndef KMEANS_PLUS_PLUS_INITIALIZATION_HPP -#define KMEANS_PLUS_PLUS_INITIALIZATION_HPP +#ifndef MLPACK_METHODS_KMEANS_KMEANS_PLUS_PLUS_INITIALIZATION_HPP +#define MLPACK_METHODS_KMEANS_KMEANS_PLUS_PLUS_INITIALIZATION_HPP #include From 79d2621a838256dafd77ab05645df6a178363d7c Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 21 Jan 2021 18:39:20 -0500 Subject: [PATCH 102/253] Add const. --- .../methods/kmeans/kmeans_plus_plus_initialization.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp b/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp index ae63ee80c5..e43c59fe1a 100644 --- a/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp +++ b/src/mlpack/methods/kmeans/kmeans_plus_plus_initialization.hpp @@ -91,9 +91,10 @@ class KMeansPlusPlusInitialization // Sample a point... const double sampleValue = mlpack::math::Random(); - double* elem = std::lower_bound(distribution.begin(), distribution.end(), - sampleValue); - size_t position = (size_t) (elem - distribution.begin()) / sizeof(double); + const double* elem = std::lower_bound(distribution.begin(), + distribution.end(), sampleValue); + const size_t position = (size_t) + (elem - distribution.begin()) / sizeof(double); centroids.col(i) = data.col(position); } } From 4e39217837bd05934c2dc4a8cacacb0adc538bcd Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 21 Jan 2021 18:53:01 -0500 Subject: [PATCH 103/253] Modify RequireOnlyOnePassed() to allow none to be passed. --- src/mlpack/core/util/param_checks.hpp | 5 ++++- src/mlpack/core/util/param_checks_impl.hpp | 5 +++-- src/mlpack/methods/kmeans/kmeans_main.cpp | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/mlpack/core/util/param_checks.hpp b/src/mlpack/core/util/param_checks.hpp index a9180a4816..c1ac39aeea 100644 --- a/src/mlpack/core/util/param_checks.hpp +++ b/src/mlpack/core/util/param_checks.hpp @@ -43,11 +43,14 @@ namespace util { * @param fatal If true, output goes to Log::Fatal instead of Log::Warn and an * exception is thrown. * @param customErrorMessage Error message to append. + * @param allowNone If true, then no error message will be thrown if none of the + * parameters in the constraints were passed. */ void RequireOnlyOnePassed( const std::vector& constraints, const bool fatal = true, - const std::string& customErrorMessage = ""); + const std::string& customErrorMessage = "", + const bool allowNone = false); /** * Require that at least one of the given parameters in the constraints set was diff --git a/src/mlpack/core/util/param_checks_impl.hpp b/src/mlpack/core/util/param_checks_impl.hpp index be88c8a3e9..8562e1341f 100644 --- a/src/mlpack/core/util/param_checks_impl.hpp +++ b/src/mlpack/core/util/param_checks_impl.hpp @@ -21,7 +21,8 @@ namespace util { inline void RequireOnlyOnePassed( const std::vector& constraints, const bool fatal, - const std::string& errorMessage) + const std::string& errorMessage, + const bool allowNone) { if (BINDING_IGNORE_CHECK(constraints)) return; @@ -57,7 +58,7 @@ inline void RequireOnlyOnePassed( stream << "; " << errorMessage; stream << "!" << std::endl; } - else if (set == 0) + else if (set == 0 && !allowNone) { stream << (fatal ? "Must " : "Should "); diff --git a/src/mlpack/methods/kmeans/kmeans_main.cpp b/src/mlpack/methods/kmeans/kmeans_main.cpp index 1f0833e9da..4707c05b7e 100644 --- a/src/mlpack/methods/kmeans/kmeans_main.cpp +++ b/src/mlpack/methods/kmeans/kmeans_main.cpp @@ -183,8 +183,8 @@ static void mlpackMain() else math::RandomSeed((size_t) std::time(NULL)); - util::RequireOnlyOnePassed({ "refined_start", "kmeans_plus_plus" }, true, - "Only one initialization strategy can be specified!"); + RequireOnlyOnePassed({ "refined_start", "kmeans_plus_plus" }, true, + "Only one initialization strategy can be specified!", true); // Now, start building the KMeans type that we'll be using. Start with the // initial partition policy. The call to FindEmptyClusterPolicy<> results in @@ -286,7 +286,7 @@ void RunKMeans(const InitialPartitionPolicy& ipp) const int maxIterations = IO::GetParam("max_iterations"); // Make sure we have an output file if we're not doing the work in-place. - RequireAtLeastOnePassed({ "in_place", "output", "centroid" }, false, + RequireOnlyOnePassed({ "in_place", "output", "centroid" }, false, "no results will be saved"); arma::mat dataset = IO::GetParam("input"); // Load our dataset. From 5ffb8b4ea41424fcdaf0063f917befd81b681c5d Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 21 Jan 2021 18:53:50 -0500 Subject: [PATCH 104/253] Update src/mlpack/tests/main.cpp Co-authored-by: Marcus Edel --- src/mlpack/tests/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/main.cpp b/src/mlpack/tests/main.cpp index 44ae40d641..3267ae850d 100644 --- a/src/mlpack/tests/main.cpp +++ b/src/mlpack/tests/main.cpp @@ -22,8 +22,8 @@ int main(int argc, char** argv) * each run. This is good for ensuring that a test's tolerance is sufficient * across many different runs. */ - size_t seed = std::time(NULL); - mlpack::math::RandomSeed(seed); + // size_t seed = std::time(NULL); + // mlpack::math::RandomSeed(seed); #ifndef TEST_VERBOSE #ifdef DEBUG mlpack::Log::Debug.ignoreInput = true; From 2f504f5669c570401b8e4efc260813ab7a1bead3 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 21 Jan 2021 18:55:46 -0500 Subject: [PATCH 105/253] Fix style. --- src/mlpack/methods/cf/cf_main.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/cf/cf_main.cpp b/src/mlpack/methods/cf/cf_main.cpp index ce083c8c4a..0c8cd49539 100644 --- a/src/mlpack/methods/cf/cf_main.cpp +++ b/src/mlpack/methods/cf/cf_main.cpp @@ -371,10 +371,15 @@ static void mlpackMain() arma::Mat users = std::move(IO::GetParam>("query")); if (users.n_rows > 1) + { users = users.t(); + } + if (users.n_rows > 1) + { Log::Fatal << "List of query users must be one-dimensional!" - << std::endl; + << std::endl; + } Log::Info << "Generating recommendations for " << users.n_elem << " users." << endl; From 0c77578f47cac2d14a67e70af56bb9260f511036 Mon Sep 17 00:00:00 2001 From: jeffin143 Date: Fri, 22 Jan 2021 21:18:33 +0530 Subject: [PATCH 106/253] Add cereal library to history --- HISTORY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index c8a3c94497..b7b0ad75ee 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -16,6 +16,8 @@ * HMM: add functions to calculate likelihood for data stream with/without pre-calculated emission probability (#2142). + * Replace boost Boost serialization library by Cereal (#2458). + ### mlpack 3.4.2 ###### 2020-10-26 * Added Mean Absolute Percentage Error. From 22e3fb4bff0512e98716ea3b3c6922b22de56a4c Mon Sep 17 00:00:00 2001 From: jeffin sam Date: Sat, 23 Jan 2021 01:40:33 +0530 Subject: [PATCH 107/253] Update HISTORY.md Co-authored-by: Marcus Edel --- HISTORY.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HISTORY.md b/HISTORY.md index b7b0ad75ee..001e6e2762 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -16,7 +16,7 @@ * HMM: add functions to calculate likelihood for data stream with/without pre-calculated emission probability (#2142). - * Replace boost Boost serialization library by Cereal (#2458). + * Replace Boost serialization library by Cereal (#2458). ### mlpack 3.4.2 ###### 2020-10-26 From eba621e9cbc965f4ea209d2d2f500d05c9168842 Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Fri, 22 Jan 2021 22:48:37 +0100 Subject: [PATCH 108/253] Remove libarmadillo-dev from the path, keep the manually installed one Signed-off-by: Omar Shrit --- .ci/linux-steps.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/linux-steps.yaml b/.ci/linux-steps.yaml index 21baace148..eba826ac92 100644 --- a/.ci/linux-steps.yaml +++ b/.ci/linux-steps.yaml @@ -21,7 +21,7 @@ steps: unset BOOST_ROOT echo "##vso[task.setvariable variable=BOOST_ROOT]"$BOOST_ROOT - sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libboost1.70-dev libarmadillo-dev xz-utils + sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libboost1.70-dev xz-utils if [ "$(binding)" == "python" ]; then export PYBIN=$(which python) From 0e8e6f1ba14755e072f68f952625f7dca0a32c15 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Sat, 23 Jan 2021 19:53:47 +0530 Subject: [PATCH 109/253] simplification --- src/mlpack/core/util/io.cpp | 29 ++++++++++++++--------------- src/mlpack/core/util/io.hpp | 3 ++- src/mlpack/core/util/io_impl.hpp | 6 +++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index d36b287a4e..8687a6df12 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -279,27 +279,26 @@ void IO::CheckInputMatrices() std::string paramType = itr->second.cppType; if (paramType == "arma::mat") - IO::CheckInputMatrix>(paramName); + IO::CheckInputMatrix>( + IO::GetParam>(paramName), paramName); else if (paramType == "arma::Mat") - IO::CheckInputMatrix>(paramName); + IO::CheckInputMatrix>( + IO::GetParam>(paramName), paramName); else if (paramType == "arma::colvec") - IO::CheckInputMatrix>(paramName); + IO::CheckInputMatrix>( + IO::GetParam>(paramName), paramName); else if (paramType == "arma::Col") - IO::CheckInputMatrix>(paramName); + IO::CheckInputMatrix>( + IO::GetParam>(paramName), paramName); else if (paramType == "arma::rowvec") - IO::CheckInputMatrix>(paramName); + IO::CheckInputMatrix>( + IO::GetParam>(paramName), paramName); else if (paramType == "arma::Row") - IO::CheckInputMatrix>(paramName); + IO::CheckInputMatrix>( + IO::GetParam>(paramName), paramName); else if (paramType == "std::tuple") - { - std::string errMsg1 = "The input " + paramName + " has NaN values."; - std::string errMsg2 = "The input " + paramName + " has inf values."; - - if (std::get<1>(GetParam(paramName)).has_nan()) - Log::Fatal << errMsg1 << std::endl; - if (std::get<1>(GetParam(paramName)).has_inf()) - Log::Fatal << errMsg2 << std::endl; - } + IO::CheckInputMatrix>( + std::get<1>(IO::GetParam(paramName)), paramName); } } diff --git a/src/mlpack/core/util/io.hpp b/src/mlpack/core/util/io.hpp index 5189695abe..aa9d71c16f 100644 --- a/src/mlpack/core/util/io.hpp +++ b/src/mlpack/core/util/io.hpp @@ -222,10 +222,11 @@ class IO /** * Utility function for CheckInputMatrices(). * + * @param matrix Matrix to check. * @param identifier Name of the parameter in question. */ template - static void CheckInputMatrix(const std::string& identifier); + static void CheckInputMatrix(const T& matrix, const std::string& identifier); /** * Given two (matrix) parameters, ensure that the first is an in-place copy of diff --git a/src/mlpack/core/util/io_impl.hpp b/src/mlpack/core/util/io_impl.hpp index f54aaa4eab..e7407efd7f 100644 --- a/src/mlpack/core/util/io_impl.hpp +++ b/src/mlpack/core/util/io_impl.hpp @@ -146,14 +146,14 @@ T& IO::GetRawParam(const std::string& identifier) } template -void IO::CheckInputMatrix(const std::string& identifier) +void IO::CheckInputMatrix(const T& matrix, const std::string& identifier) { std::string errMsg1 = "The input " + identifier + " has NaN values."; std::string errMsg2 = "The input " + identifier + " has inf values."; - if (GetParam(identifier).has_nan()) + if (matrix.has_nan()) Log::Fatal << errMsg1 << std::endl; - if (GetParam(identifier).has_inf()) + if (matrix.has_inf()) Log::Fatal << errMsg2 << std::endl; } From 654e6503d892e9f4934266a5f977297c56a44b10 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Sat, 23 Jan 2021 19:57:18 +0530 Subject: [PATCH 110/253] updated HISTORY.md --- HISTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 001e6e2762..0c81a8265a 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,8 @@ ### mlpack ?.?.? ###### ????-??-?? + * Add "check_input_matrices" option to python bindings that checks + for NaN and inf values in all the input matrices (#2787). + * Add Adjusted R squared functionality to R2Score::Evaluate (#2624). * Disabled all the bindings by default in CMake (#2782). From 33af71dbce383b4809509429d40603aa4e69a1ab Mon Sep 17 00:00:00 2001 From: Nippun Sharma <53967069+NippunSharma@users.noreply.github.com> Date: Sun, 24 Jan 2021 00:35:21 +0530 Subject: [PATCH 111/253] Update src/mlpack/core/util/io.cpp Co-authored-by: Ryan Curtin --- src/mlpack/core/util/io.cpp | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index 8687a6df12..dba1bbecd8 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -279,26 +279,36 @@ void IO::CheckInputMatrices() std::string paramType = itr->second.cppType; if (paramType == "arma::mat") - IO::CheckInputMatrix>( - IO::GetParam>(paramName), paramName); + { + IO::CheckInputMatrix(IO::GetParam(paramName), paramName); + } else if (paramType == "arma::Mat") - IO::CheckInputMatrix>( + { + IO::CheckInputMatrix( IO::GetParam>(paramName), paramName); + } else if (paramType == "arma::colvec") - IO::CheckInputMatrix>( - IO::GetParam>(paramName), paramName); + { + IO::CheckInputMatrix(IO::GetParam(paramName), paramName); + } else if (paramType == "arma::Col") - IO::CheckInputMatrix>( + { + IO::CheckInputMatrix( IO::GetParam>(paramName), paramName); + } else if (paramType == "arma::rowvec") - IO::CheckInputMatrix>( - IO::GetParam>(paramName), paramName); + { + IO::CheckInputMatrix(IO::GetParam(paramName), paramName); + } else if (paramType == "arma::Row") - IO::CheckInputMatrix>( + { + IO::CheckInputMatrix( IO::GetParam>(paramName), paramName); + } else if (paramType == "std::tuple") - IO::CheckInputMatrix>( + { + IO::CheckInputMatrix( std::get<1>(IO::GetParam(paramName)), paramName); + } } } - From 723ecf82ebf0a6e47d3ab50e9804bc1a2f8f32f9 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Sun, 24 Jan 2021 00:36:50 +0530 Subject: [PATCH 112/253] added more tests --- .../python/tests/test_python_binding.py | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/src/mlpack/bindings/python/tests/test_python_binding.py b/src/mlpack/bindings/python/tests/test_python_binding.py index f6beffa483..207e8711d3 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding.py +++ b/src/mlpack/bindings/python/tests/test_python_binding.py @@ -1354,6 +1354,60 @@ class TestPythonBinding(unittest.TestCase): matrix_in=x, check_input_matrices=True)) + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + umatrix_in=x, + check_input_matrices=True)) + + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + row_in=x, + check_input_matrices=True)) + + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + urow_in=x, + check_input_matrices=True)) + + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + col_in=x, + check_input_matrices=True)) + + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + ucol_in=x, + check_input_matrices=True)) + + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + matrix_and_info_in=x, + check_input_matrices=True)) + def testCheckInputMatricesInf(self): """ Checks that an exception is thrown if the input matrix contains @@ -1372,5 +1426,59 @@ class TestPythonBinding(unittest.TestCase): matrix_in=x, check_input_matrices=True)) + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + umatrix_in=x, + check_input_matrices=True)) + + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + row_in=x, + check_input_matrices=True)) + + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + urow_in=x, + check_input_matrices=True)) + + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + col_in=x, + check_input_matrices=True)) + + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + ucol_in=x, + check_input_matrices=True)) + + self.assertRaises(RuntimeError, + lambda : test_python_binding(string_in="hello", + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + matrix_and_info_in=x, + check_input_matrices=True)) + if __name__ == '__main__': unittest.main() From 8cc834fe4357a0a5289f739c9fcc8c8ee277c02d Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Sat, 23 Jan 2021 20:20:03 +0100 Subject: [PATCH 113/253] Remove lapack, it is not need, openblas should be enough Signed-off-by: Omar Shrit --- .ci/linux-steps.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/linux-steps.yaml b/.ci/linux-steps.yaml index eba826ac92..f695c14fe1 100644 --- a/.ci/linux-steps.yaml +++ b/.ci/linux-steps.yaml @@ -21,7 +21,7 @@ steps: unset BOOST_ROOT echo "##vso[task.setvariable variable=BOOST_ROOT]"$BOOST_ROOT - sudo apt-get install -y --allow-unauthenticated libopenblas-dev liblapack-dev g++ libboost1.70-dev xz-utils + sudo apt-get install -y --allow-unauthenticated libopenblas-dev g++ libboost1.70-dev xz-utils if [ "$(binding)" == "python" ]; then export PYBIN=$(which python) From 141b92d07cef34ace3b3e2714125195755cb9183 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Sun, 24 Jan 2021 00:57:00 +0530 Subject: [PATCH 114/253] fixes --- .../python/tests/test_python_binding.py | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/mlpack/bindings/python/tests/test_python_binding.py b/src/mlpack/bindings/python/tests/test_python_binding.py index 207e8711d3..0fcdb70353 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding.py +++ b/src/mlpack/bindings/python/tests/test_python_binding.py @@ -1363,13 +1363,16 @@ class TestPythonBinding(unittest.TestCase): umatrix_in=x, check_input_matrices=True)) + x_row = np.random.rand(1, 100) + a = np.random.randint(low=0, high=100) + x_row[0][a] = np.nan self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - row_in=x, + row_in=x_row, check_input_matrices=True)) self.assertRaises(RuntimeError, @@ -1378,16 +1381,19 @@ class TestPythonBinding(unittest.TestCase): double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - urow_in=x, + urow_in=x_row, check_input_matrices=True)) + x_col = np.random.rand(100, 1) + a = np.random.randint(low=0, high=100) + x_col[a][0] = np.nan self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - col_in=x, + col_in=x_col, check_input_matrices=True)) self.assertRaises(RuntimeError, @@ -1396,7 +1402,7 @@ class TestPythonBinding(unittest.TestCase): double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - ucol_in=x, + ucol_in=x_col, check_input_matrices=True)) self.assertRaises(RuntimeError, @@ -1435,13 +1441,16 @@ class TestPythonBinding(unittest.TestCase): umatrix_in=x, check_input_matrices=True)) + x_row = np.random.rand(1, 100) + a = np.random.randint(low=0, high=100) + x_row[0][a] = np.inf self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - row_in=x, + row_in=x_row, check_input_matrices=True)) self.assertRaises(RuntimeError, @@ -1450,16 +1459,19 @@ class TestPythonBinding(unittest.TestCase): double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - urow_in=x, + urow_in=x_row, check_input_matrices=True)) + x_col = np.random.rand(100, 1) + a = np.random.randint(low=0, high=100) + x_col[a][0] = np.inf self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - col_in=x, + col_in=x_col, check_input_matrices=True)) self.assertRaises(RuntimeError, @@ -1468,7 +1480,7 @@ class TestPythonBinding(unittest.TestCase): double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - ucol_in=x, + ucol_in=x_col, check_input_matrices=True)) self.assertRaises(RuntimeError, From 0d31176db8dfe643578d66645d759e29abcd2876 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Sun, 24 Jan 2021 21:14:41 +0530 Subject: [PATCH 115/253] added check for unsigned matrix --- src/mlpack/core/util/io.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index dba1bbecd8..8c36aa442a 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -287,6 +287,11 @@ void IO::CheckInputMatrices() IO::CheckInputMatrix( IO::GetParam>(paramName), paramName); } + else if (paramType == "arma::Mat") + { + IO::CheckInputMatrix( + IO::GetParam>(paramName), paramName); + } else if (paramType == "arma::colvec") { IO::CheckInputMatrix(IO::GetParam(paramName), paramName); From 954f3c490e8d0617f09a74dba55233bd0804d289 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Mon, 25 Jan 2021 00:51:57 +0530 Subject: [PATCH 116/253] fixing parameter types while checking --- .../python/tests/test_python_binding.py | 48 +++++++++---------- src/mlpack/core/util/io.cpp | 10 +--- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/src/mlpack/bindings/python/tests/test_python_binding.py b/src/mlpack/bindings/python/tests/test_python_binding.py index 0fcdb70353..c4af5fa18b 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding.py +++ b/src/mlpack/bindings/python/tests/test_python_binding.py @@ -1341,7 +1341,7 @@ class TestPythonBinding(unittest.TestCase): Checks that an exception is thrown if the input matrix contains NaN values. """ - x = np.random.rand(100, 5) + x = np.random.randint(low=0, high=500, size=[100, 5]).astype(float) a = np.random.randint(low=0, high=100) b = np.random.randint(low=0, high=5) x[a][b] = np.nan @@ -1356,16 +1356,16 @@ class TestPythonBinding(unittest.TestCase): self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", - int_in=12, - double_in=4.0, - mat_req_in=[[1.0]], - col_req_in=[1.0], - umatrix_in=x, - check_input_matrices=True)) + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + umatrix_in=x, + check_input_matrices=True)) - x_row = np.random.rand(1, 100) + x_row = np.random.randint(0, high=500, size=100).astype(float) a = np.random.randint(low=0, high=100) - x_row[0][a] = np.nan + x_row[a] = np.nan self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, @@ -1384,9 +1384,9 @@ class TestPythonBinding(unittest.TestCase): urow_in=x_row, check_input_matrices=True)) - x_col = np.random.rand(100, 1) + x_col = np.random.randint(0, high=500, size=100).astype(float) a = np.random.randint(low=0, high=100) - x_col[a][0] = np.nan + x_col[a] = np.nan self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, @@ -1395,7 +1395,7 @@ class TestPythonBinding(unittest.TestCase): col_req_in=[1.0], col_in=x_col, check_input_matrices=True)) - + self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, @@ -1419,7 +1419,7 @@ class TestPythonBinding(unittest.TestCase): Checks that an exception is thrown if the input matrix contains inf values. """ - x = np.random.rand(100, 5) + x = np.random.randint(low=0, high=500, size=[100, 5]).astype(float) a = np.random.randint(low=0, high=100) b = np.random.randint(low=0, high=5) x[a][b] = np.inf @@ -1434,16 +1434,16 @@ class TestPythonBinding(unittest.TestCase): self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", - int_in=12, - double_in=4.0, - mat_req_in=[[1.0]], - col_req_in=[1.0], - umatrix_in=x, - check_input_matrices=True)) + int_in=12, + double_in=4.0, + mat_req_in=[[1.0]], + col_req_in=[1.0], + umatrix_in=x, + check_input_matrices=True)) - x_row = np.random.rand(1, 100) + x_row = np.random.randint(0, high=500, size=100).astype(float) a = np.random.randint(low=0, high=100) - x_row[0][a] = np.inf + x_row[a] = np.inf self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, @@ -1462,9 +1462,9 @@ class TestPythonBinding(unittest.TestCase): urow_in=x_row, check_input_matrices=True)) - x_col = np.random.rand(100, 1) + x_col = np.random.randint(0, high=500, size=100).astype(float) a = np.random.randint(low=0, high=100) - x_col[a][0] = np.inf + x_col[a] = np.inf self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, @@ -1473,7 +1473,7 @@ class TestPythonBinding(unittest.TestCase): col_req_in=[1.0], col_in=x_col, check_input_matrices=True)) - + self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index 8c36aa442a..e13903d6cf 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -277,7 +277,6 @@ void IO::CheckInputMatrices() { std::string paramName = itr->first; std::string paramType = itr->second.cppType; - if (paramType == "arma::mat") { IO::CheckInputMatrix(IO::GetParam(paramName), paramName); @@ -287,14 +286,9 @@ void IO::CheckInputMatrices() IO::CheckInputMatrix( IO::GetParam>(paramName), paramName); } - else if (paramType == "arma::Mat") + else if (paramType == "arma::vec") { - IO::CheckInputMatrix( - IO::GetParam>(paramName), paramName); - } - else if (paramType == "arma::colvec") - { - IO::CheckInputMatrix(IO::GetParam(paramName), paramName); + IO::CheckInputMatrix(IO::GetParam(paramName), paramName); } else if (paramType == "arma::Col") { From 3890be60f15be006771a8192d1151ec4642adf11 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sun, 24 Jan 2021 17:21:07 -0500 Subject: [PATCH 117/253] Update tolerance. --- src/mlpack/tests/kmeans_test.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/kmeans_test.cpp b/src/mlpack/tests/kmeans_test.cpp index ef14467b74..c20014c046 100644 --- a/src/mlpack/tests/kmeans_test.cpp +++ b/src/mlpack/tests/kmeans_test.cpp @@ -548,8 +548,9 @@ TEST_CASE("KMeansPlusPlusTest", "[KMeansTest]") // 10000. Regular k-means is between 10000 and 30000 (I think the 10000 // figure is a corner case which actually does not give good clusters), and // random initial starts give distortion around 22000. So we'll require that - // our distortion is less than 12000. - REQUIRE(distortion < 12000.0); + // our distortion is less than 14500. (It seems like there is a lot of noise + // in the result.) + REQUIRE(distortion < 14500.0); } #ifdef ARMA_HAS_SPMAT From f5b32bc890c38f38f1e763907c3c9401f5b18fec Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Mon, 25 Jan 2021 19:59:51 +0530 Subject: [PATCH 118/253] removing size_t tests --- .../python/tests/test_python_binding.py | 80 +++---------------- src/mlpack/core/util/io.cpp | 2 +- 2 files changed, 11 insertions(+), 71 deletions(-) diff --git a/src/mlpack/bindings/python/tests/test_python_binding.py b/src/mlpack/bindings/python/tests/test_python_binding.py index c4af5fa18b..dd67aed974 100644 --- a/src/mlpack/bindings/python/tests/test_python_binding.py +++ b/src/mlpack/bindings/python/tests/test_python_binding.py @@ -1341,7 +1341,7 @@ class TestPythonBinding(unittest.TestCase): Checks that an exception is thrown if the input matrix contains NaN values. """ - x = np.random.randint(low=0, high=500, size=[100, 5]).astype(float) + x = np.random.rand(100, 5) a = np.random.randint(low=0, high=100) b = np.random.randint(low=0, high=5) x[a][b] = np.nan @@ -1354,25 +1354,16 @@ class TestPythonBinding(unittest.TestCase): matrix_in=x, check_input_matrices=True)) - self.assertRaises(RuntimeError, - lambda : test_python_binding(string_in="hello", - int_in=12, - double_in=4.0, - mat_req_in=[[1.0]], - col_req_in=[1.0], - umatrix_in=x, - check_input_matrices=True)) - - x_row = np.random.randint(0, high=500, size=100).astype(float) + x_vec = np.random.rand(100) a = np.random.randint(low=0, high=100) - x_row[a] = np.nan + x_vec[a] = np.nan self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - row_in=x_row, + row_in=x_vec, check_input_matrices=True)) self.assertRaises(RuntimeError, @@ -1381,28 +1372,7 @@ class TestPythonBinding(unittest.TestCase): double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - urow_in=x_row, - check_input_matrices=True)) - - x_col = np.random.randint(0, high=500, size=100).astype(float) - a = np.random.randint(low=0, high=100) - x_col[a] = np.nan - self.assertRaises(RuntimeError, - lambda : test_python_binding(string_in="hello", - int_in=12, - double_in=4.0, - mat_req_in=[[1.0]], - col_req_in=[1.0], - col_in=x_col, - check_input_matrices=True)) - - self.assertRaises(RuntimeError, - lambda : test_python_binding(string_in="hello", - int_in=12, - double_in=4.0, - mat_req_in=[[1.0]], - col_req_in=[1.0], - ucol_in=x_col, + col_in=x_vec, check_input_matrices=True)) self.assertRaises(RuntimeError, @@ -1419,7 +1389,7 @@ class TestPythonBinding(unittest.TestCase): Checks that an exception is thrown if the input matrix contains inf values. """ - x = np.random.randint(low=0, high=500, size=[100, 5]).astype(float) + x = np.random.rand(100, 5) a = np.random.randint(low=0, high=100) b = np.random.randint(low=0, high=5) x[a][b] = np.inf @@ -1432,25 +1402,16 @@ class TestPythonBinding(unittest.TestCase): matrix_in=x, check_input_matrices=True)) - self.assertRaises(RuntimeError, - lambda : test_python_binding(string_in="hello", - int_in=12, - double_in=4.0, - mat_req_in=[[1.0]], - col_req_in=[1.0], - umatrix_in=x, - check_input_matrices=True)) - - x_row = np.random.randint(0, high=500, size=100).astype(float) + x_vec = np.random.rand(100) a = np.random.randint(low=0, high=100) - x_row[a] = np.inf + x_vec[a] = np.inf self.assertRaises(RuntimeError, lambda : test_python_binding(string_in="hello", int_in=12, double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - row_in=x_row, + row_in=x_vec, check_input_matrices=True)) self.assertRaises(RuntimeError, @@ -1459,28 +1420,7 @@ class TestPythonBinding(unittest.TestCase): double_in=4.0, mat_req_in=[[1.0]], col_req_in=[1.0], - urow_in=x_row, - check_input_matrices=True)) - - x_col = np.random.randint(0, high=500, size=100).astype(float) - a = np.random.randint(low=0, high=100) - x_col[a] = np.inf - self.assertRaises(RuntimeError, - lambda : test_python_binding(string_in="hello", - int_in=12, - double_in=4.0, - mat_req_in=[[1.0]], - col_req_in=[1.0], - col_in=x_col, - check_input_matrices=True)) - - self.assertRaises(RuntimeError, - lambda : test_python_binding(string_in="hello", - int_in=12, - double_in=4.0, - mat_req_in=[[1.0]], - col_req_in=[1.0], - ucol_in=x_col, + col_in=x_vec, check_input_matrices=True)) self.assertRaises(RuntimeError, diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index e13903d6cf..c3c3182ac3 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -304,7 +304,7 @@ void IO::CheckInputMatrices() IO::CheckInputMatrix( IO::GetParam>(paramName), paramName); } - else if (paramType == "std::tuple") + else if (paramType == "TUPLE_TYPE") { IO::CheckInputMatrix( std::get<1>(IO::GetParam(paramName)), paramName); From 7ec4058f35e6af50db55123a0c16899763b574f4 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Tue, 26 Jan 2021 19:08:07 +0530 Subject: [PATCH 119/253] removed size_t conditions from CheckInputMatrices() --- src/mlpack/core/util/io.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index c3c3182ac3..2c9efefb3a 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -281,29 +281,14 @@ void IO::CheckInputMatrices() { IO::CheckInputMatrix(IO::GetParam(paramName), paramName); } - else if (paramType == "arma::Mat") - { - IO::CheckInputMatrix( - IO::GetParam>(paramName), paramName); - } else if (paramType == "arma::vec") { IO::CheckInputMatrix(IO::GetParam(paramName), paramName); } - else if (paramType == "arma::Col") - { - IO::CheckInputMatrix( - IO::GetParam>(paramName), paramName); - } else if (paramType == "arma::rowvec") { IO::CheckInputMatrix(IO::GetParam(paramName), paramName); } - else if (paramType == "arma::Row") - { - IO::CheckInputMatrix( - IO::GetParam>(paramName), paramName); - } else if (paramType == "TUPLE_TYPE") { IO::CheckInputMatrix( From 16ff91b60b201bde0c18aff0a4aa35e839eba613 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Tue, 26 Jan 2021 21:58:03 +0530 Subject: [PATCH 120/253] made definition of TUPLE_TYPE inline --- src/mlpack/core/util/param.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/core/util/param.hpp b/src/mlpack/core/util/param.hpp index 208ca64b2f..c820df4b65 100644 --- a/src/mlpack/core/util/param.hpp +++ b/src/mlpack/core/util/param.hpp @@ -1013,9 +1013,9 @@ using DatasetInfo = DatasetMapper; * collisions are still possible, and they produce bizarre error messages. See * https://github.com/mlpack/mlpack/issues/100 for more information. */ -#define TUPLE_TYPE std::tuple #define PARAM_MATRIX_AND_INFO_IN(ID, DESC, ALIAS) \ - PARAM_IN(TUPLE_TYPE, ID, DESC, ALIAS, TUPLE_TYPE(), false) + PARAM_IN(std::tuple, ID, DESC, \ + ALIAS, std::tuple(), false) /** * Define an input model. From the command line, the user can specify the file From 458b302c39ffbf11e293ea115f8eeca8eec9bdc5 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Wed, 27 Jan 2021 00:31:58 +0530 Subject: [PATCH 121/253] removed TUPLE_TYPE --- src/mlpack/core/util/io.cpp | 2 +- src/mlpack/core/util/param.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index 2c9efefb3a..9dd571e369 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -289,7 +289,7 @@ void IO::CheckInputMatrices() { IO::CheckInputMatrix(IO::GetParam(paramName), paramName); } - else if (paramType == "TUPLE_TYPE") + else if (paramType == "std::tuple") { IO::CheckInputMatrix( std::get<1>(IO::GetParam(paramName)), paramName); diff --git a/src/mlpack/core/util/param.hpp b/src/mlpack/core/util/param.hpp index c820df4b65..73f462e464 100644 --- a/src/mlpack/core/util/param.hpp +++ b/src/mlpack/core/util/param.hpp @@ -1014,8 +1014,8 @@ using DatasetInfo = DatasetMapper; * https://github.com/mlpack/mlpack/issues/100 for more information. */ #define PARAM_MATRIX_AND_INFO_IN(ID, DESC, ALIAS) \ - PARAM_IN(std::tuple, ID, DESC, \ - ALIAS, std::tuple(), false) + PARAM_IN(std::tuple, ID, DESC, ALIAS, \ + std::tuple(), false) /** * Define an input model. From the command line, the user can specify the file From ab3110e08965b437e62d44fcb8162074907a3dea Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Wed, 27 Jan 2021 00:33:23 +0530 Subject: [PATCH 122/253] minor change --- src/mlpack/core/util/io.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index 9dd571e369..b7ca51987e 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -289,7 +289,7 @@ void IO::CheckInputMatrices() { IO::CheckInputMatrix(IO::GetParam(paramName), paramName); } - else if (paramType == "std::tuple") + else if (paramType == "std::tuple") { IO::CheckInputMatrix( std::get<1>(IO::GetParam(paramName)), paramName); From 28f369cb14c0b81d64f78d0f382df1034356926a Mon Sep 17 00:00:00 2001 From: Alex Nguyen <60036798+rxng8@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:32:29 -0500 Subject: [PATCH 123/253] Update src/mlpack/core/tree/hrectbound.hpp Co-authored-by: Marcus Edel --- src/mlpack/core/tree/hrectbound.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/core/tree/hrectbound.hpp b/src/mlpack/core/tree/hrectbound.hpp index 31186f621d..6b8ef6c69a 100644 --- a/src/mlpack/core/tree/hrectbound.hpp +++ b/src/mlpack/core/tree/hrectbound.hpp @@ -80,7 +80,7 @@ class HRectBound //! Move constructor: take possession of another bound's information. HRectBound(HRectBound&& other); - //! Move assignment operator + //! Move assignment operator. HRectBound& operator=(HRectBound&& other); //! Destructor: clean up memory. From e2adf5ec7c08a7495de2d855736db49164801c37 Mon Sep 17 00:00:00 2001 From: Alex Nguyen <60036798+rxng8@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:32:37 -0500 Subject: [PATCH 124/253] Update src/mlpack/methods/amf/termination_policies/incomplete_incremental_termination.hpp Co-authored-by: Marcus Edel --- .../termination_policies/incomplete_incremental_termination.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/amf/termination_policies/incomplete_incremental_termination.hpp b/src/mlpack/methods/amf/termination_policies/incomplete_incremental_termination.hpp index d01fdfd4c5..5646b0d205 100644 --- a/src/mlpack/methods/amf/termination_policies/incomplete_incremental_termination.hpp +++ b/src/mlpack/methods/amf/termination_policies/incomplete_incremental_termination.hpp @@ -36,7 +36,7 @@ class IncompleteIncrementalTermination IncompleteIncrementalTermination( TerminationPolicy tPolicy = TerminationPolicy()) : tPolicy(tPolicy), incrementalIndex(0), iteration(0) - { /** Nothing to do here. */ } + { /* Nothing to do here. */ } /** * Initializes the termination policy before stating the factorization. From dd8f73d246ea4e4745fef1f2510ec436cc8bbb94 Mon Sep 17 00:00:00 2001 From: Alex Nguyen <60036798+rxng8@users.noreply.github.com> Date: Tue, 26 Jan 2021 23:32:46 -0500 Subject: [PATCH 125/253] Update src/mlpack/methods/amf/termination_policies/complete_incremental_termination.hpp Co-authored-by: Marcus Edel --- .../termination_policies/complete_incremental_termination.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mlpack/methods/amf/termination_policies/complete_incremental_termination.hpp b/src/mlpack/methods/amf/termination_policies/complete_incremental_termination.hpp index bdd02d7fec..78eb24108e 100644 --- a/src/mlpack/methods/amf/termination_policies/complete_incremental_termination.hpp +++ b/src/mlpack/methods/amf/termination_policies/complete_incremental_termination.hpp @@ -37,7 +37,7 @@ class CompleteIncrementalTermination CompleteIncrementalTermination( TerminationPolicy tPolicy = TerminationPolicy()) : tPolicy(tPolicy), incrementalIndex(0), iteration(0) - { /** Nothing to do here. */ } + { /* Nothing to do here. */ } /** * Initializes the termination policy before stating the factorization. @@ -120,4 +120,3 @@ class CompleteIncrementalTermination } // namespace mlpack #endif // MLPACK_METHODS_AMF_COMPLETE_INCREMENTAL_TERMINATION_HPP - From 0914fe94394eaefba557a304b37c8a25283ee66f Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Wed, 27 Jan 2021 16:01:41 +0530 Subject: [PATCH 126/253] added PARAM_IN_WITH_NAME --- src/mlpack/core/util/param.hpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/mlpack/core/util/param.hpp b/src/mlpack/core/util/param.hpp index 73f462e464..e2b58d1dcd 100644 --- a/src/mlpack/core/util/param.hpp +++ b/src/mlpack/core/util/param.hpp @@ -1013,9 +1013,11 @@ using DatasetInfo = DatasetMapper; * collisions are still possible, and they produce bizarre error messages. See * https://github.com/mlpack/mlpack/issues/100 for more information. */ +#define TUPLE_TYPE std::tuple #define PARAM_MATRIX_AND_INFO_IN(ID, DESC, ALIAS) \ - PARAM_IN(std::tuple, ID, DESC, ALIAS, \ - std::tuple(), false) + PARAM_IN_WITH_NAME(TUPLE_TYPE, ID, DESC, ALIAS, \ + "std::tuple", TUPLE_TYPE(), \ + false) /** * Define an input model. From the command line, the user can specify the file @@ -1228,6 +1230,11 @@ using DatasetInfo = DatasetMapper; JOIN(io_option_dummy_object_in_, __COUNTER__) \ (DEF, ID, DESC, ALIAS, #T, REQ, true, false, testName); + #define PARAM_IN_WITH_NAME(T, ID, DESC, ALIAS, NAME, DEF, REQ) \ + static mlpack::util::Option \ + JOIN(io_option_dummy_object_in_, __COUNTER__) \ + (DEF, ID, DESC, ALIAS, NAME, REQ, true, false, testName); + #define PARAM_OUT(T, ID, DESC, ALIAS, DEF, REQ) \ static mlpack::util::Option \ JOIN(io_option_dummy_object_out_, __COUNTER__) \ @@ -1285,6 +1292,11 @@ using DatasetInfo = DatasetMapper; JOIN(JOIN(io_option_dummy_object_in_, __LINE__), opt) \ (DEF, ID, DESC, ALIAS, #T, REQ, true, false, testName); + #define PARAM_IN_WITH_NAME(T, ID, DESC, ALIAS, NAME, DEF, REQ) \ + static mlpack::util::Option \ + JOIN(JOIN(io_option_dummy_object_in_, __LINE__), opt) \ + (DEF, ID, DESC, ALIAS, NAME, REQ, true, false, testName); + #define PARAM_OUT(T, ID, DESC, ALIAS, DEF, REQ) \ static mlpack::util::Option \ JOIN(JOIN(io_option_dummy_object_out_, __LINE__), opt) \ From 46281ee3ef45a6bd25b6cf170a0a3becba256ef1 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Wed, 27 Jan 2021 19:20:44 -0500 Subject: [PATCH 127/253] Update HISTORY and ANN tutorial. --- HISTORY.md | 5 ++++- doc/tutorials/ann/ann.txt | 13 +++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index ffc90ca02a..6d1cd06bc4 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -12,7 +12,7 @@ * Add Triplet Margin Loss function (#2762). * Add finalizers to Julia binding model types to fix memory handling (#2756). - + * HMM: add functions to calculate likelihood for data stream with/without pre-calculated emission probability (#2142). @@ -23,6 +23,9 @@ * Add k-means++ initialization strategy (#2813). + * `NegativeLogLikelihood<>` now expects classes in the range `0` to + `numClasses - 1` (#2534). + ### mlpack 3.4.2 ###### 2020-10-26 * Added Mean Absolute Percentage Error. diff --git a/doc/tutorials/ann/ann.txt b/doc/tutorials/ann/ann.txt index 7cdb9d1f57..43678fb84e 100644 --- a/doc/tutorials/ann/ann.txt +++ b/doc/tutorials/ann/ann.txt @@ -210,8 +210,9 @@ int main() data::Load("thyroid_test.csv", testData, true); // Split the labels from the training set and testing set respectively. - arma::mat trainLabels = trainData.row(trainData.n_rows - 1); - arma::mat testLabels = testData.row(testData.n_rows - 1); + // Decrement the labels by 1, so they are in the range 0 to (numClasses - 1). + arma::mat trainLabels = trainData.row(trainData.n_rows - 1) - 1; + arma::mat testLabels = testData.row(testData.n_rows - 1) - 1; trainData.shed_row(trainData.n_rows - 1); testData.shed_row(testData.n_rows - 1); @@ -246,9 +247,8 @@ int main() // Find index of max prediction for each data point and store in "prediction" for (size_t i = 0; i < predictionTemp.n_cols; ++i) { - // we add 1 to the max index, so that it matches the actual test labels. prediction(i) = arma::as_scalar(arma::find( - arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1; + arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)); } /* @@ -311,7 +311,7 @@ void RNNModel() for (size_t i = 0; i < labelsTemp.n_cols; ++i) { const int value = arma::as_scalar(arma::find( - arma::max(labelsTemp.col(i)) == labelsTemp.col(i), 1)) + 1; + arma::max(labelsTemp.col(i)) == labelsTemp.col(i), 1)); labels.col(i).fill(value); } @@ -589,8 +589,9 @@ arma::mat trainData = dataset.submat(0, 0, dataset.n_rows - 4, dataset.n_cols - 1); // Split the data from the training set. +// Subtract 1 so the labels are the range from 0 to (numClasses - 1). arma::mat trainLabels = dataset.submat(dataset.n_rows - 3, 0, - dataset.n_rows - 1, dataset.n_cols - 1); + dataset.n_rows - 1, dataset.n_cols - 1) - 1; // Initialize the network. FFN<> model; From 5b76b2f5e752bb3f298de89568eaa9d20a0e56de Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Thu, 28 Jan 2021 13:02:19 +0530 Subject: [PATCH 128/253] changed PARAM_IN_WITH_NAME to PARAM_COMPLETE and editted other macros --- src/mlpack/core/util/param.hpp | 136 +++++++++------------------------ 1 file changed, 37 insertions(+), 99 deletions(-) diff --git a/src/mlpack/core/util/param.hpp b/src/mlpack/core/util/param.hpp index e2b58d1dcd..8652db4fbe 100644 --- a/src/mlpack/core/util/param.hpp +++ b/src/mlpack/core/util/param.hpp @@ -1015,9 +1015,9 @@ using DatasetInfo = DatasetMapper; */ #define TUPLE_TYPE std::tuple #define PARAM_MATRIX_AND_INFO_IN(ID, DESC, ALIAS) \ - PARAM_IN_WITH_NAME(TUPLE_TYPE, ID, DESC, ALIAS, \ - "std::tuple", TUPLE_TYPE(), \ - false) + PARAM_COMPLETE(TUPLE_TYPE, ID, DESC, ALIAS, \ + "std::tuple", false, true, true, \ + TUPLE_TYPE()) /** * Define an input model. From the command line, the user can specify the file @@ -1208,6 +1208,36 @@ using DatasetInfo = DatasetMapper; #define PARAM_VECTOR_IN_REQ(T, ID, DESC, ALIAS) \ PARAM_IN(std::vector, ID, DESC, ALIAS, std::vector(), true); +#define PARAM_IN(T, ID, DESC, ALIAS, DEF, REQ) \ + PARAM_COMPLETE(T, ID, DESC, ALIAS, #T, REQ, true, false, DEF); + +#define PARAM_OUT(T, ID, DESC, ALIAS, DEF, REQ) \ + PARAM_COMPLETE(T, ID, DESC, ALIAS, #T, REQ, false, false, DEF); + +#define PARAM_MATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \ + PARAM_COMPLETE(arma::mat, ID, DESC, ALIAS, "arma::mat", REQ, IN, \ + TRANS, arma::mat()); + +#define PARAM_UMATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \ + PARAM_COMPLETE(arma::Mat, ID, DESC, ALIAS, "arma::Mat", \ + REQ, IN, TRANS, arma::Mat()); + +#define PARAM_COL(ID, DESC, ALIAS, REQ, TRANS, IN) \ + PARAM_COMPLETE(arma::vec, ID, DESC, ALIAS, "arma::vec", REQ, IN, TRANS, \ + arma::vec()); + +#define PARAM_UCOL(ID, DESC, ALIAS, REQ, TRANS, IN) \ + PARAM_COMPLETE(arma::Col, ID, DESC, ALIAS, "arma::Col", \ + REQ, IN, TRANS, arma::Col()); + +#define PARAM_ROW(ID, DESC, ALIAS, REQ, TRANS, IN) \ + PARAM_COMPLETE(arma::rowvec, ID, DESC, ALIAS, "arma::rowvec", REQ, IN, \ + TRANS, arma::rowvec()); + +#define PARAM_UROW(ID, DESC, ALIAS, REQ, TRANS, IN) \ + PARAM_COMPLETE(arma::Row, ID, DESC, ALIAS, "arma::Row", \ + REQ, IN, TRANS, arma::Row()); + /** * Define an input parameter. Don't use this function; use the other ones above * that call it. Note that we are using the __LINE__ macro for naming these @@ -1225,56 +1255,10 @@ using DatasetInfo = DatasetMapper; * @param REQ Whether or not parameter is required (boolean value). */ #ifdef __COUNTER__ - #define PARAM_IN(T, ID, DESC, ALIAS, DEF, REQ) \ + #define PARAM_COMPLETE(T, ID, DESC, ALIAS, NAME, REQ, IN, TRANS, DEF) \ static mlpack::util::Option \ JOIN(io_option_dummy_object_in_, __COUNTER__) \ - (DEF, ID, DESC, ALIAS, #T, REQ, true, false, testName); - - #define PARAM_IN_WITH_NAME(T, ID, DESC, ALIAS, NAME, DEF, REQ) \ - static mlpack::util::Option \ - JOIN(io_option_dummy_object_in_, __COUNTER__) \ - (DEF, ID, DESC, ALIAS, NAME, REQ, true, false, testName); - - #define PARAM_OUT(T, ID, DESC, ALIAS, DEF, REQ) \ - static mlpack::util::Option \ - JOIN(io_option_dummy_object_out_, __COUNTER__) \ - (DEF, ID, DESC, ALIAS, #T, REQ, false, false, testName); - - #define PARAM_MATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option \ - JOIN(io_option_dummy_matrix_, __COUNTER__) \ - (arma::mat(), ID, DESC, ALIAS, "arma::mat", \ - REQ, IN, !TRANS, testName); - - #define PARAM_UMATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option> \ - JOIN(io_option_dummy_umatrix_, __COUNTER__) \ - (arma::Mat(), ID, DESC, ALIAS, "arma::Mat", \ - REQ, IN, !TRANS, testName); - - #define PARAM_COL(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option \ - JOIN(io_option_dummy_col_, __COUNTER__) \ - (arma::vec(), ID, DESC, ALIAS, "arma::vec", \ - REQ, IN, !TRANS, testName); - - #define PARAM_UCOL(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option> \ - JOIN(io_option_dummy_ucol_, __COUNTER__) \ - (arma::Col(), ID, DESC, ALIAS, "arma::Col", \ - REQ, IN, !TRANS, testName); - - #define PARAM_ROW(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option \ - JOIN(io_option_dummy_row_, __COUNTER__) \ - (arma::rowvec(), ID, DESC, ALIAS, "arma::rowvec", \ - REQ, IN, !TRANS, testName); - - #define PARAM_UROW(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option> \ - JOIN(io_option_dummy_urow_, __COUNTER__) \ - (arma::Row(), ID, DESC, ALIAS, "arma::Row", \ - REQ, IN, !TRANS, testName); + (DEF, ID, DESC, ALIAS, NAME, REQ, IN, !TRANS, testName); // There are no uses of required models, so that is not an option to this // macro (it would be easy to add). @@ -1287,56 +1271,10 @@ using DatasetInfo = DatasetMapper; // don't think we can absolutely guarantee success, but it should be "good // enough". We use the __LINE__ macro and the type of the parameter to try // and get a good guess at something unique. - #define PARAM_IN(T, ID, DESC, ALIAS, DEF, REQ) \ + #define PARAM_COMPLETE(T, ID, DESC, ALIAS, NAME, REQ, IN, TRANS, DEF) \ static mlpack::util::Option \ JOIN(JOIN(io_option_dummy_object_in_, __LINE__), opt) \ - (DEF, ID, DESC, ALIAS, #T, REQ, true, false, testName); - - #define PARAM_IN_WITH_NAME(T, ID, DESC, ALIAS, NAME, DEF, REQ) \ - static mlpack::util::Option \ - JOIN(JOIN(io_option_dummy_object_in_, __LINE__), opt) \ - (DEF, ID, DESC, ALIAS, NAME, REQ, true, false, testName); - - #define PARAM_OUT(T, ID, DESC, ALIAS, DEF, REQ) \ - static mlpack::util::Option \ - JOIN(JOIN(io_option_dummy_object_out_, __LINE__), opt) \ - (DEF, ID, DESC, ALIAS, #T, REQ, false, false, testName); - - #define PARAM_MATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option \ - JOIN(JOIN(io_option_dummy_object_matrix_, __LINE__), opt) \ - (arma::mat(), ID, DESC, ALIAS, "arma::mat", REQ, IN, !TRANS, \ - testName); - - #define PARAM_UMATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option> \ - JOIN(JOIN(io_option_dummy_object_umatrix_, __LINE__), opt) \ - (arma::Mat(), ID, DESC, ALIAS, "arma::Mat", REQ, IN, \ - !TRANS, testName); - - #define PARAM_COL(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option \ - JOIN(io_option_dummy_object_col_, __LINE__) \ - (arma::vec(), ID, DESC, ALIAS, "arma::vec", REQ, IN, !TRANS, \ - testName); - - #define PARAM_UCOL(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option> \ - JOIN(io_option_dummy_object_ucol_, __LINE__) \ - (arma::Col(), ID, DESC, ALIAS, "arma::Col", REQ, IN, \ - !TRANS, testName); - - #define PARAM_ROW(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option \ - JOIN(io_option_dummy_object_row_, __LINE__) \ - (arma::rowvec(), ID, DESC, ALIAS, "arma::rowvec", REQ, IN, !TRANS, \ - testName); - - #define PARAM_UROW(ID, DESC, ALIAS, REQ, TRANS, IN) \ - static mlpack::util::Option> \ - JOIN(io_option_dummy_object_urow_, __LINE__) \ - (arma::Row(), ID, DESC, ALIAS, "arma::Row", REQ, IN, \ - !TRANS, testName); + (DEF, ID, DESC, ALIAS, NAME, REQ, IN, !TRANS, testName); #define PARAM_MODEL(TYPE, ID, DESC, ALIAS, REQ, IN) \ static mlpack::util::Option \ From 3664422c3996b59a140854e1a1d4bc02497f7ce6 Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Thu, 28 Jan 2021 13:23:23 +0530 Subject: [PATCH 129/253] added comments --- src/mlpack/core/util/param.hpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/mlpack/core/util/param.hpp b/src/mlpack/core/util/param.hpp index 8652db4fbe..9499e1a870 100644 --- a/src/mlpack/core/util/param.hpp +++ b/src/mlpack/core/util/param.hpp @@ -1208,6 +1208,9 @@ using DatasetInfo = DatasetMapper; #define PARAM_VECTOR_IN_REQ(T, ID, DESC, ALIAS) \ PARAM_IN(std::vector, ID, DESC, ALIAS, std::vector(), true); +/** + * Defining useful macros using PARAM_COMPLETE() macro defined later. + */ #define PARAM_IN(T, ID, DESC, ALIAS, DEF, REQ) \ PARAM_COMPLETE(T, ID, DESC, ALIAS, #T, REQ, true, false, DEF); @@ -1239,11 +1242,11 @@ using DatasetInfo = DatasetMapper; REQ, IN, TRANS, arma::Row()); /** - * Define an input parameter. Don't use this function; use the other ones above - * that call it. Note that we are using the __LINE__ macro for naming these - * actual parameters when __COUNTER__ does not exist, which is a bit of an ugly - * hack... but this is the preprocessor, after all. We don't have much choice - * other than ugliness. + * Define the PARAM_COMPLETE(), PARAM_MODEL() macro. Don't use this function; + * use the other ones above that call it. Note that we are using the __LINE__ + * macro for naming these actual parameters when __COUNTER__ does not exist, + * which is a bit of an ugly hack... but this is the preprocessor, after all. + * We don't have much choice other than ugliness. * * @param T Type of the parameter. * @param ID Name of the parameter. From b48ba3e77d9aea9ef0ede600f058355d448d0aa8 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 28 Jan 2021 14:03:33 -0500 Subject: [PATCH 130/253] Normalize labels of thyroid data. --- src/mlpack/tests/feedforward_network_test.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/mlpack/tests/feedforward_network_test.cpp b/src/mlpack/tests/feedforward_network_test.cpp index f12573e4ee..552145704e 100644 --- a/src/mlpack/tests/feedforward_network_test.cpp +++ b/src/mlpack/tests/feedforward_network_test.cpp @@ -109,7 +109,8 @@ TEST_CASE("CheckCopyMovingVanillaNetworkTest", "[FeedForwardNetworkTest]") arma::mat trainData; data::Load("thyroid_train.csv", trainData, true); - arma::mat trainLabels = trainData.row(trainData.n_rows - 1); + // Normalize labels to [0, 2]. + arma::mat trainLabels = trainData.row(trainData.n_rows - 1) - 1; trainData.shed_row(trainData.n_rows - 1); /* @@ -162,7 +163,8 @@ TEST_CASE("CheckCopyMovingReparametrizationNetworkTest", "[FeedForwardNetworkTes arma::mat trainData; data::Load("thyroid_train.csv", trainData, true); - arma::mat trainLabels = trainData.row(trainData.n_rows - 1); + // Normalize labels to [0, 2]. + arma::mat trainLabels = trainData.row(trainData.n_rows - 1) - 1; trainData.shed_row(trainData.n_rows - 1); /* @@ -196,7 +198,8 @@ TEST_CASE("CheckCopyMovingLinear3DNetworkTest", "[FeedForwardNetworkTest]") arma::mat trainData; data::Load("thyroid_train.csv", trainData, true); - arma::mat trainLabels = trainData.row(trainData.n_rows - 1); + // Normalize labels to [0, 2]. + arma::mat trainLabels = trainData.row(trainData.n_rows - 1) - 1; trainData.shed_row(trainData.n_rows - 1); /* @@ -334,7 +337,8 @@ TEST_CASE("CheckCopyMovingDropoutNetworkTest", "[FeedForwardNetworkTest]") arma::mat trainData; data::Load("thyroid_train.csv", trainData, true); - arma::mat trainLabels = trainData.row(trainData.n_rows - 1); + // Normalize labels to [0, 2]. + arma::mat trainLabels = trainData.row(trainData.n_rows - 1) - 1; trainData.shed_row(trainData.n_rows - 1); /* @@ -962,13 +966,14 @@ TEST_CASE("FFNCheckInputShapeTest", "[FeedForwardNetworkTest]") arma::mat trainData; data::Load("thyroid_train.csv", trainData, true); - arma::mat trainLabels = trainData.row(trainData.n_rows - 1); + // Normalize labels to [0, 2]. + arma::mat trainLabels = trainData.row(trainData.n_rows - 1) - 1; trainData.shed_row(trainData.n_rows - 1); arma::mat testData; data::Load("thyroid_test.csv", testData, true); - arma::mat testLabels = testData.row(testData.n_rows - 1); + arma::mat testLabels = testData.row(testData.n_rows - 1) - 1; testData.shed_row(testData.n_rows - 1); FFN, RandomInitialization, CustomLayer<> > model; From 5dd135b551e799612744668d36ae2071fe6b5893 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Thu, 28 Jan 2021 20:22:59 -0500 Subject: [PATCH 131/253] Fix (hopefully) last test. --- src/mlpack/tests/feedforward_network_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mlpack/tests/feedforward_network_test.cpp b/src/mlpack/tests/feedforward_network_test.cpp index 552145704e..d4789aac1c 100644 --- a/src/mlpack/tests/feedforward_network_test.cpp +++ b/src/mlpack/tests/feedforward_network_test.cpp @@ -248,10 +248,10 @@ TEST_CASE("CheckCopyMovingLinear3DNetworkTest", "[FeedForwardNetworkTest]") */ TEST_CASE("CheckCopyMovingNoisyLinearTest", "[FeedForwardNetworkTest]") { - // Create training input by 5x5 matrix. - arma::mat input = arma::randu(10,1); - // Create training output by 1 matrix. - arma::mat output = arma::mat("1"); + // Create training input by 10x1 matrix (only 1 point). + arma::mat input = arma::randu(10, 1); + // Create training output by 1-point matrix. + arma::mat output = arma::mat("0"); // Check copying constructor. FFN> *model1 = new FFN>(); From d7bc9e364890ab53b442c7143ac950b7edbf2e53 Mon Sep 17 00:00:00 2001 From: Alex Nguyen <60036798+rxng8@users.noreply.github.com> Date: Fri, 29 Jan 2021 00:04:59 -0500 Subject: [PATCH 132/253] Update src/mlpack/core/tree/hrectbound_impl.hpp Co-authored-by: Ryan Curtin --- src/mlpack/core/tree/hrectbound_impl.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mlpack/core/tree/hrectbound_impl.hpp b/src/mlpack/core/tree/hrectbound_impl.hpp index a1259a677c..491e25fed6 100644 --- a/src/mlpack/core/tree/hrectbound_impl.hpp +++ b/src/mlpack/core/tree/hrectbound_impl.hpp @@ -107,10 +107,9 @@ inline HRectBound::HRectBound( * Move assignment operator. */ template -inline HRectBound< - MetricType, - ElemType>& HRectBound::operator=(HRectBound&& other) +inline HRectBound& +HRectBound::operator=( + HRectBound&& other) { if (this != &other) { From 53571929d57ef8a1a4bf4b3f52cc034465661419 Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Fri, 29 Jan 2021 01:05:49 -0500 Subject: [PATCH 133/253] next static code fix --- src/mlpack/core/tree/ballbound_impl.hpp | 32 ++++++++++++------- .../simple_residue_termination.hpp | 14 ++++---- src/mlpack/methods/hmm/hmm_model.hpp | 6 ++++ 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/mlpack/core/tree/ballbound_impl.hpp b/src/mlpack/core/tree/ballbound_impl.hpp index 5722fb854a..59cc86a5ea 100644 --- a/src/mlpack/core/tree/ballbound_impl.hpp +++ b/src/mlpack/core/tree/ballbound_impl.hpp @@ -71,10 +71,14 @@ template BallBound& BallBound::operator=( const BallBound& other) { - radius = other.radius; - center = other.center; - metric = other.metric; - ownsMetric = false; + if (this != &other) + { + radius = other.radius; + center = other.center; + metric = other.metric; + ownsMetric = false; + } + return *this; } //! Move constructor. @@ -97,15 +101,19 @@ template BallBound& BallBound::operator=( BallBound&& other) { - radius = other.radius; - center = std::move(other.center); - metric = other.metric; - ownsMetric = other.ownsMetric; + if (this != &other) + { + radius = other.radius; + center = std::move(other.center); + metric = other.metric; + ownsMetric = other.ownsMetric; - other.radius = 0.0; - other.center = VecType(); - other.metric = nullptr; - other.ownsMetric = false; + other.radius = 0.0; + other.center = VecType(); + other.metric = nullptr; + other.ownsMetric = false; + } + return *this; } //! Destructor to release allocated memory. diff --git a/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp b/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp index 81893f4fa3..86631e32ce 100644 --- a/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp +++ b/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp @@ -40,13 +40,13 @@ class SimpleResidueTermination * @param maxIterations Maximum number of iterations. */ SimpleResidueTermination(const double minResidue = 1e-5, - const size_t maxIterations = 10000) - : minResidue(minResidue), - maxIterations(maxIterations), - residue(0.0), - iteration(0), - nm(0), - normOld(0) + const size_t maxIterations = 10000) : + minResidue(minResidue), + maxIterations(maxIterations), + residue(0.0), + iteration(0), + nm(0), + normOld(0) { // Nothing to do here. } diff --git a/src/mlpack/methods/hmm/hmm_model.hpp b/src/mlpack/methods/hmm/hmm_model.hpp index 0a2bce384b..7665397bdc 100644 --- a/src/mlpack/methods/hmm/hmm_model.hpp +++ b/src/mlpack/methods/hmm/hmm_model.hpp @@ -139,6 +139,12 @@ class HMMModel gaussianHMM = other.gaussianHMM; gmmHMM = other.gmmHMM; diagGMMHMM = other.diagGMMHMM; + + other.type = HMMType::DiscreteHMM; + other.discreteHMM = new HMM(); + other.gaussianHMM = nullptr; + other.gmmHMM = nullptr; + other.diagGMMHMM = nullptr; } return *this; } From 8b6d068913b2be86589bc8d0625accd6287d1483 Mon Sep 17 00:00:00 2001 From: Alex Nguyen Date: Fri, 29 Jan 2021 01:59:45 -0500 Subject: [PATCH 134/253] next static code fix --- .../hoeffding_trees/hoeffding_tree_impl.hpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp index 5e31358621..f79b0eb027 100644 --- a/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp +++ b/src/mlpack/methods/hoeffding_trees/hoeffding_tree_impl.hpp @@ -251,6 +251,16 @@ HoeffdingTree:: // Remove pointers. other.dimensionMappings = nullptr; other.datasetInfo = nullptr; + + // Reset primary type variables. + other.numSamples = 0; + other.numClasses = 0; + other.checkInterval = 0; + other.minSamples = 0; + other.successProbability = 0.0; + other.splitDimension = 0; + other.majorityClass = 0; + other.majorityProbability = 0.0; } // Copy assignment operator. @@ -327,9 +337,20 @@ HoeffdingTree& majorityProbability = other.majorityProbability; categoricalSplit = std::move(other.categoricalSplit); numericSplit = std::move(other.numericSplit); + // Remove pointers. other.dimensionMappings = nullptr; other.datasetInfo = nullptr; + + // Reset primary type variables. + other.numSamples = 0; + other.numClasses = 0; + other.checkInterval = 0; + other.minSamples = 0; + other.successProbability = 0.0; + other.splitDimension = 0; + other.majorityClass = 0; + other.majorityProbability = 0.0; } return *this; } From 23c39033dee1f3b543d5b982f6708554fa6fd1df Mon Sep 17 00:00:00 2001 From: Nippun Sharma <53967069+NippunSharma@users.noreply.github.com> Date: Fri, 29 Jan 2021 18:04:40 +0530 Subject: [PATCH 135/253] Update src/mlpack/core/util/io.cpp Co-authored-by: Ryan Curtin --- src/mlpack/core/util/io.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/core/util/io.cpp b/src/mlpack/core/util/io.cpp index b7ca51987e..904a155cc0 100644 --- a/src/mlpack/core/util/io.cpp +++ b/src/mlpack/core/util/io.cpp @@ -292,7 +292,7 @@ void IO::CheckInputMatrices() else if (paramType == "std::tuple") { IO::CheckInputMatrix( - std::get<1>(IO::GetParam(paramName)), paramName); + std::get<1>(IO::GetParam(paramName)), paramName); } } } From 9a3815fc1475f4bebf2d31416d800b5b13ab84dc Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Fri, 29 Jan 2021 18:08:37 +0530 Subject: [PATCH 136/253] changed name to PARAM --- src/mlpack/core/util/param.hpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/mlpack/core/util/param.hpp b/src/mlpack/core/util/param.hpp index 9499e1a870..fc809c5b6e 100644 --- a/src/mlpack/core/util/param.hpp +++ b/src/mlpack/core/util/param.hpp @@ -1015,7 +1015,7 @@ using DatasetInfo = DatasetMapper; */ #define TUPLE_TYPE std::tuple #define PARAM_MATRIX_AND_INFO_IN(ID, DESC, ALIAS) \ - PARAM_COMPLETE(TUPLE_TYPE, ID, DESC, ALIAS, \ + PARAM(TUPLE_TYPE, ID, DESC, ALIAS, \ "std::tuple", false, true, true, \ TUPLE_TYPE()) @@ -1209,40 +1209,40 @@ using DatasetInfo = DatasetMapper; PARAM_IN(std::vector, ID, DESC, ALIAS, std::vector(), true); /** - * Defining useful macros using PARAM_COMPLETE() macro defined later. + * Defining useful macros using PARAM macro defined later. */ #define PARAM_IN(T, ID, DESC, ALIAS, DEF, REQ) \ - PARAM_COMPLETE(T, ID, DESC, ALIAS, #T, REQ, true, false, DEF); + PARAM(T, ID, DESC, ALIAS, #T, REQ, true, false, DEF); #define PARAM_OUT(T, ID, DESC, ALIAS, DEF, REQ) \ - PARAM_COMPLETE(T, ID, DESC, ALIAS, #T, REQ, false, false, DEF); + PARAM(T, ID, DESC, ALIAS, #T, REQ, false, false, DEF); #define PARAM_MATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \ - PARAM_COMPLETE(arma::mat, ID, DESC, ALIAS, "arma::mat", REQ, IN, \ + PARAM(arma::mat, ID, DESC, ALIAS, "arma::mat", REQ, IN, \ TRANS, arma::mat()); #define PARAM_UMATRIX(ID, DESC, ALIAS, REQ, TRANS, IN) \ - PARAM_COMPLETE(arma::Mat, ID, DESC, ALIAS, "arma::Mat", \ + PARAM(arma::Mat, ID, DESC, ALIAS, "arma::Mat", \ REQ, IN, TRANS, arma::Mat()); #define PARAM_COL(ID, DESC, ALIAS, REQ, TRANS, IN) \ - PARAM_COMPLETE(arma::vec, ID, DESC, ALIAS, "arma::vec", REQ, IN, TRANS, \ + PARAM(arma::vec, ID, DESC, ALIAS, "arma::vec", REQ, IN, TRANS, \ arma::vec()); #define PARAM_UCOL(ID, DESC, ALIAS, REQ, TRANS, IN) \ - PARAM_COMPLETE(arma::Col, ID, DESC, ALIAS, "arma::Col", \ + PARAM(arma::Col, ID, DESC, ALIAS, "arma::Col", \ REQ, IN, TRANS, arma::Col()); #define PARAM_ROW(ID, DESC, ALIAS, REQ, TRANS, IN) \ - PARAM_COMPLETE(arma::rowvec, ID, DESC, ALIAS, "arma::rowvec", REQ, IN, \ + PARAM(arma::rowvec, ID, DESC, ALIAS, "arma::rowvec", REQ, IN, \ TRANS, arma::rowvec()); #define PARAM_UROW(ID, DESC, ALIAS, REQ, TRANS, IN) \ - PARAM_COMPLETE(arma::Row, ID, DESC, ALIAS, "arma::Row", \ + PARAM(arma::Row, ID, DESC, ALIAS, "arma::Row", \ REQ, IN, TRANS, arma::Row()); /** - * Define the PARAM_COMPLETE(), PARAM_MODEL() macro. Don't use this function; + * Define the PARAM(), PARAM_MODEL() macro. Don't use this function; * use the other ones above that call it. Note that we are using the __LINE__ * macro for naming these actual parameters when __COUNTER__ does not exist, * which is a bit of an ugly hack... but this is the preprocessor, after all. @@ -1258,7 +1258,7 @@ using DatasetInfo = DatasetMapper; * @param REQ Whether or not parameter is required (boolean value). */ #ifdef __COUNTER__ - #define PARAM_COMPLETE(T, ID, DESC, ALIAS, NAME, REQ, IN, TRANS, DEF) \ + #define PARAM(T, ID, DESC, ALIAS, NAME, REQ, IN, TRANS, DEF) \ static mlpack::util::Option \ JOIN(io_option_dummy_object_in_, __COUNTER__) \ (DEF, ID, DESC, ALIAS, NAME, REQ, IN, !TRANS, testName); @@ -1274,7 +1274,7 @@ using DatasetInfo = DatasetMapper; // don't think we can absolutely guarantee success, but it should be "good // enough". We use the __LINE__ macro and the type of the parameter to try // and get a good guess at something unique. - #define PARAM_COMPLETE(T, ID, DESC, ALIAS, NAME, REQ, IN, TRANS, DEF) \ + #define PARAM(T, ID, DESC, ALIAS, NAME, REQ, IN, TRANS, DEF) \ static mlpack::util::Option \ JOIN(JOIN(io_option_dummy_object_in_, __LINE__), opt) \ (DEF, ID, DESC, ALIAS, NAME, REQ, IN, !TRANS, testName); From e339c551e0baf1d3f65fa538572d84e6f7b939a9 Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Tue, 2 Feb 2021 19:40:34 +0530 Subject: [PATCH 137/253] Review Cfixes --- .../methods/ann/loss_functions/hinge_loss.hpp | 5 +++- .../ann/loss_functions/hinge_loss_impl.hpp | 2 +- src/mlpack/tests/loss_functions_test.cpp | 30 +++++++++++-------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp b/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp index a9c2563b9e..37e6ed20f4 100644 --- a/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp @@ -22,6 +22,8 @@ namespace ann /** Artificial Neural Network. */ { * Computes the hinge loss between y_true and y_pred. Expects y_true to be * either -1 or 1. If y_true is either 0 or 1, a temporary conversion is made to * calculate the loss. + * The hinge loss \f$l(y_true, y_pred)\f$ is defined as + * \f$l(y_true, y_pred) = max(0, 1 - y_true*y_pred)\f$. * * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, * arma::sp_mat or arma::cube). @@ -37,6 +39,7 @@ class HingeLoss public: /** * Create HingeLoss object. + * * @param reduction Specifies the reduction to apply to the output. If false, * 'mean' reduction is used, where sum of the output will be * divided by the number of elements in the output. If @@ -54,7 +57,7 @@ class HingeLoss */ template typename PredictionType::elem_type Forward(const PredictionType& prediction, - const TargetType& target); + const TargetType& target); /** * Ordinary feed backward pass of a neural network. diff --git a/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp b/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp index 85fb07cb88..6de5a553fa 100644 --- a/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp +++ b/src/mlpack/methods/ann/loss_functions/hinge_loss_impl.hpp @@ -36,7 +36,7 @@ HingeLoss::Forward( TargetType temp = target - (target == 0); TargetType temp_zeros(size(target), arma::fill::zeros); - PredictionType loss = arma::max(1 - prediction % temp, temp_zeros); + PredictionType loss = arma::max(temp_zeros, 1 - prediction % temp); typename PredictionType::elem_type lossSum = arma::accu(loss); diff --git a/src/mlpack/tests/loss_functions_test.cpp b/src/mlpack/tests/loss_functions_test.cpp index 82e7c76db8..1fa4283c1a 100644 --- a/src/mlpack/tests/loss_functions_test.cpp +++ b/src/mlpack/tests/loss_functions_test.cpp @@ -984,21 +984,23 @@ TEST_CASE("HingeLossTest", "[LossFunctionsTest]") REQUIRE(output.n_rows == input.n_rows); REQUIRE(output.n_cols == input.n_cols); - input = {{0.90599973, -0.33040298, 0.07123354}, - {0.71988434, 0.49657596, 0.39873373}, - {-0.57646927, 0.3951491 , -0.1003365}, - {0.12528634, 0.68122971, 0.85448826}}; + // Randomly generated input. + input = { { 0.90599973, -0.33040298, 0.07123354}, + { 0.71988434, 0.49657596, 0.39873373}, + { -0.57646927, 0.3951491 , -0.1003365}, + { 0.12528634, 0.68122971, 0.85448826} }; - target = {{-1, -1, 1}, - {-1, 1, 1}, - {1, -1, -1}, - {1, -1, -1}}; + // Randomly generated target. + target = { { -1, -1, 1}, + { -1, 1, 1}, + { 1, -1, -1}, + { 1, -1, -1} }; - // Binary labels for target. - target_b = {{0, 0, 1}, - {0, 1, 1}, - {1, 0, 0}, - {1, 0, 0}}; + // Binary target can be obtained by replacing -1 with 0 in target. + target_b = { { 0, 0, 1}, + { 0, 1, 1}, + { 1, 0, 0}, + { 1, 0, 0} }; // Test for binary labels as target. loss = module1.Forward(input, target); @@ -1009,6 +1011,7 @@ TEST_CASE("HingeLossTest", "[LossFunctionsTest]") // Test for sum reduction. // Test the Forward function. + // Loss calculated by referring to implementation of tf.keras.losses.hinge. loss = module1.Forward(input, target); REQUIRE(loss == Approx(14.61065).epsilon(1e-3)); @@ -1020,6 +1023,7 @@ TEST_CASE("HingeLossTest", "[LossFunctionsTest]") // Test for mean reduction. // Test for the Forward function. + // Loss calculated by referring to implementation of tf.keras.losses.hinge. loss = module2.Forward(input, target); REQUIRE(loss == Approx(1.21755).epsilon(1e-3)); From 422ce97209bb6939716de8266aa8fbc9fc21c4dd Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Tue, 2 Feb 2021 19:48:38 +0530 Subject: [PATCH 138/253] Adding Doxygen to y_true and y_pred --- src/mlpack/methods/ann/loss_functions/hinge_loss.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp b/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp index 37e6ed20f4..60a2002782 100644 --- a/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp +++ b/src/mlpack/methods/ann/loss_functions/hinge_loss.hpp @@ -19,9 +19,9 @@ namespace mlpack { namespace ann /** Artificial Neural Network. */ { /** - * Computes the hinge loss between y_true and y_pred. Expects y_true to be - * either -1 or 1. If y_true is either 0 or 1, a temporary conversion is made to - * calculate the loss. + * Computes the hinge loss between \f$y_true\f$ and \f$y_pred\f$. Expects + * \f$y_true\f$ to be either -1 or 1. If \f$y_true\f$ is either 0 or 1, a + * temporary conversion is made to calculate the loss. * The hinge loss \f$l(y_true, y_pred)\f$ is defined as * \f$l(y_true, y_pred) = max(0, 1 - y_true*y_pred)\f$. * From 0c3ec81d4b024d214ef086e96768b3496fe62447 Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Wed, 3 Feb 2021 00:14:26 +0530 Subject: [PATCH 139/253] Changed the restrictors from is_Row to is_arma_type --- src/mlpack/core/data/split_data.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 8a50ceeaf3..055045282f 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -170,7 +170,8 @@ void StratifiedSplit(const arma::Mat& input, * @endcode * * @tparam T Type of the elements of the input matrix. - * @tparam LabelsType Type of input labels. It must be arma::Mat or arma::row. + * @tparam LabelsType Type of input labels. It can be arma::Mat, arma::row, + * arma::Cube or arma::SpMat. * @param input Input dataset to split. * @param inputLabel Input labels to split. * @param trainData Matrix to store training data into. @@ -182,7 +183,7 @@ void StratifiedSplit(const arma::Mat& input, * sample is visited in linear order. (Default true.) */ template::value || + typename = std::enable_if_t::value || arma::is_Mat_only::value> > void Split(const arma::Mat& input, const LabelsType& inputLabel, @@ -300,7 +301,8 @@ void Split(const arma::Mat& input, * @endcode * * @tparam T Type of the elements of the input matrix. - * @tparam LabelsType Type of input labels. It must be arma::Mat or arma::row. + * @tparam LabelsType Type of input labels. It can be arma::Mat, arma::row, + * arma::Cube or arma::SpMat. * @param input Input dataset to split. * @param inputLabel Input labels to split. * @param testRatio Percentage of dataset to use for test set (between 0 and 1). @@ -313,7 +315,7 @@ void Split(const arma::Mat& input, * (arma::Mat), trainLabel (arma::Row), and testLabel (arma::Row). */ template::value || + typename = std::enable_if_t::value || arma::is_Mat_only::value> > std::tuple, arma::Mat, LabelsType, LabelsType> Split(const arma::Mat& input, From 591ac9670571c5040aa32b2dcd69127fb93bd345 Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Wed, 3 Feb 2021 00:21:49 +0530 Subject: [PATCH 140/253] Improved documentation of overload of split for field --- src/mlpack/core/data/split_data.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 055045282f..1225e6cd8d 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -382,6 +382,8 @@ Split(const arma::Mat& input, * Given an input dataset and labels, split into a training set and test set. * Example usage below. This overload places the split dataset into the four * output parameters given (trainData, testData, trainLabel, and testLabel). + * + * The input dataset must be of type arma::field and have a single row. * * NOTE: Here FieldType could be arma::field or arma::field * @@ -460,6 +462,8 @@ void Split(FieldType& input, * Given an input dataset, split into a training set and test set. * Example usage below. This overload places the split dataset into the two * output parameters given (trainData, testData). + * + * The input dataset must be of type arma::field and have a single row. * * NOTE: Here FieldType could be arma::field or arma::field * @@ -521,6 +525,8 @@ void Split(const FieldType& input, * with four elements: an FieldType containing the training data, an * FieldType containing the test data, an arma::field containing the * training labels, and an arma::field containing the test labels. + * + * The input dataset must be of type arma::field and have a single row. * * NOTE: Here FieldType could be arma::field or arma::field * @@ -568,6 +574,8 @@ Split(FieldType& input, * Example usage below. This overload returns the split dataset as a std::tuple * with two elements: an FieldType containing the training data and an * FieldType containing the test data. + * + * The input dataset must be of type arma::field and have a single row. * * NOTE: Here FieldType could be arma::field or arma::field * From 2d98d2ac9a1d95c89f76bd601c77c99135c2c46c Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Wed, 3 Feb 2021 01:03:11 +0100 Subject: [PATCH 141/253] Test file is no no longer used. --- src/mlpack/tests/function_test.cpp | 681 ----------------------------- 1 file changed, 681 deletions(-) delete mode 100644 src/mlpack/tests/function_test.cpp diff --git a/src/mlpack/tests/function_test.cpp b/src/mlpack/tests/function_test.cpp deleted file mode 100644 index 5486ac1e87..0000000000 --- a/src/mlpack/tests/function_test.cpp +++ /dev/null @@ -1,681 +0,0 @@ -/** - * @file tests/function_test.cpp - * @author Ryan Curtin - * @author Shikhar Bhardwaj - * - * Test the Function<> class to see that it properly adds functionality. - * - * 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 -#include -#include -#include -#include -#include - -#include -#include "test_tools.hpp" - -using namespace mlpack; -using namespace mlpack::optimization; -using namespace ens::traits; // For some SFINAE checks. -using namespace mlpack::regression; - -/** - * Utility class with no functions. - */ -class EmptyTestFunction { }; - -/** - * Utility class with Evaluate() but no Evaluate(). - */ -class EvaluateTestFunction -{ - public: - double Evaluate(const arma::mat& coordinates) - { - return arma::accu(coordinates); - } - - double Evaluate(const arma::mat& coordinates, - const size_t begin, - const size_t batchSize) - { - return arma::accu(coordinates) + begin + batchSize; - } -}; - -/** - * Utility class with Gradient() but no Evaluate(). - */ -class GradientTestFunction -{ - public: - void Gradient(const arma::mat& coordinates, arma::mat& gradient) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - } - - void Gradient(const arma::mat& coordinates, - const size_t /* begin */, - arma::mat& gradient, - const size_t /* batchSize */) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - } -}; - -/** - * Utility class with Gradient() and Evaluate(). - */ -class EvaluateGradientTestFunction -{ - public: - double Evaluate(const arma::mat& coordinates) - { - return arma::accu(coordinates); - } - - double Evaluate(const arma::mat& coordinates, - const size_t /* begin */, - const size_t /* batchSize */) - { - return arma::accu(coordinates); - } - - void Gradient(const arma::mat& coordinates, arma::mat& gradient) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - } - - void Gradient(const arma::mat& coordinates, - const size_t /* begin */, - arma::mat& gradient, - const size_t /* batchSize */) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - } -}; - -/** - * Utility class with EvaluateWithGradient(). - */ -class EvaluateWithGradientTestFunction -{ - public: - double EvaluateWithGradient(const arma::mat& coordinates, arma::mat& gradient) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - return arma::accu(coordinates); - } - - double EvaluateWithGradient(const arma::mat& coordinates, - const size_t /* begin */, - arma::mat& gradient, - const size_t /* batchSize */) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - return arma::accu(coordinates); - } -}; - -/** - * Utility class with all three functions. - */ -class EvaluateAndWithGradientTestFunction -{ - public: - double Evaluate(const arma::mat& coordinates) - { - return arma::accu(coordinates); - } - - double Evaluate(const arma::mat& coordinates, - const size_t begin, - const size_t batchSize) - { - return arma::accu(coordinates) + batchSize + begin; - } - - void Gradient(const arma::mat& coordinates, arma::mat& gradient) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - } - - void Gradient(const arma::mat& coordinates, - const size_t /* begin */, - arma::mat& gradient, - const size_t /* batchSize */) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - } - - double EvaluateWithGradient(const arma::mat& coordinates, arma::mat& gradient) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - return arma::accu(coordinates); - } - - double EvaluateWithGradient(const arma::mat& coordinates, - const size_t /* begin */, - arma::mat& gradient, - const size_t /* batchSize */) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - return arma::accu(coordinates); - } -}; - -/** - * Utility class with const Evaluate() and non-const Gradient(). - */ -class EvaluateAndNonConstGradientTestFunction -{ - public: - double Evaluate(const arma::mat& coordinates) const - { - return arma::accu(coordinates); - } - - void Gradient(const arma::mat& coordinates, arma::mat& gradient) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - } -}; - -/** - * Utility class with const Evaluate() and non-const Gradient(). - */ -class EvaluateAndStaticGradientTestFunction -{ - public: - double Evaluate(const arma::mat& coordinates) const - { - return arma::accu(coordinates); - } - - static void Gradient(const arma::mat& coordinates, arma::mat& gradient) - { - gradient.ones(coordinates.n_rows, coordinates.n_cols); - } -}; - -BOOST_AUTO_TEST_SUITE(FunctionTest); - -/** - * Make sure that an empty class doesn't have any methods added to it. - */ -BOOST_AUTO_TEST_CASE(AddEvaluateWithGradientEmptyTest) -{ - const bool hasEvaluate = HasEvaluate, - EvaluateForm>::value; - const bool hasGradient = HasGradient, - GradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - EvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, false); - BOOST_REQUIRE_EQUAL(hasGradient, false); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, false); -} - -/** - * Make sure we don't add any functions if we only have Evaluate(). - */ -BOOST_AUTO_TEST_CASE(AddEvaluateWithGradientEvaluateOnlyTest) -{ - const bool hasEvaluate = HasEvaluate, - EvaluateForm>::value; - const bool hasGradient = HasGradient, - GradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - EvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, false); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, false); -} - -/** - * Make sure we don't add any functions if we only have Gradient(). - */ -BOOST_AUTO_TEST_CASE(AddEvaluateWithGradientGradientOnlyTest) -{ - const bool hasEvaluate = HasEvaluate, - EvaluateForm>::value; - const bool hasGradient = HasGradient, - GradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - EvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, false); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, false); -} - -/** - * Make sure we add EvaluateWithGradient() when we have both Evaluate() and - * Gradient(). - */ -BOOST_AUTO_TEST_CASE(AddEvaluateWithGradientBothTest) -{ - const bool hasEvaluate = - HasEvaluate, - EvaluateForm>::value; - const bool hasGradient = - HasGradient, - GradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - EvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, true); -} - -/** - * Make sure we add Evaluate() and Gradient() when we have only - * EvaluateWithGradient(). - */ -BOOST_AUTO_TEST_CASE(AddEvaluateWithGradientEvaluateWithGradientTest) -{ - const bool hasEvaluate = - HasEvaluate, - EvaluateForm>::value; - const bool hasGradient = - HasGradient, - GradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - EvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, true); -} - -/** - * Make sure we add no methods when we already have all three. - */ -BOOST_AUTO_TEST_CASE(AddEvaluateWithGradientAllThreeTest) -{ - const bool hasEvaluate = - HasEvaluate, - EvaluateForm>::value; - const bool hasGradient = - HasGradient, - GradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - EvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, true); -} - -BOOST_AUTO_TEST_CASE(LogisticRegressionEvaluateWithGradientTest) -{ - const bool hasEvaluate = - HasEvaluate>, - EvaluateConstForm>::value; - const bool hasGradient = - HasGradient>, - GradientConstForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient>, - EvaluateWithGradientConstForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, true); -} - -BOOST_AUTO_TEST_CASE(SDPTest) -{ - typedef AugLagrangianFunction>> FunctionType; - - const bool hasEvaluate = - HasEvaluate, EvaluateConstForm>::value; - const bool hasGradient = - HasGradient, GradientConstForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - EvaluateWithGradientConstForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, true); -} - -/** - * Make sure that an empty class doesn't have any methods added to it. - */ -BOOST_AUTO_TEST_CASE(AddDecomposableEvaluateWithGradientEmptyTest) -{ - const bool hasEvaluate = HasEvaluate, - DecomposableEvaluateForm>::value; - const bool hasGradient = HasGradient, - DecomposableGradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - DecomposableEvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, false); - BOOST_REQUIRE_EQUAL(hasGradient, false); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, false); -} - -/** - * Make sure we don't add any functions if we only have Evaluate(). - */ -BOOST_AUTO_TEST_CASE(AddDecomposableEvaluateWithGradientEvaluateOnlyTest) -{ - const bool hasEvaluate = HasEvaluate, - DecomposableEvaluateForm>::value; - const bool hasGradient = HasGradient, - DecomposableGradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - DecomposableEvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, false); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, false); -} - -/** - * Make sure we don't add any functions if we only have Gradient(). - */ -BOOST_AUTO_TEST_CASE(AddDecomposableEvaluateWithGradientGradientOnlyTest) -{ - const bool hasEvaluate = HasEvaluate, - DecomposableEvaluateForm>::value; - const bool hasGradient = HasGradient, - DecomposableGradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - DecomposableEvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, false); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, false); -} - -/** - * Make sure we add EvaluateWithGradient() when we have both Evaluate() and - * Gradient(). - */ -BOOST_AUTO_TEST_CASE(AddDecomposableEvaluateWithGradientBothTest) -{ - const bool hasEvaluate = - HasEvaluate, - DecomposableEvaluateForm>::value; - const bool hasGradient = - HasGradient, - DecomposableGradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - DecomposableEvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, true); -} - -/** - * Make sure we add Evaluate() and Gradient() when we have only - * EvaluateWithGradient(). - */ -BOOST_AUTO_TEST_CASE(AddDecomposableEvaluateWGradientEvaluateWithGradientTest) -{ - const bool hasEvaluate = - HasEvaluate, - DecomposableEvaluateForm>::value; - const bool hasGradient = - HasGradient, - DecomposableGradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - DecomposableEvaluateWithGradientForm>::value; - - Function f; - arma::mat coordinates(10, 10, arma::fill::ones); - arma::mat gradient; - f.Gradient(coordinates, 0, gradient, 5); - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, true); -} - -/** - * Make sure we add no methods when we already have all three. - */ -BOOST_AUTO_TEST_CASE(AddDecomposableEvaluateWithGradientAllThreeTest) -{ - const bool hasEvaluate = - HasEvaluate, - DecomposableEvaluateForm>::value; - const bool hasGradient = - HasGradient, - DecomposableGradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - DecomposableEvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, true); -} - -/** - * Make sure we can properly create EvaluateWithGradient() even when one of the - * functions is non-const. - */ -BOOST_AUTO_TEST_CASE(AddEvaluateWithGradientMixedTypesTest) -{ - const bool hasEvaluate = - HasEvaluate, - EvaluateConstForm>::value; - const bool hasGradient = - HasGradient, - GradientForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - EvaluateWithGradientForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, true); -} - -/** - * Make sure we can properly create EvaluateWithGradient() even when one of the - * functions is static. - */ -BOOST_AUTO_TEST_CASE(AddEvaluateWithGradientMixedTypesStaticTest) -{ - const bool hasEvaluate = - HasEvaluate, - EvaluateConstForm>::value; - const bool hasGradient = - HasGradient, - GradientStaticForm>::value; - const bool hasEvaluateWithGradient = - HasEvaluateWithGradient, - EvaluateWithGradientConstForm>::value; - - BOOST_REQUIRE_EQUAL(hasEvaluate, true); - BOOST_REQUIRE_EQUAL(hasGradient, true); - BOOST_REQUIRE_EQUAL(hasEvaluateWithGradient, true); -} - -class A -{ - public: - size_t NumFunctions() const; - size_t NumFeatures() const; - double Evaluate(const arma::mat&, const size_t, const size_t) const; - void Gradient(const arma::mat&, const size_t, arma::mat&, const size_t) const; - void Gradient(const arma::mat&, const size_t, arma::sp_mat&, const size_t) - const; - void PartialGradient(const arma::mat&, const size_t, arma::sp_mat&) const; -}; - -class B -{ - public: - size_t NumFunctions(); - size_t NumFeatures(); - double Evaluate(const arma::mat&, const size_t, const size_t); - void Gradient(const arma::mat&, const size_t, arma::mat&, const size_t); - void Gradient(const arma::mat&, const size_t, arma::sp_mat&, const size_t); - void PartialGradient(const arma::mat&, const size_t, arma::sp_mat&); -}; - -class C -{ - public: - size_t NumConstraints() const; - double Evaluate(const arma::mat&) const; - void Gradient(const arma::mat&, arma::mat&) const; - double EvaluateConstraint(const size_t, const arma::mat&) const; - void GradientConstraint(const size_t, const arma::mat&, arma::mat&) const; -}; - -class D -{ - public: - size_t NumConstraints(); - double Evaluate(const arma::mat&); - void Gradient(const arma::mat&, arma::mat&); - double EvaluateConstraint(const size_t, const arma::mat&); - void GradientConstraint(const size_t, const arma::mat&, arma::mat&); -}; - - -/** - * Test the correctness of the static check for DecomposableFunctionType API. - */ -BOOST_AUTO_TEST_CASE(DecomposableFunctionTypeCheckTest) -{ - static_assert(CheckNumFunctions::value, - "CheckNumFunctions static check failed."); - static_assert(CheckNumFunctions::value, - "CheckNumFunctions static check failed."); - static_assert(!CheckNumFunctions::value, - "CheckNumFunctions static check failed."); - static_assert(!CheckNumFunctions::value, - "CheckNumFunctions static check failed."); - - static_assert(CheckDecomposableEvaluate::value, - "CheckDecomposableEvaluate static check failed."); - static_assert(CheckDecomposableEvaluate::value, - "CheckDecomposableEvaluate static check failed."); - static_assert(!CheckDecomposableEvaluate::value, - "CheckDecomposableEvaluate static check failed."); - static_assert(!CheckDecomposableEvaluate::value, - "CheckDecomposableEvaluate static check failed."); - - static_assert(CheckDecomposableGradient::value, - "CheckDecomposableGradient static check failed."); - static_assert(CheckDecomposableGradient::value, - "CheckDecomposableGradient static check failed."); - static_assert(!CheckDecomposableGradient::value, - "CheckDecomposableGradient static check failed."); - static_assert(!CheckDecomposableGradient::value, - "CheckDecomposableGradient static check failed."); -} - -/** - * Test the correctness of the static check for LagrangianFunctionType API. - */ -BOOST_AUTO_TEST_CASE(LagrangianFunctionTypeCheckTest) -{ - static_assert(!CheckEvaluate::value, "CheckEvaluate static check failed."); - static_assert(!CheckEvaluate::value, "CheckEvaluate static check failed."); - static_assert(CheckEvaluate::value, "CheckEvaluate static check failed."); - static_assert(CheckEvaluate::value, "CheckEvaluate static check failed."); - - static_assert(!CheckGradient::value, "CheckGradient static check failed."); - static_assert(!CheckGradient::value, "CheckGradient static check failed."); - static_assert(CheckGradient::value, "CheckGradient static check failed."); - static_assert(CheckGradient::value, "CheckGradient static check failed."); - - static_assert(!CheckNumConstraints::value, - "CheckNumConstraints static check failed."); - static_assert(!CheckNumConstraints::value, - "CheckNumConstraints static check failed."); - static_assert(CheckNumConstraints::value, - "CheckNumConstraints static check failed."); - static_assert(CheckNumConstraints::value, - "CheckNumConstraints static check failed."); - - static_assert(!CheckEvaluateConstraint::value, - "CheckEvaluateConstraint static check failed."); - static_assert(!CheckEvaluateConstraint::value, - "CheckEvaluateConstraint static check failed."); - static_assert(CheckEvaluateConstraint::value, - "CheckEvaluateConstraint static check failed."); - static_assert(CheckEvaluateConstraint::value, - "CheckEvaluateConstraint static check failed."); - - static_assert(!CheckGradientConstraint::value, - "CheckGradientConstraint static check failed."); - static_assert(!CheckGradientConstraint::value, - "CheckGradientConstraint static check failed."); - static_assert(CheckGradientConstraint::value, - "CheckGradientConstraint static check failed."); - static_assert(CheckGradientConstraint::value, - "CheckGradientConstraint static check failed."); -} - -/** - * Test the correctness of the static check for SparseFunctionType API. - */ -BOOST_AUTO_TEST_CASE(SparseFunctionTypeCheckTest) -{ - static_assert(CheckSparseGradient::value, - "CheckSparseGradient static check failed."); - static_assert(CheckSparseGradient::value, - "CheckSparseGradient static check failed."); - static_assert(!CheckSparseGradient::value, - "CheckSparseGradient static check failed."); - static_assert(!CheckSparseGradient::value, - "CheckSparseGradient static check failed."); -} - -/** - * Test the correctness of the static check for SparseFunctionType API. - */ -BOOST_AUTO_TEST_CASE(ResolvableFunctionTypeCheckTest) -{ - static_assert(CheckNumFeatures::value, - "CheckNumFeatures static check failed."); - static_assert(CheckNumFeatures::value, - "CheckNumFeatures static check failed."); - static_assert(!CheckNumFeatures::value, - "CheckNumFeatures static check failed."); - static_assert(!CheckNumFeatures::value, - "CheckNumFeatures static check failed."); - - static_assert(CheckPartialGradient::value, - "CheckPartialGradient static check failed."); - static_assert(CheckPartialGradient::value, - "CheckPartialGradient static check failed."); - static_assert(!CheckPartialGradient::value, - "CheckPartialGradient static check failed."); - static_assert(!CheckPartialGradient::value, - "CheckPartialGradient static check failed."); -} - -BOOST_AUTO_TEST_SUITE_END(); From b2366ab1088cf08e6698309cb1ae3c7caae162d1 Mon Sep 17 00:00:00 2001 From: Marcus Edel Date: Wed, 3 Feb 2021 01:21:35 +0100 Subject: [PATCH 142/253] brew cask instal is no longer supported, use brew install --cask instead. --- .ci/macos-steps.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/macos-steps.yaml b/.ci/macos-steps.yaml index c437344050..85e92fe3b3 100644 --- a/.ci/macos-steps.yaml +++ b/.ci/macos-steps.yaml @@ -22,7 +22,7 @@ steps: fi if [ "a$(julia.version)" != "a" ]; then - brew cask install julia + brew install --cask julia fi git clone --depth 1 https://github.com/mlpack/jenkins-conf.git conf From 66fcef9e0ccf7e622cdfc1da8db15f0191e5b073 Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Thu, 4 Feb 2021 09:15:25 +0530 Subject: [PATCH 143/253] Removed redundant is_Mat_type restrictor --- src/mlpack/core/data/split_data.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 1225e6cd8d..4067e8af09 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -183,8 +183,7 @@ void StratifiedSplit(const arma::Mat& input, * sample is visited in linear order. (Default true.) */ template::value || - arma::is_Mat_only::value> > + typename = std::enable_if_t::value> void Split(const arma::Mat& input, const LabelsType& inputLabel, arma::Mat& trainData, @@ -315,8 +314,7 @@ void Split(const arma::Mat& input, * (arma::Mat), trainLabel (arma::Row), and testLabel (arma::Row). */ template::value || - arma::is_Mat_only::value> > + typename = std::enable_if_t::value> std::tuple, arma::Mat, LabelsType, LabelsType> Split(const arma::Mat& input, const LabelsType& inputLabel, From 0b06b2bfde43ce468a2207b120e48d85d6b39482 Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Thu, 4 Feb 2021 09:35:46 +0530 Subject: [PATCH 144/253] Improved documentation --- src/mlpack/core/data/split_data.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 4067e8af09..561366de2b 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -381,7 +381,8 @@ Split(const arma::Mat& input, * Example usage below. This overload places the split dataset into the four * output parameters given (trainData, testData, trainLabel, and testLabel). * - * The input dataset must be of type arma::field and have a single row. + * The input dataset must be of type arma::field. It should have the shape - + * (n_rows = 1, n_cols = Number of samples, n_slices = 1) * * NOTE: Here FieldType could be arma::field or arma::field * @@ -461,7 +462,8 @@ void Split(FieldType& input, * Example usage below. This overload places the split dataset into the two * output parameters given (trainData, testData). * - * The input dataset must be of type arma::field and have a single row. + * The input dataset must be of type arma::field. It should have the shape - + * (n_rows = 1, n_cols = Number of samples, n_slices = 1) * * NOTE: Here FieldType could be arma::field or arma::field * @@ -524,7 +526,8 @@ void Split(const FieldType& input, * FieldType containing the test data, an arma::field containing the * training labels, and an arma::field containing the test labels. * - * The input dataset must be of type arma::field and have a single row. + * The input dataset must be of type arma::field. It should have the shape - + * (n_rows = 1, n_cols = Number of samples, n_slices = 1) * * NOTE: Here FieldType could be arma::field or arma::field * @@ -573,7 +576,8 @@ Split(FieldType& input, * with two elements: an FieldType containing the training data and an * FieldType containing the test data. * - * The input dataset must be of type arma::field and have a single row. + * The input dataset must be of type arma::field. It should have the shape - + * (n_rows = 1, n_cols = Number of samples, n_slices = 1) * * NOTE: Here FieldType could be arma::field or arma::field * From 7da50e3ba577906beb005808fc5efad71d7fe178 Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Thu, 4 Feb 2021 12:25:24 +0530 Subject: [PATCH 145/253] Fixed brackets --- src/mlpack/core/data/split_data.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 561366de2b..e9358d23c9 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -183,7 +183,7 @@ void StratifiedSplit(const arma::Mat& input, * sample is visited in linear order. (Default true.) */ template::value> + typename = std::enable_if_t::value> > void Split(const arma::Mat& input, const LabelsType& inputLabel, arma::Mat& trainData, @@ -314,7 +314,7 @@ void Split(const arma::Mat& input, * (arma::Mat), trainLabel (arma::Row), and testLabel (arma::Row). */ template::value> + typename = std::enable_if_t::value> > std::tuple, arma::Mat, LabelsType, LabelsType> Split(const arma::Mat& input, const LabelsType& inputLabel, From cbb534daa150606b5b280902d4829741e14d39bb Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Thu, 4 Feb 2021 16:38:12 +0530 Subject: [PATCH 146/253] Added test case for matrix labels --- src/mlpack/tests/split_data_test.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index 996c6ccfa4..d3d445796e 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -199,6 +199,26 @@ TEST_CASE("SplitLabeledDataResultMat", "[SplitDataTest]") CheckDuplication(std::get<2>(value), std::get<3>(value)); } +TEST_CASE("SplitMatrixLabeledDataResultMat", "[SplitDataTest]") +{ + mat input(2, 10); + input.randu(); + + const mat labels(2, 10, fill::randu); + + const auto value = Split(input, labels, 0.2); + REQUIRE(std::get<0>(value).n_cols == 8); + REQUIRE(std::get<1>(value).n_cols == 2); + REQUIRE(std::get<2>(value).n_cols == 8); + REQUIRE(std::get<3>(value).n_cols == 2); + + mat input_concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); + mat labels_concat = arma::join_rows(std::get<2>(value), std::get<3>(value)); + // Order matters here. + CheckMatrices(input, input_concat); + CheckMatrices(labels, labels_concat); +} + /** * The same test as above, but on a larger dataset. */ From 0ed4da96cdb8e6ebdecf2c6f09b85f4b49c9a51f Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Sat, 6 Feb 2021 01:32:55 +0530 Subject: [PATCH 147/253] Added LP lookup layer --- src/mlpack/methods/ann/layer/lp_pooling.hpp | 289 ++++++++++++++++++ .../methods/ann/layer/lp_pooling_impl.hpp | 141 +++++++++ src/mlpack/tests/ann_layer_test.cpp | 48 +++ 3 files changed, 478 insertions(+) create mode 100644 src/mlpack/methods/ann/layer/lp_pooling.hpp create mode 100644 src/mlpack/methods/ann/layer/lp_pooling_impl.hpp diff --git a/src/mlpack/methods/ann/layer/lp_pooling.hpp b/src/mlpack/methods/ann/layer/lp_pooling.hpp new file mode 100644 index 0000000000..e698f89e93 --- /dev/null +++ b/src/mlpack/methods/ann/layer/lp_pooling.hpp @@ -0,0 +1,289 @@ +/** + * @file methods/ann/layer/lp_pooling.hpp + * @author Abhinav Anan + * + * Definition of the LpPooling layer class. + * + * 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. + */ +#ifndef MLPACK_METHODS_ANN_LAYER_LP_POOLING_HPP +#define MLPACK_METHODS_ANN_LAYER_LP_POOLING_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * Implementation of the LPPooling. + * + * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + * @tparam OutputDataType Type of the output data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + */ +template < + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +class LpPooling +{ + public: + //! Create the LpPooling object. + LpPooling(); + + /** + * Create the LpPooling object using the specified number of units. + * + * @param kernelWidth Width of the pooling window. + * @param kernelHeight Height of the pooling window. + * @param strideWidth Width of the stride operation. + * @param strideHeight Width of the stride operation. + * @param floor Set to true to use floor method. + */ + LpPooling(const size_t norm_type, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth = 1, + const size_t strideHeight = 1, + const bool floor = true); + + /** + * Ordinary feed forward pass of a neural network, evaluating the function + * f(x) by propagating the activity forward through f. + * + * @param input Input data used for evaluating the specified function. + * @param output Resulting output activation. + */ + template + void Forward(const arma::Mat& input, arma::Mat& output); + + /** + * Ordinary feed backward pass of a neural network, using 3rd-order tensors as + * input, calculating the function f(x) by propagating x backwards through f. + * Using the results from the feed forward pass. + * + * @param * (input) The propagated input activation. + * @param gy The backpropagated error. + * @param g The calculated gradient. + */ + template + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); + + //! Get the output parameter. + OutputDataType const& OutputParameter() const { return outputParameter; } + //! Modify the output parameter. + OutputDataType& OutputParameter() { return outputParameter; } + + //! Get the delta. + OutputDataType const& Delta() const { return delta; } + //! Modify the delta. + OutputDataType& Delta() { return delta; } + + //! Get the intput width. + size_t const& InputWidth() const { return inputWidth; } + //! Modify the input width. + size_t& InputWidth() { return inputWidth; } + + //! Get the input height. + size_t const& InputHeight() const { return inputHeight; } + //! Modify the input height. + size_t& InputHeight() { return inputHeight; } + + //! Get the output width. + size_t const& OutputWidth() const { return outputWidth; } + //! Modify the output width. + size_t& OutputWidth() { return outputWidth; } + + //! Get the output height. + size_t const& OutputHeight() const { return outputHeight; } + //! Modify the output height. + size_t& OutputHeight() { return outputHeight; } + + //! Get the input size. + size_t InputSize() const { return inSize; } + + //! Get the output size. + size_t OutputSize() const { return outSize; } + + //! Get the norm_type. + size_t NormType() const { return norm_type; } + //! Modify the norm_type. + size_t& NormType() const { return norm_type; } + + //! Get the kernel width. + size_t KernelWidth() const { return kernelWidth; } + //! Modify the kernel width. + size_t& KernelWidth() { return kernelWidth; } + + //! Get the kernel height. + size_t KernelHeight() const { return kernelHeight; } + //! Modify the kernel height. + size_t& KernelHeight() { return kernelHeight; } + + //! Get the stride width. + size_t StrideWidth() const { return strideWidth; } + //! Modify the stride width. + size_t& StrideWidth() { return strideWidth; } + + //! Get the stride height. + size_t StrideHeight() const { return strideHeight; } + //! Modify the stride height. + size_t& StrideHeight() { return strideHeight; } + + //! Get the value of the rounding operation + bool const& Floor() const { return floor; } + //! Modify the value of the rounding operation + bool& Floor() { return floor; } + + //! Get the value of the deterministic parameter. + bool Deterministic() const { return deterministic; } + //! Modify the value of the deterministic parameter. + bool& Deterministic() { return deterministic; } + + //! Get the size of the weights. + size_t WeightSize() const { return 0; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const uint32_t /* version */); + + private: + /** + * Apply pooling to the input and store the results. + * + * @param input The input to be apply the pooling rule. + * @param output The pooled result. + */ + template + void Pooling(const arma::Mat& input, arma::Mat& output) + { + for (size_t j = 0, colidx = 0; j < output.n_cols; + ++j, colidx += strideHeight) + { + for (size_t i = 0, rowidx = 0; i < output.n_rows; + ++i, rowidx += strideWidth) + { + arma::mat subInput = input( + arma::span(rowidx, rowidx + kernelWidth - 1 - offset), + arma::span(colidx, colidx + kernelHeight - 1 - offset)); + + output(i, j) = arma::pow(arma::accu(arma::pow(subInput, norm_type)), 1.0/norm_type); + } + } + } + + /** + * Apply unpooling to the input and store the results. + * + * @param input The input to be apply the unpooling rule. + * @param output The pooled result. + */ + template + void Unpooling(const arma::Mat& input, + const arma::Mat& error, + arma::Mat& output) + { + const size_t rStep = input.n_rows / error.n_rows - offset; + const size_t cStep = input.n_cols / error.n_cols - offset; + + arma::Mat unpooledError; + for (size_t j = 0; j < input.n_cols - cStep; j += cStep) + { + for (size_t i = 0; i < input.n_rows - rStep; i += rStep) + { + const arma::Mat& inputArea = input(arma::span(i, i + rStep - 1), + arma::span(j, j + cStep - 1)); + size_t sum = arma::pow(arma::accu(arma::pow(inputArea, norm_type)), (norm_type-1) / norm_type); + unpooledError = arma::Mat(inputArea.n_rows, inputArea.n_cols); + unpooledError.fill(error(i / rStep, j / cStep)); + unpooledError %= arma::pow(inputArea, norm_type - 1); + unpooledError /= sum; + output(arma::span(i, i + rStep - 1 - offset), + arma::span(j, j + cStep - 1 - offset)) += unpooledError; + } + } + } + + //! Locally-stored norm_type. + size_t norm_type; + + //! Locally-stored width of the pooling window. + size_t kernelWidth; + + //! Locally-stored height of the pooling window. + size_t kernelHeight; + + //! Locally-stored width of the stride operation. + size_t strideWidth; + + //! Locally-stored height of the stride operation. + size_t strideHeight; + + //! Rounding operation used. + bool floor; + + //! Locally-stored number of input channels. + size_t inSize; + + //! Locally-stored number of output channels. + size_t outSize; + + //! Locally-stored input width. + size_t inputWidth; + + //! Locally-stored input height. + size_t inputHeight; + + //! Locally-stored output width. + size_t outputWidth; + + //! Locally-stored output height. + size_t outputHeight; + + //! Locally-stored reset parameter used to initialize the module once. + bool reset; + + //! If true use maximum a posteriori during the forward pass. + bool deterministic; + + //! Locally-stored stored rounding offset. + size_t offset; + + //! Locally-stored number of input units. + size_t batchSize; + + //! Locally-stored output parameter. + arma::cube outputTemp; + + //! Locally-stored transformed input parameter. + arma::cube inputTemp; + + //! Locally-stored transformed output parameter. + arma::cube gTemp; + + //! Locally-stored delta object. + OutputDataType delta; + + //! Locally-stored gradient object. + OutputDataType gradient; + + //! Locally-stored output parameter object. + OutputDataType outputParameter; +}; // class LpPooling + + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "lp_pooling_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp b/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp new file mode 100644 index 0000000000..9f1133aee8 --- /dev/null +++ b/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp @@ -0,0 +1,141 @@ +/** + * @file methods/ann/layer/lp_pooling_impl.hpp + * @author Marcus Edel + * @author Nilay Jain + * + * Implementation of the lpPooling layer class. + * + * 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. + */ +#ifndef MLPACK_METHODS_ANN_LAYER_LP_POOLING_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_LP_POOLING_IMPL_HPP + +// In case it hasn't yet been included. +#include "lp_pooling.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +LpPooling::LpPooling() +{ + // Nothing to do here. +} + +template +LpPooling::LpPooling( + const size_t norm_type, + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, + const bool floor) : + kernelWidth(kernelWidth), + kernelHeight(kernelHeight), + strideWidth(strideWidth), + strideHeight(strideHeight), + floor(floor), + inSize(0), + outSize(0), + inputWidth(0), + inputHeight(0), + outputWidth(0), + outputHeight(0), + reset(false), + deterministic(false), + offset(0), + batchSize(0) +{ + // Nothing to do here. +} + +template +template +void LpPooling::Forward( + const arma::Mat& input, arma::Mat& output) +{ + batchSize = input.n_cols; + inSize = input.n_elem / (inputWidth * inputHeight * batchSize); + inputTemp = arma::cube(const_cast&>(input).memptr(), + inputWidth, inputHeight, batchSize * inSize, false, false); + + if (floor) + { + outputWidth = std::floor((inputWidth - + (double) kernelWidth) / (double) strideWidth + 1); + outputHeight = std::floor((inputHeight - + (double) kernelHeight) / (double) strideHeight + 1); + + offset = 0; + } + else + { + outputWidth = std::ceil((inputWidth - + (double) kernelWidth) / (double) strideWidth + 1); + outputHeight = std::ceil((inputHeight - + (double) kernelHeight) / (double) strideHeight + 1); + + offset = 1; + } + + outputTemp = arma::zeros >(outputWidth, outputHeight, + batchSize * inSize); + + for (size_t s = 0; s < inputTemp.n_slices; s++) + Pooling(inputTemp.slice(s), outputTemp.slice(s)); + + output = arma::Mat(outputTemp.memptr(), outputTemp.n_elem / batchSize, + batchSize); + + outputWidth = outputTemp.n_rows; + outputHeight = outputTemp.n_cols; + outSize = batchSize * inSize; +} + +template +template +void LpPooling::Backward( + const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g) +{ + arma::cube mappedError = arma::cube(((arma::Mat&) gy).memptr(), + outputWidth, outputHeight, outSize, false, false); + + gTemp = arma::zeros(inputTemp.n_rows, + inputTemp.n_cols, inputTemp.n_slices); + + for (size_t s = 0; s < mappedError.n_slices; s++) + { + Unpooling(inputTemp.slice(s), mappedError.slice(s), gTemp.slice(s)); + } + + g = arma::mat(gTemp.memptr(), gTemp.n_elem / batchSize, batchSize); +} + +template +template +void LpPooling::serialize( + Archive& ar, + const uint32_t /* version */) +{ + ar(CEREAL_NVP(norm_type)); + ar(CEREAL_NVP(kernelWidth)); + ar(CEREAL_NVP(kernelHeight)); + ar(CEREAL_NVP(strideWidth)); + ar(CEREAL_NVP(strideHeight)); + ar(CEREAL_NVP(batchSize)); + ar(CEREAL_NVP(floor)); + ar(CEREAL_NVP(inputWidth)); + ar(CEREAL_NVP(inputHeight)); + ar(CEREAL_NVP(outputWidth)); + ar(CEREAL_NVP(outputHeight)); +} + +} // namespace ann +} // namespace mlpack + +#endif diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 5e24a995e7..012269e479 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -3838,6 +3838,54 @@ TEST_CASE("TransposedConvolutionLayerPaddingTest", "[ANNLayerTest]") REQUIRE(arma::accu(delta) == 0.0); } +/** + * Simple test for Lp Pooling layer. + */ +TEST_CASE("LpPoolingTestCase", "[ANNLayerTest]") +{ + // For rectangular input to pooling layers. + arma::mat input = arma::mat(8, 1); + arma::mat output; + input.zeros(); + input(0) = input(6) = 30; + input(1) = input(7) = 120; + input(2) = input(4) = 272; + input(3) = input(5) = 315; + // Output-Size should be 1 x 2. + // Square output. + Lp<> module1(4, 2, 2, 2, 2); + module1.InputHeight() = 2; + module1.InputWidth() = 4; + module1.Forward(input, output); + // Calculated using torch.nn.LPPool2d(). + REQUIRE(arma::accu(output) - 706.0 == Approx(0.0).margin(2e-5)); + REQUIRE(output.n_elem == 2); + + // For Square input. + input = arma::mat(16, 1); + input.zeros(); + input(0) = 4; + input(1) = 3; + input(3) = 12; + input(7) = 35; + input(8) = 6; + input(11) = 7; + input(12) = 8; + input(15) = 24; + // Output-Size should be 2 x 2. + // Square output. + Lp<> module3(2, 2, 2, 2, 2); + module3.InputHeight() = 4; + module3.InputWidth() = 4; + module3.Forward(input, output); + // Calculated using torch.nn.LPPool2d(). + REQUIRE(arma::accu(output) - 77.0 == Approx(0.0).margin(2e-5)); + REQUIRE(output.n_elem == 4); + +} + + + /** * Simple test for Max Pooling layer. */ From 89a56d7e878c0da22bd21f77cc8800cdf95c5d59 Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Sat, 6 Feb 2021 01:46:03 +0530 Subject: [PATCH 148/253] Added LP lookup layer --- src/mlpack/tests/ann_layer_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 012269e479..6608304f3d 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -3853,7 +3853,7 @@ TEST_CASE("LpPoolingTestCase", "[ANNLayerTest]") input(3) = input(5) = 315; // Output-Size should be 1 x 2. // Square output. - Lp<> module1(4, 2, 2, 2, 2); + LpPooling<> module1(4, 2, 2, 2, 2); module1.InputHeight() = 2; module1.InputWidth() = 4; module1.Forward(input, output); @@ -3874,7 +3874,7 @@ TEST_CASE("LpPoolingTestCase", "[ANNLayerTest]") input(15) = 24; // Output-Size should be 2 x 2. // Square output. - Lp<> module3(2, 2, 2, 2, 2); + LpPooling<> module3(2, 2, 2, 2, 2); module3.InputHeight() = 4; module3.InputWidth() = 4; module3.Forward(input, output); From 7772c73332bed0816ca10a33eb90bfa37b88879f Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Sat, 6 Feb 2021 02:20:20 +0530 Subject: [PATCH 149/253] minor changes --- src/mlpack/methods/ann/layer/CMakeLists.txt | 2 ++ src/mlpack/methods/ann/layer/layer_types.hpp | 2 ++ src/mlpack/methods/ann/layer_names.hpp | 11 +++++++++++ 3 files changed, 15 insertions(+) diff --git a/src/mlpack/methods/ann/layer/CMakeLists.txt b/src/mlpack/methods/ann/layer/CMakeLists.txt index b4726b0c6f..5fe560edd4 100644 --- a/src/mlpack/methods/ann/layer/CMakeLists.txt +++ b/src/mlpack/methods/ann/layer/CMakeLists.txt @@ -63,6 +63,8 @@ set(SOURCES log_softmax_impl.hpp lookup.hpp lookup_impl.hpp + lp_pooling.hpp + lp_pooling_impl.hpp lstm.hpp lstm_impl.hpp max_pooling.hpp diff --git a/src/mlpack/methods/ann/layer/layer_types.hpp b/src/mlpack/methods/ann/layer/layer_types.hpp index 1d7fd0ccba..d27a5a6d25 100644 --- a/src/mlpack/methods/ann/layer/layer_types.hpp +++ b/src/mlpack/methods/ann/layer/layer_types.hpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -282,6 +283,7 @@ using LayerTypes = boost::variant< LSTM*, MaxPooling*, MeanPooling*, + LpPooling*, MiniBatchDiscrimination*, MultiplyConstant*, MultiplyMerge*, diff --git a/src/mlpack/methods/ann/layer_names.hpp b/src/mlpack/methods/ann/layer_names.hpp index be1b1f7fcb..15596efea3 100644 --- a/src/mlpack/methods/ann/layer_names.hpp +++ b/src/mlpack/methods/ann/layer_names.hpp @@ -206,6 +206,17 @@ class LayerNameVisitor : public boost::static_visitor return "meanpooling"; } + /** + * Return the name of the given layer of type LpPooling as a string. + * + * @param * Given layer of type LpPooling. + * @return The string representation of the layer. + */ + std::string LayerString(LpPooling<>* /*layer*/) const + { + return "lppooling"; + } + /** * Return the name of the given layer of type MultiplyConstant as a string. * From 826b1713918a8481386055c45e3160a9321e024c Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Sat, 6 Feb 2021 02:28:02 +0530 Subject: [PATCH 150/253] minor --- src/mlpack/tests/ann_layer_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index 6608304f3d..cbd66116bf 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -3841,7 +3841,7 @@ TEST_CASE("TransposedConvolutionLayerPaddingTest", "[ANNLayerTest]") /** * Simple test for Lp Pooling layer. */ -TEST_CASE("LpPoolingTestCase", "[ANNLayerTest]") +BOOST_AUTO_TEST_CASE(LpMaxPoolingTestCase) { // For rectangular input to pooling layers. arma::mat input = arma::mat(8, 1); From a88994e48bb72057204b0fbf8c75b10838096127 Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Sat, 6 Feb 2021 02:43:09 +0530 Subject: [PATCH 151/253] minor --- src/mlpack/methods/ann/layer/layer.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mlpack/methods/ann/layer/layer.hpp b/src/mlpack/methods/ann/layer/layer.hpp index 947395fd6b..9cf806b7e4 100644 --- a/src/mlpack/methods/ann/layer/layer.hpp +++ b/src/mlpack/methods/ann/layer/layer.hpp @@ -47,6 +47,7 @@ #include "linear3d.hpp" #include "log_softmax.hpp" #include "lookup.hpp" +#include "lp_pooling.hpp" #include "lstm.hpp" #include "max_pooling.hpp" #include "mean_pooling.hpp" From c1c0cfbc18c8a4492cf2f0bcab744a01b057b3e7 Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Sat, 6 Feb 2021 02:49:15 +0530 Subject: [PATCH 152/253] minor change --- src/mlpack/methods/ann/layer/lp_pooling.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lp_pooling.hpp b/src/mlpack/methods/ann/layer/lp_pooling.hpp index e698f89e93..ff360f41e7 100644 --- a/src/mlpack/methods/ann/layer/lp_pooling.hpp +++ b/src/mlpack/methods/ann/layer/lp_pooling.hpp @@ -175,7 +175,7 @@ class LpPooling arma::span(rowidx, rowidx + kernelWidth - 1 - offset), arma::span(colidx, colidx + kernelHeight - 1 - offset)); - output(i, j) = arma::pow(arma::accu(arma::pow(subInput, norm_type)), 1.0/norm_type); + output(i, j) = cmath::pow(arma::accu(arma::pow(subInput, norm_type)), 1.0/norm_type); } } } @@ -201,7 +201,7 @@ class LpPooling { const arma::Mat& inputArea = input(arma::span(i, i + rStep - 1), arma::span(j, j + cStep - 1)); - size_t sum = arma::pow(arma::accu(arma::pow(inputArea, norm_type)), (norm_type-1) / norm_type); + size_t sum = cmath::pow(arma::accu(arma::pow(inputArea, norm_type)), (norm_type-1) / norm_type); unpooledError = arma::Mat(inputArea.n_rows, inputArea.n_cols); unpooledError.fill(error(i / rStep, j / cStep)); unpooledError %= arma::pow(inputArea, norm_type - 1); From 66dc153ab2504adee07d41015b6288efc37db178 Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Sat, 6 Feb 2021 02:58:44 +0530 Subject: [PATCH 153/253] minor fix --- src/mlpack/methods/ann/layer/lp_pooling.hpp | 25 ++++++++----------- .../methods/ann/layer/lp_pooling_impl.hpp | 1 - src/mlpack/tests/ann_layer_test.cpp | 3 --- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lp_pooling.hpp b/src/mlpack/methods/ann/layer/lp_pooling.hpp index ff360f41e7..6205a0fba1 100644 --- a/src/mlpack/methods/ann/layer/lp_pooling.hpp +++ b/src/mlpack/methods/ann/layer/lp_pooling.hpp @@ -38,6 +38,7 @@ class LpPooling /** * Create the LpPooling object using the specified number of units. * + * @param norm_type Parameter for type of norm. * @param kernelWidth Width of the pooling window. * @param kernelHeight Height of the pooling window. * @param strideWidth Width of the stride operation. @@ -45,11 +46,11 @@ class LpPooling * @param floor Set to true to use floor method. */ LpPooling(const size_t norm_type, - const size_t kernelWidth, - const size_t kernelHeight, - const size_t strideWidth = 1, - const size_t strideHeight = 1, - const bool floor = true); + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth = 1, + const size_t strideHeight = 1, + const bool floor = true); /** * Ordinary feed forward pass of a neural network, evaluating the function @@ -141,11 +142,6 @@ class LpPooling //! Modify the value of the rounding operation bool& Floor() { return floor; } - //! Get the value of the deterministic parameter. - bool Deterministic() const { return deterministic; } - //! Modify the value of the deterministic parameter. - bool& Deterministic() { return deterministic; } - //! Get the size of the weights. size_t WeightSize() const { return 0; } @@ -175,7 +171,8 @@ class LpPooling arma::span(rowidx, rowidx + kernelWidth - 1 - offset), arma::span(colidx, colidx + kernelHeight - 1 - offset)); - output(i, j) = cmath::pow(arma::accu(arma::pow(subInput, norm_type)), 1.0/norm_type); + output(i, j) = cmath::pow(arma::accu(arma::pow(subInput, + norm_type)), 1.0/norm_type); } } } @@ -201,7 +198,8 @@ class LpPooling { const arma::Mat& inputArea = input(arma::span(i, i + rStep - 1), arma::span(j, j + cStep - 1)); - size_t sum = cmath::pow(arma::accu(arma::pow(inputArea, norm_type)), (norm_type-1) / norm_type); + size_t sum = cmath::pow(arma::accu(arma::pow(inputArea, norm_type)), + (norm_type-1) / norm_type); unpooledError = arma::Mat(inputArea.n_rows, inputArea.n_cols); unpooledError.fill(error(i / rStep, j / cStep)); unpooledError %= arma::pow(inputArea, norm_type - 1); @@ -251,9 +249,6 @@ class LpPooling //! Locally-stored reset parameter used to initialize the module once. bool reset; - //! If true use maximum a posteriori during the forward pass. - bool deterministic; - //! Locally-stored stored rounding offset. size_t offset; diff --git a/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp b/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp index 9f1133aee8..e646796360 100644 --- a/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp +++ b/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp @@ -45,7 +45,6 @@ LpPooling::LpPooling( outputWidth(0), outputHeight(0), reset(false), - deterministic(false), offset(0), batchSize(0) { diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index cbd66116bf..feead2800a 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -3881,11 +3881,8 @@ BOOST_AUTO_TEST_CASE(LpMaxPoolingTestCase) // Calculated using torch.nn.LPPool2d(). REQUIRE(arma::accu(output) - 77.0 == Approx(0.0).margin(2e-5)); REQUIRE(output.n_elem == 4); - } - - /** * Simple test for Max Pooling layer. */ From c9934c3975d03f9b441cafe59847b4481d40b0c8 Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Sat, 6 Feb 2021 21:18:52 +0530 Subject: [PATCH 154/253] minor fix --- src/mlpack/methods/ann/layer/lp_pooling.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/lp_pooling.hpp b/src/mlpack/methods/ann/layer/lp_pooling.hpp index 6205a0fba1..aa413c02dc 100644 --- a/src/mlpack/methods/ann/layer/lp_pooling.hpp +++ b/src/mlpack/methods/ann/layer/lp_pooling.hpp @@ -115,7 +115,7 @@ class LpPooling //! Get the norm_type. size_t NormType() const { return norm_type; } //! Modify the norm_type. - size_t& NormType() const { return norm_type; } + size_t& NormType() { return norm_type; } //! Get the kernel width. size_t KernelWidth() const { return kernelWidth; } From 92a8bd69f9c4c79efe83695e29cb5f312489d755 Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Sat, 6 Feb 2021 21:30:09 +0530 Subject: [PATCH 155/253] minor change --- src/mlpack/methods/ann/layer/lp_pooling.hpp | 4 ++-- src/mlpack/tests/ann_layer_test.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lp_pooling.hpp b/src/mlpack/methods/ann/layer/lp_pooling.hpp index aa413c02dc..0f6a2bdb83 100644 --- a/src/mlpack/methods/ann/layer/lp_pooling.hpp +++ b/src/mlpack/methods/ann/layer/lp_pooling.hpp @@ -171,7 +171,7 @@ class LpPooling arma::span(rowidx, rowidx + kernelWidth - 1 - offset), arma::span(colidx, colidx + kernelHeight - 1 - offset)); - output(i, j) = cmath::pow(arma::accu(arma::pow(subInput, + output(i, j) = pow(arma::accu(arma::pow(subInput, norm_type)), 1.0/norm_type); } } @@ -198,7 +198,7 @@ class LpPooling { const arma::Mat& inputArea = input(arma::span(i, i + rStep - 1), arma::span(j, j + cStep - 1)); - size_t sum = cmath::pow(arma::accu(arma::pow(inputArea, norm_type)), + size_t sum = pow(arma::accu(arma::pow(inputArea, norm_type)), (norm_type-1) / norm_type); unpooledError = arma::Mat(inputArea.n_rows, inputArea.n_cols); unpooledError.fill(error(i / rStep, j / cStep)); diff --git a/src/mlpack/tests/ann_layer_test.cpp b/src/mlpack/tests/ann_layer_test.cpp index feead2800a..dbb5266798 100644 --- a/src/mlpack/tests/ann_layer_test.cpp +++ b/src/mlpack/tests/ann_layer_test.cpp @@ -3841,7 +3841,7 @@ TEST_CASE("TransposedConvolutionLayerPaddingTest", "[ANNLayerTest]") /** * Simple test for Lp Pooling layer. */ -BOOST_AUTO_TEST_CASE(LpMaxPoolingTestCase) +TEST_CASE("LpMaxPoolingTestCase", "[ANNLayerTest]") { // For rectangular input to pooling layers. arma::mat input = arma::mat(8, 1); From ada4e570e8d7d43bfeadc7e94dd274e533cc2e09 Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Sat, 6 Feb 2021 22:35:12 +0530 Subject: [PATCH 156/253] minor fix --- src/mlpack/methods/ann/layer/lp_pooling.hpp | 24 +++++++++---------- .../methods/ann/layer/lp_pooling_impl.hpp | 5 ++-- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lp_pooling.hpp b/src/mlpack/methods/ann/layer/lp_pooling.hpp index 0f6a2bdb83..aa0f043c33 100644 --- a/src/mlpack/methods/ann/layer/lp_pooling.hpp +++ b/src/mlpack/methods/ann/layer/lp_pooling.hpp @@ -38,14 +38,14 @@ class LpPooling /** * Create the LpPooling object using the specified number of units. * - * @param norm_type Parameter for type of norm. + * @param normType Parameter for type of norm. * @param kernelWidth Width of the pooling window. * @param kernelHeight Height of the pooling window. * @param strideWidth Width of the stride operation. * @param strideHeight Width of the stride operation. * @param floor Set to true to use floor method. */ - LpPooling(const size_t norm_type, + LpPooling(const size_t normType, const size_t kernelWidth, const size_t kernelHeight, const size_t strideWidth = 1, @@ -112,10 +112,10 @@ class LpPooling //! Get the output size. size_t OutputSize() const { return outSize; } - //! Get the norm_type. - size_t NormType() const { return norm_type; } - //! Modify the norm_type. - size_t& NormType() { return norm_type; } + //! Get the normType. + size_t NormType() const { return normType; } + //! Modify the normType. + size_t& NormType() { return normType; } //! Get the kernel width. size_t KernelWidth() const { return kernelWidth; } @@ -172,7 +172,7 @@ class LpPooling arma::span(colidx, colidx + kernelHeight - 1 - offset)); output(i, j) = pow(arma::accu(arma::pow(subInput, - norm_type)), 1.0/norm_type); + normType)), 1.0/normType); } } } @@ -198,11 +198,11 @@ class LpPooling { const arma::Mat& inputArea = input(arma::span(i, i + rStep - 1), arma::span(j, j + cStep - 1)); - size_t sum = pow(arma::accu(arma::pow(inputArea, norm_type)), - (norm_type-1) / norm_type); + size_t sum = pow(arma::accu(arma::pow(inputArea, normType)), + (normType-1) / normType); unpooledError = arma::Mat(inputArea.n_rows, inputArea.n_cols); unpooledError.fill(error(i / rStep, j / cStep)); - unpooledError %= arma::pow(inputArea, norm_type - 1); + unpooledError %= arma::pow(inputArea, normType - 1); unpooledError /= sum; output(arma::span(i, i + rStep - 1 - offset), arma::span(j, j + cStep - 1 - offset)) += unpooledError; @@ -210,8 +210,8 @@ class LpPooling } } - //! Locally-stored norm_type. - size_t norm_type; + //! Locally-stored norm type. + size_t normType; //! Locally-stored width of the pooling window. size_t kernelWidth; diff --git a/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp b/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp index e646796360..0abe08ada6 100644 --- a/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp +++ b/src/mlpack/methods/ann/layer/lp_pooling_impl.hpp @@ -27,12 +27,13 @@ LpPooling::LpPooling() template LpPooling::LpPooling( - const size_t norm_type, + const size_t normType, const size_t kernelWidth, const size_t kernelHeight, const size_t strideWidth, const size_t strideHeight, const bool floor) : + normType(normType), kernelWidth(kernelWidth), kernelHeight(kernelHeight), strideWidth(strideWidth), @@ -121,7 +122,7 @@ void LpPooling::serialize( Archive& ar, const uint32_t /* version */) { - ar(CEREAL_NVP(norm_type)); + ar(CEREAL_NVP(normType)); ar(CEREAL_NVP(kernelWidth)); ar(CEREAL_NVP(kernelHeight)); ar(CEREAL_NVP(strideWidth)); From b0f6470767d9cc6e708169be698a3174f090f0c8 Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Mon, 8 Feb 2021 09:10:00 +0530 Subject: [PATCH 157/253] Update layer_types.hpp --- src/mlpack/methods/ann/layer/layer_types.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/layer_types.hpp b/src/mlpack/methods/ann/layer/layer_types.hpp index d27a5a6d25..091d7ece35 100644 --- a/src/mlpack/methods/ann/layer/layer_types.hpp +++ b/src/mlpack/methods/ann/layer/layer_types.hpp @@ -220,6 +220,7 @@ class AdaptiveMeanPooling; using MoreTypes = boost::variant< Linear3D*, + LpPooling*, Glimpse*, Highway*, MultiheadAttention*, @@ -283,7 +284,6 @@ using LayerTypes = boost::variant< LSTM*, MaxPooling*, MeanPooling*, - LpPooling*, MiniBatchDiscrimination*, MultiplyConstant*, MultiplyMerge*, From 709eb40dbe731a6baab317c4c2361e540e78a02d Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Tue, 9 Feb 2021 02:45:23 +0530 Subject: [PATCH 158/253] minor --- src/mlpack/methods/ann/layer/kmax_pooling.hpp | 310 ++++++++++++++++++ .../methods/ann/layer/kmax_pooling_impl.hpp | 165 ++++++++++ 2 files changed, 475 insertions(+) create mode 100644 src/mlpack/methods/ann/layer/kmax_pooling.hpp create mode 100644 src/mlpack/methods/ann/layer/kmax_pooling_impl.hpp diff --git a/src/mlpack/methods/ann/layer/kmax_pooling.hpp b/src/mlpack/methods/ann/layer/kmax_pooling.hpp new file mode 100644 index 0000000000..098a9d100a --- /dev/null +++ b/src/mlpack/methods/ann/layer/kmax_pooling.hpp @@ -0,0 +1,310 @@ +/** + * @file methods/ann/layer/max_pooling.hpp + * @author Marcus Edel + * @author Nilay Jain + * + * Definition of the MaxPooling class. + * + * 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. + */ +#ifndef MLPACK_METHODS_ANN_LAYER_MAX_POOLING_HPP +#define MLPACK_METHODS_ANN_LAYER_MAX_POOLING_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/* + * The max pooling rule for convolution neural networks. Take the maximum value + * within the receptive block. + */ +class MaxPoolingRule +{ + public: + /* + * Return the maximum value within the receptive block. + * + * @param input Input used to perform the pooling operation. + */ + template + size_t Pooling(const MatType& input) + { + return arma::as_scalar(arma::find(input.max() == input, 1)); + } +}; + +/** + * Implementation of the MaxPooling layer. + * + * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + * @tparam OutputDataType Type of the output data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + */ +template < + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +class MaxPooling +{ + public: + //! Create the MaxPooling object. + MaxPooling(); + + /** + * Create the MaxPooling object using the specified number of units. + * + * @param kernelWidth Width of the pooling window. + * @param kernelHeight Height of the pooling window. + * @param strideWidth Width of the stride operation. + * @param strideHeight Width of the stride operation. + * @param floor Rounding operator (floor or ceil). + */ + MaxPooling(const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth = 1, + const size_t strideHeight = 1, + const bool floor = true); + + /** + * Ordinary feed forward pass of a neural network, evaluating the function + * f(x) by propagating the activity forward through f. + * + * @param input Input data used for evaluating the specified function. + * @param output Resulting output activation. + */ + template + void Forward(const arma::Mat& input, arma::Mat& output); + + /** + * Ordinary feed backward pass of a neural network, using 3rd-order tensors as + * input, calculating the function f(x) by propagating x backwards through f. + * Using the results from the feed forward pass. + * + * @param * (input) The propagated input activation. + * @param gy The backpropagated error. + * @param g The calculated gradient. + */ + template + void Backward(const arma::Mat& /* input */, + const arma::Mat& gy, + arma::Mat& g); + + //! Get the output parameter. + const OutputDataType& OutputParameter() const { return outputParameter; } + //! Modify the output parameter. + OutputDataType& OutputParameter() { return outputParameter; } + + //! Get the delta. + const OutputDataType& Delta() const { return delta; } + //! Modify the delta. + OutputDataType& Delta() { return delta; } + + //! Get the input width. + size_t InputWidth() const { return inputWidth; } + //! Modify the input width. + size_t& InputWidth() { return inputWidth; } + + //! Get the input height. + size_t InputHeight() const { return inputHeight; } + //! Modify the input height. + size_t& InputHeight() { return inputHeight; } + + //! Get the output width. + size_t OutputWidth() const { return outputWidth; } + //! Modify the output width. + size_t& OutputWidth() { return outputWidth; } + + //! Get the output height. + size_t OutputHeight() const { return outputHeight; } + //! Modify the output height. + size_t& OutputHeight() { return outputHeight; } + + //! Get the input size. + size_t InputSize() const { return inSize; } + + //! Get the output size. + size_t OutputSize() const { return outSize; } + + //! Get the kernel width. + size_t KernelWidth() const { return kernelWidth; } + //! Modify the kernel width. + size_t& KernelWidth() { return kernelWidth; } + + //! Get the kernel height. + size_t KernelHeight() const { return kernelHeight; } + //! Modify the kernel height. + size_t& KernelHeight() { return kernelHeight; } + + //! Get the stride width. + size_t StrideWidth() const { return strideWidth; } + //! Modify the stride width. + size_t& StrideWidth() { return strideWidth; } + + //! Get the stride height. + size_t StrideHeight() const { return strideHeight; } + //! Modify the stride height. + size_t& StrideHeight() { return strideHeight; } + + //! Get the value of the rounding operation. + bool Floor() const { return floor; } + //! Modify the value of the rounding operation. + bool& Floor() { return floor; } + + //! Get the value of the deterministic parameter. + bool Deterministic() const { return deterministic; } + //! Modify the value of the deterministic parameter. + bool& Deterministic() { return deterministic; } + + //! Get the size of the weights. + size_t WeightSize() const { return 0; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const uint32_t /* version */); + + private: + /** + * Apply pooling to the input and store the results. + * + * @param input The input to be apply the pooling rule. + * @param output The pooled result. + * @param poolingIndices The pooled indices. + */ + template + void PoolingOperation(const arma::Mat& input, + arma::Mat& output, + arma::Mat& poolingIndices) + { + for (size_t j = 0, colidx = 0; j < output.n_cols; + ++j, colidx += strideHeight) + { + for (size_t i = 0, rowidx = 0; i < output.n_rows; + ++i, rowidx += strideWidth) + { + arma::mat subInput = input( + arma::span(rowidx, rowidx + kernelWidth - 1 - offset), + arma::span(colidx, colidx + kernelHeight - 1 - offset)); + + const size_t idx = pooling.Pooling(subInput); + output(i, j) = subInput(idx); + + if (!deterministic) + { + arma::Mat subIndices = indices(arma::span(rowidx, + rowidx + kernelWidth - 1 - offset), + arma::span(colidx, colidx + kernelHeight - 1 - offset)); + + poolingIndices(i, j) = subIndices(idx); + } + } + } + } + + /** + * Apply unpooling to the input and store the results. + * + * @param error The backward error. + * @param output The pooled result. + * @param poolingIndices The pooled indices. + */ + template + void Unpooling(const arma::Mat& error, + arma::Mat& output, + arma::Mat& poolingIndices) + { + for (size_t i = 0; i < poolingIndices.n_elem; ++i) + { + output(poolingIndices(i)) += error(i); + } + } + + //! Locally-stored width of the pooling window. + size_t kernelWidth; + + //! Locally-stored height of the pooling window. + size_t kernelHeight; + + //! Locally-stored width of the stride operation. + size_t strideWidth; + + //! Locally-stored height of the stride operation. + size_t strideHeight; + + //! Rounding operation used. + bool floor; + + //! Locally-stored number of input channels. + size_t inSize; + + //! Locally-stored number of output channels. + size_t outSize; + + //! Locally-stored reset parameter used to initialize the module once. + bool reset; + + //! Locally-stored input width. + size_t inputWidth; + + //! Locally-stored input height. + size_t inputHeight; + + //! Locally-stored output width. + size_t outputWidth; + + //! Locally-stored output height. + size_t outputHeight; + + //! If true use maximum a posteriori during the forward pass. + bool deterministic; + + //! Locally-stored stored rounding offset. + size_t offset; + + //! Locally-stored number of input units. + size_t batchSize; + + //! Locally-stored output parameter. + arma::cube outputTemp; + + //! Locally-stored transformed input parameter. + arma::cube inputTemp; + + //! Locally-stored transformed output parameter. + arma::cube gTemp; + + //! Locally-stored pooling strategy. + MaxPoolingRule pooling; + + //! Locally-stored delta object. + OutputDataType delta; + + //! Locally-stored gradient object. + OutputDataType gradient; + + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! Locally-stored indices matrix parameter. + arma::Mat indices; + + //! Locally-stored indices column parameter. + arma::Col indicesCol; + + //! Locally-stored pooling indicies. + std::vector poolingIndices; +}; // class MaxPooling + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "max_pooling_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/layer/kmax_pooling_impl.hpp b/src/mlpack/methods/ann/layer/kmax_pooling_impl.hpp new file mode 100644 index 0000000000..cbc17904c4 --- /dev/null +++ b/src/mlpack/methods/ann/layer/kmax_pooling_impl.hpp @@ -0,0 +1,165 @@ +/** + * @file methods/ann/layer/max_pooling_impl.hpp + * @author Marcus Edel + * @author Nilay Jain + * + * Implementation of the MaxPooling class. + * + * 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. + */ +#ifndef MLPACK_METHODS_ANN_LAYER_MAX_POOLING_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_MAX_POOLING_IMPL_HPP + +// In case it hasn't yet been included. +#include "max_pooling.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +MaxPooling::MaxPooling() +{ + // Nothing to do here. +} + +template +MaxPooling::MaxPooling( + const size_t kernelWidth, + const size_t kernelHeight, + const size_t strideWidth, + const size_t strideHeight, + const bool floor) : + kernelWidth(kernelWidth), + kernelHeight(kernelHeight), + strideWidth(strideWidth), + strideHeight(strideHeight), + floor(floor), + inSize(0), + outSize(0), + reset(false), + inputWidth(0), + inputHeight(0), + outputWidth(0), + outputHeight(0), + deterministic(false), + offset(0), + batchSize(0) +{ + // Nothing to do here. +} + +template +template +void MaxPooling::Forward( + const arma::Mat& input, arma::Mat& output) +{ + batchSize = input.n_cols; + inSize = input.n_elem / (inputWidth * inputHeight * batchSize); + inputTemp = arma::cube(const_cast&>(input).memptr(), + inputWidth, inputHeight, batchSize * inSize, false, false); + + if (floor) + { + outputWidth = std::floor((inputWidth - + (double) kernelWidth) / (double) strideWidth + 1); + outputHeight = std::floor((inputHeight - + (double) kernelHeight) / (double) strideHeight + 1); + offset = 0; + } + else + { + outputWidth = std::ceil((inputWidth - + (double) kernelWidth) / (double) strideWidth + 1); + outputHeight = std::ceil((inputHeight - + (double) kernelHeight) / (double) strideHeight + 1); + offset = 1; + } + + outputTemp = arma::zeros >(outputWidth, outputHeight, + batchSize * inSize); + + if (!deterministic) + { + poolingIndices.push_back(outputTemp); + } + + if (!reset) + { + size_t elements = inputWidth * inputHeight; + indicesCol = arma::linspace >(0, (elements - 1), + elements); + + indices = arma::Mat(indicesCol.memptr(), inputWidth, inputHeight); + + reset = true; + } + + for (size_t s = 0; s < inputTemp.n_slices; s++) + { + if (!deterministic) + { + PoolingOperation(inputTemp.slice(s), outputTemp.slice(s), + poolingIndices.back().slice(s)); + } + else + { + PoolingOperation(inputTemp.slice(s), outputTemp.slice(s), + inputTemp.slice(s)); + } + } + + output = arma::Mat(outputTemp.memptr(), outputTemp.n_elem / batchSize, + batchSize); + + outputWidth = outputTemp.n_rows; + outputHeight = outputTemp.n_cols; + outSize = batchSize * inSize; +} + +template +template +void MaxPooling::Backward( + const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) +{ + arma::cube mappedError = arma::cube(((arma::Mat&) gy).memptr(), + outputWidth, outputHeight, outSize, false, false); + + gTemp = arma::zeros(inputTemp.n_rows, + inputTemp.n_cols, inputTemp.n_slices); + + for (size_t s = 0; s < mappedError.n_slices; s++) + { + Unpooling(mappedError.slice(s), gTemp.slice(s), + poolingIndices.back().slice(s)); + } + + poolingIndices.pop_back(); + + g = arma::mat(gTemp.memptr(), gTemp.n_elem / batchSize, batchSize); +} + +template +template +void MaxPooling::serialize( + Archive& ar, + const uint32_t /* version */) +{ + ar(CEREAL_NVP(kernelWidth)); + ar(CEREAL_NVP(kernelHeight)); + ar(CEREAL_NVP(strideWidth)); + ar(CEREAL_NVP(strideHeight)); + ar(CEREAL_NVP(batchSize)); + ar(CEREAL_NVP(floor)); + ar(CEREAL_NVP(inputWidth)); + ar(CEREAL_NVP(inputHeight)); + ar(CEREAL_NVP(outputWidth)); + ar(CEREAL_NVP(outputHeight)); +} + +} // namespace ann +} // namespace mlpack + +#endif From 03115231bc956588ad0815ea44000c5052a8f78a Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Tue, 9 Feb 2021 03:47:23 +0530 Subject: [PATCH 159/253] Implemented ISRLU Activation Function --- src/mlpack/methods/ann/layer/CMakeLists.txt | 2 + src/mlpack/methods/ann/layer/isrlu.hpp | 145 ++++++++++++++++++ src/mlpack/methods/ann/layer/isrlu_impl.hpp | 70 +++++++++ src/mlpack/methods/ann/layer/layer_types.hpp | 2 + .../tests/activation_functions_test.cpp | 64 ++++++++ 5 files changed, 283 insertions(+) create mode 100644 src/mlpack/methods/ann/layer/isrlu.hpp create mode 100644 src/mlpack/methods/ann/layer/isrlu_impl.hpp diff --git a/src/mlpack/methods/ann/layer/CMakeLists.txt b/src/mlpack/methods/ann/layer/CMakeLists.txt index b4726b0c6f..e7894b140b 100644 --- a/src/mlpack/methods/ann/layer/CMakeLists.txt +++ b/src/mlpack/methods/ann/layer/CMakeLists.txt @@ -46,6 +46,8 @@ set(SOURCES hard_tanh_impl.hpp highway.hpp highway_impl.hpp + isrlu.hpp + isrlu_impl.hpp join.hpp join_impl.hpp layer.hpp diff --git a/src/mlpack/methods/ann/layer/isrlu.hpp b/src/mlpack/methods/ann/layer/isrlu.hpp new file mode 100644 index 0000000000..d8fad5be47 --- /dev/null +++ b/src/mlpack/methods/ann/layer/isrlu.hpp @@ -0,0 +1,145 @@ +/** + * @file methods/ann/layer/isrlu.hpp + * @author Abhinav Anand + * + * Definition of the ISRLU activation function as described by Jonathan T. Barron. + * + * For more information, read the following paper. + * + * @code + * @article{ + * author = {Carlile, Brad and Delamarter, Guy and Kinney, Paul and Marti, Akiko and Whitney, Brian}, + * title = {Improving deep learning by inverse square root linear units (ISRLUs)}, + * year = {2017}, + * url = {https://arxiv.org/pdf/1710.09967.pdf} + * } + * @endcode + * + * 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. + */ +#ifndef MLPACK_METHODS_ANN_LAYER_ISRLU_HPP +#define MLPACK_METHODS_ANN_LAYER_ISRLU_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +/** + * The ISRLU activation function, defined by + * + * @f{eqnarray*}{ + * f(x) &=& \left\{ + * \begin{array}{lr} + * x & : x \ge 0 \\ + * x(\frac{1}{1 + \alpha x^2}) & : x < 0 + * \end{array} + * \right. \\ + * f'(x) &=& \left\{ + * \begin{array}{lr} + * x & : 1 \ge 0 \\ + * (\frac{1}{1 + \alpha x^2})^3 & : x < 0 + * \end{array} + * \right. + * @f} + * + * In the deterministic mode, there is no computation of the derivative. + * + * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + * @tparam OutputDataType Type of the output data (arma::colvec, arma::mat, + * arma::sp_mat or arma::cube). + */ +template < + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +class ISRLU +{ + public: + /** + * Create the ISRLU object using the specified parameter. + * + * @param alpha Scale parameter controls the value to which an ISRLU + * saturates for negative inputs. + */ + ISRLU(const double alpha = 1.0); + + /** + * Ordinary feed forward pass of a neural network, evaluating the function + * f(x) by propagating the activity forward through f. + * + * @param input Input data used for evaluating the specified function. + * @param output Resulting output activation. + */ + template + void Forward(const InputType& input, OutputType& output); + + /** + * Ordinary feed backward pass of a neural network, calculating the function + * f(x) by propagating x backwards through f. Using the results from the feed + * forward pass. + * + * @param input The propagated input activation f(x). + * @param gy The backpropagated error. + * @param g The calculated gradient. + */ + template + void Backward(const DataType& input, const DataType& gy, DataType& g); + + //! Get the output parameter. + OutputDataType const& OutputParameter() const { return outputParameter; } + //! Modify the output parameter. + OutputDataType& OutputParameter() { return outputParameter; } + + //! Get the delta. + OutputDataType const& Delta() const { return delta; } + //! Modify the delta. + OutputDataType& Delta() { return delta; } + + //! Get the non zero gradient. + double const& Alpha() const { return alpha; } + //! Modify the non zero gradient. + double& Alpha() { return alpha; } + + //! Get the value of deterministic parameter. + bool Deterministic() const { return deterministic; } + //! Modify the value of deterministic parameter. + bool& Deterministic() { return deterministic; } + + //! Get size of weights. + size_t WeightSize() { return 0; } + + /** + * Serialize the layer. + */ + template + void serialize(Archive& ar, const uint32_t /* version */); + + private: + //! Locally-stored delta object. + OutputDataType delta; + + //! Locally-stored output parameter object. + OutputDataType outputParameter; + + //! Locally stored first derivative of the activation function. + arma::mat derivative; + + //! ISRLU Hyperparameter (alpha > 0). + double alpha; + + //! If true the derivative computation is disabled, see notes above. + bool deterministic; +}; // class ISRLU + +} // namespace ann +} // namespace mlpack + +// Include implementation. +#include "isrlu_impl.hpp" + +#endif diff --git a/src/mlpack/methods/ann/layer/isrlu_impl.hpp b/src/mlpack/methods/ann/layer/isrlu_impl.hpp new file mode 100644 index 0000000000..2774f6bb12 --- /dev/null +++ b/src/mlpack/methods/ann/layer/isrlu_impl.hpp @@ -0,0 +1,70 @@ +/** + * @file methods/ann/layer/isrlu_impl.hpp + * @author Gaurav Singh + * + * Implementation of the ISRLU activation function as described by Jonathan T. Barron. + * + * 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. + */ +#ifndef MLPACK_METHODS_ANN_LAYER_ISRLU_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_V_IMPL_HPP + +// In case it hasn't yet been included. +#include "isrlu.hpp" + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { + +template +ISRLU::ISRLU(const double alpha) : + alpha(alpha), + deterministic(false) +{} + +template +template +void ISRLU::Forward( + const InputType& input, OutputType& output) +{ + output = arma::ones(arma::size(input)); + for (size_t i = 0; i < input.n_elem; ++i) + { + output(i) = (input(i) >= 0) ? input(i) : input(i) * + (1 / std::sqrt(1 + alpha*input(i)*input(i))); + } + + if (!deterministic) + { + derivative.set_size(arma::size(input)); + for (size_t i = 0; i < input.n_elem; ++i) + { + derivative(i) = (input(i) >= 0) ? 1 : + std:pow(1 / std::sqrt(1 + alpha*input(i)*input(i)), 3); + } + } +} + +template +template +void ISRLU::Backward( + const DataType& /* input */, const DataType& gy, DataType& g) +{ + g = gy % derivative; +} + +template +template +void ISRLU::serialize( + Archive& ar, + const uint32_t /* version */) +{ + ar(CEREAL_NVP(alpha)); +} + +} // namespace ann +} // namespace mlpack + +#endif diff --git a/src/mlpack/methods/ann/layer/layer_types.hpp b/src/mlpack/methods/ann/layer/layer_types.hpp index 1d7fd0ccba..72c3df52ce 100644 --- a/src/mlpack/methods/ann/layer/layer_types.hpp +++ b/src/mlpack/methods/ann/layer/layer_types.hpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -272,6 +273,7 @@ using LayerTypes = boost::variant< FlexibleReLU*, GRU*, HardTanH*, + ISRLU*, Join*, LayerNorm*, LeakyReLU*, diff --git a/src/mlpack/tests/activation_functions_test.cpp b/src/mlpack/tests/activation_functions_test.cpp index d88c0a5109..3ac6437cd0 100644 --- a/src/mlpack/tests/activation_functions_test.cpp +++ b/src/mlpack/tests/activation_functions_test.cpp @@ -558,6 +558,54 @@ void CheckCELUDerivativeCorrect(const arma::colvec input, } } +/** + * Implementation of the ISRLU activation function test. The function is + * implemented as ISRLU layer in the file isrlu.hpp. + * + * @param input Input data used for evaluating the ISRLU activation function. + * @param target Target data used to evaluate the ISRLU activation. + */ +void CheckISRLUActivationCorrect(const arma::colvec input, + const arma::colvec target) +{ + // Initialize ISRLU object with alpha = 1.0. + ISRLU<> lrf(1.0); + + // Test the activation function using the entire vector as input. + arma::colvec activations; + lrf.Forward(input, activations); + for (size_t i = 0; i < activations.n_elem; ++i) + { + REQUIRE(activations.at(i) == Approx(target.at(i)).epsilon(1e-5)); + } +} + +/** + * Implementation of the ISRLU activation function derivative test. The function + * is implemented as ISRLU layer in the file isrlu.hpp. + * + * @param input Input data used for evaluating the ISRLU activation function. + * @param target Target data used to evaluate the ISRLU activation. + */ +void CheckISRLUDerivativeCorrect(const arma::colvec input, + const arma::colvec target) +{ + // Initialize ISRLU object with alpha = 1.0. + ISRLU<> lrf(1.0); + + // Test the calculation of the derivatives using the entire vector as input. + arma::colvec derivatives, activations; + + // This error vector will be set to 1 to get the derivatives. + arma::colvec error = arma::ones(input.n_elem); + lrf.Forward(input, activations); + lrf.Backward(activations, error, derivatives); + for (size_t i = 0; i < derivatives.n_elem; ++i) + { + REQUIRE(derivatives.at(i) == Approx(target.at(i)).epsilon(1e-5)); + } +} + /** * Implementation of the Softmin activation function test. The function is * implemented as Softmin layer in the file softmin.hpp. @@ -991,6 +1039,22 @@ TEST_CASE("CELUFunctionTest", "[ActivationFunctionsTest]") CheckCELUDerivativeCorrect(desiredActivations, desiredDerivatives); } +/** + * Basic test of the ISRLU activation function. + */ +TEST_CASE("ISRLUFunctionTest", "[ActivationFunctionsTest]") +{ + const arma::colvec desiredActivations("-0.89442719 3.2 4.5 \ + -0.99995020 1 -0.70710678 2 0"); + + const arma::colvec desiredDerivatives("0.74535599 1 1 \ + 0.70712438 1 \ + 0.81649658 1 1"); + + CheckISRLUActivationCorrect(activationData, desiredActivations); + CheckISRLUDerivativeCorrect(desiredActivations, desiredDerivatives); +} + /** * Basic test of the inverse quadratic function. */ From 638be09256da8c3e93e54c06c5f9b0e0cbcec61b Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Tue, 9 Feb 2021 03:58:31 +0530 Subject: [PATCH 160/253] minor change --- src/mlpack/methods/ann/layer/isrlu_impl.hpp | 2 +- src/mlpack/methods/ann/layer/kmax_pooling.hpp | 310 ------------------ .../methods/ann/layer/kmax_pooling_impl.hpp | 165 ---------- 3 files changed, 1 insertion(+), 476 deletions(-) delete mode 100644 src/mlpack/methods/ann/layer/kmax_pooling.hpp delete mode 100644 src/mlpack/methods/ann/layer/kmax_pooling_impl.hpp diff --git a/src/mlpack/methods/ann/layer/isrlu_impl.hpp b/src/mlpack/methods/ann/layer/isrlu_impl.hpp index 2774f6bb12..8e74241305 100644 --- a/src/mlpack/methods/ann/layer/isrlu_impl.hpp +++ b/src/mlpack/methods/ann/layer/isrlu_impl.hpp @@ -1,6 +1,6 @@ /** * @file methods/ann/layer/isrlu_impl.hpp - * @author Gaurav Singh + * @author Abhinav Anand * * Implementation of the ISRLU activation function as described by Jonathan T. Barron. * diff --git a/src/mlpack/methods/ann/layer/kmax_pooling.hpp b/src/mlpack/methods/ann/layer/kmax_pooling.hpp deleted file mode 100644 index 098a9d100a..0000000000 --- a/src/mlpack/methods/ann/layer/kmax_pooling.hpp +++ /dev/null @@ -1,310 +0,0 @@ -/** - * @file methods/ann/layer/max_pooling.hpp - * @author Marcus Edel - * @author Nilay Jain - * - * Definition of the MaxPooling class. - * - * 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. - */ -#ifndef MLPACK_METHODS_ANN_LAYER_MAX_POOLING_HPP -#define MLPACK_METHODS_ANN_LAYER_MAX_POOLING_HPP - -#include - -namespace mlpack { -namespace ann /** Artificial Neural Network. */ { - -/* - * The max pooling rule for convolution neural networks. Take the maximum value - * within the receptive block. - */ -class MaxPoolingRule -{ - public: - /* - * Return the maximum value within the receptive block. - * - * @param input Input used to perform the pooling operation. - */ - template - size_t Pooling(const MatType& input) - { - return arma::as_scalar(arma::find(input.max() == input, 1)); - } -}; - -/** - * Implementation of the MaxPooling layer. - * - * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, - * arma::sp_mat or arma::cube). - * @tparam OutputDataType Type of the output data (arma::colvec, arma::mat, - * arma::sp_mat or arma::cube). - */ -template < - typename InputDataType = arma::mat, - typename OutputDataType = arma::mat -> -class MaxPooling -{ - public: - //! Create the MaxPooling object. - MaxPooling(); - - /** - * Create the MaxPooling object using the specified number of units. - * - * @param kernelWidth Width of the pooling window. - * @param kernelHeight Height of the pooling window. - * @param strideWidth Width of the stride operation. - * @param strideHeight Width of the stride operation. - * @param floor Rounding operator (floor or ceil). - */ - MaxPooling(const size_t kernelWidth, - const size_t kernelHeight, - const size_t strideWidth = 1, - const size_t strideHeight = 1, - const bool floor = true); - - /** - * Ordinary feed forward pass of a neural network, evaluating the function - * f(x) by propagating the activity forward through f. - * - * @param input Input data used for evaluating the specified function. - * @param output Resulting output activation. - */ - template - void Forward(const arma::Mat& input, arma::Mat& output); - - /** - * Ordinary feed backward pass of a neural network, using 3rd-order tensors as - * input, calculating the function f(x) by propagating x backwards through f. - * Using the results from the feed forward pass. - * - * @param * (input) The propagated input activation. - * @param gy The backpropagated error. - * @param g The calculated gradient. - */ - template - void Backward(const arma::Mat& /* input */, - const arma::Mat& gy, - arma::Mat& g); - - //! Get the output parameter. - const OutputDataType& OutputParameter() const { return outputParameter; } - //! Modify the output parameter. - OutputDataType& OutputParameter() { return outputParameter; } - - //! Get the delta. - const OutputDataType& Delta() const { return delta; } - //! Modify the delta. - OutputDataType& Delta() { return delta; } - - //! Get the input width. - size_t InputWidth() const { return inputWidth; } - //! Modify the input width. - size_t& InputWidth() { return inputWidth; } - - //! Get the input height. - size_t InputHeight() const { return inputHeight; } - //! Modify the input height. - size_t& InputHeight() { return inputHeight; } - - //! Get the output width. - size_t OutputWidth() const { return outputWidth; } - //! Modify the output width. - size_t& OutputWidth() { return outputWidth; } - - //! Get the output height. - size_t OutputHeight() const { return outputHeight; } - //! Modify the output height. - size_t& OutputHeight() { return outputHeight; } - - //! Get the input size. - size_t InputSize() const { return inSize; } - - //! Get the output size. - size_t OutputSize() const { return outSize; } - - //! Get the kernel width. - size_t KernelWidth() const { return kernelWidth; } - //! Modify the kernel width. - size_t& KernelWidth() { return kernelWidth; } - - //! Get the kernel height. - size_t KernelHeight() const { return kernelHeight; } - //! Modify the kernel height. - size_t& KernelHeight() { return kernelHeight; } - - //! Get the stride width. - size_t StrideWidth() const { return strideWidth; } - //! Modify the stride width. - size_t& StrideWidth() { return strideWidth; } - - //! Get the stride height. - size_t StrideHeight() const { return strideHeight; } - //! Modify the stride height. - size_t& StrideHeight() { return strideHeight; } - - //! Get the value of the rounding operation. - bool Floor() const { return floor; } - //! Modify the value of the rounding operation. - bool& Floor() { return floor; } - - //! Get the value of the deterministic parameter. - bool Deterministic() const { return deterministic; } - //! Modify the value of the deterministic parameter. - bool& Deterministic() { return deterministic; } - - //! Get the size of the weights. - size_t WeightSize() const { return 0; } - - /** - * Serialize the layer. - */ - template - void serialize(Archive& ar, const uint32_t /* version */); - - private: - /** - * Apply pooling to the input and store the results. - * - * @param input The input to be apply the pooling rule. - * @param output The pooled result. - * @param poolingIndices The pooled indices. - */ - template - void PoolingOperation(const arma::Mat& input, - arma::Mat& output, - arma::Mat& poolingIndices) - { - for (size_t j = 0, colidx = 0; j < output.n_cols; - ++j, colidx += strideHeight) - { - for (size_t i = 0, rowidx = 0; i < output.n_rows; - ++i, rowidx += strideWidth) - { - arma::mat subInput = input( - arma::span(rowidx, rowidx + kernelWidth - 1 - offset), - arma::span(colidx, colidx + kernelHeight - 1 - offset)); - - const size_t idx = pooling.Pooling(subInput); - output(i, j) = subInput(idx); - - if (!deterministic) - { - arma::Mat subIndices = indices(arma::span(rowidx, - rowidx + kernelWidth - 1 - offset), - arma::span(colidx, colidx + kernelHeight - 1 - offset)); - - poolingIndices(i, j) = subIndices(idx); - } - } - } - } - - /** - * Apply unpooling to the input and store the results. - * - * @param error The backward error. - * @param output The pooled result. - * @param poolingIndices The pooled indices. - */ - template - void Unpooling(const arma::Mat& error, - arma::Mat& output, - arma::Mat& poolingIndices) - { - for (size_t i = 0; i < poolingIndices.n_elem; ++i) - { - output(poolingIndices(i)) += error(i); - } - } - - //! Locally-stored width of the pooling window. - size_t kernelWidth; - - //! Locally-stored height of the pooling window. - size_t kernelHeight; - - //! Locally-stored width of the stride operation. - size_t strideWidth; - - //! Locally-stored height of the stride operation. - size_t strideHeight; - - //! Rounding operation used. - bool floor; - - //! Locally-stored number of input channels. - size_t inSize; - - //! Locally-stored number of output channels. - size_t outSize; - - //! Locally-stored reset parameter used to initialize the module once. - bool reset; - - //! Locally-stored input width. - size_t inputWidth; - - //! Locally-stored input height. - size_t inputHeight; - - //! Locally-stored output width. - size_t outputWidth; - - //! Locally-stored output height. - size_t outputHeight; - - //! If true use maximum a posteriori during the forward pass. - bool deterministic; - - //! Locally-stored stored rounding offset. - size_t offset; - - //! Locally-stored number of input units. - size_t batchSize; - - //! Locally-stored output parameter. - arma::cube outputTemp; - - //! Locally-stored transformed input parameter. - arma::cube inputTemp; - - //! Locally-stored transformed output parameter. - arma::cube gTemp; - - //! Locally-stored pooling strategy. - MaxPoolingRule pooling; - - //! Locally-stored delta object. - OutputDataType delta; - - //! Locally-stored gradient object. - OutputDataType gradient; - - //! Locally-stored output parameter object. - OutputDataType outputParameter; - - //! Locally-stored indices matrix parameter. - arma::Mat indices; - - //! Locally-stored indices column parameter. - arma::Col indicesCol; - - //! Locally-stored pooling indicies. - std::vector poolingIndices; -}; // class MaxPooling - -} // namespace ann -} // namespace mlpack - -// Include implementation. -#include "max_pooling_impl.hpp" - -#endif diff --git a/src/mlpack/methods/ann/layer/kmax_pooling_impl.hpp b/src/mlpack/methods/ann/layer/kmax_pooling_impl.hpp deleted file mode 100644 index cbc17904c4..0000000000 --- a/src/mlpack/methods/ann/layer/kmax_pooling_impl.hpp +++ /dev/null @@ -1,165 +0,0 @@ -/** - * @file methods/ann/layer/max_pooling_impl.hpp - * @author Marcus Edel - * @author Nilay Jain - * - * Implementation of the MaxPooling class. - * - * 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. - */ -#ifndef MLPACK_METHODS_ANN_LAYER_MAX_POOLING_IMPL_HPP -#define MLPACK_METHODS_ANN_LAYER_MAX_POOLING_IMPL_HPP - -// In case it hasn't yet been included. -#include "max_pooling.hpp" - -namespace mlpack { -namespace ann /** Artificial Neural Network. */ { - -template -MaxPooling::MaxPooling() -{ - // Nothing to do here. -} - -template -MaxPooling::MaxPooling( - const size_t kernelWidth, - const size_t kernelHeight, - const size_t strideWidth, - const size_t strideHeight, - const bool floor) : - kernelWidth(kernelWidth), - kernelHeight(kernelHeight), - strideWidth(strideWidth), - strideHeight(strideHeight), - floor(floor), - inSize(0), - outSize(0), - reset(false), - inputWidth(0), - inputHeight(0), - outputWidth(0), - outputHeight(0), - deterministic(false), - offset(0), - batchSize(0) -{ - // Nothing to do here. -} - -template -template -void MaxPooling::Forward( - const arma::Mat& input, arma::Mat& output) -{ - batchSize = input.n_cols; - inSize = input.n_elem / (inputWidth * inputHeight * batchSize); - inputTemp = arma::cube(const_cast&>(input).memptr(), - inputWidth, inputHeight, batchSize * inSize, false, false); - - if (floor) - { - outputWidth = std::floor((inputWidth - - (double) kernelWidth) / (double) strideWidth + 1); - outputHeight = std::floor((inputHeight - - (double) kernelHeight) / (double) strideHeight + 1); - offset = 0; - } - else - { - outputWidth = std::ceil((inputWidth - - (double) kernelWidth) / (double) strideWidth + 1); - outputHeight = std::ceil((inputHeight - - (double) kernelHeight) / (double) strideHeight + 1); - offset = 1; - } - - outputTemp = arma::zeros >(outputWidth, outputHeight, - batchSize * inSize); - - if (!deterministic) - { - poolingIndices.push_back(outputTemp); - } - - if (!reset) - { - size_t elements = inputWidth * inputHeight; - indicesCol = arma::linspace >(0, (elements - 1), - elements); - - indices = arma::Mat(indicesCol.memptr(), inputWidth, inputHeight); - - reset = true; - } - - for (size_t s = 0; s < inputTemp.n_slices; s++) - { - if (!deterministic) - { - PoolingOperation(inputTemp.slice(s), outputTemp.slice(s), - poolingIndices.back().slice(s)); - } - else - { - PoolingOperation(inputTemp.slice(s), outputTemp.slice(s), - inputTemp.slice(s)); - } - } - - output = arma::Mat(outputTemp.memptr(), outputTemp.n_elem / batchSize, - batchSize); - - outputWidth = outputTemp.n_rows; - outputHeight = outputTemp.n_cols; - outSize = batchSize * inSize; -} - -template -template -void MaxPooling::Backward( - const arma::Mat& /* input */, const arma::Mat& gy, arma::Mat& g) -{ - arma::cube mappedError = arma::cube(((arma::Mat&) gy).memptr(), - outputWidth, outputHeight, outSize, false, false); - - gTemp = arma::zeros(inputTemp.n_rows, - inputTemp.n_cols, inputTemp.n_slices); - - for (size_t s = 0; s < mappedError.n_slices; s++) - { - Unpooling(mappedError.slice(s), gTemp.slice(s), - poolingIndices.back().slice(s)); - } - - poolingIndices.pop_back(); - - g = arma::mat(gTemp.memptr(), gTemp.n_elem / batchSize, batchSize); -} - -template -template -void MaxPooling::serialize( - Archive& ar, - const uint32_t /* version */) -{ - ar(CEREAL_NVP(kernelWidth)); - ar(CEREAL_NVP(kernelHeight)); - ar(CEREAL_NVP(strideWidth)); - ar(CEREAL_NVP(strideHeight)); - ar(CEREAL_NVP(batchSize)); - ar(CEREAL_NVP(floor)); - ar(CEREAL_NVP(inputWidth)); - ar(CEREAL_NVP(inputHeight)); - ar(CEREAL_NVP(outputWidth)); - ar(CEREAL_NVP(outputHeight)); -} - -} // namespace ann -} // namespace mlpack - -#endif From 43fb21edcc9bf264b2ba634642d8d60b99c3c3c5 Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Tue, 9 Feb 2021 09:24:58 +0530 Subject: [PATCH 161/253] Minor code quality changes --- src/mlpack/methods/ann/layer/isrlu.hpp | 3 ++- src/mlpack/methods/ann/layer/isrlu_impl.hpp | 4 ++-- src/mlpack/tests/activation_functions_test.cpp | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/ann/layer/isrlu.hpp b/src/mlpack/methods/ann/layer/isrlu.hpp index d8fad5be47..7d8eda954b 100644 --- a/src/mlpack/methods/ann/layer/isrlu.hpp +++ b/src/mlpack/methods/ann/layer/isrlu.hpp @@ -8,7 +8,8 @@ * * @code * @article{ - * author = {Carlile, Brad and Delamarter, Guy and Kinney, Paul and Marti, Akiko and Whitney, Brian}, + * author = {Carlile, Brad and Delamarter, Guy and Kinney, Paul and Marti, + * Akiko and Whitney, Brian}, * title = {Improving deep learning by inverse square root linear units (ISRLUs)}, * year = {2017}, * url = {https://arxiv.org/pdf/1710.09967.pdf} diff --git a/src/mlpack/methods/ann/layer/isrlu_impl.hpp b/src/mlpack/methods/ann/layer/isrlu_impl.hpp index 8e74241305..651f1f1a28 100644 --- a/src/mlpack/methods/ann/layer/isrlu_impl.hpp +++ b/src/mlpack/methods/ann/layer/isrlu_impl.hpp @@ -10,7 +10,7 @@ * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ #ifndef MLPACK_METHODS_ANN_LAYER_ISRLU_IMPL_HPP -#define MLPACK_METHODS_ANN_LAYER_V_IMPL_HPP +#define MLPACK_METHODS_ANN_LAYER_ISRLU_IMPL_HPP // In case it hasn't yet been included. #include "isrlu.hpp" @@ -42,7 +42,7 @@ void ISRLU::Forward( for (size_t i = 0; i < input.n_elem; ++i) { derivative(i) = (input(i) >= 0) ? 1 : - std:pow(1 / std::sqrt(1 + alpha*input(i)*input(i)), 3); + std::pow(1 / std::sqrt(1 + alpha*input(i)*input(i)), 3); } } } diff --git a/src/mlpack/tests/activation_functions_test.cpp b/src/mlpack/tests/activation_functions_test.cpp index 3ac6437cd0..847051cfac 100644 --- a/src/mlpack/tests/activation_functions_test.cpp +++ b/src/mlpack/tests/activation_functions_test.cpp @@ -566,7 +566,7 @@ void CheckCELUDerivativeCorrect(const arma::colvec input, * @param target Target data used to evaluate the ISRLU activation. */ void CheckISRLUActivationCorrect(const arma::colvec input, - const arma::colvec target) + const arma::colvec target) { // Initialize ISRLU object with alpha = 1.0. ISRLU<> lrf(1.0); @@ -588,7 +588,7 @@ void CheckISRLUActivationCorrect(const arma::colvec input, * @param target Target data used to evaluate the ISRLU activation. */ void CheckISRLUDerivativeCorrect(const arma::colvec input, - const arma::colvec target) + const arma::colvec target) { // Initialize ISRLU object with alpha = 1.0. ISRLU<> lrf(1.0); From cf9af9204500433a80e676f0bbacf0e7420442f9 Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Tue, 9 Feb 2021 10:59:05 +0530 Subject: [PATCH 162/253] changed layer_types --- src/mlpack/methods/ann/layer/layer_types.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/layer_types.hpp b/src/mlpack/methods/ann/layer/layer_types.hpp index 72c3df52ce..718dd8c12e 100644 --- a/src/mlpack/methods/ann/layer/layer_types.hpp +++ b/src/mlpack/methods/ann/layer/layer_types.hpp @@ -235,7 +235,8 @@ using MoreTypes = boost::variant< VirtualBatchNorm*, RBF*, BaseLayer*, - PositionalEncoding* + PositionalEncoding*, + ISRLU* >; template @@ -273,7 +274,6 @@ using LayerTypes = boost::variant< FlexibleReLU*, GRU*, HardTanH*, - ISRLU*, Join*, LayerNorm*, LeakyReLU*, From 3c3d936f14dff7801bcd68c3eedf870c091b930d Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Tue, 9 Feb 2021 11:51:31 +0530 Subject: [PATCH 163/253] fixed test case --- src/mlpack/tests/activation_functions_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/tests/activation_functions_test.cpp b/src/mlpack/tests/activation_functions_test.cpp index 847051cfac..642aa84dc4 100644 --- a/src/mlpack/tests/activation_functions_test.cpp +++ b/src/mlpack/tests/activation_functions_test.cpp @@ -1047,9 +1047,9 @@ TEST_CASE("ISRLUFunctionTest", "[ActivationFunctionsTest]") const arma::colvec desiredActivations("-0.89442719 3.2 4.5 \ -0.99995020 1 -0.70710678 2 0"); - const arma::colvec desiredDerivatives("0.74535599 1 1 \ - 0.70712438 1 \ - 0.81649658 1 1"); + const arma::colvec desiredDerivatives("0.41408666 1 1 \ + 0.35357980 1 \ + 0.54433105 1 1"); CheckISRLUActivationCorrect(activationData, desiredActivations); CheckISRLUDerivativeCorrect(desiredActivations, desiredDerivatives); From f2284403dfa82872a6500577aec9adbb53a20262 Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Thu, 11 Feb 2021 01:35:26 +0530 Subject: [PATCH 164/253] Apply suggestions from code review Co-authored-by: kartikdutt18 <39593019+kartikdutt18@users.noreply.github.com> --- src/mlpack/methods/ann/layer/lp_pooling.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/lp_pooling.hpp b/src/mlpack/methods/ann/layer/lp_pooling.hpp index aa0f043c33..8423dda79f 100644 --- a/src/mlpack/methods/ann/layer/lp_pooling.hpp +++ b/src/mlpack/methods/ann/layer/lp_pooling.hpp @@ -172,7 +172,7 @@ class LpPooling arma::span(colidx, colidx + kernelHeight - 1 - offset)); output(i, j) = pow(arma::accu(arma::pow(subInput, - normType)), 1.0/normType); + normType)), 1.0 / normType); } } } @@ -199,7 +199,7 @@ class LpPooling const arma::Mat& inputArea = input(arma::span(i, i + rStep - 1), arma::span(j, j + cStep - 1)); size_t sum = pow(arma::accu(arma::pow(inputArea, normType)), - (normType-1) / normType); + (normType - 1) / normType); unpooledError = arma::Mat(inputArea.n_rows, inputArea.n_cols); unpooledError.fill(error(i / rStep, j / cStep)); unpooledError %= arma::pow(inputArea, normType - 1); From 1160f1f5f2b45440324e1c2e0cc2da153d1340bf Mon Sep 17 00:00:00 2001 From: Ale Presacco Date: Wed, 10 Feb 2021 17:56:26 -0600 Subject: [PATCH 165/253] Update convolution.hpp Adding a description about how the input matrix of the CNN layer should be organized --- src/mlpack/methods/ann/layer/convolution.hpp | 22 ++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/convolution.hpp b/src/mlpack/methods/ann/layer/convolution.hpp index 1571c3e414..2ab22ddbfd 100644 --- a/src/mlpack/methods/ann/layer/convolution.hpp +++ b/src/mlpack/methods/ann/layer/convolution.hpp @@ -29,8 +29,26 @@ namespace ann /** Artificial Neural Network. */ { /** * Implementation of the Convolution class. The Convolution class represents a * single layer of a neural network. - * - * @tparam ForwardConvolutionRule Convolution to perform forward process. + *Example about how to organize the input matrix of the CNN. Say that I pass a matrix M(2744x100) to model.Add>, which I have obtained from "flattening" + *100 images (or Mel cepstral coefficients, if we talk about speech, or whatever you like) of dimension 196x14. In other words, the first 196 columns of each row of M + *will be made of the 196 columns of the first row of each of the 100 images (or Mel cepstral coefficients). Then the next 295 columns of M (196 - 393) will be made + *of the 196 columns of the second row of the 100 images (or Mel cepstral coefficients), etc. I want my input to be 196x14 for, so my add will be something like this: + + *model.Add> + *(1, // Number of input activation maps. + *14, // Number of output activation maps. + *3, // Filter width. + *3, // Filter height. + *1, // Stride along width. + *1, // Stride along height. + *0, // Padding width. + *0, // Padding height. + *196, // Input width. + *14 // Input height. + *); + *By doing so, will recreate the original 196x14 matrix for each image (or Mel cepstral coefficients) that will be used as input for the 14 filters of this example. + +* @tparam ForwardConvolutionRule Convolution to perform forward process. * @tparam BackwardConvolutionRule Convolution to perform backward process. * @tparam GradientConvolutionRule Convolution to calculate gradient. * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, From 1ae6336ab4d49cb56c2f30ae1796542ed5407d99 Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Fri, 12 Feb 2021 05:17:23 +0530 Subject: [PATCH 166/253] Update pixel_shuffle_impl.hpp Updated Cereal_nvp --- .../methods/ann/layer/pixel_shuffle_impl.hpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp index 796ee54071..17c7c93980 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -133,16 +133,17 @@ void PixelShuffle::serialize( Archive& ar, const unsigned int /* version */) { - ar & BOOST_SERIALIZATION_NVP(delta); - ar & BOOST_SERIALIZATION_NVP(outputParameter); - ar & BOOST_SERIALIZATION_NVP(upscaleFactor); - ar & BOOST_SERIALIZATION_NVP(height); - ar & BOOST_SERIALIZATION_NVP(width); - ar & BOOST_SERIALIZATION_NVP(size); - ar & BOOST_SERIALIZATION_NVP(batchSize); - ar & BOOST_SERIALIZATION_NVP(outputHeight); - ar & BOOST_SERIALIZATION_NVP(outputWidth); - ar & BOOST_SERIALIZATION_NVP(sizeOut); + ar(CEREAL_NVP(delta)); + ar(CEREAL_NVP(outputParameter)); + ar(CEREAL_NVP(upscaleFactor)); + ar(CEREAL_NVP(height)); + ar(CEREAL_NVP(width)); + ar(CEREAL_NVP(size)); + ar(CEREAL_NVP(batchSize)); + ar(CEREAL_NVP(outputHeight)); + ar(CEREAL_NVP(outputHeight)); + ar(CEREAL_NVP(outputWidth)); + ar(CEREAL_NVP(sizeOut)); } } // namespace ann From 1aae47ae0b3cc35bb5aff54d9f4a12f4f70a939f Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Fri, 12 Feb 2021 06:36:04 +0530 Subject: [PATCH 167/253] Update layer_types.hpp Added pixel shuffle to more_types --- src/mlpack/methods/ann/layer/layer_types.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/layer_types.hpp b/src/mlpack/methods/ann/layer/layer_types.hpp index 14bac39a81..c1e1987f70 100644 --- a/src/mlpack/methods/ann/layer/layer_types.hpp +++ b/src/mlpack/methods/ann/layer/layer_types.hpp @@ -220,6 +220,7 @@ class AdaptiveMeanPooling; using MoreTypes = boost::variant< Linear3D*, + PixelShuffle*, Glimpse*, Highway*, MultiheadAttention*, @@ -290,7 +291,6 @@ using LayerTypes = boost::variant< NoisyLinear*, Padding*, PReLU*, - PixelShuffle*, Softmax*, SpatialDropout*, TransposedConvolution, From a2da41c0a0aaf38429b7cd06a7cb042a68aae003 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 12 Feb 2021 12:55:15 -0500 Subject: [PATCH 168/253] Update src/mlpack/methods/ann/layer/convolution.hpp --- src/mlpack/methods/ann/layer/convolution.hpp | 50 ++++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/mlpack/methods/ann/layer/convolution.hpp b/src/mlpack/methods/ann/layer/convolution.hpp index 2ab22ddbfd..5459f34733 100644 --- a/src/mlpack/methods/ann/layer/convolution.hpp +++ b/src/mlpack/methods/ann/layer/convolution.hpp @@ -29,26 +29,36 @@ namespace ann /** Artificial Neural Network. */ { /** * Implementation of the Convolution class. The Convolution class represents a * single layer of a neural network. - *Example about how to organize the input matrix of the CNN. Say that I pass a matrix M(2744x100) to model.Add>, which I have obtained from "flattening" - *100 images (or Mel cepstral coefficients, if we talk about speech, or whatever you like) of dimension 196x14. In other words, the first 196 columns of each row of M - *will be made of the 196 columns of the first row of each of the 100 images (or Mel cepstral coefficients). Then the next 295 columns of M (196 - 393) will be made - *of the 196 columns of the second row of the 100 images (or Mel cepstral coefficients), etc. I want my input to be 196x14 for, so my add will be something like this: - - *model.Add> - *(1, // Number of input activation maps. - *14, // Number of output activation maps. - *3, // Filter width. - *3, // Filter height. - *1, // Stride along width. - *1, // Stride along height. - *0, // Padding width. - *0, // Padding height. - *196, // Input width. - *14 // Input height. - *); - *By doing so, will recreate the original 196x14 matrix for each image (or Mel cepstral coefficients) that will be used as input for the 14 filters of this example. - -* @tparam ForwardConvolutionRule Convolution to perform forward process. + * Example usage: + * + * Suppose we want to pass a matrix M (2744x100) to a `Convolution` layer; + * in this example, `M` was obtained from "flattening" 100 images (or Mel + * cepstral coefficients, if we talk about speech, or whatever you like) of + * dimension 196x14. In other words, the first 196 columns of each row of M + * will be made of the 196 columns of the first row of each of the 100 images + * (or Mel cepstral coefficients). Then the next 295 columns of M (196 - 393) + * will be made of the 196 columns of the second row of the 100 images (or Mel + * cepstral coefficients), etc. Given that the size of our 2-D input images is + * 196x14, the parameters for our `Convolution` layer will be something like + * this: + * + * ``` + * Convolution<> c(1, // Number of input activation maps. + * 14, // Number of output activation maps. + * 3, // Filter width. + * 3, // Filter height. + * 1, // Stride along width. + * 1, // Stride along height. + * 0, // Padding width. + * 0, // Padding height. + * 196, // Input width. + * 14); // Input height. + * ``` + * + * This `Convolution<>` layer will treat each column of the input matrix `M` as * a 2-D image (or object) of the original 196x14 size, using this as the input + * for the 14 filters of this example. + * + * @tparam ForwardConvolutionRule Convolution to perform forward process. * @tparam BackwardConvolutionRule Convolution to perform backward process. * @tparam GradientConvolutionRule Convolution to calculate gradient. * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, From efcba7760369c835ad44a2a00105840081f0185a Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Sat, 13 Feb 2021 04:31:06 +0530 Subject: [PATCH 169/253] Update isrlu_impl.hpp Use elementwise multiplication while calculating `output(i)` and used `output(i)` while calculating `derivative(i)` --- src/mlpack/methods/ann/layer/isrlu_impl.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/ann/layer/isrlu_impl.hpp b/src/mlpack/methods/ann/layer/isrlu_impl.hpp index 651f1f1a28..b69ffbf8bb 100644 --- a/src/mlpack/methods/ann/layer/isrlu_impl.hpp +++ b/src/mlpack/methods/ann/layer/isrlu_impl.hpp @@ -32,8 +32,8 @@ void ISRLU::Forward( output = arma::ones(arma::size(input)); for (size_t i = 0; i < input.n_elem; ++i) { - output(i) = (input(i) >= 0) ? input(i) : input(i) * - (1 / std::sqrt(1 + alpha*input(i)*input(i))); + output(i) = (input(i) >= 0) ? input(i) : input(i) % + (1 / std::sqrt(1 + alpha * (input(i) % input(i)))); } if (!deterministic) @@ -42,7 +42,7 @@ void ISRLU::Forward( for (size_t i = 0; i < input.n_elem; ++i) { derivative(i) = (input(i) >= 0) ? 1 : - std::pow(1 / std::sqrt(1 + alpha*input(i)*input(i)), 3); + std::pow(output(i), 3) / std::pow(input(i), 3); } } } From 517a3a5e8d1ccfa75fa90e6e4e2239fa0494585b Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Sun, 14 Feb 2021 12:54:35 +0530 Subject: [PATCH 170/253] Added Hard Swish Function Implementation and Test Skeleton --- .../ann/activation_functions/CMakeLists.txt | 1 + .../hard_swish_function.hpp | 116 ++++++++++++++++++ .../tests/activation_functions_test.cpp | 20 +++ 3 files changed, 137 insertions(+) create mode 100644 src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp diff --git a/src/mlpack/methods/ann/activation_functions/CMakeLists.txt b/src/mlpack/methods/ann/activation_functions/CMakeLists.txt index fd4e765006..d5c0868c1c 100644 --- a/src/mlpack/methods/ann/activation_functions/CMakeLists.txt +++ b/src/mlpack/methods/ann/activation_functions/CMakeLists.txt @@ -19,6 +19,7 @@ set(SOURCES multi_quadratic_function.hpp poisson1_function.hpp gaussian_function.hpp + hard_swish_function.hpp ) # Add directory name to sources. diff --git a/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp b/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp new file mode 100644 index 0000000000..d3526da428 --- /dev/null +++ b/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp @@ -0,0 +1,116 @@ +/** + * @file methods/ann/activation_functions/hard_swish_function.hpp + * @author Anush Kini + * + * Definition and implementation of the Hard Swish function as described by + * Howard A, Sandler M, Chu G, Chen LC, Chen B, Tan M, Wang W, Zhu Y, Pang R, + * Vasudevan V and Le QV. + * For more information, see the following paper. + * + * @code + * @misc{ + * author = {Howard A, Sandler M, Chu G, Chen LC, Chen B, Tan M, Wang W, + * Zhu Y, Pang R, Vasudevan V and Le QV}, + * title = {Searching for MobileNetV3}, + * year = {2019} + * } + * @endcode + * + * 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. + */ +#ifndef MLPACK_METHODS_ANN_ACTIVATION_FUNCTIONS_HARD_SWISH_FUNCTION_HPP +#define MLPACK_METHODS_ANN_ACTIVATION_FUNCTIONS_HARD_SWISH_FUNCTION_HPP + +#include + +namespace mlpack { +namespace ann /** Artificial Neural Network. */ { +/** + * The Hard Swish function, defined by + * + * @f{eqnarray*}{ + * f(x) &=& \begin{cases} + * 0 & x \leq -3\\ + * x & x \geq +3\\ + * \frac{x * (x + 3)}{6} & otherwise\\ + * \end{cases} \\ + * f'(x) &=& \begin{cases} + * 0 & x \leq -3\\ + * 1 & x \geq +3\\ + * \frac{2x + 3}{6} & otherwise\\ + * \end{cases} + * @f} + */ +class HardSwishFunction +{ + public: + /** + * Computes the Hard Swish function. + * + * @param x Input data. + * @return f(x). + */ + static double Fn(const double x) + { + double x2 = x + 3.0; + x2 = x2 > 0.0 ? x2 : 0.0; + x2 = x2 < 6.0 ? x2 : 6.0; + x2 = x * x2 / 6.0; + + return x2; + } + + /** + * Computes the Hard Swish function. + * + * @param x Input data. + * @param y The resulting output activation. + */ + template + static void Fn(const InputVecType &x, OutputVecType &y) + { + y.set_size(size(x)); + + for (size_t i = 0; i < x.n_elem; i++) + y(i) = Fn(x(i)); + } + + /** + * Computes the first derivative of the Hard Swish function. + * + * @param y Input data. + * @return f'(x). + */ + static double Deriv(const double y) + { + if (y <= -3) + return 0; + else if (y >= 3) + return 1; + + return (2*y + 3.0)/6.0; + } + + /** + * Computes the first derivatives of the Hard Swish function. + * + * @param y Input activations. + * @param x The resulting derivatives. + */ + template + static void Deriv(const InputVecType &y, OutputVecType &x) + { + x.set_size(size(y)); + + for (size_t i = 0; i < y.n_elem; i++) + x(i) = Deriv(y(i)); + } +}; // class HardSwishFunction + +} // namespace ann +} // namespace mlpack + +#endif diff --git a/src/mlpack/tests/activation_functions_test.cpp b/src/mlpack/tests/activation_functions_test.cpp index d88c0a5109..f99f9781e8 100644 --- a/src/mlpack/tests/activation_functions_test.cpp +++ b/src/mlpack/tests/activation_functions_test.cpp @@ -1134,3 +1134,23 @@ TEST_CASE("SoftminFunctionTest", "[ActivationFunctionsTest]") CheckSoftminDerivativeCorrect(activationData, desiredDerivatives); } + +/** + * Basic test of the Hard Swish function. + */ +TEST_CASE("HardSwishFunctionTest", "[ActivationFunctionsTest]") +{ + // Randomly generated data. + const arma::colvec activationData("3.6544 -1.9714 -5.2277 1.5448 2.1164"); + + // Calculated from torch.nn.Hardswish. + const arma::colvec desiredActivations("3.6544 -0.3380 0 1.1701 1.8047"); + + // Hand Calculated Values. + const arma::colvec desiredDerivatives("1 "); + + CheckSoftminActivationCorrect(activationData, + desiredActivations); + CheckSoftminDerivativeCorrect(activationData, + desiredDerivatives); +} From 990803af2b4904279c49cd2374e13f2918be21f9 Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Sun, 14 Feb 2021 19:31:57 +0530 Subject: [PATCH 171/253] Fixes for failing test --- src/mlpack/methods/ann/layer/base_layer.hpp | 13 +++++++++++++ src/mlpack/tests/activation_functions_test.cpp | 16 +++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/mlpack/methods/ann/layer/base_layer.hpp b/src/mlpack/methods/ann/layer/base_layer.hpp index 8429c818a7..ae49f30fe6 100644 --- a/src/mlpack/methods/ann/layer/base_layer.hpp +++ b/src/mlpack/methods/ann/layer/base_layer.hpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace mlpack { namespace ann /** Artificial Neural Network. */ { @@ -50,6 +51,7 @@ namespace ann /** Artificial Neural Network. */ { * - ELiSHLayer * - ElliotLayer * - GaussianLayer + * - HardSwishLayer * * @tparam ActivationFunction Activation function used for the embedding layer. * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, @@ -277,6 +279,17 @@ template < using GaussianFunctionLayer = BaseLayer< ActivationFunction, InputDataType, OutputDataType>; +/** + * Standard HardSwish-Layer using the HardSwish activation function. + */ +template < + class ActivationFunction = HardSwishFunction, + typename InputDataType = arma::mat, + typename OutputDataType = arma::mat +> +using HardSwishFunctionLayer = BaseLayer< + ActivationFunction, InputDataType, OutputDataType>; + } // namespace ann } // namespace mlpack diff --git a/src/mlpack/tests/activation_functions_test.cpp b/src/mlpack/tests/activation_functions_test.cpp index f99f9781e8..56682880da 100644 --- a/src/mlpack/tests/activation_functions_test.cpp +++ b/src/mlpack/tests/activation_functions_test.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "catch.hpp" @@ -1143,14 +1144,15 @@ TEST_CASE("HardSwishFunctionTest", "[ActivationFunctionsTest]") // Randomly generated data. const arma::colvec activationData("3.6544 -1.9714 -5.2277 1.5448 2.1164"); - // Calculated from torch.nn.Hardswish. - const arma::colvec desiredActivations("3.6544 -0.3380 0 1.1701 1.8047"); + // Hand Calculated Values. from torch.nn.Hardswish. + const arma::colvec desiredActivations("3.6544 -0.3379636 0.0 \ + 1.1701345 1.8047248"); // Hand Calculated Values. - const arma::colvec desiredDerivatives("1 "); + const arma::colvec desiredDerivatives("1.0 0.38734546 0.5 \ + 0.89004483 1.1015749"); - CheckSoftminActivationCorrect(activationData, - desiredActivations); - CheckSoftminDerivativeCorrect(activationData, - desiredDerivatives); + CheckActivationCorrect(activationData, desiredActivations); + CheckDerivativeCorrect + (desiredActivations, desiredDerivatives); } From 665c750e1f56a12cf014eac180b1862a9b9efaa1 Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Sun, 14 Feb 2021 22:48:25 +0530 Subject: [PATCH 172/253] Some more comment fixes --- .../methods/ann/activation_functions/hard_swish_function.hpp | 2 +- src/mlpack/tests/activation_functions_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp b/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp index d3526da428..f2780aac6e 100644 --- a/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp +++ b/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp @@ -97,7 +97,7 @@ class HardSwishFunction /** * Computes the first derivatives of the Hard Swish function. * - * @param y Input activations. + * @param y Input data. * @param x The resulting derivatives. */ template diff --git a/src/mlpack/tests/activation_functions_test.cpp b/src/mlpack/tests/activation_functions_test.cpp index 56682880da..20631566e9 100644 --- a/src/mlpack/tests/activation_functions_test.cpp +++ b/src/mlpack/tests/activation_functions_test.cpp @@ -1144,7 +1144,7 @@ TEST_CASE("HardSwishFunctionTest", "[ActivationFunctionsTest]") // Randomly generated data. const arma::colvec activationData("3.6544 -1.9714 -5.2277 1.5448 2.1164"); - // Hand Calculated Values. from torch.nn.Hardswish. + // Hand Calculated Values. const arma::colvec desiredActivations("3.6544 -0.3379636 0.0 \ 1.1701345 1.8047248"); From 7b70a820f8511d58ecfabcbcca71b14732ca585b Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Mon, 15 Feb 2021 02:37:02 +0530 Subject: [PATCH 173/253] Code style fix Co-authored-by: kartikdutt18 <39593019+kartikdutt18@users.noreply.github.com> --- src/mlpack/methods/ann/layer/pixel_shuffle.hpp | 1 + src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp | 13 ++++--------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle.hpp index c62b0f0ecb..48d89c2fe2 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle.hpp @@ -50,6 +50,7 @@ class PixelShuffle public: //! Create the PixelShuffle object. PixelShuffle(); + /** * Create the PixelShuffle object using the specified parameters. * The number of input channels should be an integral multiple of the square diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp index 17c7c93980..9edb09c2eb 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -20,15 +20,7 @@ namespace ann /** Artificial Neural Network. */ { template PixelShuffle::PixelShuffle() : - upscaleFactor(0), - height(0), - width(0), - size(0), - batchSize(0), - outputHeight(0), - outputWidth(0), - sizeOut(0), - reset(false) + PixelShuffle(0, 0, 0, 0) { // Nothing to do here. } @@ -65,6 +57,7 @@ void PixelShuffle::Forward( outputWidth = width * upscaleFactor; reset = true; } + output.zeros(outputHeight * outputWidth * sizeOut, batchSize); for (size_t n = 0; n < batchSize; n++) { @@ -90,6 +83,7 @@ void PixelShuffle::Forward( } } } + output.col(n) = outputImage; } } @@ -123,6 +117,7 @@ void PixelShuffle::Backward( } } } + g.col(n) = gImage; } } From 3856cdd00ca20995a06d0f16a20935fde538b60e Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Mon, 15 Feb 2021 10:03:06 +0530 Subject: [PATCH 174/253] Review fixes --- .../methods/ann/activation_functions/hard_swish_function.hpp | 2 +- src/mlpack/tests/activation_functions_test.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp b/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp index f2780aac6e..d308358f31 100644 --- a/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp +++ b/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp @@ -91,7 +91,7 @@ class HardSwishFunction else if (y >= 3) return 1; - return (2*y + 3.0)/6.0; + return (2 * y + 3.0) / 6.0; } /** diff --git a/src/mlpack/tests/activation_functions_test.cpp b/src/mlpack/tests/activation_functions_test.cpp index 20631566e9..5e4c5aa217 100644 --- a/src/mlpack/tests/activation_functions_test.cpp +++ b/src/mlpack/tests/activation_functions_test.cpp @@ -1144,11 +1144,11 @@ TEST_CASE("HardSwishFunctionTest", "[ActivationFunctionsTest]") // Randomly generated data. const arma::colvec activationData("3.6544 -1.9714 -5.2277 1.5448 2.1164"); - // Hand Calculated Values. + // Hand-calculated values. const arma::colvec desiredActivations("3.6544 -0.3379636 0.0 \ 1.1701345 1.8047248"); - // Hand Calculated Values. + // Hand-calculated values. const arma::colvec desiredDerivatives("1.0 0.38734546 0.5 \ 0.89004483 1.1015749"); From 0fe77567948df2aaa1ce711003c2fcdefc49d8cc Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Mon, 15 Feb 2021 10:24:01 +0530 Subject: [PATCH 175/253] Update isrlu_impl.hpp --- src/mlpack/methods/ann/layer/isrlu_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/isrlu_impl.hpp b/src/mlpack/methods/ann/layer/isrlu_impl.hpp index b69ffbf8bb..8ee468849f 100644 --- a/src/mlpack/methods/ann/layer/isrlu_impl.hpp +++ b/src/mlpack/methods/ann/layer/isrlu_impl.hpp @@ -33,7 +33,7 @@ void ISRLU::Forward( for (size_t i = 0; i < input.n_elem; ++i) { output(i) = (input(i) >= 0) ? input(i) : input(i) % - (1 / std::sqrt(1 + alpha * (input(i) % input(i)))); + (1 / arma::sqrt(1 + alpha * (input(i) % input(i)))); } if (!deterministic) @@ -42,7 +42,7 @@ void ISRLU::Forward( for (size_t i = 0; i < input.n_elem; ++i) { derivative(i) = (input(i) >= 0) ? 1 : - std::pow(output(i), 3) / std::pow(input(i), 3); + arma::pow(output(i), 3) / arma::pow(input(i), 3); } } } From e29da13c01d03986dff8f9ef3d502ba48e294362 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Mon, 15 Feb 2021 16:33:30 -0500 Subject: [PATCH 176/253] Update src/mlpack/methods/ann/layer/convolution.hpp Co-authored-by: Marcus Edel --- src/mlpack/methods/ann/layer/convolution.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/convolution.hpp b/src/mlpack/methods/ann/layer/convolution.hpp index 5459f34733..5ea92f37ea 100644 --- a/src/mlpack/methods/ann/layer/convolution.hpp +++ b/src/mlpack/methods/ann/layer/convolution.hpp @@ -55,7 +55,8 @@ namespace ann /** Artificial Neural Network. */ { * 14); // Input height. * ``` * - * This `Convolution<>` layer will treat each column of the input matrix `M` as * a 2-D image (or object) of the original 196x14 size, using this as the input + * This `Convolution<>` layer will treat each column of the input matrix `M` as + * a 2-D image (or object) of the original 196x14 size, using this as the input * for the 14 filters of this example. * * @tparam ForwardConvolutionRule Convolution to perform forward process. From 48deeeb3a6b35cf6c5b14913bc3b2bf915eb834c Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Tue, 16 Feb 2021 04:36:30 +0530 Subject: [PATCH 177/253] Changes % to * --- src/mlpack/methods/ann/layer/isrlu_impl.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/methods/ann/layer/isrlu_impl.hpp b/src/mlpack/methods/ann/layer/isrlu_impl.hpp index 8ee468849f..5d73ce0710 100644 --- a/src/mlpack/methods/ann/layer/isrlu_impl.hpp +++ b/src/mlpack/methods/ann/layer/isrlu_impl.hpp @@ -32,8 +32,8 @@ void ISRLU::Forward( output = arma::ones(arma::size(input)); for (size_t i = 0; i < input.n_elem; ++i) { - output(i) = (input(i) >= 0) ? input(i) : input(i) % - (1 / arma::sqrt(1 + alpha * (input(i) % input(i)))); + output(i) = (input(i) >= 0) ? input(i) : input(i) * + (1 / std::sqrt(1 + alpha * (input(i) * input(i)))); } if (!deterministic) @@ -42,7 +42,7 @@ void ISRLU::Forward( for (size_t i = 0; i < input.n_elem; ++i) { derivative(i) = (input(i) >= 0) ? 1 : - arma::pow(output(i), 3) / arma::pow(input(i), 3); + std::pow(output(i), 3) / std::pow(input(i), 3); } } } From f9fbf4d9b51151f9e92cf892eba2bd483c114ebe Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Wed, 17 Feb 2021 03:21:43 +0530 Subject: [PATCH 178/253] Removed space. Co-authored-by: Marcus Edel --- src/mlpack/methods/ann/layer/isrlu_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/isrlu_impl.hpp b/src/mlpack/methods/ann/layer/isrlu_impl.hpp index 5d73ce0710..5e08aaa707 100644 --- a/src/mlpack/methods/ann/layer/isrlu_impl.hpp +++ b/src/mlpack/methods/ann/layer/isrlu_impl.hpp @@ -33,7 +33,7 @@ void ISRLU::Forward( for (size_t i = 0; i < input.n_elem; ++i) { output(i) = (input(i) >= 0) ? input(i) : input(i) * - (1 / std::sqrt(1 + alpha * (input(i) * input(i)))); + (1 / std::sqrt(1 + alpha * (input(i) * input(i)))); } if (!deterministic) From 1994c4fc419e0623938039389fba90e571e56940 Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Thu, 18 Feb 2021 11:15:15 +0530 Subject: [PATCH 179/253] Fn implementation changed to if else statements --- .../ann/activation_functions/hard_swish_function.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp b/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp index d308358f31..d387e86474 100644 --- a/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp +++ b/src/mlpack/methods/ann/activation_functions/hard_swish_function.hpp @@ -55,12 +55,12 @@ class HardSwishFunction */ static double Fn(const double x) { - double x2 = x + 3.0; - x2 = x2 > 0.0 ? x2 : 0.0; - x2 = x2 < 6.0 ? x2 : 6.0; - x2 = x * x2 / 6.0; + if (x <= -3) + return 0; + else if (x >= 3) + return x; - return x2; + return x * (x + 3) / 6; } /** From f6b626d7178716d2f414647586aabddf223fb43e Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Fri, 19 Feb 2021 03:13:49 +0530 Subject: [PATCH 180/253] Moved derivative to backward --- src/mlpack/methods/ann/layer/isrlu_impl.hpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/mlpack/methods/ann/layer/isrlu_impl.hpp b/src/mlpack/methods/ann/layer/isrlu_impl.hpp index 5e08aaa707..fc022929ad 100644 --- a/src/mlpack/methods/ann/layer/isrlu_impl.hpp +++ b/src/mlpack/methods/ann/layer/isrlu_impl.hpp @@ -35,16 +35,6 @@ void ISRLU::Forward( output(i) = (input(i) >= 0) ? input(i) : input(i) * (1 / std::sqrt(1 + alpha * (input(i) * input(i)))); } - - if (!deterministic) - { - derivative.set_size(arma::size(input)); - for (size_t i = 0; i < input.n_elem; ++i) - { - derivative(i) = (input(i) >= 0) ? 1 : - std::pow(output(i), 3) / std::pow(input(i), 3); - } - } } template @@ -52,6 +42,15 @@ template void ISRLU::Backward( const DataType& /* input */, const DataType& gy, DataType& g) { + if (!deterministic) + { + derivative.set_size(arma::size(input)); + for (size_t i = 0; i < input.n_elem; ++i) + { + derivative(i) = (input(i) >= 0) ? 1 : + std::pow(1 / std::sqrt(1 + alpha*input(i)*input(i)), 3); + } + } g = gy % derivative; } From 4394e99151cb05d4d45a0e5fb507396035c5d3fb Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Fri, 19 Feb 2021 03:15:22 +0530 Subject: [PATCH 181/253] minor change --- src/mlpack/methods/ann/layer/isrlu_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/isrlu_impl.hpp b/src/mlpack/methods/ann/layer/isrlu_impl.hpp index fc022929ad..57f196b3fe 100644 --- a/src/mlpack/methods/ann/layer/isrlu_impl.hpp +++ b/src/mlpack/methods/ann/layer/isrlu_impl.hpp @@ -40,7 +40,7 @@ void ISRLU::Forward( template template void ISRLU::Backward( - const DataType& /* input */, const DataType& gy, DataType& g) + const DataType& input, const DataType& gy, DataType& g) { if (!deterministic) { From f7289b8fd7ae085f87c5c1503c0971608f925f28 Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Fri, 19 Feb 2021 21:37:53 +0530 Subject: [PATCH 182/253] Integrated Anush's Code --- src/mlpack/core/data/split_data.hpp | 93 +++++++++------------------- src/mlpack/tests/split_data_test.cpp | 45 +++----------- 2 files changed, 37 insertions(+), 101 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index e9358d23c9..5d8c6aa720 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -23,6 +23,8 @@ namespace data { * It is recommended to have the input labels between the range [0, n) where n * is the number of different labels. The NormalizeLabels() function in * mlpack::data can be used for this. + * Expects labels to be of type arma::Row<>. + * Throws a runtime error if this is not the case. * Example usage below. This overload places the stratified dataset into the * four output parameters given (trainData, testData, trainLabel, * and testLabel). @@ -52,56 +54,27 @@ namespace data { * @param shuffleData If true, the sample order is shuffled; otherwise, each * sample is visited in linear order. (Default true.) */ -template +template::value> > void StratifiedSplit(const arma::Mat& input, - const arma::Row& inputLabel, + const LabelsType& inputLabel, arma::Mat& trainData, arma::Mat& testData, - arma::Row& trainLabel, - arma::Row& testLabel, + LabelsType& trainLabel, + LabelsType& testLabel, const double testRatio, const bool shuffleData = true) { - /** - * Basic idea: - * Let us say we have to stratify a dataset based on labels: - * 0 0 0 0 0 (5 0s) - * 1 1 1 1 1 1 1 1 1 1 1 (11 1s) - * - * Let our test ratio be 0.2. - * Then, the number of 0 labels in our test set = floor(5 * 0.2) = 1. - * The number of 1 labels in our test set = floor(11 * 0.2) = 2. - * - * In our first pass over the dataset, - * We visit each label and keep count of each label in our 'labelCounts' uvec. - * - * We then take a second pass over the dataset. - * We now maintain an additional uvec 'testLabelCounts' to hold the label - * counts of our test set. - * - * In this pass, when we encounter a label we check the 'testLabelCounts' uvec - * for the count of this label in the test set. - * If this count is less than the required number of labels in the test set, - * we add the data to the test set and increment the label count in the uvec. - * If this count is equal to or more than the required count in the test set, - * we add this data to the train set. - * - * Based on the above steps, we get the following labels in the split set: - * Train set (4 0s, 9 1s) - * 0 0 0 0 - * 1 1 1 1 1 1 1 1 1 - * - * Test set (1 0s, 2 1s) - * 0 - * 1 1 - */ + if (!arma::is_Row::value) + throw std::runtime_error("data::Split(): when stratified sampling is done," + "labels must have type `arma::Row<>`!"); size_t trainIdx = 0; size_t testIdx = 0; size_t trainSize = 0; size_t testSize = 0; arma::uvec labelCounts; arma::uvec testLabelCounts; - U maxLabel = inputLabel.max(); + auto maxLabel = inputLabel.max(); labelCounts.zeros(maxLabel+1); testLabelCounts.zeros(maxLabel+1); @@ -114,7 +87,7 @@ void StratifiedSplit(const arma::Mat& input, order = arma::shuffle(order); } - for (U label : inputLabel) + for (auto label : inputLabel) { ++labelCounts[label]; } @@ -132,7 +105,7 @@ void StratifiedSplit(const arma::Mat& input, for (arma::uword i : order) { - U label = inputLabel[i]; + auto label = inputLabel[i]; if (testLabelCounts[label] < floor(labelCounts[label] * testRatio)) { testLabelCounts[label] += 1; @@ -197,36 +170,26 @@ void Split(const arma::Mat& input, const size_t trainSize = input.n_cols - testSize; trainData.set_size(input.n_rows, trainSize); testData.set_size(input.n_rows, testSize); - trainLabel.set_size(trainSize); - testLabel.set_size(testSize); + arma::uvec order = arma::linspace(0, input.n_cols - 1, + input.n_cols); if (shuffleData) { - arma::uvec order = arma::shuffle(arma::linspace( - 0, input.n_cols - 1, input.n_cols)); - if (trainSize > 0) - { - trainData = input.cols(order.subvec(0, trainSize - 1)); - trainLabel = inputLabel.cols(order.subvec(0, trainSize - 1)); - } - if (trainSize < input.n_cols) - { - testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); - testLabel = inputLabel.cols(order.subvec(trainSize, input.n_cols - 1)); - } + trainLabel.set_size(1, trainSize); + trainData = input.cols(order.subvec(0, trainSize - 1)); + + for (size_t i = 0; i < trainSize; i++) + trainLabel(0, i) = inputLabel(0, order(i)); } else + + if (trainSize < input.n_cols) { - if (trainSize > 0) - { - trainData = input.cols(0, trainSize - 1); - trainLabel = inputLabel.subvec(0, trainSize - 1); - } - if (trainSize < input.n_cols) - { - testData = input.cols(trainSize , input.n_cols - 1); - testLabel = inputLabel.subvec(trainSize , input.n_cols - 1); - } + testLabel.set_size(1, testSize); + testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); + + for (size_t i = trainSize; i < input.n_cols; i++) + testLabel(0, i - trainSize) = inputLabel(0, order(i)); } } @@ -309,7 +272,7 @@ void Split(const arma::Mat& input, * sample is visited in linear order. (Default true). * @param stratifyData If true, the train and test splits are stratified * so that the ratio of each class in the training and test sets is the same - * as in the original dataset. + * as in the original dataset. Expects labels to be of type arma::Row<>. * @return std::tuple containing trainData (arma::Mat), testData * (arma::Mat), trainLabel (arma::Row), and testLabel (arma::Row). */ diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index d3d445796e..41227097f3 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -322,47 +322,20 @@ TEST_CASE("StratifiedSplitDataResultTest", "[SplitDataTest]") CheckMatEqual(input, concat); } + /** - * Check if data is stratified according to labels on a larger data set. - * Example calculation to find resultant number of samples in the train and - * test set: - * - * Since there are 256 0s and the test ratio is 0.3, - * Number of 0s in the test set = 76 ( floor(256 * 0.3) = floor(76.8) ). - * Number of 0s in the train set = 180 ( 256 - 76 ). + * Check that Split() with stratifyData true throws a runtime error if labels + * are not of type arma::Row<>. */ -TEST_CASE("StratifiedSplitLargerDataResultTest", "[SplitDataTest]") +TEST_CASE("StratifiedSplitRunTimeErrorTest", "[SplitDataTest]") { mat input(3, 480); + mat labels(2, 480); input.randu(); + labels.randu(); - // 256 0s, 128 1s, 64 2s and 32 3s. - Row zero_label(256); - Row one_label(128); - Row two_label(64); - Row three_label(32); - - zero_label.fill(0); - one_label.fill(1); - two_label.fill(2); - three_label.fill(3); - - Row labels = arma::join_rows(zero_label, one_label); - labels = arma::join_rows(labels, two_label); - labels = arma::join_rows(labels, three_label); const double test_ratio = 0.3; - const auto value = Split(input, labels, test_ratio, false, true); - REQUIRE(static_cast(find(std::get<2>(value) == 0)).n_rows == 180); - REQUIRE(static_cast(find(std::get<2>(value) == 1)).n_rows == 90); - REQUIRE(static_cast(find(std::get<2>(value) == 2)).n_rows == 45); - REQUIRE(static_cast(find(std::get<2>(value) == 3)).n_rows == 23); - - REQUIRE(static_cast(find(std::get<3>(value) == 0)).n_rows == 76); - REQUIRE(static_cast(find(std::get<3>(value) == 1)).n_rows == 38); - REQUIRE(static_cast(find(std::get<3>(value) == 2)).n_rows == 19); - REQUIRE(static_cast(find(std::get<3>(value) == 3)).n_rows == 9); - - mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); - CheckMatEqual(input, concat); -} + REQUIRE_THROWS_AS(Split(input, labels, test_ratio, false, true), + std::runtime_error); +} \ No newline at end of file From 00778322a60661555cb8200d45e28e218df59528 Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Sat, 20 Feb 2021 16:59:18 +0530 Subject: [PATCH 183/253] Fixed errors and added the accidentally removed testcase --- src/mlpack/core/data/split_data.hpp | 23 +++++++++-------- src/mlpack/tests/split_data_test.cpp | 38 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 5d8c6aa720..a4d10e389d 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -1,3 +1,4 @@ + /** * @file core/data/split_data.hpp * @author Tham Ngap Wei, Keon Kim @@ -174,6 +175,9 @@ void Split(const arma::Mat& input, arma::uvec order = arma::linspace(0, input.n_cols - 1, input.n_cols); if (shuffleData) + order = arma::shuffle(order); + + if (trainSize > 0) { trainLabel.set_size(1, trainSize); trainData = input.cols(order.subvec(0, trainSize - 1)); @@ -181,7 +185,6 @@ void Split(const arma::Mat& input, for (size_t i = 0; i < trainSize; i++) trainLabel(0, i) = inputLabel(0, order(i)); } - else if (trainSize < input.n_cols) { @@ -346,7 +349,7 @@ Split(const arma::Mat& input, * * The input dataset must be of type arma::field. It should have the shape - * (n_rows = 1, n_cols = Number of samples, n_slices = 1) - * + * * NOTE: Here FieldType could be arma::field or arma::field * * @code @@ -385,7 +388,7 @@ void Split(FieldType& input, FieldType& testData, arma::field& testLabels, const double testRatio, - const bool shuffleData = true) + const bool shuffleData = true) { const size_t testSize = static_cast(input.n_cols * testRatio); const size_t trainSize = input.n_cols - testSize; @@ -406,7 +409,7 @@ void Split(FieldType& input, trainData[i] = input(0, order(i)); for (size_t i = 0; i < trainSize; i++) - trainLabels(0, i) = inputLabel[i]; + trainLabels(0, i) = inputLabel(0, order(i)); } if (testSize <= input.n_cols) @@ -416,7 +419,7 @@ void Split(FieldType& input, testLabels.set_size(1, testSize); for (size_t i = trainSize; i < input.n_cols; i++) - testLabels(0, i - trainSize) = inputLabel[i]; + testLabels(0, i - trainSize) = inputLabel(0, order(i)); } } @@ -427,7 +430,7 @@ void Split(FieldType& input, * * The input dataset must be of type arma::field. It should have the shape - * (n_rows = 1, n_cols = Number of samples, n_slices = 1) - * + * * NOTE: Here FieldType could be arma::field or arma::field * * @code @@ -491,7 +494,7 @@ void Split(const FieldType& input, * * The input dataset must be of type arma::field. It should have the shape - * (n_rows = 1, n_cols = Number of samples, n_slices = 1) - * + * * NOTE: Here FieldType could be arma::field or arma::field * * @code @@ -506,7 +509,7 @@ void Split(const FieldType& input, * @param shuffleData If true, the sample order is shuffled; otherwise, each * sample is visited in linear order. (Default true). * @return std::tuple containing trainData (FieldType), testData - * (FieldType), trainLabel (arma::field), and + * (FieldType), trainLabel (arma::field), and * testLabel (arma::field). */ template or arma::field * * @code @@ -576,4 +579,4 @@ Split(const FieldType& input, } // namespace data } // namespace mlpack -#endif +#endif \ No newline at end of file diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index 41227097f3..f6136b8d99 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -322,6 +322,44 @@ TEST_CASE("StratifiedSplitDataResultTest", "[SplitDataTest]") CheckMatEqual(input, concat); } +/** + * Check if data is stratified according to labels on a larger data set. + * Example calculation to find resultant number of samples in the train and + * test set: + * + * Since there are 256 0s and the test ratio is 0.3, + * Number of 0s in the test set = 76 ( floor(256 * 0.3) = floor(76.8) ). + * Number of 0s in the train set = 180 ( 256 - 76 ). + */ +TEST_CASE("StratifiedSplitLargerDataResultTest", "[SplitDataTest]") +{ + mat input(3, 480); + input.randu(); + // 256 0s, 128 1s, 64 2s and 32 3s. + Row zero_label(256); + Row one_label(128); + Row two_label(64); + Row three_label(32); + zero_label.fill(0); + one_label.fill(1); + two_label.fill(2); + three_label.fill(3); + Row labels = arma::join_rows(zero_label, one_label); + labels = arma::join_rows(labels, two_label); + labels = arma::join_rows(labels, three_label); + const double test_ratio = 0.3; + const auto value = Split(input, labels, test_ratio, false, true); + REQUIRE(static_cast(find(std::get<2>(value) == 0)).n_rows == 180); + REQUIRE(static_cast(find(std::get<2>(value) == 1)).n_rows == 90); + REQUIRE(static_cast(find(std::get<2>(value) == 2)).n_rows == 45); + REQUIRE(static_cast(find(std::get<2>(value) == 3)).n_rows == 23); + REQUIRE(static_cast(find(std::get<3>(value) == 0)).n_rows == 76); + REQUIRE(static_cast(find(std::get<3>(value) == 1)).n_rows == 38); + REQUIRE(static_cast(find(std::get<3>(value) == 2)).n_rows == 19); + REQUIRE(static_cast(find(std::get<3>(value) == 3)).n_rows == 9); + mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); + CheckMatEqual(input, concat); +} /** * Check that Split() with stratifyData true throws a runtime error if labels From dfd5f142d80480d4c19f088e832689cca3c8f0eb Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Sun, 21 Feb 2021 20:37:58 +0530 Subject: [PATCH 184/253] fixed test case --- src/mlpack/tests/activation_functions_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/activation_functions_test.cpp b/src/mlpack/tests/activation_functions_test.cpp index 642aa84dc4..2a64068891 100644 --- a/src/mlpack/tests/activation_functions_test.cpp +++ b/src/mlpack/tests/activation_functions_test.cpp @@ -1052,7 +1052,7 @@ TEST_CASE("ISRLUFunctionTest", "[ActivationFunctionsTest]") 0.54433105 1 1"); CheckISRLUActivationCorrect(activationData, desiredActivations); - CheckISRLUDerivativeCorrect(desiredActivations, desiredDerivatives); + CheckISRLUDerivativeCorrect(activationData, desiredDerivatives); } /** From fd201b7d5e31e538af573a35731c98bff74f7948 Mon Sep 17 00:00:00 2001 From: Abhinav Anand Date: Mon, 22 Feb 2021 06:38:37 +0530 Subject: [PATCH 185/253] removed deterministic parameter and improved co --- src/mlpack/methods/ann/layer/isrlu.hpp | 8 -------- src/mlpack/methods/ann/layer/isrlu_impl.hpp | 14 +++++--------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/mlpack/methods/ann/layer/isrlu.hpp b/src/mlpack/methods/ann/layer/isrlu.hpp index 7d8eda954b..b0a786c6ba 100644 --- a/src/mlpack/methods/ann/layer/isrlu.hpp +++ b/src/mlpack/methods/ann/layer/isrlu.hpp @@ -47,7 +47,6 @@ namespace ann /** Artificial Neural Network. */ { * \right. * @f} * - * In the deterministic mode, there is no computation of the derivative. * * @tparam InputDataType Type of the input data (arma::colvec, arma::mat, * arma::sp_mat or arma::cube). @@ -106,11 +105,6 @@ class ISRLU //! Modify the non zero gradient. double& Alpha() { return alpha; } - //! Get the value of deterministic parameter. - bool Deterministic() const { return deterministic; } - //! Modify the value of deterministic parameter. - bool& Deterministic() { return deterministic; } - //! Get size of weights. size_t WeightSize() { return 0; } @@ -133,8 +127,6 @@ class ISRLU //! ISRLU Hyperparameter (alpha > 0). double alpha; - //! If true the derivative computation is disabled, see notes above. - bool deterministic; }; // class ISRLU } // namespace ann diff --git a/src/mlpack/methods/ann/layer/isrlu_impl.hpp b/src/mlpack/methods/ann/layer/isrlu_impl.hpp index 57f196b3fe..a91830f51d 100644 --- a/src/mlpack/methods/ann/layer/isrlu_impl.hpp +++ b/src/mlpack/methods/ann/layer/isrlu_impl.hpp @@ -20,8 +20,7 @@ namespace ann /** Artificial Neural Network. */ { template ISRLU::ISRLU(const double alpha) : - alpha(alpha), - deterministic(false) + alpha(alpha) {} template @@ -42,14 +41,11 @@ template void ISRLU::Backward( const DataType& input, const DataType& gy, DataType& g) { - if (!deterministic) + derivative.set_size(arma::size(input)); + for (size_t i = 0; i < input.n_elem; ++i) { - derivative.set_size(arma::size(input)); - for (size_t i = 0; i < input.n_elem; ++i) - { - derivative(i) = (input(i) >= 0) ? 1 : - std::pow(1 / std::sqrt(1 + alpha*input(i)*input(i)), 3); - } + derivative(i) = (input(i) >= 0) ? 1 : + std::pow(1 / std::sqrt(1 + alpha * input(i) * input(i)), 3); } g = gy % derivative; } From a2db3c92ed682f49d2a4360bf27b42fcb1607dd8 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Mon, 22 Feb 2021 18:26:45 +0530 Subject: [PATCH 186/253] Apply suggestions from code review Co-authored-by: Anush Kini <33577829+Abilityguy@users.noreply.github.com> Co-authored-by: Ryan Curtin --- src/mlpack/core/data/split_data.hpp | 26 +++++++++++++------------- src/mlpack/tests/split_data_test.cpp | 3 +-- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index a4d10e389d..f4a75d871b 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -1,4 +1,3 @@ - /** * @file core/data/split_data.hpp * @author Tham Ngap Wei, Keon Kim @@ -67,7 +66,7 @@ void StratifiedSplit(const arma::Mat& input, const bool shuffleData = true) { if (!arma::is_Row::value) - throw std::runtime_error("data::Split(): when stratified sampling is done," + throw std::runtime_error("data::Split(): when stratified sampling is done, " "labels must have type `arma::Row<>`!"); size_t trainIdx = 0; size_t testIdx = 0; @@ -75,7 +74,7 @@ void StratifiedSplit(const arma::Mat& input, size_t testSize = 0; arma::uvec labelCounts; arma::uvec testLabelCounts; - auto maxLabel = inputLabel.max(); + typename LabelsType::elem_type maxLabel = inputLabel.max(); labelCounts.zeros(maxLabel+1); testLabelCounts.zeros(maxLabel+1); @@ -88,7 +87,7 @@ void StratifiedSplit(const arma::Mat& input, order = arma::shuffle(order); } - for (auto label : inputLabel) + for (typename LabelsType::elem_type label : inputLabel) { ++labelCounts[label]; } @@ -106,7 +105,7 @@ void StratifiedSplit(const arma::Mat& input, for (arma::uword i : order) { - auto label = inputLabel[i]; + typename LabelsType::elem_type label = inputLabel[i]; if (testLabelCounts[label] < floor(labelCounts[label] * testRatio)) { testLabelCounts[label] += 1; @@ -182,7 +181,7 @@ void Split(const arma::Mat& input, trainLabel.set_size(1, trainSize); trainData = input.cols(order.subvec(0, trainSize - 1)); - for (size_t i = 0; i < trainSize; i++) + for (size_t i = 0; i < trainSize; ++i) trainLabel(0, i) = inputLabel(0, order(i)); } @@ -191,7 +190,7 @@ void Split(const arma::Mat& input, testLabel.set_size(1, testSize); testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); - for (size_t i = trainSize; i < input.n_cols; i++) + for (size_t i = trainSize; i < input.n_cols; ++i) testLabel(0, i - trainSize) = inputLabel(0, order(i)); } } @@ -398,6 +397,7 @@ void Split(FieldType& input, arma::uvec order = arma::linspace(0, input.n_cols - 1, input.n_cols); + if (shuffleData) order = arma::shuffle(order); @@ -405,20 +405,20 @@ void Split(FieldType& input, { trainLabels.set_size(1, trainSize); - for (size_t i = 0; i < trainSize; i++) + for (size_t i = 0; i < trainSize; ++i) trainData[i] = input(0, order(i)); - for (size_t i = 0; i < trainSize; i++) + for (size_t i = 0; i < trainSize; ++i) trainLabels(0, i) = inputLabel(0, order(i)); } if (testSize <= input.n_cols) { - for (size_t i = trainSize; i < input.n_cols - 1; i++) + for (size_t i = trainSize; i < input.n_cols - 1; ++i) testData[i - trainSize] = input(0, order(i)); testLabels.set_size(1, testSize); - for (size_t i = trainSize; i < input.n_cols; i++) + for (size_t i = trainSize; i < input.n_cols; ++i) testLabels(0, i - trainSize) = inputLabel(0, order(i)); } } @@ -480,7 +480,7 @@ void Split(const FieldType& input, if (testSize <= input.n_cols) { - for (size_t i = trainSize; i < input.n_cols - 1; i++) + for (size_t i = trainSize; i < input.n_cols - 1; ++i) testData[i - trainSize] = input(0, order(i)); } } @@ -579,4 +579,4 @@ Split(const FieldType& input, } // namespace data } // namespace mlpack -#endif \ No newline at end of file +#endif diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index f6136b8d99..74862469ba 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -144,7 +144,6 @@ TEST_CASE("SplitDataResultField", "[SplitDataTest]") CheckFields(input, concat); } - TEST_CASE("ZeroRatioSplitData", "[SplitDataTest]") { mat input(2, 10); @@ -376,4 +375,4 @@ TEST_CASE("StratifiedSplitRunTimeErrorTest", "[SplitDataTest]") REQUIRE_THROWS_AS(Split(input, labels, test_ratio, false, true), std::runtime_error); -} \ No newline at end of file +} From 1b2ffe201f9139a4dc91c01fcadaee66ebdc56f4 Mon Sep 17 00:00:00 2001 From: Heisenbuug Date: Mon, 22 Feb 2021 19:08:50 +0530 Subject: [PATCH 187/253] Checking --- .../tests/feedforward_network_2_test.cpp | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/mlpack/tests/feedforward_network_2_test.cpp b/src/mlpack/tests/feedforward_network_2_test.cpp index 456367912c..104561cf03 100644 --- a/src/mlpack/tests/feedforward_network_2_test.cpp +++ b/src/mlpack/tests/feedforward_network_2_test.cpp @@ -31,12 +31,12 @@ using namespace mlpack::kmeans; /** * Train and evaluate a model with the specified structure. */ -template -void TestNetwork(ModelType& model, - MatType& trainData, - MatType& trainLabels, - MatType& testData, - MatType& testLabels, +template +void TestNetwork(ModelType &model, + MatType &trainData, + MatType &trainLabels, + MatType &testData, + MatType &testLabels, const size_t maxEpochs, const double classificationErrorThreshold) { @@ -50,7 +50,8 @@ void TestNetwork(ModelType& model, for (size_t i = 0; i < predictionTemp.n_cols; ++i) { prediction(i) = arma::as_scalar(arma::find( - arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1; + arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + + 1; } size_t correct = arma::accu(prediction == testLabels); @@ -65,7 +66,8 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - data::Load("thyroid_train.csv", trainData, true); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot load dataset thyroid_train.csv") arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); @@ -77,7 +79,8 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") } arma::mat testData; - data::Load("thyroid_test.csv", testData, true); + if (!data::Load("thyroid_test.csv", testData)) + FAIL("Cannot load dataset thyroid_test.csv") arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); @@ -99,9 +102,9 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") KMeans<> kmeans; kmeans.Cluster(trainData, 8, centroids); - FFN > model; - model.Add >(trainData.n_rows, 8, centroids); - model.Add >(8, 3); + FFN> model; + model.Add>(trainData.n_rows, 8, centroids); + model.Add>(8, 3); // RBFN neural net with MeanSquaredError. TestNetwork<>(model, trainData, trainLabels1, testData, testLabels, 10, 0.1); @@ -131,9 +134,9 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") KMeans<> kmeans1; kmeans1.Cluster(dataset, 140, centroids1); - FFN > model1; - model1.Add >(dataset.n_rows, 140, centroids1, 4.1); - model1.Add >(140, 2); + FFN> model1; + model1.Add>(dataset.n_rows, 140, centroids1, 4.1); + model1.Add>(140, 2); // RBFN neural net with MeanSquaredError. TestNetwork<>(model1, dataset, labels1, dataset, labels, 10, 0.1); From 1f88bc9630472daf01efaa3ef448a71335208e44 Mon Sep 17 00:00:00 2001 From: Heisenbuug Date: Mon, 22 Feb 2021 20:32:12 +0530 Subject: [PATCH 188/253] Adding FAIL Messages --- .../tests/feedforward_network_2_test.cpp | 35 ++++++----- src/mlpack/tests/feedforward_network_test.cpp | 45 +++++++++----- src/mlpack/tests/io_test.cpp | 18 ++++-- src/mlpack/tests/kfn_test.cpp | 12 ++-- src/mlpack/tests/knn_test.cpp | 6 +- src/mlpack/tests/krann_search_test.cpp | 54 +++++++++++------ src/mlpack/tests/ksinit_test.cpp | 6 +- src/mlpack/tests/lars_test.cpp | 30 ++++++---- src/mlpack/tests/lin_alg_test.cpp | 3 +- src/mlpack/tests/lmnn_test.cpp | 12 ++-- src/mlpack/tests/load_save_test.cpp | 57 ++++++++++++------ src/mlpack/tests/lrsdp_test.cpp | 12 ++-- src/mlpack/tests/lsh_test.cpp | 45 +++++++++----- src/mlpack/tests/matrix_completion_test.cpp | 6 +- src/mlpack/tests/nbc_test.cpp | 60 ++++++++++++------- src/mlpack/tests/nystroem_method_test.cpp | 3 +- src/mlpack/tests/one_hot_encoding_test.cpp | 3 +- src/mlpack/tests/pca_test.cpp | 3 +- src/mlpack/tests/quic_svd_test.cpp | 3 +- src/mlpack/tests/radical_test.cpp | 6 +- src/mlpack/tests/random_forest_test.cpp | 42 ++++++++----- src/mlpack/tests/svd_incremental_test.cpp | 3 +- src/mlpack/tests/svdplusplus_test.cpp | 6 +- 23 files changed, 306 insertions(+), 164 deletions(-) diff --git a/src/mlpack/tests/feedforward_network_2_test.cpp b/src/mlpack/tests/feedforward_network_2_test.cpp index 104561cf03..3a57624d26 100644 --- a/src/mlpack/tests/feedforward_network_2_test.cpp +++ b/src/mlpack/tests/feedforward_network_2_test.cpp @@ -21,7 +21,7 @@ #include #include "catch.hpp" -#include "serialization_catch.hpp" +#include "serialization.hpp" #include "custom_layer.hpp" using namespace mlpack; @@ -31,12 +31,12 @@ using namespace mlpack::kmeans; /** * Train and evaluate a model with the specified structure. */ -template -void TestNetwork(ModelType &model, - MatType &trainData, - MatType &trainLabels, - MatType &testData, - MatType &testLabels, +template +void TestNetwork(ModelType& model, + MatType& trainData, + MatType& trainLabels, + MatType& testData, + MatType& testLabels, const size_t maxEpochs, const double classificationErrorThreshold) { @@ -50,8 +50,7 @@ void TestNetwork(ModelType &model, for (size_t i = 0; i < predictionTemp.n_cols; ++i) { prediction(i) = arma::as_scalar(arma::find( - arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + - 1; + arma::max(predictionTemp.col(i)) == predictionTemp.col(i), 1)) + 1; } size_t correct = arma::accu(prediction == testLabels); @@ -67,7 +66,7 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") // Load the dataset. arma::mat trainData; if (!data::Load("thyroid_train.csv", trainData)) - FAIL("Cannot load dataset thyroid_train.csv") + Fail("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); @@ -80,7 +79,7 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") arma::mat testData; if (!data::Load("thyroid_test.csv", testData)) - FAIL("Cannot load dataset thyroid_test.csv") + Fail("Cannot open thyroid_test.csv"); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); @@ -102,9 +101,9 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") KMeans<> kmeans; kmeans.Cluster(trainData, 8, centroids); - FFN> model; - model.Add>(trainData.n_rows, 8, centroids); - model.Add>(8, 3); + FFN > model; + model.Add >(trainData.n_rows, 8, centroids); + model.Add >(8, 3); // RBFN neural net with MeanSquaredError. TestNetwork<>(model, trainData, trainLabels1, testData, testLabels, 10, 0.1); @@ -134,10 +133,10 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") KMeans<> kmeans1; kmeans1.Cluster(dataset, 140, centroids1); - FFN> model1; - model1.Add>(dataset.n_rows, 140, centroids1, 4.1); - model1.Add>(140, 2); + FFN > model1; + model1.Add >(dataset.n_rows, 140, centroids1, 4.1); + model1.Add >(140, 2); // RBFN neural net with MeanSquaredError. TestNetwork<>(model1, dataset, labels1, dataset, labels, 10, 0.1); -} +} \ No newline at end of file diff --git a/src/mlpack/tests/feedforward_network_test.cpp b/src/mlpack/tests/feedforward_network_test.cpp index 7188f69f50..c7386261bf 100644 --- a/src/mlpack/tests/feedforward_network_test.cpp +++ b/src/mlpack/tests/feedforward_network_test.cpp @@ -107,7 +107,8 @@ TEST_CASE("CheckCopyMovingVanillaNetworkTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - data::Load("thyroid_train.csv", trainData, true); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); @@ -160,13 +161,15 @@ TEST_CASE("FFVanillaNetworkTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - data::Load("thyroid_train.csv", trainData, true); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); arma::mat testData; - data::Load("thyroid_test.csv", testData, true); + if (!data::Load("thyroid_test.csv", testData)) + FAIL("Cannot load dataset thyroid_test.csv"); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); @@ -307,13 +310,15 @@ TEST_CASE("DropoutNetworkTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - data::Load("thyroid_train.csv", trainData, true); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); arma::mat testData; - data::Load("thyroid_test.csv", testData, true); + if (!data::Load("thyroid_test.csv", testData)) + FAIL("Cannot load dataset thyroid_test.csv"); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); @@ -408,13 +413,15 @@ TEST_CASE("DropConnectNetworkTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - data::Load("thyroid_train.csv", trainData, true); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); arma::mat testData; - data::Load("thyroid_test.csv", testData, true); + if (!data::Load("thyroid_test.csv", testData)) + FAIL("Cannot load dataset thyroid_test.csv"); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); @@ -497,13 +504,15 @@ TEST_CASE("FFSerializationTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - data::Load("thyroid_train.csv", trainData, true); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); arma::mat testData; - data::Load("thyroid_test.csv", testData, true); + if (!data::Load("thyroid_test.csv", testData)) + FAIL("Cannot load dataset thyroid_test.csv"); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); @@ -546,13 +555,15 @@ TEST_CASE("CustomLayerTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - data::Load("thyroid_train.csv", trainData, true); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); arma::mat testData; - data::Load("thyroid_test.csv", testData, true); + if (!data::Load("thyroid_test.csv", testData)) + FAIL("Cannot load dataset thyroid_test.csv"); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); @@ -625,13 +636,15 @@ TEST_CASE("FFNTrainReturnObjective", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - data::Load("thyroid_train.csv", trainData, true); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); arma::mat testData; - data::Load("thyroid_test.csv", testData, true); + if (!data::Load("thyroid_test.csv", testData)) + FAIL("Cannot load dataset thyroid_test.csv"); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); @@ -695,13 +708,15 @@ TEST_CASE("OptimizerTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - data::Load("thyroid_train.csv", trainData, true); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); arma::mat testData; - data::Load("thyroid_test.csv", testData, true); + if (!data::Load("thyroid_test.csv", testData)) + FAIL("Cannot load dataset thyroid_test.csv"); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); diff --git a/src/mlpack/tests/io_test.cpp b/src/mlpack/tests/io_test.cpp index fa363face9..26319a8d79 100644 --- a/src/mlpack/tests/io_test.cpp +++ b/src/mlpack/tests/io_test.cpp @@ -413,7 +413,8 @@ TEST_CASE_METHOD(IOTestDestroyer, "OutputColParamTest", // Now load the vector back and make sure it was saved correctly. arma::vec dataset2; - data::Load("test.csv", dataset2); + if (!data::Load("test.csv", dataset2)) + FAIL("Cannot load dataset test.csv"); REQUIRE(dataset.n_rows == dataset2.n_rows); for (size_t i = 0; i < dataset.n_elem; ++i) @@ -461,7 +462,8 @@ TEST_CASE_METHOD(IOTestDestroyer, "OutputUnsignedColParamTest", // Now load the vector back and make sure it was saved correctly. arma::Col dataset2; - data::Load("test.csv", dataset2); + if (!data::Load("test.csv", dataset2)) + FAIL("Cannot load dataset test.csv"); REQUIRE(dataset.n_rows == dataset2.n_rows); for (size_t i = 0; i < dataset.n_elem; ++i) @@ -509,7 +511,8 @@ TEST_CASE_METHOD(IOTestDestroyer, "OutputRowParamTest", // Now load the row vector back and make sure it was saved correctly. arma::rowvec dataset2; - data::Load("test.csv", dataset2); + if (!data::Load("test.csv", dataset2)) + FAIL("Cannot load dataset test.csv"); REQUIRE(dataset.n_cols == dataset2.n_cols); for (size_t i = 0; i < dataset.n_elem; ++i) @@ -556,7 +559,8 @@ TEST_CASE_METHOD(IOTestDestroyer, "OutputUnsignedRowParamTest", "[IOTest]") // Now load the row vector back and make sure it was saved correctly. arma::Row dataset2; - data::Load("test.csv", dataset2); + if (!data::Load("test.csv", dataset2)) + FAIL("Cannot load dataset test.csv"); REQUIRE(dataset.n_cols == dataset2.n_cols); for (size_t i = 0; i < dataset.n_elem; ++i) @@ -784,7 +788,8 @@ TEST_CASE_METHOD(IOTestDestroyer, "OutputMatrixParamTest", // Now load the matrix back and make sure it was saved correctly. arma::mat dataset2; - data::Load("test.csv", dataset2); + if (!data::Load("test.csv", dataset2)) + FAIL("Cannot load dataset test.csv"); REQUIRE(dataset.n_cols == dataset2.n_cols); REQUIRE(dataset.n_rows == dataset2.n_rows); @@ -833,7 +838,8 @@ TEST_CASE_METHOD(IOTestDestroyer, "OutputMatrixNoTransposeParamTest", // Now load the matrix back and make sure it was saved correctly. arma::mat dataset2; - data::Load("test.csv", dataset2, true, false); + if (!data::Load("test.csv", dataset2, false, false)) + FAIL("Cannot load dataset test.csv"); REQUIRE(dataset.n_cols == dataset2.n_cols); REQUIRE(dataset.n_rows == dataset2.n_rows); diff --git a/src/mlpack/tests/kfn_test.cpp b/src/mlpack/tests/kfn_test.cpp index f3fefadb7a..1fb813b2e1 100644 --- a/src/mlpack/tests/kfn_test.cpp +++ b/src/mlpack/tests/kfn_test.cpp @@ -335,7 +335,7 @@ TEST_CASE("KFNDualTreeVsNaive1", "[KFNTest]") // Hard-coded filename: bad? if (!data::Load("test_data_3_1000.csv", dataset)) - FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv"); KFN kfn(dataset); @@ -369,7 +369,7 @@ TEST_CASE("KFNDualTreeVsNaive2", "[KFNTest]") // Hard-coded filename: bad? // Code duplication: also bad! if (!data::Load("test_data_3_1000.csv", dataset)) - FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv"); KFN kfn(dataset); @@ -403,7 +403,7 @@ TEST_CASE("KFNSingleTreeVsNaive", "[KFNTest]") // Hard-coded filename: bad! // Code duplication: also bad! if (!data::Load("test_data_3_1000.csv", dataset)) - FAIL("Cannot load test dataset test_data_3_1000.csv!"); + FAIL("Cannot load test dataset test_data_3_1000.csv"); KFN kfn(dataset, SINGLE_TREE_MODE); @@ -466,7 +466,8 @@ TEST_CASE("KFNSingleCoverTreeTest", "[KFNTest]") TEST_CASE("KFNDualCoverTreeTest", "[KFNTest]") { arma::mat dataset; - data::Load("test_data_3_1000.csv", dataset); + if (!data::Load("test_data_3_1000.csv", dataset)) + FAIL("Cannot load test dataset test_data_3_1000.csv"); KFN tree(dataset); @@ -538,7 +539,8 @@ TEST_CASE("KFNSingleBallTreeTest", "[KFNTest]") TEST_CASE("KFNDualBallTreeTest", "[KFNTest]") { arma::mat dataset; - data::Load("test_data_3_1000.csv", dataset); + if (!data::Load("test_data_3_1000.csv", dataset)) + FAIL("Cannot load test dataset test_data_3_1000.csv"); KFN tree(dataset); diff --git a/src/mlpack/tests/knn_test.cpp b/src/mlpack/tests/knn_test.cpp index 7e84700843..5f151eb4b6 100644 --- a/src/mlpack/tests/knn_test.cpp +++ b/src/mlpack/tests/knn_test.cpp @@ -794,7 +794,8 @@ TEST_CASE("KNNSingleCoverTreeTest", "[KNNTest]") TEST_CASE("KNNDualCoverTreeTest", "[KNNTest]") { arma::mat dataset; - data::Load("test_data_3_1000.csv", dataset); + if (!data::Load("test_data_3_1000.csv", dataset)) + FAIL("Cannot load test dataset test_data_3_1000.csv"); KNN tree(dataset); @@ -865,7 +866,8 @@ TEST_CASE("KNNSingleBallTreeTest", "[KNNTest]") TEST_CASE("KNNDualBallTreeTest", "[KNNTest]") { arma::mat dataset; - data::Load("test_data_3_1000.csv", dataset); + if (!data::Load("test_data_3_1000.csv", dataset)) + FAIL("Cannot load test dataset test_data_3_1000.csv"); KNN tree(dataset); diff --git a/src/mlpack/tests/krann_search_test.cpp b/src/mlpack/tests/krann_search_test.cpp index 4efa022776..5bc13eb952 100644 --- a/src/mlpack/tests/krann_search_test.cpp +++ b/src/mlpack/tests/krann_search_test.cpp @@ -35,13 +35,16 @@ TEST_CASE("NaiveGuaranteeTest", "[KRANNTest]") arma::mat refData; arma::mat queryData; - data::Load("rann_test_r_3_900.csv", refData, true); - data::Load("rann_test_q_3_100.csv", queryData, true); + if (!data::Load("rann_test_r_3_900.csv", refData)) + FAIL("Cannot load dataset rann_test_r_3_900.csv"); + if (!data::Load("rann_test_q_3_100.csv", queryData)) + FAIL("Cannot load dataset rann_test_q_3_100.csv"); RASearch<> rsRann(refData, true, false, 1.0); arma::mat qrRanks; - data::Load("rann_test_qr_ranks.csv", qrRanks, true, false); // No transpose. + if (!data::Load("rann_test_qr_ranks.csv", qrRanks, false, false)) // No transpose. + FAIL("Cannot load dataset rann_test_qr_ranks.csv"); size_t numRounds = 1000; arma::Col numSuccessRounds(queryData.n_cols); @@ -88,8 +91,10 @@ TEST_CASE("SingleTreeSearch", "[KRANNTest]") arma::mat refData; arma::mat queryData; - data::Load("rann_test_r_3_900.csv", refData, true); - data::Load("rann_test_q_3_100.csv", queryData, true); + if (!data::Load("rann_test_r_3_900.csv", refData)) + FAIL("Cannot load dataset rann_test_r_3_900.csv"); + if (!data::Load("rann_test_q_3_100.csv", queryData)) + FAIL("Cannot load dataset rann_test_q_3_100.csv"); // Search for 1 rank-approximate nearest-neighbors in the top 30% of the point // (rank error of 3). @@ -100,7 +105,8 @@ TEST_CASE("SingleTreeSearch", "[KRANNTest]") // The relative ranks for the given query reference pair arma::Mat qrRanks; - data::Load("rann_test_qr_ranks.csv", qrRanks, true, false); // No transpose. + if (!data::Load("rann_test_qr_ranks.csv", qrRanks, false, false)) // No transpose. + FAIL("Cannot load dataset rann_test_qr_ranks.csv"); size_t numRounds = 1000; arma::Col numSuccessRounds(queryData.n_cols); @@ -147,8 +153,10 @@ TEST_CASE("DualTreeSearch", "[KRANNTest]") arma::mat refData; arma::mat queryData; - data::Load("rann_test_r_3_900.csv", refData, true); - data::Load("rann_test_q_3_100.csv", queryData, true); + if (!data::Load("rann_test_r_3_900.csv", refData)) + FAIL("Cannot load dataset rann_test_r_3_900.csv"); + if (!data::Load("rann_test_q_3_100.csv", queryData)) + FAIL("Cannot load dataset rann_test_q_3_100.csv"); // Search for 1 rank-approximate nearest-neighbors in the top 30% of the point // (rank error of 3). @@ -158,7 +166,8 @@ TEST_CASE("DualTreeSearch", "[KRANNTest]") RASearch<> tsdRann(refData, false, false, 1.0, 0.95, false, false, 5); arma::Mat qrRanks; - data::Load("rann_test_qr_ranks.csv", qrRanks, true, false); // No transpose. + if (!data::Load("rann_test_qr_ranks.csv", qrRanks, false, false)) // No transpose. + FAIL("Cannot load dataset rann_test_qr_ranks.csv"); size_t numRounds = 1000; arma::Col numSuccessRounds(queryData.n_cols); @@ -274,8 +283,10 @@ TEST_CASE("SingleCoverTreeTest", "[KRANNTest]") arma::mat refData; arma::mat queryData; - data::Load("rann_test_r_3_900.csv", refData, true); - data::Load("rann_test_q_3_100.csv", queryData, true); + if (!data::Load("rann_test_r_3_900.csv", refData)) + FAIL("Cannot load dataset rann_test_r_3_900.csv"); + if (!data::Load("rann_test_q_3_100.csv", queryData)) + FAIL("Cannot load dataset rann_test_q_3_100.csv"); // Search for 1 rank-approximate nearest-neighbors in the top 30% of the point // (rank error of 3). @@ -289,7 +300,8 @@ TEST_CASE("SingleCoverTreeTest", "[KRANNTest]") // The relative ranks for the given query reference pair. arma::Mat qrRanks; - data::Load("rann_test_qr_ranks.csv", qrRanks, true, false); // No transpose. + if (!data::Load("rann_test_qr_ranks.csv", qrRanks, false, false)) // No transpose. + FAIL("Cannot load dataset rann_test_qr_ranks.csv"); size_t numRounds = 100; arma::Col numSuccessRounds(queryData.n_cols); @@ -335,8 +347,10 @@ TEST_CASE("DualCoverTreeTest", "[KRANNTest]") arma::mat refData; arma::mat queryData; - data::Load("rann_test_r_3_900.csv", refData, true); - data::Load("rann_test_q_3_100.csv", queryData, true); + if (!data::Load("rann_test_r_3_900.csv", refData)) + FAIL("Cannot load dataset rann_test_r_3_900.csv"); + if (!data::Load("rann_test_q_3_100.csv", queryData)) + FAIL("Cannot load dataset rann_test_q_3_100.csv"); // Search for 1 rank-approximate nearest-neighbors in the top 30% of the point // (rank error of 3). @@ -354,7 +368,8 @@ TEST_CASE("DualCoverTreeTest", "[KRANNTest]") RACoverTreeSearch tsdRann(&refTree, false, 1.0, 0.95, false, false, 5); arma::Mat qrRanks; - data::Load("rann_test_qr_ranks.csv", qrRanks, true, false); // No transpose. + if (!data::Load("rann_test_qr_ranks.csv", qrRanks, false, false)) // No transpose. + FAIL("Cannot load dataset rann_test_qr_ranks.csv"); size_t numRounds = 100; arma::Col numSuccessRounds(queryData.n_cols); @@ -623,8 +638,10 @@ TEST_CASE("RAModelTest", "[KRANNTest]") typedef RAModel KNNModel; arma::mat queryData, referenceData; - data::Load("rann_test_r_3_900.csv", referenceData, true); - data::Load("rann_test_q_3_100.csv", queryData, true); + if (!data::Load("rann_test_r_3_900.csv", referenceData)) + FAIL("Cannot load dataset rann_test_r_3_900.csv"); + if (!data::Load("rann_test_q_3_100.csv", queryData)) + FAIL("Cannot load dataset rann_test_q_3_100.csv"); // Build all the possible models. KNNModel models[20]; @@ -650,7 +667,8 @@ TEST_CASE("RAModelTest", "[KRANNTest]") models[19] = KNNModel(KNNModel::TreeTypes::OCTREE, true); arma::Mat qrRanks; - data::Load("rann_test_qr_ranks.csv", qrRanks, true, false); // No transpose. + if (!data::Load("rann_test_qr_ranks.csv", qrRanks, false, false)) // No transpose. + FAIL("Cannot load dataset rann_test_qr_ranks.csv"); for (size_t j = 0; j < 3; ++j) { diff --git a/src/mlpack/tests/ksinit_test.cpp b/src/mlpack/tests/ksinit_test.cpp index 11d6cdae40..930df617e4 100644 --- a/src/mlpack/tests/ksinit_test.cpp +++ b/src/mlpack/tests/ksinit_test.cpp @@ -230,8 +230,10 @@ TEST_CASE("IrisDataset", "[KSInitialization]") arma::mat dataset, labels; - data::Load("iris.csv", dataset, true); - data::Load("iris_labels.txt", labels, true); + if (!data::Load("iris.csv", dataset)) + FAIL("Cannot load dataset iris.csv"); + if (!data::Load("iris_labels.txt", labels)) + FAIL("Cannot load dataset iris_labels.txt"); dataset.insert_rows(dataset.n_rows, labels); diff --git a/src/mlpack/tests/lars_test.cpp b/src/mlpack/tests/lars_test.cpp index ef030343ae..bb3a2aa767 100644 --- a/src/mlpack/tests/lars_test.cpp +++ b/src/mlpack/tests/lars_test.cpp @@ -111,8 +111,10 @@ TEST_CASE("CholeskySingularityTest", "[LARSTest]") arma::mat X; arma::mat Y; - data::Load("lars_dependent_x.csv", X); - data::Load("lars_dependent_y.csv", Y); + if (!data::Load("lars_dependent_x.csv", X)) + FAIL("Cannot load dataset lars_dependent_x.csv"); + if (!data::Load("lars_dependent_y.csv", Y)) + FAIL("Cannot load dataset lars_dependent_y.csv"); arma::rowvec y = Y.row(0); @@ -135,8 +137,10 @@ TEST_CASE("NoCholeskySingularityTest", "[LARSTest]") arma::mat X; arma::mat Y; - data::Load("lars_dependent_x.csv", X); - data::Load("lars_dependent_y.csv", Y); + if (!data::Load("lars_dependent_x.csv", X)) + FAIL("Cannot load dataset lars_dependent_x.csv"); + if (!data::Load("lars_dependent_y.csv", Y)) + FAIL("Cannot load dataset lars_dependent_y.csv"); arma::rowvec y = Y.row(0); @@ -357,8 +361,10 @@ TEST_CASE("LARSTrainReturnCorrelation", "[LARSTest]") arma::mat X; arma::mat Y; - data::Load("lars_dependent_x.csv", X); - data::Load("lars_dependent_y.csv", Y); + if (!data::Load("lars_dependent_x.csv", X)) + FAIL("Cannot load dataset lars_dependent_x.csv"); + if (!data::Load("lars_dependent_y.csv", Y)) + FAIL("Cannot load dataset lars_dependent_y.csv"); arma::rowvec y = Y.row(0); @@ -403,8 +409,10 @@ TEST_CASE("LARSTestComputeError", "[LARSTest]") arma::mat X; arma::mat Y; - data::Load("lars_dependent_x.csv", X); - data::Load("lars_dependent_y.csv", Y); + if (!data::Load("lars_dependent_x.csv", X)) + FAIL("Cannot load dataset lars_dependent_x.csv"); + if (!data::Load("lars_dependent_y.csv", Y)) + FAIL("Cannot load dataset lars_dependent_y.csv"); arma::rowvec y = Y.row(0); @@ -427,8 +435,10 @@ TEST_CASE("LARSCopyConstructorTest", "[LARSTest]") arma::rowvec targets; // Load training input and predictions for testing. - data::Load("lars_dependent_x.csv", features); - data::Load("lars_dependent_y.csv", Y); + if (!data::Load("lars_dependent_x.csv", features)) + FAIL("Cannot load dataset lars_dependent_x.csv"); + if (!data::Load("lars_dependent_y.csv", Y)) + FAIL("Cannot load dataset lars_dependent_y.csv"); targets = Y.row(0); // Check if the copy is accessible even after deleting the pointer to the diff --git a/src/mlpack/tests/lin_alg_test.cpp b/src/mlpack/tests/lin_alg_test.cpp index a43821d75d..4b8af04b79 100644 --- a/src/mlpack/tests/lin_alg_test.cpp +++ b/src/mlpack/tests/lin_alg_test.cpp @@ -91,7 +91,8 @@ TEST_CASE("TestOrthogonalize", "[LinAlgTest]") // Generate a random matrix; then, orthogonalize it and test if it's // orthogonal. mat tmp, orth; - data::Load("fake.csv", tmp); + if (!data::Load("fake.csv", tmp)) + FAIL("Cannot load dataset fake.csv"); Orthogonalize(tmp, orth); // test orthogonality diff --git a/src/mlpack/tests/lmnn_test.cpp b/src/mlpack/tests/lmnn_test.cpp index b767f4a940..4a0ce99360 100644 --- a/src/mlpack/tests/lmnn_test.cpp +++ b/src/mlpack/tests/lmnn_test.cpp @@ -699,8 +699,10 @@ TEST_CASE("LMNNFunctionGradientTest3", "[LMNNTest]") { arma::mat dataset; arma::Row labels; - data::Load("iris.csv", dataset); - data::Load("iris_labels.txt", labels); + if (!data::Load("iris.csv", dataset)) + FAIL("Cannot load dataset iris.csv"); + if (!data::Load("iris_labels.txt", labels)) + FAIL("Cannot load dataset iris_labels.txt"); LMNNFunction<> lmnnfn(dataset, labels, 1, 0.6, 1); @@ -716,8 +718,10 @@ TEST_CASE("LMNNFunctionGradientTest4", "[LMNNTest]") { arma::mat dataset; arma::Row labels; - data::Load("iris.csv", dataset); - data::Load("iris_labels.txt", labels); + if (!data::Load("iris.csv", dataset)) + FAIL("Cannot load dataset iris.csv"); + if (!data::Load("iris_labels.txt", labels)) + FAIL("Cannot load dataset iris_labels.txt"); LMNNFunction<> lmnnfn(dataset, labels, 1, 0.6, 1); diff --git a/src/mlpack/tests/load_save_test.cpp b/src/mlpack/tests/load_save_test.cpp index b9e8a839cf..bf7066c04f 100644 --- a/src/mlpack/tests/load_save_test.cpp +++ b/src/mlpack/tests/load_save_test.cpp @@ -1414,8 +1414,10 @@ TEST_CASE("RegularCSVDatasetInfoLoad", "[LoadSaveTest]") { arma::mat one, two; DatasetInfo info; - data::Load(testFiles[i], one); - data::Load(testFiles[i], two, info); + if (!data::Load(testFiles[i], one)) + FAIL("Cannot load dataset"); + if (!data::Load(testFiles[i], two, info); + FAIL("Cannot load dataset"); // Check that the matrices contain the same information. REQUIRE(one.n_elem == two.n_elem); @@ -1454,8 +1456,10 @@ TEST_CASE("NontransposedCSVDatasetInfoLoad", "[LoadSaveTest]") { arma::mat one, two; DatasetInfo info; - data::Load(testFiles[i], one, true, false); // No transpose. - data::Load(testFiles[i], two, info, true, false); + if (!data::Load(testFiles[i], one, false, false)) // No transpose. + FAIL("Cannot load dataset"); + if (!data::Load(testFiles[i], two, info, false, false)) + FAIL("Cannot load dataset"); // Check that the matrices contain the same information. REQUIRE(one.n_elem == two.n_elem); @@ -1494,7 +1498,8 @@ TEST_CASE("CategoricalCSVLoadTest00", "[LoadSaveTest]") // Load the test CSV. arma::umat matrix; DatasetInfo info; - data::Load("test.csv", matrix, info); + if (!data::Load("test.csv", matrix, info)) + FAIL("Cannot load dataset"); REQUIRE(matrix.n_cols == 7); REQUIRE(matrix.n_rows == 3); @@ -1551,7 +1556,8 @@ TEST_CASE("CategoricalCSVLoadTest01", "[LoadSaveTest]") // Load the test CSV. arma::umat matrix; DatasetInfo info; - data::Load("test.csv", matrix, info, true); + if (!data::Load("test.csv", matrix, info)) + FAIL("Cannot load dataset"); REQUIRE(matrix.n_cols == 4); REQUIRE(matrix.n_rows == 3); @@ -1596,7 +1602,8 @@ TEST_CASE("CategoricalCSVLoadTest02", "[LoadSaveTest]") // Load the test CSV. arma::umat matrix; DatasetInfo info; - data::Load("test.csv", matrix, info, true); + if (!data::Load("test.csv", matrix, info)) + FAIL("Cannot load dataset"); REQUIRE(matrix.n_cols == 4); REQUIRE(matrix.n_rows == 3); @@ -1640,7 +1647,8 @@ TEST_CASE("CategoricalCSVLoadTest03", "[LoadSaveTest]") // Load the test CSV. arma::umat matrix; DatasetInfo info; - data::Load("test.csv", matrix, info, true); + if (!data::Load("test.csv", matrix, info)) + FAIL("Cannot load dataset"); REQUIRE(matrix.n_cols == 4); REQUIRE(matrix.n_rows == 3); @@ -1684,7 +1692,8 @@ TEST_CASE("CategoricalCSVLoadTest04", "[LoadSaveTest]") // Load the test CSV. arma::umat matrix; DatasetInfo info; - data::Load("test.csv", matrix, info, true); + if (!data::Load("test.csv", matrix, info)) + FAIL("Cannot load dataset"); REQUIRE(matrix.n_cols == 4); REQUIRE(matrix.n_rows == 3); @@ -1731,7 +1740,8 @@ TEST_CASE("CategoricalNontransposedCSVLoadTest00", "[LoadSaveTest]") // Load the test CSV. arma::umat matrix; DatasetInfo info; - data::Load("test.csv", matrix, info, true, false); // No transpose. + if (!data::Load("test.csv", matrix, info, false, false)) // No transpose. + FAIL("Cannot load dataset"); REQUIRE(matrix.n_cols == 3); REQUIRE(matrix.n_rows == 7); @@ -1820,7 +1830,8 @@ TEST_CASE("CategoricalNontransposedCSVLoadTest01", "[LoadSaveTest]") // Load the test CSV. arma::umat matrix; DatasetInfo info; - data::Load("test.csv", matrix, info, true, false); // No transpose. + if (!data::Load("test.csv", matrix, info, false, false)) // No transpose. + FAIL("Cannot load dataset"); REQUIRE(matrix.n_cols == 3); REQUIRE(matrix.n_rows == 4); @@ -1865,7 +1876,8 @@ TEST_CASE("CategoricalNontransposedCSVLoadTest02", "[LoadSaveTest]") // Load the test CSV. arma::umat matrix; DatasetInfo info; - data::Load("test.csv", matrix, info, true, false); // No transpose. + if (!data::Load("test.csv", matrix, info, false, false)) // No transpose. + FAIL("Cannot load dataset"); REQUIRE(matrix.n_cols == 3); REQUIRE(matrix.n_rows == 4); @@ -1910,7 +1922,8 @@ TEST_CASE("CategoricalNontransposedCSVLoadTest03", "[LoadSaveTest]") // Load the test CSV. arma::umat matrix; DatasetInfo info; - data::Load("test.csv", matrix, info, true, false); // No transpose. + if (!data::Load("test.csv", matrix, info, false, false)) // No transpose. + FAIL("Cannot load dataset"); REQUIRE(matrix.n_cols == 3); REQUIRE(matrix.n_rows == 4); @@ -1955,7 +1968,8 @@ TEST_CASE("CategoricalNontransposedCSVLoadTest04", "[LoadSaveTest]") // Load the test CSV. arma::umat matrix; DatasetInfo info; - data::Load("test.csv", matrix, info, true, false); // No transpose. + if (!data::Load("test.csv", matrix, info, false, false)) // No transpose. + FAIL("Cannot load dataset"); REQUIRE(matrix.n_cols == 3); REQUIRE(matrix.n_rows == 4); @@ -2003,7 +2017,8 @@ TEST_CASE("HarderKeonTest", "[LoadSaveTest]") // Load transposed. arma::mat dataset; data::DatasetInfo info; - data::Load("test.csv", dataset, info, true, true); + if (!data::Load("test.csv", dataset, info, false, true)) + FAIL("Cannot load dataset"); REQUIRE(dataset.n_rows == 5); REQUIRE(dataset.n_cols == 4); @@ -2017,7 +2032,8 @@ TEST_CASE("HarderKeonTest", "[LoadSaveTest]") // Now load non-transposed. data::DatasetInfo ntInfo; - data::Load("test.csv", dataset, ntInfo, true, false); + if (!data::Load("test.csv", dataset, ntInfo, false, false)) + FAIL("Cannot load dataset"); REQUIRE(dataset.n_rows == 4); REQUIRE(dataset.n_cols == 5); @@ -2052,7 +2068,8 @@ TEST_CASE("SimpleARFFTest", "[LoadSaveTest]") arma::mat dataset; DatasetInfo info; - data::Load("test.arff", dataset, info); + if (!data::Load("test.arff", dataset, info)) + FAIL("Cannot load dataset"); REQUIRE(info.Dimensionality() == 2); REQUIRE(info.Type(0) == Datatype::numeric); @@ -2093,7 +2110,8 @@ TEST_CASE("SimpleARFFCategoricalTest", "[LoadSaveTest]") arma::mat dataset; DatasetInfo info; - data::Load("test.arff", dataset, info); + if (!data::Load("test.arff", dataset, info)) + FAIL("Cannot load dataset"); REQUIRE(info.Dimensionality() == 3); @@ -2152,7 +2170,8 @@ TEST_CASE("HarderARFFTest", "[LoadSaveTest]") arma::mat dataset; DatasetInfo info; - data::Load("test.arff", dataset, info); + if (!data::Load("test.arff", dataset, info)) + FAIL("Cannot load dataset"); REQUIRE(info.Dimensionality() == 5); diff --git a/src/mlpack/tests/lrsdp_test.cpp b/src/mlpack/tests/lrsdp_test.cpp index f07b13ad7f..b2ac089997 100644 --- a/src/mlpack/tests/lrsdp_test.cpp +++ b/src/mlpack/tests/lrsdp_test.cpp @@ -95,7 +95,8 @@ BOOST_AUTO_TEST_CASE(Johnson844LovaszThetaSDP) { // Load the edges. arma::mat edges; - data::Load("johnson8-4-4.csv", edges, true); + if (!data::Load("johnson8-4-4.csv", edges)) + FAIL("Cannot load dataset johnson8-4-4.csv"); // The LRSDP itself and the initial point. arma::mat coordinates; @@ -150,7 +151,8 @@ BOOST_AUTO_TEST_CASE(ErdosRenyiRandomGraphMaxCutSDP) { // Load the edges. arma::mat edges; - data::Load("erdosrenyi-n100.csv", edges, true); + if (!data::Load("erdosrenyi-n100.csv", edges) + FAIL("Cannot load dataset erdosrenyi-n100.csv"); arma::sp_mat laplacian; CreateSparseGraphLaplacian(edges, laplacian); @@ -221,8 +223,10 @@ BOOST_AUTO_TEST_CASE(GaussianMatrixSensingSDP) arma::mat Xorig, A; // read the unknown matrix X and the measurement matrices A_i in - data::Load("sensing_X.csv", Xorig, true, false); - data::Load("sensing_A.csv", A, true, false); + if (!data::Load("sensing_X.csv", Xorig, false, false)) + FAIL("Cannot load dataset sensing_X.csv"); + if (!data::Load("sensing_A.csv", A, false, false)) + FAIL("Cannot load dataset sensing_A.csv"); const size_t m = Xorig.n_rows; const size_t n = Xorig.n_cols; diff --git a/src/mlpack/tests/lsh_test.cpp b/src/mlpack/tests/lsh_test.cpp index c9583d9853..7eca5fbcc5 100644 --- a/src/mlpack/tests/lsh_test.cpp +++ b/src/mlpack/tests/lsh_test.cpp @@ -115,8 +115,10 @@ TEST_CASE("NumTablesTest", "[LSHTest]") const string testSet = "iris_test.csv"; arma::mat rdata; arma::mat qdata; - data::Load(trainSet, rdata, true); - data::Load(testSet, qdata, true); + if (!data::Load(trainSet, rdata)) + FAIL("Cannot load dataset"); + if (!data::Load(testSet, qdata)) + FAIL("Cannot load dataset"); // Run classic knn on reference data. KNN knn(rdata); @@ -187,8 +189,10 @@ TEST_CASE("HashWidthTest", "[LSHTest]") const string testSet = "iris_test.csv"; arma::mat rdata; arma::mat qdata; - data::Load(trainSet, rdata, true); - data::Load(testSet, qdata, true); + if (!data::Load(trainSet, rdata)) + FAIL("Cannot load dataset"); + if (!data::Load(testSet, qdata)) + FAIL("Cannot load dataset"); // Run classic knn on reference data. KNN knn(rdata); @@ -247,8 +251,10 @@ TEST_CASE("NumProjTest", "[LSHTest]") const string testSet = "iris_test.csv"; arma::mat rdata; arma::mat qdata; - data::Load(trainSet, rdata, true); - data::Load(testSet, qdata, true); + if (!data::Load(trainSet, rdata)) + FAIL("Cannot load dataset"); + if (!data::Load(testSet, qdata)) + FAIL("Cannot load dataset"); // Run classic knn on reference data. KNN knn(rdata); @@ -307,8 +313,10 @@ TEST_CASE("RecallTest", "[LSHTest]") const string testSet = "iris_test.csv"; arma::mat rdata; arma::mat qdata; - data::Load(trainSet, rdata, true); - data::Load(testSet, qdata, true); + if (!data::Load(trainSet, rdata)) + FAIL("Cannot load dataset"); + if (!data::Load(testSet, qdata)) + FAIL("Cannot load dataset"); // Run classic knn on reference data. KNN knn(rdata); @@ -502,8 +510,10 @@ TEST_CASE("MultiprobeTest", "[LSHTest]") const string testSet = "iris_test.csv"; arma::mat rdata; arma::mat qdata; - data::Load(trainSet, rdata, true); - data::Load(testSet, qdata, true); + if (!data::Load(trainSet, rdata)) + FAIL("Cannot load dataset"); + if (!data::Load(testSet, qdata)) + FAIL("Cannot load dataset"); // Add a slight amount of noise to the dataset, so that we don't end up with // points that have the same distance (hopefully). @@ -780,8 +790,10 @@ TEST_CASE("ParallelBichromatic", "[LSHTest]") const string testSet = "iris_test.csv"; arma::mat rdata; arma::mat qdata; - data::Load(trainSet, rdata, true); - data::Load(testSet, qdata, true); + if (!data::Load(trainSet, rdata)) + FAIL("Cannot load dataset"); + if (!data::Load(testSet, qdata)) + FAIL("Cannot load dataset"); // Where to store neighbors and distances arma::Mat sequentialNeighbors; @@ -819,7 +831,8 @@ TEST_CASE("ParallelMonochromatic", "[LSHTest]") // Read iris training data as reference and query set. const string trainSet = "iris_train.csv"; arma::mat rdata; - data::Load(trainSet, rdata, true); + if (!data::Load(trainSet, rdata)) + FAIL("Cannot load dataset"); // Where to store neighbors and distances arma::Mat sequentialNeighbors; @@ -936,8 +949,10 @@ TEST_CASE("SparseLSHTest", "[LSHTest]") const string testSet = "iris_test.csv"; arma::mat rdata; arma::mat qdata; - data::Load(trainSet, rdata, true); - data::Load(testSet, qdata, true); + if (!data::Load(trainSet, rdata)) + FAIL("Cannot load dataset"); + if (!data::Load(testSet, qdata)) + FAIL("Cannot load dataset"); // Run on dense data. LSHSearch<> denseLSH( diff --git a/src/mlpack/tests/matrix_completion_test.cpp b/src/mlpack/tests/matrix_completion_test.cpp index 104d169ef6..6fb3baff79 100644 --- a/src/mlpack/tests/matrix_completion_test.cpp +++ b/src/mlpack/tests/matrix_completion_test.cpp @@ -34,8 +34,10 @@ TEST_CASE("UniformMatrixCompletionSDP", "[MatrixCompletionTest]") arma::mat Xorig, values; arma::umat indices; - data::Load("completion_X.csv", Xorig, true, false); - data::Load("completion_indices.csv", indices, true, false); + if (!data::Load("completion_X.csv", Xorig, false, false)) + FAIL("Cannot load dataset completion_X.csv"); + if (!data::Load("completion_indices.csv", indices, false, false)) + FAIL("Cannot load dataset completion_indices.csv"); values.set_size(indices.n_cols); for (size_t i = 0; i < indices.n_cols; ++i) diff --git a/src/mlpack/tests/nbc_test.cpp b/src/mlpack/tests/nbc_test.cpp index ddc0487315..3b757d3b76 100644 --- a/src/mlpack/tests/nbc_test.cpp +++ b/src/mlpack/tests/nbc_test.cpp @@ -26,8 +26,10 @@ TEST_CASE("NaiveBayesClassifierTest", "[NBCTest]") size_t classes = 2; arma::mat trainData, trainRes, calcMat; - data::Load(trainFilename, trainData, true); - data::Load(trainResultFilename, trainRes, true); + if (!data::Load(trainFilename, trainData)) + FAIL("Cannot load dataset"); + if (!data::Load(trainResultFilename, trainRes)) + FAIL("Cannot load dataset"); // Get the labels out. arma::Row labels(trainData.n_cols); @@ -66,9 +68,12 @@ TEST_CASE("NaiveBayesClassifierTest", "[NBCTest]") arma::mat testResProbs; arma::Row calcVec; arma::mat calcProbs; - data::Load(testFilename, testData, true); - data::Load(testResultFilename, testRes, true); - data::Load(testResultProbsFilename, testResProbs, true); + if (!data::Load(testFilename, testData)) + FAIL("Cannot load dataset"); + if (!data::Load(testResultFilename, testRes)) + FAIL("Cannot load dataset"); + if (!data::Load(testResultProbsFilename, testResProbs)) + FAIL("Cannot load dataset"); testData.shed_row(testData.n_rows - 1); // Remove the labels. @@ -99,8 +104,10 @@ TEST_CASE("NaiveBayesClassifierIncrementalTest", "[NBCTest]") size_t classes = 2; arma::mat trainData, trainRes, calcMat; - data::Load(trainFilename, trainData, true); - data::Load(trainResultFilename, trainRes, true); + if (!data::Load(trainFilename, trainData)) + FAIL("Cannot load dataset"); + if (!data::Load(trainResultFilename, trainRes)) + FAIL("Cannot load dataset"); // Get the labels out. arma::Row labels(trainData.n_cols); @@ -139,9 +146,12 @@ TEST_CASE("NaiveBayesClassifierIncrementalTest", "[NBCTest]") arma::mat testResProba; arma::Row calcVec; arma::mat calcProbs; - data::Load(testFilename, testData, true); - data::Load(testResultFilename, testRes, true); - data::Load(testResultProbsFilename, testResProba, true); + if (!data::Load(testFilename, testData)) + FAIL("Cannot load dataset"); + if (!data::Load(testResultFilename, testRes)) + FAIL("Cannot load dataset"); + if (!data::Load(testResultProbsFilename, testResProba)) + FAIL("Cannot load dataset"); testData.shed_row(testData.n_rows - 1); // Remove the labels. @@ -170,8 +180,10 @@ TEST_CASE("SeparateTrainTest", "[NBCTest]") size_t classes = 2; arma::mat trainData, trainRes, calcMat; - data::Load(trainFilename, trainData, true); - data::Load(trainResultFilename, trainRes, true); + if (!data::Load(trainFilename, trainData)) + FAIL("Cannot load dataset"); + if (!data::Load(trainResultFilename, trainRes)) + FAIL("Cannot load dataset"); // Get the labels out. arma::Row labels(trainData.n_cols); @@ -228,8 +240,10 @@ TEST_CASE("SeparateTrainIncrementalTest", "[NBCTest]") size_t classes = 2; arma::mat trainData, trainRes, calcMat; - data::Load(trainFilename, trainData, true); - data::Load(trainResultFilename, trainRes, true); + if (!data::Load(trainFilename, trainData)) + FAIL("Cannot load dataset"); + if (!data::Load(trainResultFilename, trainRes)) + FAIL("Cannot load dataset"); // Get the labels out. arma::Row labels(trainData.n_cols); @@ -286,8 +300,10 @@ TEST_CASE("SeparateTrainIndividualIncrementalTest", "[NBCTest]") size_t classes = 2; arma::mat trainData, trainRes, calcMat; - data::Load(trainFilename, trainData, true); - data::Load(trainResultFilename, trainRes, true); + if (!data::Load(trainFilename, trainData)) + FAIL("Cannot load dataset"); + if (!data::Load(trainResultFilename, trainRes)) + FAIL("Cannot load dataset"); // Get the labels out. arma::Row labels(trainData.n_cols); @@ -356,8 +372,10 @@ TEST_CASE("NaiveBayesClassifierHighDimensionsTest", "[NBCTest]") // Create variables for training and assign data to them. arma::mat trainData; arma::Row trainLabels; - data::Load(trainFilename, trainData, true); - data::Load(trainLabelsFileName, trainLabels, true); + if (!data::Load(trainFilename, trainData)) + FAIL("Cannot load dataset"); + if (!data::Load(trainLabelsFileName, trainLabels)) + FAIL("Cannot load dataset"); // Initialize and train a NBC model. NaiveBayesClassifier<> nbcTest(trainData, trainLabels, classes); @@ -366,8 +384,10 @@ TEST_CASE("NaiveBayesClassifierHighDimensionsTest", "[NBCTest]") arma::mat testData, calcProbs; arma::Row testLabels; arma::Row calcVec; - data::Load(testFilename, testData, true); - data::Load(testLabelsFilename, testLabels, true); + if (!data::Load(testFilename, testData)) + FAIL("Cannot load dataset"); + if (!data::Load(testLabelsFilename, testLabels)) + FAIL("Cannot load dataset"); // Classify observations in the test dataset. To use Classify() method with // a parameter for probabilities of predictions, we pass 'calcProbs' to the diff --git a/src/mlpack/tests/nystroem_method_test.cpp b/src/mlpack/tests/nystroem_method_test.cpp index 1c99a7b7e6..32bf189d49 100644 --- a/src/mlpack/tests/nystroem_method_test.cpp +++ b/src/mlpack/tests/nystroem_method_test.cpp @@ -146,7 +146,8 @@ TEST_CASE("GermanTest", "[NystroemMethodTest]") { // Load the dataset. arma::mat dataset; - data::Load("german.csv", dataset, true); + if (!data::Load("german.csv", dataset)) + FAIL("Cannot load dataset german.csv"); // These are our tolerance bounds. double results[5] = { 32.0, 20.0, 15.0, 12.0, 9.0 }; diff --git a/src/mlpack/tests/one_hot_encoding_test.cpp b/src/mlpack/tests/one_hot_encoding_test.cpp index a3b19363f6..1844539f0f 100644 --- a/src/mlpack/tests/one_hot_encoding_test.cpp +++ b/src/mlpack/tests/one_hot_encoding_test.cpp @@ -191,7 +191,8 @@ TEST_CASE("OneHotEncodingDatasetinfoTest", "[OneHotEncodingTest]") // Load the test CSV. arma::umat matrix; DatasetInfo info; - data::Load("test.csv", matrix, info); + if (!data::Load("test.csv", matrix, info)) + FAIL("Cannot load dataset test.csv"); arma::umat output; data::OneHotEncoding(matrix, output, info); REQUIRE(output.n_cols == 7); diff --git a/src/mlpack/tests/pca_test.cpp b/src/mlpack/tests/pca_test.cpp index 6ccefbbaeb..1d4a1657ed 100644 --- a/src/mlpack/tests/pca_test.cpp +++ b/src/mlpack/tests/pca_test.cpp @@ -240,7 +240,8 @@ TEST_CASE("RandomizedPCADimensionalityReductionTest", "[PCATest]") TEST_CASE("QUICPCADimensionalityReductionTest", "[PCATest]") { arma::mat data, data1; - data::Load("test_data_3_1000.csv", data); + if (!data::Load("test_data_3_1000.csv", data)) + FAIL("Cannot load dataset test_data_3_1000.csv"); data1 = data; arma::mat backupData(data); diff --git a/src/mlpack/tests/quic_svd_test.cpp b/src/mlpack/tests/quic_svd_test.cpp index 9ae2e33a79..16cbfa98af 100644 --- a/src/mlpack/tests/quic_svd_test.cpp +++ b/src/mlpack/tests/quic_svd_test.cpp @@ -24,7 +24,8 @@ TEST_CASE("QUICSVDReconstructionError", "[QUICSVDTest]") { // Load the dataset. arma::mat dataset; - data::Load("test_data_3_1000.csv", dataset); + if (!data::Load("test_data_3_1000.csv", dataset)) + FAIL("Cannot load dataset test_data_3_1000.csv"); // The QUIC-SVD procedure can fail---the Monte Carlo error calculation is // random. Therefore we simply require at least one success. diff --git a/src/mlpack/tests/radical_test.cpp b/src/mlpack/tests/radical_test.cpp index feb687ee52..39b77a11f7 100644 --- a/src/mlpack/tests/radical_test.cpp +++ b/src/mlpack/tests/radical_test.cpp @@ -21,7 +21,8 @@ using namespace arma; TEST_CASE("Radical_Test_Radical3D", "[RadicalTest]") { mat matX; - data::Load("data_3d_mixed.txt", matX); + if (!data::Load("data_3d_mixed.txt", matX)) + FAIL("Cannot load dataset data_3d_mixed.txt"); Radical rad(0.175, 5, 100, matX.n_rows - 1); @@ -39,7 +40,8 @@ TEST_CASE("Radical_Test_Radical3D", "[RadicalTest]") } mat matS; - data::Load("data_3d_ind.txt", matS); + if (!data::Load("data_3d_ind.txt", matS)) + FAIL("Cannot load dataset data_3d_ind.txt"); rad.DoRadical(matS, matY, matW); matYT = trans(matY); diff --git a/src/mlpack/tests/random_forest_test.cpp b/src/mlpack/tests/random_forest_test.cpp index b916ac446f..20397641e0 100644 --- a/src/mlpack/tests/random_forest_test.cpp +++ b/src/mlpack/tests/random_forest_test.cpp @@ -122,9 +122,11 @@ TEST_CASE("UnweightedNumericLearningTest", "[RandomForestTest]") { // Load the vc2 dataset. arma::mat dataset; - data::Load("vc2.csv", dataset); + if (!data::Load("vc2.csv", dataset)) + FAIL("Cannot load dataset vc2.csv"); arma::Row labels; - data::Load("vc2_labels.txt", labels); + if (!data::Load("vc2_labels.txt", labels)) + FAIL("Cannot load dataset vc2.csv"); // Build a random forest and a decision tree. RandomForest<> rf(dataset, labels, 3, 20 /* 20 trees */, 1, 1e-7); @@ -132,9 +134,11 @@ TEST_CASE("UnweightedNumericLearningTest", "[RandomForestTest]") // Get performance statistics on test data. arma::mat testDataset; - data::Load("vc2_test.csv", testDataset); + if (!data::Load("vc2_test.csv", testDataset)) + FAIL("Cannot load dataset vc2_test.csv"); arma::Row testLabels; - data::Load("vc2_test_labels.txt", testLabels); + if (!data::Load("vc2_test_labels.txt", testLabels)) + FAIL("Cannot load dataset vc2_test_labels.txt"); arma::Row rfPredictions; arma::Row dtPredictions; @@ -158,8 +162,10 @@ TEST_CASE("WeightedNumericLearningTest", "[RandomForestTest]") { arma::mat dataset; arma::Row labels; - data::Load("vc2.csv", dataset); - data::Load("vc2_labels.txt", labels); + if (!data::Load("vc2.csv", dataset)) + FAIL("Cannot load dataset vc2.csv"); + if (!data::Load("vc2_labels.txt", labels)) + FAIL("Cannot load dataset vc2_labels.txt"); // Add some noise. arma::mat noise(dataset.n_rows, 1000, arma::fill::randu); @@ -184,9 +190,11 @@ TEST_CASE("WeightedNumericLearningTest", "[RandomForestTest]") // Get performance statistics on test data. arma::mat testDataset; - data::Load("vc2_test.csv", testDataset); + if (!data::Load("vc2_test.csv", testDataset)) + FAIL("Cannot load dataset vc2_test.csv"); arma::Row testLabels; - data::Load("vc2_test_labels.txt", testLabels); + if (!data::Load("vc2_test_labels.txt", testLabels)) + FAIL("Cannot load dataset vc2_test_labels.txt"); arma::Row rfPredictions; arma::Row dtPredictions; @@ -304,9 +312,11 @@ TEST_CASE("LeafSizeDatasetTest", "[RandomForestTest]") { // Load the vc2 dataset. arma::mat dataset; - data::Load("vc2.csv", dataset); + if (!data::Load("vc2.csv", dataset)) + FAIL("Cannot load dataset vc2.csv"); arma::Row labels; - data::Load("vc2_labels.txt", labels); + if (!data::Load("vc2_labels.txt", labels)) + FAIL("Cannot load dataset vc2.csv"); // Build a random forest with a leaf size equal to the number of points in the // dataset. @@ -338,9 +348,11 @@ TEST_CASE("RandomForestSerializationTest", "[RandomForestTest]") { // Load the vc2 dataset. arma::mat dataset; - data::Load("vc2.csv", dataset); + if (!data::Load("vc2.csv", dataset)) + FAIL("Cannot load dataset vc2.csv"); arma::Row labels; - data::Load("vc2_labels.txt", labels); + if (!data::Load("vc2_labels.txt", labels)) + FAIL("Cannot load dataset vc2.csv"); RandomForest<> rf(dataset, labels, 3, 10 /* 10 trees */, 1); @@ -374,8 +386,10 @@ TEST_CASE("RandomForestNumericTrainReturnEntropy", "[RandomForestTest]") { arma::mat dataset; arma::Row labels; - data::Load("vc2.csv", dataset); - data::Load("vc2_labels.txt", labels); + if (!data::Load("vc2.csv", dataset)) + FAIL("Cannot load dataset vc2.csv"); + if (!data::Load("vc2_labels.txt", labels)) + FAIL("Cannot load dataset vc2_labels.txt"); // Add some noise. arma::mat noise(dataset.n_rows, 1000, arma::fill::randu); diff --git a/src/mlpack/tests/svd_incremental_test.cpp b/src/mlpack/tests/svd_incremental_test.cpp index 433a86755f..56a55459d7 100644 --- a/src/mlpack/tests/svd_incremental_test.cpp +++ b/src/mlpack/tests/svd_incremental_test.cpp @@ -98,7 +98,8 @@ class SpecificRandomInitialization TEST_CASE("SVDIncompleteIncrementalRegularizationTest", "[SVDIncrementalTest]") { mat dataset; - data::Load("GroupLensSmall.csv", dataset); + if (!data::Load("GroupLensSmall.csv", dataset)) + FAIL("Cannot load dataset GroupLensSmall.csv"); // Generate list of locations for batch insert constructor for sparse // matrices. diff --git a/src/mlpack/tests/svdplusplus_test.cpp b/src/mlpack/tests/svdplusplus_test.cpp index dbf1417397..4ca13e55ad 100644 --- a/src/mlpack/tests/svdplusplus_test.cpp +++ b/src/mlpack/tests/svdplusplus_test.cpp @@ -255,7 +255,8 @@ TEST_CASE("SVDplusPlusOutputSizeTest", "[SVDPlusPlusTest]") { // Load small GroupLens dataset. arma::mat data; - data::Load("GroupLensSmall.csv", data); + if (!data::Load("GroupLensSmall.csv", data)) + FAIL("Cannot load dataset GroupLensSmall.csv"); // Define useful constants. const size_t numUsers = max(data.row(0)) + 1; @@ -288,7 +289,8 @@ TEST_CASE("SVDPlusPlusCleanDataTest", "[SVDPlusPlusTest]") { // Load small GroupLens dataset. arma::mat data; - data::Load("GroupLensSmall.csv", data); + if (!data::Load("GroupLensSmall.csv", data)) + FAIL("Cannot load dataset GroupLensSmall.csv"); // Define useful constants. const size_t numUsers = max(data.row(0)) + 1; From 1b79ef0678a5ed7acdd27eb9cebb5d5fdf1593b6 Mon Sep 17 00:00:00 2001 From: Gopi M Tatiraju Date: Tue, 23 Feb 2021 00:08:27 +0530 Subject: [PATCH 189/253] Update load_save_test.cpp --- src/mlpack/tests/load_save_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/load_save_test.cpp b/src/mlpack/tests/load_save_test.cpp index bf7066c04f..015ece667f 100644 --- a/src/mlpack/tests/load_save_test.cpp +++ b/src/mlpack/tests/load_save_test.cpp @@ -1415,7 +1415,7 @@ TEST_CASE("RegularCSVDatasetInfoLoad", "[LoadSaveTest]") arma::mat one, two; DatasetInfo info; if (!data::Load(testFiles[i], one)) - FAIL("Cannot load dataset"); + FAIL("Cannot load dataset") if (!data::Load(testFiles[i], two, info); FAIL("Cannot load dataset"); From a71a968f17aad63984c2050bca7826d0364b2de4 Mon Sep 17 00:00:00 2001 From: Gopi M Tatiraju Date: Tue, 23 Feb 2021 00:09:24 +0530 Subject: [PATCH 190/253] Update load_save_test.cpp --- src/mlpack/tests/load_save_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/load_save_test.cpp b/src/mlpack/tests/load_save_test.cpp index 015ece667f..d4c5f6f58a 100644 --- a/src/mlpack/tests/load_save_test.cpp +++ b/src/mlpack/tests/load_save_test.cpp @@ -1415,8 +1415,8 @@ TEST_CASE("RegularCSVDatasetInfoLoad", "[LoadSaveTest]") arma::mat one, two; DatasetInfo info; if (!data::Load(testFiles[i], one)) - FAIL("Cannot load dataset") - if (!data::Load(testFiles[i], two, info); + FAIL("Cannot load dataset"); + if (!data::Load(testFiles[i], two, info) FAIL("Cannot load dataset"); // Check that the matrices contain the same information. From 656c29ba6d31ca237199d48f9f6a046123bf9e11 Mon Sep 17 00:00:00 2001 From: Gopi M Tatiraju Date: Tue, 23 Feb 2021 01:35:31 +0530 Subject: [PATCH 191/253] Update load_save_test.cpp --- src/mlpack/tests/load_save_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/load_save_test.cpp b/src/mlpack/tests/load_save_test.cpp index d4c5f6f58a..602533a84b 100644 --- a/src/mlpack/tests/load_save_test.cpp +++ b/src/mlpack/tests/load_save_test.cpp @@ -1416,7 +1416,7 @@ TEST_CASE("RegularCSVDatasetInfoLoad", "[LoadSaveTest]") DatasetInfo info; if (!data::Load(testFiles[i], one)) FAIL("Cannot load dataset"); - if (!data::Load(testFiles[i], two, info) + if (!data::Load(testFiles[i], two, info)) FAIL("Cannot load dataset"); // Check that the matrices contain the same information. From 0180ca4f09b82aa875cfc82a59205d492ddb0d4f Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Tue, 23 Feb 2021 12:38:19 +0530 Subject: [PATCH 192/253] Changed author name format --- src/mlpack/methods/ann/layer/isrlu.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/isrlu.hpp b/src/mlpack/methods/ann/layer/isrlu.hpp index b0a786c6ba..fb4cd65947 100644 --- a/src/mlpack/methods/ann/layer/isrlu.hpp +++ b/src/mlpack/methods/ann/layer/isrlu.hpp @@ -8,8 +8,8 @@ * * @code * @article{ - * author = {Carlile, Brad and Delamarter, Guy and Kinney, Paul and Marti, - * Akiko and Whitney, Brian}, + * author = {Carlile, Brad, Delamarter, Guy, Kinney, Paul, Marti, + * Akiko, Whitney, Brian}, * title = {Improving deep learning by inverse square root linear units (ISRLUs)}, * year = {2017}, * url = {https://arxiv.org/pdf/1710.09967.pdf} From 5e695f99c8ea389fcf9b08080c51ce8b0ecc5ad9 Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Tue, 23 Feb 2021 13:55:23 +0530 Subject: [PATCH 193/253] Removed copying --- .../methods/ann/layer/pixel_shuffle_impl.hpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp index 9edb09c2eb..89ae8b79d5 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -61,12 +61,10 @@ void PixelShuffle::Forward( output.zeros(outputHeight * outputWidth * sizeOut, batchSize); for (size_t n = 0; n < batchSize; n++) { - arma::mat inputImage = input.col(n); - arma::mat outputImage = output.col(n); - arma::cube inputTemp(const_cast(inputImage).memptr(), height, - width, size, false, false); - arma::cube outputTemp(const_cast(outputImage).memptr(), - outputHeight, outputWidth, sizeOut, false, false); + arma::cube inputTemp(const_cast(input).memptr(), height, + width, size * batchSize, false, false); + arma::cube outputTemp(const_cast(output).memptr(), + outputHeight, outputWidth, sizeOut * batchSize, false, false); for (size_t c = 0; c < sizeOut ; c++) { @@ -78,13 +76,12 @@ void PixelShuffle::Forward( size_t width_index = w / upscaleFactor; size_t channel_index = (upscaleFactor * (h % upscaleFactor)) + (w % upscaleFactor) + (c * std::pow(upscaleFactor, 2)); - outputTemp(w, h, c) = inputTemp(width_index, height_index, - channel_index); + outputTemp(w, h, c + n * sizeOut) = inputTemp(width_index, height_index, + channel_index + n * size); } } } - output.col(n) = outputImage; } } From 4eff650f9d90b236139117b4c6a69acfbb8f0329 Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Tue, 23 Feb 2021 15:16:44 +0530 Subject: [PATCH 194/253] Remove copying in backward function. --- .../methods/ann/layer/pixel_shuffle_impl.hpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp index 89ae8b79d5..7bcf985f45 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -66,7 +66,7 @@ void PixelShuffle::Forward( arma::cube outputTemp(const_cast(output).memptr(), outputHeight, outputWidth, sizeOut * batchSize, false, false); - for (size_t c = 0; c < sizeOut ; c++) + for (size_t c = 0; c < sizeOut; c++) { for (size_t h = 0; h < outputHeight; h++) { @@ -93,14 +93,12 @@ void PixelShuffle::Backward( g.zeros(arma::size(input)); for (size_t n = 0; n < batchSize; n++) { - arma::mat gyImage = gy.col(n); - arma::mat gImage = g.col(n); - arma::cube gyTemp(const_cast(gyImage).memptr(), outputHeight, - outputWidth, sizeOut, false, false); - arma::cube gTemp(const_cast(gImage).memptr(), height, width, - size, false, false); + arma::cube gyTemp(const_cast(gy).memptr(), outputHeight, + outputWidth, sizeOut * batchSize, false, false); + arma::cube gTemp(const_cast(g).memptr(), height, width, + size * batchSize, false, false); - for (size_t c = 0; c < sizeOut ; c++) + for (size_t c = 0; c < sizeOut; c++) { for (size_t h = 0; h < outputHeight; h++) { @@ -110,12 +108,12 @@ void PixelShuffle::Backward( size_t width_index = w / upscaleFactor; size_t channel_index = (upscaleFactor * (h % upscaleFactor)) + (w % upscaleFactor) + (c * std::pow(upscaleFactor, 2)); - gTemp(width_index, height_index, channel_index) = gyTemp(w, h, c); + gTemp(width_index, height_index, channel_index + n * sizeOut) = gyTemp(w, h, + c + n * size); } } } - g.col(n) = gImage; } } From 34ca85cad3cbf3dd60397b632f6cbc2368a79839 Mon Sep 17 00:00:00 2001 From: Gopi M Tatiraju Date: Tue, 23 Feb 2021 16:00:09 +0530 Subject: [PATCH 195/253] Apply suggestions from code review Co-authored-by: Anush Kini <33577829+Abilityguy@users.noreply.github.com> --- src/mlpack/tests/feedforward_network_test.cpp | 21 +++++++++---------- src/mlpack/tests/krann_search_test.cpp | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/mlpack/tests/feedforward_network_test.cpp b/src/mlpack/tests/feedforward_network_test.cpp index c7386261bf..629df89749 100644 --- a/src/mlpack/tests/feedforward_network_test.cpp +++ b/src/mlpack/tests/feedforward_network_test.cpp @@ -161,7 +161,7 @@ TEST_CASE("FFVanillaNetworkTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - if (!data::Load("thyroid_train.csv", trainData)) + if (!data::Load("thyroid_train.csv", trainData)) FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); @@ -310,7 +310,7 @@ TEST_CASE("DropoutNetworkTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - if (!data::Load("thyroid_train.csv", trainData)) + if (!data::Load("thyroid_train.csv", trainData)) FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); @@ -413,7 +413,7 @@ TEST_CASE("DropConnectNetworkTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - if (!data::Load("thyroid_train.csv", trainData)) + if (!data::Load("thyroid_train.csv", trainData)) FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); @@ -504,8 +504,8 @@ TEST_CASE("FFSerializationTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - if (!data::Load("thyroid_train.csv", trainData)) - FAIL("Cannot open thyroid_train.csv"); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); @@ -555,8 +555,8 @@ TEST_CASE("CustomLayerTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - if (!data::Load("thyroid_train.csv", trainData)) - FAIL("Cannot open thyroid_train.csv"); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); @@ -636,8 +636,8 @@ TEST_CASE("FFNTrainReturnObjective", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - if (!data::Load("thyroid_train.csv", trainData)) - FAIL("Cannot open thyroid_train.csv"); + if (!data::Load("thyroid_train.csv", trainData)) + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); @@ -708,7 +708,7 @@ TEST_CASE("OptimizerTest", "[FeedForwardNetworkTest]") { // Load the dataset. arma::mat trainData; - if (!data::Load("thyroid_train.csv", trainData)) + if (!data::Load("thyroid_train.csv", trainData)) FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); @@ -730,4 +730,3 @@ TEST_CASE("OptimizerTest", "[FeedForwardNetworkTest]") ens::DE opt(200, 1000, 0.6, 0.8, 1e-5); model.Train(trainData, trainLabels, opt); } - diff --git a/src/mlpack/tests/krann_search_test.cpp b/src/mlpack/tests/krann_search_test.cpp index 5bc13eb952..29aa5335ff 100644 --- a/src/mlpack/tests/krann_search_test.cpp +++ b/src/mlpack/tests/krann_search_test.cpp @@ -43,7 +43,7 @@ TEST_CASE("NaiveGuaranteeTest", "[KRANNTest]") RASearch<> rsRann(refData, true, false, 1.0); arma::mat qrRanks; - if (!data::Load("rann_test_qr_ranks.csv", qrRanks, false, false)) // No transpose. + if (!data::Load("rann_test_qr_ranks.csv", qrRanks, false, false)) // No transpose. FAIL("Cannot load dataset rann_test_qr_ranks.csv"); size_t numRounds = 1000; From 4f9eb2845c7d2f94886ead42119e2be2c97f8561 Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Tue, 23 Feb 2021 16:47:45 +0530 Subject: [PATCH 196/253] Update pixel_shuffle_impl.hpp --- src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp index 7bcf985f45..c062c2a029 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -76,8 +76,8 @@ void PixelShuffle::Forward( size_t width_index = w / upscaleFactor; size_t channel_index = (upscaleFactor * (h % upscaleFactor)) + (w % upscaleFactor) + (c * std::pow(upscaleFactor, 2)); - outputTemp(w, h, c + n * sizeOut) = inputTemp(width_index, height_index, - channel_index + n * size); + outputTemp(w, h, c + n * size) = inputTemp(width_index, height_index, + channel_index + n * sizeOut); } } } From cd167d98ad75c45bb9ef72589807450a51ce57a4 Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Tue, 23 Feb 2021 18:13:32 +0530 Subject: [PATCH 197/253] Update pixel_shuffle_impl.hpp --- src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp index c062c2a029..7aa976e4d6 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -76,8 +76,8 @@ void PixelShuffle::Forward( size_t width_index = w / upscaleFactor; size_t channel_index = (upscaleFactor * (h % upscaleFactor)) + (w % upscaleFactor) + (c * std::pow(upscaleFactor, 2)); - outputTemp(w, h, c + n * size) = inputTemp(width_index, height_index, - channel_index + n * sizeOut); + outputTemp(w, h, c + n * sizeOut) = inputTemp(width_index, height_index, + channel_index + n * size); } } } @@ -108,8 +108,8 @@ void PixelShuffle::Backward( size_t width_index = w / upscaleFactor; size_t channel_index = (upscaleFactor * (h % upscaleFactor)) + (w % upscaleFactor) + (c * std::pow(upscaleFactor, 2)); - gTemp(width_index, height_index, channel_index + n * sizeOut) = gyTemp(w, h, - c + n * size); + gTemp(width_index, height_index, channel_index + n * size) = gyTemp(w, h, + c + n * sizeOut); } } } From b1cb6255e68328164f0452a70c5b45ab648225a9 Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Wed, 24 Feb 2021 11:00:31 +0530 Subject: [PATCH 198/253] changed authors name Co-authored-by: Ryan Birmingham --- src/mlpack/methods/ann/layer/isrlu.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mlpack/methods/ann/layer/isrlu.hpp b/src/mlpack/methods/ann/layer/isrlu.hpp index fb4cd65947..b0a786c6ba 100644 --- a/src/mlpack/methods/ann/layer/isrlu.hpp +++ b/src/mlpack/methods/ann/layer/isrlu.hpp @@ -8,8 +8,8 @@ * * @code * @article{ - * author = {Carlile, Brad, Delamarter, Guy, Kinney, Paul, Marti, - * Akiko, Whitney, Brian}, + * author = {Carlile, Brad and Delamarter, Guy and Kinney, Paul and Marti, + * Akiko and Whitney, Brian}, * title = {Improving deep learning by inverse square root linear units (ISRLUs)}, * year = {2017}, * url = {https://arxiv.org/pdf/1710.09967.pdf} From 95e756dbb4f5e400dd58e2d7ba71a1088915be14 Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Thu, 25 Feb 2021 18:15:22 +0530 Subject: [PATCH 199/253] Adding co-author --- src/mlpack/methods/ann/layer/pixel_shuffle.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle.hpp index 48d89c2fe2..f425d7c508 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle.hpp @@ -1,6 +1,7 @@ /** * @file methods/ann/layer/pixel_shuffle.hpp * @author Anjishnu Mukherjee + * @author Abhinav Anand * * Definition of the PixelShuffle class. * From 6e040a48aebb4ec213e069473e81798c1a418a09 Mon Sep 17 00:00:00 2001 From: abh2k <41710346+abh2k@users.noreply.github.com> Date: Thu, 25 Feb 2021 18:16:42 +0530 Subject: [PATCH 200/253] Adding co-author --- src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp index 7aa976e4d6..f56f708981 100644 --- a/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp +++ b/src/mlpack/methods/ann/layer/pixel_shuffle_impl.hpp @@ -1,6 +1,7 @@ /** * @file methods/ann/layer/pixel_shuffle_impl.hpp * @author Anjishnu Mukherjee + * @author Abhinav Anand * * Implementation of the PixelShuffle class. * From 73bb3515ce29fb165606431f6d55a9f2aacea4ee Mon Sep 17 00:00:00 2001 From: Anush Kini <33577829+Abilityguy@users.noreply.github.com> Date: Fri, 26 Feb 2021 16:53:17 +0530 Subject: [PATCH 201/253] Some review changes implemented. Changes implemented for the following reviews in 2746: 1. Using ```cols``` and ```subvec``` to avoid the for loop. 2. Changed instances of ```arma::row``` to ```arma::Row```. 3. Logic added where ```order``` is initialised only when ```shuffleData``` is true. 4. input fields made ```const```. 5. Removed extra new line where the line was less than 80 characters long. 6. Spacing fix (Refer line 566 in changed file). --- src/mlpack/core/data/split_data.hpp | 151 +++++++++++++++++----------- 1 file changed, 93 insertions(+), 58 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index f4a75d871b..370128dfc6 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -143,7 +143,7 @@ void StratifiedSplit(const arma::Mat& input, * @endcode * * @tparam T Type of the elements of the input matrix. - * @tparam LabelsType Type of input labels. It can be arma::Mat, arma::row, + * @tparam LabelsType Type of input labels. It can be arma::Mat, arma::Row, * arma::Cube or arma::SpMat. * @param input Input dataset to split. * @param inputLabel Input labels to split. @@ -170,28 +170,39 @@ void Split(const arma::Mat& input, const size_t trainSize = input.n_cols - testSize; trainData.set_size(input.n_rows, trainSize); testData.set_size(input.n_rows, testSize); + trainLabel.set_size(1, trainSize); + testLabel.set_size(1, testSize); - arma::uvec order = arma::linspace(0, input.n_cols - 1, - input.n_cols); if (shuffleData) - order = arma::shuffle(order); - - if (trainSize > 0) { - trainLabel.set_size(1, trainSize); - trainData = input.cols(order.subvec(0, trainSize - 1)); + arma::uvec order = arma::shuffle(arma::linspace(0, input.n_cols - 1, + input.n_cols)); - for (size_t i = 0; i < trainSize; ++i) - trainLabel(0, i) = inputLabel(0, order(i)); + if (trainSize > 0) + { + trainData = input.cols(order.subvec(0, trainSize - 1)); + trainLabel = inputLabel.cols(order.subvec(0, trainSize - 1)); + } + + if (trainSize < input.n_cols) + { + testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); + testLabel = inputLabel.cols(order.subvec(trainSize, input.n_cols - 1)); + } } - - if (trainSize < input.n_cols) + else { - testLabel.set_size(1, testSize); - testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); + if (trainSize > 0) + { + trainData = input.cols(0, trainSize - 1); + trainLabel = inputLabel.cols(0, trainSize - 1); + } - for (size_t i = trainSize; i < input.n_cols; ++i) - testLabel(0, i - trainSize) = inputLabel(0, order(i)); + if (trainSize < input.n_cols) + { + testData = input.cols(trainSize, input.n_cols - 1); + testLabel = inputLabel.cols(trainSize, inputLabel.n_cols - 1); + } } } @@ -265,7 +276,7 @@ void Split(const arma::Mat& input, * @endcode * * @tparam T Type of the elements of the input matrix. - * @tparam LabelsType Type of input labels. It can be arma::Mat, arma::row, + * @tparam LabelsType Type of input labels. It can be arma::Mat, arma::Row, * arma::Cube or arma::SpMat. * @param input Input dataset to split. * @param inputLabel Input labels to split. @@ -362,8 +373,7 @@ Split(const arma::Mat& input, * * // Split the dataset into a training and test set, with 30% of the data being * // held out for the test set. - * Split(input, label, trainData, - * testData, trainLabel, testLabel, 0.3); + * Split(input, label, trainData, testData, trainLabel, testLabel, 0.3); * @endcode * * @param input Input dataset to split. @@ -380,46 +390,56 @@ template ::value || arma::is_Mat_only::value>> -void Split(FieldType& input, - arma::field& inputLabel, +void Split(const FieldType& input, + const arma::field& inputLabel, FieldType& trainData, - arma::field& trainLabels, + arma::field& trainLabel, FieldType& testData, - arma::field& testLabels, + arma::field& testLabel, const double testRatio, const bool shuffleData = true) { const size_t testSize = static_cast(input.n_cols * testRatio); const size_t trainSize = input.n_cols - testSize; - - trainData.set_size(1, trainSize); - testData.set_size(1, testSize); - - arma::uvec order = arma::linspace(0, input.n_cols - 1, - input.n_cols); + trainLabel.set_size(1, trainSize); + testLabel.set_size(1, testSize); if (shuffleData) - order = arma::shuffle(order); - - if (trainSize > 0) { - trainLabels.set_size(1, trainSize); + arma::uvec order = arma::shuffle(arma::linspace(0, + input.n_cols - 1, input.n_cols)); - for (size_t i = 0; i < trainSize; ++i) - trainData[i] = input(0, order(i)); + if (trainSize > 0) + { + trainData = input.cols(order.subvec(0, trainSize - 1)); - for (size_t i = 0; i < trainSize; ++i) - trainLabels(0, i) = inputLabel(0, order(i)); + for (size_t i = 0; i < trainSize; ++i) + trainLabel(0, i) = inputLabel(0, order(i)); + } + + if (trainSize < input.n_cols) + { + testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); + + for (size_t i = trainSize; i < input.n_cols; ++i) + testLabel(0, i - trainSize) = inputLabel(0, order(i)); + } } - - if (testSize <= input.n_cols) + else { - for (size_t i = trainSize; i < input.n_cols - 1; ++i) - testData[i - trainSize] = input(0, order(i)); + if (trainSize > 0) + { + trainData = input.cols(0, trainSize - 1); + for (size_t i = 0; i < trainSize; ++i) + trainLabel(0, i) = inputLabel(0, i); + } - testLabels.set_size(1, testSize); - for (size_t i = trainSize; i < input.n_cols; ++i) - testLabels(0, i - trainSize) = inputLabel(0, order(i)); + if (trainSize < input.n_cols) + { + testData = input.cols(trainSize, input.n_cols - 1); + for (size_t i = trainSize; i < input.n_cols; ++i) + testLabel(0, i - trainSize) = inputLabel(0, i); + } } } @@ -467,21 +487,36 @@ void Split(const FieldType& input, trainData.set_size(1, trainSize); testData.set_size(1, testSize); - arma::uvec order = arma::linspace(0, input.n_cols - 1, - input.n_cols); if (shuffleData) - order = arma::shuffle(order); - - if (trainSize > 0) { - for (size_t i = 0; i < trainSize; i++) - trainData[i] = input(0, order(i)); + arma::uvec order = arma::shuffle(arma::linspace(0, + input.n_cols - 1, input.n_cols)); + + if (trainSize > 0) + { + for (size_t i = 0; i < trainSize; i++) + trainData[i] = input(0, order(i)); + } + + if (trainSize < input.n_cols) + { + for (size_t i = trainSize; i < input.n_cols - 1; ++i) + testData[i - trainSize] = input(0, order(i)); + } } - - if (testSize <= input.n_cols) + else { - for (size_t i = trainSize; i < input.n_cols - 1; ++i) - testData[i - trainSize] = input(0, order(i)); + if (trainSize > 0) + { + for (size_t i = 0; i < trainSize; i++) + trainData[i] = input(0, i); + } + + if (trainSize < input.n_cols) + { + for (size_t i = trainSize; i < input.n_cols - 1; ++i) + testData[i - trainSize] = input(0, i); + } } } @@ -517,8 +552,8 @@ template ::value || arma::is_Mat_only::value>> std::tuple -Split(FieldType& input, - arma::field& inputLabel, +Split(const FieldType& input, + const arma::field& inputLabel, const double testRatio, const bool shuffleData = true) { @@ -528,7 +563,7 @@ Split(FieldType& input, arma::field testLabel; Split(input, inputLabel, trainData, testData, trainLabel, testLabel, - testRatio, shuffleData); + testRatio, shuffleData); return std::make_tuple(std::move(trainData), std::move(testData), From e837763302237357b0b0fc2eadfb1ce9dfc6a4ff Mon Sep 17 00:00:00 2001 From: Anush Kini <33577829+Abilityguy@users.noreply.github.com> Date: Fri, 26 Feb 2021 17:02:22 +0530 Subject: [PATCH 202/253] Review changes made to test suite 1. Restored blank lines that were removed in a previous commit. 2. Edited test ```SplitMatrixLabeledDataResultMat``` to ```SplitMatrixLabeledData``` and made changes to fix this failing test. --- src/mlpack/tests/split_data_test.cpp | 97 ++++++++++++++++------------ 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index 74862469ba..1419756e5b 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -121,29 +121,6 @@ TEST_CASE("SplitDataResultMat", "[SplitDataTest]") CheckMatrices(input, concat); } -TEST_CASE("SplitDataResultField", "[SplitDataTest]") -{ - field input(1, 2); - - mat matA(2, 10); - mat matB(2, 10); - - size_t count = 0; // Counter for unique sequential values. - matA.imbue([&count]() { return ++count; }); - matB.imbue([&count]() { return ++count; }); - - input(0, 0) = matA; - input(0, 1) = matB; - - const auto value = Split(input, 0.5, false); - REQUIRE(std::get<0>(value).n_cols == 1); // Train data. - REQUIRE(std::get<1>(value).n_cols == 1); // Test data. - - field concat = {std::get<0>(value)(0), std::get<1>(value)(0)}; - // Order matters here. - CheckFields(input, concat); -} - TEST_CASE("ZeroRatioSplitData", "[SplitDataTest]") { mat input(2, 10); @@ -198,26 +175,6 @@ TEST_CASE("SplitLabeledDataResultMat", "[SplitDataTest]") CheckDuplication(std::get<2>(value), std::get<3>(value)); } -TEST_CASE("SplitMatrixLabeledDataResultMat", "[SplitDataTest]") -{ - mat input(2, 10); - input.randu(); - - const mat labels(2, 10, fill::randu); - - const auto value = Split(input, labels, 0.2); - REQUIRE(std::get<0>(value).n_cols == 8); - REQUIRE(std::get<1>(value).n_cols == 2); - REQUIRE(std::get<2>(value).n_cols == 8); - REQUIRE(std::get<3>(value).n_cols == 2); - - mat input_concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); - mat labels_concat = arma::join_rows(std::get<2>(value), std::get<3>(value)); - // Order matters here. - CheckMatrices(input, input_concat); - CheckMatrices(labels, labels_concat); -} - /** * The same test as above, but on a larger dataset. */ @@ -334,28 +291,34 @@ TEST_CASE("StratifiedSplitLargerDataResultTest", "[SplitDataTest]") { mat input(3, 480); input.randu(); + // 256 0s, 128 1s, 64 2s and 32 3s. Row zero_label(256); Row one_label(128); Row two_label(64); Row three_label(32); + zero_label.fill(0); one_label.fill(1); two_label.fill(2); three_label.fill(3); + Row labels = arma::join_rows(zero_label, one_label); labels = arma::join_rows(labels, two_label); labels = arma::join_rows(labels, three_label); const double test_ratio = 0.3; + const auto value = Split(input, labels, test_ratio, false, true); REQUIRE(static_cast(find(std::get<2>(value) == 0)).n_rows == 180); REQUIRE(static_cast(find(std::get<2>(value) == 1)).n_rows == 90); REQUIRE(static_cast(find(std::get<2>(value) == 2)).n_rows == 45); REQUIRE(static_cast(find(std::get<2>(value) == 3)).n_rows == 23); + REQUIRE(static_cast(find(std::get<3>(value) == 0)).n_rows == 76); REQUIRE(static_cast(find(std::get<3>(value) == 1)).n_rows == 38); REQUIRE(static_cast(find(std::get<3>(value) == 2)).n_rows == 19); REQUIRE(static_cast(find(std::get<3>(value) == 3)).n_rows == 9); + mat concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); CheckMatEqual(input, concat); } @@ -376,3 +339,51 @@ TEST_CASE("StratifiedSplitRunTimeErrorTest", "[SplitDataTest]") REQUIRE_THROWS_AS(Split(input, labels, test_ratio, false, true), std::runtime_error); } + +/* + * Split with input of type field<>. + */ +TEST_CASE("SplitDataResultField", "[SplitDataTest]") +{ + field input(1, 2); + + mat matA(2, 10); + mat matB(2, 10); + + size_t count = 0; // Counter for unique sequential values. + matA.imbue([&count]() { return ++count; }); + matB.imbue([&count]() { return ++count; }); + + input(0, 0) = matA; + input(0, 1) = matB; + + const auto value = Split(input, 0.5, false); + REQUIRE(std::get<0>(value).n_cols == 1); // Train data. + REQUIRE(std::get<1>(value).n_cols == 1); // Test data. + + field concat = {std::get<0>(value)(0), std::get<1>(value)(0)}; + // Order matters here. + CheckFields(input, concat); +} + +/** + * Test for Split() with labels of type arma::Mat with shuffleData = False. + */ +TEST_CASE("SplitMatrixLabeledData", "[SplitDataTest]") +{ + const mat input(2, 10, fill::randu); + const mat labels(2, 10, fill::randu); + + const auto value = Split(input, labels, 0.2, false); + REQUIRE(std::get<0>(value).n_cols == 8); + REQUIRE(std::get<1>(value).n_cols == 2); + REQUIRE(std::get<2>(value).n_cols == 8); + REQUIRE(std::get<3>(value).n_cols == 2); + + mat input_concat = arma::join_rows(std::get<0>(value), std::get<1>(value)); + mat labels_concat = arma::join_rows(std::get<2>(value), std::get<3>(value)); + + // Order matters here. + CheckMatrices(input, input_concat); + CheckMatrices(labels, labels_concat); +} From c74ef9cc22a345a4a44b27bcf4c4c6fc62239b3d Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Sat, 27 Feb 2021 18:13:01 +0530 Subject: [PATCH 203/253] order is init in Stratified Split only when shuffleData is true --- src/mlpack/core/data/split_data.hpp | 67 ++++++++++++++++++----------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 370128dfc6..1c7b6578fe 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -23,7 +23,7 @@ namespace data { * It is recommended to have the input labels between the range [0, n) where n * is the number of different labels. The NormalizeLabels() function in * mlpack::data can be used for this. - * Expects labels to be of type arma::Row<>. + * Expects labels to be of type arma::Row<> or arma::Col<>. * Throws a runtime error if this is not the case. * Example usage below. This overload places the stratified dataset into the * four output parameters given (trainData, testData, trainLabel, @@ -65,7 +65,9 @@ void StratifiedSplit(const arma::Mat& input, const double testRatio, const bool shuffleData = true) { - if (!arma::is_Row::value) + const bool typeCheck = (arma::is_Row::value) + || (arma::is_Col::value); + if (!typeCheck) throw std::runtime_error("data::Split(): when stratified sampling is done, " "labels must have type `arma::Row<>`!"); size_t trainIdx = 0; @@ -79,18 +81,8 @@ void StratifiedSplit(const arma::Mat& input, labelCounts.zeros(maxLabel+1); testLabelCounts.zeros(maxLabel+1); - arma::uvec order = - arma::linspace(0, input.n_cols - 1, input.n_cols); - - if (shuffleData) - { - order = arma::shuffle(order); - } - for (typename LabelsType::elem_type label : inputLabel) - { ++labelCounts[label]; - } for (arma::uword labelCount : labelCounts) { @@ -103,21 +95,47 @@ void StratifiedSplit(const arma::Mat& input, trainLabel.set_size(trainSize); testLabel.set_size(testSize); - for (arma::uword i : order) + if (shuffleData) { - typename LabelsType::elem_type label = inputLabel[i]; - if (testLabelCounts[label] < floor(labelCounts[label] * testRatio)) + arma::uvec order = arma::shuffle( + arma::linspace(0, input.n_cols - 1, input.n_cols)); + + for (arma::uword i : order) { - testLabelCounts[label] += 1; - testData.col(testIdx) = input.col(i); - testLabel[testIdx] = inputLabel[i]; - testIdx += 1; + typename LabelsType::elem_type label = inputLabel[i]; + if (testLabelCounts[label] < floor(labelCounts[label] * testRatio)) + { + testLabelCounts[label] += 1; + testData.col(testIdx) = input.col(i); + testLabel[testIdx] = inputLabel[i]; + testIdx += 1; + } + else + { + trainData.col(trainIdx) = input.col(i); + trainLabel[trainIdx] = inputLabel[i]; + trainIdx += 1; + } } - else + } + else + { + for (arma::uword i = 0; i < input.n_cols; i++) { - trainData.col(trainIdx) = input.col(i); - trainLabel[trainIdx] = inputLabel[i]; - trainIdx += 1; + typename LabelsType::elem_type label = inputLabel[i]; + if (testLabelCounts[label] < floor(labelCounts[label] * testRatio)) + { + testLabelCounts[label] += 1; + testData.col(testIdx) = input.col(i); + testLabel[testIdx] = inputLabel[i]; + testIdx += 1; + } + else + { + trainData.col(trainIdx) = input.col(i); + trainLabel[trainIdx] = inputLabel[i]; + trainIdx += 1; + } } } } @@ -285,7 +303,8 @@ void Split(const arma::Mat& input, * sample is visited in linear order. (Default true). * @param stratifyData If true, the train and test splits are stratified * so that the ratio of each class in the training and test sets is the same - * as in the original dataset. Expects labels to be of type arma::Row<>. + * as in the original dataset. Expects labels to be of type arma::Row<> or + * arma::Col<>. * @return std::tuple containing trainData (arma::Mat), testData * (arma::Mat), trainLabel (arma::Row), and testLabel (arma::Row). */ From 26e311ac7286bb808b7a063e83db1578ec0184b2 Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Sat, 27 Feb 2021 20:41:54 +0530 Subject: [PATCH 204/253] Added test with label of type field and other review fixes --- src/mlpack/core/data/split_data.hpp | 38 +++++++++++++++++----------- src/mlpack/tests/split_data_test.cpp | 36 +++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 1c7b6578fe..da4c240ca2 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -420,8 +420,11 @@ void Split(const FieldType& input, { const size_t testSize = static_cast(input.n_cols * testRatio); const size_t trainSize = input.n_cols - testSize; - trainLabel.set_size(1, trainSize); - testLabel.set_size(1, testSize); + + trainData.set_size(1, trainSize); + testData.set_size(1, testSize); + trainLabel.set_size(trainSize); + testLabel.set_size(testSize); if (shuffleData) { @@ -430,34 +433,39 @@ void Split(const FieldType& input, if (trainSize > 0) { - trainData = input.cols(order.subvec(0, trainSize - 1)); - for (size_t i = 0; i < trainSize; ++i) - trainLabel(0, i) = inputLabel(0, order(i)); + { + trainData[i] = input(0, order(i)); + trainLabel[i] = inputLabel(0, order(i)); + } } - if (trainSize < input.n_cols) { - testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); - for (size_t i = trainSize; i < input.n_cols; ++i) - testLabel(0, i - trainSize) = inputLabel(0, order(i)); + { + testData[i - trainSize] = input(0, order(i)); + testLabel[i - trainSize] = inputLabel(0, order(i)); + } } } else { if (trainSize > 0) { - trainData = input.cols(0, trainSize - 1); for (size_t i = 0; i < trainSize; ++i) - trainLabel(0, i) = inputLabel(0, i); + { + trainData[i] = input(0, i); + trainLabel[i] = inputLabel(0, i); + } } if (trainSize < input.n_cols) { - testData = input.cols(trainSize, input.n_cols - 1); for (size_t i = trainSize; i < input.n_cols; ++i) - testLabel(0, i - trainSize) = inputLabel(0, i); + { + testData[i - trainSize] = input(0, i); + testLabel[i - trainSize] = inputLabel(0, i); + } } } } @@ -570,7 +578,7 @@ template ::value || arma::is_Mat_only::value>> -std::tuple +std::tuple, arma::field> Split(const FieldType& input, const arma::field& inputLabel, const double testRatio, @@ -581,7 +589,7 @@ Split(const FieldType& input, arma::field trainLabel; arma::field testLabel; - Split(input, inputLabel, trainData, testData, trainLabel, testLabel, + Split(input, inputLabel, trainData, trainLabel, testData, testLabel, testRatio, shuffleData); return std::make_tuple(std::move(trainData), diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index 1419756e5b..8d2b5e470e 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -341,7 +341,7 @@ TEST_CASE("StratifiedSplitRunTimeErrorTest", "[SplitDataTest]") } /* - * Split with input of type field<>. + * Split with input of type field. */ TEST_CASE("SplitDataResultField", "[SplitDataTest]") { @@ -387,3 +387,37 @@ TEST_CASE("SplitMatrixLabeledData", "[SplitDataTest]") CheckMatrices(input, input_concat); CheckMatrices(labels, labels_concat); } + +/* + * Split with input of type field and label of type field. + */ +TEST_CASE("SplitLabeledDataResultField", "[SplitDataTest]") +{ + field input(1, 2); + field label(1, 2); + + mat matA(2, 10, fill::randu); + mat matB(2, 10, fill::randu); + + vec vecA(10, fill::randu); + vec vecB(10, fill::randu); + + input(0, 0) = matA; + input(0, 1) = matB; + + label(0, 0) = vecA; + label(0, 1) = vecB; + + const auto value = Split(input, label, 0.5, false); + REQUIRE(std::get<0>(value).n_cols == 1); // Train data. + REQUIRE(std::get<1>(value).n_cols == 1); // Test data. + REQUIRE(std::get<2>(value).n_cols == 1); // Train label. + REQUIRE(std::get<3>(value).n_cols == 1); // Test label. + + field input_concat = {std::get<0>(value)(0), std::get<1>(value)(0)}; + field label_concat = {std::get<2>(value)(0), std::get<3>(value)(0)}; + + // Order matters here. + CheckFields(input, input_concat); + CheckFields(label, label_concat); +} From 332bbd4ea27cf3f397e8fbae41b724b7f193082d Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Sun, 12 Apr 2020 23:32:58 +0530 Subject: [PATCH 205/253] CheckSameSize() added --- src/mlpack/core/util/CMakeLists.txt | 1 + src/mlpack/core/util/facilities.hpp | 71 +++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/mlpack/core/util/facilities.hpp diff --git a/src/mlpack/core/util/CMakeLists.txt b/src/mlpack/core/util/CMakeLists.txt index 19ddff3293..4872652826 100644 --- a/src/mlpack/core/util/CMakeLists.txt +++ b/src/mlpack/core/util/CMakeLists.txt @@ -33,6 +33,7 @@ set(SOURCES to_lower.hpp version.hpp version.cpp + facilities.hpp ) # add directory name to sources diff --git a/src/mlpack/core/util/facilities.hpp b/src/mlpack/core/util/facilities.hpp new file mode 100644 index 0000000000..dee4cd7ee8 --- /dev/null +++ b/src/mlpack/core/util/facilities.hpp @@ -0,0 +1,71 @@ +/** + * @file facilities.hpp + * @author Kirill Mishchenko + * @author Bisakh Mondal + * + * Utility that is used for checking same size & same dimensionality between + * data & response. + * + * 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. + */ +#ifndef MLPACK_UTIL_FACILITIES_HPP +#define MLPACK_UTIL_FACILITIES_HPP + +#include + +namespace mlpack { +namespace util { + +/** + * Check for if the given data points & labels have same size. + * + * @param data data. + * @param labels Labels. + * @param callerDescription A description of the caller that can be used for + * error generation. + * @param mode For nature of comparision(default "CE"). + * types of mode: + * "CE" equivalent to (data.n_cols, labels.n_elem). + * "CC" equivalent to (data.n_cols, labels.n_cols). + */ +template +inline void CheckSameSizes(const DataType& data, + const LabelsType& labels, + const std::string& callerDescription, + const std::string& mode = "CE") +{ + if (mode == "CE") + { + if (data.n_cols != labels.n_elem) + { + std::ostringstream oss; + oss << callerDescription << ": number of points (" << data.n_cols << ") " + << "does not match number of labels (" << labels.n_elem << ")!" + << std::endl; + throw std::invalid_argument(oss.str()); + } + } + else if (mode == "CC") + { + if (data.n_cols != labels.n_cols) + { + std::ostringstream oss; + oss << callerDescription << ": number of points (" << data.n_cols << ") " + << "does not match number of responses (" << labels.n_cols << ")!" + << std::endl; + throw std::invalid_argument(oss.str()); + } + } + else + //For development purpose, not intended for user. + Log::Fatal << "Ensure Providing Correct mode!!" << std::endl; + +} + +} // namespace util +} // namespace mlpack + +#endif From 5a328bae3f6069e83bd09d8a947dc23b500297c1 Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Mon, 13 Apr 2020 02:05:52 +0530 Subject: [PATCH 206/253] CheckSameDimensionality() added --- src/mlpack/core/util/facilities.hpp | 56 +++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/src/mlpack/core/util/facilities.hpp b/src/mlpack/core/util/facilities.hpp index dee4cd7ee8..b466634eb2 100644 --- a/src/mlpack/core/util/facilities.hpp +++ b/src/mlpack/core/util/facilities.hpp @@ -3,8 +3,7 @@ * @author Kirill Mishchenko * @author Bisakh Mondal * - * Utility that is used for checking same size & same dimensionality between - * data & response. + * Utility for checking same size & same dimensionality. * * 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 @@ -33,9 +32,9 @@ namespace util { */ template inline void CheckSameSizes(const DataType& data, - const LabelsType& labels, - const std::string& callerDescription, - const std::string& mode = "CE") + const LabelsType& labels, + const std::string& callerDescription, + const std::string& mode = "CE") { if (mode == "CE") { @@ -59,13 +58,58 @@ inline void CheckSameSizes(const DataType& data, throw std::invalid_argument(oss.str()); } } + else + //For development purpose, not intended for user. + Log::Fatal << "Ensure Providing Correct mode." << std::endl; + +} + +/** + * Check for if the given dataset dimension matches with the model's. + * + * @param data dataset. + * @param dimension Dimension of the model. + * @param callerDescription A description of the caller that can be used for + * error generation. + * @param mode For nature of comparision(default "R"). + * types of mode: + * "R" for comparision with number of rows of the dataset. + * "C" for comparision with number of columns of the dataset. + */ +template +inline void CheckSameDimentionality(const DataType& data, + const size_t& dimension, + const std::string& callerDescription, + const std::string& mode = "R") +{ + if (mode == "R") + { + if (data.n_rows != dimension) + { + std::ostringstream oss; + oss << callerDescription << ": dataset has " << data.n_rows + << " dimensions, but model has " << dimension << " dimensions!"; + throw std::invalid_argument(oss.str()); + } + } + else if (mode == "C") + { + if (data.n_cols != dimension) + { + std::ostringstream oss; + oss << callerDescription << ": dataset has " << data.n_cols + << " dimensions, but model has " << dimension << " dimensions!"; + throw std::invalid_argument(oss.str()); + } + } else //For development purpose, not intended for user. Log::Fatal << "Ensure Providing Correct mode!!" << std::endl; - + } } // namespace util } // namespace mlpack #endif + From 1dd543b5518bdab70c415f5844e30e97624fbb20 Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Mon, 13 Apr 2020 02:06:45 +0530 Subject: [PATCH 207/253] Added header file to core.hpp --- src/mlpack/core.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mlpack/core.hpp b/src/mlpack/core.hpp index b4645d2b09..7c73678163 100644 --- a/src/mlpack/core.hpp +++ b/src/mlpack/core.hpp @@ -89,6 +89,8 @@ #include #include #include +#include +#include // mlpack::backtrace only for linux #ifdef HAS_BFD_DL From ed6bb2af15079661cb34ec709e98427e12d8522c Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Mon, 13 Apr 2020 02:07:28 +0530 Subject: [PATCH 208/253] Tests added --- src/mlpack/tests/facilities_test.cpp | 55 +++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/mlpack/tests/facilities_test.cpp b/src/mlpack/tests/facilities_test.cpp index 65b754bb4e..5d95734fca 100644 --- a/src/mlpack/tests/facilities_test.cpp +++ b/src/mlpack/tests/facilities_test.cpp @@ -1,8 +1,9 @@ /** * @file facilities_test.cpp * @author Khizir Siddiqui - * - * Test file for facilities in metrics. + * @author Bisakh Mondal + * + * Test file for Utility facilities. * * 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 @@ -14,11 +15,15 @@ #include #include #include +#include #include "catch.hpp" using namespace mlpack; using namespace mlpack::cv; +using namespace mlpack::util; + +BOOST_AUTO_TEST_SUITE(FacilityTest); /** * The unequal sizes for data and labels show throw an error. @@ -54,3 +59,49 @@ TEST_CASE("PairwiseDistanceTest", "[FacilitiesTest]") REQUIRE(dist(1, 0) == Approx(1.41421).epsilon(1e-5)); REQUIRE(dist(2, 0) == 3); } + + +/** + * Test that CheckSameSizes() works in different cases. + */ +BOOST_AUTO_TEST_CASE(CheckSizeTest) +{ + arma::mat data = arma::randu(20,30); + arma::colvec firstLabels = arma::randu(20); + arma::colvec secondLabels = arma::randu(30); + arma::mat thirdLabels = arma::randu(20,30); + + BOOST_REQUIRE_THROW(CheckSameSizes(data,firstLabels,"TestChecking"), + std::invalid_argument); + BOOST_REQUIRE_THROW(CheckSameSizes(data,firstLabels,"TestChecking","CC"), + std::invalid_argument); + BOOST_REQUIRE_THROW(CheckSameSizes(data,firstLabels,"TestChecking","AB"), + std::runtime_error); + + BOOST_REQUIRE_NO_THROW(CheckSameSizes(data,secondLabels,"TestChecking")); + BOOST_REQUIRE_NO_THROW(CheckSameSizes(data,thirdLabels,"TestChecking", + "CC")); + +} + + +/** + * Test that CheckSameDimensionality() works in different cases. + */ +BOOST_AUTO_TEST_CASE(CheckDimensioinality) +{ + arma::mat dataset = arma::randu(20,30); + + BOOST_REQUIRE_NO_THROW(CheckSameDimentionality(dataset,20,"TestingDim")); + BOOST_REQUIRE_NO_THROW(CheckSameDimentionality(dataset,30,"TestingDim", + "C")); + + BOOST_REQUIRE_THROW(CheckSameDimentionality(dataset, 100, "TestingDim"), + std::invalid_argument); + BOOST_REQUIRE_THROW(CheckSameDimentionality(dataset, 50, "TestingDim", "C"), + std::invalid_argument); + BOOST_REQUIRE_THROW(CheckSameDimentionality(dataset, 20, "TestingDim", "A"), + std::runtime_error); +} + +BOOST_AUTO_TEST_SUITE_END(); From 2e0e08edbf6694df6f2db09a12493736b0405b98 Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Mon, 13 Apr 2020 04:04:50 +0530 Subject: [PATCH 209/253] Old updated --- src/mlpack/core/cv/metrics/CMakeLists.txt | 1 - src/mlpack/core/cv/metrics/accuracy_impl.hpp | 4 +--- src/mlpack/core/cv/metrics/f1_impl.hpp | 7 +++---- src/mlpack/core/cv/metrics/precision_impl.hpp | 7 +++---- src/mlpack/core/cv/metrics/recall_impl.hpp | 7 +++---- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/mlpack/core/cv/metrics/CMakeLists.txt b/src/mlpack/core/cv/metrics/CMakeLists.txt index b9edacaf9a..e2322e673c 100644 --- a/src/mlpack/core/cv/metrics/CMakeLists.txt +++ b/src/mlpack/core/cv/metrics/CMakeLists.txt @@ -6,7 +6,6 @@ set(SOURCES average_strategy.hpp f1.hpp f1_impl.hpp - facilities.hpp mse.hpp mse_impl.hpp precision.hpp diff --git a/src/mlpack/core/cv/metrics/accuracy_impl.hpp b/src/mlpack/core/cv/metrics/accuracy_impl.hpp index 91f3dc1c3e..b6f08332af 100644 --- a/src/mlpack/core/cv/metrics/accuracy_impl.hpp +++ b/src/mlpack/core/cv/metrics/accuracy_impl.hpp @@ -12,8 +12,6 @@ #ifndef MLPACK_CORE_CV_METRICS_ACCURACY_IMPL_HPP #define MLPACK_CORE_CV_METRICS_ACCURACY_IMPL_HPP -#include - namespace mlpack { namespace cv { @@ -22,7 +20,7 @@ double Accuracy::Evaluate(MLAlgorithm& model, const DataType& data, const arma::Row& labels) { - AssertSizes(data, labels, "Accuracy::Evaluate()"); + util::CheckSameSizes(data, labels, "Accuracy::Evaluate()"); arma::Row predictedLabels; model.Classify(data, predictedLabels); diff --git a/src/mlpack/core/cv/metrics/f1_impl.hpp b/src/mlpack/core/cv/metrics/f1_impl.hpp index 6e89754941..5af0558a68 100644 --- a/src/mlpack/core/cv/metrics/f1_impl.hpp +++ b/src/mlpack/core/cv/metrics/f1_impl.hpp @@ -13,7 +13,6 @@ #define MLPACK_CORE_CV_METRICS_F1_IMPL_HPP #include -#include namespace mlpack { namespace cv { @@ -33,7 +32,7 @@ double F1::Evaluate(MLAlgorithm& model, const DataType& data, const arma::Row& labels) { - AssertSizes(data, labels, "F1::Evaluate()"); + util::CheckSameSizes(data, labels, "F1::Evaluate()"); arma::Row predictedLabels; model.Classify(data, predictedLabels); @@ -56,7 +55,7 @@ double F1::Evaluate(MLAlgorithm& model, const DataType& data, const arma::Row& labels) { - AssertSizes(data, labels, "F1::Evaluate()"); + util::CheckSameSizes(data, labels, "F1::Evaluate()"); // Microaveraged F1 is really the same as microaveraged precision and // microaveraged recall, which are in turn the same as accuracy. @@ -70,7 +69,7 @@ double F1::Evaluate(MLAlgorithm& model, const DataType& data, const arma::Row& labels) { - AssertSizes(data, labels, "F1::Evaluate()"); + util::CheckSameSizes(data, labels, "F1::Evaluate()"); arma::Row predictedLabels; model.Classify(data, predictedLabels); diff --git a/src/mlpack/core/cv/metrics/precision_impl.hpp b/src/mlpack/core/cv/metrics/precision_impl.hpp index b8831fe132..25afd43454 100644 --- a/src/mlpack/core/cv/metrics/precision_impl.hpp +++ b/src/mlpack/core/cv/metrics/precision_impl.hpp @@ -13,7 +13,6 @@ #define MLPACK_CORE_CV_METRICS_PRECISION_IMPL_HPP #include -#include namespace mlpack { namespace cv { @@ -33,7 +32,7 @@ double Precision::Evaluate(MLAlgorithm& model, const DataType& data, const arma::Row& labels) { - AssertSizes(data, labels, "Precision::Evaluate()"); + util::CheckSameSizes(data, labels, "Precision::Evaluate()"); arma::Row predictedLabels; model.Classify(data, predictedLabels); @@ -51,7 +50,7 @@ double Precision::Evaluate(MLAlgorithm& model, const DataType& data, const arma::Row& labels) { - AssertSizes(data, labels, "Precision::Evaluate()"); + util::CheckSameSizes(data, labels, "Precision::Evaluate()"); // Microaveraged precision turns out to be just accuracy. return Accuracy::Evaluate(model, data, labels); @@ -64,7 +63,7 @@ double Precision::Evaluate(MLAlgorithm& model, const DataType& data, const arma::Row& labels) { - AssertSizes(data, labels, "Precision::Evaluate()"); + util::CheckSameSizes(data, labels, "Precision::Evaluate()"); arma::Row predictedLabels; model.Classify(data, predictedLabels); diff --git a/src/mlpack/core/cv/metrics/recall_impl.hpp b/src/mlpack/core/cv/metrics/recall_impl.hpp index 5ff7bd7400..bbfbe7071d 100644 --- a/src/mlpack/core/cv/metrics/recall_impl.hpp +++ b/src/mlpack/core/cv/metrics/recall_impl.hpp @@ -13,7 +13,6 @@ #define MLPACK_CORE_CV_METRICS_RECALL_IMPL_HPP #include -#include namespace mlpack { namespace cv { @@ -33,7 +32,7 @@ double Recall::Evaluate(MLAlgorithm& model, const DataType& data, const arma::Row& labels) { - AssertSizes(data, labels, "Recall::Evaluate()"); + util::CheckSameSizes(data, labels, "Recall::Evaluate()"); arma::Row predictedLabels; model.Classify(data, predictedLabels); @@ -51,7 +50,7 @@ double Recall::Evaluate(MLAlgorithm& model, const DataType& data, const arma::Row& labels) { - AssertSizes(data, labels, "Recall::Evaluate()"); + util::CheckSameSizes(data, labels, "Recall::Evaluate()"); // Microaveraged recall is really the same as accuracy. return Accuracy::Evaluate(model, data, labels); @@ -64,7 +63,7 @@ double Recall::Evaluate(MLAlgorithm& model, const DataType& data, const arma::Row& labels) { - AssertSizes(data, labels, "Recall::Evaluate()"); + util::CheckSameSizes(data, labels, "Recall::Evaluate()"); arma::Row predictedLabels; model.Classify(data, predictedLabels); From e8cba43562a1013f9c74d192935f28ded8738d3f Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Mon, 13 Apr 2020 04:08:04 +0530 Subject: [PATCH 210/253] unnecessary file removed --- src/mlpack/core/cv/metrics/facilities.hpp | 71 ----------------------- 1 file changed, 71 deletions(-) delete mode 100644 src/mlpack/core/cv/metrics/facilities.hpp diff --git a/src/mlpack/core/cv/metrics/facilities.hpp b/src/mlpack/core/cv/metrics/facilities.hpp deleted file mode 100644 index c7b9b4b70e..0000000000 --- a/src/mlpack/core/cv/metrics/facilities.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file core/cv/metrics/facilities.hpp - * @author Kirill Mishchenko - * @author Khizir Siddiqui - * - * Functionality that is used more than in one metric. - * - * 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. - */ -#ifndef MLPACK_CORE_CV_METRICS_FACILITIES_HPP -#define MLPACK_CORE_CV_METRICS_FACILITIES_HPP - -#include -#include - -namespace mlpack { -namespace cv { - -/** - * Assert there is the same number of the given data points and labels. - * - * @param data Column-major data. - * @param labels Labels. - * @param callerDescription A description of the caller that can be used for - * error generation. - */ -template -void AssertSizes(const DataType& data, - const arma::Row& labels, - const std::string& callerDescription) -{ - if (data.n_cols != labels.n_elem) - { - std::ostringstream oss; - oss << callerDescription << ": number of points (" << data.n_cols << ") " - << "does not match number of labels (" << labels.n_elem << ")!" - << std::endl; - throw std::invalid_argument(oss.str()); - } -} - -/** - * Pairwise distance of the given data. - * - * @param data Column-major matrix. - * @param metric Distance metric to be used. - */ -template -DataType PairwiseDistances(const DataType& data, - const Metric& metric) -{ - DataType distances = DataType(data.n_cols, data.n_cols, arma::fill::none); - for (size_t i = 0; i < data.n_cols; i++) - { - for (size_t j = 0; j < i; j++) - { - distances(i, j) = metric.Evaluate(data.col(i), data.col(j)); - distances(j, i) = distances(i, j); - } - } - distances.diag().zeros(); - return distances; -} - -} // namespace cv -} // namespace mlpack - -#endif From 72e000f09bdd7d509b3f621c259836a15e188752 Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Mon, 13 Apr 2020 09:41:30 +0530 Subject: [PATCH 211/253] spelling error corrected --- src/mlpack/core/util/facilities.hpp | 2 +- src/mlpack/tests/facilities_test.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mlpack/core/util/facilities.hpp b/src/mlpack/core/util/facilities.hpp index b466634eb2..5a7d22069e 100644 --- a/src/mlpack/core/util/facilities.hpp +++ b/src/mlpack/core/util/facilities.hpp @@ -77,7 +77,7 @@ inline void CheckSameSizes(const DataType& data, * "C" for comparision with number of columns of the dataset. */ template -inline void CheckSameDimentionality(const DataType& data, +inline void CheckSameDimensionality(const DataType& data, const size_t& dimension, const std::string& callerDescription, const std::string& mode = "R") diff --git a/src/mlpack/tests/facilities_test.cpp b/src/mlpack/tests/facilities_test.cpp index 5d95734fca..4b1042fe72 100644 --- a/src/mlpack/tests/facilities_test.cpp +++ b/src/mlpack/tests/facilities_test.cpp @@ -88,19 +88,19 @@ BOOST_AUTO_TEST_CASE(CheckSizeTest) /** * Test that CheckSameDimensionality() works in different cases. */ -BOOST_AUTO_TEST_CASE(CheckDimensioinality) +BOOST_AUTO_TEST_CASE(CheckDimensionality) { arma::mat dataset = arma::randu(20,30); - BOOST_REQUIRE_NO_THROW(CheckSameDimentionality(dataset,20,"TestingDim")); - BOOST_REQUIRE_NO_THROW(CheckSameDimentionality(dataset,30,"TestingDim", + BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset,20,"TestingDim")); + BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset,30,"TestingDim", "C")); - BOOST_REQUIRE_THROW(CheckSameDimentionality(dataset, 100, "TestingDim"), + BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, 100, "TestingDim"), std::invalid_argument); - BOOST_REQUIRE_THROW(CheckSameDimentionality(dataset, 50, "TestingDim", "C"), + BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, 50, "TestingDim", "C"), std::invalid_argument); - BOOST_REQUIRE_THROW(CheckSameDimentionality(dataset, 20, "TestingDim", "A"), + BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, 20, "TestingDim", "A"), std::runtime_error); } From f02fe11fbc7f7a430de879f281c13be7894d925e Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Mon, 13 Apr 2020 10:19:15 +0530 Subject: [PATCH 212/253] style issue fixed --- src/mlpack/core/util/facilities.hpp | 6 ++---- src/mlpack/tests/facilities_test.cpp | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/mlpack/core/util/facilities.hpp b/src/mlpack/core/util/facilities.hpp index 5a7d22069e..bd9605b460 100644 --- a/src/mlpack/core/util/facilities.hpp +++ b/src/mlpack/core/util/facilities.hpp @@ -59,9 +59,8 @@ inline void CheckSameSizes(const DataType& data, } } else - //For development purpose, not intended for user. + // For development purpose, not intended for user. Log::Fatal << "Ensure Providing Correct mode." << std::endl; - } /** @@ -103,9 +102,8 @@ inline void CheckSameDimensionality(const DataType& data, } } else - //For development purpose, not intended for user. + // For development purpose, not intended for user. Log::Fatal << "Ensure Providing Correct mode!!" << std::endl; - } } // namespace util diff --git a/src/mlpack/tests/facilities_test.cpp b/src/mlpack/tests/facilities_test.cpp index 4b1042fe72..11ee5c68b1 100644 --- a/src/mlpack/tests/facilities_test.cpp +++ b/src/mlpack/tests/facilities_test.cpp @@ -66,22 +66,21 @@ TEST_CASE("PairwiseDistanceTest", "[FacilitiesTest]") */ BOOST_AUTO_TEST_CASE(CheckSizeTest) { - arma::mat data = arma::randu(20,30); + arma::mat data = arma::randu(20, 30); arma::colvec firstLabels = arma::randu(20); arma::colvec secondLabels = arma::randu(30); - arma::mat thirdLabels = arma::randu(20,30); + arma::mat thirdLabels = arma::randu(20, 30); - BOOST_REQUIRE_THROW(CheckSameSizes(data,firstLabels,"TestChecking"), + BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking"), std::invalid_argument); - BOOST_REQUIRE_THROW(CheckSameSizes(data,firstLabels,"TestChecking","CC"), + BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking", "CC"), std::invalid_argument); - BOOST_REQUIRE_THROW(CheckSameSizes(data,firstLabels,"TestChecking","AB"), + BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking", "AB"), std::runtime_error); - BOOST_REQUIRE_NO_THROW(CheckSameSizes(data,secondLabels,"TestChecking")); - BOOST_REQUIRE_NO_THROW(CheckSameSizes(data,thirdLabels,"TestChecking", + BOOST_REQUIRE_NO_THROW(CheckSameSizes(data, secondLabels, "TestChecking")); + BOOST_REQUIRE_NO_THROW(CheckSameSizes(data, thirdLabels, "TestChecking", "CC")); - } @@ -90,10 +89,10 @@ BOOST_AUTO_TEST_CASE(CheckSizeTest) */ BOOST_AUTO_TEST_CASE(CheckDimensionality) { - arma::mat dataset = arma::randu(20,30); + arma::mat dataset = arma::randu(20, 30); - BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset,20,"TestingDim")); - BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset,30,"TestingDim", + BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset, 20, "TestingDim")); + BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset, 30, "TestingDim", "C")); BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, 100, "TestingDim"), From bd8710d53483493407200defeaa6c7e368512df6 Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Tue, 28 Apr 2020 21:49:36 +0530 Subject: [PATCH 213/253] Size Check Suite added --- src/mlpack/core/util/size_checks.hpp | 108 ++++++++++++++++++++++++++ src/mlpack/tests/size_checks_test.cpp | 62 +++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 src/mlpack/core/util/size_checks.hpp create mode 100644 src/mlpack/tests/size_checks_test.cpp diff --git a/src/mlpack/core/util/size_checks.hpp b/src/mlpack/core/util/size_checks.hpp new file mode 100644 index 0000000000..7a02a2ee5e --- /dev/null +++ b/src/mlpack/core/util/size_checks.hpp @@ -0,0 +1,108 @@ +/** + * @file size_checks.hpp + * @author Kirill Mishchenko + * @author Bisakh Mondal + * + * Utility for checking same size & same dimensionality. + * + * 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. + */ +#ifndef MLPACK_UTIL_SIZE_CHECKS_HPP +#define MLPACK_UTIL_SIZE_CHECKS_HPP + +#include + +namespace mlpack { +namespace util { + +/** + * Check for if the given data points & labels have same size. + * + * @param data data. + * @param labels Labels. + * @param callerDescription A description of the caller that can be used for + * error generation. + * @param mode For nature of comparision(default "CE"). + * types of mode: + * "CE" equivalent to (data.n_cols, labels.n_elem). + * "CC" equivalent to (data.n_cols, labels.n_cols). + * @param addInfo An additional information about labels that can be used for + * precise error generation. Default is "labels". Another e.g. weights + */ +template +inline void CheckSameSizes(const DataType& data, + const LabelsType& labels, + const std::string& callerDescription, + const std::string& mode = "CE", + const std::string& addInfo = "labels") +{ + if (mode != "CE" && mode != "CC") + // For development purpose, not intended for user. + Log::Fatal << "Ensure Providing Correct mode." << std::endl; + + const size_t size1 = data.n_cols; + const size_t size2 = mode == "CE" ? labels.n_elem : labels.n_cols; + + if (size1 != size2) + { + std::ostringstream oss; + oss << callerDescription << ": number of points (" << size1 << ") " + << "does not match number of " << addInfo << " (" << size2 << ")!" + << std::endl; + throw std::invalid_argument(oss.str()); + } +} + +/** + * Check for if the given dataset dimension matches with the model's. + * + * @param data dataset. + * @param dimension Dimension of the model. + * @param callerDescription A description of the caller that can be used for + * error generation. + * @param addInfo An additional information about data that can be used for + * precise error generation. Default is "dataset". Another e.g. weights. + */ +template +inline void CheckSameDimensionality(const DataType& data, + const DimType& dimension, + const std::string& callerDescription, + const std::string& addInfo = "dataset") +{ + if (data.n_rows != dimension.n_rows) + { + std::ostringstream oss; + oss << callerDescription << ": dimensionality of " << addInfo << " (" + << data.n_rows << ") is not equal to the dimensionality of the model" + " (" << dimension.n_rows << ")!"; + + throw std::invalid_argument(oss.str()); + } +} + +// An overload of CheckSameDimensionality() where second param is unsigned +// long int. +template +inline void CheckSameDimensionality(const DataType& data, + const size_t& dimension, + const std::string& callerDescription, + const std::string& addInfo = "dataset") +{ + if (data.n_rows != dimension) + { + std::ostringstream oss; + oss << callerDescription << ": dimensionality of " << addInfo << " (" + << data.n_rows << ") is not equal to the dimensionality of the model" + " (" << dimension << ")!"; + throw std::invalid_argument(oss.str()); + } +} + +} // namespace util +} // namespace mlpack + +#endif + diff --git a/src/mlpack/tests/size_checks_test.cpp b/src/mlpack/tests/size_checks_test.cpp new file mode 100644 index 0000000000..44539036b9 --- /dev/null +++ b/src/mlpack/tests/size_checks_test.cpp @@ -0,0 +1,62 @@ +/** + * @file size_checks_test.cpp + * @author Bisakh Mondal + * + * Test file for Utility size_checks. + * + * 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 +#include + +using namespace mlpack; +using namespace mlpack::util; +BOOST_AUTO_TEST_SUITE(SizeCheckTest); + +/** + * Test that CheckSameSizes() works in different cases. + */ +BOOST_AUTO_TEST_CASE(CheckSizeTest) +{ + arma::mat data = arma::randu(20, 30); + arma::colvec firstLabels = arma::randu(20); + arma::colvec secondLabels = arma::randu(30); + arma::mat thirdLabels = arma::randu(20, 30); + + BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking"), + std::invalid_argument); + BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking", "CC"), + std::invalid_argument); + BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking", "AB"), + std::runtime_error); + + BOOST_REQUIRE_NO_THROW(CheckSameSizes(data, secondLabels, "TestChecking")); + BOOST_REQUIRE_NO_THROW(CheckSameSizes(data, thirdLabels, "TestChecking", + "CC")); +} + +/** + * Test that CheckSameDimensionality() works in different cases. + */ +BOOST_AUTO_TEST_CASE(CheckDimensionality) +{ + arma::mat dataset = arma::randu(20, 30); + arma::colvec refSet = arma::randu(20); + arma::colvec refSet2 = arma::randu(40); + + BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset, (size_t) 20, + "TestingDim")); + BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, (size_t) 100, + "TestingDim"), std::invalid_argument); + + BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, refSet2, "TestingDim"), + std::invalid_argument); + BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset, refSet, "TestingDim" + )); +} + +BOOST_AUTO_TEST_SUITE_END(); + From d4f0cad156307409924d3952d312507418f7042f Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Tue, 28 Apr 2020 21:59:52 +0530 Subject: [PATCH 214/253] updated implementations --- src/mlpack/core.hpp | 2 +- src/mlpack/core/cv/cv_base_impl.hpp | 10 +- src/mlpack/core/cv/metrics/mse_impl.hpp | 9 +- src/mlpack/core/cv/metrics/r2_score_impl.hpp | 10 +- src/mlpack/core/util/CMakeLists.txt | 2 +- src/mlpack/core/util/facilities.hpp | 113 ------------------ src/mlpack/core/util/size_checks.hpp | 2 +- .../decision_tree/decision_tree_impl.hpp | 60 +++++----- .../methods/linear_svm/linear_svm_impl.hpp | 8 +- src/mlpack/methods/lsh/lsh_search_impl.hpp | 10 +- .../range_search/range_search_impl.hpp | 10 +- .../softmax_regression/softmax_regression.cpp | 10 +- src/mlpack/tests/CMakeLists.txt | 4 +- src/mlpack/tests/facilities_test.cpp | 106 ---------------- 14 files changed, 46 insertions(+), 310 deletions(-) delete mode 100644 src/mlpack/core/util/facilities.hpp delete mode 100644 src/mlpack/tests/facilities_test.cpp diff --git a/src/mlpack/core.hpp b/src/mlpack/core.hpp index 7c73678163..c4522ba05f 100644 --- a/src/mlpack/core.hpp +++ b/src/mlpack/core.hpp @@ -90,7 +90,7 @@ #include #include #include -#include +#include // mlpack::backtrace only for linux #ifdef HAS_BFD_DL diff --git a/src/mlpack/core/cv/cv_base_impl.hpp b/src/mlpack/core/cv/cv_base_impl.hpp index a7017d770a..fc819603db 100644 --- a/src/mlpack/core/cv/cv_base_impl.hpp +++ b/src/mlpack/core/cv/cv_base_impl.hpp @@ -106,14 +106,8 @@ void CVBase::AssertDataConsistency(const MatType& xs, const PredictionsType& ys) { - if (xs.n_cols != ys.n_cols) - { - std::ostringstream oss; - oss << "CVBase::AssertDataConsistency(): number of data points (" - << xs.n_cols << ") does not match number of predictions (" << ys.n_cols - << ")!" << std::endl; - throw std::invalid_argument(oss.str()); - } + util::CheckSameSizes(xs, ys, "CVBase::AssertDataConsistency()", "CC", + "predictions"); } template::Evaluate(MLAlgorithm& model, const DataType& data, const ResponsesType& responses) { - if (data.n_cols != responses.n_cols) - { - std::ostringstream oss; - oss << "R2Score::Evaluate(): number of points (" << data.n_cols << ") " - << "does not match number of responses (" << responses.n_cols << ")!" - << std::endl; - throw std::invalid_argument(oss.str()); - } + util::CheckSameSizes(data, responses, "R2Score::Evaluate()", "CC", + "responses"); ResponsesType predictedResponses; // Taking Predicted Output from the model. diff --git a/src/mlpack/core/util/CMakeLists.txt b/src/mlpack/core/util/CMakeLists.txt index 4872652826..ef21ff91ca 100644 --- a/src/mlpack/core/util/CMakeLists.txt +++ b/src/mlpack/core/util/CMakeLists.txt @@ -26,6 +26,7 @@ set(SOURCES prefixedoutstream_impl.hpp program_doc.hpp program_doc.cpp + size_checks.hpp sfinae_utility.hpp singletons.cpp timers.hpp @@ -33,7 +34,6 @@ set(SOURCES to_lower.hpp version.hpp version.cpp - facilities.hpp ) # add directory name to sources diff --git a/src/mlpack/core/util/facilities.hpp b/src/mlpack/core/util/facilities.hpp deleted file mode 100644 index bd9605b460..0000000000 --- a/src/mlpack/core/util/facilities.hpp +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @file facilities.hpp - * @author Kirill Mishchenko - * @author Bisakh Mondal - * - * Utility for checking same size & same dimensionality. - * - * 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. - */ -#ifndef MLPACK_UTIL_FACILITIES_HPP -#define MLPACK_UTIL_FACILITIES_HPP - -#include - -namespace mlpack { -namespace util { - -/** - * Check for if the given data points & labels have same size. - * - * @param data data. - * @param labels Labels. - * @param callerDescription A description of the caller that can be used for - * error generation. - * @param mode For nature of comparision(default "CE"). - * types of mode: - * "CE" equivalent to (data.n_cols, labels.n_elem). - * "CC" equivalent to (data.n_cols, labels.n_cols). - */ -template -inline void CheckSameSizes(const DataType& data, - const LabelsType& labels, - const std::string& callerDescription, - const std::string& mode = "CE") -{ - if (mode == "CE") - { - if (data.n_cols != labels.n_elem) - { - std::ostringstream oss; - oss << callerDescription << ": number of points (" << data.n_cols << ") " - << "does not match number of labels (" << labels.n_elem << ")!" - << std::endl; - throw std::invalid_argument(oss.str()); - } - } - else if (mode == "CC") - { - if (data.n_cols != labels.n_cols) - { - std::ostringstream oss; - oss << callerDescription << ": number of points (" << data.n_cols << ") " - << "does not match number of responses (" << labels.n_cols << ")!" - << std::endl; - throw std::invalid_argument(oss.str()); - } - } - else - // For development purpose, not intended for user. - Log::Fatal << "Ensure Providing Correct mode." << std::endl; -} - -/** - * Check for if the given dataset dimension matches with the model's. - * - * @param data dataset. - * @param dimension Dimension of the model. - * @param callerDescription A description of the caller that can be used for - * error generation. - * @param mode For nature of comparision(default "R"). - * types of mode: - * "R" for comparision with number of rows of the dataset. - * "C" for comparision with number of columns of the dataset. - */ -template -inline void CheckSameDimensionality(const DataType& data, - const size_t& dimension, - const std::string& callerDescription, - const std::string& mode = "R") -{ - if (mode == "R") - { - if (data.n_rows != dimension) - { - std::ostringstream oss; - oss << callerDescription << ": dataset has " << data.n_rows - << " dimensions, but model has " << dimension << " dimensions!"; - throw std::invalid_argument(oss.str()); - } - } - else if (mode == "C") - { - if (data.n_cols != dimension) - { - std::ostringstream oss; - oss << callerDescription << ": dataset has " << data.n_cols - << " dimensions, but model has " << dimension << " dimensions!"; - throw std::invalid_argument(oss.str()); - } - } - else - // For development purpose, not intended for user. - Log::Fatal << "Ensure Providing Correct mode!!" << std::endl; -} - -} // namespace util -} // namespace mlpack - -#endif - diff --git a/src/mlpack/core/util/size_checks.hpp b/src/mlpack/core/util/size_checks.hpp index 7a02a2ee5e..318de15567 100644 --- a/src/mlpack/core/util/size_checks.hpp +++ b/src/mlpack/core/util/size_checks.hpp @@ -3,7 +3,7 @@ * @author Kirill Mishchenko * @author Bisakh Mondal * - * Utility for checking same size & same dimensionality. + * Utility for checking same size & same dimensionality. * * 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 diff --git a/src/mlpack/methods/decision_tree/decision_tree_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_impl.hpp index 1646608d0b..8967e88f1b 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_impl.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_impl.hpp @@ -469,14 +469,7 @@ double DecisionTree::type; using TrueLabelsType = typename std::decay::type; @@ -518,14 +511,15 @@ double DecisionTree::type; using TrueLabelsType = typename std::decay::type; @@ -573,14 +567,15 @@ double DecisionTree::type>::value>*) { // Sanity check on data. - if (data.n_cols != labels.n_elem) - { - std::ostringstream oss; - oss << "DecisionTree::Train(): number of points (" << data.n_cols << ") " - << "does not match number of labels (" << labels.n_elem << ")!" - << std::endl; - throw std::invalid_argument(oss.str()); - } + // if (data.n_cols != labels.n_elem) + // { + // std::ostringstream oss; + // oss << "DecisionTree::Train(): number of points (" << data.n_cols << ") " + // << "does not match number of labels (" << labels.n_elem << ")!" + // << std::endl; + // throw std::invalid_argument(oss.str()); + // } + util::CheckSameSizes(data, labels, "DecisionTree::Train()"); using TrueMatType = typename std::decay::type; using TrueLabelsType = typename std::decay::type; @@ -628,14 +623,15 @@ double DecisionTree::type>::value>*) { // Sanity check on data. - if (data.n_cols != labels.n_elem) - { - std::ostringstream oss; - oss << "DecisionTree::Train(): number of points (" << data.n_cols << ") " - << "does not match number of labels (" << labels.n_elem << ")!" - << std::endl; - throw std::invalid_argument(oss.str()); - } + // if (data.n_cols != labels.n_elem) + // { + // std::ostringstream oss; + // oss << "DecisionTree::Train(): number of points (" << data.n_cols << ") " + // << "does not match number of labels (" << labels.n_elem << ")!" + // << std::endl; + // throw std::invalid_argument(oss.str()); + // } + util::CheckSameSizes(data, labels, "DecisionTree::Train()"); using TrueMatType = typename std::decay::type; using TrueLabelsType = typename std::decay::type; diff --git a/src/mlpack/methods/linear_svm/linear_svm_impl.hpp b/src/mlpack/methods/linear_svm/linear_svm_impl.hpp index 243ba772ce..69f0887f9d 100644 --- a/src/mlpack/methods/linear_svm/linear_svm_impl.hpp +++ b/src/mlpack/methods/linear_svm/linear_svm_impl.hpp @@ -173,13 +173,7 @@ void LinearSVM::Classify( const MatType& data, arma::mat& scores) const { - if (data.n_rows != FeatureSize()) - { - std::ostringstream oss; - oss << "LinearSVM::Classify(): dataset has " << data.n_rows - << " dimensions, but model has " << FeatureSize() << " dimensions!"; - throw std::invalid_argument(oss.str()); - } + util::CheckSameDimensionality(data, FeatureSize(), "LinearSVM::Classify()"); if (fitIntercept) { diff --git a/src/mlpack/methods/lsh/lsh_search_impl.hpp b/src/mlpack/methods/lsh/lsh_search_impl.hpp index c3838bd4b6..6c3aeb8259 100644 --- a/src/mlpack/methods/lsh/lsh_search_impl.hpp +++ b/src/mlpack/methods/lsh/lsh_search_impl.hpp @@ -865,14 +865,8 @@ void LSHSearch::Search( const size_t T) { // Ensure the dimensionality of the query set is correct. - if (querySet.n_rows != referenceSet.n_rows) - { - std::ostringstream oss; - oss << "LSHSearch::Search(): dimensionality of query set (" - << querySet.n_rows << ") is not equal to the dimensionality the model " - << "was trained on (" << referenceSet.n_rows << ")!" << std::endl; - throw std::invalid_argument(oss.str()); - } + util::CheckSameDimensionality(querySet, referenceSet, "LSHSearch::Search()", + "query set"); if (k > referenceSet.n_cols) { diff --git a/src/mlpack/methods/range_search/range_search_impl.hpp b/src/mlpack/methods/range_search/range_search_impl.hpp index 03f90b3057..cce20339a3 100644 --- a/src/mlpack/methods/range_search/range_search_impl.hpp +++ b/src/mlpack/methods/range_search/range_search_impl.hpp @@ -312,14 +312,8 @@ void RangeSearch::Search( std::vector>& neighbors, std::vector>& distances) { - if (querySet.n_rows != referenceSet->n_rows) - { - std::ostringstream oss; - oss << "RangeSearch::Search(): dimensionalities of query set (" - << querySet.n_rows << ") and reference set (" << referenceSet->n_rows - << ") do not match!"; - throw std::invalid_argument(oss.str()); - } + util::CheckSameDimensionality(querySet, *referenceSet, + "RangeSearch::Search()", "query set"); // If there are no points, there is no search to be done. if (referenceSet->n_cols == 0) diff --git a/src/mlpack/methods/softmax_regression/softmax_regression.cpp b/src/mlpack/methods/softmax_regression/softmax_regression.cpp index ae39513df6..b269c07690 100644 --- a/src/mlpack/methods/softmax_regression/softmax_regression.cpp +++ b/src/mlpack/methods/softmax_regression/softmax_regression.cpp @@ -11,6 +11,7 @@ */ #include "softmax_regression.hpp" +#include namespace mlpack { namespace regression { @@ -91,13 +92,8 @@ void SoftmaxRegression::Classify(const arma::mat& dataset, arma::mat& probabilities) const { - if (dataset.n_rows != FeatureSize()) - { - std::ostringstream oss; - oss << "SoftmaxRegression::Classify(): dataset has " << dataset.n_rows - << " dimensions, but model has " << FeatureSize() << " dimensions!"; - throw std::invalid_argument(oss.str()); - } + util::CheckSameDimensionality(dataset, FeatureSize(), + "SoftmaxRegression::Classify()"); // Calculate the probabilities for each test input. arma::mat hypothesis; diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index e6dd629266..a384be6825 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -30,8 +30,7 @@ add_executable(mlpack_test det_test.cpp distribution_test.cpp drusilla_select_test.cpp - emst_test.cpp - facilities_test.cpp + emst_test.cpp fastmks_test.cpp feedforward_network_test.cpp gan_test.cpp @@ -98,6 +97,7 @@ add_executable(mlpack_test reward_clipping_test.cpp rl_components_test.cpp scaling_test.cpp + size_checks_test.cpp serialization.cpp serialization.hpp serialization_test.cpp diff --git a/src/mlpack/tests/facilities_test.cpp b/src/mlpack/tests/facilities_test.cpp deleted file mode 100644 index 11ee5c68b1..0000000000 --- a/src/mlpack/tests/facilities_test.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @file facilities_test.cpp - * @author Khizir Siddiqui - * @author Bisakh Mondal - * - * Test file for Utility facilities. - * - * 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 -#include -#include -#include -#include - -#include "catch.hpp" - -using namespace mlpack; -using namespace mlpack::cv; -using namespace mlpack::util; - -BOOST_AUTO_TEST_SUITE(FacilityTest); - -/** - * The unequal sizes for data and labels show throw an error. - */ -TEST_CASE("AssertSizesTest", "[FacilitiesTest]") -{ - // Load the dataset. - arma::mat dataset; - if (!data::Load("iris_train.csv", dataset)) - FAIL("Cannot load test dataset iris_train.csv!"); - // Load the labels. - arma::Row labels; - if (!data::Load("iris_test_labels.csv", labels)) - FAIL("Cannot load test dataset iris_test_labels.csv!"); - - REQUIRE_THROWS_AS( - AssertSizes(dataset, labels, "test"), std::invalid_argument); -} - - -/** - * Pairwise distances. - */ -TEST_CASE("PairwiseDistanceTest", "[FacilitiesTest]") -{ - arma::mat X; - X = { { 0, 1, 1, 0, 0 }, - { 0, 1, 2, 0, 0 }, - { 1, 1, 3, 2, 0 } }; - metric::EuclideanDistance metric; - arma::mat dist = PairwiseDistances(X, metric); - REQUIRE(dist(0, 0) == 0); - REQUIRE(dist(1, 0) == Approx(1.41421).epsilon(1e-5)); - REQUIRE(dist(2, 0) == 3); -} - - -/** - * Test that CheckSameSizes() works in different cases. - */ -BOOST_AUTO_TEST_CASE(CheckSizeTest) -{ - arma::mat data = arma::randu(20, 30); - arma::colvec firstLabels = arma::randu(20); - arma::colvec secondLabels = arma::randu(30); - arma::mat thirdLabels = arma::randu(20, 30); - - BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking"), - std::invalid_argument); - BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking", "CC"), - std::invalid_argument); - BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking", "AB"), - std::runtime_error); - - BOOST_REQUIRE_NO_THROW(CheckSameSizes(data, secondLabels, "TestChecking")); - BOOST_REQUIRE_NO_THROW(CheckSameSizes(data, thirdLabels, "TestChecking", - "CC")); -} - - -/** - * Test that CheckSameDimensionality() works in different cases. - */ -BOOST_AUTO_TEST_CASE(CheckDimensionality) -{ - arma::mat dataset = arma::randu(20, 30); - - BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset, 20, "TestingDim")); - BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset, 30, "TestingDim", - "C")); - - BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, 100, "TestingDim"), - std::invalid_argument); - BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, 50, "TestingDim", "C"), - std::invalid_argument); - BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, 20, "TestingDim", "A"), - std::runtime_error); -} - -BOOST_AUTO_TEST_SUITE_END(); From e6e41199a007fb882d4fda8023e83515417fe7fd Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Tue, 28 Apr 2020 22:07:37 +0530 Subject: [PATCH 215/253] Deletion of Commented out code Done. --- .../decision_tree/decision_tree_impl.hpp | 24 ------------------- src/mlpack/tests/size_checks_test.cpp | 4 ++-- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/mlpack/methods/decision_tree/decision_tree_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_impl.hpp index 8967e88f1b..b99075f5b2 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_impl.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_impl.hpp @@ -511,14 +511,6 @@ double DecisionTree::type; @@ -567,14 +559,6 @@ double DecisionTree::type>::value>*) { // Sanity check on data. - // if (data.n_cols != labels.n_elem) - // { - // std::ostringstream oss; - // oss << "DecisionTree::Train(): number of points (" << data.n_cols << ") " - // << "does not match number of labels (" << labels.n_elem << ")!" - // << std::endl; - // throw std::invalid_argument(oss.str()); - // } util::CheckSameSizes(data, labels, "DecisionTree::Train()"); using TrueMatType = typename std::decay::type; @@ -623,14 +607,6 @@ double DecisionTree::type>::value>*) { // Sanity check on data. - // if (data.n_cols != labels.n_elem) - // { - // std::ostringstream oss; - // oss << "DecisionTree::Train(): number of points (" << data.n_cols << ") " - // << "does not match number of labels (" << labels.n_elem << ")!" - // << std::endl; - // throw std::invalid_argument(oss.str()); - // } util::CheckSameSizes(data, labels, "DecisionTree::Train()"); using TrueMatType = typename std::decay::type; diff --git a/src/mlpack/tests/size_checks_test.cpp b/src/mlpack/tests/size_checks_test.cpp index 44539036b9..d5ca71e6a8 100644 --- a/src/mlpack/tests/size_checks_test.cpp +++ b/src/mlpack/tests/size_checks_test.cpp @@ -54,8 +54,8 @@ BOOST_AUTO_TEST_CASE(CheckDimensionality) BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, refSet2, "TestingDim"), std::invalid_argument); - BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset, refSet, "TestingDim" - )); + BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset, refSet, + "TestingDim")); } BOOST_AUTO_TEST_SUITE_END(); From 7e463525253bcd29fc347821cf78e9b080113595 Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Wed, 29 Apr 2020 15:54:43 +0530 Subject: [PATCH 216/253] Updated --- src/mlpack/core/cv/cv_base_impl.hpp | 2 ++ src/mlpack/methods/decision_tree/decision_tree_impl.hpp | 1 + src/mlpack/methods/linear_svm/linear_svm_impl.hpp | 1 + src/mlpack/methods/lsh/lsh_search_impl.hpp | 1 + src/mlpack/methods/range_search/range_search_impl.hpp | 1 + 5 files changed, 6 insertions(+) diff --git a/src/mlpack/core/cv/cv_base_impl.hpp b/src/mlpack/core/cv/cv_base_impl.hpp index fc819603db..e5df5d8bca 100644 --- a/src/mlpack/core/cv/cv_base_impl.hpp +++ b/src/mlpack/core/cv/cv_base_impl.hpp @@ -12,6 +12,8 @@ #ifndef MLPACK_CORE_CV_CV_BASE_IMPL_HPP #define MLPACK_CORE_CV_CV_BASE_IMPL_HPP +#include + namespace mlpack { namespace cv { diff --git a/src/mlpack/methods/decision_tree/decision_tree_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_impl.hpp index b99075f5b2..171675a84b 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_impl.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_impl.hpp @@ -13,6 +13,7 @@ #define MLPACK_METHODS_DECISION_TREE_DECISION_TREE_IMPL_HPP #include "decision_tree.hpp" +#include namespace mlpack { namespace tree { diff --git a/src/mlpack/methods/linear_svm/linear_svm_impl.hpp b/src/mlpack/methods/linear_svm/linear_svm_impl.hpp index 69f0887f9d..db7275eff8 100644 --- a/src/mlpack/methods/linear_svm/linear_svm_impl.hpp +++ b/src/mlpack/methods/linear_svm/linear_svm_impl.hpp @@ -14,6 +14,7 @@ // In case it hasn't been included yet. #include "linear_svm.hpp" +#include namespace mlpack { namespace svm { diff --git a/src/mlpack/methods/lsh/lsh_search_impl.hpp b/src/mlpack/methods/lsh/lsh_search_impl.hpp index 6c3aeb8259..0eb69d850b 100644 --- a/src/mlpack/methods/lsh/lsh_search_impl.hpp +++ b/src/mlpack/methods/lsh/lsh_search_impl.hpp @@ -14,6 +14,7 @@ #include #include +#include namespace mlpack { namespace neighbor { diff --git a/src/mlpack/methods/range_search/range_search_impl.hpp b/src/mlpack/methods/range_search/range_search_impl.hpp index cce20339a3..0a8162301b 100644 --- a/src/mlpack/methods/range_search/range_search_impl.hpp +++ b/src/mlpack/methods/range_search/range_search_impl.hpp @@ -17,6 +17,7 @@ // The rules for traversal. #include "range_search_rules.hpp" +#include namespace mlpack { namespace range { From 30299c0f039c64615576cc9edc6786fc03449e32 Mon Sep 17 00:00:00 2001 From: Bisakh Date: Wed, 24 Feb 2021 20:36:11 +0530 Subject: [PATCH 217/253] Two new utility APIs introduced --- src/mlpack/core.hpp | 1 - src/mlpack/core/cv/cv_base_impl.hpp | 14 +--- src/mlpack/core/cv/metrics/CMakeLists.txt | 1 + src/mlpack/core/cv/metrics/accuracy.hpp | 1 + src/mlpack/core/cv/metrics/facilities.hpp | 73 +++++++++++++++++++ src/mlpack/core/cv/metrics/mse_impl.hpp | 2 +- src/mlpack/core/cv/metrics/r2_score_impl.hpp | 2 +- src/mlpack/core/util/size_checks.hpp | 47 +++++++----- .../decision_tree/decision_tree_impl.hpp | 1 - .../methods/linear_svm/linear_svm_impl.hpp | 1 - src/mlpack/methods/lsh/lsh_search_impl.hpp | 1 - .../range_search/range_search_impl.hpp | 1 - .../softmax_regression/softmax_regression.cpp | 1 - src/mlpack/prereqs.hpp | 3 + src/mlpack/tests/CMakeLists.txt | 3 +- src/mlpack/tests/facilities_test.cpp | 56 ++++++++++++++ src/mlpack/tests/size_checks_test.cpp | 34 ++++----- 17 files changed, 184 insertions(+), 58 deletions(-) create mode 100644 src/mlpack/core/cv/metrics/facilities.hpp create mode 100644 src/mlpack/tests/facilities_test.cpp diff --git a/src/mlpack/core.hpp b/src/mlpack/core.hpp index c4522ba05f..34cf60dd09 100644 --- a/src/mlpack/core.hpp +++ b/src/mlpack/core.hpp @@ -90,7 +90,6 @@ #include #include #include -#include // mlpack::backtrace only for linux #ifdef HAS_BFD_DL diff --git a/src/mlpack/core/cv/cv_base_impl.hpp b/src/mlpack/core/cv/cv_base_impl.hpp index e5df5d8bca..0da9f8f4fa 100644 --- a/src/mlpack/core/cv/cv_base_impl.hpp +++ b/src/mlpack/core/cv/cv_base_impl.hpp @@ -12,7 +12,7 @@ #ifndef MLPACK_CORE_CV_CV_BASE_IMPL_HPP #define MLPACK_CORE_CV_CV_BASE_IMPL_HPP -#include +#include namespace mlpack { namespace cv { @@ -108,7 +108,7 @@ void CVBase::AssertDataConsistency(const MatType& xs, const PredictionsType& ys) { - util::CheckSameSizes(xs, ys, "CVBase::AssertDataConsistency()", "CC", + util::CheckSameSizes(xs, (size_t) ys.n_cols, "CVBase::AssertDataConsistency()", "predictions"); } @@ -125,14 +125,8 @@ void CVBase +#include namespace mlpack { namespace cv { diff --git a/src/mlpack/core/cv/metrics/facilities.hpp b/src/mlpack/core/cv/metrics/facilities.hpp new file mode 100644 index 0000000000..4cd2a8f36e --- /dev/null +++ b/src/mlpack/core/cv/metrics/facilities.hpp @@ -0,0 +1,73 @@ +/** + * @file core/cv/metrics/facilities.hpp + * @author Kirill Mishchenko + * @author Khizir Siddiqui + * + * Functionality that is used more than in one metric. + * + * 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. + */ +#ifndef MLPACK_CORE_CV_METRICS_FACILITIES_HPP +#define MLPACK_CORE_CV_METRICS_FACILITIES_HPP + +#include +#include + +namespace mlpack { +namespace cv { + +/** + * Assert there is the same number of the given data points and labels. + * + * @param data Column-major data. + * @param labels Labels. + * @param callerDescription A description of the caller that can be used for + * error generation. + * @deprecated Check the new versions, util::CheckSameSizes & + * util::CheckSameDimensionality. + */ +template +void AssertSizes(const DataType& data, + const arma::Row& labels, + const std::string& callerDescription) +{ + if (data.n_cols != labels.n_elem) + { + std::ostringstream oss; + oss << callerDescription << ": number of points (" << data.n_cols << ") " + << "does not match number of labels (" << labels.n_elem << ")!" + << std::endl; + throw std::invalid_argument(oss.str()); + } +} + +/** + * Pairwise distance of the given data. + * + * @param data Column-major matrix. + * @param metric Distance metric to be used. + */ +template +DataType PairwiseDistances(const DataType& data, + const Metric& metric) +{ + DataType distances = DataType(data.n_cols, data.n_cols, arma::fill::none); + for (size_t i = 0; i < data.n_cols; i++) + { + for (size_t j = 0; j < i; j++) + { + distances(i, j) = metric.Evaluate(data.col(i), data.col(j)); + distances(j, i) = distances(i, j); + } + } + distances.diag().zeros(); + return distances; +} + +} // namespace cv +} // namespace mlpack + +#endif diff --git a/src/mlpack/core/cv/metrics/mse_impl.hpp b/src/mlpack/core/cv/metrics/mse_impl.hpp index a55a0e7ed0..d4eb83cd97 100644 --- a/src/mlpack/core/cv/metrics/mse_impl.hpp +++ b/src/mlpack/core/cv/metrics/mse_impl.hpp @@ -20,7 +20,7 @@ double MSE::Evaluate(MLAlgorithm& model, const DataType& data, const ResponsesType& responses) { - util::CheckSameSizes(data, responses, "MSE::Evaluate()", "CC", "responses"); + util::CheckSameSizes(data,(size_t) responses.n_cols, "MSE::Evaluate()", "responses"); ResponsesType predictedResponses; model.Predict(data, predictedResponses); diff --git a/src/mlpack/core/cv/metrics/r2_score_impl.hpp b/src/mlpack/core/cv/metrics/r2_score_impl.hpp index dad46216eb..bb3d491447 100644 --- a/src/mlpack/core/cv/metrics/r2_score_impl.hpp +++ b/src/mlpack/core/cv/metrics/r2_score_impl.hpp @@ -21,7 +21,7 @@ double R2Score::Evaluate(MLAlgorithm& model, const DataType& data, const ResponsesType& responses) { - util::CheckSameSizes(data, responses, "R2Score::Evaluate()", "CC", + util::CheckSameSizes(data,(size_t) responses.n_cols, "R2Score::Evaluate()", "responses"); ResponsesType predictedResponses; diff --git a/src/mlpack/core/util/size_checks.hpp b/src/mlpack/core/util/size_checks.hpp index 318de15567..ee06e29214 100644 --- a/src/mlpack/core/util/size_checks.hpp +++ b/src/mlpack/core/util/size_checks.hpp @@ -25,37 +25,45 @@ namespace util { * @param labels Labels. * @param callerDescription A description of the caller that can be used for * error generation. - * @param mode For nature of comparision(default "CE"). - * types of mode: - * "CE" equivalent to (data.n_cols, labels.n_elem). - * "CC" equivalent to (data.n_cols, labels.n_cols). - * @param addInfo An additional information about labels that can be used for + * @param addInfo Additional information about labels that can be used for * precise error generation. Default is "labels". Another e.g. weights */ template inline void CheckSameSizes(const DataType& data, - const LabelsType& labels, + const LabelsType& label, const std::string& callerDescription, - const std::string& mode = "CE", const std::string& addInfo = "labels") { - if (mode != "CE" && mode != "CC") - // For development purpose, not intended for user. - Log::Fatal << "Ensure Providing Correct mode." << std::endl; - - const size_t size1 = data.n_cols; - const size_t size2 = mode == "CE" ? labels.n_elem : labels.n_cols; - - if (size1 != size2) + if (data.n_cols != label.n_elem) { std::ostringstream oss; - oss << callerDescription << ": number of points (" << size1 << ") " - << "does not match number of " << addInfo << " (" << size2 << ")!" + oss << callerDescription << ": number of points (" << data.n_cols << ") " + << "does not match number of " << addInfo << " (" << label.n_elem << ")!" << std::endl; throw std::invalid_argument(oss.str()); } } +/** An overload of CheckSameSizes() where the size to be checked is known + * previously. The second parameter is of type unsigned int. + */ +template +inline void CheckSameSizes(const DataType& data, + const size_t& size, + const std::string& callerDescription, + const std::string& addInfo = "labels") +{ + if (data.n_cols != size) + { + std::ostringstream oss; + oss << callerDescription << ": number of points (" << data.n_cols << ") " + << "does not match number of " << addInfo << " (" << size << ")!" + << std::endl; + throw std::invalid_argument(oss.str()); + } +} + + /** * Check for if the given dataset dimension matches with the model's. * @@ -83,8 +91,9 @@ inline void CheckSameDimensionality(const DataType& data, } } -// An overload of CheckSameDimensionality() where second param is unsigned -// long int. +/** An overload of CheckSameDimensionality() where the dimension to be checked + * is known second param is unsigned long int. + */ template inline void CheckSameDimensionality(const DataType& data, const size_t& dimension, diff --git a/src/mlpack/methods/decision_tree/decision_tree_impl.hpp b/src/mlpack/methods/decision_tree/decision_tree_impl.hpp index 171675a84b..b99075f5b2 100644 --- a/src/mlpack/methods/decision_tree/decision_tree_impl.hpp +++ b/src/mlpack/methods/decision_tree/decision_tree_impl.hpp @@ -13,7 +13,6 @@ #define MLPACK_METHODS_DECISION_TREE_DECISION_TREE_IMPL_HPP #include "decision_tree.hpp" -#include namespace mlpack { namespace tree { diff --git a/src/mlpack/methods/linear_svm/linear_svm_impl.hpp b/src/mlpack/methods/linear_svm/linear_svm_impl.hpp index db7275eff8..69f0887f9d 100644 --- a/src/mlpack/methods/linear_svm/linear_svm_impl.hpp +++ b/src/mlpack/methods/linear_svm/linear_svm_impl.hpp @@ -14,7 +14,6 @@ // In case it hasn't been included yet. #include "linear_svm.hpp" -#include namespace mlpack { namespace svm { diff --git a/src/mlpack/methods/lsh/lsh_search_impl.hpp b/src/mlpack/methods/lsh/lsh_search_impl.hpp index 0eb69d850b..6c3aeb8259 100644 --- a/src/mlpack/methods/lsh/lsh_search_impl.hpp +++ b/src/mlpack/methods/lsh/lsh_search_impl.hpp @@ -14,7 +14,6 @@ #include #include -#include namespace mlpack { namespace neighbor { diff --git a/src/mlpack/methods/range_search/range_search_impl.hpp b/src/mlpack/methods/range_search/range_search_impl.hpp index 0a8162301b..cce20339a3 100644 --- a/src/mlpack/methods/range_search/range_search_impl.hpp +++ b/src/mlpack/methods/range_search/range_search_impl.hpp @@ -17,7 +17,6 @@ // The rules for traversal. #include "range_search_rules.hpp" -#include namespace mlpack { namespace range { diff --git a/src/mlpack/methods/softmax_regression/softmax_regression.cpp b/src/mlpack/methods/softmax_regression/softmax_regression.cpp index b269c07690..567241b35a 100644 --- a/src/mlpack/methods/softmax_regression/softmax_regression.cpp +++ b/src/mlpack/methods/softmax_regression/softmax_regression.cpp @@ -11,7 +11,6 @@ */ #include "softmax_regression.hpp" -#include namespace mlpack { namespace regression { diff --git a/src/mlpack/prereqs.hpp b/src/mlpack/prereqs.hpp index 4ec1031235..5eb9ee6fd7 100644 --- a/src/mlpack/prereqs.hpp +++ b/src/mlpack/prereqs.hpp @@ -140,4 +140,7 @@ or upgrade Boost to 1.59 or newer. // We need to be able to mark functions deprecated. #include +// Include ready to use utility function for better workflow. +#include + #endif diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index a384be6825..cf9628eea3 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -30,7 +30,8 @@ add_executable(mlpack_test det_test.cpp distribution_test.cpp drusilla_select_test.cpp - emst_test.cpp + emst_test.cpp + facilities_test.cpp fastmks_test.cpp feedforward_network_test.cpp gan_test.cpp diff --git a/src/mlpack/tests/facilities_test.cpp b/src/mlpack/tests/facilities_test.cpp new file mode 100644 index 0000000000..65b754bb4e --- /dev/null +++ b/src/mlpack/tests/facilities_test.cpp @@ -0,0 +1,56 @@ +/** + * @file facilities_test.cpp + * @author Khizir Siddiqui + * + * Test file for facilities in metrics. + * + * 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 +#include +#include +#include + +#include "catch.hpp" + +using namespace mlpack; +using namespace mlpack::cv; + +/** + * The unequal sizes for data and labels show throw an error. + */ +TEST_CASE("AssertSizesTest", "[FacilitiesTest]") +{ + // Load the dataset. + arma::mat dataset; + if (!data::Load("iris_train.csv", dataset)) + FAIL("Cannot load test dataset iris_train.csv!"); + // Load the labels. + arma::Row labels; + if (!data::Load("iris_test_labels.csv", labels)) + FAIL("Cannot load test dataset iris_test_labels.csv!"); + + REQUIRE_THROWS_AS( + AssertSizes(dataset, labels, "test"), std::invalid_argument); +} + + +/** + * Pairwise distances. + */ +TEST_CASE("PairwiseDistanceTest", "[FacilitiesTest]") +{ + arma::mat X; + X = { { 0, 1, 1, 0, 0 }, + { 0, 1, 2, 0, 0 }, + { 1, 1, 3, 2, 0 } }; + metric::EuclideanDistance metric; + arma::mat dist = PairwiseDistances(X, metric); + REQUIRE(dist(0, 0) == 0); + REQUIRE(dist(1, 0) == Approx(1.41421).epsilon(1e-5)); + REQUIRE(dist(2, 0) == 3); +} diff --git a/src/mlpack/tests/size_checks_test.cpp b/src/mlpack/tests/size_checks_test.cpp index d5ca71e6a8..d5c7f22e46 100644 --- a/src/mlpack/tests/size_checks_test.cpp +++ b/src/mlpack/tests/size_checks_test.cpp @@ -9,54 +9,48 @@ * 3-clause BSD license along with mlpack. If not, see * http://www.opensource.org/licenses/BSD-3-Clause for more information. */ -#include -#include +#include +#include "catch.hpp" using namespace mlpack; using namespace mlpack::util; -BOOST_AUTO_TEST_SUITE(SizeCheckTest); /** * Test that CheckSameSizes() works in different cases. */ -BOOST_AUTO_TEST_CASE(CheckSizeTest) +TEST_CASE("CheckSizeTest", "[SizeCheckTest]") { arma::mat data = arma::randu(20, 30); arma::colvec firstLabels = arma::randu(20); arma::colvec secondLabels = arma::randu(30); - arma::mat thirdLabels = arma::randu(20, 30); + arma::mat thirdLabels = arma::randu(40, 30); - BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking"), + REQUIRE_THROWS_AS(CheckSameSizes(data, firstLabels, "TestChecking"), std::invalid_argument); - BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking", "CC"), + REQUIRE_THROWS_AS(CheckSameSizes(data, (size_t) 20, "TestChecking"), std::invalid_argument); - BOOST_REQUIRE_THROW(CheckSameSizes(data, firstLabels, "TestChecking", "AB"), - std::runtime_error); - BOOST_REQUIRE_NO_THROW(CheckSameSizes(data, secondLabels, "TestChecking")); - BOOST_REQUIRE_NO_THROW(CheckSameSizes(data, thirdLabels, "TestChecking", - "CC")); + REQUIRE_NOTHROW(CheckSameSizes(data, secondLabels, "TestChecking")); + REQUIRE_NOTHROW(CheckSameSizes(data, (size_t) 30, "TestChecking")); + REQUIRE_NOTHROW(CheckSameSizes(data, (size_t) thirdLabels.n_cols, "TestChecking")); } /** * Test that CheckSameDimensionality() works in different cases. */ -BOOST_AUTO_TEST_CASE(CheckDimensionality) +TEST_CASE("CheckDimensionality", "[SizeCheckTest]") { arma::mat dataset = arma::randu(20, 30); arma::colvec refSet = arma::randu(20); arma::colvec refSet2 = arma::randu(40); - BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset, (size_t) 20, + REQUIRE_NOTHROW(CheckSameDimensionality(dataset, (size_t) 20, "TestingDim")); - BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, (size_t) 100, + REQUIRE_THROWS_AS(CheckSameDimensionality(dataset, (size_t) 100, "TestingDim"), std::invalid_argument); - BOOST_REQUIRE_THROW(CheckSameDimensionality(dataset, refSet2, "TestingDim"), + REQUIRE_THROWS_AS(CheckSameDimensionality(dataset, refSet2, "TestingDim"), std::invalid_argument); - BOOST_REQUIRE_NO_THROW(CheckSameDimensionality(dataset, refSet, + REQUIRE_NOTHROW(CheckSameDimensionality(dataset, refSet, "TestingDim")); } - -BOOST_AUTO_TEST_SUITE_END(); - From de67fb4faae8f7e31c3fd38daf4f9b7428f428af Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Wed, 24 Feb 2021 20:39:50 +0530 Subject: [PATCH 218/253] Grammar fix as suggested by @rcurtin Co-authored-by: Ryan Curtin --- src/mlpack/core/util/size_checks.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mlpack/core/util/size_checks.hpp b/src/mlpack/core/util/size_checks.hpp index ee06e29214..1ef5555749 100644 --- a/src/mlpack/core/util/size_checks.hpp +++ b/src/mlpack/core/util/size_checks.hpp @@ -71,7 +71,7 @@ inline void CheckSameSizes(const DataType& data, * @param dimension Dimension of the model. * @param callerDescription A description of the caller that can be used for * error generation. - * @param addInfo An additional information about data that can be used for + * @param addInfo Additional information about data that can be used for * precise error generation. Default is "dataset". Another e.g. weights. */ template @@ -114,4 +114,3 @@ inline void CheckSameDimensionality(const DataType& data, } // namespace mlpack #endif - From c474e30378cfed52f5c03d664e69a0a03a8b8c0a Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Sat, 27 Feb 2021 21:49:20 +0530 Subject: [PATCH 219/253] Applying suggestions from code review by @rcurtin Co-authored-by: Ryan Curtin --- src/mlpack/core/cv/metrics/mse_impl.hpp | 3 +- src/mlpack/core/cv/metrics/r2_score_impl.hpp | 2 +- src/mlpack/core/util/size_checks.hpp | 42 ++++++++++---------- src/mlpack/prereqs.hpp | 2 +- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/mlpack/core/cv/metrics/mse_impl.hpp b/src/mlpack/core/cv/metrics/mse_impl.hpp index d4eb83cd97..d2fdcf8e74 100644 --- a/src/mlpack/core/cv/metrics/mse_impl.hpp +++ b/src/mlpack/core/cv/metrics/mse_impl.hpp @@ -20,7 +20,8 @@ double MSE::Evaluate(MLAlgorithm& model, const DataType& data, const ResponsesType& responses) { - util::CheckSameSizes(data,(size_t) responses.n_cols, "MSE::Evaluate()", "responses"); + util::CheckSameSizes(data, (size_t) responses.n_cols, "MSE::Evaluate()", + "responses"); ResponsesType predictedResponses; model.Predict(data, predictedResponses); diff --git a/src/mlpack/core/cv/metrics/r2_score_impl.hpp b/src/mlpack/core/cv/metrics/r2_score_impl.hpp index bb3d491447..00eb9a1448 100644 --- a/src/mlpack/core/cv/metrics/r2_score_impl.hpp +++ b/src/mlpack/core/cv/metrics/r2_score_impl.hpp @@ -21,7 +21,7 @@ double R2Score::Evaluate(MLAlgorithm& model, const DataType& data, const ResponsesType& responses) { - util::CheckSameSizes(data,(size_t) responses.n_cols, "R2Score::Evaluate()", + util::CheckSameSizes(data, (size_t) responses.n_cols, "R2Score::Evaluate()", "responses"); ResponsesType predictedResponses; diff --git a/src/mlpack/core/util/size_checks.hpp b/src/mlpack/core/util/size_checks.hpp index 1ef5555749..933655f475 100644 --- a/src/mlpack/core/util/size_checks.hpp +++ b/src/mlpack/core/util/size_checks.hpp @@ -19,15 +19,15 @@ namespace mlpack { namespace util { /** - * Check for if the given data points & labels have same size. - * - * @param data data. - * @param labels Labels. - * @param callerDescription A description of the caller that can be used for - * error generation. - * @param addInfo Additional information about labels that can be used for - * precise error generation. Default is "labels". Another e.g. weights - */ + * Check for if the given data points & labels have same size. + * + * @param data data. + * @param labels Labels. + * @param callerDescription A description of the caller that can be used for + * error generation. + * @param addInfo Name to use for labels for precise error generation. Default + * is "labels"; for example, "weights" could also be used. + */ template inline void CheckSameSizes(const DataType& data, const LabelsType& label, @@ -44,7 +44,8 @@ inline void CheckSameSizes(const DataType& data, } } -/** An overload of CheckSameSizes() where the size to be checked is known +/** + * An overload of CheckSameSizes() where the size to be checked is known * previously. The second parameter is of type unsigned int. */ template @@ -65,15 +66,15 @@ inline void CheckSameSizes(const DataType& data, /** - * Check for if the given dataset dimension matches with the model's. - * - * @param data dataset. - * @param dimension Dimension of the model. - * @param callerDescription A description of the caller that can be used for - * error generation. - * @param addInfo Additional information about data that can be used for - * precise error generation. Default is "dataset". Another e.g. weights. - */ + * Check for if the given dataset dimension matches with the model's. + * + * @param data dataset. + * @param dimension Dimension of the model. + * @param callerDescription A description of the caller that can be used for + * error generation. + * @param addInfo Name to use for dataset for precise error generation. Default + * is "dataset"; for example, "weights" could also be used. + */ template inline void CheckSameDimensionality(const DataType& data, const DimType& dimension, @@ -91,7 +92,8 @@ inline void CheckSameDimensionality(const DataType& data, } } -/** An overload of CheckSameDimensionality() where the dimension to be checked +/** + * An overload of CheckSameDimensionality() where the dimension to be checked * is known second param is unsigned long int. */ template diff --git a/src/mlpack/prereqs.hpp b/src/mlpack/prereqs.hpp index 5eb9ee6fd7..1d049d711c 100644 --- a/src/mlpack/prereqs.hpp +++ b/src/mlpack/prereqs.hpp @@ -140,7 +140,7 @@ or upgrade Boost to 1.59 or newer. // We need to be able to mark functions deprecated. #include -// Include ready to use utility function for better workflow. +// Include ready to use utility function to check sizes of datasets. #include #endif From 970588c5daa9f15173c833be60558d5b8561e6f2 Mon Sep 17 00:00:00 2001 From: Bisakh Date: Sat, 27 Feb 2021 22:46:50 +0530 Subject: [PATCH 220/253] AssertSizes api has been replaced by CheckSameSizes --- src/mlpack/core/cv/metrics/facilities.hpp | 25 ------------------- .../core/cv/metrics/silhouette_score_impl.hpp | 6 ++--- src/mlpack/tests/facilities_test.cpp | 19 -------------- 3 files changed, 3 insertions(+), 47 deletions(-) diff --git a/src/mlpack/core/cv/metrics/facilities.hpp b/src/mlpack/core/cv/metrics/facilities.hpp index 4cd2a8f36e..fdd5b1216a 100644 --- a/src/mlpack/core/cv/metrics/facilities.hpp +++ b/src/mlpack/core/cv/metrics/facilities.hpp @@ -19,31 +19,6 @@ namespace mlpack { namespace cv { -/** - * Assert there is the same number of the given data points and labels. - * - * @param data Column-major data. - * @param labels Labels. - * @param callerDescription A description of the caller that can be used for - * error generation. - * @deprecated Check the new versions, util::CheckSameSizes & - * util::CheckSameDimensionality. - */ -template -void AssertSizes(const DataType& data, - const arma::Row& labels, - const std::string& callerDescription) -{ - if (data.n_cols != labels.n_elem) - { - std::ostringstream oss; - oss << callerDescription << ": number of points (" << data.n_cols << ") " - << "does not match number of labels (" << labels.n_elem << ")!" - << std::endl; - throw std::invalid_argument(oss.str()); - } -} - /** * Pairwise distance of the given data. * diff --git a/src/mlpack/core/cv/metrics/silhouette_score_impl.hpp b/src/mlpack/core/cv/metrics/silhouette_score_impl.hpp index 89041f736e..b271f0d6df 100644 --- a/src/mlpack/core/cv/metrics/silhouette_score_impl.hpp +++ b/src/mlpack/core/cv/metrics/silhouette_score_impl.hpp @@ -22,7 +22,7 @@ double SilhouetteScore::Overall(const DataType& X, const arma::Row& labels, const Metric& metric) { - AssertSizes(X, labels, "SilhouetteScore::Overall()"); + util::CheckSameSizes(X, labels, "SilhouetteScore::Overall()"); return arma::mean(SamplesScore(X, labels, metric)); } @@ -30,7 +30,7 @@ template arma::rowvec SilhouetteScore::SamplesScore(const DataType& distances, const arma::Row& labels) { - AssertSizes(distances, labels, "SilhouetteScore::SamplesScore()"); + util::CheckSameSizes(distances, labels, "SilhouetteScore::SamplesScore()"); // Stores the silhouette scores of individual samples. arma::rowvec sampleScores(distances.n_rows); @@ -76,7 +76,7 @@ arma::rowvec SilhouetteScore::SamplesScore(const DataType& X, const arma::Row& labels, const Metric& metric) { - AssertSizes(X, labels, "SilhouetteScore::SamplesScore()"); + util::CheckSameSizes(X, labels, "SilhouetteScore::SamplesScore()"); DataType distances = PairwiseDistances(X, metric); return SamplesScore(distances, labels); } diff --git a/src/mlpack/tests/facilities_test.cpp b/src/mlpack/tests/facilities_test.cpp index 65b754bb4e..d4bcec3c3b 100644 --- a/src/mlpack/tests/facilities_test.cpp +++ b/src/mlpack/tests/facilities_test.cpp @@ -20,25 +20,6 @@ using namespace mlpack; using namespace mlpack::cv; -/** - * The unequal sizes for data and labels show throw an error. - */ -TEST_CASE("AssertSizesTest", "[FacilitiesTest]") -{ - // Load the dataset. - arma::mat dataset; - if (!data::Load("iris_train.csv", dataset)) - FAIL("Cannot load test dataset iris_train.csv!"); - // Load the labels. - arma::Row labels; - if (!data::Load("iris_test_labels.csv", labels)) - FAIL("Cannot load test dataset iris_test_labels.csv!"); - - REQUIRE_THROWS_AS( - AssertSizes(dataset, labels, "test"), std::invalid_argument); -} - - /** * Pairwise distances. */ From cdede9018bdf5f22735b11b3815c9a01662ea03d Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sat, 27 Feb 2021 15:59:50 -0500 Subject: [PATCH 221/253] Make sure feedforward_network_2_test.cpp gets compiled and run. --- src/mlpack/tests/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mlpack/tests/CMakeLists.txt b/src/mlpack/tests/CMakeLists.txt index e6dd629266..e94c73e0d3 100644 --- a/src/mlpack/tests/CMakeLists.txt +++ b/src/mlpack/tests/CMakeLists.txt @@ -34,6 +34,7 @@ add_executable(mlpack_test facilities_test.cpp fastmks_test.cpp feedforward_network_test.cpp + feedforward_network_2_test.cpp gan_test.cpp gmm_test.cpp hmm_test.cpp From bf238ed213d2d09dfeae40c506f57402d6e04293 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sat, 27 Feb 2021 16:09:13 -0500 Subject: [PATCH 222/253] Don't take a second argument for ToLower(). --- src/mlpack/core/util/to_lower.hpp | 5 +++-- src/mlpack/methods/ann/layer/atrous_convolution_impl.hpp | 3 +-- src/mlpack/methods/ann/layer/convolution_impl.hpp | 3 +-- src/mlpack/methods/ann/layer/transposed_convolution_impl.hpp | 3 +-- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/mlpack/core/util/to_lower.hpp b/src/mlpack/core/util/to_lower.hpp index 866b160ffd..98f46de9b5 100644 --- a/src/mlpack/core/util/to_lower.hpp +++ b/src/mlpack/core/util/to_lower.hpp @@ -19,12 +19,13 @@ namespace util {  * Convert a string to lowercase letters.  *  * @param input The string to convert. - * @param output The string to be converted.  */ -inline void ToLower(const std::string& input, std::string& output) +inline std::string ToLower(const std::string& input) { + std::string output; std::transform(input.begin(), input.end(), output.begin(), [](unsigned char c){ return std::tolower(c); }); + return output; } } // namespace util diff --git a/src/mlpack/methods/ann/layer/atrous_convolution_impl.hpp b/src/mlpack/methods/ann/layer/atrous_convolution_impl.hpp index cfb200e3ec..2377ddee00 100644 --- a/src/mlpack/methods/ann/layer/atrous_convolution_impl.hpp +++ b/src/mlpack/methods/ann/layer/atrous_convolution_impl.hpp @@ -125,8 +125,7 @@ AtrousConvolution< weights.set_size(WeightSize(), 1); // Transform paddingType to lowercase. - std::string paddingTypeLow = paddingType; - util::ToLower(paddingType, paddingTypeLow); + const std::string paddingTypeLow = util::ToLower(paddingType); size_t padWLeft = std::get<0>(padW); size_t padWRight = std::get<1>(padW); diff --git a/src/mlpack/methods/ann/layer/convolution_impl.hpp b/src/mlpack/methods/ann/layer/convolution_impl.hpp index 5018593279..7e6cebf184 100644 --- a/src/mlpack/methods/ann/layer/convolution_impl.hpp +++ b/src/mlpack/methods/ann/layer/convolution_impl.hpp @@ -120,8 +120,7 @@ Convolution< weights.set_size(WeightSize(), 1); // Transform paddingType to lowercase. - std::string paddingTypeLow = paddingType; - util::ToLower(paddingType, paddingTypeLow); + const std::string paddingTypeLow = util::ToLower(paddingType); if (paddingTypeLow == "valid") { diff --git a/src/mlpack/methods/ann/layer/transposed_convolution_impl.hpp b/src/mlpack/methods/ann/layer/transposed_convolution_impl.hpp index 47cf2cd6c8..d932acb6a7 100644 --- a/src/mlpack/methods/ann/layer/transposed_convolution_impl.hpp +++ b/src/mlpack/methods/ann/layer/transposed_convolution_impl.hpp @@ -126,8 +126,7 @@ TransposedConvolution< { weights.set_size(WeightSize(), 1); // Transform paddingType to lowercase. - std::string paddingTypeLow = paddingType; - util::ToLower(paddingType, paddingTypeLow); + const std::string paddingTypeLow = util::ToLower(paddingType); if (paddingTypeLow == "valid") { From 355e6db33a2b187e9b06aa780a725aadc267320b Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sat, 27 Feb 2021 16:50:39 -0500 Subject: [PATCH 223/253] Oops, use std::back_inserter(). --- src/mlpack/core/util/to_lower.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/core/util/to_lower.hpp b/src/mlpack/core/util/to_lower.hpp index 98f46de9b5..f427449baf 100644 --- a/src/mlpack/core/util/to_lower.hpp +++ b/src/mlpack/core/util/to_lower.hpp @@ -23,7 +23,7 @@ namespace util { inline std::string ToLower(const std::string& input) { std::string output; - std::transform(input.begin(), input.end(), output.begin(), + std::transform(input.begin(), input.end(), std::back_inserter(output), [](unsigned char c){ return std::tolower(c); }); return output; } From 12333a6b8b797807e658a5d513ead0e4148c0266 Mon Sep 17 00:00:00 2001 From: Bisakh Mondal Date: Sun, 28 Feb 2021 05:46:51 +0530 Subject: [PATCH 224/253] Update src/mlpack/core/util/size_checks.hpp Co-authored-by: Ryan Curtin --- src/mlpack/core/util/size_checks.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mlpack/core/util/size_checks.hpp b/src/mlpack/core/util/size_checks.hpp index 933655f475..ab81a9b355 100644 --- a/src/mlpack/core/util/size_checks.hpp +++ b/src/mlpack/core/util/size_checks.hpp @@ -13,7 +13,6 @@ #ifndef MLPACK_UTIL_SIZE_CHECKS_HPP #define MLPACK_UTIL_SIZE_CHECKS_HPP -#include namespace mlpack { namespace util { From 6800e5a05885b15fadaf905cdce2ad156a866f65 Mon Sep 17 00:00:00 2001 From: Gopi M Tatiraju Date: Mon, 1 Mar 2021 15:34:06 +0530 Subject: [PATCH 225/253] Apply suggestions from code review Co-authored-by: Marcus Edel --- src/mlpack/tests/feedforward_network_2_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/tests/feedforward_network_2_test.cpp b/src/mlpack/tests/feedforward_network_2_test.cpp index 3a57624d26..90ba3c3fbd 100644 --- a/src/mlpack/tests/feedforward_network_2_test.cpp +++ b/src/mlpack/tests/feedforward_network_2_test.cpp @@ -66,7 +66,7 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") // Load the dataset. arma::mat trainData; if (!data::Load("thyroid_train.csv", trainData)) - Fail("Cannot open thyroid_train.csv"); + FAIL("Cannot open thyroid_train.csv"); arma::mat trainLabels = trainData.row(trainData.n_rows - 1); trainData.shed_row(trainData.n_rows - 1); @@ -79,7 +79,7 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") arma::mat testData; if (!data::Load("thyroid_test.csv", testData)) - Fail("Cannot open thyroid_test.csv"); + FAIL("Cannot open thyroid_test.csv"); arma::mat testLabels = testData.row(testData.n_rows - 1); testData.shed_row(testData.n_rows - 1); @@ -139,4 +139,4 @@ TEST_CASE("RBFNetworkTest", "[FeedForwardNetworkTest]") // RBFN neural net with MeanSquaredError. TestNetwork<>(model1, dataset, labels1, dataset, labels, 10, 0.1); -} \ No newline at end of file +} From f33f003c3e9d9ea0d8906706e47be92dd9f98c58 Mon Sep 17 00:00:00 2001 From: onikolskyy Date: Mon, 1 Mar 2021 15:03:08 +0100 Subject: [PATCH 226/253] fix default values of cmake config for bindings in docs --- doc/guide/build.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/guide/build.hpp b/doc/guide/build.hpp index d889652e81..9996f5132d 100644 --- a/doc/guide/build.hpp +++ b/doc/guide/build.hpp @@ -175,9 +175,13 @@ The full list of options mlpack allows: (i.e. \c mlpack_knn, \c mlpack_kfn, \c mlpack_logistic_regression, etc.) (default ON) - BUILD_PYTHON_BINDINGS=(ON/OFF): compile the bindings for Python, if the - necessary Python libraries are available (default ON except on Windows) + necessary Python libraries are available (default OFF) + - BUILD_R_BINDINGS=(ON/OFF): compile the bindings for R, if R is found + (default OFF) + - BUILD_GO_BINDINGS=(ON/OFF): compile Go bindings, if Go and the necessary Go + and Gonum exist. (default OFF) - BUILD_JULIA_BINDINGS=(ON/OFF): compile Julia bindings, if Julia is found - (default ON) + (default OFF) - BUILD_SHARED_LIBS=(ON/OFF): compile shared libraries as opposed to static libraries (default ON) - TEST_VERBOSE=(ON/OFF): run test cases in \c mlpack_test with verbose output From 89163f648332d7c8a1d7137ea4c17bb01e5b3274 Mon Sep 17 00:00:00 2001 From: RishabhGarg108 Date: Tue, 2 Mar 2021 13:01:13 +0530 Subject: [PATCH 227/253] Templated labels for field labels --- src/mlpack/core/data/split_data.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index da4c240ca2..61f9860f54 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -405,16 +405,16 @@ Split(const arma::Mat& input, * @param shuffleData If true, the sample order is shuffled; otherwise, each * sample is visited in linear order. (Default true.) */ -template ::value || arma::is_Mat_only::value>> void Split(const FieldType& input, - const arma::field& inputLabel, + const arma::field& inputLabel, FieldType& trainData, - arma::field& trainLabel, + arma::field& trainLabel, FieldType& testData, - arma::field& testLabel, + arma::field& testLabel, const double testRatio, const bool shuffleData = true) { @@ -574,20 +574,20 @@ void Split(const FieldType& input, * (FieldType), trainLabel (arma::field), and * testLabel (arma::field). */ -template ::value || arma::is_Mat_only::value>> -std::tuple, arma::field> +std::tuple, arma::field> Split(const FieldType& input, - const arma::field& inputLabel, + const arma::field& inputLabel, const double testRatio, const bool shuffleData = true) { FieldType trainData; FieldType testData; - arma::field trainLabel; - arma::field testLabel; + arma::field trainLabel; + arma::field testLabel; Split(input, inputLabel, trainData, trainLabel, testData, testLabel, testRatio, shuffleData); From 9bffdb6d6e15e82d8b14ad3489909aa7c7b6657f Mon Sep 17 00:00:00 2001 From: Tru Hoang Date: Tue, 2 Mar 2021 13:51:51 -0800 Subject: [PATCH 228/253] Add CMake linking for OpenMP . Fixes build error for macOS 10.15 Catalina (#2412) * Update CMakeLists for macOS Catalina build * The XCode switch is probably not necessary with the new version. * Test OpenMP on macOS 10.15. * Update CMakeLists.txt Add guard condition for OpenMP_CXX_LIBRARIES for compatible CMake versions Co-authored-by: Ryan Birmingham * Update CMakeLists.txt Add endif() Co-authored-by: Ryan Birmingham * export OMP_NUM_THREADS in CI script * Empty commit to set up deployments * Use macOS latest image. * Add name to list of contributors Co-authored-by: Marcus Edel Co-authored-by: Ryan Birmingham --- .ci/macos-steps.yaml | 4 ++-- CMakeLists.txt | 3 +++ COPYRIGHT.txt | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.ci/macos-steps.yaml b/.ci/macos-steps.yaml index 85e92fe3b3..ce3c7796f5 100644 --- a/.ci/macos-steps.yaml +++ b/.ci/macos-steps.yaml @@ -14,7 +14,7 @@ steps: set -e sudo xcode-select --switch /Applications/Xcode_12.2.app/Contents/Developer unset BOOST_ROOT - brew install openblas armadillo boost cereal + brew install libomp openblas armadillo boost cereal if [ "$(binding)" == "python" ]; then pip install --upgrade pip @@ -65,4 +65,4 @@ steps: inputs: pathtoPublish: 'build/Testing/' artifactName: 'Tests' - displayName: 'Publish artifacts test results' + displayName: 'Publish artifacts test results' \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e0be77df06..2ecd13769c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -467,6 +467,9 @@ if (OPENMP_FOUND) add_definitions(-DHAS_OPENMP) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + if(OpenMP_CXX_FOUND) + set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${OpenMP_CXX_LIBRARIES}) + endif () else () # Disable warnings for all the unknown OpenMP pragmas. if (NOT MSVC) diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index d2d177da71..a3c8f90f38 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -141,6 +141,7 @@ Copyright: Copyright 2020, Alex Nguyen Copyright 2020, Gaurav Ghati Copyright 2020, Anmolpreet Singh + Copyright 2021, Tru Hoang License: BSD-3-clause All rights reserved. From 08d2a6d68db1eb4b7ecc3b043789684b6ab6806e Mon Sep 17 00:00:00 2001 From: Oleksandr Nikolskyy Date: Thu, 4 Mar 2021 20:33:56 +0100 Subject: [PATCH 229/253] add WeightSize() Method for linear_no_bias and radial_basis_function --- src/mlpack/methods/ann/layer/linear_no_bias.hpp | 6 ++++++ src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp | 2 +- src/mlpack/methods/ann/layer/radial_basis_function.hpp | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/mlpack/methods/ann/layer/linear_no_bias.hpp b/src/mlpack/methods/ann/layer/linear_no_bias.hpp index 7182e84238..5426f1ff4f 100644 --- a/src/mlpack/methods/ann/layer/linear_no_bias.hpp +++ b/src/mlpack/methods/ann/layer/linear_no_bias.hpp @@ -123,6 +123,12 @@ class LinearNoBias //! Modify the gradient. OutputDataType& Gradient() { return gradient; } + //! Get the size of the weights. + size_t WeightSize() const + { + return inSize * outSize; + } + //! Get the shape of the input. size_t InputShape() const { diff --git a/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp b/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp index 032552f599..dbea56e94f 100644 --- a/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp +++ b/src/mlpack/methods/ann/layer/linear_no_bias_impl.hpp @@ -38,7 +38,7 @@ LinearNoBias::LinearNoBias( outSize(outSize), regularizer(regularizer) { - weights.set_size(outSize * inSize, 1); + weights.set_size(WeightSize(), 1); } template Date: Thu, 4 Mar 2021 20:42:12 +0100 Subject: [PATCH 230/253] add WeightSize() Method for constant --- src/mlpack/methods/ann/layer/constant.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mlpack/methods/ann/layer/constant.hpp b/src/mlpack/methods/ann/layer/constant.hpp index b908a0018e..9a0956ddf8 100644 --- a/src/mlpack/methods/ann/layer/constant.hpp +++ b/src/mlpack/methods/ann/layer/constant.hpp @@ -79,6 +79,12 @@ class Constant //! Get the output size. size_t OutSize() const { return outSize; } + //! Get the size of the weights. + size_t WeightSize() const + { + return 0; + } + /** * Serialize the layer. */ From 6e241b33617364876179951d888114a81396c5be Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 5 Mar 2021 00:09:59 -0500 Subject: [PATCH 231/253] Fix anchor links in generated Markdown documentation (#2856) * Use the correct binding name to generate the anchor link. * Fix compilation warnings. --- src/mlpack/bindings/go/print_type_doc_impl.hpp | 2 +- src/mlpack/bindings/markdown/print_docs.cpp | 14 ++++++++++++-- .../simple_residue_termination.hpp | 6 +++--- .../svd_complete_incremental_learning.hpp | 2 +- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/mlpack/bindings/go/print_type_doc_impl.hpp b/src/mlpack/bindings/go/print_type_doc_impl.hpp index 0755f60b8a..d0a5fef659 100644 --- a/src/mlpack/bindings/go/print_type_doc_impl.hpp +++ b/src/mlpack/bindings/go/print_type_doc_impl.hpp @@ -84,7 +84,7 @@ std::string PrintTypeDoc( */ template std::string PrintTypeDoc( - util::ParamData& data, + util::ParamData& /* data */, const typename std::enable_if::value>::type*) { if (T::is_col || T::is_row) diff --git a/src/mlpack/bindings/markdown/print_docs.cpp b/src/mlpack/bindings/markdown/print_docs.cpp index 45b9807afa..44adf69e93 100644 --- a/src/mlpack/bindings/markdown/print_docs.cpp +++ b/src/mlpack/bindings/markdown/print_docs.cpp @@ -36,8 +36,18 @@ void PrintHeaders(const std::string& bindingName, { BindingInfo::Language() = languages[i]; - cout << " - [" << GetBindingName(bindingName) << "](#" << languages[i] - << "_" << bindingName << "){: .language-link #" << languages[i] << " }" + // Get the name of the binding in the target language, and convert it to + // lowercase (since the anchor link will be in lowercase). + const std::string langBindingName = GetBindingName(bindingName); + std::string anchorName = langBindingName; + std::transform(anchorName.begin(), anchorName.end(), anchorName.begin(), + [](unsigned char c) { return std::tolower(c); }); + // Strip '()' from the end if needed. + if (anchorName.substr(anchorName.size() - 2, 2) == "()") + anchorName = anchorName.substr(0, anchorName.size() - 2); + + cout << " - [" << langBindingName << "](#" << languages[i] + << "_" << anchorName << "){: .language-link #" << languages[i] << " }" << endl; } } diff --git a/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp b/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp index 86631e32ce..6c214795c4 100644 --- a/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp +++ b/src/mlpack/methods/amf/termination_policies/simple_residue_termination.hpp @@ -45,9 +45,9 @@ class SimpleResidueTermination maxIterations(maxIterations), residue(0.0), iteration(0), - nm(0), - normOld(0) - { + normOld(0), + nm(0) + { // Nothing to do here. } diff --git a/src/mlpack/methods/amf/update_rules/svd_complete_incremental_learning.hpp b/src/mlpack/methods/amf/update_rules/svd_complete_incremental_learning.hpp index 37b7ab8c0a..ab2e9d2503 100644 --- a/src/mlpack/methods/amf/update_rules/svd_complete_incremental_learning.hpp +++ b/src/mlpack/methods/amf/update_rules/svd_complete_incremental_learning.hpp @@ -172,7 +172,7 @@ class SVDCompleteIncrementalLearning SVDCompleteIncrementalLearning(double u = 0.01, double kw = 0, double kh = 0) - : u(u), kw(kw), kh(kh), it(NULL), m(0), n(0), isStart(false) + : u(u), kw(kw), kh(kh), n(0), m(0), it(NULL), isStart(false) {} ~SVDCompleteIncrementalLearning() From d53b08d936971531be77a8d3cca2737846d13692 Mon Sep 17 00:00:00 2001 From: Anush V Kini Date: Fri, 5 Mar 2021 13:17:05 +0530 Subject: [PATCH 232/253] Removed loop from bootstrap --- src/mlpack/methods/random_forest/bootstrap.hpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/mlpack/methods/random_forest/bootstrap.hpp b/src/mlpack/methods/random_forest/bootstrap.hpp index fa6e5af6be..abbbbbaa05 100644 --- a/src/mlpack/methods/random_forest/bootstrap.hpp +++ b/src/mlpack/methods/random_forest/bootstrap.hpp @@ -38,13 +38,10 @@ void Bootstrap(const MatType& dataset, // Random sampling with replacement. arma::uvec indices = arma::randi(dataset.n_cols, arma::distr_param(0, dataset.n_cols - 1)); - for (size_t i = 0; i < dataset.n_cols; ++i) - { - bootstrapDataset.col(i) = dataset.col(indices[i]); - bootstrapLabels[i] = labels[indices[i]]; - if (UseWeights) - bootstrapWeights[i] = weights[indices[i]]; - } + bootstrapDataset = dataset.cols(indices); + bootstrapLabels = labels.cols(indices); + if (UseWeights) + bootstrapWeights = weights.cols(indices); } } // namespace tree From 3bd4567bdfbbfe5cbb29bcb76d5c1ef88dc13d1a Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 5 Mar 2021 09:29:29 -0500 Subject: [PATCH 233/253] Add functions to access and modify parameters for training. --- src/mlpack/methods/lars/lars.cpp | 4 ++++ src/mlpack/methods/lars/lars.hpp | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/mlpack/methods/lars/lars.cpp b/src/mlpack/methods/lars/lars.cpp index 03612406fc..16bfa64124 100644 --- a/src/mlpack/methods/lars/lars.cpp +++ b/src/mlpack/methods/lars/lars.cpp @@ -178,6 +178,10 @@ double LARS::Train(const arma::mat& matX, isIgnored.clear(); matUtriCholFactor.reset(); + // Update values in case lambda1 or lambda2 changed. + lasso = (lambda1 != 0); + elasticNet = (lambda1 != 0 && lambda2 != 0); + // This matrix may end up holding the transpose -- if necessary. arma::mat dataTrans; // dataRef is row-major. diff --git a/src/mlpack/methods/lars/lars.hpp b/src/mlpack/methods/lars/lars.hpp index 8989d13e55..d019fec900 100644 --- a/src/mlpack/methods/lars/lars.hpp +++ b/src/mlpack/methods/lars/lars.hpp @@ -249,6 +249,26 @@ class LARS arma::rowvec& predictions, const bool rowMajor = false) const; + //! Get the L1 regularization coefficient. + double Lambda1() const { return lambda1; } + //! Modify the L1 regularization coefficient. + double& Lambda1() { return lambda1; } + + //! Get the L2 regularization coefficient. + double Lambda2() const { return lambda2; } + //! Modify the L2 regularization coefficient. + double& Lambda2() { return lambda2; } + + //! Get whether to use the Cholesky decomposition. + bool UseCholesky() const { return useCholesky; } + //! Modify whether to use the Cholesky decomposition. + bool& UseCholesky() { return useCholesky; } + + //! Get the tolerance for maximum correlation during training. + double Tolerance() const { return tolerance; } + //! Modify the tolerance for maximum correlation during training. + double& Tolerance() { return tolerance; } + //! Access the set of active dimensions. const std::vector& ActiveSet() const { return activeSet; } From b11720c4defe4af59764e5c7d0b768208bb910aa Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 5 Mar 2021 09:31:44 -0500 Subject: [PATCH 234/253] Update history. --- HISTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 12692b8308..f0b696d6ac 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -34,6 +34,9 @@ * `NegativeLogLikelihood<>` now expects classes in the range `0` to `numClasses - 1` (#2534). + * Add `Lambda1()`, `Lambda2()`, `UseCholesky()`, and `Tolerance()` members to + `LARS` so parameters for training can be modified (#2861). + ### mlpack 3.4.2 ###### 2020-10-26 * Added Mean Absolute Percentage Error. From 5d078b4e173a818e4393c26a73677fd12a63d288 Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Fri, 5 Mar 2021 18:21:45 -0500 Subject: [PATCH 235/253] Loosen tolerances: AdaBoost does not guarantee better performance than a single weak learner. --- src/mlpack/tests/adaboost_test.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/mlpack/tests/adaboost_test.cpp b/src/mlpack/tests/adaboost_test.cpp index cccf6f42d8..6f584a0f04 100644 --- a/src/mlpack/tests/adaboost_test.cpp +++ b/src/mlpack/tests/adaboost_test.cpp @@ -67,7 +67,7 @@ TEST_CASE("HammingLossBoundIris", "[AdaBoostTest]") /** * This test case runs the AdaBoost.mh algorithm on the UCI Iris dataset. It * checks if the error returned by running a single instance of the weak learner - * is worse than running the boosted weak learner using adaboost. + * close to that of the boosted weak learner using adaboost. */ TEST_CASE("WeakLearnerErrorIris", "[AdaBoostTest]") { @@ -105,7 +105,7 @@ TEST_CASE("WeakLearnerErrorIris", "[AdaBoostTest]") size_t countError = arma::accu(labels != predictedLabels);; double error = (double) countError / labels.n_cols; - REQUIRE(error <= weakLearnerErrorRate); + REQUIRE(error <= weakLearnerErrorRate + 0.03); } /** @@ -151,7 +151,7 @@ TEST_CASE("HammingLossBoundVertebralColumn", "[AdaBoostTest]") /** * This test case runs the AdaBoost.mh algorithm on the UCI Vertebral Column * dataset. It checks if the error returned by running a single instance of the - * weak learner is worse than running the boosted weak learner using adaboost. + * weak learner is close to that of a boosted weak learner using adaboost. */ TEST_CASE("WeakLearnerErrorVertebralColumn", "[AdaBoostTest]") { @@ -187,7 +187,7 @@ TEST_CASE("WeakLearnerErrorVertebralColumn", "[AdaBoostTest]") size_t countError = arma::accu(labels != predictedLabels); double error = (double) countError / labels.n_cols; - REQUIRE(error <= weakLearnerErrorRate); + REQUIRE(error <= weakLearnerErrorRate + 0.03); } /** @@ -233,7 +233,7 @@ TEST_CASE("HammingLossBoundNonLinearSepData", "[AdaBoostTest]") /** * This test case runs the AdaBoost.mh algorithm on a non-linearly separable * dataset. It checks if the error returned by running a single instance of the - * weak learner is worse than running the boosted weak learner using AdaBoost. + * weak learner is close to that of a boosted weak learner using AdaBoost. */ TEST_CASE("WeakLearnerErrorNonLinearSepData", "[AdaBoostTest]") { @@ -269,7 +269,7 @@ TEST_CASE("WeakLearnerErrorNonLinearSepData", "[AdaBoostTest]") size_t countError = arma::accu(labels != predictedLabels); double error = (double) countError / labels.n_cols; - REQUIRE(error == weakLearnerErrorRate); + REQUIRE(error <= weakLearnerErrorRate + 0.03); } /** @@ -314,7 +314,7 @@ TEST_CASE("HammingLossIris_DS", "[AdaBoostTest]") /** * This test case runs the AdaBoost.mh algorithm on a non-linearly separable * dataset. It checks if the error returned by running a single instance of the - * weak learner is worse than running the boosted weak learner using adaboost. + * weak learner is close to that of a boosted weak learner using adaboost. * This is for the weak learner: decision stumps. */ TEST_CASE("WeakLearnerErrorIris_DS", "[AdaBoostTest]") @@ -355,13 +355,13 @@ TEST_CASE("WeakLearnerErrorIris_DS", "[AdaBoostTest]") size_t countError = arma::accu(labels != predictedLabels); double error = (double) countError / labels.n_cols; - REQUIRE(error <= weakLearnerErrorRate); + REQUIRE(error <= weakLearnerErrorRate + 0.03); } /** * This test case runs the AdaBoost.mh algorithm on the UCI Vertebral Column * dataset. It checks if the error returned by running a single instance of the - * weak learner is worse than running the boosted weak learner using adaboost. + * weak learner is close to that of a boosted weak learner using adaboost. * This is for the weak learner: decision stumps. */ TEST_CASE("HammingLossBoundVertebralColumn_DS", "[AdaBoostTest]") @@ -403,7 +403,7 @@ TEST_CASE("HammingLossBoundVertebralColumn_DS", "[AdaBoostTest]") /** * This test case runs the AdaBoost.mh algorithm on the UCI Vertebral Column * dataset. It checks if the error returned by running a single instance of the - * weak learner is worse than running the boosted weak learner using adaboost. + * weak learner is close to that of a boosted weak learner using adaboost. * This is for the weak learner: decision stumps. */ TEST_CASE("WeakLearnerErrorVertebralColumn_DS", "[AdaBoostTest]") @@ -440,7 +440,7 @@ TEST_CASE("WeakLearnerErrorVertebralColumn_DS", "[AdaBoostTest]") size_t countError = arma::accu(labels != predictedLabels); double error = (double) countError / labels.n_cols; - REQUIRE(error <= weakLearnerErrorRate); + REQUIRE(error <= weakLearnerErrorRate + 0.03); } /** @@ -487,7 +487,7 @@ TEST_CASE("HammingLossBoundNonLinearSepData_DS", "[AdaBoostTest]") /** * This test case runs the AdaBoost.mh algorithm on a non-linearly separable * dataset. It checks if the error returned by running a single instance of the - * weak learner is worse than running the boosted weak learner using adaboost. + * weak learner is close to that of a boosted weak learner using adaboost. * This for the weak learner: decision stumps. */ TEST_CASE("WeakLearnerErrorNonLinearSepData_DS", "[AdaBoostTest]") @@ -526,7 +526,7 @@ TEST_CASE("WeakLearnerErrorNonLinearSepData_DS", "[AdaBoostTest]") size_t countError = arma::accu(labels != predictedLabels); double error = (double) countError / labels.n_cols; - REQUIRE(error <= weakLearnerErrorRate); + REQUIRE(error <= weakLearnerErrorRate + 0.03); } /** From 4a4de532dc3a539a075e6d648ce3129b13cc544f Mon Sep 17 00:00:00 2001 From: Ryan Curtin Date: Sat, 6 Mar 2021 17:56:00 -0500 Subject: [PATCH 236/253] Move initialization of static members into a cpp file. --- .../environment/CMakeLists.txt | 1 + .../environment/env_type.cpp | 27 +++++++++++++++++++ .../environment/env_type.hpp | 4 --- 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 src/mlpack/methods/reinforcement_learning/environment/env_type.cpp diff --git a/src/mlpack/methods/reinforcement_learning/environment/CMakeLists.txt b/src/mlpack/methods/reinforcement_learning/environment/CMakeLists.txt index 04e5b8b2a8..f93995ab75 100644 --- a/src/mlpack/methods/reinforcement_learning/environment/CMakeLists.txt +++ b/src/mlpack/methods/reinforcement_learning/environment/CMakeLists.txt @@ -2,6 +2,7 @@ # Anything not in this list will not be compiled into mlpack. set(SOURCES env_type.hpp + env_type.cpp mountain_car.hpp cart_pole.hpp continuous_mountain_car.hpp diff --git a/src/mlpack/methods/reinforcement_learning/environment/env_type.cpp b/src/mlpack/methods/reinforcement_learning/environment/env_type.cpp new file mode 100644 index 0000000000..d5363b5501 --- /dev/null +++ b/src/mlpack/methods/reinforcement_learning/environment/env_type.cpp @@ -0,0 +1,27 @@ +/** + * @file methods/reinforcement_learning/environment/env_type.cpp + * @author Nishant Kumar + * + * This file defines the static variables used by the discrete and continuous + * environments. + * + * 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 "env_type.hpp" + +namespace mlpack { +namespace rl { + +// Instantiate static members. + +size_t DiscreteActionEnv::State::dimension = 0; +size_t DiscreteActionEnv::Action::size = 0; + +size_t ContinuousActionEnv::State::dimension = 0; +size_t ContinuousActionEnv::Action::size = 0; + +} // namespace rl +} // namespace mlpack diff --git a/src/mlpack/methods/reinforcement_learning/environment/env_type.hpp b/src/mlpack/methods/reinforcement_learning/environment/env_type.hpp index e8513e3bb9..4fcf797322 100644 --- a/src/mlpack/methods/reinforcement_learning/environment/env_type.hpp +++ b/src/mlpack/methods/reinforcement_learning/environment/env_type.hpp @@ -105,8 +105,6 @@ class DiscreteActionEnv */ bool IsTerminal(const State& /* state */) const { return false; } }; -size_t DiscreteActionEnv::State::dimension = 0; -size_t DiscreteActionEnv::Action::size = 0; /** * To use the dummy environment, one may start by specifying the state and @@ -201,8 +199,6 @@ class ContinuousActionEnv */ bool IsTerminal(const State& /* state */) const { return false; } }; -size_t ContinuousActionEnv::State::dimension = 0; -size_t ContinuousActionEnv::Action::size = 0; } // namespace rl } // namespace mlpack From e516f72472bd606fc2b1d46acca1285e60fe5781 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Sun, 7 Mar 2021 18:27:01 +0530 Subject: [PATCH 237/253] Added SplitHelper to remove redundant code --- src/mlpack/core/data/split_data.hpp | 256 ++++++++++++---------------- 1 file changed, 105 insertions(+), 151 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 61f9860f54..1fa9bab6db 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -18,6 +18,101 @@ namespace mlpack { namespace data { +template +void SplitHelper(const InputType& input, + const LabelsType& inputLabel, + InputType& trainData, + InputType& testData, + LabelsType& trainLabel, + LabelsType& testLabel, + const double testRatio, + const bool shuffleData = true) +{ + const size_t testSize = static_cast(input.n_cols * testRatio); + const size_t trainSize = input.n_cols - testSize; + + trainData.set_size(input.n_rows, trainSize); + testData.set_size(input.n_rows, testSize); + trainLabel.set_size(inputLabel.n_rows, trainSize); + testLabel.set_size(inputLabel.n_rows, testSize); + + if (shuffleData) + { + arma::uvec order = arma::shuffle(arma::linspace(0, + input.n_cols - 1, input.n_cols)); + + if (trainSize > 0) + { + for (size_t i = 0; i < trainSize; ++i) + { + trainData.col(i) = input.col(order(i)); + trainLabel.col(i) = inputLabel.col(order(i)); + } + } + if (trainSize < input.n_cols) + { + for (size_t i = trainSize; i < input.n_cols; ++i) + { + testData.col(i - trainSize) = input.col(order(i)); + testLabel.col(i - trainSize) = inputLabel.col(order(i)); + } + } + } + else + { + if (trainSize > 0) + { + trainData = input.cols(0, trainSize - 1); + trainLabel = inputLabel.cols(0, trainSize - 1); + } + + if (trainSize < input.n_cols) + { + testData = input.cols(trainSize, input.n_cols - 1); + testLabel = inputLabel.cols(trainSize, inputLabel.n_cols - 1); + } + } +} + +template +void SplitHelper(const InputType& input, + InputType& trainData, + InputType& testData, + const double testRatio, + const bool shuffleData = true) +{ + const size_t testSize = static_cast(input.n_cols * testRatio); + const size_t trainSize = input.n_cols - testSize; + + trainData.set_size(input.n_rows, trainSize); + testData.set_size(input.n_rows, testSize); + + if (shuffleData) + { + arma::uvec order = arma::shuffle(arma::linspace(0, + input.n_cols - 1, input.n_cols)); + + if (trainSize > 0) + { + for (size_t i = 0; i < trainSize; ++i) + trainData.col(i) = input.col(order(i)); + } + if (trainSize < input.n_cols) + { + for (size_t i = trainSize; i < input.n_cols; ++i) + testData.col(i - trainSize) = input.col(order(i)); + } + } + else + { + if (trainSize > 0) + trainData = input.cols(0, trainSize - 1); + + if (trainSize < input.n_cols) + testData = input.cols(trainSize, input.n_cols - 1); + } +} + /** * Given an input dataset and labels, stratify into a training set and test set. * It is recommended to have the input labels between the range [0, n) where n @@ -92,8 +187,8 @@ void StratifiedSplit(const arma::Mat& input, trainData.set_size(input.n_rows, trainSize); testData.set_size(input.n_rows, testSize); - trainLabel.set_size(trainSize); - testLabel.set_size(testSize); + trainLabel.set_size(inputLabel.n_rows, trainSize); + testLabel.set_size(inputLabel.n_rows, testSize); if (shuffleData) { @@ -184,44 +279,9 @@ void Split(const arma::Mat& input, const double testRatio, const bool shuffleData = true) { - const size_t testSize = static_cast(input.n_cols * testRatio); - const size_t trainSize = input.n_cols - testSize; - trainData.set_size(input.n_rows, trainSize); - testData.set_size(input.n_rows, testSize); - trainLabel.set_size(1, trainSize); - testLabel.set_size(1, testSize); - - if (shuffleData) - { - arma::uvec order = arma::shuffle(arma::linspace(0, input.n_cols - 1, - input.n_cols)); - - if (trainSize > 0) - { - trainData = input.cols(order.subvec(0, trainSize - 1)); - trainLabel = inputLabel.cols(order.subvec(0, trainSize - 1)); - } - - if (trainSize < input.n_cols) - { - testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); - testLabel = inputLabel.cols(order.subvec(trainSize, input.n_cols - 1)); - } - } - else - { - if (trainSize > 0) - { - trainData = input.cols(0, trainSize - 1); - trainLabel = inputLabel.cols(0, trainSize - 1); - } - - if (trainSize < input.n_cols) - { - testData = input.cols(trainSize, input.n_cols - 1); - testLabel = inputLabel.cols(trainSize, inputLabel.n_cols - 1); - } - } + SplitHelper(input, inputLabel, trainData, + testData, trainLabel, testLabel, testRatio, + shuffleData); } /** @@ -254,30 +314,7 @@ void Split(const arma::Mat& input, const double testRatio, const bool shuffleData = true) { - const size_t testSize = static_cast(input.n_cols * testRatio); - const size_t trainSize = input.n_cols - testSize; - trainData.set_size(input.n_rows, trainSize); - testData.set_size(input.n_rows, testSize); - - if (shuffleData) - { - arma::uvec order = arma::shuffle(arma::linspace( - 0, input.n_cols - 1, input.n_cols)); - - if (trainSize > 0) - trainData = input.cols(order.subvec(0, trainSize - 1)); - - if (trainSize < input.n_cols) - testData = input.cols(order.subvec(trainSize, input.n_cols - 1)); - } - else - { - if (trainSize > 0) - trainData = input.cols(0, trainSize - 1); - - if (trainSize < input.n_cols) - testData = input.cols(trainSize , input.n_cols - 1); - } + SplitHelper(input, trainData, testData, testRatio, shuffleData); } /** @@ -418,56 +455,9 @@ void Split(const FieldType& input, const double testRatio, const bool shuffleData = true) { - const size_t testSize = static_cast(input.n_cols * testRatio); - const size_t trainSize = input.n_cols - testSize; - - trainData.set_size(1, trainSize); - testData.set_size(1, testSize); - trainLabel.set_size(trainSize); - testLabel.set_size(testSize); - - if (shuffleData) - { - arma::uvec order = arma::shuffle(arma::linspace(0, - input.n_cols - 1, input.n_cols)); - - if (trainSize > 0) - { - for (size_t i = 0; i < trainSize; ++i) - { - trainData[i] = input(0, order(i)); - trainLabel[i] = inputLabel(0, order(i)); - } - } - if (trainSize < input.n_cols) - { - for (size_t i = trainSize; i < input.n_cols; ++i) - { - testData[i - trainSize] = input(0, order(i)); - testLabel[i - trainSize] = inputLabel(0, order(i)); - } - } - } - else - { - if (trainSize > 0) - { - for (size_t i = 0; i < trainSize; ++i) - { - trainData[i] = input(0, i); - trainLabel[i] = inputLabel(0, i); - } - } - - if (trainSize < input.n_cols) - { - for (size_t i = trainSize; i < input.n_cols; ++i) - { - testData[i - trainSize] = input(0, i); - testLabel[i - trainSize] = inputLabel(0, i); - } - } - } + SplitHelper(input, inputLabel, trainData, + testData, trainLabel, testLabel, testRatio, + shuffleData); } /** @@ -508,43 +498,7 @@ void Split(const FieldType& input, const double testRatio, const bool shuffleData = true) { - const size_t testSize = static_cast(input.n_cols * testRatio); - const size_t trainSize = input.n_cols - testSize; - - trainData.set_size(1, trainSize); - testData.set_size(1, testSize); - - if (shuffleData) - { - arma::uvec order = arma::shuffle(arma::linspace(0, - input.n_cols - 1, input.n_cols)); - - if (trainSize > 0) - { - for (size_t i = 0; i < trainSize; i++) - trainData[i] = input(0, order(i)); - } - - if (trainSize < input.n_cols) - { - for (size_t i = trainSize; i < input.n_cols - 1; ++i) - testData[i - trainSize] = input(0, order(i)); - } - } - else - { - if (trainSize > 0) - { - for (size_t i = 0; i < trainSize; i++) - trainData[i] = input(0, i); - } - - if (trainSize < input.n_cols) - { - for (size_t i = trainSize; i < input.n_cols - 1; ++i) - testData[i - trainSize] = input(0, i); - } - } + SplitHelper(input, trainData, testData, testRatio, shuffleData); } /** From 9ae544a31b1d16b535b4ea7067e53cd67e96fbe5 Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Tue, 9 Mar 2021 19:15:32 +0100 Subject: [PATCH 238/253] Clean Coverage, no longer used Signed-off-by: Omar Shrit --- CMakeLists.txt | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ecd13769c..38785e0165 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,8 +80,6 @@ option(BUILD_R_BINDINGS "Build R bindings." OFF) # generation. option(BUILD_MARKDOWN_BINDINGS "Build Markdown bindings for website documentation." OFF) -option(BUILD_WITH_COVERAGE - "Build with support for code coverage tools (gcc only)." OFF) option(MATHJAX "Use MathJax for HTML Doxygen output (disabled by default)." OFF) option(FORCE_CXX11 @@ -196,38 +194,6 @@ if(CMAKE_COMPILER_IS_GNUCC) ${CMAKE_THREAD_LIBS_INIT}) endif() -# Setup build for test coverage -if(BUILD_WITH_COVERAGE) - # Currently coverage only works with GNU g++. - if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") - # Find gcov and lcov - find_program(GCOV gcov) - find_program(LCOV lcov) - - if(NOT GCOV) - message(FATAL_ERROR - "gcov not found! gcov is required when BUILD_WITH_COVERAGE=ON.") - endif() - - set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} "supc++") - set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} "quadmath") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -fno-inline -fno-inline-small-functions -fno-default-inline -fprofile-arcs -fkeep-inline-functions") - message(STATUS "Adding debug compile options for code coverage.") - # Remove optimizations for better line coverage - set(DEBUG ON) - - if(LCOV) - configure_file(CMake/mlpack_coverage.in mlpack_coverage @ONLY) - add_custom_target(mlpack_coverage DEPENDS mlpack_test COMMAND ${PROJECT_BINARY_DIR}/mlpack_coverage) - else() - message(WARNING "'lcov' not found; local coverage report is disabled. " - "Install 'lcov' and rerun cmake to generate local coverage report.") - endif() - else() - message(FATAL_ERROR "BUILD_WITH_COVERAGE can only work with GNU environment.") - endif() -endif() - # Debugging CFLAGS. Turn optimizations off; turn debugging symbols on. if(DEBUG) if (NOT MSVC) From 9a1a6e983e32a4dec741fd8fa02c6676fcb23249 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Wed, 10 Mar 2021 11:25:35 +0530 Subject: [PATCH 239/253] Update src/mlpack/core/data/split_data.hpp Co-authored-by: Ryan Curtin --- src/mlpack/core/data/split_data.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 1fa9bab6db..67f8491c68 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -20,13 +20,13 @@ namespace data { template void SplitHelper(const InputType& input, - const LabelsType& inputLabel, - InputType& trainData, - InputType& testData, - LabelsType& trainLabel, - LabelsType& testLabel, - const double testRatio, - const bool shuffleData = true) + const LabelsType& inputLabel, + InputType& trainData, + InputType& testData, + LabelsType& trainLabel, + LabelsType& testLabel, + const double testRatio, + const bool shuffleData = true) { const size_t testSize = static_cast(input.n_cols * testRatio); const size_t trainSize = input.n_cols - testSize; From b39ef0f9a9cd09e94200aaac274300fa7c06a92c Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Wed, 10 Mar 2021 12:25:39 +0530 Subject: [PATCH 240/253] Removed un needed overload of SplitHelper --- src/mlpack/core/data/split_data.hpp | 125 ++++++++++++---------------- 1 file changed, 51 insertions(+), 74 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 67f8491c68..1dd1abc62c 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -18,68 +18,12 @@ namespace mlpack { namespace data { -template -void SplitHelper(const InputType& input, - const LabelsType& inputLabel, - InputType& trainData, - InputType& testData, - LabelsType& trainLabel, - LabelsType& testLabel, - const double testRatio, - const bool shuffleData = true) -{ - const size_t testSize = static_cast(input.n_cols * testRatio); - const size_t trainSize = input.n_cols - testSize; - - trainData.set_size(input.n_rows, trainSize); - testData.set_size(input.n_rows, testSize); - trainLabel.set_size(inputLabel.n_rows, trainSize); - testLabel.set_size(inputLabel.n_rows, testSize); - - if (shuffleData) - { - arma::uvec order = arma::shuffle(arma::linspace(0, - input.n_cols - 1, input.n_cols)); - - if (trainSize > 0) - { - for (size_t i = 0; i < trainSize; ++i) - { - trainData.col(i) = input.col(order(i)); - trainLabel.col(i) = inputLabel.col(order(i)); - } - } - if (trainSize < input.n_cols) - { - for (size_t i = trainSize; i < input.n_cols; ++i) - { - testData.col(i - trainSize) = input.col(order(i)); - testLabel.col(i - trainSize) = inputLabel.col(order(i)); - } - } - } - else - { - if (trainSize > 0) - { - trainData = input.cols(0, trainSize - 1); - trainLabel = inputLabel.cols(0, trainSize - 1); - } - - if (trainSize < input.n_cols) - { - testData = input.cols(trainSize, input.n_cols - 1); - testLabel = inputLabel.cols(trainSize, inputLabel.n_cols - 1); - } - } -} - template void SplitHelper(const InputType& input, - InputType& trainData, - InputType& testData, - const double testRatio, - const bool shuffleData = true) + InputType& trainData, + InputType& testData, + const double testRatio, + const arma::uvec* order = nullptr) { const size_t testSize = static_cast(input.n_cols * testRatio); const size_t trainSize = input.n_cols - testSize; @@ -87,20 +31,17 @@ void SplitHelper(const InputType& input, trainData.set_size(input.n_rows, trainSize); testData.set_size(input.n_rows, testSize); - if (shuffleData) + if (order) { - arma::uvec order = arma::shuffle(arma::linspace(0, - input.n_cols - 1, input.n_cols)); - if (trainSize > 0) { for (size_t i = 0; i < trainSize; ++i) - trainData.col(i) = input.col(order(i)); + trainData.col(i) = input.col( (*order)(i) ); } if (trainSize < input.n_cols) { for (size_t i = trainSize; i < input.n_cols; ++i) - testData.col(i - trainSize) = input.col(order(i)); + testData.col(i - trainSize) = input.col( (*order)(i) ); } } else @@ -279,9 +220,18 @@ void Split(const arma::Mat& input, const double testRatio, const bool shuffleData = true) { - SplitHelper(input, inputLabel, trainData, - testData, trainLabel, testLabel, testRatio, - shuffleData); + if(shuffleData) + { + arma::uvec order = arma::shuffle(arma::linspace(0, + input.n_cols - 1, input.n_cols)); + SplitHelper(input, trainData, testData, testRatio, &order); + SplitHelper(inputLabel, trainLabel, testLabel, testRatio, &order); + } + else + { + SplitHelper(input, trainData, testData, testRatio); + SplitHelper(inputLabel, trainLabel, testLabel, testRatio); + } } /** @@ -314,7 +264,16 @@ void Split(const arma::Mat& input, const double testRatio, const bool shuffleData = true) { - SplitHelper(input, trainData, testData, testRatio, shuffleData); + if(shuffleData) + { + arma::uvec order = arma::shuffle(arma::linspace(0, + input.n_cols - 1, input.n_cols)); + SplitHelper(input, trainData, testData, testRatio, &order); + } + else + { + SplitHelper(input, trainData, testData, testRatio); + } } /** @@ -455,9 +414,18 @@ void Split(const FieldType& input, const double testRatio, const bool shuffleData = true) { - SplitHelper(input, inputLabel, trainData, - testData, trainLabel, testLabel, testRatio, - shuffleData); + if(shuffleData) + { + arma::uvec order = arma::shuffle(arma::linspace(0, + input.n_cols - 1, input.n_cols)); + SplitHelper(input, trainData, testData, testRatio, &order); + SplitHelper(inputLabel, trainLabel, testLabel, testRatio, &order); + } + else + { + SplitHelper(input, trainData, testData, testRatio); + SplitHelper(inputLabel, trainLabel, testLabel, testRatio); + } } /** @@ -498,7 +466,16 @@ void Split(const FieldType& input, const double testRatio, const bool shuffleData = true) { - SplitHelper(input, trainData, testData, testRatio, shuffleData); + if(shuffleData) + { + arma::uvec order = arma::shuffle(arma::linspace(0, + input.n_cols - 1, input.n_cols)); + SplitHelper(input, trainData, testData, testRatio, &order); + } + else + { + SplitHelper(input, trainData, testData, testRatio); + } } /** From 0557f042bf80ffcac471cbb0f461fb1103ea3db5 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Wed, 10 Mar 2021 12:26:59 +0530 Subject: [PATCH 241/253] Resurrected StratifiedSplit implementation explanation --- src/mlpack/core/data/split_data.hpp | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 1dd1abc62c..7d61e434ec 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -101,6 +101,39 @@ void StratifiedSplit(const arma::Mat& input, const double testRatio, const bool shuffleData = true) { + /** + * Basic idea: + * Let us say we have to stratify a dataset based on labels: + * 0 0 0 0 0 (5 0s) + * 1 1 1 1 1 1 1 1 1 1 1 (11 1s) + * + * Let our test ratio be 0.2. + * Then, the number of 0 labels in our test set = floor(5 * 0.2) = 1. + * The number of 1 labels in our test set = floor(11 * 0.2) = 2. + * + * In our first pass over the dataset, + * We visit each label and keep count of each label in our 'labelCounts' uvec. + * + * We then take a second pass over the dataset. + * We now maintain an additional uvec 'testLabelCounts' to hold the label + * counts of our test set. + * + * In this pass, when we encounter a label we check the 'testLabelCounts' uvec + * for the count of this label in the test set. + * If this count is less than the required number of labels in the test set, + * we add the data to the test set and increment the label count in the uvec. + * If this count is equal to or more than the required count in the test set, + * we add this data to the train set. + * + * Based on the above steps, we get the following labels in the split set: + * Train set (4 0s, 9 1s) + * 0 0 0 0 + * 1 1 1 1 1 1 1 1 1 + * + * Test set (1 0s, 2 1s) + * 0 + * 1 1 + */ const bool typeCheck = (arma::is_Row::value) || (arma::is_Col::value); if (!typeCheck) From 1117300efb742cc1fe0cb53aba3d2ba5b1b2c8bb Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Wed, 10 Mar 2021 12:40:09 +0530 Subject: [PATCH 242/253] Added documentation --- src/mlpack/core/data/split_data.hpp | 32 ++++++++++++++++++----------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 7d61e434ec..a97058d29b 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -18,39 +18,47 @@ namespace mlpack { namespace data { +/** + * This helper function splits any `input` data into training and testing parts. + * In order to shuffle the input data before spliting, an array of shuffled + * indices of the input data is passed in the form of argument `order`. + */ template void SplitHelper(const InputType& input, - InputType& trainData, - InputType& testData, + InputType& train, + InputType& test, const double testRatio, const arma::uvec* order = nullptr) { const size_t testSize = static_cast(input.n_cols * testRatio); const size_t trainSize = input.n_cols - testSize; - trainData.set_size(input.n_rows, trainSize); - testData.set_size(input.n_rows, testSize); + // Initialising the sizes of outputs if not already initialized. + train.set_size(input.n_rows, trainSize); + test.set_size(input.n_rows, testSize); + // Shuffling and spliting simultaneously. if (order) { if (trainSize > 0) { for (size_t i = 0; i < trainSize; ++i) - trainData.col(i) = input.col( (*order)(i) ); + train.col(i) = input.col( (*order)(i) ); } if (trainSize < input.n_cols) { for (size_t i = trainSize; i < input.n_cols; ++i) - testData.col(i - trainSize) = input.col( (*order)(i) ); + test.col(i - trainSize) = input.col( (*order)(i) ); } } + // Spliting only. else { if (trainSize > 0) - trainData = input.cols(0, trainSize - 1); + train = input.cols(0, trainSize - 1); if (trainSize < input.n_cols) - testData = input.cols(trainSize, input.n_cols - 1); + test = input.cols(trainSize, input.n_cols - 1); } } @@ -253,7 +261,7 @@ void Split(const arma::Mat& input, const double testRatio, const bool shuffleData = true) { - if(shuffleData) + if (shuffleData) { arma::uvec order = arma::shuffle(arma::linspace(0, input.n_cols - 1, input.n_cols)); @@ -297,7 +305,7 @@ void Split(const arma::Mat& input, const double testRatio, const bool shuffleData = true) { - if(shuffleData) + if (shuffleData) { arma::uvec order = arma::shuffle(arma::linspace(0, input.n_cols - 1, input.n_cols)); @@ -447,7 +455,7 @@ void Split(const FieldType& input, const double testRatio, const bool shuffleData = true) { - if(shuffleData) + if (shuffleData) { arma::uvec order = arma::shuffle(arma::linspace(0, input.n_cols - 1, input.n_cols)); @@ -499,7 +507,7 @@ void Split(const FieldType& input, const double testRatio, const bool shuffleData = true) { - if(shuffleData) + if (shuffleData) { arma::uvec order = arma::shuffle(arma::linspace(0, input.n_cols - 1, input.n_cols)); From 43760f7aa36163d11d90a623b61cd0a244de6f3c Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Wed, 10 Mar 2021 11:43:45 +0100 Subject: [PATCH 243/253] Remove the coverage badge Signed-off-by: Omar Shrit --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index bb8ba1be6c..84eb8260b4 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ src="https://cdn.rawgit.com/mlpack/mlpack.org/e7d36ed8/mlpack-black.svg" style=" From bd8a5e44c08b6a7b68e79ab8d1155946ab69abfd Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Wed, 10 Mar 2021 22:35:39 +0100 Subject: [PATCH 244/253] Remove appveyor, no longer used Signed-off-by: Omar Shrit --- .appveyor.yml | 219 -------------------------------------------------- 1 file changed, 219 deletions(-) delete mode 100644 .appveyor.yml diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 722a597468..0000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,219 +0,0 @@ -clone_depth: 10 - -environment: - BOOST_MATH : "C:/projects/mlpack/\ - boost_math_c99-vc140.1.60.0.0/lib/native/address-model-64/lib/*.*" - BOOST_RANDOM : "C:/projects/mlpack/\ - boost_random-vc140.1.60.0.0/lib/native/address-model-64/lib/*.*" - ARMADILLO_DOWNLOAD : "https://data.kurg.org/armadillo-8.400.0.tar.xz" - ARMADILLO_LIBRARY : "C:/projects/mlpack/armadillo-8.400.0/\ - build/Debug/armadillo.lib" - BLAS_LIBRARY : "%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/\ - libopenblas.dll.a" - BOOST_INCLUDE : "C:/projects/mlpack/boost.1.60.0.0/lib/native/include" - JENKINS_DOC_DOWNLOAD : "http://ci.mlpack.org/job/mlpack%20-%20doxygen%20\ - build/lastSuccessfulBuild/artifact/build/doc/html/*zip*/html.zip" - JENKINS_DOC : "C:/projects/mlpack/dist/win-installer/jenkinsdoc.zip" - GIT_VERSION_FILE : "C:/projects/mlpack/src/mlpack/core/util/gitversion.hpp" - matrix: - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - VSVER: Visual Studio 16 2019 - MSBUILD: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe - -# We have removed the VS studio 15 2017 build since it is not possible to complete -# or finish the build due to the `compiler out of heap space issues`. -# Therefore, in the meanwhile, we are only doing the installation for VS 16 2019. - -configuration: Release - -os: Visual Studio 2019 - -install: - - ps: nuget install boost -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0 - - ps: > - nuget install boost_random-vc140 - -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0 - - ps: > - nuget install boost_math_c99-vc140 - -o "${env:APPVEYOR_BUILD_FOLDER}" -Version 1.60.0 - - ps: > - nuget install unofficial-flayan-cereal - -o "${env:APPVEYOR_BUILD_FOLDER}" - - ps: nuget install OpenBLAS -o "${env:APPVEYOR_BUILD_FOLDER}" - - set path=C:\Program Files (x86)\WiX Toolset v3.11\bin;%path% - -build_script: - - mkdir boost_libs - - ps: cp ${env:BOOST_MATH} C:\projects\mlpack\boost_libs\ - - ps: cp ${env:BOOST_RANDOM} C:\projects\mlpack\boost_libs\ - - echo TEST_ARMA is %ARMADILLO_DOWNLOAD% - - > - appveyor DownloadFile %ARMADILLO_DOWNLOAD% - -FileName armadillo.tar.xz - - 7z x armadillo.tar.xz -so -txz | 7z x -si -ttar > nul - - cd armadillo-8.400.0 && mkdir build && cd build - - > - cmake -G "%VSVER%" - -DBLAS_LIBRARY:FILEPATH=%BLAS_LIBRARY% - -DLAPACK_LIBRARY:FILEPATH=%BLAS_LIBRARY% - -DCMAKE_PREFIX:FILEPATH="%APPVEYOR_BUILD_FOLDER%/armadillo" - -DBUILD_SHARED_LIBS=OFF - -DCMAKE_BUILD_TYPE=Release .. - - > - "%MSBUILD%" "C:\projects\mlpack\armadillo-8.400.0\build\armadillo.sln" - /m /verbosity:quiet /p:Configuration=Release;Platform=x64 - - cd C:\projects\mlpack && mkdir build && cd build - - > - cmake -G "%VSVER%" - -DBLAS_LIBRARIES:FILEPATH=%BLAS_LIBRARY% - -DLAPACK_LIBRARIES:FILEPATH=%BLAS_LIBRARY% - -DARMADILLO_INCLUDE_DIR="C:/projects/mlpack/armadillo-8.400.0/include" - -DARMADILLO_LIBRARY:FILEPATH=%ARMADILLO_LIBRARY% - -DCEREAL_INCLUDE_DIR="C:/projects/mlpack/unofficial-flayan-cereal.1.2.2/build/native/include" - -DBOOST_INCLUDEDIR:PATH=%BOOST_INCLUDE% - -DDEBUG=OFF - -DPROFILE=OFF - -DBUILD_PYTHON_BINDINGS=OFF - -DBUILD_GO_BINDINGS=OFF - -DBUILD_R_BINDINGS=OFF - -DBUILD_TESTS=OFF - -DCMAKE_BUILD_TYPE=Release .. - - > - "%MSBUILD%" "C:\projects\mlpack\build\mlpack.sln" - /m /verbosity:minimal /nologo /p:BuildInParallel=true - /p:Configuration=Release;Platform=x64 - - # Zip Artifacts. - - > - 7z a mlpack-windows-no-libs.zip - "%APPVEYOR_BUILD_FOLDER%\build\Release\*.exe" - - > - 7z a mlpack-windows.zip - "%APPVEYOR_BUILD_FOLDER%\build\Release\*.*" - "%APPVEYOR_BUILD_FOLDER%/OpenBLAS.0.2.14.1/lib/native/lib/x64/*.*" - - # Pulling documentation for the installer. - - ps: > - try{(new-object net.webclient).DownloadFile(${env:JENKINS_DOC_DOWNLOAD}, - 'C:\projects\mlpack\dist\win-installer\jenkinsdoc.zip')} - catch{Write-Output "Unable to pull jenkins doc, skipping!"} - - ps: > - try{(Add-Type -AssemblyName System.IO.Compression.FileSystem); - [System.IO.Compression.ZipFile]::ExtractToDirectory(${env:JENKINS_DOC}, - 'C:\projects\mlpack\dist\win-installer\staging\doc')} - catch{Write-Output "Unable to add doc to installer, skipping!"} - - # Preparing installer staging. - - cd C:\projects\mlpack\dist\win-installer\staging && mkdir lib - - ps: > - cp C:\projects\mlpack\build\Release\*.lib - C:\projects\mlpack\dist\win-installer\staging\lib\ - - ps: > - cp C:\projects\mlpack\build\Release\*.exp - C:\projects\mlpack\dist\win-installer\staging\lib\ - - ps: > - cp C:\projects\mlpack\build\Release\*.dll - C:\projects\mlpack\dist\win-installer\staging\ - - ps: > - cp C:\projects\mlpack\build\Release\*.exe - C:\projects\mlpack\dist\win-installer\staging\ - - ps: > - cp C:\projects\mlpack\OpenBLAS.0.2.14.1\lib\native\bin\x64\*.dll - C:\projects\mlpack\dist\win-installer\staging\ - - ps: > - cp C:\projects\mlpack\build\include\mlpack - C:\projects\mlpack\dist\win-installer\staging -recurse - - ps: > - cp C:\projects\mlpack\doc\examples - C:\projects\mlpack\dist\win-installer\staging -recurse - - ps: > - cp C:\projects\mlpack\src\mlpack\tests\data\german.csv - C:\projects\mlpack\dist\win-installer\staging\examples\sample-ml-app\sample-ml-app\data\ - - # Checking current gitversion or mlpack version. - - ps: > - $ver = (Get-Content - "${env:APPVEYOR_BUILD_FOLDER}\src\mlpack\core\util\version.hpp" | - where {$_ -like "*MLPACK_VERSION*"}); - $env:MLPACK_VERSION += $ver[0].substring($ver[0].length - 1, 1) + '.'; - $env:MLPACK_VERSION += $ver[1].substring($ver[1].length - 1, 1) + '.'; - $env:MLPACK_VERSION += $ver[2].substring($ver[2].length - 1, 1); - - if (Test-Path ${env:GIT_VERSION_FILE}) - { - $ver = (Get-Content ${env:GIT_VERSION_FILE}); - $env:INSTALL_VERSION = $ver.Split('"')[1].Split(' ')[1]; - } - else - { - $env:INSTALL_VERSION = $env:MLPACK_VERSION; - } - - echo INSTALL_VERSION is %INSTALL_VERSION% - - # Building MSI installer. - - cd C:\projects\mlpack\dist\win-installer\mlpack-win-installer - - > - heat dir ..\staging - -cg HeatGenerated - -dr INSTALLFOLDER - -sreg - -srd - -var var.HarvestPath - -ag - -sfrag - -out HeatGeneratedFileList.wxs - - > - candle -dHarvestPath=..\staging - -dConfiguration=Release - -dOutDir=bin\x64\Release\ - -dPlatform=x64 - -dProjectDir=. - -dProjectExt=.wixproj - -dProjectFileName=mlpack-win-installer.wixproj - -dProjectName=mlpack-win-installer - -dProjectPath=mlpack-win-installer.wixproj - -dTargetDir=.\bin\x64\Release\ - -dTargetExt=.msi - -dTargetFileName=mlpack-windows.msi - -dTargetName=mlpack-windows - -dTargetPath=.\bin\x64\Release\mlpack-windows.msi - -out obj\x64\Release\ - -arch x64 - -ext "C:\Program Files (x86)\WiX Toolset v3.11\bin\\WixUIExtension.dll" - Product.wxs HeatGeneratedFileList.wxs - - > - light -out .\bin\x64\Release\mlpack-%INSTALL_VERSION%.msi - -pdbout .\bin\x64\Release\mlpack-windows.wixpdb - -cultures:null - -loc mlpack-localization.wxl - -ext "C:\Program Files (x86)\WiX Toolset v3.11\bin\\WixUIExtension.dll" - -contentsfile - obj\x64\Release\mlpack-win-installer.wixproj.BindContentsFileListnull.txt - -outputsfile - obj\x64\Release\mlpack-win-installer.wixproj.BindOutputsFileListnull.txt - -builtoutputsfile - obj\x64\Release\mlpack-win-installer.wixproj.BindBuiltOutputsFileListnull.txt - -wixprojectfile - mlpack-win-installer.wixproj - obj\x64\Release\Product.wixobj - obj\x64\Release\HeatGeneratedFileList.wixobj - -artifacts: - - path: 'build\*.zip' - name: mlpack-windows-zip - - - path: 'dist\win-installer\mlpack-win-installer\bin\x64\Release\*.msi' - name: mlpack-windows-installer - -notifications: -- provider: Email - to: - - mlpack-git@lists.mlpack.org - on_build_success: true - on_build_failure: true - on_build_status_changed: true - -cache: - - packages -> **\packages.config - - armadillo.tar.xz -> appveyor.yaml - From d384a83c3dbc6448320ba4ef5aa07d90ca356d67 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Thu, 11 Mar 2021 07:31:15 +0530 Subject: [PATCH 245/253] Update src/mlpack/tests/split_data_test.cpp Co-authored-by: Marcus Edel --- src/mlpack/tests/split_data_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/split_data_test.cpp b/src/mlpack/tests/split_data_test.cpp index 8d2b5e470e..075347bd3a 100644 --- a/src/mlpack/tests/split_data_test.cpp +++ b/src/mlpack/tests/split_data_test.cpp @@ -388,7 +388,7 @@ TEST_CASE("SplitMatrixLabeledData", "[SplitDataTest]") CheckMatrices(labels, labels_concat); } -/* +/** * Split with input of type field and label of type field. */ TEST_CASE("SplitLabeledDataResultField", "[SplitDataTest]") From 9339e42c1f51e3502a45c58b840890ab335c82a8 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Thu, 11 Mar 2021 07:31:33 +0530 Subject: [PATCH 246/253] Update src/mlpack/tests/test_catch_tools.hpp Co-authored-by: Marcus Edel --- src/mlpack/tests/test_catch_tools.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/tests/test_catch_tools.hpp b/src/mlpack/tests/test_catch_tools.hpp index dfd0577b19..879cac8b49 100644 --- a/src/mlpack/tests/test_catch_tools.hpp +++ b/src/mlpack/tests/test_catch_tools.hpp @@ -53,7 +53,7 @@ inline void CheckMatrices(const arma::Mat& a, template ::value>> -// Check the values of two field types +// Check the values of two field types. inline void CheckFields(const FieldType& a, const FieldType& b) { From 3c67db795d83c59f80634af2549ff66dd0e07546 Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Fri, 12 Mar 2021 10:28:41 +0100 Subject: [PATCH 247/253] Remove doc and config related to coverage Signed-off-by: Omar Shrit --- CMake/mlpack_coverage.in | 135 --------------------------------------- doc/guide/build.hpp | 2 - 2 files changed, 137 deletions(-) delete mode 100755 CMake/mlpack_coverage.in diff --git a/CMake/mlpack_coverage.in b/CMake/mlpack_coverage.in deleted file mode 100755 index b67ecf3cc1..0000000000 --- a/CMake/mlpack_coverage.in +++ /dev/null @@ -1,135 +0,0 @@ -#!/bin/bash -# This script gets the test coverage for mlpack_test. -test_case="ALL" -gcov_loc="" -token="" -clean=true -current_log_file=`date +'%Y.%h.%d:%H:%M:%S-coverage.log'` -current_coverage_file=`date +'%Y.%h.%d:%H:%M:%S-coverage.info'` -max_cov_count=50000 - -# default directories -root_dir="../" - -# Extract arguments. -for i in "$@" -do -case $i in - -h|--help) - echo "Usage: mlpack_coverage --help|-h" - echo " mlpack_coverage [-r=test_suite] [-g=gcov_tool_location]" - echo " [--token=coveralls_token]" - echo "Optional parameters:" - echo " -n|--no_test Do not run test before coverage computation" - echo " -r|--run_test Run tests with specific test suite" - echo " --no_clean Do not remove existing gcda file" - echo " -g|--gcov_tool_location Gcov location if not default" - echo " -t|--token Upload to coveralls with given token" - echo " --max_cov_count Max line coverage count (default 50000)" - echo " --root_dir Set the root directory from which gcov will be called. (default ../)" - exit 0 - shift - ;; - -n|--no_test) - test_case="" - shift - ;; - -r=*|--run_test=*) - test_case="${i#*=}" - shift # past argument=value - ;; - --no_clean) - clean=false - shift - ;; - -g=*|--gcov_tool_location=*) - gcov_loc="${i#*=}" - shift # past argument=value - ;; - -t=*|--token=*) - token="${i#*=}" - shift # past argument=value - ;; - --max_cov_count) - max_cov_count="${i#*=}" - shift - ;; - --root_dir=*) - root_dir="${i#*=}" - shift - ;; - *) - # unknown option - ;; -esac -done - -if [ "$clean" = true ]; then - echo "Deleting existing coverage data..." - find ./ -name "*.gcda" -type f -delete -fi - -# Initial pass. -echo "Generating primary coverage report." -[[ -d ./coveragehistory/ ]] || mkdir coveragehistory -lcov -b . -c -i -d ./ -o .coverage.wtest.base > ./coveragehistory/$current_log_file - -# Run the tests. -if [ "$test_case" = "ALL" ]; then - echo "Running all the tests..." - "@CMAKE_BINARY_DIR@"/bin/mlpack_test -elif ! [ "$test_case" = "" ]; then - echo "Running test suite: $test_case" - "@CMAKE_BINARY_DIR@"/bin/mlpack_test --run_test=$test_case -fi - -# Generate coverage based on executed tests. -echo "Computing coverage..." -if [ "$gcov_loc" = "" ]; -then lcov -b . -c -d ./ -o .coverage.wtest.run >> ./coveragehistory/$current_log_file -else - lcov -b . -c -d ./ -o .coverage.wtest.run --gcov-tool=$gcov_loc >> ./coveragehistory/$current_log_file -fi - -echo "Filtering coverage files..." -# Clear negative entries in coverage file -sed -E 's/-([0-9]+)/$max_cov_count/g' -i .coverage.wtest.run -# Merge coverage tracefiles. -lcov -a .coverage.wtest.base -a .coverage.wtest.run -o .coverage.total >> ./coveragehistory/$current_log_file - -# Filtering, extracting project files. -lcov -e .coverage.total "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/*" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file - -# Filtering, removing test-files and main.cpp. -lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/*/*_main.cpp" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file -lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/tests/*" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file - -# Remove untestable files. -lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/core/util/gitversion.hpp" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file -lcov -r .coverage.total.filtered "@CMAKE_CURRENT_SOURCE_DIR@/src/mlpack/core/util/arma_config.hpp" -o .coverage.total.filtered >> ./coveragehistory/$current_log_file - -# Extra: Replace /build/ with /src/ to unify directories. -cat .coverage.total.filtered > .coverage.total - -# Extra: Clear up previous data, create html folder. -if [[ -d ./coverage/ ]] ; then - rm -rf ./coverage/* -else - mkdir coverage -fi - -# Step 9: Generate webpage. -genhtml -o ./coverage/ .coverage.total - -# Extra: Preserve coverage file in coveragehistory folder. -coverage_file=$current_coverage_file -cp .coverage.total ./coveragehistory/$current_coverage_file - -# Clean temporary coverage files. -#rm .coverage.* - -# Upload the result to coveralls if token is provided. -if ! [ "$token" = "" ]; then - cpp-coveralls -n -r $root_dir -b $root_dir -l ./coveragehistory/$current_coverage_file -t "$token" --max-cov-count $max_cov_count -fi - diff --git a/doc/guide/build.hpp b/doc/guide/build.hpp index 9996f5132d..9356f725cc 100644 --- a/doc/guide/build.hpp +++ b/doc/guide/build.hpp @@ -191,8 +191,6 @@ The full list of options mlpack allows: - DOWNLOAD_ENSMALLEN=(ON/OFF): If ensmallen is not found, download it (default ON) - DOWNLOAD_STB_IMAGE=(ON/OFF): If STB is not found, download it (default ON) - - BUILD_WITH_COVERAGE=(ON/OFF): Build with support for code coverage tools - (gcc only) (default OFF) - PYTHON_EXECUTABLE=(/path/to/python_version): Path to specific Python executable - PYTHON_INSTALL_PREFIX=(/path/to/python/): Path to root of Python installation - JULIA_EXECUTABLE=(/path/to/julia): Path to specific Julia executable From a41fc26651c2696ca75758ff186dc58ab006cff2 Mon Sep 17 00:00:00 2001 From: Omar Shrit Date: Fri, 12 Mar 2021 11:13:32 +0100 Subject: [PATCH 248/253] Remove addition t from the word test I do think this is a typo, unless if this is intended Signed-off-by: Omar Shrit --- src/mlpack/tests/tree_traits_test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mlpack/tests/tree_traits_test.cpp b/src/mlpack/tests/tree_traits_test.cpp index caa642c71f..e7c95d1cd4 100644 --- a/src/mlpack/tests/tree_traits_test.cpp +++ b/src/mlpack/tests/tree_traits_test.cpp @@ -31,7 +31,7 @@ using namespace mlpack::metric; // weird things and will cause bizarre problems. // Test the defaults. -TEST_CASE("DefaultsTraitsTest", "[TreeTraitsTestt]") +TEST_CASE("DefaultsTraitsTest", "[TreeTraitsTest]") { // An irrelevant non-tree type class is used here so that the default // implementation of TreeTraits is chosen. @@ -48,7 +48,7 @@ TEST_CASE("DefaultsTraitsTest", "[TreeTraitsTestt]") } // Test the binary space tree traits. -TEST_CASE("BinarySpaceTreeTraitsTest", "[TreeTraitsTestt]") +TEST_CASE("BinarySpaceTreeTraitsTest", "[TreeTraitsTest]") { typedef BinarySpaceTree> TreeType; @@ -74,7 +74,7 @@ TEST_CASE("BinarySpaceTreeTraitsTest", "[TreeTraitsTestt]") } // Test the cover tree traits. -TEST_CASE("CoverTreeTraitsTest", "[TreeTraitsTestt]") +TEST_CASE("CoverTreeTraitsTest", "[TreeTraitsTest]") { // Children may be overlapping. bool b = TreeTraits>::HasOverlappingChildren; From 10ea5a0706c6ddae4f55f30f7d93c216fe279f01 Mon Sep 17 00:00:00 2001 From: Nippun Sharma <53967069+NippunSharma@users.noreply.github.com> Date: Fri, 12 Mar 2021 19:40:24 +0530 Subject: [PATCH 249/253] remove_matlab_1 --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ecd13769c..1a6e1e5bd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,6 @@ include(CMake/CheckHash.cmake) option(DEBUG "Compile with debugging information." OFF) option(PROFILE "Compile with profiling information." OFF) option(ARMA_EXTRA_DEBUG "Compile with extra Armadillo debugging symbols." OFF) -option(MATLAB_BINDINGS "Compile MATLAB bindings if MATLAB is found." OFF) option(TEST_VERBOSE "Run test cases with verbose output." OFF) option(BUILD_TESTS "Build tests." ON) option(BUILD_CLI_EXECUTABLES "Build command-line executables." ON) From 14996379dbb4150d6e61824c03ce5f22865a109a Mon Sep 17 00:00:00 2001 From: NippunSharma Date: Fri, 12 Mar 2021 19:49:53 +0530 Subject: [PATCH 250/253] removed_matlab_2 --- CMake/FindMatlabMex.cmake | 110 -------------------------------------- 1 file changed, 110 deletions(-) delete mode 100644 CMake/FindMatlabMex.cmake diff --git a/CMake/FindMatlabMex.cmake b/CMake/FindMatlabMex.cmake deleted file mode 100644 index 43b342c4a5..0000000000 --- a/CMake/FindMatlabMex.cmake +++ /dev/null @@ -1,110 +0,0 @@ -# This module looks for mex, the MATLAB compiler. -# The following variables are defined when the script completes: -# MATLAB_MEX: location of mex compiler -# MATLAB_ROOT: root of MATLAB installation -# MATLABMEX_FOUND: 0 if not found, 1 if found - -set(MATLABMEX_FOUND 0) - -if(WIN32) - # This is untested but taken from the older FindMatlab.cmake script as well as - # the modifications by Ramon Casero and Tom Doel for Gerardus. - - # Search for a version of Matlab available, starting from the most modern one - # to older versions. - foreach(MATVER "7.20" "7.19" "7.18" "7.17" "7.16" "7.15" "7.14" "7.13" "7.12" -"7.11" "7.10" "7.9" "7.8" "7.7" "7.6" "7.5" "7.4") - if((NOT DEFINED MATLAB_ROOT) - OR ("${MATLAB_ROOT}" STREQUAL "") - OR ("${MATLAB_ROOT}" STREQUAL "/registry")) - get_filename_component(MATLAB_ROOT - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${MATVER};MATLABROOT]" - ABSOLUTE) - set(MATLAB_VERSION ${MATVER}) - endif() - OR ("${MATLAB_ROOT}" STREQUAL "") - OR ("${MATLAB_ROOT}" STREQUAL "/registry")) - endforeach() - - find_program(MATLAB_MEX - mex - ${MATLAB_ROOT}/bin - ) -else() - # Check if this is a Mac. - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - # This code is untested but taken from the older FindMatlab.cmake script as - # well as the modifications by Ramon Casero and Tom Doel for Gerardus. - - set(LIBRARY_EXTENSION .dylib) - - # If this is a Mac and the attempts to find MATLAB_ROOT have so far failed,~ - # we look in the applications folder - if((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL "")) - - # Search for a version of Matlab available, starting from the most modern - # one to older versions - foreach(MATVER "R2013b" "R2013a" "R2012b" "R2012a" "R2011b" "R2011a" -"R2010b" "R2010a" "R2009b" "R2009a" "R2008b") - if((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL "")) - if(EXISTS /Applications/MATLAB_${MATVER}.app) - set(MATLAB_ROOT /Applications/MATLAB_${MATVER}.app) - - endif() - endif() - endforeach() - - endif() - - find_program(MATLAB_MEX - mex - PATHS - ${MATLAB_ROOT}/bin - ) - - else() - # On a Linux system. The goal is to find MATLAB_ROOT. - set(LIBRARY_EXTENSION .so) - - find_program(MATLAB_MEX_POSSIBLE_LINK - mex - PATHS - ${MATLAB_ROOT}/bin - /opt/matlab/bin - /usr/local/matlab/bin - $ENV{HOME}/matlab/bin - # Now all the versions - /opt/matlab/[rR]20[0-9][0-9][abAB]/bin - /usr/local/matlab/[rR]20[0-9][0-9][abAB]/bin - /opt/matlab-[rR]20[0-9][0-9][abAB]/bin - /opt/matlab_[rR]20[0-9][0-9][abAB]/bin - /usr/local/matlab-[rR]20[0-9][0-9][abAB]/bin - /usr/local/matlab_[rR]20[0-9][0-9][abAB]/bin - $ENV{HOME}/matlab/[rR]20[0-9][0-9][abAB]/bin - $ENV{HOME}/matlab-[rR]20[0-9][0-9][abAB]/bin - $ENV{HOME}/matlab_[rR]20[0-9][0-9][abAB]/bin - ) - - get_filename_component(MATLAB_MEX "${MATLAB_MEX_POSSIBLE_LINK}" REALPATH) - get_filename_component(MATLAB_BIN_ROOT "${MATLAB_MEX}" PATH) - # Strip ./bin/. - get_filename_component(MATLAB_ROOT "${MATLAB_BIN_ROOT}" PATH) - endif() -endif() - -if(NOT EXISTS "${MATLAB_MEX}" AND "${MatlabMex_FIND_REQUIRED}") - message(FATAL_ERROR "Could not find MATLAB mex compiler; try specifying MATLAB_ROOT.") -else() - if(EXISTS "${MATLAB_MEX}") - message(STATUS "Found MATLAB mex compiler: ${MATLAB_MEX}") - message(STATUS "MATLAB root: ${MATLAB_ROOT}") - set(MATLABMEX_FOUND 1) - endif() -endif() - -mark_as_advanced( - MATLAB_MEX - MATLABMEX_FOUND - MATLAB_ROOT -) - From 3801b16e13d1f8a503e2f618a9d0f317142e4e1f Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Fri, 12 Mar 2021 22:19:43 +0530 Subject: [PATCH 251/253] Removed pointer from default function argument --- src/mlpack/core/data/split_data.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index a97058d29b..12f3b0efec 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -28,7 +28,7 @@ void SplitHelper(const InputType& input, InputType& train, InputType& test, const double testRatio, - const arma::uvec* order = nullptr) + const arma::uvec& order = arma::uvec()) { const size_t testSize = static_cast(input.n_cols * testRatio); const size_t trainSize = input.n_cols - testSize; @@ -38,17 +38,17 @@ void SplitHelper(const InputType& input, test.set_size(input.n_rows, testSize); // Shuffling and spliting simultaneously. - if (order) + if (!order.is_empty()) { if (trainSize > 0) { for (size_t i = 0; i < trainSize; ++i) - train.col(i) = input.col( (*order)(i) ); + train.col(i) = input.col(order(i)); } if (trainSize < input.n_cols) { for (size_t i = trainSize; i < input.n_cols; ++i) - test.col(i - trainSize) = input.col( (*order)(i) ); + test.col(i - trainSize) = input.col(order(i)); } } // Spliting only. @@ -265,8 +265,8 @@ void Split(const arma::Mat& input, { arma::uvec order = arma::shuffle(arma::linspace(0, input.n_cols - 1, input.n_cols)); - SplitHelper(input, trainData, testData, testRatio, &order); - SplitHelper(inputLabel, trainLabel, testLabel, testRatio, &order); + SplitHelper(input, trainData, testData, testRatio, order); + SplitHelper(inputLabel, trainLabel, testLabel, testRatio, order); } else { @@ -309,7 +309,7 @@ void Split(const arma::Mat& input, { arma::uvec order = arma::shuffle(arma::linspace(0, input.n_cols - 1, input.n_cols)); - SplitHelper(input, trainData, testData, testRatio, &order); + SplitHelper(input, trainData, testData, testRatio, order); } else { @@ -459,8 +459,8 @@ void Split(const FieldType& input, { arma::uvec order = arma::shuffle(arma::linspace(0, input.n_cols - 1, input.n_cols)); - SplitHelper(input, trainData, testData, testRatio, &order); - SplitHelper(inputLabel, trainLabel, testLabel, testRatio, &order); + SplitHelper(input, trainData, testData, testRatio, order); + SplitHelper(inputLabel, trainLabel, testLabel, testRatio, order); } else { @@ -511,7 +511,7 @@ void Split(const FieldType& input, { arma::uvec order = arma::shuffle(arma::linspace(0, input.n_cols - 1, input.n_cols)); - SplitHelper(input, trainData, testData, testRatio, &order); + SplitHelper(input, trainData, testData, testRatio, order); } else { From 6ebe71864b46383a79fd46f4fbb194118e11d26d Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Sat, 13 Mar 2021 08:55:30 +0530 Subject: [PATCH 252/253] Update src/mlpack/core/data/split_data.hpp Co-authored-by: Ryan Curtin --- src/mlpack/core/data/split_data.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 12f3b0efec..6347d68a98 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -414,7 +414,7 @@ Split(const arma::Mat& input, * output parameters given (trainData, testData, trainLabel, and testLabel). * * The input dataset must be of type arma::field. It should have the shape - - * (n_rows = 1, n_cols = Number of samples, n_slices = 1) + * (n_rows = 1, n_cols = Number of samples, n_slices = 1). * * NOTE: Here FieldType could be arma::field or arma::field * From 4dd32a662180ba1b6895dce01809c665dc64f104 Mon Sep 17 00:00:00 2001 From: Rishabh Garg <56191449+RishabhGarg108@users.noreply.github.com> Date: Sat, 13 Mar 2021 08:55:43 +0530 Subject: [PATCH 253/253] Update src/mlpack/core/data/split_data.hpp Co-authored-by: Ryan Curtin --- src/mlpack/core/data/split_data.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mlpack/core/data/split_data.hpp b/src/mlpack/core/data/split_data.hpp index 6347d68a98..f9b0c1558f 100644 --- a/src/mlpack/core/data/split_data.hpp +++ b/src/mlpack/core/data/split_data.hpp @@ -416,7 +416,7 @@ Split(const arma::Mat& input, * The input dataset must be of type arma::field. It should have the shape - * (n_rows = 1, n_cols = Number of samples, n_slices = 1). * - * NOTE: Here FieldType could be arma::field or arma::field + * NOTE: Here FieldType could be arma::field or arma::field. * * @code * arma::field input = loadData();

Jenkins - Coveralls License NumFOCUS