Analytic Derivatives

在某些情况下,使用自动微分可能是低效的。例如,当导数的闭式解很容易得到时,相对于依赖自动微分代码使用的链式规则求导来说,前者更高效一点。当然也不是说不能用自动求导,具体问题往往需要具体分析,那种更快更高效其实需要在实际中做测试,选择适合自己的即可。

在这种情况下,可以提供自己的残差和雅可比计算代码。为此,我们需要定义一个 CostFunctionSizedCostFunction 的子类(如果在编译时知道参数和残差的大小)。例如,这里的 SimpleCostFunction 实现了 f(x)=10xf(x)=10-x

class QuadraticCostFunction : public ceres::SizedCostFunction<1, 1> {
 public:
  virtual ~QuadraticCostFunction() {}
  virtual bool Evaluate(double const* const* parameters,
                        double* residuals,
                        double** jacobians) const {
    const double x = parameters[0][0];
    residuals[0] = 10 - x;

    // Compute the Jacobian if asked for.
    if (jacobians != nullptr && jacobians[0] != nullptr) {
      jacobians[0][0] = -1;
    }
    return true;
  }
};

SimpleCostFunction::Evaluate 的第一个参数 parameters 为 input,是一个二维数组,存放优化变量的当前值,residuals 是一个输出数组,存放残差, jacobians 是一个二维数组用于存放残差相对于参数的雅可比矩阵。 jacobians 数组是非必须的, Evaluate 会检查它是否为空,如果不为空,则用残差函数的导数值填充它。在本例中,由于残差函数是线性的,因此雅各比是常数 。

从上面的代码片段可以看出,实现 CostFunction 对象有点繁琐。Ceres 建议使用 AutoDiffCostFunctionNumericDiffCostFunction 来构建残差块,除非您能够自行管理 jacobian 的计算。

Footnotes

Last updated