[opengm] 70/386: fixed gradient computation in struct-max-margin, re-enabled test

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Wed Aug 31 08:35:06 UTC 2016


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch debian/master
in repository opengm.

commit 7194ff36c56e26f92f75280b27ed4756319141c3
Author: Jan Funke <funke at ini.ch>
Date:   Tue Dec 16 16:04:21 2014 +0100

    fixed gradient computation in struct-max-margin, re-enabled test
---
 include/opengm/learning/gradient-accumulator.hxx |  24 +++-
 include/opengm/learning/struct-max-margin.hxx    |  74 +++++++++---
 src/unittest/CMakeLists.txt                      |  10 +-
 src/unittest/test_learning.cxx                   | 143 +++--------------------
 4 files changed, 104 insertions(+), 147 deletions(-)

diff --git a/include/opengm/learning/gradient-accumulator.hxx b/include/opengm/learning/gradient-accumulator.hxx
index fd54314..151967c 100644
--- a/include/opengm/learning/gradient-accumulator.hxx
+++ b/include/opengm/learning/gradient-accumulator.hxx
@@ -14,14 +14,25 @@ class GradientAccumulator {
 public:
 
 	/**
+	 * How to accumulate the gradient on the provided ModelWeights.
+	 */
+	enum Mode {
+
+		Add,
+
+		Subtract
+	};
+
+	/**
 	 * @param gradient
 	 *              ModelWeights reference to store the gradients.
 	 * @param configuration
 	 *              Current configuration of the variables in the model.
 	 */
-	GradientAccumulator(ModelWeights& gradient, ConfigurationType& configuration) :
+	GradientAccumulator(ModelWeights& gradient, const ConfigurationType& configuration, Mode mode = Add) :
 		_gradient(gradient),
-		_configuration(configuration) {
+		_configuration(configuration),
+		_mode(mode) {
 
 		for (size_t i = 0; i < gradient.numberOfWeights(); i++)
 			gradient[i] = 0;
@@ -34,14 +45,19 @@ public:
 
 			int index = function.weightIndex(i);
 
-			_gradient[index] += function.weightGradient(i, _configuration.begin());
+			double g = function.weightGradient(i, _configuration.begin());
+			if (_mode == Add)
+				_gradient[index] += g;
+			else
+				_gradient[index] -= g;
 		}
 	}
 
 private:
 
 	ModelWeights& _gradient;
-	ConfigurationType& _configuration;
+	const ConfigurationType& _configuration;
+	Mode _mode;
 };
 
 }} // namespace opengm::learning
diff --git a/include/opengm/learning/struct-max-margin.hxx b/include/opengm/learning/struct-max-margin.hxx
index a6d0321..e5b3baf 100644
--- a/include/opengm/learning/struct-max-margin.hxx
+++ b/include/opengm/learning/struct-max-margin.hxx
@@ -65,29 +65,77 @@ private:
 
 				typedef std::vector<typename InferenceType::LabelType> ConfigurationType;
 
