高翔【自动驾驶与机器人中的SLAM技术】学习笔记(四)高斯牛顿法详解

news2024/11/24 15:40:39

一、高斯牛顿法详解

 拓展阅读:高斯牛顿法详解_gauss-newton算法步骤-CSDN博客

1、梯度下降法

​ 

无论一阶泰勒展开,还是二阶泰勒展开都是关于增量\Delta x_k​的方程。 



2、牛顿法

 这个自变量增量都是可求的。但是二阶求解复杂。因此为了简化有了下面的高斯牛顿法。不过只适用于最小二乘法。



3、高斯牛顿法

最小二乘法展开的是后面的函数部分。将f(x)一阶泰勒展开(一阶就要带雅可比矩阵)。而非目标函数展开。

记住这个增量方程中的H(x_k)。这里后面代码要用到。

缺点:当近似求解的增量过大时算法无法收敛,我理解到是不是通俗说的SLAM飞了

缺点:雅可比矩阵有时是奇异矩阵。 从而导致增量不稳定

补充:来源《随手笔记——如何手写高斯牛顿法》

还是那句话:高斯牛顿法是对:最小二乘法展开的是后面的函数部分。将f(x)一阶泰勒展开(一阶就要带雅可比矩阵)。而非目标函数展开。是对小f(x)(每个样本即误差项)

下面这个图是讲最小二乘法的样式:

  • 模型函数预测值与观察值(真实值)之间的偏差的二次方的加和为目标函数。这个目标函数等效上面提到的大F(x)。
  • 而高斯牛顿法是将这个上面这个偏差项给展开了。是对这个偏差项进行了泰拉展开,而不是对目标函数。

最优化算法之高斯牛顿法

#include <iostream>
#include <chrono>
#include <opencv2/opencv.hpp>
#include <Eigen/Core>
#include <Eigen/Dense>

using namespace std;
using namespace Eigen;

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));
  }

  // 开始Gauss-Newton迭代
  int iterations = 100;    // 迭代次数
  double cost = 0, lastCost = 0;  // 本次迭代的cost和上一次迭代的cost

  chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
  for (int iter = 0; iter < iterations; iter++) {

    Matrix3d H = Matrix3d::Zero();             // 黑森(海塞)矩阵:Hessian = J^T W^{-1} J in Gauss-Newton
    Vector3d b = Vector3d::Zero();             // bias
    cost = 0;

    for (int i = 0; i < N; i++) {
      double xi = x_data[i], yi = y_data[i];  // 第i个数据点
      double error = yi - exp(ae * xi * xi + be * xi + ce);
      Vector3d J; // 雅可比矩阵
      J[0] = -xi * xi * exp(ae * xi * xi + be * xi + ce);  // de/da
      J[1] = -xi * exp(ae * xi * xi + be * xi + ce);  // de/db
      J[2] = -exp(ae * xi * xi + be * xi + ce);  // de/dc

      H += inv_sigma * inv_sigma * J * J.transpose();
      b += -inv_sigma * inv_sigma * error * J;

      cost += error * error;
    }

    // 求解线性方程 Hx=b
    Vector3d dx = H.ldlt().solve(b);
    if (isnan(dx[0])) {
      cout << "result is nan!" << endl;
      break;
    }

    if (iter > 0 && cost >= lastCost) {
      cout << "cost: " << cost << ">= last cost: " << lastCost << ", break." << endl;
      break;
    }

    ae += dx[0];
    be += dx[1];
    ce += dx[2];

    lastCost = cost;

    cout << "total cost: " << cost << ", \t\tupdate: " << dx.transpose() <<
         "\t\testimated params: " << ae << "," << be << "," << ce << endl;
  }

  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 << "estimated abc = " << ae << ", " << be << ", " << ce << endl;
  return 0;
}

手写高斯牛顿法-CSDN博客

#include <iostream>
#include <chrono>
#include <opencv2/opencv.hpp>
#include <Eigen/Core>
#include <Eigen/Dense>

