Unit test for NMF added successfully. Validation conditions need to be tuned

This commit is contained in:
mohanrajendran
2012-06-14 22:59:04 +00:00
parent be7a6c39ec
commit a74054a66f
8 changed files with 117 additions and 11 deletions
+1
View File
@@ -5,6 +5,7 @@ cmake_minimum_required(VERSION 2.8)
set(SOURCES
mdistupdate.hpp
mdivupdate.hpp
randominit.hpp
nmf.hpp
nmf_impl.hpp
)
+1 -1
View File
@@ -42,7 +42,7 @@ class MultiplicativeDistanceW
* @param H Encoding matrix to output
*/
inline static void Update(const arma::mat& V,
inline static void Init(const arma::mat& V,
arma::mat& W,
const arma::mat& H)
{
+9 -2
View File
@@ -10,6 +10,7 @@
#include <mlpack/core.hpp>
#include "mdistupdate.hpp"
#include "randominit.hpp"
namespace mlpack {
namespace nmf {
@@ -43,7 +44,8 @@ namespace nmf {
* @tparam HUpdateRule The update rule for calculating H matrix at each
* iteration; @see MultiplicativeDistanceH for an example.
*/
template<typename WUpdateRule = MultiplicativeDistanceW,
template<typename InitializeRule = RandomInitialization,
typename WUpdateRule = MultiplicativeDistanceW,
typename HUpdateRule = MultiplicativeDistanceH>
class NMF
{
@@ -59,13 +61,16 @@ class NMF
* A low residual value denotes that subsequent iterationas are not
* producing much different values of W and H. Once the difference goes
* below the supplied value, the iteration terminates.
* @param Initialize Optional Initialization object for initializing the
* W and H matrices
* @param WUpdate Optional WUpdateRule object; for when the update rule for
* the W vector has states that it needs to store.
* @param HUpdate Optional HUpdateRule object; for when the update rule for
* the H vector has states that it needs to store.
*/
NMF(const size_t maxIterations = 1000,
NMF(const size_t maxIterations = 10000,
const double maxResidue = 1e-10,
const InitializeRule Initialize = InitializeRule(),
const WUpdateRule WUpdate = WUpdateRule(),
const HUpdateRule HUpdate = HUpdateRule());
@@ -85,6 +90,8 @@ class NMF
size_t maxIterations;
//! The maximum residue below which iteration is considered converged
double maxResidue;
//! Instantiated W&H Initialization Rule
InitializeRule Initialize;
//! Instantiated W Update Rule
WUpdateRule WUpdate;
//! Instantiated H Update Rule
+17 -7
View File
@@ -6,6 +6,7 @@
* on the given matrix.
*/
#include "nmf.hpp"
#include <iostream>
namespace mlpack {
namespace nmf {
@@ -13,16 +14,20 @@ namespace nmf {
/**
* Construct the NMF object.
*/
template<typename WUpdateRule,
template<typename InitializeRule,
typename WUpdateRule,
typename HUpdateRule>
NMF<WUpdateRule,
NMF<InitializeRule,
WUpdateRule,
HUpdateRule>::
NMF(const size_t maxIterations,
const double maxResidue,
const InitializeRule Initialize,
const WUpdateRule WUpdate,
const HUpdateRule HUpdate) :
maxIterations(maxIterations),
maxResidue(maxResidue),
Initialize(Initialize),
WUpdate(WUpdate),
HUpdate(HUpdate)
{
@@ -43,20 +48,23 @@ NMF(const size_t maxIterations,
* @param H Encoding matrix to output
* @param r Rank r of the factorization
*/
template<typename WUpdateRule,
template<typename InitializeRule,
typename WUpdateRule,
typename HUpdateRule>
void NMF<WUpdateRule,
void NMF<InitializeRule,
WUpdateRule,
HUpdateRule>::
Apply(const arma::mat& V, arma::mat& W, arma::mat& H, size_t& r) const
{
size_t n = V.n_rows;
size_t m = V.n_cols;
// old and new product WH for residue checking
arma::mat WHold,WH,diff;
// Allocate random values to the starting iteration
W.randu(n,r);
H.randu(r,m);
// Intialize W and H
Initialize.Init(V,W,H,r);
// Store the original calculated value for residue checking
WHold = W*H;
@@ -77,6 +85,8 @@ Apply(const arma::mat& V, arma::mat& W, arma::mat& H, size_t& r) const
diff = diff%diff;
residue = accu(diff)/(double)(n*m);
WHold = WH;
Log::Debug << "Iteration: " << iteration << " Residue: "
<< residue << std::endl;
iteration++;
+1 -1
View File
@@ -25,7 +25,7 @@ PARAM_STRING_REQ("H_output_file", "File to save the calculated H matrix to.",
"h");
PARAM_INT_REQ("rank", "Rank of the factorization.", "r");
PARAM_INT("max_iterations", "Number of iterations before NMF terminates",
"m", 1000);
"m", 10000);
PARAM_DOUBLE("max_residue", "The maximum root mean square allowed below which "
"the program termiates", "e", 1e-10);
+43
View File
@@ -0,0 +1,43 @@
/**
* @file randominit.hpp
* @author Mohan Rajendran
*
* Intialization rule for the Non-negative Matrix Factorization. This simple
* initialization is performed by assigning a random matrix to W and H
*
*/
#ifndef __MLPACK_METHODS_NMF_RANDOMINIT_HPP
#define __MLPACK_METHODS_NMF_RANDOMINIT_HPP
#include <mlpack/core.hpp>
namespace mlpack {
namespace nmf {
class RandomInitialization
{
public:
// Empty constructor required for the InitializeRule template
RandomInitialization() { }
inline static void Init(const arma::mat& V,
arma::mat& W,
arma::mat& H,
const size_t& r)
{
// Simple inplementation. This can be left here.
size_t n = V.n_rows;
size_t m = V.n_cols;
// Intialize to random values
W.randu(n,r);
H.randu(r,m);
}
}; // Class RandomInitialization
}; // namespace nmf
}; // namespace mlpack
#endif
+1
View File
@@ -24,6 +24,7 @@ add_executable(mlpack_test
max_ip_test.cpp
nbc_test.cpp
nca_test.cpp
nmf_test.cpp
pca_test.cpp
radical_test.cpp
range_search_test.cpp
+44
View File
@@ -0,0 +1,44 @@
/**
* @file nmf_test.cpp
* @author Mohan Rajendran
*
* Test file for NMF class.
*/
#include <mlpack/core.hpp>
#include <mlpack/methods/nmf/nmf.hpp>
#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"
BOOST_AUTO_TEST_SUITE(NMFTest);
using namespace std;
using namespace arma;
using namespace mlpack;
using namespace mlpack::nmf;
/**
* Check the if the product of the calculated factorization is close to the
* input matrix.
*/
BOOST_AUTO_TEST_CASE(NMFTest)
{
mat V = randu<mat>(5,5);
size_t r = 4;
mat W,H;
NMF<> nmf;
nmf.Apply(V,W,H,r);
mat WH = W*H;
V.print("V=");
WH.print("WH=");
for (size_t row = 0; row < 5; row++)
for (size_t col = 0; col < 5; col++)
BOOST_REQUIRE_CLOSE(V(row, col), WH(row, col), 5);
}
BOOST_AUTO_TEST_SUITE_END();