[opengm] 16/386: added test-learning, added scaffolds for bundle-optimizer and struct-max-margin, fixed compile errors in hammingloss and testdataset

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Wed Aug 31 08:34:59 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 88f57ab8a90387b5d9bcf1ee56d8761e64f8bac7
Author: Jan Funke <funke at ini.ch>
Date:   Thu Jun 19 14:09:20 2014 -0400

    added test-learning, added scaffolds for bundle-optimizer and struct-max-margin, fixed compile errors in hammingloss and testdataset
---
 include/opengm/learning/bundle-optimizer.hxx    | 207 ++++++++++++++++++++++++
 include/opengm/learning/dataset/testdataset.hxx |  10 +-
 include/opengm/learning/loss/hammingloss.hxx    |   4 +-
 include/opengm/learning/struct-max-margin.hxx   |  91 +++++++++++
 src/unittest/CMakeLists.txt                     |   3 +
 src/unittest/test_learning.cxx                  |  58 +++++++
 6 files changed, 367 insertions(+), 6 deletions(-)

diff --git a/include/opengm/learning/bundle-optimizer.hxx b/include/opengm/learning/bundle-optimizer.hxx
new file mode 100644
index 0000000..dd8de4e
--- /dev/null
+++ b/include/opengm/learning/bundle-optimizer.hxx
@@ -0,0 +1,207 @@
+#pragma once
+#ifndef OPENGM_LEARNING_BUNDLE_OPTIMIZER_HXX
+#define OPENGM_LEARNING_BUNDLE_OPTIMIZER_HXX
+
+namespace opengm {
+
+namespace learning {
+
+enum OptimizerResult {
+
+	// the minimal optimization gap was reached
+	ReachedMinGap,
+
+	// the requested number of steps was exceeded
+	ReachedSteps,
+
+	// something went wrong
+	Error
+};
+
+template <typename ValueType>
+class BundleOptimizer {
+
+public:
+
+	struct Parameter {
+
+		Parameter() :
+			min_gap(1e-5),
+			steps(0) {}
+
+		// stopping criteria of the bundle method optimization
+		ValueType min_gap;
+
+		// the maximal number of steps to perform, 0 = no limit
+		unsigned int steps;
+	};
+
+	/**
+	 * Start the bundle method optimization on the given dataset. It is assumed 
+	 * that the models in the dataset were already augmented by the loss.
+	 */
+	template <typename DatasetType>
+	OptimizerResult optimize(const DatasetType& dataset, typename DatasetType::ModelParameters& w);
+
+private:
+
+	void setupQp();
+
+	void findMinLowerBound(std::vector<ValueType>& w, ValueType& value);
+
+	ValueType dot(const std::vector<ValueType>& a, const std::vector<ValueType>& b);
+};
+
+template <typename T>
+template <typename DatasetType>
+OptimizerResult
+BundleOptimizer<T>::optimize(const DatasetType& dataset, typename DatasetType::ModelParameters& w) {
+
+	setupQp();
+
+	/*
+	  1. w_0 = 0, t = 0
+	  2. t++
+	  3. compute a_t = ∂L(w_t-1)/∂w
+	  4. compute b_t =  L(w_t-1) - <w_t-1,a_t>
+	  5. ℒ_t(w) = max_i <w,a_i> + b_i
+	  6. w_t = argmin λ½|w|² + ℒ_t(w)
+	  7. ε_t = min_i [ λ½|w_i|² + L(w_i) ] - [ λ½|w_t|² + ℒ_t(w_t) ]
+			   ^^^^^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^^
+				 smallest L(w) ever seen    current min of lower bound
+	  8. if ε_t > ε, goto 2
+	  9. return w_t
+	*/
+
+	//std::vector<T> w(_dims, 0.0);
+	//T minValue = std::numeric_limits<T>::infinity();
+
+	//unsigned int t = 0;
+
+	//while (true) {
+
+		//t++;
+
+		//LOG_USER(bundlelog) << std::endl << "----------------- iteration " << t << std::endl;
+
+		//std::vector<T> w_tm1 = w;
+
+		//LOG_DEBUG(bundlelog) << "current w is " << w_tm1 << std::endl;
+
+		//// value of L at current w
+		//T L_w_tm1 = 0.0;
+
+		//// gradient of L at current w
+		//std::vector<T> a_t(_dims, 0.0);
+
+		//// get current value and gradient
+		//_valueGradientCallback(w_tm1, L_w_tm1, a_t);
+
+		//LOG_DEBUG(bundlelog) << "       L(w)              is: " << L_w_tm1 << std::endl;
+		//LOG_ALL(bundlelog)   << "      ∂L(w)/∂            is: " << a_t << std::endl;
+
+		//// update smallest observed value of regularized L
+		//minValue = std::min(minValue, L_w_tm1 + _lambda*0.5*dot(w_tm1, w_tm1));
+
+		//LOG_DEBUG(bundlelog) << " min_i L(w_i) + ½λ|w_i|² is: " << minValue << std::endl;
+
+		//// compute hyperplane offset
+		//T b_t = L_w_tm1 - dot(w_tm1, a_t);
+
+		//LOG_ALL(bundlelog) << "adding hyperplane " << a_t << "*w + " << b_t << std::endl;
+
+		//// update lower bound
+		//_bundleCollector->addHyperplane(a_t, b_t);
+
+		//// minimal value of lower bound
+		//T minLower;
+
+		//// update w and get minimal value
+		//findMinLowerBound(w, minLower);
+
+		//LOG_DEBUG(bundlelog) << " min_w ℒ(w)   + ½λ|w|²   is: " << minLower << std::endl;
+		//LOG_DEBUG(bundlelog) << " w* of ℒ(w)   + ½λ|w|²   is: "  << w << std::endl;
+
+		//// compute gap
+		//T eps_t = minValue - minLower;
+
+		//LOG_USER(bundlelog)  << "          ε   is: " << eps_t << std::endl;
+
+		//// converged?
+		//if (eps_t <= _eps) {
+
+			//if (eps_t >= 0) {
+
+				//LOG_USER(bundlelog) << "converged!" << std::endl;
+
+			//} else {
+
+				//LOG_ERROR(bundlelog) << "ε < 0 -- something went wrong" << std::endl;
+			//}
+
+			//break;
+		//}
+	//}
+
+	return ReachedMinGap;
+}
+
+template <typename T>
+void
+BundleOptimizer<T>::setupQp() {
+
+	/*
+	  w* = argmin λ½|w|² + ξ, s.t. <w,a_i> + b_i ≤ ξ ∀i
+	*/
+
+	//// one variable for each component of w and for ξ
+	//_qpObjective->resize(_dims + 1);
+
+	//// regularizer
+	//for (unsigned int i = 0; i < _dims; i++)
+		//_qpObjective->setQuadraticCoefficient(i, i, 0.5*_lambda);
+
+	//// ξ
+	//_qpObjective->setCoefficient(_dims, 1.0);
+
+	//// we minimize
+	//_qpObjective->setSense(Minimize);
+
+	//// connect pipeline
+	//_qpSolver->setInput("objective", _qpObjective);
+	//_qpSolver->setInput("linear constraints", _bundleCollector->getOutput());
+	//_qpSolver->setInput("parameters", _qpParameters);
+	//_qpSolution = _qpSolver->getOutput("solution");
+}
+
+template <typename T>
+void
+BundleOptimizer<T>::findMinLowerBound(std::vector<T>& w, T& value) {
+
+	// read the solution (pipeline magic!)
+	//for (unsigned int i = 0; i < _dims; i++)
+		//w[i] = (*_qpSolution)[i];
+
+	//value = _qpSolution->getValue();
+}
+
+template <typename T>
+T
+BundleOptimizer<T>::dot(const std::vector<T>& a, const std::vector<T>& b) {
+
+	OPENGM_ASSERT(a.size() == b.size());
+
+	T d = 0.0;
+	typename std::vector<T>::const_iterator i, j;
+	for (i = a.begin(), j = b.begin(); i != a.end(); i++, j++)
+		d += (*i)*(*j);
+
+	return d;
+}
+
+} // learning
+
+} // opengm
+
+#endif // OPENGM_LEARNING_BUNDLE_OPTIMIZER_HXX
+
diff --git a/include/opengm/learning/dataset/testdataset.hxx b/include/opengm/learning/dataset/testdataset.hxx
index a6b6aaf..77537ac 100644
--- a/include/opengm/learning/dataset/testdataset.hxx
+++ b/include/opengm/learning/dataset/testdataset.hxx
@@ -5,6 +5,7 @@
 #include <vector>
 #include <cstdlib>
 