-				// initialize gradient with zero
+				// initialize gradient and value with zero
+				for (int i = 0; i < gradient.numberOfWeights(); i++)
+					gradient[i] = 0;
+				value = 0;
+
+				// For each model E(y,w), we have to compute the value and 
+				// gradient of
+				//
+				//   max_y E(y',w) - E(y,w) + Δ(y',y)            (1)
+				//   =
+				//   max_y L(y,w)
+				//
+				// where y' is the best-effort solution (also known as 
+				// groundtruth) and w are the current weights. The loss 
+				// augmented model given by the dataset is
+				//
+				//   F(y,w) = E(y,w) - Δ(y',y).
+				//
+				// Let c = E(y',w) be the constant contribution of the 
+				// best-effort solution. (1) is equal to
+				//
+				//  -min_y -c + F(y,w).
+				//
+				// The gradient of the maximand in (1) at y* is
+				//
+				//   ∂L(y,w)/∂w = ∂E(y',w)/∂w -
+				//                ∂E(y,w)/∂w
+				//
+				//              = Σ_θ ∂θ(y'_θ,w)/∂w -
+				//                Σ_θ ∂θ(y_θ,w)/∂w,
+				//
+				// which is a positive gradient contribution for the 
+				// best-effort, and a negative contribution for the maximizer 
+				// y*.
 
 				for (int i = 0; i < _dataset.getNumberOfModels(); i++) {
 
-					// NOT IMPLEMENTED, YET
-					//_dataset.lockModel(i);
-					//const typename DatasetType::GMWITHLOSS& gm = _dataset.getModelWithLoss(i);
-					const typename DatasetType::GMType& gm = _dataset.getModel(i);
+					// get E(x,y) and F(x,y)
+					_dataset.lockModel(i);
+					const typename DatasetType::GMType&     gm  = _dataset.getModel(i);
+					const typename DatasetType::GMWITHLOSS& gml = _dataset.getModelWithLoss(i);
 
+					// set the weights w in E(x,y) and F(x,y)
 					_dataset.getWeights() = w;
 
-					InferenceType inference(gm);
+					// get the best-effort solution y'
+					const ConfigurationType& bestEffort = _dataset.getGT(i);
 
-					ConfigurationType configuration;
+					// compute constant c for current w
+					ValueType c = gm.evaluate(bestEffort);
+
+					// find the minimizer y* of F(y,w)
+					ConfigurationType mostViolated;
+					InferenceType inference(gml);
 					inference.infer();
-					inference.arg(configuration);
+					inference.arg(mostViolated);
+
+					// the optimal value of (1) is now c - F(y*,w)
+					value += c - gml.evaluate(mostViolated);
+
+					// the gradients are
+					typedef GradientAccumulator<Weights, ConfigurationType> GA;
+					GA gaBestEffort(gradient, bestEffort, GA::Add);
+					GA gaMostViolated(gradient, mostViolated, GA::Subtract);
+					for (size_t j = 0; j < gm.numberOfFactors(); j++) {
 
-					GradientAccumulator<Weights, ConfigurationType> ga(gradient, configuration);
-					for (size_t i = 0; i < gm.numberOfFactors(); i++)
-						gm[i].callFunctor(ga);
+						gm[j].callFunctor(gaBestEffort);
+						gm[j].callFunctor(gaMostViolated);
+					}
 
-					// NOT IMPLEMENTED, YET
-					//_dataset.unlockModel(i);
+					_dataset.unlockModel(i);
 				}
 			}
 
diff --git a/src/unittest/CMakeLists.txt b/src/unittest/CMakeLists.txt
index 7eeb1eb..535880b 100644
--- a/src/unittest/CMakeLists.txt
+++ b/src/unittest/CMakeLists.txt
@@ -80,11 +80,11 @@ if(BUILD_TESTING)
    endif()
 
 # Loop forever - fix and move to subfolder learning
-#   if(WITH_GUROBI)
-#     ADD_EXECUTABLE(test-learning test_learning.cxx ${headers})
-#      target_link_libraries(test-learning ${GUROBI_CXX_LIBRARY} ${GUROBI_LIBRARY})
-#     add_test(test-learning ${CMAKE_CURRENT_BINARY_DIR}/test-learning) 
-#   endif()
+  if(WITH_GUROBI)
+    ADD_EXECUTABLE(test-learning test_learning.cxx ${headers})
+     target_link_libraries(test-learning ${GUROBI_CXX_LIBRARY} ${GUROBI_LIBRARY})
+    add_test(test-learning ${CMAKE_CURRENT_BINARY_DIR}/test-learning) 
+  endif()
 
    add_subdirectory(inference)
    add_subdirectory(learning)
