Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose GNC params to python #1239

Merged
merged 24 commits into from
Jul 28, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
aee494a
Expose GNC params to python
amadoantonini Jun 14, 2022
4333f9a
Revert changes to verbosity
amadoantonini Jul 7, 2022
26dd94b
Expose remaining attributes, add tests
amadoantonini Jul 8, 2022
9dd1f8f
Adress review comments
amadoantonini Jul 8, 2022
b4fdda4
Run yapf
amadoantonini Jul 8, 2022
01ea316
Make vector<size_t> opaque
amadoantonini Jul 13, 2022
e381a7c
Revert pybind stl include
amadoantonini Jul 14, 2022
3d37034
wrap custom factor in a separate file
varunagrawal Jul 19, 2022
31d174d
add gtsam namespace
varunagrawal Jul 19, 2022
74678fb
Merge pull request #1 from varunagrawal/custom-factor-separate
amadoantonini Jul 19, 2022
90723d9
Remove pybind/stl.h again
amadoantonini Jul 19, 2022
029631e
Merge branch 'develop' into main
amadoantonini Jul 21, 2022
12b35b4
remove pybind stl.h
varunagrawal Jul 19, 2022
7eb9a95
minor fixes
varunagrawal Jul 22, 2022
c15d288
Merge branch 'develop' into custom-factor-separate
varunagrawal Jul 23, 2022
27951b7
use python 3.7
varunagrawal Jul 26, 2022
4edcb41
remove redundant KeyVector definition
varunagrawal Jul 26, 2022
42bab8f
use KeyVector for GNC inliers & outliers
varunagrawal Jul 26, 2022
1d51c4e
Use new GncParams::IndexVector
varunagrawal Jul 26, 2022
aeceb45
Merge pull request #2 from varunagrawal/gnc/index-vector
amadoantonini Jul 27, 2022
1b614a0
Merge branch 'develop' into main
amadoantonini Jul 27, 2022
a3aaaeb
undo CI changes
varunagrawal Jul 28, 2022
5048886
Merge pull request #3 from varunagrawal/openspacelabs-main
amadoantonini Jul 28, 2022
790403c
revert checkout version
varunagrawal Jul 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gtsam/nonlinear/GncParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class GTSAM_EXPORT GncParams {
std::cout << "knownInliers: " << knownInliers[i] << "\n";
for (size_t i = 0; i < knownOutliers.size(); i++)
std::cout << "knownOutliers: " << knownOutliers[i] << "\n";
baseOptimizerParams.print(str);
baseOptimizerParams.print("Base optimizer params: ");
}
};

Expand Down
29 changes: 28 additions & 1 deletion gtsam/nonlinear/nonlinear.i
Original file line number Diff line number Diff line change
Expand Up @@ -544,12 +544,34 @@ virtual class DoglegParams : gtsam::NonlinearOptimizerParams {
};

#include <gtsam/nonlinear/GncParams.h>
enum GncLossType {
GM /*Geman McClure*/,
TLS /*Truncated least squares*/
};

