Ceres(3)---Interfacing with Automatic Differentiation

来源:互联网 发布:网络推广平均工资 编辑:程序博客网 时间:2024/06/05 00:21

转载地址:

http://ceres-solver.org/interfacing_with_autodiff.html

本篇主要介绍在一些情况下,不能直接使用 Automatic Differentiation


We begin by considering the case, where we have a templated function TemplatedComputeDistortionthat can compute the function f. Then the implementation of the corresponding residual functor is straightforward and will look as follows:

template <typename T>  TemplatedComputeDistortion(const T r2) {  const double k1 = 0.0082;  const double k2 = 0.000023;  return 1.0 + k1 * r2 + k2 * r2 * r2;}struct Affine2DWithDistortion {  Affine2DWithDistortion(const double x_in[2], const double y_in[2]) {    x[0] = x_in[0];    x[1] = x_in[1];    y[0] = y_in[0];    y[1] = y_in[1];  }  template <typename T>    //模板类型  bool operator()(const T* theta,                  const T* t,                  T* residuals) const {    const T q_0 =  cos(theta[0]) * x[0] - sin(theta[0]) * x[1] + t[0];    const T q_1 =  sin(theta[0]) * x[0] + cos(theta[0]) * x[1] + t[1];    const T f = TemplatedComputeDistortion(q_0 * q_0 + q_1 * q_1);   //模板类型    residuals[0] = y[0] - f * q_0;    residuals[1] = y[1] - f * q_1;    return true;  }  double x[2];  double y[2];};

 Automatic Differentiation 的函数对象是模板形式的

So far so good, but let us now consider three ways of defining fwhich are not directly amenable to being used with automatic differentiation:

  1. A non-templated function that evaluates its value. (仿函数中要使用非模板的函数)
  2. A function that evaluates its value and derivative.
  3. A function that is defined as a table of values to be interpolated.

We will consider them in turn below.

A function that returns its value

Suppose we were given a function ComputeDistortionValue with the following signature

double ComputeDistortionValue(double r2);  //非模板类型函数

that computes the value of f. The actual implementation of the function does not matter. Interfacing this function with Affine2DWithDistortion is a three step process:

  1. Wrap ComputeDistortionValue into a functor ComputeDistortionValueFunctor.
  2. Numerically differentiate ComputeDistortionValueFunctor using NumericDiffCostFunction to create a CostFunction.
  3. Wrap the resulting CostFunction object using CostFunctionToFunctor.The resulting object is a functor with a templated operator() method, which pipes the Jacobian computed by NumericDiffCostFunction into the approproate Jet objects.

An implementation of the above three steps looks as follows:

struct ComputeDistortionValueFunctor {   bool operator()(const double* r2, double* value) const {   //非模板仿函数,供NumericDiffCostFunction使用    *value = ComputeDistortionValue(r2[0]);                       //要使用的非模板函数    return true;  }};struct Affine2DWithDistortion {  Affine2DWithDistortion(const double x_in[2], const double y_in[2]) {    x[0] = x_in[0];    x[1] = x_in[1];    y[0] = y_in[0];    y[1] = y_in[1];    compute_distortion.reset(new ceres::CostFunctionToFunctor<1, 1>(  // compute_distortion赋值         new ceres::NumericDiffCostFunction<ComputeDistortionValueFunctor,                                            ceres::CENTRAL,                                            1,                                            1>(            new ComputeDistortionValueFunctor)));  }  template <typename T>  bool operator()(const T* theta, const T* t, T* residuals) const {    const T q_0 = cos(theta[0]) * x[0] - sin(theta[0]) * x[1] + t[0];    const T q_1 = sin(theta[0]) * x[0] + cos(theta[0]) * x[1] + t[1];    const T r2 = q_0 * q_0 + q_1 * q_1;    T f;    (*compute_distortion)(&r2, &f);     //调用指向的模板仿函数    residuals[0] = y[0] - f * q_0;    residuals[1] = y[1] - f * q_1;    return true;  }  double x[2];  double y[2];  std::unique_ptr<ceres::CostFunctionToFunctor<1, 1> > compute_distortion;   //指向仿函数的指针};

猜测:这样做以后, Affine2DWithDistortion就是一个模板仿函数,这样就可以像之前使用 Automatic Derivatives 一样使用。

A function that returns its value and derivative

Now suppose we are given a function ComputeDistortionValue that is able to compute its value and optionally its Jacobian on demand and has the following signature:

void ComputeDistortionValueAndJacobian(double r2,                                       double* value,                                       double* jacobian);

Again, the actual implementation of the function does not matter. Interfacing this function with Affine2DWithDistortion is a two step process:

  1. Wrap ComputeDistortionValueAndJacobian into a CostFunction object which we callComputeDistortionFunction.
  2. Wrap the resulting ComputeDistortionFunction object using CostFunctionToFunctor. The resulting object is a functor with a templated operator() method, which pipes the Jacobian computed by NumericDiffCostFunction into the approproate Jet objects.
对于官网的第三个例子完全没理解,就不记录了
通过下面的例子可以看出:
  第一种是将 要用的函数包装在 NumericDiffCostFunction 要用的仿函数中,再用 NumericDiffCostFunction new 一个 CostFunction,供CostFunctionToFunctor使用;
  第二种是通过将要用的函数包装在CostFunction中,然后供CostFunctionToFunctor使用;
class ComputeDistortionFunction : public ceres::SizedCostFunction<1, 1> {   public:  virtual bool Evaluate(double const* const* parameters,                        double* residuals,                        double** jacobians) const {    if (!jacobians) {      ComputeDistortionValueAndJacobian(parameters[0][0], residuals, NULL);    } else {      ComputeDistortionValueAndJacobian(parameters[0][0], residuals, jacobians[0]);    }    return true;  }};struct Affine2DWithDistortion {  Affine2DWithDistortion(const double x_in[2], const double y_in[2]) {    x[0] = x_in[0];    x[1] = x_in[1];    y[0] = y_in[0];    y[1] = y_in[1];    compute_distortion.reset(        new ceres::CostFunctionToFunctor<1, 1>(new ComputeDistortionFunction)); //这的<1,1>是和上面定义ComputeDistortionFunction时指定的<1,1>是一致的  }  template <typename T>  bool operator()(const T* theta,                  const T* t,                  T* residuals) const {    const T q_0 =  cos(theta[0]) * x[0] - sin(theta[0]) * x[1] + t[0];    const T q_1 =  sin(theta[0]) * x[0] + cos(theta[0]) * x[1] + t[1];    const T r2 = q_0 * q_0 + q_1 * q_1;    T f;    (*compute_distortion)(&r2, &f);    residuals[0] = y[0] - f * q_0;    residuals[1] = y[1] - f * q_1;    return true;  }  double x[2];  double y[2];  std::unique_ptr<ceres::CostFunctionToFunctor<1, 1> > compute_distortion;};
原创粉丝点击