using namespace std;
using namespace Eigen;

int main() {
    //设定曲线真实参数
    double ar = 1.0, br = 2.0, cr = 1.0;
    //给定曲线参数优化初始估计值
    double ae = 2.0, be = -1.0, ce = 5.0;
    //设定数据点个数
    int N = 100;
    //设定噪声服从的正态分布的sigma值
    double w_sigma = 1.0;
    //计算sigma的倒数,之后用于误差归一化
    double inv_sigma = 1.0 / w_sigma;
    //OpenCV随机数产生器
    cv::RNG rng;

    //初始化数据容器,容器内元素类型为double
    vector<double> x_data, y_data;
    //生成N个数据点
    for (int i=0; i < N; ++i){
        //x在0-1之间均匀取100个值
        double x = i / 100.0;
        x_data.push_back(x);
        //y用真实函数生成再加上高斯噪声
        y_data.push_back(exp(ar*x*x+br*x+cr)+rng.gaussian(w_sigma * w_sigma));
    }

    //开始高斯牛顿迭代
    //设定迭代次数
    int iterations = 100;
    //本次迭代和上次迭代的cost
    double cost = 0, lastcost = 0;

    //开始及时,当前时间点存储到t1中
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();

    //牛顿高斯算法迭代iterations次
    for (int iter = 0; iter < iterations; ++iter) {



        //初始化H矩阵,b矩阵,雅克比矩阵J和cost
        Matrix3d H = Matrix3d::Zero();
        Vector3d b = Vector3d::Zero();
        cost = 0;

        //对N个数据点进行处理,列出总的增量方程,计算初始误差
        for (int i = 0; i < N; ++i) {
            double xi = x_data[i], yi = y_data[i];
            double error = yi - exp(ae * xi * xi + be * xi + ce);
            //计算雅克比矩阵在该点取值
            Vector3d J;
            J[0] = -xi * xi * exp(ae * xi * xi + be * xi + ce);  // de/da
            J[1] = -xi * exp(ae * xi * xi + be * xi + ce);   // de/db
            J[2] = -exp(ae * xi * xi + be * xi + ce);   // de/dc

            H += inv_sigma * inv_sigma * J * J.transpose();   //这里除以sigma是归一化
            b += -inv_sigma * inv_sigma * error * J;

            cost += error * error;
        }

        //求解线性方程Hx=b
        Vector3d dx = H.ldlt().solve(b);
        //如果方程无解,那么dx[0]是非法字符nan,退出迭代
        if (isnan(dx[0])) {
            cout << "result is nan!" << endl;
            break;
        }

        //如果本次迭代误差大于上次误差,算法结束,退出迭代
        if(iter > 0 && cost >= lastcost){
            cout << "cost:" << cost << ">=" << lastcost << ",break." << endl;
            break;
        }

        //进行估计参数的增量更新,存储本次代价
        ae += dx[0];
        be += dx[1];
        ce += dx[2];

        lastcost = cost;
        //输出本次迭代信息
        cout << "total cost:" << cost << ",\t\tupdate:" << dx.transpose() << "\t\testimatec:" << ae << "," << be <<
        "," << ce << endl;

    }
    //及时结束,获取当前时间赋给t2
    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 << "estimated abc = " << ae << ", " << be << ", " << ce << endl;
    return 0;
}

cmake_minimum_required(VERSION 3.15)
project(GuassNewton)

set(CMAKE_CXX_STANDARD 14)

#OpenCV
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})

#Eigen
include_directories("/usr/include/eigen3")

add_executable(GuassNewton main.cpp)
target_link_libraries(GuassNewton ${OpenCV_LIBS})


 4、列文伯格-马夸尔特方法

 因为高斯牛顿更新时增量可能会不稳定,甚至太大。所以为了使增量的更加稳定可靠,对其做了限制,增加了置信域。



5、拟牛顿法

为了解决牛顿法中海森矩阵H计算复杂的问题,拟牛顿法提供了另外一种解决思路:

