Expose line search parameters in Solver::Options.
Change-Id: Ifc52980976e7bac73c8164d80518a5a19db1b79d
diff --git a/docs/source/solving.rst b/docs/source/solving.rst
index 254c120..9f6cb6b 100644
--- a/docs/source/solving.rst
+++ b/docs/source/solving.rst
@@ -819,6 +819,42 @@
rank. The best choice usually requires some problem specific
experimentation.
+.. member:: LineSearchIterpolationType Solver::Options::line_search_interpolation_type
+
+ Default: ``CUBIC``
+
+ Degree of the polynomial used to approximate the objective
+ function. Valid values are ``BISECTION``, ``QUADRATIC`` and
+ ``CUBIC``.
+
+.. member:: double Solver::Options::min_line_search_step_size
+
+ If during the line search, the step size falls below this value, it
+ is truncated to zero.
+
+.. member:: double Solver::Options::armijo_sufficient_decrease
+
+ Solving the line search problem exactly is computationally
+ prohibitive. Fortunately, line search based optimization algorithms
+ can still guarantee convergence if instead of an exact solution,
+ the line search algorithm returns a solution which decreases the
+ value of the objective function sufficiently. More precisely, we
+ are looking for a step size s.t.
+
+ .. math:: f(\text{step_size}) \le f(0) + \text{sufficient_decrease} * [f'(0) * \text{step_size}]
+
+.. member:: double Solver::Options::min_armijo_relative_step_size_change
+
+ In each iteration of the Armijo line search,
+
+ .. math:: \text{new_step_size} \ge \text{min_relative_step_size_change} * \text{step_size}
+
+.. member:: double Solver::Options::max_armijo_relative_step_size_change
+
+ In each iteration of the Armijo line search,
+
+ .. math:: \text{new_step_size} \le \text{max_relative_step_size_change} * \text{step_size}
+
.. member:: TrustRegionStrategyType Solver::Options::trust_region_strategy_type
Default: ``LEVENBERG_MARQUARDT``
diff --git a/include/ceres/solver.h b/include/ceres/solver.h
index a86a586..8bebf9b 100644
--- a/include/ceres/solver.h
+++ b/include/ceres/solver.h
@@ -63,6 +63,12 @@
line_search_type = ARMIJO;
nonlinear_conjugate_gradient_type = FLETCHER_REEVES;
max_lbfgs_rank = 20;
+ line_search_interpolation_type = CUBIC;
+ min_line_search_step_size = 1e-9;
+ armijo_sufficient_decrease = 1e-4;
+ min_armijo_relative_step_size_change = 1e-3;
+ max_armijo_relative_step_size_change = 0.6;
+
trust_region_strategy_type = LEVENBERG_MARQUARDT;
dogleg_type = TRADITIONAL_DOGLEG;
use_nonmonotonic_steps = false;
@@ -172,6 +178,43 @@
// Limited Storage". Mathematics of Computation 35 (151): 773–782.
int max_lbfgs_rank;
+ // Degree of the polynomial used to approximate the objective
+ // function. Valid values are BISECTION, QUADRATIC and CUBIC.
+ //
+ // BISECTION corresponds to pure backtracking search with no
+ // interpolation.
+ LineSearchInterpolationType line_search_interpolation_type;
+
+ // If during the line search, the step_size falls below this
+ // value, it is truncated to zero.
+ double min_line_search_step_size;
+
+ // Armijo line search parameters.
+
+ // Solving the line search problem exactly is computationally
+ // prohibitive. Fortunately, line search based optimization
+ // algorithms can still guarantee convergence if instead of an
+ // exact solution, the line search algorithm returns a solution
+ // which decreases the value of the objective function
+ // sufficiently. More precisely, we are looking for a step_size
+ // s.t.
+ //
+ // f(step_size) <= f(0) + sufficient_decrease * f'(0) * step_size
+ //
+ double armijo_sufficient_decrease;
+
+ // In each iteration of the Armijo line search,
+ //
+ // new_step_size >= min_relative_step_size_change * step_size
+ //
+ double min_armijo_relative_step_size_change;
+
+ // In each iteration of the Armijo line search,
+ //
+ // new_step_size <= max_relative_step_size_change * step_size
+ //
+ double max_armijo_relative_step_size_change;
+
TrustRegionStrategyType trust_region_strategy_type;
// Type of dogleg strategy to use.
@@ -673,6 +716,7 @@
LineSearchDirectionType line_search_direction_type;
LineSearchType line_search_type;
+
int max_lbfgs_rank;
};
diff --git a/include/ceres/types.h b/include/ceres/types.h
index 5edd128..5becb53 100644
--- a/include/ceres/types.h
+++ b/include/ceres/types.h
@@ -332,6 +332,12 @@
FORWARD
};
+enum LineSearchInterpolationType {
+ BISECTION,
+ QUADRATIC,
+ CUBIC
+};
+
const char* LinearSolverTypeToString(LinearSolverType type);
bool StringToLinearSolverType(string value, LinearSolverType* type);
@@ -364,7 +370,14 @@
const char* NonlinearConjugateGradientTypeToString(
NonlinearConjugateGradientType type);
bool StringToNonlinearConjugateGradientType(
- string value, NonlinearConjugateGradientType* type);
+ string value,
+ NonlinearConjugateGradientType* type);
+
+const char* LineSearchInterpolationTypeToString(
+ LineSearchInterpolationType type);
+bool StringToLineSearchInterpolationType(
+ string value,
+ LineSearchInterpolationType* type);
const char* LinearSolverTerminationTypeToString(
LinearSolverTerminationType type);
diff --git a/internal/ceres/line_search.cc b/internal/ceres/line_search.cc
index bc47814..06c823f 100644
--- a/internal/ceres/line_search.cc
+++ b/internal/ceres/line_search.cc
@@ -125,7 +125,7 @@
step_size_is_valid =
function->Evaluate(step_size,
&cost,
- options.interpolation_degree < 2 ? NULL : &gradient);
+ options.interpolation_type != CUBIC ? NULL : &gradient);
while (!step_size_is_valid || cost > (initial_cost
+ options.sufficient_decrease
* initial_gradient
@@ -137,26 +137,22 @@
const double current_step_size = step_size;
// Backtracking search. Each iteration of this loop finds a new point
- if ((options.interpolation_degree == 0) || !step_size_is_valid) {
- // Backtrack by halving the step_size;
+ if ((options.interpolation_type == BISECTION) || !step_size_is_valid) {
step_size *= 0.5;
} else {
// Backtrack by interpolating the function and gradient values
// and minimizing the corresponding polynomial.
-
vector<FunctionSample> samples;
samples.push_back(ValueAndGradientSample(0.0,
initial_cost,
initial_gradient));
- if (options.interpolation_degree == 1) {
+ if (options.interpolation_type == QUADRATIC) {
// Two point interpolation using function values and the
// initial gradient.
samples.push_back(ValueSample(step_size, cost));
- if (options.use_higher_degree_interpolation_when_possible &&
- summary->num_evaluations > 1 &&
- previous_step_size_is_valid) {
+ if (summary->num_evaluations > 1 && previous_step_size_is_valid) {
// Three point interpolation, using function values and the
// initial gradient.
samples.push_back(ValueSample(previous_step_size, previous_cost));
@@ -167,9 +163,7 @@
cost,
gradient));
- if (options.use_higher_degree_interpolation_when_possible &&
- summary->num_evaluations > 1 &&
- previous_step_size_is_valid) {
+ if (summary->num_evaluations > 1 && previous_step_size_is_valid) {
// Three point interpolation using the function values and
// the gradients.
samples.push_back(ValueAndGradientSample(previous_step_size,
@@ -191,7 +185,7 @@
previous_cost = cost;
previous_gradient = gradient;
- if (fabs(initial_gradient) * step_size < options.step_size_threshold) {
+ if (fabs(initial_gradient) * step_size < options.min_step_size) {
LOG(WARNING) << "Line search failed: step_size too small: " << step_size;
return;
}
@@ -200,7 +194,7 @@
step_size_is_valid =
function->Evaluate(step_size,
&cost,
- options.interpolation_degree < 2 ? NULL : &gradient);
+ options.interpolation_type != CUBIC ? NULL : &gradient);
}
summary->optimal_step_size = step_size;
diff --git a/internal/ceres/line_search.h b/internal/ceres/line_search.h
index a2b59b1..5792652 100644
--- a/internal/ceres/line_search.h
+++ b/internal/ceres/line_search.h
@@ -38,6 +38,7 @@
#include <vector>
#include "ceres/internal/eigen.h"
#include "ceres/internal/port.h"
+#include "ceres/types.h"
namespace ceres {
namespace internal {
@@ -60,30 +61,16 @@
struct Options {
Options()
- : interpolation_degree(1),
- use_higher_degree_interpolation_when_possible(false),
+ : interpolation_type(CUBIC),
sufficient_decrease(1e-4),
min_relative_step_size_change(1e-3),
- max_relative_step_size_change(0.6),
- step_size_threshold(1e-9),
+ max_relative_step_size_change(0.9),
+ min_step_size(1e-9),
function(NULL) {}
- // TODO(sameeragarwal): Replace this with enums which are common
- // across various line searches.
- //
// Degree of the polynomial used to approximate the objective
- // function. Valid values are {0, 1, 2}.
- //
- // For Armijo line search
- //
- // 0: Bisection based backtracking search.
- // 1: Quadratic interpolation.
- // 2: Cubic interpolation.
- int interpolation_degree;
-
- // Usually its possible to increase the degree of the
- // interpolation polynomial by storing and using an extra point.
- bool use_higher_degree_interpolation_when_possible;
+ // function.
+ LineSearchInterpolationType interpolation_type;
// Armijo line search parameters.
@@ -110,7 +97,7 @@
// If during the line search, the step_size falls below this
// value, it is truncated to zero.
- double step_size_threshold;
+ double min_step_size;
// The one dimensional function that the line search algorithm
// minimizes.
diff --git a/internal/ceres/line_search_minimizer.cc b/internal/ceres/line_search_minimizer.cc
index 92b7965..24aada3 100644
--- a/internal/ceres/line_search_minimizer.cc
+++ b/internal/ceres/line_search_minimizer.cc
@@ -164,11 +164,19 @@
LineSearchDirection::Create(line_search_direction_options));
LineSearchFunction line_search_function(evaluator);
+
LineSearch::Options line_search_options;
+ line_search_options.interpolation_type =
+ options.line_search_interpolation_type;
+ line_search_options.min_step_size = options.min_line_search_step_size;
+ line_search_options.sufficient_decrease =
+ options.armijo_sufficient_decrease;
+ line_search_options.min_relative_step_size_change =
+ options.min_armijo_relative_step_size_change;
+ line_search_options.max_relative_step_size_change =
+ options.max_armijo_relative_step_size_change;
line_search_options.function = &line_search_function;
- // TODO(sameeragarwal): Make this parameterizable over different
- // line searches.
ArmijoLineSearch line_search;
LineSearch::Summary line_search_summary;
diff --git a/internal/ceres/minimizer.h b/internal/ceres/minimizer.h
index f8f8a96..300d2df 100644
--- a/internal/ceres/minimizer.h
+++ b/internal/ceres/minimizer.h
@@ -88,6 +88,14 @@
nonlinear_conjugate_gradient_type =
options.nonlinear_conjugate_gradient_type;
max_lbfgs_rank = options.max_lbfgs_rank;
+ line_search_interpolation_type =
+ options.line_search_interpolation_type;
+ min_line_search_step_size = options.min_line_search_step_size;
+ armijo_sufficient_decrease = options.armijo_sufficient_decrease;
+ min_armijo_relative_step_size_change =
+ options.min_armijo_relative_step_size_change;
+ max_armijo_relative_step_size_change =
+ options.max_armijo_relative_step_size_change;
evaluator = NULL;
trust_region_strategy = NULL;
jacobian = NULL;
@@ -123,6 +131,12 @@
LineSearchType line_search_type;
NonlinearConjugateGradientType nonlinear_conjugate_gradient_type;
int max_lbfgs_rank;
+ LineSearchInterpolationType line_search_interpolation_type;
+ double min_line_search_step_size;
+ double armijo_sufficient_decrease;
+ double min_armijo_relative_step_size_change;
+ double max_armijo_relative_step_size_change;
+
// List of callbacks that are executed by the Minimizer at the end
// of each iteration.
diff --git a/internal/ceres/types.cc b/internal/ceres/types.cc
index 2e19322..e88cdd6 100644
--- a/internal/ceres/types.cc
+++ b/internal/ceres/types.cc
@@ -193,6 +193,27 @@
return false;
}
+const char* LineSearchInterpolationTypeToString(
+ LineSearchInterpolationType type) {
+ switch (type) {
+ CASESTR(BISECTION);
+ CASESTR(QUADRATIC);
+ CASESTR(CUBIC);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+bool StringToLineSearchInterpolationType(
+ string value,
+ LineSearchInterpolationType* type) {
+ UpperCase(&value);
+ STRENUM(BISECTION);
+ STRENUM(QUADRATIC);
+ STRENUM(CUBIC);
+ return false;
+}
+
const char* NonlinearConjugateGradientTypeToString(
NonlinearConjugateGradientType type) {
switch (type) {