首页 > 其他分享 >状态估计之非线性优化学习

状态估计之非线性优化学习

时间:2024-08-12 19:09:45浏览次数:14  
标签:ceres double 非线性 Ceres 估计 优化

SLAM的后端优化,一般分为滤波方法与非线性优化方法,其中部分思想重叠,具有很鲜明的对比特性。在前几章中,我们学习了KF系列与PF系列,并对一部分内容进行扩展,这些方法的本质是在一步步过程中进行优化收敛,本篇将引入后端整体优化思想,在建图,轨迹跟踪,系统状态估计中应用广泛。

本篇的学习大纲是:

  1. 状态估计问题与最大似然估计;
  2. 线性估计的最小二乘法;
  3. 非线性最小二乘法:梯度下降:最速/牛顿法;高斯-牛顿方法;列文伯格-马夸尔特方法学习;
  4. ceres库的简介与应用学习。

1.状态估计问题与最大似然估计的引出

在SLAM中,我们可以通过滤波来单步进行优化状态估计的结果(马尔科夫思想),但需要知道的是,即使我们的传感器精度再高,运动方程与观测方程也只是近似成立。所以,与其假设数据符合目标方程,不如直接讨论如何在有噪声的数据中进行准确的状态估计。首先想起我们最基本的状态方程和观测方程。

 

直观一点讲,似然是指“在现在的位姿下,可能会产生怎样的观测数据”。由于我们能够获得观测数据,所以最大似然估计可以理解为:“在什么样的状态下,最可能产生现在观测到的数据”。这就是SLAM中最大似然估计的直观意义。

 

2.线性估计最小二乘法的引出

最小二乘法的目标是:求解误差的最小平方和。根据Cost Function的对应,分为了线性与非线性。这个取决于对应的残差(Residual)是线性的还是非线性的。

先从模型角度入手,我们假设某次观测为:

3.非线性最小二乘法

考虑一个简单的最小二乘问题:

 

 

4.Ceres的简介与学习

Ceres是一个广泛使用的最小二乘问题求解库,其代码基于C++实现。我们使用时只需要按照一定的步骤定义待求解的优化问题,然后运行代码就可以。Crese求解的最小二乘问题最一般的形式如下(带边界的核函数最小二乘):

 

 

Ceres安装

代码库地址:https://link.zhihu.com/?target=https%3A//github.com/ceres-solver/ceres-solver

 

下载后cmake,make,make install编译安装就行。在/usr/local/lib/目录下能够看到libceres.a的库就说明安装完成。

Ceres的使用[3]

//代码借鉴于高翔博士的SLAM专题 ch6

#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 ar = 1.0, br = 2.0, cr = 1.0;         // 真实参数值
  double ae = 2.0, be = -1.0, ce = 5.0;        // 估计参数值
  int N = 100;                                 // 数据点
  double w_sigma = 1.0;                        // 噪声Sigma值
  double inv_sigma = 1.0 / w_sigma;
  cv::RNG rng;                                 // OpenCV随机数产生器

  vector<double> x_data, y_data;      // 数据
  for (int i = 0; i < N; i++) {
    double x = i / 100.0;
    x_data.push_back(x);
    y_data.push_back(exp(ar * x * x + br * x + cr) + rng.gaussian(w_sigma * w_sigma));
  }

  double abc[3] = {ae, be, ce};

  // 构建最小二乘问题
  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_NORMAL_CHOLESKY;  // 增量方程如何求解
  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;
}

大意是使用CV的生成器随机生成100个带高斯噪声的数据,利用Ceres进行拟合。代码中涉及到的注意点(与前述工作步骤相似)有:

  1. 书写了一个结构体,并在类中定义带模板参数的()运算符,形成了一个拟函数,这样直接用Ceres的对象调用该函数就可以;
  2. 参数块求导部分,采用自动求导函数Auto diff,类似的选择还有数值求导Numeric diff或自行编写求导部分,出于方便,使用自动求导;
  3. 优化的量的单位及维度,本篇中的误差是标量,所以单位与维度均为1,所以Auto diff中对a、b、c三个优化量的参数设置为1,3(表示单位标量1,维度3个);
  4. 设定好后,在options中配置优化选项。例如,是否使用线搜索,或是置信区间,迭代步长,次数等。

Ceres的简介与学习说到这里,更多的学习可以参考文献书籍与代码。关于SLAM框架,也有许多应用,计划在后期进行学习记录。

 