通过使用不含有二阶导数的矩阵U代替牛顿法中的H,根据矩阵U构造的不同,具有不同的拟牛顿法。

1、拟牛顿法的基本原理

2、DFP

为了方便区分,下面把U称作D(表示DFP)

1)DFP结果

DFP算法的问题在于在求取增量的时候D矩阵仍要求逆

3、BFGS

2)BFGS算步骤

4、L-BFGS

1)L-BFGS原理

2)L-BFGS应用

 

因此,L-BFGS的算法流程如下:
 


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1951210.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023IMO预选题几何第6题

锐角 △ A B C \triangle ABC △ABC 的外接圆为 ω \omega ω, 圆 I I I 与 ω \omega ω 内切于 A A A, 且与 B C BC BC 切于点 D D D. 设直线 A B AB AB, A C AC AC 分别与 I I I 交于点 P P P, Q Q Q, 点 M M M, N N N 在直线 B C BC BC 上, 满足 B B B 是 …

【Golang 面试基础题】每日 5 题(九)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/UWz06 &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏…

探索Linux-1-虚拟机远程登陆XShell6远程传输文件Xftp6

Linux是什么&#xff1f; Linux是一个开源的操作系统内核&#xff0c;由林纳斯托瓦兹&#xff08;Linus Torvalds&#xff09;于1991年首次发布。它基于Unix操作系统&#xff0c;但提供了更多的自由和灵活性。Linux内核是操作系统的核心部分&#xff0c;负责管理系统资源、处理…

【HarmonyOS】应用推送使用个推SDK如何实现?

【HarmonyOS】应用推送使用个推SDK如何实现&#xff1f; 前言 个推和极光都是市面上很成熟的推送第三方SDK了。今天讲讲个推SDK在鸿蒙中如何集成使用。 存在即合理&#xff0c;三方SDK推送给我们带来了极大的好处&#xff0c;首先在服务器后台处理一套API就可搞定&#xff0…

lambda 28

