template <typenameCostFunctor,intkNumResiduals, // Number of residuals, or ceres::DYNAMIC.int... Ns> // Size of each parameter blockclassAutoDiffCostFunction:publicSizedCostFunction<kNumResiduals,Ns> {public: // Instantiate CostFunctor using the supplied arguments.template<class ...Args>explicitAutoDiffCostFunction(Args&& ...args);explicitAutoDiffCostFunction(std::unique_ptr<CostFunctor> functor);explicitAutoDiffCostFunction(CostFunctor* functor,ownership= TAKE_OWNERSHIP); // Ignore the template parameter kNumResiduals and use // num_residuals instead.AutoDiffCostFunction(CostFunctor* functor,int num_residuals,ownership= TAKE_OWNERSHIP);AutoDiffCostFunction(std::unique_ptr<CostFunctor> functor,int num_residuals);};
为了能够自动计算导数,用户在使用的时候需要自定义一个 class 并且重载 operator() 运算,且要使用模板参数 T。自动求导框架使用 Jet 对象来替换模板参数 T,以便于计算导数,但这些操作对用户来说都是隐藏的,因此用户只需要把这里的 T 当做一个 double 或者 float 类型的数据进行使用即可。括号运算符重载函数必须将残差的计算结果写入到最后一个非 const 参数中去,同时返回 true 预示着计算成功。
例如,考虑一个误差 e=k−x⊤y,其中 x,y 都是两个维度的向量,k 是一个常数,该误差的形式是最小二乘问题中的常见模式, x⊤y 值可能是一系列测量结果的模型期望值,其中每次测量都有一个 k 来构成代价函数实例,也就是说 x,y 使我们的待优化变量,实际中我们会有多个 k ,每个都会构成一个残差项。可以参考曲线拟合的思路。通过 Ceres 去实现上述建模的问题,我们首先要定义一个对象,并对括号运算符进行重载,计算残差。
auto* cost_function=newAutoDiffCostFunction<MyScalarCostFunctor,1,2,2>(1.0);^^^||| Dimension of residual ------+|| Dimension of x ----------------+| Dimension of y -------------------+
auto functor = std::make_unique<CostFunctorWithDynamicNumResiduals>(1.0);auto* cost_function=new AutoDiffCostFunction<CostFunctorWithDynamicNumResiduals, DYNAMIC,2,2>( std::move(functor),^^^ runtime_number_of_residuals); <----+||||||||||| Actual number of residuals ------+||| Indicate dynamic number of residuals --------+|| Dimension of x ------------------------------------+| Dimension of y ---------------------------------------+
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.