+#include <opengm/functions/learnable/lpotts.hxx>
 
 namespace opengm {
    namespace datasets{
@@ -17,7 +18,7 @@ namespace opengm {
          typedef typename GM::LabelType LabelType; 
          typedef opengm::Parameters<ValueType,IndexType> ModelParameters;
 
-         const GM&                     getModel(const size_t i)  { return gms_[i]; }
+         GM&                           getModel(const size_t i)  { return gms_[i]; }
          const std::vector<LabelType>& getGT(const size_t i)     { return gt_; }
          ModelParameters&              getModelParameters()      { return modelParameters_; }
          size_t                        getNumberOfParameters()   { return 1; }
@@ -45,12 +46,13 @@ namespace opengm {
          gms_.resize(numModels);
          for(size_t m=0; m<numModels; ++m){
             std::srand(m);
-            gms_[m].addVariables(64*64,2);
+			for (int j = 0; j < 64*64; j++)
+				gms_[m].addVariable(2);
             for(size_t y = 0; y < 64; ++y){ 
                for(size_t x = 0; x < 64; ++x) {
                   // function
                   const size_t shape[] = {numberOfLabels};
-                  ExplicitFunction<double> f(shape, shape + 1);
+                  ExplicitFunction<ValueType> f(shape, shape + 1);
                   ValueType val = (double)(gt_[y*64+x]) + (double)(std::rand()) / (double) (RAND_MAX) * 0.75 ;
                   f(0) = std::fabs(val-0);
                   f(1) = std::fabs(val-1);
@@ -62,7 +64,7 @@ namespace opengm {
                }
             }
           
-            opengm::functions::learnable::LPotts<ValueType,IndexType,LabelType> f(modelParameters_,2,std::vector<size_t>(1,0),std::vector<double>(1,1));
+            opengm::functions::learnable::LPotts<ValueType,IndexType,LabelType> f(modelParameters_,2,std::vector<size_t>(1,0),std::vector<ValueType>(1,1));
             typename GM::FunctionIdentifier fid = gms_[m].addFunction(f);      
             for(size_t y = 0; y < 64; ++y){ 
                for(size_t x = 0; x < 64; ++x) {
diff --git a/include/opengm/learning/loss/hammingloss.hxx b/include/opengm/learning/loss/hammingloss.hxx
index 4e543bd..44b99b3 100644
--- a/include/opengm/learning/loss/hammingloss.hxx
+++ b/include/opengm/learning/loss/hammingloss.hxx
@@ -32,11 +32,11 @@ namespace opengm {
       {
 
          for(typename GM::IndexType i=0; i<gm.numberOfVariables(); ++i){
-            typename GM::LabelType numL = gm.numberOFLabels(i);
+            typename GM::LabelType numL = gm.numberOfLabels(i);
             opengm::ExplicitFunction<typename GM::ValueType,typename GM::IndexType, typename GM::LabelType> f(&numL, &(numL)+1,1);
             f(*gt) = 0;
             ++gt;
-            gm.addFactor(gm.addfunction(f), &i, &(i)+1);
+            gm.addFactor(gm.addFunction(f), &i, &(i)+1);
          }
       }
 
diff --git a/include/opengm/learning/struct-max-margin.hxx b/include/opengm/learning/struct-max-margin.hxx
new file mode 100644
index 0000000..47e4d01
--- /dev/null
+++ b/include/opengm/learning/struct-max-margin.hxx
@@ -0,0 +1,91 @@
+#pragma once
+#ifndef OPENGM_LEARNING_STRUCT_MAX_MARGIN_HXX
+#define OPENGM_LEARNING_STRUCT_MAX_MARGIN_HXX
+
+// uncomment when dataset is done
+//#include "dataset.hxx"
+#include "bundle-optimizer.hxx"
+
+namespace opengm {
+
+namespace learning {
+
+template <
+		typename DS,
+		typename LG,
+		typename O = BundleOptimizer<typename DS::ValueType> >
+class StructMaxMargin {
+
+public:
+
+	typedef DS DatasetType;
+	typedef LG LossGeneratorType;
+	typedef O  OptimizerType;
+
+	typedef typename DatasetType::ValueType       ValueType;
+	typedef typename DatasetType::ModelParameters ModelParameters;
+
+	struct Parameter {
+
+		Parameter() :
+			regularizerWeight(1.0) {}
+
+		typedef typename OptimizerType::Parameter OptimizerParameter;
+
+		ValueType regularizerWeight;
+
+		OptimizerParameter optimizerParameter;
+	};
+
+	StructMaxMargin(DatasetType& dataset, const Parameter& parameter = Parameter()) :
+		_dataset(dataset),
+		_parameter(parameter) {}
+
+	Parameter& parameter() { return _parameter; }
+
+	template <typename InferenceType>
+	void learn(typename InferenceType::Parameter& parameter);
+
+	const ModelParameters& getModelParameters() { return _learntParameters; }
+
+private:
+
+	DatasetType& _dataset;
+
+	Parameter _parameter;
+
+	OptimizerType _optimizer;
+
+	ModelParameters _learntParameters;
+};
+
+template <typename DS, typename LG, typename O>
+template <typename InfereneType>
+void
+StructMaxMargin<DS, LG, O>::learn(typename InfereneType::Parameter& infParams) {
+
+	// create a loss-augmented copy of the dataset
+	DS augmentedDataset = _dataset;
+	LossGeneratorType loss;
+	for (unsigned int i = 0; i < augmentedDataset.getNumberOfModels(); i++)
+		loss.addLoss(augmentedDataset.getModel(i), augmentedDataset.getGT(i).begin());
+
+	// minimize structured loss
+	OptimizerResult result = _optimizer.optimize(augmentedDataset, _learntParameters);
+
+	if (result == Error)
+		throw opengm::RuntimeError("optimizer did not succeed");
+
+	if (result == ReachedMinGap)
+		std::cout << "optimization converged to requested precision" << std::endl;
+
+	if (result == ReachedSteps)
+		std::cout << "optimization stopped after " << parameter().optimizerParameter.steps << " iterations" << std::endl;
+}
+
+} // namespace learning
+
+} // namespace opengm
+
+#endif // OPENGM_LEARNING_STRUCT_MAX_MARGIN_HXX
+
diff --git a/src/unittest/CMakeLists.txt b/src/unittest/CMakeLists.txt
index ed5681b..717f505 100644
--- a/src/unittest/CMakeLists.txt
+++ b/src/unittest/CMakeLists.txt
@@ -82,5 +82,8 @@ if(BUILD_TESTING)
       add_test(test-io-hdf5 ${CMAKE_CURRENT_BINARY_DIR}/test-io-hdf5)
    endif()
 
+   ADD_EXECUTABLE(test-learning test_learning.cxx ${headers})
+   add_test(test-learning ${CMAKE_CURRENT_BINARY_DIR}/test-learning) 
+
    add_subdirectory(inference)
 endif()
diff --git a/src/unittest/test_learning.cxx b/src/unittest/test_learning.cxx
new file mode 100644
index 0000000..0b3dadb
--- /dev/null
+++ b/src/unittest/test_learning.cxx
@@ -0,0 +1,58 @@
+#include "opengm/unittests/test.hxx"
+#include "opengm/graphicalmodel/graphicalmodel.hxx"
+#include "opengm/operations/adder.hxx"
+#include "opengm/learning/struct-max-margin.hxx"
+#include "opengm/learning/dataset/testdataset.hxx"
+#include "opengm/learning/loss/hammingloss.hxx"
+#include "opengm/inference/bruteforce.hxx"
+
+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::ModelParameters                              ModelParameters;
+	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 ModelParameters& learntParameters = structMaxMargin.getModelParameters();
+	}
+
+	void run() {
+
+		this->testStructMaxMargin();
+   }
+};
+
+int
+main() {
+   std::cout << "Learning test...  " << std::endl;
+   //{
+   //   LearningTest<float >t;
+   //   t.run();
+   //}
+   {
+      LearningTest<double >t;
+      t.run();
+   }
+   std::cout << "done.." << std::endl;
+   return 0;
+}
+

-- 
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