diff --git a/src/unittest/test_learning.cxx b/src/unittest/test_learning.cxx
index a101aeb..ec69b10 100644
--- a/src/unittest/test_learning.cxx
+++ b/src/unittest/test_learning.cxx
@@ -12,8 +12,9 @@
 #include <opengm/functions/learnable/sum_of_experts.hxx>
 #include <opengm/learning/struct-max-margin.hxx>
 #include <opengm/learning/loss/hammingloss.hxx>
-#include <opengm/learning/dataset/testdataset.hxx>
-#include <opengm/learning/dataset/testdataset2.hxx>
+//#include <opengm/learning/dataset/testdataset.hxx>
+//#include <opengm/learning/dataset/testdataset2.hxx>
+#include <opengm/learning/dataset/testdatasets.hxx>
 
 
 //*************************************
@@ -22,142 +23,30 @@ typedef size_t IndexType;
 typedef size_t LabelType; 
 typedef opengm::meta::TypeListGenerator<opengm::ExplicitFunction<ValueType,IndexType,LabelType>, opengm::functions::learnable::LPotts<ValueType,IndexType,LabelType>, opengm::functions::learnable::SumOfExperts<ValueType,IndexType,LabelType> >::type FunctionListType;
 typedef opengm::GraphicalModel<ValueType,opengm::Adder, FunctionListType, opengm::DiscreteSpace<IndexType,LabelType> > GM; 
-typedef opengm::datasets::TestDataset<GM>  DS;
-typedef opengm::datasets::TestDataset2<GM> DS2;
+//typedef opengm::datasets::TestDataset<GM>  DS;
+//typedef opengm::datasets::TestDataset2<GM> DS2;
 typedef opengm::learning::HammingLoss     LOSS;
 typedef opengm::ICM<GM,opengm::Minimizer> INF;
+typedef opengm::datasets::TestDataset1<GM,LOSS> DS1;
+typedef opengm::datasets::TestDataset2<GM,LOSS> DS2;
 
 //*************************************
 