package Api;public class local7 {public static void main(String[] args) {Swimmimg w()->{System.out.println("方式");};} } interface Swimmimg{void run(); }/* public static void main(String[] args) {Animal a new Animal(){Overridepublic void…

基于高光谱图像的压缩感知网络

压缩感知算法原理 压缩感知&#xff08;Compressed Sensing, CS&#xff09;是一种信号处理技术&#xff0c;它允许在远低于Nyquist采样率的情况下对信号进行有效采样和重建。压缩感知理论的核心思想是利用信号的稀疏性&#xff0c;通过少量的线性测量重建出原始信号。以下是压…

指令重排:

目录 指令重排&#xff1a; 代码&#xff1a; 执行结果&#xff1a; 分析原因&#xff1a; 解决办法&#xff1a; 加入语句&#xff1a; 完整代码&#xff1a; 补充&#xff1a; 1.printStackTrace(); 2.yield() 指令重排&#xff1a; 在class文件执行的时候&#…

OAK-FFC 分体式相机使用入门介绍

概述 OAK FFC 主控板和多种可选配镜头模组非常适合灵活的搭建您的3D人工智能产品原型。由于镜头是分体式的&#xff0c;因此你可以根据需要测量的距离&#xff0c;自定义深度相机安装基线&#xff0c;并根据你的项目要求&#xff08;分辨率、快门类型、FPS、光学元件&#xff…

【C++】选择结构-switch语句

switch 语句语法格式&#xff1a; switch (已定义整型或字符型变量名) { case 单个整型或字符型1&#xff1a; 满足这个 case 下整型或字符型执行的操作 break; case 单个整型或字符型2&#xff1a; 满足这个 case 下整型或字符型执行的操作 break; ...... default : 所有 ca…

SpringBoot3整合Druid报错Cannot load driver class: org.h2.Driver

报错显示springboot自带的H2数据库报错&#xff0c;其实是因为druid并未加载进去。如果你其它配置都没问题的话&#xff0c;请检查druid的依赖是什么版本的&#xff0c;因为springboot3刚开始是不支持druid的。 方案一&#xff1a; 即需要手动在resources目录下创建META-INF/s…

opencascade AIS_MouseGesture AIS_MultipleConnectedInteractive源码学习

AIS_MouseGesture //! 鼠标手势 - 同一时刻只能激活一个。 enum AIS_MouseGesture { AIS_MouseGesture_NONE, //!< 无激活手势 // AIS_MouseGesture_SelectRectangle, //!< 矩形选择&#xff1b; //! 按下按钮开始&#xff0c;移动鼠标定义矩形&…

队列--顺序队列的表示和实现

#include<stdio.h> #define MAXQSIZE 10 typedef int QElemType; typedef int Status; //顺序队列 (循环队列,有一个空间不用) typedef struct{QElemType *base;int rear;int front; }SqQueue; //初始化队列 Status InitQueue(SqQueue &Q){Q.basenew QElemType[MAX…

微信Android一面凉经(2024)

微信Android一面凉经(2024) 笔者作为一名双非二本毕业7年老Android, 最近面试了不少公司, 目前已告一段落, 整理一下各家的面试问题, 打算陆续发布出来, 供有缘人参考。今天给大家带来的是《微信Android一面凉经(2024)》。 面试职位: 微信-客户端开发工程师-基础功能(广州) And…

数据结构——二叉树性质

性质1:在二叉树的第i层上至多有2^(i-1)个结点(i>1)。 这个性质很好记忆&#xff0c;观察一下图6-5-5。 第一层是根结点&#xff0c;只有一个&#xff0c;所以2^(1-1)2^01。 第二层有两个&#xff0c;2^(2-1)22。 第三层有四个&#xff0c;2^(3-1)2^24。 第四层有八个&am…

centos7 mysql 基本测试(6)主从简单测试

centos7 xtrabackup mysql 基本测试&#xff08;6&#xff09;主从简单测试 mysql -u etc -p 1234aA~1 参考&#xff1a; centos7 时区设置 时间同步 https://blog.csdn.net/wowocpp/article/details/135931129 Mysql数据库&#xff1a;主从复制与读写分离 https://blog.csd…

【中项】系统集成项目管理工程师-第5章 软件工程-5.3软件设计

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

800G以太网测试之FEC压力测试(FEC统计,FEC Error Injection)

目录 FEC是什么 FEC测试需要关注哪些内容 基础的 FEC 性能监测 需要测试和验证的 FEC 特性 FEC Error Injection / FEC误码压力测试 Codeword & Symbol Error Configuration Errored Symbol Per CW Configuration Bit Error Mask Configuration Loop Mode FEC 引擎…

JavaScript Let

ECMAScript 2015 ES2015 引入了两个重要的 JavaScript 新关键词&#xff1a;let 和 const。 这两个关键字在 JavaScript 中提供了块作用域&#xff08;Block Scope&#xff09;变量&#xff08;和常量&#xff09;。 在 ES2015 之前&#xff0c;JavaScript 只有两种类型的作…

为边缘开发由生成式 AI 驱动的视觉 AI 智能体

为边缘开发由生成式 AI 驱动的视觉 AI 智能体 文章目录 为边缘开发由生成式 AI 驱动的视觉 AI 智能体什么是可视化 AI 智能体&#xff1f;使用 Jetson 平台服务为边缘构建视觉 AI 智能体构建基于 VLM 的视觉 AI 智能体应用程序VLM AI 服务提示工程与 Jetson 平台服务和移动应用…

针对网络延迟与弱网下的测试

学习的时候看见大佬这样的回复 作为一个测试小白&#xff0c;我心想&#xff0c;这我不得上手试一试 大佬说的工具模拟&#xff0c;大概是指Charles和fiddler两个软件&#xff0c;都可以模拟弱网&#xff0c;但是Charles收费&#xff0c;我拿fiddler练手 另一个故意引入固定百…