1. Ceres Solver 是什么
Ceres 可以解决以下形式的边界约束鲁棒化非线性最小二乘问题:
给定初始值,通过优化算法,得到最优解。
其中, f i f_i fi是CostFunction,也叫误差函数,或者代价函数。 ρ i \rho_i ρi是LossFunction。LossFunction 是一个标量函数,用于减少异常值对非线性最小二乘问题的解决方案的影响。 x i x_i xi就是我们输入的变量(包括要优化的和不用优化的)。
2. 如何使用Ceres
Ceres 求解优化问题的函数是:
CERES_EXPORT void Solve(const Solver::Options& options,
Problem* problem,
Solver::Summary* summary);
Ceres的用法就是围绕这个函数的参数展开的。
2.1 Solver::Options
Solver::Options 用来设置优化的参数。
常用的就是设置迭代的次数,步长,线性求解器的类型。
2.2 Problem
Problem 用来定义待解的优化问题。
核心就是往优化问题里面添加Residual block:
template <typename... Ts>
ResidualBlockId AddResidualBlock(CostFunction* cost_function,
LossFunction* loss_function,
double* x0,
Ts*... xs)
残差块有三个参数,cost_function对应 f i f_i fi,loss_function对应 ρ i \rho_i ρi,x0和xs对应 x i x_i xi。
我们来展开讲CostFunction和LossFunction。
2.2.1 CostFunction
CostFunction是一个基类,单看这个基类本身是没什么作用的,实际上使用的时候是用它的派生类AutoDiffCostFunction
,如下所示:
template <typename CostFunctor,
int kNumResiduals, // Number of residuals, or ceres::DYNAMIC.
int... Ns> // Number of parameters in each parameter block.
class AutoDiffCostFunction final
: public SizedCostFunction<kNumResiduals, Ns...> {
public:
// Takes ownership of functor by default. Uses the template-provided
// value for the number of residuals ("kNumResiduals").
explicit AutoDiffCostFunction(CostFunctor* functor,
Ownership ownership = TAKE_OWNERSHIP)
: functor_(functor), ownership_(ownership) {
static_assert(kNumResiduals != DYNAMIC,
"Can't run the fixed-size constructor if the number of "
"residuals is set to ceres::DYNAMIC.");
}
...
}
对于这个类,我们要关注的是CostFunctor
,因为它定义的就是我们优化问题的cost_function,也就是方程中的
f
i
f_i
fi。这个CostFunctor
是一个结构体,我们需要在里面重写Operator()
,从而定义我们的cost_function,如下所示:
struct CostFunc
{
template <typename T>
bool operator()(const T* const x0,
const T* const ... xs,
T* residuals) const
{
//定义residuals是怎么来的
//...
return true;
}
};
举个例子:
f ( x ) = 1 2 ( 10 − x ) 2 f(x)= \frac {1} {2} (10−x)^2 f(x)=21(10−x)2
那么,residuals就对应方程里面的10-x
.
2.2.2 LossFunction
LossFunction 就是套在cost_function外面一层的修饰,为了提升鲁棒性。一般是nullptr,代表LossFunction就是1。如果为了提升鲁棒性,可以换成别的函数,常用的是HuberLoss:
在Ceres里面的代码如下:
class CERES_EXPORT HuberLoss final : public LossFunction {
public:
explicit HuberLoss(double a) : a_(a), b_(a * a) {}
void Evaluate(double, double*) const override;
private:
const double a_;
// b = a^2.
const double b_;
};
举个例子:
f ( x ) = 1 2 ( 10 − x ) 2 f(x)= \frac {1} {2} (10−x)^2 f(x)=21(10−x)2
当我们将LossFunction定义成nullptr的时候,那么优化函数就是上面的式子。如果定义成HuberLoss的时候,那么优化函数如下所示:
f ( x ) = H u b e r ( 1 2 ( 10 − x ) 2 ) f(x)=Huber( \frac {1} {2} (10−x)^2) f(x)=Huber(21(10−x)2)
2.3 Solver::Summary
用来存日志的。
3. 示例
参考ceres教程(1)
参考
- ceres教程(1)
- Ceres Solver 入门教程