[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