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

Feature/robust shonan #547

Merged
merged 33 commits into from
Jan 12, 2021
Merged

Feature/robust shonan #547

merged 33 commits into from
Jan 12, 2021

Conversation

lucacarlone
Copy link
Contributor

Added option to use a Huber norm in Shonan Rotation Averaging.
The main changes were:

  • added a useHuber option in Shonan

  • added machinery to convert binaryMeasurements to use a robust noise model

  • adjusted the FrobeniusFactor-related code to cope with possibly robust costs

  • updated the example ShonanAveragingCLI.cpp

Copy link
Member

@dellaert dellaert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! However, please refactor to pass noise model in constructor of binary measurements. Imperative code goes against GTSAM design guidelines.

gtsam/sfm/BinaryMeasurement.h Outdated Show resolved Hide resolved
gtsam/sfm/ShonanAveraging.cpp Outdated Show resolved Hide resolved
gtsam/sfm/ShonanAveraging.h Outdated Show resolved Hide resolved
gtsam/slam/FrobeniusFactor.h Show resolved Hide resolved
.cproject Outdated Show resolved Hide resolved
@varunagrawal
Copy link
Collaborator

@dellaert @lucacarlone I went ahead and addressed the review comments while also removing the goto in the FrobeniusFactor.

@varunagrawal
Copy link
Collaborator

I'm pretty sure I'll never hear the end of it from Frank if I "screw good practice".

@dellaert
Copy link
Member

dellaert commented Nov 9, 2020

I’ll review, but FWIW a goto can be the best choice within a function. It’s bad reputation stems from very long programs with lots of goto statements.

@lucacarlone
Copy link
Contributor Author

@varunagrawal this is great!! it was still on my calendar, but had to push it back for a while. Is there anything else for which you need my help on this branch?

@varunagrawal
Copy link
Collaborator

@lucacarlone I think I've got this covered. The PR was already in great shape to begin with. 😊

I only need folks to review all my PRs now.

@varunagrawal
Copy link
Collaborator

@dellaert gentle reminder 🙂

Copy link
Member

@dellaert dellaert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You asked for my review :-) Sorry about it being late.

auto initial = shonan.initializeRandomly(rng);
auto result = shonan.run(initial);
auto result = shonan.run(initial,pMin);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spacing. Did you lint?

@@ -58,6 +61,10 @@ int main(int argc, char* argv[]) {
"Write solution to the specified file")(
"dimension,d", po::value<int>(&d)->default_value(3),
"Optimize over 2D or 3D rotations")(
"useHuberLoss,h", po::value<bool>(&useHuberLoss)->default_value(false),
"set True to use Huber loss")(
"pMin,p", po::value<int>(&pMin)->default_value(3),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spacing. Please format (only parts that have been changed to avoid large diff) and also lint

auto initial = shonan.initializeRandomly(rng);
auto result = shonan.run(initial);
auto result = shonan.run(initial,pMin);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spacing

: Factor(std::vector<Key>({key1, key2})), measured_(measured),
noiseModel_(model) {}
const SharedNoiseModel &model = nullptr,
bool useHuber = false)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit puzzled about this flag. Why not just give BinaryMeasurement a robust error model as the input argument. I think the code should be re-factored to do just that, construct the noise model out of this class.

