Add _impl.hpp file and serialization.
This commit is contained in:
@@ -189,6 +189,10 @@ class LocalCoordinateCoding
|
||||
//! Modify the objective tolerance.
|
||||
double& Tolerance() { return tolerance; }
|
||||
|
||||
//! Serialize the model.
|
||||
template<typename Archive>
|
||||
void Serialize(Archive& ar, const unsigned int /* version */);
|
||||
|
||||
private:
|
||||
//! Number of atoms in dictionary.
|
||||
size_t atoms;
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @file lcc_impl.hpp
|
||||
* @author Nishant Mehta
|
||||
*
|
||||
* Implementation of Local Coordinate Coding
|
||||
*/
|
||||
#ifndef __MLPACK_METHODS_LOCAL_COORDINATE_CODING_LCC_IMPL_HPP
|
||||
#define __MLPACK_METHODS_LOCAL_COORDINATE_CODING_LCC_IMPL_HPP
|
||||
|
||||
// In case it hasn't been included yet.
|
||||
#include "lcc.hpp"
|
||||
|
||||
namespace mlpack {
|
||||
namespace lcc {
|
||||
|
||||
template<typename DictionaryInitializer>
|
||||
LocalCoordinateCoding::LocalCoordinateCoding(
|
||||
const arma::mat& data,
|
||||
const size_t atoms,
|
||||
const double lambda,
|
||||
const size_t maxIterations,
|
||||
const double tolerance,
|
||||
const DictionaryInitializer& initializer) :
|
||||
atoms(atoms),
|
||||
lambda(lambda),
|
||||
maxIterations(maxIterations),
|
||||
tolerance(tolerance)
|
||||
{
|
||||
// Train the model.
|
||||
Train(data, initializer);
|
||||
}
|
||||
|
||||
template<typename DictionaryInitializer>
|
||||
void LocalCoordinateCoding::Train(
|
||||
const arma::mat& data,
|
||||
const DictionaryInitializer& initializer)
|
||||
{
|
||||
Timer::Start("local_coordinate_coding");
|
||||
|
||||
// Initialize the dictionary.
|
||||
initializer.Initialize(data, atoms, dictionary);
|
||||
|
||||
double lastObjVal = DBL_MAX;
|
||||
|
||||
// Take the initial coding step, which has to happen before entering the main
|
||||
// loop.
|
||||
Log::Info << "Initial Coding Step." << std::endl;
|
||||
|
||||
arma::mat codes;
|
||||
Encode(data, codes);
|
||||
arma::uvec adjacencies = find(codes);
|
||||
|
||||
Log::Info << " Sparsity level: " << 100.0 * ((double)(adjacencies.n_elem)) /
|
||||
((double)(atoms * data.n_cols)) << "%.\n";
|
||||
Log::Info << " Objective value: " << Objective(data, codes, adjacencies)
|
||||
<< "." << std::endl;
|
||||
|
||||
for (size_t t = 1; t != maxIterations; t++)
|
||||
{
|
||||
Log::Info << "Iteration " << t << " of " << maxIterations << "."
|
||||
<< std::endl;
|
||||
|
||||
// First step: optimize the dictionary.
|
||||
Log::Info << "Performing dictionary step..." << std::endl;
|
||||
OptimizeDictionary(data, codes, adjacencies);
|
||||
double dsObjVal = Objective(data, codes, adjacencies);
|
||||
Log::Info << " Objective value: " << dsObjVal << "." << std::endl;
|
||||
|
||||
// Second step: perform the coding.
|
||||
Log::Info << "Performing coding step..." << std::endl;
|
||||
Encode(data, codes);
|
||||
adjacencies = find(codes);
|
||||
Log::Info << " Sparsity level: " << 100.0 * ((double) (adjacencies.n_elem))
|
||||
/ ((double)(atoms * data.n_cols)) << "%.\n";
|
||||
|
||||
// Terminate if the objective increased in the coding step.
|
||||
double curObjVal = Objective(data, codes, adjacencies);
|
||||
if (curObjVal > dsObjVal)
|
||||
{
|
||||
Log::Warn << "Objective increased in coding step! Terminating."
|
||||
<< std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
// Find the new objective value and improvement so we can check for
|
||||
// convergence.
|
||||
double improvement = lastObjVal - curObjVal;
|
||||
Log::Info << "Objective value: " << curObjVal << " (improvement "
|
||||
<< std::scientific << improvement << ")." << std::endl;
|
||||
|
||||
if (improvement < tolerance)
|
||||
{
|
||||
Log::Info << "Converged within tolerance " << tolerance << ".\n";
|
||||
break;
|
||||
}
|
||||
|
||||
lastObjVal = curObjVal;
|
||||
}
|
||||
|
||||
Timer::Stop("local_coordinate_coding");
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
void LocalCoordinateCoding::Serialize(Archive& ar,
|
||||
const unsigned int /* version */)
|
||||
{
|
||||
ar & data::CreateNVP(atoms, "atoms");
|
||||
ar & data::CreateNVP(dictionary, "dictionary");
|
||||
ar & data::CreateNVP(lambda, "lambda");
|
||||
ar & data::CreateNVP(maxIterations, "maxIterations");
|
||||
ar & data::CreateNVP(tolerance, "tolerance");
|
||||
}
|
||||
|
||||
} // namespace lcc
|
||||
} // namespace mlpack
|
||||
|
||||
#endif
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include "old_boost_test_definitions.hpp"
|
||||
#include "serialization.hpp"
|
||||
|
||||
using namespace arma;
|
||||
using namespace mlpack;
|
||||
@@ -117,4 +118,47 @@ BOOST_AUTO_TEST_CASE(LocalCoordinateCodingTestDictionaryStep)
|
||||
BOOST_REQUIRE_SMALL(norm(grad, "fro"), tol);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SerializationTest)
|
||||
{
|
||||
mat X = randu<mat>(100, 100);
|
||||
size_t nAtoms = 25;
|
||||
|
||||
LocalCoordinateCoding lcc(nAtoms, 0.05);
|
||||
lcc.Train(X);
|
||||
|
||||
mat Y = randu<mat>(100, 200);
|
||||
mat codes;
|
||||
lcc.Encode(Y, codes);
|
||||
|
||||
LocalCoordinateCoding lccXml(50, 0.1), lccText(12, 0.0), lccBinary(0, 0.0);
|
||||
SerializeObjectAll(lcc, lccXml, lccText, lccBinary);
|
||||
|
||||
CheckMatrices(lcc.Dictionary(), lccXml.Dictionary(), lccText.Dictionary(),
|
||||
lccBinary.Dictionary());
|
||||
|
||||
mat xmlCodes, textCodes, binaryCodes;
|
||||
lccXml.Encode(Y, xmlCodes);
|
||||
lccText.Encode(Y, textCodes);
|
||||
lccBinary.Encode(Y, binaryCodes);
|
||||
|
||||
CheckMatrices(codes, xmlCodes, textCodes, binaryCodes);
|
||||
|
||||
// Check the parameters, too.
|
||||
BOOST_REQUIRE_EQUAL(lcc.Atoms(), lccXml.Atoms());
|
||||
BOOST_REQUIRE_EQUAL(lcc.Atoms(), lccText.Atoms());
|
||||
BOOST_REQUIRE_EQUAL(lcc.Atoms(), lccBinary.Atoms());
|
||||
|
||||
BOOST_REQUIRE_CLOSE(lcc.Tolerance(), lccXml.Tolerance(), 1e-5);
|
||||
BOOST_REQUIRE_CLOSE(lcc.Tolerance(), lccText.Tolerance(), 1e-5);
|
||||
BOOST_REQUIRE_CLOSE(lcc.Tolerance(), lccBinary.Tolerance(), 1e-5);
|
||||
|
||||
BOOST_REQUIRE_CLOSE(lcc.Lambda(), lccXml.Lambda(), 1e-5);
|
||||
BOOST_REQUIRE_CLOSE(lcc.Lambda(), lccText.Lambda(), 1e-5);
|
||||
BOOST_REQUIRE_CLOSE(lcc.Lambda(), lccBinary.Lambda(), 1e-5);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(lcc.MaxIterations(), lccXml.MaxIterations());
|
||||
BOOST_REQUIRE_EQUAL(lcc.MaxIterations(), lccText.MaxIterations());
|
||||
BOOST_REQUIRE_EQUAL(lcc.MaxIterations(), lccBinary.MaxIterations());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END();
|
||||
|
||||
Reference in New Issue
Block a user