非线性优化Ceres的学习和使用(一)
绿色化学提倡使用可再生资源,而非一次性或有害的化学制品 #生活常识# #环保生活Tips# #绿色化学#
本文参考视觉slam十四讲实现使用Ceres拟合曲线。
1.问题描述
假设下面曲线
y = e x p ( a x 2 + b x + c ) + w y=exp(ax^{2}+bx+c)+w y=exp(ax2+bx+c)+w
其中a,b,c为曲线的参数,w为高斯噪声。假设我们有N个关于x,y的观测数据点,想根据这些数据点求出曲线的参数。那么可以求解下面的最小二乘问题。
min a , b , c 1 2 ∑ i = 1 N ∥ y i − e x p ( a x i 2 + b x i + c ) ∥ 2 \min_{a,b,c}\frac{1}{2}\sum_{i=1}^{N}\left \| y_{i}-exp(ax_i^{2}+bx_i+c) \right \|^{2} a,b,cmin21i=1∑N∥∥yi−exp(axi2+bxi+c)∥∥2
2.自动求导代码实现
CmakeLists.txt
project(ceresexp) cmake_minimum_required(VERSION 2.8) set( CMAKE_BUILD_TYPE "Debug" ) set( CMAKE_CXX_FLAGS "-std=c++11 -O3" ) # 寻找Ceres库并添加它的头文件 find_package( Ceres REQUIRED ) include_directories( ${CERES_INCLUDE_DIRS} ) # OpenCV find_package( OpenCV REQUIRED ) include_directories( ${OpenCV_DIRS} ) add_executable(${PROJECT_NAME} main.cpp ) # 与Ceres和OpenCV链接 target_link_libraries( ${PROJECT_NAME} ${CERES_LIBRARIES} ${OpenCV_LIBS}) 123456789101112131415
主函数
#include <iostream> #include <opencv2/core/core.hpp> #include <ceres/ceres.h> #include <chrono> using namespace std; // 代价函数的计算模型 struct CURVE_FITTING_COST { CURVE_FITTING_COST ( double x, double y ) : _x ( x ), _y ( y ) {} // 残差的计算 template <typename T> bool operator() ( const T* const abc, // 模型参数,有3维 T* residual ) const // 残差 { residual[0] = T ( _y ) - ceres::exp ( abc[0]*T ( _x ) *T ( _x ) + abc[1]*T ( _x ) + abc[2] ); // y-exp(ax^2+bx+c) return true; } const double _x, _y; // x,y数据 }; int main ( int argc, char** argv ) { double a=1.0, b=2.0, c=1.0; // 真实参数值 int N=100; // 数据点 double w_sigma=1.0; // 噪声Sigma值 cv::RNG rng; // OpenCV随机数产生器 double abc[3] = {0,0,0}; // abc参数的估计值 vector<double> x_data, y_data; // 数据 cout<<"generating data: "<<endl; for ( int i=0; i<N; i++ ) { double x = i/100.0; x_data.push_back ( x ); y_data.push_back ( exp ( a*x*x + b*x + c ) + rng.gaussian ( w_sigma ) ); cout<<x_data[i]<<" "<<y_data[i]<<endl; } // 构建最小二乘问题 ceres::Problem problem; for ( int i=0; i<N; i++ ) { problem.AddResidualBlock ( // 向问题中添加误差项 // 使用自动求导,模板参数:误差类型,输出维度,输入维度,维数要与前面struct中一致 new ceres::AutoDiffCostFunction<CURVE_FITTING_COST, 1, 3> ( new CURVE_FITTING_COST ( x_data[i], y_data[i] ) ), nullptr, // 核函数,这里不使用,为空 abc // 待估计参数 ); } // 配置求解器 ceres::Solver::Options options; // 这里有很多配置项可以填 options.linear_solver_type = ceres::DENSE_QR; // 增量方程如何求解 options.minimizer_progress_to_stdout = true; // 输出到cout ceres::Solver::Summary summary; // 优化信息 chrono::steady_clock::time_point t1 = chrono::steady_clock::now(); ceres::Solve ( options, &problem, &summary ); // 开始优化 chrono::steady_clock::time_point t2 = chrono::steady_clock::now(); chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>( t2-t1 ); cout<<"solve time cost = "<<time_used.count()<<" seconds. "<<endl; // 输出结果 cout<<summary.BriefReport() <<endl; cout<<"estimated a,b,c = "; for ( auto a:abc ) cout<<a<<" "; cout<<endl; return 0; }
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677783输出结果
Ceres Solver Report: Iterations: 22, Initial cost: 1.824887e+04, Final cost: 5.096854e+01, Termination: CONVERGENCE estimated a,b,c = 0.891943 2.17039 0.944142 12
4.总结1
Ceres求解最小二乘问题过程如下:
(1)构建最小二乘问题
problem.AddResidualBlock ( ) // 向问题中添加误差项 1
(2) 配置求解器
ceres::Solver::Options options; // 这里有很多配置项可以填 options.linear_solver_type = ceres::DENSE_QR; // 增量方程如何求解 12
(3)设置输出优化迭代的信息
ceres::Solver::Summary summary; // 优化信息 1
(4)开始优化
ceres::Solve ( options, &problem, &summary ); // 开始优化 1
网址:非线性优化Ceres的学习和使用(一) https://www.yuejiaxmz.com/news/view/235515
相关内容
在线学习和线下面对面学习,优点和缺点能不能深度分析一下?非线性规划
线性空间与优化问题:如何利用线性代数解决实际问题
在线学习的优势
【运筹优化】优化模型线性化方法总结
在线学习如何才能高效?线上学习的方法和工具,学生和家长都可以来看看
在线学习的 12 个令人惊讶的优势(2024 年更新)
使用Python实现深度学习模型:智能家电控制与优化
一根线千“编”万化,这项非遗绝活你也能学
小户型住宅空间的优化性使用研究