至此,本篇的记录即将结束,再次回顾学习记录的内容:状态估计问题的优化之后端非线性优化,与单步马尔科夫式滤波(如EKF,UKF等)不同的是这种方法会对整体的模型函数进行非线性最小二乘思想的问题构建,通过导数定义的方式去寻求目标函数的极小值,来确保结果收敛。在求解极小值过程中,我们学习了在分布函数一阶/二阶泰勒展开截断的梯度下降法,分别是最速下降法与牛顿法;并推理对其概率密度函数的泰勒展开进行截断,得到了高斯牛顿方法;随后在其步长上做出优化,将置信区间的思想加入高斯牛顿法,得到列文伯格-马夸尔特方法(LM方法)。最后,简单介绍学习了SLAM中用于处理非线性优化的Ceres库。

参考大佬:SLAM算法工程师之路:状态估计之非线性优化学习 - 知乎 (zhihu.com)

标签:ceres,double,非线性,Ceres,估计,优化
From: https://www.cnblogs.com/Gaowaly/p/18355556

相关文章

  • NoSQL之Redis配置与优化
    Redis简介Redis(RemoteDictionaryServer,远程字典型)是一个开源的、使用C语言编写的NoSQL数据库。Redis基于内存运行并支持持久化,采用key-value(键值对)的存储形式,是目前分布式架构中不可或缺的一环Redis优点:具有极高的数据读写速度,数据读取的速度最高可达到110000次/......
  • PHP性能优化秘籍:让代码飞起来
    标题:PHP性能优化秘籍:让代码飞起来PHP作为一门广泛使用的服务器端脚本语言,其性能直接影响到Web应用的响应速度和用户体验。本文将深入探讨PHP性能优化的多种技巧,从代码层面到服务器配置,帮助你的PHP应用达到最佳性能。我们将通过一系列详细的优化策略和实际代码示例,展示如何......
  • Scrapy框架进阶攻略:代理设置、请求优化及链家网实战项目全解析
    scrapy框架加代理付费代理IP池middlewares.py#代理IP池classProxyMiddleware(object):proxypool_url='http://127.0.0.1:5555/random'logger=logging.getLogger('middlewares.proxy')asyncdefprocess_request(self,request,spider):......
  • 猜数字完全体?还能优化不?
    1>> 前言     首先感谢大家对之前文章的喜欢,你们的三连是我持续更新的动力!    继续采纳大佬们的意见,今天将以代码的形式,逐步剖析来进行分享和交流经验,希望能得到大家的喜欢。接下来和我一起步入C语言世界吧!注:以下代码是C语言,但CSDN好像选不了,只有C++也可能......
  • JVM参数详解:优化应用程序性能的关键
    Java虚拟机(JVM)是Java程序的运行环境,它负责将Java字节码转换为机器码,并在实际计算机上执行。为了优化应用程序的性能,我们需要了解JVM的参数设置。本文将详细介绍JVM的常见参数及其作用,帮助您更好地理解和配置JVM。JVM参数分类JVM参数分为两大类:启动参数和系统属性。1.启......
  • linux反向代理原理:帮助用户更好地优化网络架构
    Linux反向代理原理详解反向代理是一种在网络架构中常用的技术,尤其在Linux环境下被广泛应用。它可以帮助实现负载均衡、安全防护和请求缓存等功能。本文将深入探讨Linux反向代理的原理、工作机制以及其应用场景。1.什么是反向代理反向代理是指代理服务器接收客户端的请求,......
  • 打造高效存储与访问体验:NFS共享携手Nginx负载均衡,赋能企业级数据流通与性能优化
     作者简介:我是团团儿,是一名专注于云计算领域的专业创作者,感谢大家的关注 座右铭:   云端筑梦,数据为翼,探索无限可能,引领云计算新纪元 个人主页:团团-CSDN博客前言:随着业务的增长,公司需要更多的服务器来支持用户访问和应用程序的运行。NFS共享可以解决文件存储的问题,而n......
  • 【机器学习】机器学习在电商领域:个性化推荐系统优化与销售转化提升
    ......
  • 最优化 | 凸优化 | 二次规划cvxopt求解,如何确定系数?
    目录一、定义二、系数的确定三、例子四、代码一、定义在凸优化问题中,特别是在二次规划(QuadraticProgramming,QP)问题中,矩阵PPP通常用来定义目标函数中的二次项......
  • 深度学习优化器:《Lookahead Optimizer: k steps forward, 1 step back》
    深度学习优化器:《LookaheadOptimizer:kstepsforward,1stepback》项目地址:https://github.com/michaelrzhang/lookaheadpytorch版本:https://github.com/michaelrzhang/lookahead/blob/master/lookahead_pytorch.py论文地址:https://arxiv.org/abs/1907.08610使用......