Ceres 数值导数 (NumericDerivatives)进阶

您所在的位置:网站首页 数值求导的方法有几种 Ceres 数值导数 (NumericDerivatives)进阶

Ceres 数值导数 (NumericDerivatives)进阶

2024-04-07 23:54| 来源: 网络整理| 查看: 265

在这里插入图片描述

数值导数(NumericDerivatives)进阶 一、问题定义二、代价函数定义1. Forward Differences2. Central Differences3. Ridders Differences 三、完整代码四、输出结果五、配置文件六、适用情况   ceres中有三种求导的方式,分别是自动求导、数值导数和解析导数,本节详细讲述数值导数的使用方式。

一、问题定义

  考虑一个直线拟合问题: y = b 1 ( 1 + e b 2 − b 3 x ) 1 / b 4 y = \frac{b_1}{(1+e^{b_2-b_3x})^{1/b_4}} y=(1+eb2​−b3​x)1/b4​b1​​ 我们给定一些数据 { x i , y i } ,   ∀ i = 1 , . . . , n \{x_i, y_i\},\ \forall i=1,... ,n {xi​,yi​}, ∀i=1,...,n来求解参数 b 1 , b 2 , b 3 b_1, b_2, b_3 b1​,b2​,b3​和 b 4 b_4 b4​,这个问题可以等价为,需要寻找一组参数 b 1 , b 2 , b 3 b_1, b_2, b_3 b1​,b2​,b3​和 b 4 b_4 b4​,使得如下方程的数值最小: E ( b 1 , b 2 , b 3 , b 4 ) = ∑ i f 2 ( b 1 , b 2 , b 3 , b 4 ; x i , y i ) = ∑ i ( b 1 ( 1 + e b 2 − b 3 x i ) 1 / b 4 − y i ) 2 \begin{split} E(b_1, b_2, b_3, b_4) &= \sum_i f^2(b_1, b_2, b_3, b_4 ; x_i, y_i)\\ &= \sum_i \left(\frac{b_1}{(1+e^{b_2-b_3x_i})^{1/b_4}} - y_i\right)^2\\ \end{split} E(b1​,b2​,b3​,b4​)​=i∑​f2(b1​,b2​,b3​,b4​;xi​,yi​)=i∑​((1+eb2​−b3​xi​)1/b4​b1​​−yi​)2​ 为了用ceres来解决这个问题,我们需要定义一个CostFunction(代价函数)来计算给定的 x x x和 y y y的残差 f f f和导数。利用数值导数的形式对这个代价函数进行求解,求解的方式有前向查分、中值差分和Ridder差分。

二、代价函数定义 1. Forward Differences

  我们不能在计算机上进行数值极限运算,所以我们做的事情,就是选择一个很小的值,并将导数近似为: D f ( x ) ≈ f ( x + h ) − f ( x ) h Df(x) \approx \frac{f(x + h) - f(x)}{h} Df(x)≈hf(x+h)−f(x)​ 上面的公式是最简单最基本的数值微分形式。它被称为前向差分公式。我们定义代价函数,并用前向差分的方式进行求解,如下:

struct Rat43CostFunctor { Rat43CostFunctor(const double x, const double y) : x_(x), y_(y) {} bool operator()(const double* parameters, double* residuals) const { const double b1 = parameters[0]; const double b2 = parameters[1]; const double b3 = parameters[2]; const double b4 = parameters[3]; residuals[0] = b1 * pow(1.0 + exp(b2 - b3 * x_), -1.0 / b4) - y_; return true; } const double x_; const double y_; }; ceres::CostFunction* cost_function = new ceres::NumericDiffCostFunction( new Rat43CostFunctor(x_data[i],y_data[i])); 2. Central Differences

  中值差分的表达式如下: D f ( x ) ≈ f ( x + h ) − f ( x − h ) 2 h Df(x) \approx \frac{f(x + h) - f(x - h)}{2h} Df(x)≈2hf(x+h)−f(x−h)​ 定义如下:

ceres::CostFunction* cost_function = new ceres::NumericDiffCostFunction( new Rat43CostFunctor(x_data[i],y_data[i])); 3. Ridders Differences

  Ridders差分的表达式如下: D f ( x ) = f ( x + h ) − f ( x − h ) 2 h + h 2 3 ! D 3 f ( x ) + h 4 5 ! D 5 f ( x ) + ⋯ = f ( x + h ) − f ( x − h ) 2 h + K 2 h 2 + K 4 h 4 + ⋯ \begin{split} Df(x) & = \frac{f(x + h) - f(x - h)}{2h} + \frac{h^2}{3!} D^3f(x) + \frac{h^4}{5!} D^5f(x) + \cdots\\ & = \frac{f(x + h) - f(x - h)}{2h} + K_2 h^2 + K_4 h^4 + \cdots \end{split} Df(x)​=2hf(x+h)−f(x−h)​+3!h2​D3f(x)+5!h4​D5f(x)+⋯=2hf(x+h)−f(x−h)​+K2​h2+K4​h4+⋯​ 定义如下:

ceres::CostFunction* cost_function = new ceres::NumericDiffCostFunction( new Rat43CostFunctor(x_data[i],y_data[i])); 三、完整代码 #include #include "ceres/ceres.h" #include "glog/logging.h" #include struct Rat43CostFunctor { Rat43CostFunctor(const double x, const double y) : x_(x), y_(y) {} bool operator()(const double* parameters, double* residuals) const { const double b1 = parameters[0]; const double b2 = parameters[1]; const double b3 = parameters[2]; const double b4 = parameters[3]; residuals[0] = b1 * pow(1.0 + exp(b2 - b3 * x_), -1.0 / b4) - y_; return true; } const double x_; const double y_; }; int main(int argc, char** argv) { /*第一部分,生成观测数据*/ double B1=1.0,B2= 2.0,B3=2.0,B4=2.0;//true value double b1=2.0,b2=-1.0,b3=0.0,b4=1.5;//estimate value int N=20;//num of data double w_sigma=0.02;//sigma of noise cv::RNG rng((unsigned)time(NULL));//opencv random generator std::vector x_data, y_data; for (int i = 0; i b1,b2,b3,b4};//give initial value const double parameters_init[4] ={b1,b2,b3,b4};//give initial value // 构建 problem. ceres::Problem problem; // 建立优化方程. ceres::LossFunction* loss_function = new ceres::HuberLoss(1.0); for (int i = 0; i OpenCV_INCLUDE_DIRS}) include_directories( ${CERES_INCLUDE_DIRS}) include_directories("/usr/include/eigen3") add_executable(NumericDerivatives NumericDerivatives.cpp) target_link_libraries(NumericDerivatives ${CERES_LIBRARIES} ${OpenCV_LIBS}) 六、适用情况

  当无法分析或使用自动微分计算导数时,应使用数值微分。通常情况下,当您用一个外部库或函数时,我们不知道它的分析形式,或者即使知道,也无法以使用自动导数所需的方式重新编写它。当使用数值微分时,至少使用中值差分,如果执行时间不是问题,或者目标函数难以确定良好的静态相对步长,建议使用Ridders方法。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3