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

一、高斯牛顿法详解

 拓展阅读:高斯牛顿法详解_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和上一次迭代的costchrono::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-NewtonVector3d b = Vector3d::Zero();             // biascost = 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/daJ[1] = -xi * exp(ae * xi * xi + be * xi + ce);  // de/dbJ[2] = -exp(ae * xi * xi + be * xi + ce);  // de/dcH += inv_sigma * inv_sigma * J * J.transpose();b += -inv_sigma * inv_sigma * error * J;cost += error * error;}// 求解线性方程 Hx=bVector3d 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;//初始化数据容器,容器内元素类型为doublevector<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;//本次迭代和上次迭代的costdouble 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和costMatrix3d 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/daJ[1] = -xi * exp(ae * xi * xi + be * xi + ce);   // de/dbJ[2] = -exp(ae * xi * xi + be * xi + ce);   // de/dcH += inv_sigma * inv_sigma * J * J.transpose();   //这里除以sigma是归一化b += -inv_sigma * inv_sigma * error * J;cost += error * error;}//求解线性方程Hx=bVector3d 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;}//及时结束,获取当前时间赋给t2chrono::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://xiahunao.cn/news/3268411.html

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

相关文章

windows下运行sh文件

1、打开git bash 2、进入sh文件所在文件夹&#xff0c;使用sh xx.sh运行

@RequiredArgsConstructor详解

RequiredArgsConstructor详解 一、什么是RequiredArgsConstructor? RequiredArgsConstructor是Lombok的一个注解&#xff0c;简化了我们对Autowired书写&#xff0c;我们在写Controller层或者Service层的时候&#xff0c;总是需要注入很多mapper接口或者service接口&#xf…

初识Play Framework框架和第一个Java play web项目的创建

文章目录 初识Play Framework框架和第一个Java play web项目的创建一、简介特点架构开发流程示例代码总结 二、创建第一个Java play web项目1、下载play框架&#xff0c;配置系统环境变量(jdk的安装就不再说了) 2、检查play的版本和创建第一个play项目3、将项目通过idea或eclip…

【NoSQL数据库】Redis知识小册

一、缓存穿透 缓存穿透是先查Redis&#xff0c;发现缓存中没有数据&#xff0c;再查数据库。然而&#xff0c;如果查询的数据在数据库中也不存在&#xff0c;那么每次查询都会绕过缓存&#xff0c;直接落到数据库上。 解决方案一、缓存空数据 查询Redis缓存&#xff1a;首先查…

Java泛型的介绍和基本使用

什么是泛型 ​ 泛型就是将类型参数化&#xff0c;比如定义了一个栈&#xff0c;你必须在定义之前声明这个栈中存放的数据的类型&#xff0c;是int也好是double或者其他的引用数据类型也好&#xff0c;定义好了之后这个栈就无法用来存放其他类型的数据。如果这时候我们想要使用这…

Codeforces 903 div3 A-F

A 题目分析 数据范围很小&#xff0c;暴力枚举即可&#xff0c;然后给字符串x的长度设置一个上限&#xff0c;我设了50&#xff0c;因为n*m<25&#xff0c;多一倍够用了 C代码 #include<iostream> using namespace std; void solve(){int n,m;string x,s;cin>>…

基于RS485的Modbus协议

RS485&#xff1a;用来传输数据&#xff0c;RS485是一种差分传输的串行通信标准&#xff0c;以其强大的抗干扰能力、长距离传输和多点通信能力&#xff0c;在工业控制领域得到广泛应用。RS485使用一对差分信号线&#xff08;A和B&#xff09;来传输数据&#xff0c;差分信号能有…

eclipse ui bug

eclipse ui bug界面缺陷&#xff0c;可能项目过多&#xff0c;特别maven项目过多&#xff0c;下载&#xff0c;自动编译&#xff0c;加载更新界面异常 所有窗口死活Restore不回去了 1&#xff09;尝试创建项目&#xff0c;还原界面&#xff0c;失败 2&#xff09;关闭所有窗口&…

Django学习(二)