template<PARAMS>
virtual class GncParams {
GncParams(const PARAMS& baseOptimizerParams);
GncParams();
BaseOptimizerParameters baseOptimizerParams;
GncLossType lossType;
size_t maxIterations;
double muStep;
double relativeCostTol;
double weightsTol;
Verbosity verbosity;
std::vector<size_t> knownInliers;
std::vector<size_t> knownOutliers;

void setLossType(const GncLossType type);
void setMaxIterations(const size_t maxIter);
void setMuStep(const double step);
void setRelativeCostTol(double value);
void setWeightsTol(double value);
void setVerbosityGNC(const This::Verbosity value);
void print(const string& str) const;
void setKnownInliers(const std::vector<size_t>& knownIn);
void setKnownOutliers(const std::vector<size_t>& knownOut);
void print(const string& str = "GncParams: ") const;

enum Verbosity {
SILENT,
Expand Down Expand Up @@ -597,6 +619,11 @@ virtual class GncOptimizer {
GncOptimizer(const gtsam::NonlinearFactorGraph& graph,
const gtsam::Values& initialValues,
const PARAMS& params);
void setInlierCostThresholds(const double inth);
const Vector& getInlierCostThresholds();
void setInlierCostThresholdsAtProbability(const double alpha);
void setWeights(const Vector w);
const Vector& getWeights();
gtsam::Values optimize();
};

Expand Down
3 changes: 2 additions & 1 deletion python/gtsam/preamble/nonlinear.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
* automatic STL binding, such that the raw objects can be accessed in Python.
* Without this they will be automatically converted to a Python object, and all
* mutations on Python side will not be reflected on C++.
*/
*/
#include <pybind11/stl.h>
amadoantonini marked this conversation as resolved.
Show resolved Hide resolved
79 changes: 74 additions & 5 deletions python/gtsam/tests/test_NonlinearOptimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
import unittest

import gtsam
from gtsam import (DoglegOptimizer, DoglegParams, DummyPreconditionerParameters,
GaussNewtonOptimizer, GaussNewtonParams, GncLMParams, GncLMOptimizer,
LevenbergMarquardtOptimizer, LevenbergMarquardtParams, NonlinearFactorGraph,
Ordering, PCGSolverParameters, Point2, PriorFactorPoint2, Values)
from gtsam import (
DoglegOptimizer, DoglegParams, DummyPreconditionerParameters, GaussNewtonOptimizer,
GaussNewtonParams, GncLMParams, GncLossType, GncLMOptimizer, LevenbergMarquardtOptimizer,
LevenbergMarquardtParams, NonlinearFactorGraph, Ordering, PCGSolverParameters, Point2,
PriorFactorPoint2, Values
)
from gtsam.utils.test_case import GtsamTestCase

KEY1 = 1
Expand All @@ -27,7 +29,6 @@

class TestScenario(GtsamTestCase):
"""Do trivial test with three optimizer variants."""

def setUp(self):
"""Set up the optimization problem and ordering"""
# create graph
Expand Down Expand Up @@ -83,16 +84,83 @@ def test_graduated_non_convexity(self):
actual = GncLMOptimizer(self.fg, self.initial_values, gncParams).optimize()
self.assertAlmostEqual(0, self.fg.error(actual))

def test_gnc_params(self):
base_params = LevenbergMarquardtParams()
# Test base params
for base_max_iters in (50, 100):
base_params.setMaxIterations(base_max_iters)
params = GncLMParams(base_params)
self.assertEqual(params.baseOptimizerParams.getMaxIterations(), base_max_iters)

# Test printing
params_str = str(params)
for s in (
"lossType",
"maxIterations",
"muStep",
"relativeCostTol",
"weightsTol",
"verbosity",
):
self.assertTrue(s in params_str)

# Test each parameter
for loss_type in (GncLossType.TLS, GncLossType.GM):
amadoantonini marked this conversation as resolved.
Show resolved Hide resolved
params.setLossType(loss_type) # Default is TLS
self.assertEqual(params.lossType, loss_type)
for max_iter in (1, 10, 100):
params.setMaxIterations(max_iter)
self.assertEqual(params.maxIterations, max_iter)
for mu_step in (1.1, 1.2, 1.5):
params.setMuStep(mu_step)
self.assertEqual(params.muStep, mu_step)
for rel_cost_tol in (1e-5, 1e-6, 1e-7):
params.setRelativeCostTol(rel_cost_tol)
self.assertEqual(params.relativeCostTol, rel_cost_tol)
for weights_tol in (1e-4, 1e-3, 1e-2):
params.setWeightsTol(weights_tol)
self.assertEqual(params.weightsTol, weights_tol)
for i in (0, 1, 2):
verb = GncLMParams.Verbosity(i)
params.setVerbosityGNC(verb)
self.assertEqual(params.verbosity, verb)
for inl in ([], [10], [0, 100]):
params.setKnownInliers(inl)
self.assertEqual(params.knownInliers, inl)
params.knownInliers = []
for out in ([], [1], [0, 10]):
params.setKnownInliers(out)
self.assertEqual(params.knownInliers, out)
params.knownInliers = []

# Test optimizer params
optimizer = GncLMOptimizer(self.fg, self.initial_values, params)
for ict_factor in (0.9, 1.1):
new_ict = ict_factor * optimizer.getInlierCostThresholds()
optimizer.setInlierCostThresholds(new_ict)
self.assertAlmostEqual(optimizer.getInlierCostThresholds(), new_ict)
for w_factor in (0.8, 0.9):
new_weights = w_factor * optimizer.getWeights()
optimizer.setWeights(new_weights)
self.assertAlmostEqual(optimizer.getWeights(), new_weights)
optimizer.setInlierCostThresholdsAtProbability(0.9)
w1 = optimizer.getInlierCostThresholds()
optimizer.setInlierCostThresholdsAtProbability(0.8)
w2 = optimizer.getInlierCostThresholds()
self.assertLess(w2, w1)

def test_iteration_hook(self):
# set up iteration hook to track some testable values
iteration_count = 0
final_error = 0
final_values = None

def iteration_hook(iter, error_before, error_after):
nonlocal iteration_count, final_error, final_values
iteration_count = iter
final_error = error_after
final_values = optimizer.values()

# optimize
params = LevenbergMarquardtParams.CeresDefaults()
params.setOrdering(self.ordering)
Expand All @@ -104,5 +172,6 @@ def iteration_hook(iter, error_before, error_after):
self.assertEqual(self.fg.error(actual), final_error)
self.assertEqual(optimizer.iterations(), iteration_count)


if __name__ == "__main__":
unittest.main()