Ceres是一个非线性的优化库,在优化问题中广泛使用,今天我们就来使用这一优化库来求解一个函数的极值点。非线性优化库优化的原理是在给定初值的条件下不断计算偏移量,使得待优化参数向着目标函数梯度最小处移动。
使用Ceres优化库的步骤可以归纳为以下几步:
- 定义参数块,主要定义待优化参数的形式;
- 定义残差块的计算方式。残差块通常关联若干个参数块,对它们进行一些自定义的计算,然后返回残差值;
- 残差块也需要定义雅可比的计算方式。在Ceres中,你可以使用它提供的“自动求导”功能,也可以手动指定雅可比的计算过程。如果要使用自动求导,那么残差块需要按照特定的写法书写;残差的计算过程应该是一个带模板的括号运算符;
- 将所有的参数块和残差块加入Ceres定义的Problem对象中,调用Slove函数求解即可。求解之前,我们可以传入一些配置信息,例如迭代次数、终止条件等,也可以使用默认的配置。
#include <iostream>
#include <ceres/ceres.h>
#include <glog/logging.h>
#include<chrono>
#include <math.h>
#include <algorithm>
using namespace std;
using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solve;
using ceres::Solver;
//x表示待优化参数块,residual表示残差块
//通过非线性优化找到函数梯度下降的自变量的取值。
struct CostFunctor {
template <typename T>
bool operator()(const T* const x, T* residual) const {
residual[0] = 2.0*pow(x[0]-5.0,2);
return true;
}
};
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
// The variable to solve for with its initial value. It will be
// mutated in place by the solver.
double x = 0.5;
const double initial_x = x;
// Build the problem.
Problem problem;
// Set up the only cost function (also known as residual). This uses
// auto-differentiation to obtain the derivative (jacobian).
//定义误差函数,误差类型,输入维度,输出维度
CostFunction* cost_function =
new AutoDiffCostFunction<CostFunctor, 1, 1>(new CostFunctor);
//优化问题添加残差块,不使用核函数
problem.AddResidualBlock(cost_function, nullptr, &x);
// Run the solver!
Solver::Options options;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);
std::cout << summary.BriefReport() << "\n";
std::cout << "x : " << initial_x << " -> " << x << "\n";
return 0;
}