Add adaptive stopping to inner iterations. Change-Id: I83c909b8b87f1320aa30dcc80ac43a63765b9181
diff --git a/include/ceres/solver.h b/include/ceres/solver.h index 0603a30..8f394ea 100644 --- a/include/ceres/solver.h +++ b/include/ceres/solver.h
@@ -98,6 +98,7 @@ linear_solver_ordering = NULL; use_postordering = false; use_inner_iterations = false; + inner_iteration_tolerance = 1e-3; inner_iteration_ordering = NULL; linear_solver_min_num_iterations = 1; linear_solver_max_num_iterations = 500; @@ -443,6 +444,16 @@ // number groups. Each group must be an independent set. ParameterBlockOrdering* inner_iteration_ordering; + // Generally speaking, inner iterations make significant progress + // in the early stages of the solve and then their contribution + // drops down sharply, at which point the time spent doing inner + // iterations is not worth it. + // + // Once the relative decrease in the objective function drops + // below inner_iteration_tolerance, the use of inner iterations + // in subsequent trust region minimizer iterations is disabled. + double inner_iteration_tolerance; + // Minimum number of iterations for which the linear solver should // run, even if the convergence criterion is satisfied. int linear_solver_min_num_iterations;
diff --git a/internal/ceres/minimizer.h b/internal/ceres/minimizer.h index 040ddd9..18ce64d 100644 --- a/internal/ceres/minimizer.h +++ b/internal/ceres/minimizer.h
@@ -89,6 +89,7 @@ jacobian = NULL; callbacks = options.callbacks; inner_iteration_minimizer = NULL; + inner_iteration_tolerance = options.inner_iteration_tolerance; } int max_num_iterations; @@ -141,6 +142,7 @@ SparseMatrix* jacobian; Minimizer* inner_iteration_minimizer; + double inner_iteration_tolerance; }; static bool RunCallbacks(const vector<IterationCallback*> callbacks,
diff --git a/internal/ceres/trust_region_minimizer.cc b/internal/ceres/trust_region_minimizer.cc index 7d4c093..ab0f44b 100644 --- a/internal/ceres/trust_region_minimizer.cc +++ b/internal/ceres/trust_region_minimizer.cc
@@ -191,6 +191,7 @@ } int num_consecutive_invalid_steps = 0; + bool inner_iterations_are_enabled = options.inner_iteration_minimizer != NULL; while (true) { if (!RunCallbacks(options.callbacks, iteration_summary, summary)) { return; @@ -317,7 +318,7 @@ new_cost = numeric_limits<double>::max(); } else { // Check if performing an inner iteration will make it better. - if (options.inner_iteration_minimizer != NULL) { + if (inner_iterations_are_enabled) { const double x_plus_delta_cost = new_cost; Vector inner_iteration_x = x_plus_delta; Solver::Summary inner_iteration_summary; @@ -337,6 +338,18 @@ VLOG(2) << "Inner iteration succeeded; current cost: " << cost << " x_plus_delta_cost: " << x_plus_delta_cost << " new_cost: " << new_cost; + const double inner_iteration_relative_progress = + (x_plus_delta_cost - new_cost) / x_plus_delta_cost; + inner_iterations_are_enabled = + (inner_iteration_relative_progress > + options.inner_iteration_tolerance); + + // Disable inner iterations once the relative improvement + // drops below tolerance. + if (!inner_iterations_are_enabled) { + LOG(INFO) << "Disabling inner iterations. Progress : " + << inner_iteration_relative_progress; + } } } } @@ -356,7 +369,6 @@ return; } - VLOG(2) << "old cost: " << cost << " new cost: " << new_cost; iteration_summary.cost_change = cost - new_cost; const double absolute_function_tolerance = options_.function_tolerance * cost;