Interfacing with Automatic Differentiation
来源:互联网 发布:linux日志函数 编辑:程序博客网 时间:2024/06/05 01:19
Interfacing with Automatic Differentiation
在提供了一个明确的cost function表达式的情况下,自动求导可以直接使用。但这不是每次都可行。通常需要接入外部调用或者数据。在本章中,我们将会讨论一些用于实现这些的不同的方法。
我们设计了一个模板函数 TemplatedComputeDistortion 可以计算函数f。实现了简单的相应的残差算子
template <typename T> T TemplatedComputeDistortion(const T r2) { const double k1 = 0.0082; const double k2 = 0.000023; return 1.0 + k1 * y2 + 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];};
目前为止都很完美,让我们讨论三种定义f的方式,在这些方式下自动求导不可以直接使用。
1.一个非模板函数,计算它的函数值
2.一个函数,计算它的值和导数值
3.一个函数,定义为一个数组,进行差值
A function that returns its value
假设提供了如下形式的函数 ComputeDistortionValue
double ComputeDistortionValue(double r2);
计算 f 的值。函数实际的实现不重要。将这个函数接入到 Affine2DWithDistortion 需要三个步骤
1.将 ComputeDistortionValue 函数封装在 ComputeDistortionValueFunctor 算子中。
2.数值微分 ComputeDistortionValueFunctor, 使用 NumbericDiffCostFunction 生成一个 CostFunction。
3.将得到的 CostFunction 对象包装,使用CostFunctionToFunctor。得到的对象是一个算子,具有一个模板运算符,可以输出Jacobian,由 NumericDiffCostFunction 计算得出,以一个合适的 Jet 对象方式输出。
以上的三个步骤的实现如下:
struct ComputeDistortionValueFunctor { bool operator()(const double* r2, double* value) const { *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>( 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;};
A function that returns its value and derivative
现在假设,给我们一个函数 ComputeDistortionValue,可以计算函数值,可以按需计算 Jacobian,声明如下
void ComputeDistortionValueAndJacobian(double r2, double* value, double* jacobian);
通过如下两个步骤实现 Affine2DWithDistortion 接口函数
1.将 ComputeDistortionValueAndJacobian 封装到 CostFunction 对象中,我们可以调用 ComputeDistortionFunction。
2.将 ComputeDistortionFunction 对象封装起来,使用 CostFunctionToFunctor。得到的对象是一个拥有模板运算符()方法的算子,可以将使用 NumericDiffCostFunction 计算得到的 Jacobian 输出到一个合适的 Jet 对象中。
代码如下:
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)); } 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;};
A function that is defined as a table of values
第三个也是最后一种情况,我们要讨论函数f被定义成一个[0,100)的整数数值列表。
vector<double> distortion_values;
给一个数值列表进行差值有很多种方式。最简单也是最常见的方法是线性差值。然而使用线性差值并不是一个好主意,因为差值函数在采样点处不可微。
一种(效果较好)可微的差值方法叫做 Cubic Hermite Spline。Ceres Solver 提供例程来执行 Cubic & Bi-Cubic 差值,很适合自动求导。
使用 Cubic 差值,需要首先构造一个 Grid1D 对象来封装数值列表,接着构造一个 CubicInterpolator 对象来使用它。
代码如下:
struct Affine2DWithDistortion { Affine2DWithDistortion(const double x_in[2], const double y_in[2], const std::vector<double>& distortion_values) { x[0] = x_in[0]; x[1] = x_in[1]; y[0] = y_in[0]; y[1] = y_in[1]; grid.reset(new ceres::Grid1D<double, 1>( &distortion_values[0], 0, distortion_values.size())); compute_distortion.reset( new ceres::CubicInterpolator<ceres::Grid1D<double, 1> >(*grid)); } 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->Evaluate(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::Grid1D<double, 1> > grid; std::unique_ptr<ceres::CubicInterpolator<ceres::Grid1D<double, 1> > > compute_distortion;};
在上面的例子中,我们使用了 Grid1D 以及 CubicInterpolator 来差值一个一维的数值列表。Grid2D 与CubicInterpolator 结合,使用者可以差值二维数值列表。注意不论是 Grid1D 还是 Grid2D 受限标量数值函数,他们同样可以用在向量函数。
- Interfacing with Automatic Differentiation
- Ceres(3)---Interfacing with Automatic Differentiation
- Automatic differentiation
- 自动微分(Automatic Differentiation)简介
- 自动微分(Automatic Differentiation)简介
- Interfacing with I2C Devices
- C++自动微分(Automatic differentiation)原理1
- The differentiation program with abstract data
- Interfacing DJGPP with Assembly-Language Procedures
- Interfacing DJGPP with Assembly-Language Procedures
- Interfacing with Pixhawk using the NSH
- A brief introduction to C++ and Interfacing with Excel
- Lesson17 Interfacing with raw buffers: the Map class
- Automatic Android* Testing with UiAutomator
- Differentiation Rules
- Jayantha Katupitiya, Kim Bentley, «Interfacing with C++: Programming Real-World Applications»
- hyperopt中文文档:Interfacing-With-Other-Languages(在其他语言中使用hyperopt)
- Setting up automatic network installations with AutoYaST
- jQuery对象与DOM对象之间的转换
- 深入分析Parquet列式存储格式
- 50款大数据分析神器 :你还是只会用Excel吗?
- 干货|JVM内存模型和常规问题定位手段
- ABAP ALV 总结整理
- Interfacing with Automatic Differentiation
- ETL拉链算法简介
- powershell和cmd区别
- android studio Instant Run 问题
- 关于git的使用
- 15:接水问题
- navicat for mysql 导入psc文件
- 射频遥控:固定码与学习码的区别
- tensorflow 解决SyntaxError: invalid syntax