Ceres 数值导数 (NumericDerivatives)进阶 |
您所在的位置:网站首页 › 数值求导的方法有几种 › Ceres 数值导数 (NumericDerivatives)进阶 |
考虑一个直线拟合问题: 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−b3x)1/b4b1 我们给定一些数据 { 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−b3xi)1/b4b1−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 DifferencesRidders差分的表达式如下: 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!h2D3f(x)+5!h4D5f(x)+⋯=2hf(x+h)−f(x−h)+K2h2+K4h4+⋯ 定义如下: 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 |