-template<class T>
-struct LearningTest{
-
-    typedef T                                                                  ValueType;
-    typedef OPENGM_TYPELIST_2(
-        opengm::ExplicitFunction<T>,
-        opengm::functions::learnable::LPotts<T>)                               FunctionTypeList;
-    typedef opengm::GraphicalModel<ValueType, opengm::Adder, FunctionTypeList> GraphicalModelType;
-    typedef opengm::datasets::TestDataset<GraphicalModelType>                  DatasetType;
-    typedef typename DatasetType::Weights                                      Weights;
-    typedef opengm::learning::HammingLoss                                      LossGeneratorType;
-    typedef opengm::Bruteforce<GraphicalModelType, opengm::Minimizer>          InferenceType;
-
-    void testStructMaxMargin()
-    {
-
-        // create a dataset
-        DatasetType dataset;
-
-        // create a learning algorithm
-        opengm::learning::StructMaxMargin<DatasetType, LossGeneratorType> structMaxMargin(dataset);
-
-        // train
-        typename InferenceType::Parameter infParams;
-        structMaxMargin.template learn<InferenceType>(infParams);
-
-        // get the result
-        const Weights &learntParameters = structMaxMargin.getWeights();
-        std::cout << learntParameters.numberOfWeights() << std::endl;
-        for (size_t i = 0; i < learntParameters.numberOfWeights(); ++i)
-            std::cout << learntParameters[i] << " ";
-        std::cout << std::endl;
-    }
-
-
-    void testStructMaxMargin_prediction()
-    {
-
-        // create a dataset
-        DatasetType dataset;
-
-        std::vector< std::vector<size_t> >GTSolutionVector;
-
-        std::cout << "inference with fixed, arbitrary weights to generate solution" << std::endl;
-
-        Weights weightVector = dataset.getWeights();
-        // std::srand(std::time(0));
-
-        for (int i = 0; i < weightVector.numberOfWeights(); i++)
-        {
-            weightVector.setWeight(i, double(std::rand()) / RAND_MAX * 100);
-            std::cout << weightVector[i] << std::endl;
-        }
-
-        for (size_t modelIndex = 0; modelIndex < dataset.getNumberOfModels(); modelIndex++)
-        {
-
-            std::cout << "starting inference on GM " << modelIndex << std::endl;
-            InferenceType solver(dataset.getModel(modelIndex));
-            solver.infer();
-            std::vector<size_t> sol1;
-            OPENGM_TEST(solver.arg(sol1) == opengm::NORMAL);
-            GTSolutionVector.push_back(sol1);
-            std::cout << "add solution to GM " << modelIndex << std::endl;
-            for (size_t j = 0; j < sol1.size(); j++)
-            {
-                // TODO: find way to set GT weights
-                // dataset.getGT(modelIndex)[j] = sol1[j]; does not work
-            }
-        }
-
-        std::cout << "learn weights (without regularization)" << std::endl;
-        // create a learning algorithm
-        opengm::learning::StructMaxMargin<DatasetType, LossGeneratorType> structMaxMargin(dataset);
-        // train
-        typename InferenceType::Parameter infParams;
-        structMaxMargin.template learn<InferenceType>(infParams);
-
-        // get the result
-        const Weights &learntParameters = structMaxMargin.getWeights();
-        std::cout << learntParameters.numberOfWeights() << std::endl;
-        std::cout << "learntParameters: ";
-        for (size_t i = 0; i < learntParameters.numberOfWeights(); ++i)
-        {
-            std::cout << learntParameters[i] << " ";
-            weightVector.setWeight(i, learntParameters[i]);
-        }
-        std::cout << std::endl;
-
-        std::cout << "inference with new weights" << std::endl;
-        for (size_t modelIndex = 0; modelIndex < dataset.getNumberOfModels(); modelIndex++)
-        {
-            std::cout << "starting inference on GM " << modelIndex << "with learned weights" << std::endl;
-            InferenceType solver(dataset.getModel(modelIndex));
-            solver.infer();
-            std::vector<size_t> sol2;
-            OPENGM_TEST(solver.arg(sol2) == opengm::NORMAL);
-            for (size_t j = 0; j < sol2.size(); j++)
-            {
-                OPENGM_TEST(sol2[j] == GTSolutionVector[modelIndex][j]);
-            }
-        }
-    }
-
-    void run()
-    {
-        this->testStructMaxMargin();
-        this->testStructMaxMargin_prediction();
-    }
-};
 
 int main() {
    std::cout << " Includes are fine :-) " << std::endl; 
-
-    //  {
-    //  LearningTest<double >t;
-    //  t.run();
-    // }
-
-    {
-      DS dataset;
+   {
+      DS1 dataset;
       std::cout << "Dataset includes " << dataset.getNumberOfModels() << " instances and has " << dataset.getNumberOfWeights() << " parameters."<<std::endl;
       
       
-      opengm::learning::StructMaxMargin<DS,LOSS> learner(dataset);
+      opengm::learning::StructMaxMargin<DS1,LOSS>::Parameter para;
+      opengm::learning::StructMaxMargin<DS1,LOSS> learner(dataset,para);
       
       
       INF::Parameter infPara;
       learner.learn<INF>(infPara);
+      
    }
 
    {
@@ -165,10 +54,14 @@ int main() {
       std::cout << "Dataset includes " << dataset.getNumberOfModels() << " instances and has " << dataset.getNumberOfWeights() << " parameters."<<std::endl;
       
       
-      opengm::learning::StructMaxMargin<DS2,LOSS> learner(dataset);
+      opengm::learning::StructMaxMargin<DS2,LOSS>::Parameter para;
+      opengm::learning::StructMaxMargin<DS2,LOSS> learner(dataset,para);
       
       
       INF::Parameter infPara;
       learner.learn<INF>(infPara);
    }
-}
\ No newline at end of file
+
+
+}
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/opengm.git



More information about the debian-science-commits mailing list