[mlpack-svn] r13820 - mlpack/trunk/src/mlpack/tests

fastlab-svn at coffeetalk-1.cc.gatech.edu fastlab-svn at coffeetalk-1.cc.gatech.edu
Thu Nov 1 12:58:44 EDT 2012


Author: rcurtin
Date: 2012-11-01 12:58:42 -0400 (Thu, 01 Nov 2012)
New Revision: 13820

Modified:
   mlpack/trunk/src/mlpack/tests/nca_test.cpp
Log:
Tests for the separable evaluation and gradient of the NCA softmax error
function.


Modified: mlpack/trunk/src/mlpack/tests/nca_test.cpp
===================================================================
--- mlpack/trunk/src/mlpack/tests/nca_test.cpp	2012-11-01 16:58:23 UTC (rev 13819)
+++ mlpack/trunk/src/mlpack/tests/nca_test.cpp	2012-11-01 16:58:42 UTC (rev 13820)
@@ -138,6 +138,110 @@
   BOOST_REQUIRE_SMALL(gradient(1, 1), 1e-5);
 }
 
+/**
+ * Ensure the separable objective function is right.
+ */
+BOOST_AUTO_TEST_CASE(SoftmaxSeparableObjective)
+{
+  // Useful but simple dataset with six points and two classes.
+  arma::mat data    = "-0.1 -0.1 -0.1  0.1  0.1  0.1;"
+                      " 1.0  0.0 -1.0  1.0  0.0 -1.0 ";
+  arma::uvec labels = " 0    0    0    1    1    1   ";
+
+  SoftmaxErrorFunction<SquaredEuclideanDistance> sef(data, labels);
+
+  // Results painstakingly calculated by hand by rcurtin (recorded forever in
+  // his notebook).  As a result of lack of precision of the by-hand result, the
+  // tolerance is fairly high.
+  arma::mat coordinates = arma::eye<arma::mat>(2, 2);
+  BOOST_REQUIRE_CLOSE(sef.Evaluate(coordinates, 0), -0.22480, 0.01);
+  BOOST_REQUIRE_CLOSE(sef.Evaluate(coordinates, 1), -0.30613, 0.01);
+  BOOST_REQUIRE_CLOSE(sef.Evaluate(coordinates, 2), -0.22480, 0.01);
+  BOOST_REQUIRE_CLOSE(sef.Evaluate(coordinates, 3), -0.22480, 0.01);
+  BOOST_REQUIRE_CLOSE(sef.Evaluate(coordinates, 4), -0.30613, 0.01);
+  BOOST_REQUIRE_CLOSE(sef.Evaluate(coordinates, 5), -0.22480, 0.01);
+}
+
+/**
+ * Ensure the optimal separable objective function is right.
+ */
+BOOST_AUTO_TEST_CASE(OptimalSoftmaxSeparableObjective)
+{
+  // Simple optimal dataset.
+  arma::mat data    = " 500  500 -500 -500;"
+                      "   1    0    1    0 ";
+  arma::uvec labels = "   0    0    1    1 ";
+
+  SoftmaxErrorFunction<SquaredEuclideanDistance> sef(data, labels);
+
+  arma::mat coordinates = arma::eye<arma::mat>(2, 2);
+
+  // Use a very close tolerance for optimality; we need to be sure this function
+  // gives optimal results correctly.
+  BOOST_REQUIRE_CLOSE(sef.Evaluate(coordinates, 0), -1.0, 1e-10);
+  BOOST_REQUIRE_CLOSE(sef.Evaluate(coordinates, 1), -1.0, 1e-10);
+  BOOST_REQUIRE_CLOSE(sef.Evaluate(coordinates, 2), -1.0, 1e-10);
+  BOOST_REQUIRE_CLOSE(sef.Evaluate(coordinates, 3), -1.0, 1e-10);
+}
+
+/**
+ * Ensure the separable gradient is right.
+ */
+BOOST_AUTO_TEST_CASE(SoftmaxSeparableGradient)
+{
+  // Useful but simple dataset with six points and two classes.
+  arma::mat data    = "-0.1 -0.1 -0.1  0.1  0.1  0.1;"
+                      " 1.0  0.0 -1.0  1.0  0.0 -1.0 ";
+  arma::uvec labels = " 0    0    0    1    1    1   ";
+
+  SoftmaxErrorFunction<SquaredEuclideanDistance> sef(data, labels);
+
+  arma::mat coordinates = arma::eye<arma::mat>(2, 2);
+  arma::mat gradient(2, 2);
+
+  sef.Gradient(coordinates, 0, gradient);
+
+  BOOST_REQUIRE_CLOSE(gradient(0, 0), -2.0 * 0.0069708, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(0, 1), -2.0 * -0.0101707, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(1, 0), -2.0 * -0.0101707, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(1, 1), -2.0 * -0.14359, 0.01);
+
+  sef.Gradient(coordinates, 1, gradient);
+
+  BOOST_REQUIRE_CLOSE(gradient(0, 0), -2.0 * 0.008496, 0.01);
+  BOOST_REQUIRE_SMALL(gradient(0, 1), 1e-5);
+  BOOST_REQUIRE_SMALL(gradient(1, 0), 1e-5);
+  BOOST_REQUIRE_CLOSE(gradient(1, 1), -2.0 * -0.12238, 0.01);
+
+  sef.Gradient(coordinates, 2, gradient);
+
+  BOOST_REQUIRE_CLOSE(gradient(0, 0), -2.0 * 0.0069708, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(0, 1), -2.0 * 0.0101707, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(1, 0), -2.0 * 0.0101707, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(1, 1), -2.0 * -0.1435886, 0.01);
+
+  sef.Gradient(coordinates, 3, gradient);
+
+  BOOST_REQUIRE_CLOSE(gradient(0, 0), -2.0 * 0.0069708, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(0, 1), -2.0 * 0.0101707, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(1, 0), -2.0 * 0.0101707, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(1, 1), -2.0 * -0.1435886, 0.01);
+
+  sef.Gradient(coordinates, 4, gradient);
+
+  BOOST_REQUIRE_CLOSE(gradient(0, 0), -2.0 * 0.008496, 0.01);
+  BOOST_REQUIRE_SMALL(gradient(0, 1), 1e-5);
+  BOOST_REQUIRE_SMALL(gradient(1, 0), 1e-5);
+  BOOST_REQUIRE_CLOSE(gradient(1, 1), -2.0 * -0.12238, 0.01);
+
+  sef.Gradient(coordinates, 5, gradient);
+
+  BOOST_REQUIRE_CLOSE(gradient(0, 0), -2.0 * 0.0069708, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(0, 1), -2.0 * -0.0101707, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(1, 0), -2.0 * -0.0101707, 0.01);
+  BOOST_REQUIRE_CLOSE(gradient(1, 1), -2.0 * -0.1435886, 0.01);
+}
+
 //
 // Tests for the NCA algorithm.
 //
@@ -153,7 +257,8 @@
                       " 1.0  0.0 -1.0  1.0  0.0 -1.0 ";
   arma::uvec labels = " 0    0    0    1    1    1   ";
 
-  NCA<SquaredEuclideanDistance> nca(data, labels);
+  // Huge learning rate because this is so simple.
+  NCA<SquaredEuclideanDistance> nca(data, labels, 1.2, 300000, 0);
 
   arma::mat outputMatrix;
   nca.LearnDistance(outputMatrix);
@@ -169,10 +274,10 @@
   // finalObj must be less than initObj.
   BOOST_REQUIRE_LT(finalObj, initObj);
   // Verify that final objective is optimal.
-  BOOST_REQUIRE_CLOSE(finalObj, -6.0, 1e-8);
+  BOOST_REQUIRE_CLOSE(finalObj, -6.0, 1e-5);
   // The solution is not unique, so the best we can do is ensure the gradient
   // norm is close to 0.
-  BOOST_REQUIRE_LT(arma::norm(finalGradient, 2), 1e-10);
+  BOOST_REQUIRE_LT(arma::norm(finalGradient, 2), 1e-6);
 }
 
 BOOST_AUTO_TEST_SUITE_END();




More information about the mlpack-svn mailing list