Ceres的Options详解
AutoDiffCostFunction
http://www.ceres-solver.org/nnls_modeling.html?highlight=autodiffcostfunction#autodiffcostfunction
classAutoDiffCostFunction
Defining a CostFunction
or a SizedCostFunction
can be a tedious and error prone especially when computing derivatives. To this end Ceres provides automatic differentiation.
template <typename CostFunctor,
int kNumResiduals, // Number of residuals, or ceres::DYNAMIC.
int... Ns> // Size of each parameter block
class AutoDiffCostFunction : public
SizedCostFunction<kNumResiduals, Ns> {
public:
AutoDiffCostFunction(CostFunctor* functor, ownership = TAKE_OWNERSHIP);
// Ignore the template parameter kNumResiduals and use
// num_residuals instead.
AutoDiffCostFunction(CostFunctor* functor,
int num_residuals,
ownership = TAKE_OWNERSHIP);
};
To get an auto differentiated cost function, you must define a class with a templated operator()
(a functor) that computes the cost function in terms of the template parameter T
. The autodiff framework substitutes appropriate Jet
objects for T
in order to compute the derivative when necessary, but this is hidden, and you should write the function as if T
were a scalar type (e.g. a double-precision floating point number).
The function must write the computed value in the last argument (the only non-const
one) and return true to indicate success.
For example, consider a scalar error e=k−x⊤ye=k−x⊤y, where both xx and yy are two-dimensional vector parameters and kk is a constant. The form of this error, which is the difference between a constant and an expression, is a common pattern in least squares problems. For example, the value x⊤yx⊤y might be the model expectation for a series of measurements, where there is an instance of the cost function for each measurement kk.
The actual cost added to the total problem is e2e2, or (k−x⊤y)2(k−x⊤y)2; however, the squaring is implicitly done by the optimization framework.
To write an auto-differentiable cost function for the above model, first define the object
class MyScalarCostFunctor {
MyScalarCostFunctor(double k): k_(k) {}
template <typename T>
bool operator()(const T* const x , const T* const y, T* e) const {
e[0] = k_ - x[0] * y[0] - x[1] * y[1];
return true;
}
private:
double k_;
};
Note that in the declaration of operator()
the input parameters x
and y
come first, and are passed as const pointers to arrays of T
. If there were three input parameters, then the third input parameter would come after y
. The output is always the last parameter, and is also a pointer to an array. In the example above, e
is a scalar, so only e[0]
is set.
Then given this class definition, the auto differentiated cost function for it can be constructed as follows.
CostFunction* cost_function
= new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
new MyScalarCostFunctor(1.0)); ^ ^ ^
| | |
Dimension of residual ------+ | |
Dimension of x ----------------+ |
Dimension of y -------------------+
In this example, there is usually an instance for each measurement of k
.
In the instantiation above, the template parameters following MyScalarCostFunction
, <1, 2, 2>
describe the functor as computing a 1-dimensional output from two arguments, both 2-dimensional.
By default AutoDiffCostFunction
will take ownership of the cost functor pointer passed to it, ie. will call delete on the cost functor when the AutoDiffCostFunction
itself is deleted. However, this may be undesirable in certain cases, therefore it is also possible to specify DO_NOT_TAKE_OWNERSHIP
as a second argument in the constructor, while passing a pointer to a cost functor which does not need to be deleted by the AutoDiffCostFunction. For example:
MyScalarCostFunctor functor(1.0)
CostFunction* cost_function
= new AutoDiffCostFunction<MyScalarCostFunctor, 1, 2, 2>(
&functor, DO_NOT_TAKE_OWNERSHIP);
AutoDiffCostFunction
also supports cost functions with a runtime-determined number of residuals. For example:
CostFunction* cost_function
= new AutoDiffCostFunction<MyScalarCostFunctor, DYNAMIC, 2, 2>(
new CostFunctorWithDynamicNumResiduals(1.0), ^ ^ ^
runtime_number_of_residuals); <----+ | | |
| | | |
| | | |
Actual number of residuals ------+ | | |
Indicate dynamic number of residuals --------+ | |
Dimension of x ------------------------------------+ |
Dimension of y ---------------------------------------+
WARNING 1 A common beginner’s error when first using AutoDiffCostFunction
is to get the sizing wrong. In particular, there is a tendency to set the template parameters to (dimension of residual, number of parameters) instead of passing a dimension parameter for every parameter block. In the example above, that would be <MyScalarCostFunction, 1, 2>
, which is missing the 2 as the last template argument.