Adapt code to new LinearRegression<> template parameter.

This commit is contained in:
Ryan Curtin
2023-11-30 10:36:57 -05:00
parent d32087c046
commit 20fbb6abf0
11 changed files with 95 additions and 75 deletions
@@ -31,7 +31,7 @@ class RegressionDistribution
{
private:
//! Regression function for representing conditional mean.
LinearRegression rf;
LinearRegression<> rf;
//! Error distribution.
GaussianDistribution err;
@@ -81,9 +81,9 @@ class RegressionDistribution
}
//! Return regression function.
const LinearRegression& Rf() const { return rf; }
const LinearRegression<>& Rf() const { return rf; }
//! Modify regression function.
LinearRegression& Rf() { return rf; }
LinearRegression<>& Rf() { return rf; }
//! Return error distribution.
const GaussianDistribution& Err() const { return err; }
@@ -24,7 +24,7 @@ namespace mlpack {
*/
inline void RegressionDistribution::Train(const arma::mat& observations)
{
LinearRegression lr(observations.rows(1, observations.n_rows - 1),
LinearRegression<> lr(observations.rows(1, observations.n_rows - 1),
arma::rowvec(observations.row(0)), 0, true);
rf = lr;
arma::rowvec fitted;
@@ -46,7 +46,7 @@ inline void RegressionDistribution::Train(const arma::mat& observations,
inline void RegressionDistribution::Train(const arma::mat& observations,
const arma::rowvec& weights)
{
LinearRegression lr(observations.rows(1, observations.n_rows - 1),
LinearRegression<> lr(observations.rows(1, observations.n_rows - 1),
arma::rowvec(observations.row(0)), weights, 0, true);
rf = lr;
arma::rowvec fitted;
@@ -95,9 +95,9 @@ PARAM_ROW_IN("training_responses", "Optional vector containing y "
"(responses). If not given, the responses are assumed to be the last row "
"of the input file.", "r");
PARAM_MODEL_IN(LinearRegression, "input_model", "Existing LinearRegression "
PARAM_MODEL_IN(LinearRegression<>, "input_model", "Existing LinearRegression "
"model to use.", "m");
PARAM_MODEL_OUT(LinearRegression, "output_model", "Output LinearRegression "
PARAM_MODEL_OUT(LinearRegression<>, "output_model", "Output LinearRegression "
"model.", "M");
PARAM_MATRIX_IN("test", "Matrix containing X' (test regressors).", "T");
@@ -120,7 +120,7 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& timer)
mat regressors;
rowvec responses;
LinearRegression* lr;
LinearRegression<>* lr;
const bool computeModel = !params.Has("input_model");
const bool computePrediction = params.Has("test");
@@ -172,14 +172,14 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& timer)
}
timer.Start("regression");
lr = new LinearRegression(regressors, responses, lambda);
lr = new LinearRegression<>(regressors, responses, lambda);
timer.Stop("regression");
}
else
{
// A model file was passed in, so load it.
timer.Start("load_model");
lr = params.Get<LinearRegression*>("input_model");
lr = params.Get<LinearRegression<>*>("input_model");
timer.Stop("load_model");
}
@@ -221,5 +221,5 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& timer)
}
// Save the model if needed.
params.Get<LinearRegression*>("output_model") = lr;
params.Get<LinearRegression<>*>("output_model") = lr;
}
@@ -37,8 +37,8 @@ BINDING_LONG_DESC("");
BINDING_EXAMPLE(
CALL_METHOD("model", "predict", "test", "X_test"));
PARAM_MODEL_IN_REQ(LinearRegression, "input_model", "Existing LinearRegression "
"model to use.", "m");
PARAM_MODEL_IN_REQ(LinearRegression<>, "input_model", "Existing "
"LinearRegression model to use.", "m");
PARAM_MATRIX_IN_REQ("test", "Matrix containing X' (test regressors).", "T");
@@ -50,7 +50,7 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& timer)
{
// A model file was passed in, so load it.
timer.Start("load_model");
LinearRegression* lr = params.Get<LinearRegression*>("input_model");
LinearRegression<>* lr = params.Get<LinearRegression<>*>("input_model");
timer.Stop("load_model");
// Cache the output of GetPrintable before we std::move() the test
@@ -61,7 +61,7 @@ PARAM_ROW_IN("training_responses", "Optional vector containing y "
"(responses). If not given, the responses are assumed to be the last row "
"of the input file.", "r");
PARAM_MODEL_OUT(LinearRegression, "output_model", "Output LinearRegression "
PARAM_MODEL_OUT(LinearRegression<>, "output_model", "Output LinearRegression "
"model.", "M");
PARAM_DOUBLE_IN("lambda", "Tikhonov regularization for ridge regression. If 0,"
@@ -108,9 +108,10 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& timer)
Log::Fatal << "Regressors and Responses must have the same number of data points!" << endl;
timer.Start("regression");
LinearRegression* lr = new LinearRegression(regressors, responses, lambda);
LinearRegression<>* lr = new LinearRegression<>(regressors, responses,
lambda);
timer.Stop("regression");
// Save the model if needed.
params.Get<LinearRegression*>("output_model") = lr;
params.Get<LinearRegression<>*>("output_model") = lr;
}
@@ -174,7 +174,7 @@ TEST_CASE("EqualtoRidge", "[BayesianLinearRegressionTest]")
BayesianLinearRegression blr(false, false);
blr.Train(matX, y);
LinearRegression ridge(matX, y, blr.Alpha() / blr.Beta(), false);
LinearRegression<> ridge(matX, y, blr.Alpha() / blr.Beta(), false);
blr.Predict(matX, blrPred);
ridge.Predict(matX, ridgePred);
+13 -13
View File
@@ -207,7 +207,7 @@ TEST_CASE("MSETest", "[CVTest]")
arma::mat trainingData("0 1");
arma::rowvec trainingResponses("-1 0");
LinearRegression lr(trainingData, trainingResponses);
LinearRegression<> lr(trainingData, trainingResponses);
// Making three responses that differ from the correct ones by 0, 1, and 2
// respectively
@@ -229,7 +229,7 @@ TEST_CASE("R2ScoreTest", "[CVTest]")
arma::mat trainingData("0 1");
arma::rowvec trainingResponses("-1 0");
LinearRegression lr(trainingData, trainingResponses);
LinearRegression<> lr(trainingData, trainingResponses);
// Making five responses that are the output of regression function f(x)
// with some responses having a slight deviation of 0.005.
@@ -256,7 +256,7 @@ TEST_CASE("AdjR2ScoreTest", "[CVTest]")
arma::rowvec Y;
Y = { 3, 5, 7, 9, 11, 13 };
LinearRegression lr(X, Y);
LinearRegression<> lr(X, Y);
// Theoretically Adjusted R squared should be equal 1
double expAdjR2 = 1;
@@ -309,7 +309,7 @@ void CheckPredictionsType()
*/
TEST_CASE("PredictionsTypeTest", "[CVTest]")
{
CheckPredictionsType<LinearRegression, arma::rowvec>();
CheckPredictionsType<LinearRegression<>, arma::rowvec>();
// CheckPredictionsType<FFN<>, arma::mat>();
CheckPredictionsType<LogisticRegression<>, arma::Row<size_t>>();
@@ -328,7 +328,7 @@ TEST_CASE("PredictionsTypeTest", "[CVTest]")
*/
TEST_CASE("SupportsWeightsTest", "[CVTest]")
{
static_assert(MetaInfoExtractor<LinearRegression>::SupportsWeights,
static_assert(MetaInfoExtractor<LinearRegression<>>::SupportsWeights,
"Value should be true");
static_assert(MetaInfoExtractor<DecisionTree<>>::SupportsWeights,
"Value should be true");
@@ -360,7 +360,7 @@ void CheckWeightsType()
*/
TEST_CASE("WeightsTypeTest", "[CVTest]")
{
CheckWeightsType<LinearRegression, arma::rowvec>();
CheckWeightsType<LinearRegression<>, arma::rowvec>();
CheckWeightsType<DecisionTree<>, arma::rowvec>();
CheckWeightsType<DecisionTree<>, arma::Row<float>, arma::mat,
arma::Row<size_t>, arma::Row<float>>();
@@ -374,7 +374,7 @@ TEST_CASE("TakesDatasetInfoTest", "[CVTest]")
{
static_assert(MetaInfoExtractor<DecisionTree<>>::TakesDatasetInfo,
"Value should be true");
static_assert(!MetaInfoExtractor<LinearRegression>::TakesDatasetInfo,
static_assert(!MetaInfoExtractor<LinearRegression<>>::TakesDatasetInfo,
"Value should be false");
static_assert(!MetaInfoExtractor<SoftmaxRegression>::TakesDatasetInfo,
"Value should be false");
@@ -390,7 +390,7 @@ TEST_CASE("TakesNumClassesTest", "[CVTest]")
"Value should be true");
static_assert(MetaInfoExtractor<SoftmaxRegression>::TakesNumClasses,
"Value should be true");
static_assert(!MetaInfoExtractor<LinearRegression>::TakesNumClasses,
static_assert(!MetaInfoExtractor<LinearRegression<>>::TakesNumClasses,
"Value should be false");
static_assert(!MetaInfoExtractor<LARS>::TakesNumClasses,
"Value should be false");
@@ -425,7 +425,7 @@ TEST_CASE("SimpleCVMSETest", "[CVTest]")
double expectedMSE = (0 * 0 + 1 * 1 + 2 * 2) / 3.0;
SimpleCV<LinearRegression, MSE> cv(0.6, data, responses);
SimpleCV<LinearRegression<>, MSE> cv(0.6, data, responses);
REQUIRE(cv.Evaluate() == Approx(expectedMSE).epsilon(1e-7));
@@ -438,7 +438,7 @@ TEST_CASE("SimpleCVMSETest", "[CVTest]")
arma::rowvec weights = arma::join_rows(arma::zeros(noiseData.n_cols).t(),
arma::ones(data.n_cols).t());
SimpleCV<LinearRegression, MSE> weightedCV(0.3, allData, allResponces,
SimpleCV<LinearRegression<>, MSE> weightedCV(0.3, allData, allResponces,
weights);
REQUIRE(weightedCV.Evaluate() == Approx(expectedMSE).epsilon(1e-7));
@@ -446,7 +446,7 @@ TEST_CASE("SimpleCVMSETest", "[CVTest]")
arma::rowvec weights2 = arma::join_rows(arma::zeros(noiseData.n_cols - 1).t(),
arma::ones(data.n_cols + 1).t());
SimpleCV<LinearRegression, MSE> weightedCV2(0.3, allData, allResponces,
SimpleCV<LinearRegression<>, MSE> weightedCV2(0.3, allData, allResponces,
weights2);
REQUIRE(std::abs(weightedCV2.Evaluate() - expectedMSE) > 1e-5);
@@ -543,7 +543,7 @@ TEST_CASE("KFoldCVMSETest", "[CVTest]")
arma::rowvec responses("0 1 1 3");
// 2-fold cross-validation, no shuffling.
KFoldCV<LinearRegression, MSE> cv(2, data, responses, false);
KFoldCV<LinearRegression<>, MSE> cv(2, data, responses, false);
// In each of two validation tests the MSE value should be the same.
double expectedMSE =
@@ -620,7 +620,7 @@ TEST_CASE("KFoldCVWithWeightedLRTest", "[CVTest]")
arma::rowvec responses("1 2 30 40");
arma::rowvec weights("1 1 0 0");
KFoldCV<LinearRegression, MSE> cv(2, arma::join_rows(data, data),
KFoldCV<LinearRegression<>, MSE> cv(2, arma::join_rows(data, data),
arma::join_rows(responses, responses), arma::join_rows(weights, weights),
false);
cv.Evaluate();
+57 -36
View File
@@ -21,25 +21,30 @@ using namespace mlpack;
* Creates two 10x3 random matrices and one 10x1 "results" matrix.
* Finds B in y=BX with one matrix, then predicts against the other.
*/
TEST_CASE("LinearRegressionTestCase", "[LinearRegressionTest]")
TEMPLATE_TEST_CASE("LinearRegressionTestCase", "[LinearRegressionTest]",
arma::fmat, arma::mat)
{
typedef TestType MatType;
typedef arma::Row<typename MatType::elem_type> RowType;
typedef arma::Col<typename MatType::elem_type> ColType;
// Predictors and points are 10x3 matrices.
arma::mat predictors(3, 10);
arma::mat points(3, 10);
MatType predictors(3, 10);
MatType points(3, 10);
// Responses is the "correct" value for each point in predictors and points.
arma::rowvec responses(10);
RowType responses(10);
// The values we get back when we predict for points.
arma::rowvec predictions(10);
RowType predictions(10);
// We'll randomly select some coefficients for the linear response.
arma::vec coeffs;
ColType coeffs;
coeffs.randu(4);
// Now generate each point.
for (size_t row = 0; row < 3; row++)
predictors.row(row) = arma::linspace<arma::rowvec>(0, 9, 10);
predictors.row(row) = arma::linspace<RowType>(0, 9, 10);
points = predictors;
@@ -57,7 +62,7 @@ TEST_CASE("LinearRegressionTestCase", "[LinearRegressionTest]")
dot(coeffs.rows(1, 3), arma::ones<arma::rowvec>(3) * elem);
// Initialize and predict.
LinearRegression lr(predictors, responses);
LinearRegression<MatType> lr(predictors, responses);
lr.Predict(points, predictions);
// Output result and verify we have less than 5% error from "correct" value
@@ -69,16 +74,20 @@ TEST_CASE("LinearRegressionTestCase", "[LinearRegressionTest]")
/**
* Check the functionality of ComputeError().
*/
TEST_CASE("ComputeErrorTest", "[LinearRegressionTest]")
TEMPLATE_TEST_CASE("ComputeErrorTest", "[LinearRegressionTest]", arma::fmat,
arma::mat)
{
arma::mat predictors;
typedef TestType MatType;
typedef arma::Row<typename MatType::elem_type> RowType;
MatType predictors;
predictors = { { 0, 1, 2, 4, 8, 16 },
{ 16, 8, 4, 2, 1, 0 } };
arma::rowvec responses = "0 2 4 3 8 8";
RowType responses = "0 2 4 3 8 8";
// http://www.mlpack.org/trac/ticket/298
// This dataset gives a cost of 1.189500337 (as calculated in Octave).
LinearRegression lr(predictors, responses);
LinearRegression<MatType> lr(predictors, responses);
REQUIRE(lr.ComputeError(predictors, responses) ==
Approx(1.189500337).epsilon(1e-5));
@@ -95,7 +104,7 @@ TEST_CASE("ComputeErrorPerfectFitTest", "[LinearRegressionTest]")
{ 0, 1, 2, 2, 2, 6 } };
arma::rowvec responses = "0 2 4 3 8 8";
LinearRegression lr(predictors, responses);
LinearRegression<> lr(predictors, responses);
REQUIRE(lr.ComputeError(predictors, responses) == Approx(0.0).margin(1e-25));
}
@@ -116,7 +125,7 @@ TEST_CASE("RidgeRegressionTest", "[LinearRegressionTest]")
// invertible. If ridge regression is not working correctly, then the matrix
// will not be invertible and the test should segfault (or something else
// ugly).
LinearRegression lr(data, responses, 0.0001);
LinearRegression<> lr(data, responses, 0.0001);
// Now just make sure that it predicts some more zeros.
arma::rowvec predictedResponses;
@@ -167,7 +176,7 @@ TEST_CASE("RidgeRegressionTestCase", "[LinearRegressionTest]")
dot(coeffs.rows(1, 3), arma::ones<arma::rowvec>(3) * elem);
// Initialize and predict with very small lambda.
LinearRegression lr(predictors, responses, 0.001);
LinearRegression<> lr(predictors, responses, 0.001);
lr.Predict(points, predictions);
// Output result and verify we have less than 5% error from "correct" value
@@ -186,8 +195,8 @@ TEST_CASE("LinearRegressionTrainTest", "[LinearRegressionTest]")
arma::mat dataset = arma::randu<arma::mat>(5, 1000);
arma::rowvec responses = arma::randu<arma::rowvec>(1000);
LinearRegression lr(dataset, responses, 0.3);
LinearRegression lrTrain;
LinearRegression<> lr(dataset, responses, 0.3);
LinearRegression<> lrTrain;
lrTrain.Lambda() = 0.3;
lrTrain.Train(dataset, responses);
@@ -209,8 +218,8 @@ TEST_CASE("LinearRegressionTest", "[LinearRegressionTest]")
arma::rowvec responses;
responses.randn(800);
LinearRegression lr(data, responses, 0.05); // Train the model.
LinearRegression xmlLr, jsonLr, binaryLr;
LinearRegression<> lr(data, responses, 0.05); // Train the model.
LinearRegression<> xmlLr, jsonLr, binaryLr;
SerializeObjectAll(lr, xmlLr, jsonLr, binaryLr);
@@ -260,7 +269,7 @@ TEST_CASE("LinearRegressionTrainReturnObjective", "[LinearRegressionTest]")
dot(coeffs.rows(1, 3), arma::ones<arma::rowvec>(3) * elem);
// Initialize and predict.
LinearRegression lr;
LinearRegression<> lr;
double error = lr.Train(predictors, responses);
REQUIRE(std::isfinite(error) == true);
@@ -269,24 +278,28 @@ TEST_CASE("LinearRegressionTrainReturnObjective", "[LinearRegressionTest]")
/**
* Make sure all versions of Train() work correctly.
*/
TEST_CASE("LinearRegressionAllTrainVersionsTest", "[LinearRegressionTest]")
TEMPLATE_TEST_CASE("LinearRegressionAllTrainVersionsTest",
"[LinearRegressionTest]", arma::fmat, arma::mat)
{
typedef TestType MatType;
typedef arma::Row<typename MatType::elem_type> RowType;
// The data doesn't really matter for this test; mostly we want to make sure
// that all the Train() variants work properly.
arma::mat predictors;
MatType predictors;
predictors = { { 0, 1, 2, 4, 8, 16 },
{ 16, 8, 4, 2, 1, 0 } };
arma::rowvec responses = "0 2 4 3 8 8";
arma::rowvec weights = "1.0 1.1 1.2 0.8 0.9 1.0";
RowType responses = "0 2 4 3 8 8";
RowType weights = "1.0 1.1 1.2 0.8 0.9 1.0";
LinearRegression lr1, lr2, lr3, lr4, lr5, lr6;
LinearRegression<MatType> lr1, lr2, lr3, lr4, lr5, lr6;
lr1.Train(predictors, responses);
lr2.Train(predictors, responses, 0.1);
lr3.Train(predictors, responses, 0.2, false);
lr4.Train(predictors, responses, weights);
lr5.Train(predictors, responses, weights, 0.3);
lr6.Train(predictors, responses, weights, 0.4, false);
(void) lr1.Train(predictors, responses);
(void) lr2.Train(predictors, responses, 0.1);
(void) lr3.Train(predictors, responses, 0.2, false);
(void) lr4.Train(predictors, responses, weights);
(void) lr5.Train(predictors, responses, weights, 0.3);
(void) lr6.Train(predictors, responses, weights, 0.4, false);
// We don't care about the specifics of the trained model, but we want to just
// make sure everything appears to be correct from the sizes and
@@ -325,17 +338,21 @@ TEST_CASE("LinearRegressionAllTrainVersionsTest", "[LinearRegressionTest]")
* Ensure that single-point Predict() returns the same results as multi-point
* Predict().
*/
TEST_CASE("LinearRegressionSinglePointPredictTest", "[LinearRegressionTest]")
TEMPLATE_TEST_CASE("LinearRegressionSinglePointPredictTest",
"[LinearRegressionTest]", arma::fmat, arma::mat)
{
arma::mat predictors;
typedef TestType MatType;
typedef arma::Row<typename MatType::elem_type> RowType;
MatType predictors;
predictors = { { 0, 1, 2, 4, 8, 16 },
{ 16, 8, 4, 2, 1, 0 } };
arma::rowvec responses = "0 2 4 3 8 8";
RowType responses = "0 2 4 3 8 8";
LinearRegression lr(predictors, responses, 0.1, true);
LinearRegression<MatType> lr(predictors, responses, 0.1, true);
// Compute predictions for test points in batch.
arma::rowvec predictions;
RowType predictions;
lr.Predict(predictors, predictions);
// Now compute each prediction individually.
@@ -345,3 +362,7 @@ TEST_CASE("LinearRegressionSinglePointPredictTest", "[LinearRegressionTest]")
REQUIRE(prediction == Approx(predictions[i]));
}
}
// Make sure training on submatrices and subvectors works.
// Make sure we can train on sparse data.
@@ -37,7 +37,7 @@ TEST_CASE_METHOD(LRPredictTestFixture, "LRPredictWrongDimOfDataTest1t",
arma::rowvec trainY = arma::randu<arma::rowvec>(N);
arma::mat testX = arma::randu<arma::mat>(D - 1, M); // Wrong dimensionality.
LinearRegression* model = new LinearRegression();
LinearRegression<>* model = new LinearRegression<>();
model->Train(trainX, trainY);
SetInputParam("input_model", std::move(model));
@@ -60,7 +60,7 @@ TEST_CASE_METHOD(LRPredictTestFixture, "LRPredictPredictionSizeCheck",
arma::rowvec trainY = arma::randu<arma::rowvec>(N);
arma::mat testX = arma::randu<arma::mat>(D, M);
LinearRegression* model = new LinearRegression();
LinearRegression<>* model = new LinearRegression<>();
model->Train(trainX, trainY);
SetInputParam("input_model", std::move(model));
@@ -118,7 +118,7 @@ TEST_CASE_METHOD(LRTestFixture, "LRModelReload",
RUN_BINDING();
LinearRegression* model = params.Get<LinearRegression*>("output_model");
LinearRegression<>* model = params.Get<LinearRegression<>*>("output_model");
const arma::rowvec testY1 = params.Get<arma::rowvec>("output_predictions");
ResetSettings();
@@ -191,7 +191,7 @@ TEST_CASE_METHOD(LRTestFixture, "LRWrongDimOfDataTest2",
RUN_BINDING();
LinearRegression* model = params.Get<LinearRegression*>("output_model");
LinearRegression<>* model = params.Get<LinearRegression<>*>("output_model");
ResetSettings();
@@ -44,8 +44,7 @@ TEST_CASE_METHOD(LRFitTestFixture, "LRFitDifferentLambdas",
// The first solution.
RUN_BINDING();
arma::rowvec preds1;
params.Get<LinearRegression*>("output_model")->Predict(testX,
preds1);
params.Get<LinearRegression<>*>("output_model")->Predict(testX, preds1);
const double testY1 = preds1(0);
ResetSettings();
@@ -57,8 +56,7 @@ TEST_CASE_METHOD(LRFitTestFixture, "LRFitDifferentLambdas",
// The second solution.
RUN_BINDING();
arma::rowvec preds2;
params.Get<LinearRegression*>("output_model")->Predict(testX,
preds2);
params.Get<LinearRegression<>*>("output_model")->Predict(testX, preds2);
const double testY2 = preds2(0);
// Second solution has stronger regularization,