Files
mlpack/src/mlpack/tests/serialization_test.cpp
T

1849 lines
60 KiB
C++

/**
* @file serialization_test.cpp
* @author Ryan Curtin
*
* Test serialization of mlpack objects.
*
* 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 <mlpack/core.hpp>
#include <mlpack/methods/ann/layer/layer.hpp>
#include <mlpack/methods/ann/layer/layer_types.hpp>
#include <mlpack/methods/ann/init_rules/random_init.hpp>
#include <mlpack/methods/ann/ffn.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "serialization.hpp"
#include <mlpack/core/dists/regression_distribution.hpp>
#include <mlpack/core/tree/ballbound.hpp>
#include <mlpack/core/tree/hrectbound.hpp>
#include <mlpack/core/metrics/mahalanobis_distance.hpp>
#include <mlpack/core/tree/binary_space_tree.hpp>
#include <mlpack/methods/hoeffding_trees/hoeffding_tree.hpp>
#include <mlpack/core/tree/cover_tree.hpp>
#include <mlpack/core/tree/rectangle_tree.hpp>
#include <mlpack/methods/perceptron/perceptron.hpp>
#include <mlpack/methods/logistic_regression/logistic_regression.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>
#include <mlpack/methods/softmax_regression/softmax_regression.hpp>
#include <mlpack/methods/det/dtree.hpp>
#include <mlpack/methods/naive_bayes/naive_bayes_classifier.hpp>
#include <mlpack/methods/rann/ra_search.hpp>
#include <mlpack/methods/lsh/lsh_search.hpp>
#include <mlpack/methods/decision_stump/decision_stump.hpp>
#include <mlpack/methods/lars/lars.hpp>
#include <mlpack/methods/ann/rbm/rbm.hpp>
#include <mlpack/methods/ann/init_rules/gaussian_init.hpp>
using namespace mlpack;
using namespace mlpack::distribution;
using namespace mlpack::regression;
using namespace mlpack::bound;
using namespace mlpack::metric;
using namespace mlpack::tree;
using namespace mlpack::perceptron;
using namespace mlpack::regression;
using namespace mlpack::naive_bayes;
using namespace mlpack::neighbor;
using namespace mlpack::decision_stump;
using namespace mlpack::ann;
using namespace arma;
using namespace boost;
using namespace boost::archive;
using namespace boost::serialization;
using namespace std;
BOOST_AUTO_TEST_SUITE(SerializationTest);
/**
* Serialize a random cube.
*/
BOOST_AUTO_TEST_CASE(CubeSerializeTest)
{
arma::cube m;
m.randu(2, 50, 50);
TestAllArmadilloSerialization(m);
}
/**
* Serialize an empty cube.
*/
BOOST_AUTO_TEST_CASE(EmptyCubeSerializeTest)
{
arma::cube c;
TestAllArmadilloSerialization(c);
}
/**
* Can we load and save an Armadillo matrix?
*/
BOOST_AUTO_TEST_CASE(MatrixSerializeXMLTest)
{
arma::mat m;
m.randu(50, 50);
TestAllArmadilloSerialization(m);
}
/**
* How about columns?
*/
BOOST_AUTO_TEST_CASE(ColSerializeTest)
{
arma::vec m;
m.randu(50, 1);
TestAllArmadilloSerialization(m);
}
/**
* How about rows?
*/
BOOST_AUTO_TEST_CASE(RowSerializeTest)
{
arma::rowvec m;
m.randu(1, 50);
TestAllArmadilloSerialization(m);
}
// A quick test with an empty matrix.
BOOST_AUTO_TEST_CASE(EmptyMatrixSerializeTest)
{
arma::mat m;
TestAllArmadilloSerialization(m);
}
/**
* Can we load and save a sparse Armadillo matrix?
*/
BOOST_AUTO_TEST_CASE(SparseMatrixSerializeTest)
{
arma::sp_mat m;
m.sprandu(50, 50, 0.3);
TestAllArmadilloSerialization(m);
}
/**
* How about columns?
*/
BOOST_AUTO_TEST_CASE(SparseColSerializeTest)
{
arma::sp_vec m;
m.sprandu(50, 1, 0.3);
TestAllArmadilloSerialization(m);
}
/**
* How about rows?
*/
BOOST_AUTO_TEST_CASE(SparseRowSerializeTest)
{
arma::sp_rowvec m;
m.sprandu(1, 50, 0.3);
TestAllArmadilloSerialization(m);
}
// A quick test with an empty matrix.
BOOST_AUTO_TEST_CASE(EmptySparseMatrixSerializeTest)
{
arma::sp_mat m;
TestAllArmadilloSerialization(m);
}
// Now, test mlpack objects.
BOOST_AUTO_TEST_CASE(DiscreteDistributionTest)
{
// I assume that I am properly saving vectors, so, this should be
// straightforward.
vec prob;
prob.randu(12);
std::vector<arma::vec> prob_vector = std::vector<arma::vec>(1, prob);
DiscreteDistribution t(prob_vector);
DiscreteDistribution xmlT, textT, binaryT;
// Load and save with all serializers.
SerializeObjectAll(t, xmlT, textT, binaryT);
for (size_t i = 0; i < 12; ++i)
{
vec obs(1);
obs[0] = i;
const double prob = t.Probability(obs);
if (prob == 0.0)
{
BOOST_REQUIRE_SMALL(xmlT.Probability(obs), 1e-8);
BOOST_REQUIRE_SMALL(textT.Probability(obs), 1e-8);
BOOST_REQUIRE_SMALL(binaryT.Probability(obs), 1e-8);
}
else
{
BOOST_REQUIRE_CLOSE(prob, xmlT.Probability(obs), 1e-8);
BOOST_REQUIRE_CLOSE(prob, textT.Probability(obs), 1e-8);
BOOST_REQUIRE_CLOSE(prob, binaryT.Probability(obs), 1e-8);
}
}
}
BOOST_AUTO_TEST_CASE(GaussianDistributionTest)
{
vec mean(10);
mean.randu();
// Generate a covariance matrix.
mat cov;
cov.randu(10, 10);
cov = (cov * cov.t());
GaussianDistribution g(mean, cov);
GaussianDistribution xmlG, textG, binaryG;
SerializeObjectAll(g, xmlG, textG, binaryG);
BOOST_REQUIRE_EQUAL(g.Dimensionality(), xmlG.Dimensionality());
BOOST_REQUIRE_EQUAL(g.Dimensionality(), textG.Dimensionality());
BOOST_REQUIRE_EQUAL(g.Dimensionality(), binaryG.Dimensionality());
// First, check the means.
CheckMatrices(g.Mean(), xmlG.Mean(), textG.Mean(), binaryG.Mean());
// Now, check the covariance.
CheckMatrices(g.Covariance(), xmlG.Covariance(), textG.Covariance(),
binaryG.Covariance());
// Lastly, run some observations through and make sure the probability is the
// same. This should test anything cached internally.
arma::mat randomObs;
randomObs.randu(10, 500);
for (size_t i = 0; i < 500; ++i)
{
const double prob = g.Probability(randomObs.unsafe_col(i));
if (prob == 0.0)
{
BOOST_REQUIRE_SMALL(xmlG.Probability(randomObs.unsafe_col(i)), 1e-8);
BOOST_REQUIRE_SMALL(textG.Probability(randomObs.unsafe_col(i)), 1e-8);
BOOST_REQUIRE_SMALL(binaryG.Probability(randomObs.unsafe_col(i)), 1e-8);
}
else
{
BOOST_REQUIRE_CLOSE(prob, xmlG.Probability(randomObs.unsafe_col(i)),
1e-8);
BOOST_REQUIRE_CLOSE(prob, textG.Probability(randomObs.unsafe_col(i)),
1e-8);
BOOST_REQUIRE_CLOSE(prob, binaryG.Probability(randomObs.unsafe_col(i)),
1e-8);
}
}
}
BOOST_AUTO_TEST_CASE(LaplaceDistributionTest)
{
vec mean(20);
mean.randu();
LaplaceDistribution l(mean, 2.5);
LaplaceDistribution xmlL, textL, binaryL;
SerializeObjectAll(l, xmlL, textL, binaryL);
BOOST_REQUIRE_CLOSE(l.Scale(), xmlL.Scale(), 1e-8);
BOOST_REQUIRE_CLOSE(l.Scale(), textL.Scale(), 1e-8);
BOOST_REQUIRE_CLOSE(l.Scale(), binaryL.Scale(), 1e-8);
CheckMatrices(l.Mean(), xmlL.Mean(), textL.Mean(), binaryL.Mean());
}
BOOST_AUTO_TEST_CASE(MahalanobisDistanceTest)
{
MahalanobisDistance<> d;
d.Covariance().randu(50, 50);
MahalanobisDistance<> xmlD, textD, binaryD;
SerializeObjectAll(d, xmlD, textD, binaryD);
// Check the covariance matrices.
CheckMatrices(d.Covariance(),
xmlD.Covariance(),
textD.Covariance(),
binaryD.Covariance());
}
BOOST_AUTO_TEST_CASE(LinearRegressionTest)
{
// Generate some random data.
mat data;
data.randn(15, 800);
rowvec responses;
responses.randn(800);
LinearRegression lr(data, responses, 0.05); // Train the model.
LinearRegression xmlLr, textLr, binaryLr;
SerializeObjectAll(lr, xmlLr, textLr, binaryLr);
BOOST_REQUIRE_CLOSE(lr.Lambda(), xmlLr.Lambda(), 1e-8);
BOOST_REQUIRE_CLOSE(lr.Lambda(), textLr.Lambda(), 1e-8);
BOOST_REQUIRE_CLOSE(lr.Lambda(), binaryLr.Lambda(), 1e-8);
CheckMatrices(lr.Parameters(), xmlLr.Parameters(), textLr.Parameters(),
binaryLr.Parameters());
}
BOOST_AUTO_TEST_CASE(RegressionDistributionTest)
{
// Generate some random data.
mat data;
data.randn(15, 800);
rowvec responses;
responses.randn(800);
RegressionDistribution rd(data, responses);
RegressionDistribution xmlRd, textRd, binaryRd;
// Okay, now save it and load it.
SerializeObjectAll(rd, xmlRd, textRd, binaryRd);
// Check the gaussian distribution.
CheckMatrices(rd.Err().Mean(),
xmlRd.Err().Mean(),
textRd.Err().Mean(),
binaryRd.Err().Mean());
CheckMatrices(rd.Err().Covariance(),
xmlRd.Err().Covariance(),
textRd.Err().Covariance(),
binaryRd.Err().Covariance());
// Check the regression function.
if (rd.Rf().Lambda() == 0.0)
{
BOOST_REQUIRE_SMALL(xmlRd.Rf().Lambda(), 1e-8);
BOOST_REQUIRE_SMALL(textRd.Rf().Lambda(), 1e-8);
BOOST_REQUIRE_SMALL(binaryRd.Rf().Lambda(), 1e-8);
}
else
{
BOOST_REQUIRE_CLOSE(rd.Rf().Lambda(), xmlRd.Rf().Lambda(), 1e-8);
BOOST_REQUIRE_CLOSE(rd.Rf().Lambda(), textRd.Rf().Lambda(), 1e-8);
BOOST_REQUIRE_CLOSE(rd.Rf().Lambda(), binaryRd.Rf().Lambda(), 1e-8);
}
CheckMatrices(rd.Rf().Parameters(),
xmlRd.Rf().Parameters(),
textRd.Rf().Parameters(),
binaryRd.Rf().Parameters());
}
BOOST_AUTO_TEST_CASE(BallBoundTest)
{
BallBound<> b(100);
b.Center().randu();
b.Radius() = 14.0;
BallBound<> xmlB, textB, binaryB;
SerializeObjectAll(b, xmlB, textB, binaryB);
// Check the dimensionality.
BOOST_REQUIRE_EQUAL(b.Dim(), xmlB.Dim());
BOOST_REQUIRE_EQUAL(b.Dim(), textB.Dim());
BOOST_REQUIRE_EQUAL(b.Dim(), binaryB.Dim());
// Check the radius.
BOOST_REQUIRE_CLOSE(b.Radius(), xmlB.Radius(), 1e-8);
BOOST_REQUIRE_CLOSE(b.Radius(), textB.Radius(), 1e-8);
BOOST_REQUIRE_CLOSE(b.Radius(), binaryB.Radius(), 1e-8);
// Now check the vectors.
CheckMatrices(b.Center(), xmlB.Center(), textB.Center(), binaryB.Center());
}
BOOST_AUTO_TEST_CASE(MahalanobisBallBoundTest)
{
BallBound<MahalanobisDistance<>, arma::vec> b(100);
b.Center().randu();
b.Radius() = 14.0;
b.Metric().Covariance().randu(100, 100);
BallBound<MahalanobisDistance<>, arma::vec> xmlB, textB, binaryB;
SerializeObjectAll(b, xmlB, textB, binaryB);
// Check the radius.
BOOST_REQUIRE_CLOSE(b.Radius(), xmlB.Radius(), 1e-8);
BOOST_REQUIRE_CLOSE(b.Radius(), textB.Radius(), 1e-8);
BOOST_REQUIRE_CLOSE(b.Radius(), binaryB.Radius(), 1e-8);
// Check the vectors.
CheckMatrices(b.Center(), xmlB.Center(), textB.Center(), binaryB.Center());
CheckMatrices(b.Metric().Covariance(),
xmlB.Metric().Covariance(),
textB.Metric().Covariance(),
binaryB.Metric().Covariance());
}
BOOST_AUTO_TEST_CASE(HRectBoundTest)
{
HRectBound<> b(2);
arma::mat points("0.0, 1.1; 5.0, 2.2");
points = points.t();
b |= points; // [0.0, 5.0]; [1.1, 2.2];
HRectBound<> xmlB, textB, binaryB;
SerializeObjectAll(b, xmlB, textB, binaryB);
// Check the dimensionality.
BOOST_REQUIRE_EQUAL(b.Dim(), xmlB.Dim());
BOOST_REQUIRE_EQUAL(b.Dim(), textB.Dim());
BOOST_REQUIRE_EQUAL(b.Dim(), binaryB.Dim());
// Check the bounds.
for (size_t i = 0; i < b.Dim(); ++i)
{
BOOST_REQUIRE_CLOSE(b[i].Lo(), xmlB[i].Lo(), 1e-8);
BOOST_REQUIRE_CLOSE(b[i].Hi(), xmlB[i].Hi(), 1e-8);
BOOST_REQUIRE_CLOSE(b[i].Lo(), textB[i].Lo(), 1e-8);
BOOST_REQUIRE_CLOSE(b[i].Hi(), textB[i].Hi(), 1e-8);
BOOST_REQUIRE_CLOSE(b[i].Lo(), binaryB[i].Lo(), 1e-8);
BOOST_REQUIRE_CLOSE(b[i].Hi(), binaryB[i].Hi(), 1e-8);
}
// Check the minimum width.
BOOST_REQUIRE_CLOSE(b.MinWidth(), xmlB.MinWidth(), 1e-8);
BOOST_REQUIRE_CLOSE(b.MinWidth(), textB.MinWidth(), 1e-8);
BOOST_REQUIRE_CLOSE(b.MinWidth(), binaryB.MinWidth(), 1e-8);
}
template<typename TreeType>
void CheckTrees(TreeType& tree,
TreeType& xmlTree,
TreeType& textTree,
TreeType& binaryTree)
{
const typename TreeType::Mat* dataset = &tree.Dataset();
// Make sure that the data matrices are the same.
if (tree.Parent() == NULL)
{
CheckMatrices(*dataset,
xmlTree.Dataset(),
textTree.Dataset(),
binaryTree.Dataset());
// Also ensure that the other parents are null too.
BOOST_REQUIRE_EQUAL(xmlTree.Parent(), (TreeType*) NULL);
BOOST_REQUIRE_EQUAL(textTree.Parent(), (TreeType*) NULL);
BOOST_REQUIRE_EQUAL(binaryTree.Parent(), (TreeType*) NULL);
}
// Make sure the number of children is the same.
BOOST_REQUIRE_EQUAL(tree.NumChildren(), xmlTree.NumChildren());
BOOST_REQUIRE_EQUAL(tree.NumChildren(), textTree.NumChildren());
BOOST_REQUIRE_EQUAL(tree.NumChildren(), binaryTree.NumChildren());
// Make sure the number of descendants is the same.
BOOST_REQUIRE_EQUAL(tree.NumDescendants(), xmlTree.NumDescendants());
BOOST_REQUIRE_EQUAL(tree.NumDescendants(), textTree.NumDescendants());
BOOST_REQUIRE_EQUAL(tree.NumDescendants(), binaryTree.NumDescendants());
// Make sure the number of points is the same.
BOOST_REQUIRE_EQUAL(tree.NumPoints(), xmlTree.NumPoints());
BOOST_REQUIRE_EQUAL(tree.NumPoints(), textTree.NumPoints());
BOOST_REQUIRE_EQUAL(tree.NumPoints(), binaryTree.NumPoints());
// Check that each point is the same.
for (size_t i = 0; i < tree.NumPoints(); ++i)
{
BOOST_REQUIRE_EQUAL(tree.Point(i), xmlTree.Point(i));
BOOST_REQUIRE_EQUAL(tree.Point(i), textTree.Point(i));
BOOST_REQUIRE_EQUAL(tree.Point(i), binaryTree.Point(i));
}
// Check that the parent distance is the same.
BOOST_REQUIRE_CLOSE(tree.ParentDistance(), xmlTree.ParentDistance(), 1e-8);
BOOST_REQUIRE_CLOSE(tree.ParentDistance(), textTree.ParentDistance(), 1e-8);
BOOST_REQUIRE_CLOSE(tree.ParentDistance(), binaryTree.ParentDistance(), 1e-8);
// Check that the furthest descendant distance is the same.
BOOST_REQUIRE_CLOSE(tree.FurthestDescendantDistance(),
xmlTree.FurthestDescendantDistance(), 1e-8);
BOOST_REQUIRE_CLOSE(tree.FurthestDescendantDistance(),
textTree.FurthestDescendantDistance(), 1e-8);
BOOST_REQUIRE_CLOSE(tree.FurthestDescendantDistance(),
binaryTree.FurthestDescendantDistance(), 1e-8);
// Check that the minimum bound distance is the same.
BOOST_REQUIRE_CLOSE(tree.MinimumBoundDistance(),
xmlTree.MinimumBoundDistance(), 1e-8);
BOOST_REQUIRE_CLOSE(tree.MinimumBoundDistance(),
textTree.MinimumBoundDistance(), 1e-8);
BOOST_REQUIRE_CLOSE(tree.MinimumBoundDistance(),
binaryTree.MinimumBoundDistance(), 1e-8);
// Recurse into the children.
for (size_t i = 0; i < tree.NumChildren(); ++i)
{
// Check that the child dataset is the same.
BOOST_REQUIRE_EQUAL(&xmlTree.Dataset(), &xmlTree.Child(i).Dataset());
BOOST_REQUIRE_EQUAL(&textTree.Dataset(), &textTree.Child(i).Dataset());
BOOST_REQUIRE_EQUAL(&binaryTree.Dataset(), &binaryTree.Child(i).Dataset());
// Make sure the parent link is right.
BOOST_REQUIRE_EQUAL(xmlTree.Child(i).Parent(), &xmlTree);
BOOST_REQUIRE_EQUAL(textTree.Child(i).Parent(), &textTree);
BOOST_REQUIRE_EQUAL(binaryTree.Child(i).Parent(), &binaryTree);
CheckTrees(tree.Child(i), xmlTree.Child(i), textTree.Child(i),
binaryTree.Child(i));
}
}
BOOST_AUTO_TEST_CASE(BinarySpaceTreeTest)
{
arma::mat data;
data.randu(3, 100);
typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
TreeType tree(data);
TreeType* xmlTree;
TreeType* textTree;
TreeType* binaryTree;
SerializePointerObjectAll(&tree, xmlTree, textTree, binaryTree);
CheckTrees(tree, *xmlTree, *textTree, *binaryTree);
delete xmlTree;
delete textTree;
delete binaryTree;
}
BOOST_AUTO_TEST_CASE(BinarySpaceTreeOverwriteTest)
{
arma::mat data;
data.randu(3, 100);
typedef KDTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
TreeType tree(data);
arma::mat otherData;
otherData.randu(5, 50);
TreeType xmlTree(otherData);
TreeType textTree(xmlTree);
TreeType binaryTree(xmlTree);
SerializeObjectAll(tree, xmlTree, textTree, binaryTree);
CheckTrees(tree, xmlTree, textTree, binaryTree);
}
BOOST_AUTO_TEST_CASE(CoverTreeTest)
{
arma::mat data;
data.randu(3, 100);
typedef StandardCoverTree<EuclideanDistance, EmptyStatistic, arma::mat>
TreeType;
TreeType tree(data);
TreeType* xmlTree;
TreeType* textTree;
TreeType* binaryTree;
SerializePointerObjectAll(&tree, xmlTree, textTree, binaryTree);
CheckTrees(tree, *xmlTree, *textTree, *binaryTree);
// Also check a few other things.
std::stack<TreeType*> stack, xmlStack, textStack, binaryStack;
stack.push(&tree);
xmlStack.push(xmlTree);
textStack.push(textTree);
binaryStack.push(binaryTree);
while (!stack.empty())
{
TreeType* node = stack.top();
TreeType* xmlNode = xmlStack.top();
TreeType* textNode = textStack.top();
TreeType* binaryNode = binaryStack.top();
stack.pop();
xmlStack.pop();
textStack.pop();
binaryStack.pop();
BOOST_REQUIRE_EQUAL(node->Scale(), xmlNode->Scale());
BOOST_REQUIRE_EQUAL(node->Scale(), textNode->Scale());
BOOST_REQUIRE_EQUAL(node->Scale(), binaryNode->Scale());
BOOST_REQUIRE_CLOSE(node->Base(), xmlNode->Base(), 1e-5);
BOOST_REQUIRE_CLOSE(node->Base(), textNode->Base(), 1e-5);
BOOST_REQUIRE_CLOSE(node->Base(), binaryNode->Base(), 1e-5);
for (size_t i = 0; i < node->NumChildren(); ++i)
{
stack.push(&node->Child(i));
xmlStack.push(&xmlNode->Child(i));
textStack.push(&textNode->Child(i));
binaryStack.push(&binaryNode->Child(i));
}
}
delete xmlTree;
delete textTree;
delete binaryTree;
}
BOOST_AUTO_TEST_CASE(CoverTreeOverwriteTest)
{
arma::mat data;
data.randu(3, 100);
typedef StandardCoverTree<EuclideanDistance, EmptyStatistic, arma::mat>
TreeType;
TreeType tree(data);
arma::mat otherData;
otherData.randu(5, 50);
TreeType xmlTree(otherData);
TreeType textTree(xmlTree);
TreeType binaryTree(xmlTree);
SerializeObjectAll(tree, xmlTree, textTree, binaryTree);
CheckTrees(tree, xmlTree, textTree, binaryTree);
// Also check a few other things.
std::stack<TreeType*> stack, xmlStack, textStack, binaryStack;
stack.push(&tree);
xmlStack.push(&xmlTree);
textStack.push(&textTree);
binaryStack.push(&binaryTree);
while (!stack.empty())
{
TreeType* node = stack.top();
TreeType* xmlNode = xmlStack.top();
TreeType* textNode = textStack.top();
TreeType* binaryNode = binaryStack.top();
stack.pop();
xmlStack.pop();
textStack.pop();
binaryStack.pop();
BOOST_REQUIRE_EQUAL(node->Scale(), xmlNode->Scale());
BOOST_REQUIRE_EQUAL(node->Scale(), textNode->Scale());
BOOST_REQUIRE_EQUAL(node->Scale(), binaryNode->Scale());
BOOST_REQUIRE_CLOSE(node->Base(), xmlNode->Base(), 1e-5);
BOOST_REQUIRE_CLOSE(node->Base(), textNode->Base(), 1e-5);
BOOST_REQUIRE_CLOSE(node->Base(), binaryNode->Base(), 1e-5);
for (size_t i = 0; i < node->NumChildren(); ++i)
{
stack.push(&node->Child(i));
xmlStack.push(&xmlNode->Child(i));
textStack.push(&textNode->Child(i));
binaryStack.push(&binaryNode->Child(i));
}
}
}
BOOST_AUTO_TEST_CASE(RectangleTreeTest)
{
arma::mat data;
data.randu(3, 1000);
typedef RTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
TreeType tree(data);
TreeType* xmlTree;
TreeType* textTree;
TreeType* binaryTree;
SerializePointerObjectAll(&tree, xmlTree, textTree, binaryTree);
CheckTrees(tree, *xmlTree, *textTree, *binaryTree);
// Check a few other things too.
std::stack<TreeType*> stack, xmlStack, textStack, binaryStack;
stack.push(&tree);
xmlStack.push(xmlTree);
textStack.push(textTree);
binaryStack.push(binaryTree);
while (!stack.empty())
{
// Check more things...
TreeType* node = stack.top();
TreeType* xmlNode = xmlStack.top();
TreeType* textNode = textStack.top();
TreeType* binaryNode = binaryStack.top();
stack.pop();
xmlStack.pop();
textStack.pop();
binaryStack.pop();
BOOST_REQUIRE_EQUAL(node->MaxLeafSize(), xmlNode->MaxLeafSize());
BOOST_REQUIRE_EQUAL(node->MaxLeafSize(), textNode->MaxLeafSize());
BOOST_REQUIRE_EQUAL(node->MaxLeafSize(), binaryNode->MaxLeafSize());
BOOST_REQUIRE_EQUAL(node->MinLeafSize(), xmlNode->MinLeafSize());
BOOST_REQUIRE_EQUAL(node->MinLeafSize(), textNode->MinLeafSize());
BOOST_REQUIRE_EQUAL(node->MinLeafSize(), binaryNode->MinLeafSize());
BOOST_REQUIRE_EQUAL(node->MaxNumChildren(), xmlNode->MaxNumChildren());
BOOST_REQUIRE_EQUAL(node->MaxNumChildren(), textNode->MaxNumChildren());
BOOST_REQUIRE_EQUAL(node->MaxNumChildren(), binaryNode->MaxNumChildren());
BOOST_REQUIRE_EQUAL(node->MinNumChildren(), xmlNode->MinNumChildren());
BOOST_REQUIRE_EQUAL(node->MinNumChildren(), textNode->MinNumChildren());
BOOST_REQUIRE_EQUAL(node->MinNumChildren(), binaryNode->MinNumChildren());
}
delete xmlTree;
delete textTree;
delete binaryTree;
}
BOOST_AUTO_TEST_CASE(RectangleTreeOverwriteTest)
{
arma::mat data;
data.randu(3, 1000);
typedef RTree<EuclideanDistance, EmptyStatistic, arma::mat> TreeType;
TreeType tree(data);
arma::mat otherData;
otherData.randu(5, 50);
TreeType xmlTree(otherData);
TreeType textTree(otherData);
TreeType binaryTree(textTree);
SerializeObjectAll(tree, xmlTree, textTree, binaryTree);
CheckTrees(tree, xmlTree, textTree, binaryTree);
// Check a few other things too.
std::stack<TreeType*> stack, xmlStack, textStack, binaryStack;
stack.push(&tree);
xmlStack.push(&xmlTree);
textStack.push(&textTree);
binaryStack.push(&binaryTree);
while (!stack.empty())
{
// Check more things...
TreeType* node = stack.top();
TreeType* xmlNode = xmlStack.top();
TreeType* textNode = textStack.top();
TreeType* binaryNode = binaryStack.top();
stack.pop();
xmlStack.pop();
textStack.pop();
binaryStack.pop();
BOOST_REQUIRE_EQUAL(node->MaxLeafSize(), xmlNode->MaxLeafSize());
BOOST_REQUIRE_EQUAL(node->MaxLeafSize(), textNode->MaxLeafSize());
BOOST_REQUIRE_EQUAL(node->MaxLeafSize(), binaryNode->MaxLeafSize());
BOOST_REQUIRE_EQUAL(node->MinLeafSize(), xmlNode->MinLeafSize());
BOOST_REQUIRE_EQUAL(node->MinLeafSize(), textNode->MinLeafSize());
BOOST_REQUIRE_EQUAL(node->MinLeafSize(), binaryNode->MinLeafSize());
BOOST_REQUIRE_EQUAL(node->MaxNumChildren(), xmlNode->MaxNumChildren());
BOOST_REQUIRE_EQUAL(node->MaxNumChildren(), textNode->MaxNumChildren());
BOOST_REQUIRE_EQUAL(node->MaxNumChildren(), binaryNode->MaxNumChildren());
BOOST_REQUIRE_EQUAL(node->MinNumChildren(), xmlNode->MinNumChildren());
BOOST_REQUIRE_EQUAL(node->MinNumChildren(), textNode->MinNumChildren());
BOOST_REQUIRE_EQUAL(node->MinNumChildren(), binaryNode->MinNumChildren());
}
}
BOOST_AUTO_TEST_CASE(PerceptronTest)
{
// Create a perceptron. Train it randomly. Then check that it hasn't
// changed.
arma::mat data;
data.randu(3, 100);
arma::Row<size_t> labels(100);
for (size_t i = 0; i < labels.n_elem; ++i)
{
if (data(1, i) > 0.5)
labels[i] = 0;
else
labels[i] = 1;
}
Perceptron<> p(data, labels, 2, 15);
Perceptron<> pXml(2, 3), pText(2, 3), pBinary(2, 3);
SerializeObjectAll(p, pXml, pText, pBinary);
// Now check that things are the same.
CheckMatrices(p.Weights(), pXml.Weights(), pText.Weights(),
pBinary.Weights());
CheckMatrices(p.Biases(), pXml.Biases(), pText.Biases(), pBinary.Biases());
BOOST_REQUIRE_EQUAL(p.MaxIterations(), pXml.MaxIterations());
BOOST_REQUIRE_EQUAL(p.MaxIterations(), pText.MaxIterations());
BOOST_REQUIRE_EQUAL(p.MaxIterations(), pBinary.MaxIterations());
}
BOOST_AUTO_TEST_CASE(LogisticRegressionTest)
{
arma::mat data;
data.randu(3, 100);
arma::Row<size_t> responses;
responses.randu(100);
LogisticRegression<> lr(data, responses, 0.5);
LogisticRegression<> lrXml(data, responses + 3, 0.3);
LogisticRegression<> lrText(data, responses + 1);
LogisticRegression<> lrBinary(3, 0.0);
SerializeObjectAll(lr, lrXml, lrText, lrBinary);
CheckMatrices(lr.Parameters(), lrXml.Parameters(), lrText.Parameters(),
lrBinary.Parameters());
BOOST_REQUIRE_CLOSE(lr.Lambda(), lrXml.Lambda(), 1e-5);
BOOST_REQUIRE_CLOSE(lr.Lambda(), lrText.Lambda(), 1e-5);
BOOST_REQUIRE_CLOSE(lr.Lambda(), lrBinary.Lambda(), 1e-5);
}
BOOST_AUTO_TEST_CASE(KNNTest)
{
using neighbor::KNN;
arma::mat dataset = arma::randu<arma::mat>(5, 2000);
KNN knn(dataset, DUAL_TREE_MODE);
KNN knnXml, knnText, knnBinary;
SerializeObjectAll(knn, knnXml, knnText, knnBinary);
// Now run nearest neighbor and make sure the results are the same.
arma::mat querySet = arma::randu<arma::mat>(5, 1000);
arma::mat distances, xmlDistances, textDistances, binaryDistances;
arma::Mat<size_t> neighbors, xmlNeighbors, textNeighbors, binaryNeighbors;
knn.Search(querySet, 5, neighbors, distances);
knnXml.Search(querySet, 5, xmlNeighbors, xmlDistances);
knnText.Search(querySet, 5, textNeighbors, textDistances);
knnBinary.Search(querySet, 5, binaryNeighbors, binaryDistances);
CheckMatrices(distances, xmlDistances, textDistances, binaryDistances);
CheckMatrices(neighbors, xmlNeighbors, textNeighbors, binaryNeighbors);
}
BOOST_AUTO_TEST_CASE(SoftmaxRegressionTest)
{
using regression::SoftmaxRegression;
arma::mat dataset = arma::randu<arma::mat>(5, 1000);
arma::Row<size_t> labels(1000);
for (size_t i = 0; i < 500; ++i)
labels[i] = 0;
for (size_t i = 500; i < 1000; ++i)
labels[i] = 1;
SoftmaxRegression sr(dataset, labels, 2);
SoftmaxRegression srXml(dataset.n_rows, 2);
SoftmaxRegression srText(dataset.n_rows, 2);
SoftmaxRegression srBinary(dataset.n_rows, 2);
SerializeObjectAll(sr, srXml, srText, srBinary);
CheckMatrices(sr.Parameters(), srXml.Parameters(), srText.Parameters(),
srBinary.Parameters());
}
BOOST_AUTO_TEST_CASE(DETTest)
{
using det::DTree;
typedef DTree<arma::mat> DTreeX;
// Create a density estimation tree on a random dataset.
arma::mat dataset = arma::randu<arma::mat>(25, 5000);
DTreeX tree(dataset);
arma::mat otherDataset = arma::randu<arma::mat>(5, 100);
DTreeX xmlTree, binaryTree, textTree(otherDataset);
SerializeObjectAll(tree, xmlTree, binaryTree, textTree);
std::stack<DTreeX*> stack, xmlStack, binaryStack, textStack;
stack.push(&tree);
xmlStack.push(&xmlTree);
binaryStack.push(&binaryTree);
textStack.push(&textTree);
while (!stack.empty())
{
// Get the top node from the stack.
DTreeX* node = stack.top();
DTreeX* xmlNode = xmlStack.top();
DTreeX* binaryNode = binaryStack.top();
DTreeX* textNode = textStack.top();
stack.pop();
xmlStack.pop();
binaryStack.pop();
textStack.pop();
// Check that all the members are the same.
BOOST_REQUIRE_EQUAL(node->Start(), xmlNode->Start());
BOOST_REQUIRE_EQUAL(node->Start(), binaryNode->Start());
BOOST_REQUIRE_EQUAL(node->Start(), textNode->Start());
BOOST_REQUIRE_EQUAL(node->End(), xmlNode->End());
BOOST_REQUIRE_EQUAL(node->End(), binaryNode->End());
BOOST_REQUIRE_EQUAL(node->End(), textNode->End());
BOOST_REQUIRE_EQUAL(node->SplitDim(), xmlNode->SplitDim());
BOOST_REQUIRE_EQUAL(node->SplitDim(), binaryNode->SplitDim());
BOOST_REQUIRE_EQUAL(node->SplitDim(), textNode->SplitDim());
if (std::abs(node->SplitValue()) < 1e-5)
{
BOOST_REQUIRE_SMALL(xmlNode->SplitValue(), 1e-5);
BOOST_REQUIRE_SMALL(binaryNode->SplitValue(), 1e-5);
BOOST_REQUIRE_SMALL(textNode->SplitValue(), 1e-5);
}
else
{
BOOST_REQUIRE_CLOSE(node->SplitValue(), xmlNode->SplitValue(), 1e-5);
BOOST_REQUIRE_CLOSE(node->SplitValue(), binaryNode->SplitValue(), 1e-5);
BOOST_REQUIRE_CLOSE(node->SplitValue(), textNode->SplitValue(), 1e-5);
}
if (std::abs(node->LogNegError()) < 1e-5)
{
BOOST_REQUIRE_SMALL(xmlNode->LogNegError(), 1e-5);
BOOST_REQUIRE_SMALL(binaryNode->LogNegError(), 1e-5);
BOOST_REQUIRE_SMALL(textNode->LogNegError(), 1e-5);
}
else
{
BOOST_REQUIRE_CLOSE(node->LogNegError(), xmlNode->LogNegError(), 1e-5);
BOOST_REQUIRE_CLOSE(node->LogNegError(), binaryNode->LogNegError(), 1e-5);
BOOST_REQUIRE_CLOSE(node->LogNegError(), textNode->LogNegError(), 1e-5);
}
if (std::abs(node->SubtreeLeavesLogNegError()) < 1e-5)
{
BOOST_REQUIRE_SMALL(xmlNode->SubtreeLeavesLogNegError(), 1e-5);
BOOST_REQUIRE_SMALL(binaryNode->SubtreeLeavesLogNegError(), 1e-5);
BOOST_REQUIRE_SMALL(textNode->SubtreeLeavesLogNegError(), 1e-5);
}
else
{
BOOST_REQUIRE_CLOSE(node->SubtreeLeavesLogNegError(),
xmlNode->SubtreeLeavesLogNegError(), 1e-5);
BOOST_REQUIRE_CLOSE(node->SubtreeLeavesLogNegError(),
binaryNode->SubtreeLeavesLogNegError(), 1e-5);
BOOST_REQUIRE_CLOSE(node->SubtreeLeavesLogNegError(),
textNode->SubtreeLeavesLogNegError(), 1e-5);
}
BOOST_REQUIRE_EQUAL(node->SubtreeLeaves(), xmlNode->SubtreeLeaves());
BOOST_REQUIRE_EQUAL(node->SubtreeLeaves(), binaryNode->SubtreeLeaves());
BOOST_REQUIRE_EQUAL(node->SubtreeLeaves(), textNode->SubtreeLeaves());
if (std::abs(node->Ratio()) < 1e-5)
{
BOOST_REQUIRE_SMALL(xmlNode->Ratio(), 1e-5);
BOOST_REQUIRE_SMALL(binaryNode->Ratio(), 1e-5);
BOOST_REQUIRE_SMALL(textNode->Ratio(), 1e-5);
}
else
{
BOOST_REQUIRE_CLOSE(node->Ratio(), xmlNode->Ratio(), 1e-5);
BOOST_REQUIRE_CLOSE(node->Ratio(), binaryNode->Ratio(), 1e-5);
BOOST_REQUIRE_CLOSE(node->Ratio(), textNode->Ratio(), 1e-5);
}
if (std::abs(node->LogVolume()) < 1e-5)
{
BOOST_REQUIRE_SMALL(xmlNode->LogVolume(), 1e-5);
BOOST_REQUIRE_SMALL(binaryNode->LogVolume(), 1e-5);
BOOST_REQUIRE_SMALL(textNode->LogVolume(), 1e-5);
}
else
{
BOOST_REQUIRE_CLOSE(node->LogVolume(), xmlNode->LogVolume(), 1e-5);
BOOST_REQUIRE_CLOSE(node->LogVolume(), binaryNode->LogVolume(), 1e-5);
BOOST_REQUIRE_CLOSE(node->LogVolume(), textNode->LogVolume(), 1e-5);
}
if (node->Left() == NULL)
{
BOOST_REQUIRE(xmlNode->Left() == NULL);
BOOST_REQUIRE(binaryNode->Left() == NULL);
BOOST_REQUIRE(textNode->Left() == NULL);
}
else
{
BOOST_REQUIRE(xmlNode->Left() != NULL);
BOOST_REQUIRE(binaryNode->Left() != NULL);
BOOST_REQUIRE(textNode->Left() != NULL);
// Push children onto stack.
stack.push(node->Left());
xmlStack.push(xmlNode->Left());
binaryStack.push(binaryNode->Left());
textStack.push(textNode->Left());
}
if (node->Right() == NULL)
{
BOOST_REQUIRE(xmlNode->Right() == NULL);
BOOST_REQUIRE(binaryNode->Right() == NULL);
BOOST_REQUIRE(textNode->Right() == NULL);
}
else
{
BOOST_REQUIRE(xmlNode->Right() != NULL);
BOOST_REQUIRE(binaryNode->Right() != NULL);
BOOST_REQUIRE(textNode->Right() != NULL);
// Push children onto stack.
stack.push(node->Right());
xmlStack.push(xmlNode->Right());
binaryStack.push(binaryNode->Right());
textStack.push(textNode->Right());
}
BOOST_REQUIRE_EQUAL(node->Root(), xmlNode->Root());
BOOST_REQUIRE_EQUAL(node->Root(), binaryNode->Root());
BOOST_REQUIRE_EQUAL(node->Root(), textNode->Root());
if (std::abs(node->AlphaUpper()) < 1e-5)
{
BOOST_REQUIRE_SMALL(xmlNode->AlphaUpper(), 1e-5);
BOOST_REQUIRE_SMALL(binaryNode->AlphaUpper(), 1e-5);
BOOST_REQUIRE_SMALL(textNode->AlphaUpper(), 1e-5);
}
else
{
BOOST_REQUIRE_CLOSE(node->AlphaUpper(), xmlNode->AlphaUpper(), 1e-5);
BOOST_REQUIRE_CLOSE(node->AlphaUpper(), binaryNode->AlphaUpper(), 1e-5);
BOOST_REQUIRE_CLOSE(node->AlphaUpper(), textNode->AlphaUpper(), 1e-5);
}
BOOST_REQUIRE_EQUAL(node->MaxVals().n_elem, xmlNode->MaxVals().n_elem);
BOOST_REQUIRE_EQUAL(node->MaxVals().n_elem, binaryNode->MaxVals().n_elem);
BOOST_REQUIRE_EQUAL(node->MaxVals().n_elem, textNode->MaxVals().n_elem);
for (size_t i = 0; i < node->MaxVals().n_elem; ++i)
{
if (std::abs(node->MaxVals()[i]) < 1e-5)
{
BOOST_REQUIRE_SMALL(xmlNode->MaxVals()[i], 1e-5);
BOOST_REQUIRE_SMALL(binaryNode->MaxVals()[i], 1e-5);
BOOST_REQUIRE_SMALL(textNode->MaxVals()[i], 1e-5);
}
else
{
BOOST_REQUIRE_CLOSE(node->MaxVals()[i], xmlNode->MaxVals()[i], 1e-5);
BOOST_REQUIRE_CLOSE(node->MaxVals()[i], binaryNode->MaxVals()[i], 1e-5);
BOOST_REQUIRE_CLOSE(node->MaxVals()[i], textNode->MaxVals()[i], 1e-5);
}
}
BOOST_REQUIRE_EQUAL(node->MinVals().n_elem, xmlNode->MinVals().n_elem);
BOOST_REQUIRE_EQUAL(node->MinVals().n_elem, binaryNode->MinVals().n_elem);
BOOST_REQUIRE_EQUAL(node->MinVals().n_elem, textNode->MinVals().n_elem);
for (size_t i = 0; i < node->MinVals().n_elem; ++i)
{
if (std::abs(node->MinVals()[i]) < 1e-5)
{
BOOST_REQUIRE_SMALL(xmlNode->MinVals()[i], 1e-5);
BOOST_REQUIRE_SMALL(binaryNode->MinVals()[i], 1e-5);
BOOST_REQUIRE_SMALL(textNode->MinVals()[i], 1e-5);
}
else
{
BOOST_REQUIRE_CLOSE(node->MinVals()[i], xmlNode->MinVals()[i], 1e-5);
BOOST_REQUIRE_CLOSE(node->MinVals()[i], binaryNode->MinVals()[i], 1e-5);
BOOST_REQUIRE_CLOSE(node->MinVals()[i], textNode->MinVals()[i], 1e-5);
}
}
}
}
BOOST_AUTO_TEST_CASE(NaiveBayesSerializationTest)
{
// Train NBC randomly. Make sure the model is the same after serializing and
// re-loading.
arma::mat dataset;
dataset.randu(10, 500);
arma::Row<size_t> labels(500);
for (size_t i = 0; i < 500; ++i)
{
if (dataset(0, i) > 0.5)
labels[i] = 0;
else
labels[i] = 1;
}
NaiveBayesClassifier<> nbc(dataset, labels, 2);
// Initialize some empty Naive Bayes classifiers.
NaiveBayesClassifier<> xmlNbc(0, 0), textNbc(0, 0), binaryNbc(0, 0);
SerializeObjectAll(nbc, xmlNbc, textNbc, binaryNbc);
BOOST_REQUIRE_EQUAL(nbc.Means().n_elem, xmlNbc.Means().n_elem);
BOOST_REQUIRE_EQUAL(nbc.Means().n_elem, textNbc.Means().n_elem);
BOOST_REQUIRE_EQUAL(nbc.Means().n_elem, binaryNbc.Means().n_elem);
for (size_t i = 0; i < nbc.Means().n_elem; ++i)
{
BOOST_REQUIRE_CLOSE(nbc.Means()[i], xmlNbc.Means()[i], 1e-5);
BOOST_REQUIRE_CLOSE(nbc.Means()[i], textNbc.Means()[i], 1e-5);
BOOST_REQUIRE_CLOSE(nbc.Means()[i], binaryNbc.Means()[i], 1e-5);
}
BOOST_REQUIRE_EQUAL(nbc.Variances().n_elem, xmlNbc.Variances().n_elem);
BOOST_REQUIRE_EQUAL(nbc.Variances().n_elem, textNbc.Variances().n_elem);
BOOST_REQUIRE_EQUAL(nbc.Variances().n_elem, binaryNbc.Variances().n_elem);
for (size_t i = 0; i < nbc.Variances().n_elem; ++i)
{
BOOST_REQUIRE_CLOSE(nbc.Variances()[i], xmlNbc.Variances()[i], 1e-5);
BOOST_REQUIRE_CLOSE(nbc.Variances()[i], textNbc.Variances()[i], 1e-5);
BOOST_REQUIRE_CLOSE(nbc.Variances()[i], binaryNbc.Variances()[i], 1e-5);
}
BOOST_REQUIRE_EQUAL(nbc.Probabilities().n_elem,
xmlNbc.Probabilities().n_elem);
BOOST_REQUIRE_EQUAL(nbc.Probabilities().n_elem,
textNbc.Probabilities().n_elem);
BOOST_REQUIRE_EQUAL(nbc.Probabilities().n_elem,
binaryNbc.Probabilities().n_elem);
for (size_t i = 0; i < nbc.Probabilities().n_elem; ++i)
{
BOOST_REQUIRE_CLOSE(nbc.Probabilities()[i], xmlNbc.Probabilities()[i],
1e-5);
BOOST_REQUIRE_CLOSE(nbc.Probabilities()[i], textNbc.Probabilities()[i],
1e-5);
BOOST_REQUIRE_CLOSE(nbc.Probabilities()[i], binaryNbc.Probabilities()[i],
1e-5);
}
}
BOOST_AUTO_TEST_CASE(RASearchTest)
{
using neighbor::KRANN;
using neighbor::KNN;
arma::mat dataset = arma::randu<arma::mat>(5, 200);
arma::mat otherDataset = arma::randu<arma::mat>(5, 100);
// Find nearest neighbors in the top 10, with accuracy 0.95. So 95% of the
// results we get (at least) should fall into the top 10 of the true nearest
// neighbors.
KRANN allkrann(dataset, false, false, 5, 0.95);
KRANN krannXml(otherDataset, false, false);
KRANN krannText(otherDataset, true, false);
KRANN krannBinary(otherDataset, true, true);
SerializeObjectAll(allkrann, krannXml, krannText, krannBinary);
// Now run nearest neighbor and make sure the results are the same.
arma::mat querySet = arma::randu<arma::mat>(5, 100);
arma::mat distances, xmlDistances, textDistances, binaryDistances;
arma::Mat<size_t> neighbors, xmlNeighbors, textNeighbors, binaryNeighbors;
KNN knn(dataset); // Exact search.
knn.Search(querySet, 10, neighbors, distances);
krannXml.Search(querySet, 5, xmlNeighbors, xmlDistances);
krannText.Search(querySet, 5, textNeighbors, textDistances);
krannBinary.Search(querySet, 5, binaryNeighbors, binaryDistances);
BOOST_REQUIRE_EQUAL(xmlNeighbors.n_rows, 5);
BOOST_REQUIRE_EQUAL(xmlNeighbors.n_cols, 100);
BOOST_REQUIRE_EQUAL(textNeighbors.n_rows, 5);
BOOST_REQUIRE_EQUAL(textNeighbors.n_cols, 100);
BOOST_REQUIRE_EQUAL(binaryNeighbors.n_rows, 5);
BOOST_REQUIRE_EQUAL(binaryNeighbors.n_cols, 100);
size_t xmlCorrect = 0;
size_t textCorrect = 0;
size_t binaryCorrect = 0;
for (size_t i = 0; i < xmlNeighbors.n_cols; ++i)
{
// See how many are in the top 10.
for (size_t j = 0; j < xmlNeighbors.n_rows; ++j)
{
for (size_t k = 0; k < neighbors.n_rows; ++k)
{
if (neighbors(k, i) == xmlNeighbors(j, i))
xmlCorrect++;
if (neighbors(k, i) == textNeighbors(j, i))
textCorrect++;
if (neighbors(k, i) == binaryNeighbors(j, i))
binaryCorrect++;
}
}
}
// We need 95% of these to be correct.
BOOST_REQUIRE_GT(xmlCorrect, 95 * 5);
BOOST_REQUIRE_GT(binaryCorrect, 95 * 5);
BOOST_REQUIRE_GT(textCorrect, 95 * 5);
}
/**
* Test that an LSH model can be serialized and deserialized.
*/
BOOST_AUTO_TEST_CASE(LSHTest)
{
// Since we still don't have good tests for LSH, basically what we're going to
// do is serialize an LSH model, and make sure we can deserialize it and that
// we still get results when we call Search().
arma::mat referenceData = arma::randu<arma::mat>(10, 100);
LSHSearch<> lsh(referenceData, 5, 10); // Arbitrary chosen parameters.
LSHSearch<> xmlLsh;
arma::mat textData = arma::randu<arma::mat>(5, 50);
LSHSearch<> textLsh(textData, 4, 5);
LSHSearch<> binaryLsh(referenceData, 15, 2);
// Now serialize.
SerializeObjectAll(lsh, xmlLsh, textLsh, binaryLsh);
// Check what we can about the serialized objects.
BOOST_REQUIRE_EQUAL(lsh.NumProjections(), xmlLsh.NumProjections());
BOOST_REQUIRE_EQUAL(lsh.NumProjections(), textLsh.NumProjections());
BOOST_REQUIRE_EQUAL(lsh.NumProjections(), binaryLsh.NumProjections());
for (size_t i = 0; i < lsh.NumProjections(); ++i)
{
CheckMatrices(lsh.Projections().slice(i), xmlLsh.Projections().slice(i),
textLsh.Projections().slice(i), binaryLsh.Projections().slice(i));
}
CheckMatrices(lsh.ReferenceSet(), xmlLsh.ReferenceSet(),
textLsh.ReferenceSet(), binaryLsh.ReferenceSet());
CheckMatrices(lsh.Offsets(), xmlLsh.Offsets(), textLsh.Offsets(),
binaryLsh.Offsets());
CheckMatrices(lsh.SecondHashWeights(), xmlLsh.SecondHashWeights(),
textLsh.SecondHashWeights(), binaryLsh.SecondHashWeights());
BOOST_REQUIRE_EQUAL(lsh.BucketSize(), xmlLsh.BucketSize());
BOOST_REQUIRE_EQUAL(lsh.BucketSize(), textLsh.BucketSize());
BOOST_REQUIRE_EQUAL(lsh.BucketSize(), binaryLsh.BucketSize());
BOOST_REQUIRE_EQUAL(lsh.SecondHashTable().size(),
xmlLsh.SecondHashTable().size());
BOOST_REQUIRE_EQUAL(lsh.SecondHashTable().size(),
textLsh.SecondHashTable().size());
BOOST_REQUIRE_EQUAL(lsh.SecondHashTable().size(),
binaryLsh.SecondHashTable().size());
for (size_t i = 0; i < lsh.SecondHashTable().size(); ++i)
CheckMatrices(lsh.SecondHashTable()[i], xmlLsh.SecondHashTable()[i],
textLsh.SecondHashTable()[i], binaryLsh.SecondHashTable()[i]);
}
// Make sure serialization works for the decision stump.
BOOST_AUTO_TEST_CASE(DecisionStumpTest)
{
// Generate dataset.
arma::mat trainingData = arma::randu<arma::mat>(4, 100);
arma::Row<size_t> labels(100);
for (size_t i = 0; i < 25; ++i)
labels[i] = 0;
for (size_t i = 25; i < 50; ++i)
labels[i] = 3;
for (size_t i = 50; i < 75; ++i)
labels[i] = 1;
for (size_t i = 75; i < 100; ++i)
labels[i] = 2;
DecisionStump<> ds(trainingData, labels, 4, 3);
arma::mat otherData = arma::randu<arma::mat>(3, 100);
arma::Row<size_t> otherLabels = arma::randu<arma::Row<size_t>>(100);
DecisionStump<> xmlDs(otherData, otherLabels, 2, 3);
DecisionStump<> textDs;
DecisionStump<> binaryDs(trainingData, labels, 4, 10);
SerializeObjectAll(ds, xmlDs, textDs, binaryDs);
// Make sure that everything is the same about the new decision stumps.
BOOST_REQUIRE_EQUAL(ds.SplitDimension(), xmlDs.SplitDimension());
BOOST_REQUIRE_EQUAL(ds.SplitDimension(), textDs.SplitDimension());
BOOST_REQUIRE_EQUAL(ds.SplitDimension(), binaryDs.SplitDimension());
CheckMatrices(ds.Split(), xmlDs.Split(), textDs.Split(), binaryDs.Split());
CheckMatrices(ds.BinLabels(), xmlDs.BinLabels(), textDs.BinLabels(),
binaryDs.BinLabels());
}
// Make sure serialization works for LARS.
BOOST_AUTO_TEST_CASE(LARSTest)
{
using namespace mlpack::regression;
// Create a dataset.
arma::mat X = arma::randn(75, 250);
arma::vec beta = arma::randn(75, 1);
arma::rowvec y = beta.t() * X;
LARS lars(true, 0.1, 0.1);
arma::vec betaOpt;
lars.Train(X, y, betaOpt);
// Now, serialize.
LARS xmlLars(false, 0.5, 0.0), binaryLars(true, 1.0, 0.0),
textLars(false, 0.1, 0.1);
// Train textLars.
arma::mat textX = arma::randn(25, 150);
arma::vec textBeta = arma::randn(25, 1);
arma::rowvec textY = textBeta.t() * textX;
arma::vec textBetaOpt;
textLars.Train(textX, textY, textBetaOpt);
SerializeObjectAll(lars, xmlLars, binaryLars, textLars);
// Now, check that predictions are the same.
arma::rowvec pred, xmlPred, textPred, binaryPred;
lars.Predict(X, pred);
xmlLars.Predict(X, xmlPred);
textLars.Predict(X, textPred);
binaryLars.Predict(X, binaryPred);
CheckMatrices(pred, xmlPred, textPred, binaryPred);
}
/**
* Test serialization of the HoeffdingNumericSplit object after binning has
* occured.
*/
BOOST_AUTO_TEST_CASE(HoeffdingNumericSplitTest)
{
using namespace mlpack::tree;
HoeffdingNumericSplit<GiniImpurity> split(3);
// Train until it bins.
for (size_t i = 0; i < 200; ++i)
split.Train(mlpack::math::Random(), mlpack::math::RandInt(3));
HoeffdingNumericSplit<GiniImpurity> xmlSplit(5);
HoeffdingNumericSplit<GiniImpurity> textSplit(7);
for (size_t i = 0; i < 200; ++i)
textSplit.Train(mlpack::math::Random() + 3, 0);
HoeffdingNumericSplit<GiniImpurity> binarySplit(2);
SerializeObjectAll(split, xmlSplit, textSplit, binarySplit);
// Ensure that everything is the same.
BOOST_REQUIRE_EQUAL(split.Bins(), xmlSplit.Bins());
BOOST_REQUIRE_EQUAL(split.Bins(), textSplit.Bins());
BOOST_REQUIRE_EQUAL(split.Bins(), binarySplit.Bins());
double bestSplit, secondBestSplit;
double baseBestSplit, baseSecondBestSplit;
split.EvaluateFitnessFunction(baseBestSplit, baseSecondBestSplit);
xmlSplit.EvaluateFitnessFunction(bestSplit, secondBestSplit);
BOOST_REQUIRE_CLOSE(bestSplit, baseBestSplit, 1e-5);
BOOST_REQUIRE_SMALL(secondBestSplit, 1e-10);
textSplit.EvaluateFitnessFunction(bestSplit, secondBestSplit);
BOOST_REQUIRE_CLOSE(bestSplit, baseBestSplit, 1e-5);
BOOST_REQUIRE_SMALL(secondBestSplit, 1e-10);
binarySplit.EvaluateFitnessFunction(bestSplit, secondBestSplit);
BOOST_REQUIRE_CLOSE(bestSplit, baseBestSplit, 1e-5);
BOOST_REQUIRE_SMALL(secondBestSplit, 1e-10);
arma::Col<size_t> children, xmlChildren, textChildren, binaryChildren;
NumericSplitInfo<double> splitInfo, xmlSplitInfo, textSplitInfo,
binarySplitInfo;
split.Split(children, splitInfo);
xmlSplit.Split(xmlChildren, xmlSplitInfo);
binarySplit.Split(binaryChildren, binarySplitInfo);
textSplit.Split(textChildren, textSplitInfo);
BOOST_REQUIRE_EQUAL(children.size(), xmlChildren.size());
BOOST_REQUIRE_EQUAL(children.size(), textChildren.size());
BOOST_REQUIRE_EQUAL(children.size(), binaryChildren.size());
for (size_t i = 0; i < children.size(); ++i)
{
BOOST_REQUIRE_EQUAL(children[i], xmlChildren[i]);
BOOST_REQUIRE_EQUAL(children[i], textChildren[i]);
BOOST_REQUIRE_EQUAL(children[i], binaryChildren[i]);
}
// Random checks.
for (size_t i = 0; i < 200; ++i)
{
const double random = mlpack::math::Random() * 1.5;
BOOST_REQUIRE_EQUAL(splitInfo.CalculateDirection(random),
xmlSplitInfo.CalculateDirection(random));
BOOST_REQUIRE_EQUAL(splitInfo.CalculateDirection(random),
textSplitInfo.CalculateDirection(random));
BOOST_REQUIRE_EQUAL(splitInfo.CalculateDirection(random),
binarySplitInfo.CalculateDirection(random));
}
}
/**
* Make sure serialization of the HoeffdingNumericSplit object before binning
* occurs is successful.
*/
BOOST_AUTO_TEST_CASE(HoeffdingNumericSplitBeforeBinningTest)
{
using namespace mlpack::tree;
HoeffdingNumericSplit<GiniImpurity> split(3);
// Train but not until it bins.
for (size_t i = 0; i < 50; ++i)
split.Train(mlpack::math::Random(), mlpack::math::RandInt(3));
HoeffdingNumericSplit<GiniImpurity> xmlSplit(5);
HoeffdingNumericSplit<GiniImpurity> textSplit(7);
for (size_t i = 0; i < 200; ++i)
textSplit.Train(mlpack::math::Random() + 3, 0);
HoeffdingNumericSplit<GiniImpurity> binarySplit(2);
SerializeObjectAll(split, xmlSplit, textSplit, binarySplit);
// Ensure that everything is the same.
BOOST_REQUIRE_EQUAL(split.Bins(), xmlSplit.Bins());
BOOST_REQUIRE_EQUAL(split.Bins(), textSplit.Bins());
BOOST_REQUIRE_EQUAL(split.Bins(), binarySplit.Bins());
double baseBestSplit, baseSecondBestSplit;
double bestSplit, secondBestSplit;
split.EvaluateFitnessFunction(baseBestSplit, baseSecondBestSplit);
textSplit.EvaluateFitnessFunction(bestSplit, secondBestSplit);
BOOST_REQUIRE_SMALL(baseBestSplit, 1e-5);
BOOST_REQUIRE_SMALL(baseSecondBestSplit, 1e-5);
BOOST_REQUIRE_SMALL(bestSplit, 1e-5);
BOOST_REQUIRE_SMALL(secondBestSplit, 1e-5);
xmlSplit.EvaluateFitnessFunction(bestSplit, secondBestSplit);
BOOST_REQUIRE_SMALL(bestSplit, 1e-5);
BOOST_REQUIRE_SMALL(secondBestSplit, 1e-5);
binarySplit.EvaluateFitnessFunction(bestSplit, secondBestSplit);
BOOST_REQUIRE_SMALL(bestSplit, 1e-5);
BOOST_REQUIRE_SMALL(secondBestSplit, 1e-5);
}
/**
* Make sure the HoeffdingCategoricalSplit object serializes correctly.
*/
BOOST_AUTO_TEST_CASE(HoeffdingCategoricalSplitTest)
{
using namespace mlpack::tree;
HoeffdingCategoricalSplit<GiniImpurity> split(10, 3);
for (size_t i = 0; i < 50; ++i)
split.Train(mlpack::math::RandInt(10), mlpack::math::RandInt(3));
HoeffdingCategoricalSplit<GiniImpurity> xmlSplit(3, 7);
HoeffdingCategoricalSplit<GiniImpurity> binarySplit(4, 11);
HoeffdingCategoricalSplit<GiniImpurity> textSplit(2, 2);
for (size_t i = 0; i < 10; ++i)
textSplit.Train(mlpack::math::RandInt(2), mlpack::math::RandInt(2));
SerializeObjectAll(split, xmlSplit, textSplit, binarySplit);
BOOST_REQUIRE_EQUAL(split.MajorityClass(), xmlSplit.MajorityClass());
BOOST_REQUIRE_EQUAL(split.MajorityClass(), textSplit.MajorityClass());
BOOST_REQUIRE_EQUAL(split.MajorityClass(), binarySplit.MajorityClass());
double bestSplit, secondBestSplit;
double baseBestSplit, baseSecondBestSplit;
split.EvaluateFitnessFunction(baseBestSplit, baseSecondBestSplit);
xmlSplit.EvaluateFitnessFunction(bestSplit, secondBestSplit);
BOOST_REQUIRE_CLOSE(bestSplit, baseBestSplit, 1e-5);
BOOST_REQUIRE_SMALL(secondBestSplit, 1e-10);
textSplit.EvaluateFitnessFunction(bestSplit, secondBestSplit);
BOOST_REQUIRE_CLOSE(bestSplit, baseBestSplit, 1e-5);
BOOST_REQUIRE_SMALL(secondBestSplit, 1e-10);
binarySplit.EvaluateFitnessFunction(bestSplit, secondBestSplit);
BOOST_REQUIRE_CLOSE(bestSplit, baseBestSplit, 1e-5);
BOOST_REQUIRE_SMALL(secondBestSplit, 1e-10);
arma::Col<size_t> children, xmlChildren, textChildren, binaryChildren;
CategoricalSplitInfo splitInfo(1); // I don't care about this.
split.Split(children, splitInfo);
xmlSplit.Split(xmlChildren, splitInfo);
binarySplit.Split(binaryChildren, splitInfo);
textSplit.Split(textChildren, splitInfo);
BOOST_REQUIRE_EQUAL(children.size(), xmlChildren.size());
BOOST_REQUIRE_EQUAL(children.size(), textChildren.size());
BOOST_REQUIRE_EQUAL(children.size(), binaryChildren.size());
for (size_t i = 0; i < children.size(); ++i)
{
BOOST_REQUIRE_EQUAL(children[i], xmlChildren[i]);
BOOST_REQUIRE_EQUAL(children[i], textChildren[i]);
BOOST_REQUIRE_EQUAL(children[i], binaryChildren[i]);
}
}
/**
* Make sure the HoeffdingTree object serializes correctly before a split has
* occured.
*/
BOOST_AUTO_TEST_CASE(HoeffdingTreeBeforeSplitTest)
{
data::DatasetInfo info(5);
info.MapString<double>("0", 2); // Dimension 1 is categorical.
info.MapString<double>("1", 2);
HoeffdingTree<> split(info, 2, 0.99, 15000, 1);
// Train for 2 samples.
split.Train(arma::vec("0.3 0.4 1 0.6 0.7"), 0);
split.Train(arma::vec("-0.3 0.0 0 0.7 0.8"), 1);
data::DatasetInfo wrongInfo(3);
wrongInfo.MapString<double>("1", 1);
HoeffdingTree<> xmlSplit(wrongInfo, 7, 0.1, 10, 1);
// Force the binarySplit to split.
data::DatasetInfo binaryInfo(2);
binaryInfo.MapString<double>("cat0", 0);
binaryInfo.MapString<double>("cat1", 0);
binaryInfo.MapString<double>("cat0", 1);
HoeffdingTree<> binarySplit(info, 2, 0.95, 5000, 1);
// Feed samples from each class.
for (size_t i = 0; i < 500; ++i)
{
binarySplit.Train(arma::Col<size_t>("0 0"), 0);
binarySplit.Train(arma::Col<size_t>("1 0"), 1);
}
HoeffdingTree<> textSplit(wrongInfo, 11, 0.75, 1000, 1);
SerializeObjectAll(split, xmlSplit, textSplit, binarySplit);
BOOST_REQUIRE_EQUAL(split.SplitDimension(), xmlSplit.SplitDimension());
BOOST_REQUIRE_EQUAL(split.SplitDimension(), binarySplit.SplitDimension());
BOOST_REQUIRE_EQUAL(split.SplitDimension(), textSplit.SplitDimension());
BOOST_REQUIRE_EQUAL(split.MajorityClass(), xmlSplit.MajorityClass());
BOOST_REQUIRE_EQUAL(split.MajorityClass(), binarySplit.MajorityClass());
BOOST_REQUIRE_EQUAL(split.MajorityClass(), textSplit.MajorityClass());
BOOST_REQUIRE_EQUAL(split.SplitCheck(), xmlSplit.SplitCheck());
BOOST_REQUIRE_EQUAL(split.SplitCheck(), binarySplit.SplitCheck());
BOOST_REQUIRE_EQUAL(split.SplitCheck(), textSplit.SplitCheck());
}
/**
* Make sure the HoeffdingTree object serializes correctly after a split has
* occurred.
*/
BOOST_AUTO_TEST_CASE(HoeffdingTreeAfterSplitTest)
{
// Force the split to split.
data::DatasetInfo info(2);
info.MapString<double>("cat0", 0);
info.MapString<double>("cat1", 0);
info.MapString<double>("cat0", 1);
HoeffdingTree<> split(info, 2, 0.95, 5000, 1);
// Feed samples from each class.
for (size_t i = 0; i < 500; ++i)
{
split.Train(arma::Col<size_t>("0 0"), 0);
split.Train(arma::Col<size_t>("1 0"), 1);
}
// Ensure a split has happened.
BOOST_REQUIRE_NE(split.SplitDimension(), size_t(-1));
data::DatasetInfo wrongInfo(3);
wrongInfo.MapString<double>("1", 1);
HoeffdingTree<> xmlSplit(wrongInfo, 7, 0.1, 10, 1);
data::DatasetInfo binaryInfo(5);
binaryInfo.MapString<double>("0", 2); // Dimension 2 is categorical.
binaryInfo.MapString<double>("1", 2);
HoeffdingTree<> binarySplit(binaryInfo, 2, 0.99, 15000, 1);
// Train for 2 samples.
binarySplit.Train(arma::vec("0.3 0.4 1 0.6 0.7"), 0);
binarySplit.Train(arma::vec("-0.3 0.0 0 0.7 0.8"), 1);
HoeffdingTree<> textSplit(wrongInfo, 11, 0.75, 1000, 1);
SerializeObjectAll(split, xmlSplit, textSplit, binarySplit);
BOOST_REQUIRE_EQUAL(split.SplitDimension(), xmlSplit.SplitDimension());
BOOST_REQUIRE_EQUAL(split.SplitDimension(), binarySplit.SplitDimension());
BOOST_REQUIRE_EQUAL(split.SplitDimension(), textSplit.SplitDimension());
// If splitting has already happened, then SplitCheck() should return 0.
BOOST_REQUIRE_EQUAL(split.SplitCheck(), 0);
BOOST_REQUIRE_EQUAL(split.SplitCheck(), xmlSplit.SplitCheck());
BOOST_REQUIRE_EQUAL(split.SplitCheck(), binarySplit.SplitCheck());
BOOST_REQUIRE_EQUAL(split.SplitCheck(), textSplit.SplitCheck());
BOOST_REQUIRE_EQUAL(split.MajorityClass(), xmlSplit.MajorityClass());
BOOST_REQUIRE_EQUAL(split.MajorityClass(), binarySplit.MajorityClass());
BOOST_REQUIRE_EQUAL(split.MajorityClass(), textSplit.MajorityClass());
BOOST_REQUIRE_EQUAL(split.CalculateDirection(arma::vec("0.3 0.4 1 0.6 0.7")),
xmlSplit.CalculateDirection(arma::vec("0.3 0.4 1 0.6 0.7")));
BOOST_REQUIRE_EQUAL(split.CalculateDirection(arma::vec("0.3 0.4 1 0.6 0.7")),
binarySplit.CalculateDirection(arma::vec("0.3 0.4 1 0.6 0.7")));
BOOST_REQUIRE_EQUAL(split.CalculateDirection(arma::vec("0.3 0.4 1 0.6 0.7")),
textSplit.CalculateDirection(arma::vec("0.3 0.4 1 0.6 0.7")));
}
BOOST_AUTO_TEST_CASE(EmptyHoeffdingTreeTest)
{
using namespace mlpack::tree;
data::DatasetInfo info(6);
HoeffdingTree<> tree(info, 2);
HoeffdingTree<> xmlTree(info, 3);
HoeffdingTree<> binaryTree(info, 4);
HoeffdingTree<> textTree(info, 5);
SerializeObjectAll(tree, xmlTree, binaryTree, textTree);
BOOST_REQUIRE_EQUAL(tree.NumChildren(), 0);
BOOST_REQUIRE_EQUAL(xmlTree.NumChildren(), 0);
BOOST_REQUIRE_EQUAL(binaryTree.NumChildren(), 0);
BOOST_REQUIRE_EQUAL(textTree.NumChildren(), 0);
}
/**
* Build a Hoeffding tree, then save it and make sure other trees can classify
* as effectively.
*/
BOOST_AUTO_TEST_CASE(HoeffdingTreeTest)
{
using namespace mlpack::tree;
arma::mat dataset(2, 400);
arma::Row<size_t> labels(400);
for (size_t i = 0; i < 200; ++i)
{
dataset(0, 2 * i) = mlpack::math::RandInt(4);
dataset(1, 2 * i) = mlpack::math::RandInt(2);
dataset(0, 2 * i + 1) = mlpack::math::RandInt(4);
dataset(1, 2 * i + 1) = mlpack::math::RandInt(2) + 2;
labels[2 * i] = 0;
labels[2 * i + 1] = 1;
}
// Make the features categorical.
data::DatasetInfo info(2);
info.MapString<double>("a", 0);
info.MapString<double>("b", 0);
info.MapString<double>("c", 0);
info.MapString<double>("d", 0);
info.MapString<double>("a", 1);
info.MapString<double>("b", 1);
info.MapString<double>("c", 1);
info.MapString<double>("d", 1);
HoeffdingTree<> tree(dataset, info, labels, 2, false /* no batch mode */);
data::DatasetInfo xmlInfo(1);
HoeffdingTree<> xmlTree(xmlInfo, 1);
data::DatasetInfo binaryInfo(5);
HoeffdingTree<> binaryTree(binaryInfo, 6);
data::DatasetInfo textInfo(7);
HoeffdingTree<> textTree(textInfo, 100);
SerializeObjectAll(tree, xmlTree, textTree, binaryTree);
BOOST_REQUIRE_EQUAL(tree.NumChildren(), xmlTree.NumChildren());
BOOST_REQUIRE_EQUAL(tree.NumChildren(), textTree.NumChildren());
BOOST_REQUIRE_EQUAL(tree.NumChildren(), binaryTree.NumChildren());
BOOST_REQUIRE_EQUAL(tree.SplitDimension(), xmlTree.SplitDimension());
BOOST_REQUIRE_EQUAL(tree.SplitDimension(), textTree.SplitDimension());
BOOST_REQUIRE_EQUAL(tree.SplitDimension(), binaryTree.SplitDimension());
for (size_t i = 0; i < tree.NumChildren(); ++i)
{
BOOST_REQUIRE_EQUAL(tree.Child(i).NumChildren(), 0);
BOOST_REQUIRE_EQUAL(xmlTree.Child(i).NumChildren(), 0);
BOOST_REQUIRE_EQUAL(binaryTree.Child(i).NumChildren(), 0);
BOOST_REQUIRE_EQUAL(textTree.Child(i).NumChildren(), 0);
BOOST_REQUIRE_EQUAL(tree.Child(i).SplitDimension(),
xmlTree.Child(i).SplitDimension());
BOOST_REQUIRE_EQUAL(tree.Child(i).SplitDimension(),
textTree.Child(i).SplitDimension());
BOOST_REQUIRE_EQUAL(tree.Child(i).SplitDimension(),
binaryTree.Child(i).SplitDimension());
}
}
/**
* Build a Binary RBM, then save it and make sure the parameters of the
* all the RBM are equal.
*/
BOOST_AUTO_TEST_CASE(BinaryRBMTest)
{
arma::mat data;
size_t hiddenLayerSize = 5;
data.randu(3, 100);
GaussianInitialization gaussian(0, 0.1);
RBM<GaussianInitialization> Rbm(data, gaussian, data.n_rows, hiddenLayerSize,
1, 1, 1, 2, 8, 1, true);
RBM<GaussianInitialization> RbmXml(data, gaussian, data.n_rows,
hiddenLayerSize, 1, 1, 1, 2, 8, 1, true);
RBM<GaussianInitialization> RbmText(data, gaussian, data.n_rows,
hiddenLayerSize, 1, 1, 1, 2, 8, 1, true);
RBM<GaussianInitialization> RbmBinary(data, gaussian, data.n_rows,
hiddenLayerSize, 1, 1, 1, 2, 8, 1, true);
Rbm.Reset();
SerializeObjectAll(Rbm, RbmXml, RbmText, RbmBinary);
CheckMatrices(Rbm.Parameters(), RbmXml.Parameters(), RbmText.Parameters(),
RbmBinary.Parameters());
CheckMatrices(Rbm.VisibleBias(), RbmXml.VisibleBias());
CheckMatrices(Rbm.VisibleBias(), RbmText.VisibleBias());
CheckMatrices(Rbm.VisibleBias(), RbmBinary.VisibleBias());
CheckMatrices(Rbm.HiddenBias(), RbmXml.HiddenBias());
CheckMatrices(Rbm.HiddenBias(), RbmText.HiddenBias());
CheckMatrices(Rbm.HiddenBias(), RbmBinary.HiddenBias());
CheckMatrices(Rbm.Weight(), RbmXml.Weight());
CheckMatrices(Rbm.Weight(), RbmText.Weight());
CheckMatrices(Rbm.Weight(), RbmBinary.Weight());
}
/**
* Build a ssRBM, then save it and make sure the parameters of the
* all the RBM are equal.
*/
BOOST_AUTO_TEST_CASE(ssRBMTest)
{
arma::mat data;
size_t hiddenLayerSize = 5;
data.randu(3, 100);
double slabPenalty = 1;
double tempRadius, radius = arma::norm(data.col(0));
for (size_t i = 1; i < data.n_cols; i++)
{
tempRadius = arma::norm(data.col(i));
if (radius < tempRadius)
radius = tempRadius;
}
size_t poolSize = 1;
GaussianInitialization gaussian(0, 0.1);
RBM<GaussianInitialization, arma::mat, SpikeSlabRBM> Rbm(data, gaussian,
data.n_rows, hiddenLayerSize, 1, 1, 1, poolSize, slabPenalty, radius,
true);
RBM<GaussianInitialization, arma::mat, SpikeSlabRBM> RbmXml(data, gaussian,
data.n_rows, hiddenLayerSize, 1, 1, 1, poolSize, slabPenalty, radius,
true);
RBM<GaussianInitialization, arma::mat, SpikeSlabRBM> RbmText(data, gaussian,
data.n_rows, hiddenLayerSize, 1, 1, 1, poolSize, slabPenalty, radius,
true);
RBM<GaussianInitialization, arma::mat, SpikeSlabRBM> RbmBinary(data, gaussian,
data.n_rows, hiddenLayerSize, 1, 1, 1, poolSize, slabPenalty, radius,
true);
Rbm.Reset();
Rbm.VisiblePenalty().fill(15);
Rbm.SpikeBias().ones();
SerializeObjectAll(Rbm, RbmXml, RbmText, RbmBinary);
CheckMatrices(Rbm.Parameters(), RbmXml.Parameters(), RbmText.Parameters(),
RbmBinary.Parameters());
CheckMatrices(Rbm.VisiblePenalty(), RbmXml.VisiblePenalty());
CheckMatrices(Rbm.VisiblePenalty(), RbmText.VisiblePenalty());
CheckMatrices(Rbm.VisiblePenalty(), RbmBinary.VisiblePenalty());
CheckMatrices(Rbm.SpikeBias(), RbmXml.SpikeBias());
CheckMatrices(Rbm.SpikeBias(), RbmText.SpikeBias());
CheckMatrices(Rbm.SpikeBias(), RbmBinary.SpikeBias());
CheckMatrices(Rbm.Weight(), RbmXml.Weight());
CheckMatrices(Rbm.Weight(), RbmText.Weight());
CheckMatrices(Rbm.Weight(), RbmBinary.Weight());
}
// General ANN serialization test.
template<typename LayerType>
void ANNLayerSerializationTest(LayerType& layer)
{
arma::mat input(5, 100, arma::fill::randu);
arma::mat output(5, 100, arma::fill::randu);
FFN<NegativeLogLikelihood<>, ann::RandomInitialization> model;
model.Add<Linear<>>(input.n_rows, 10);
model.Add<LayerType>(layer);
model.Add<ReLULayer<>>();
model.Add<Linear<>>(10, output.n_rows);
model.Add<LogSoftMax<>>();
optimization::StandardSGD opt(0.1, 1, 5, -100, false);
model.Train(input, output, opt);
arma::mat originalOutput;
model.Predict(input.col(0), originalOutput);
// Now serialize the model.
FFN<NegativeLogLikelihood<>, ann::RandomInitialization> xmlModel, textModel,
binaryModel;
SerializeObjectAll(model, xmlModel, textModel, binaryModel);
// Ensure that predictions are the same.
arma::mat modelOutput, xmlOutput, textOutput, binaryOutput;
model.Predict(input.col(0), modelOutput);
xmlModel.Predict(input.col(0), xmlOutput);
textModel.Predict(input.col(0), textOutput);
binaryModel.Predict(input.col(0), binaryOutput);
CheckMatrices(originalOutput, modelOutput, 1e-5);
CheckMatrices(originalOutput, xmlOutput, 1e-5);
CheckMatrices(originalOutput, textOutput, 1e-5);
CheckMatrices(originalOutput, binaryOutput, 1e-5);
}
/**
* Simple serialization test for batch normalization layer.
*/
BOOST_AUTO_TEST_CASE(BatchNormSerializationTest)
{
BatchNorm<> layer(10);
ANNLayerSerializationTest(layer);
}
/**
* Simple serialization test for layer normalization layer.
*/
BOOST_AUTO_TEST_CASE(LayerNormSerializationTest)
{
LayerNorm<> layer(10);
ANNLayerSerializationTest(layer);
}
BOOST_AUTO_TEST_SUITE_END();