-
Notifications
You must be signed in to change notification settings - Fork 802
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
Conversation
…ved hard-coded sigma in FrobeniusFactor
There was a problem hiding this 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.
@dellaert @lucacarlone I went ahead and addressed the review comments while also removing the |
I'm pretty sure I'll never hear the end of it from Frank if I "screw good practice". |
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. |
@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? |
@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. |
@dellaert gentle reminder 🙂 |
There was a problem hiding this 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.
examples/ShonanAveragingCLI.cpp
Outdated
auto initial = shonan.initializeRandomly(rng); | ||
auto result = shonan.run(initial); | ||
auto result = shonan.run(initial,pMin); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spacing. Did you lint?
examples/ShonanAveragingCLI.cpp
Outdated
@@ -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), |
There was a problem hiding this comment.
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
examples/ShonanAveragingCLI.cpp
Outdated
auto initial = shonan.initializeRandomly(rng); | ||
auto result = shonan.run(initial); | ||
auto result = shonan.run(initial,pMin); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spacing
gtsam/sfm/BinaryMeasurement.h
Outdated
: Factor(std::vector<Key>({key1, key2})), measured_(measured), | ||
noiseModel_(model) {} | ||
const SharedNoiseModel &model = nullptr, | ||
bool useHuber = false) |
There was a problem hiding this comment.
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.
gtsam/sfm/ShonanAveraging.h
Outdated
@@ -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 |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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.
gtsam/sfm/ShonanAveraging.h
Outdated
Measurements makeNoiseModelRobust(const Measurements& measurements) const { | ||
Measurements robustMeasurements = measurements; | ||
for (auto &measurement : robustMeasurements) { | ||
measurement = BinaryMeasurement<Rot>(measurement, true); |
There was a problem hiding this comment.
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 :-)
gtsam/slam/FrobeniusFactor.cpp
Outdated
size_t n = sigmas.size(); | ||
if (n == 1) { | ||
sigma = sigmas(0); // Rot2 | ||
goto exit; | ||
exit = true; |
There was a problem hiding this comment.
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.
gtsam/sfm/ShonanAveraging.cpp
Outdated
const auto &robust = boost::dynamic_pointer_cast<noiseModel::Robust>( | ||
measurement.noiseModel()); | ||
if (robust) { | ||
std::cout << "Verification of optimality does not work with robust cost " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should throw.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try remove the autos?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
gtsam/sfm/ShonanAveraging.cpp
Outdated
@@ -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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw
gtsam/sfm/ShonanAveraging.cpp
Outdated
: ShonanAveraging<3>(parseMeasurements<Rot3>(g2oFile), parameters) {} | ||
: ShonanAveraging<3>( | ||
parameters.useHuber | ||
? makeNoiseModelRobust(parseMeasurements<Rot3>(g2oFile)) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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))
.
@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!). |
@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. |
gtsam/sfm/ShonanAveraging.h
Outdated
@@ -47,12 +47,16 @@ struct GTSAM_EXPORT ShonanAveragingParameters { | |||
using Anchor = std::pair<size_t, Rot>; | |||
|
|||
// Paremeters themselves: |
There was a problem hiding this comment.
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"?
There was a problem hiding this 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.
@dellaert gentle reminder. |
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