get请求 练习&#xff1a; views.py def test_method(request):if request.method GET:print(request.GET)# 如果链接中没有参数a会报错print(request.GET[a])# 使用这个方法&#xff0c;当查询不到参数时&#xff0c;不会报错而是返回你设置的值print(request.GET.get(c,n…

winrar安装好后,鼠标右键没有弹出解压的选项

本来安装挺好的&#xff0c;可以正常使用&#xff0c;有天我把winrar相关的文件挪了个位置&#xff0c;就不能正常使用了。 然后我去应用里面找&#xff0c;找到应用标识了&#xff0c;但是找不到对应的文件夹&#xff08;因为我挪到另外一个文件夹里了&#xff09;。 于是我找…

语言转文字

因为工作原因需要将语音转化为文字&#xff0c;经常搜索终于找到一个免费的好用工具&#xff0c;记录下使用方法 安装Whisper 搜索Colaboratory 右上方链接服务 执行 !pip install githttps://github.com/openai/whisper.git !sudo apt update && sudo apt install f…

Android 软键盘挡住输入框

Android原生输入法软键盘挡住输入框,网上各种解法,但不起效。 输入框都是被挡住了,第二张图的小点,实际就是输入法的光标。 解法: packages\inputmethods\LatinIME\java\res\values-land config.xml <!-- <fraction name="config_min_keyboard_height"&g…

pikachu靶场之目录遍历、敏感信息泄露

一、目录遍历 漏洞概述 在web功能设计中,很多时候我们会要将需要访问的文件定义成变量&#xff0c;从而让前端的功能便的更加灵活。 当用户发起一个前端的请求时&#xff0c;便会将请求的这个文件的值(比如文件名称)传递到后台&#xff0c;后台再执行其对应的文件。 在这个过…

如何评价估计量的好坏

目录 三大方法 概念 无偏性 如何计算估计量的无偏性&#xff1f; 步骤 有效性 有效性在不同类型的数据分析中如何评估&#xff1f; 步骤 一致性 一致性原则在实际应用中的挑战有哪些&#xff1f; 挑战 在大样本情况下&#xff0c;如何准确测量估计量的一致性&#xf…

AcWing-差分矩阵

insert函数影响范围&#xff0c;在b差分数组这样操作影响到是a里面的&#xff0c;所以下图的矩阵表示的是a数组 b[x1][y1]c;会导致a里面仅绿色范围的a[i][j]c b[x1][y21]-c;会导致a里面仅黄色范围的a[i][j]-c b[x21][y1]-c;会导致a里面仅蓝色范围的a[i][j]-c b[x21][y21]c;会导…

SQL Server 设置端口号:详细步骤与注意事项

目录 一、了解SQL Server端口号的基础知识 1.1 默认端口号 1.2 静态端口与动态端口 二、使用SQL Server配置管理器设置端口号 2.1 打开SQL Server配置管理器 2.2 定位到SQL Server网络配置 2.3 修改TCP/IP属性 2.4 重启SQL Server服务 三、注意事项 3.1 防火墙设置 3…

数据结构与算法-归并排序

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、归并排…

MySQL笔记3——高级数据查询语句DQL

多表联查 多表联查可以通过连接运算实现&#xff0c;即将多张表通过主外键关系关联在一起进行查询。下图提供了多表联查 时用到的数据库表之间的关系。 等值查询和非等值查询 非等值查询&#xff1a;SELECT * FROM 表1&#xff0c;表2 等值查询&#xff1a;SELECT * FROM 表…

Oracle对比两表数据的不一致

MINUS 基本语法如下 [SQL 语句 1] MINUS [SQL 语句 2];举个例子&#xff1a; select 1 from dual minus select 2 from dual--运行结果 1-------------------------------- select 2 from dual minus select 1 from dual--运行结果 2所以&#xff0c;如果想找所有不一致的&a…

Codeforces Round 962 (Div. 3)

链接 C题&#xff1a; 思路&#xff1a; 直接暴力求每个字母的前缀和&#xff0c;对于区间l&#xff0c;r的最小操作就是区间不同数的一半&#xff0c;因为可以把一个数变成另一个不一样的数&#xff0c;一下抵消两个。 #include<bits/stdc.h> using namespace std; //…