@@ -53,6 +53,8 @@ struct GTSAM_EXPORT ShonanAveragingParameters {
double alpha; // weight of anchor-based prior (default 0)
double beta; // weight of Karcher-based prior (default 1)
double gamma; // weight of gauge-fixing factors (default 0)
bool useHuber; // if enabled, the Huber loss is used in the optimization
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spacing for comments is inconsistent. (Format changed part only)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the result of the formatter.

Measurements makeNoiseModelRobust(const Measurements& measurements) const {
Measurements robustMeasurements = measurements;
for (auto &measurement : robustMeasurements) {
measurement = BinaryMeasurement<Rot>(measurement, true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

imperative, without any good reason. Please create a new Measurements variables, reserve space, and emplace_back :-)

size_t n = sigmas.size();
if (n == 1) {
sigma = sigmas(0); // Rot2
goto exit;
exit = true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

restore goto flow. It was good.

const auto &robust = boost::dynamic_pointer_cast<noiseModel::Robust>(
measurement.noiseModel());
if (robust) {
std::cout << "Verification of optimality does not work with robust cost "
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should throw.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This causes the constructor to error out when using the huber noise model. Thoughts?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try remove the autos?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that will help, because there are test cases where we specifically use the huber model and this if-case will succeed. Throwing an exception will cause the test to fail.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can test an exception, no? You can't check whether something prints out. Anyway, printing a warning is not the way to handle a wrong use of the module.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure I understand. Shonan should still be able to work with a robust model, only losing the power to provide the certificate of optimality, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a ‘robust’ flag somewhere, right? If the flag is set, then robust should be allowed without a message. If it is not set it should throw. Printing out a message and then muddling on is not an option in my view.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha. I did misunderstand what you meant, sorry about that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my 2 cents: it might be fishy to just disable the optimality verification when using robust loss, since the user might still think s/he is getting a certifiably-optimal solution. I suggest adding a flag "certifyOptimality" and throw an exception when certifyOptimality = true and we use a robust loss. The flag certifyOptimality might be useful also in the non-robust case since the user might want to disable the certification to save time/computation.

@@ -793,6 +803,12 @@ std::pair<Values, double> ShonanAveraging<d>::run(const Values &initialEstimate,
for (size_t p = pMin; p <= pMax; p++) {
// Optimize until convergence at this level
Qstar = tryOptimizingAt(p, initialSOp);
if(parameters_.useHuber){ // in this case, there is no optimality verification
if(pMin!=pMax)
std::cout << "When using robust norm, Shonan only tests a single rank" << std::endl;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

throw

: ShonanAveraging<3>(parseMeasurements<Rot3>(g2oFile), parameters) {}
: ShonanAveraging<3>(
parameters.useHuber
? makeNoiseModelRobust(parseMeasurements<Rot3>(g2oFile))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a parseMeasurements version that takes the flag rather than complicate the logic of these constructors

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseMeasurements is a part of dataset.cpp whereas makeNoiseModelRobust is of ShonanAveraging.h. This kind of specialization of parseMeasurements seems finicky to me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just add it here as a local helper method

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I came up with something neater: maybeRobust(measurements, useHuber). If useHuber is false, just return the measurements.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also make the constructor more functional, since we can use it across all constructors as simple as maybeRobust(measurements) or maybeRobust(parseMeasurements<Rot3>(g2oFile)).

@lucacarlone
Copy link
Contributor Author

@varunagrawal : let me know if there are pending tasks on this PR that you want me to help with. It seems that except the "throw issue" above, everything else has been solved (thanks!).

@varunagrawal
Copy link
Collaborator

@lucacarlone I am going to need your review since I've made quite a few changes, and wanted to cross-check with you if the overall code is indeed what you expected.

@@ -47,12 +47,16 @@ struct GTSAM_EXPORT ShonanAveragingParameters {
using Anchor = std::pair<size_t, Rot>;

// Paremeters themselves:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Paremeters -> Parameters

also: following GaussNewtonParams, LevenbergMarquardtParams, etc, shouldn't we call this class "ShonanAveragingParams"?

Copy link
Contributor Author

@lucacarlone lucacarlone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mostly looked at the "robust" aspects and everything seems to be in place.

@varunagrawal
Copy link
Collaborator

@dellaert gentle reminder.

gtsam/sfm/ShonanAveraging.h Outdated Show resolved Hide resolved
@varunagrawal varunagrawal merged commit fb44e56 into develop Jan 12, 2021
@varunagrawal varunagrawal deleted the feature/RobustShonan branch January 12, 2021 02:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New proposed feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants