算法基础 - 高斯牛顿法(曲线拟合)

news2024/11/29 20:42:10

文章目录

    • 1. 高斯牛顿法发展历程
    • 2、问题的引出
    • 3、高斯牛顿法的前世
      • 3.1、一阶,二阶梯度法共有原理
      • 3.2、最速下降法(一阶梯度法)
      • 3.3、牛顿法(二阶梯度法)
    • 4、高斯牛顿法
      • 4.1 高斯牛顿法的思想
      • 4.2 最小二乘问题
      • 4.3 高斯牛顿法原理
      • 4.4 高斯牛顿法算法流程
      • 4.5 高斯牛顿法缺点
    • 5、曲线拟合示例
      • 5.1 C++代码
      • 5.2 运行结果
      • 5.3 图形化显示

1. 高斯牛顿法发展历程

从上到下为高斯牛顿法的前世今生以及未来的演化:

  • 最速下降法(一阶梯度法)

  • 牛顿法(二阶梯度法)

  • 高斯牛顿法

  • 列文伯格法

  • 马夸尔特法

2、问题的引出

先来考虑如下优化目标函数:

在这里插入图片描述

我们的目标:

对变量x 进行优化,即寻找一组合适的x使得优化目标函数F(x) 最小。

最直观的方法:
在这里插入图片描述
然后基于这些这些组x求出F ( x ) 的全部极值,然后通过比较极值的大小就可以找到F ( x ) 的最小值和其所对应的x 取值。

直观方法的问题:

根据上述方法,我们可以找到F ( x ) 全局最小值,但这里面有一个严重的问题。当F ( x ) 为复杂的非线性函数时,其关于x 的一阶导数是十分复杂的,导致 dF/dx = 0 难以求解,或者说求得其全部解是十分困难的,即我们难以获得F ( x ) 全局性质,自然后续的求极值比大小就无法进行,这个方法就走进了死胡同。

解决直观方法问题的思路:

对于不方便直接求解的最小二乘问题,我们可以用迭代的方式,从一个初始值触发,不断地更新当前的优化变量,使目标函数的值下降。

也就是说,虽然我们难以求解 dF/dx = 0,但我们给定一组x,求 dF/dx 的值是很容易的,就是把给定的x 代入 dF/dx 算,批量处理这一过程是计算机最擅长的事情,即我们可以很容易获得F ( x ) 局部性质。那么我们为了解决这样的一个优化问题,我们可以给定一个初值,然后利用F ( x ) 在初值附近的局部性质(即在初值附近x 如何变化可以使得F ( x ) 更小)得到初值的变化增量 在这里插入图片描述 ,通过迭代,当Δ x (DeltaX) 足够小时,我们就找到了F(x) 比较小的一个值和其对应的x 取值。与x相对应,这里Δ x( DeltaX)也是 n 维列向量。对应算法流程为:

在这里插入图片描述
这让求解导函数为零的问题,变成了一个不断寻找下降增量 在这里插入图片描述 的问题。我们将看到,由于可以对 f 进行线性化,增量的计算将简单的多。当函数下降直到增量非常小的时候,就认为算法收敛,目标函数达到了一个极小值。在这个过程中,问题在于如何找到每次迭代点的增量,而这是一个局部的问题,我们只需要关心 f 在迭代值处的局部性质而非全局性质。这类方法在最优化、机器学习等领域广泛应用。

接下来,我们考察如何寻找这个增量 在这里插入图片描述 。 这部分知识实际属于数值优化的领域。

这里有几点值得注意:

  • 基于局部性质找到的F ( x ) 较小值并不一定是F ( x ) 的最小值,因为我们只考察了F ( x )
    在初值附近的局部情况,没有对F ( x ) 全局性质进行考察。

  • 当 Δx (Deltax) 足够小时,算法结束。这个可以这样理解:此时x 只有在变化一点点的情况下才会使F(x) 变小,这说明F(x) 的函数值已经到了一个谷底附近,x 稍微变大一点都会使得F(x)从谷底向上走从而变大。之所以我们不把算法结束条件设置成Δ x = 0 (Delta x = 0) 这是因为我们恰好让F ( x ) 函数值在谷底点几乎不可能,会导致算法一直在谷底点附近小范围内震荡。

  • 局部方法的核心在于如何获得增量Δ x (Delta x )

在这里插入图片描述

3、高斯牛顿法的前世

由于原理的相似性,最速下降法和牛顿法可以统称为一阶,二阶梯度法。这两种方法的原理分别是在局部用一次函数,二次函数对非线性函数F ( x ) 进行近似,然后利用近似函数的最小值推测非线性函数F ( x )的极小值。

3.1、一阶,二阶梯度法共有原理

在这里插入图片描述

3.2、最速下降法(一阶梯度法)

1)最速下降法原理

最速下降法(一阶梯度法)就是保留泰勒展开的一阶项用来近似非线性函数F ( x ),即:

在这里插入图片描述
2)最速下降法缺点

该方法过于贪心,容易走出锯齿线,反而增加迭代次数。

3.3、牛顿法(二阶梯度法)

1)牛顿法的原理

牛顿法(二阶梯度法)就是保留泰勒展开的一阶项和二阶项用来近似非线性函数F(x),即:

在这里插入图片描述
解得:

在这里插入图片描述

2)牛顿法的缺点
海塞矩阵 在这里插入图片描述 计算量太大了。

3)阻尼牛顿法
阻尼牛顿法就是在使用牛顿法获得增量方向后,进一步对最优步长进行搜索:

在这里插入图片描述

4、高斯牛顿法

4.1 高斯牛顿法的思想

高斯牛顿法针对最小二乘问题,采用一定的方法对牛顿法中的海塞矩阵 在这里插入图片描述 进行近似,从而简化了计算量。

注意:只有最小二乘问题才能使用高斯牛顿法

4.2 最小二乘问题

最小二乘法(又称最小平方法)是一种数学优化技术。它通过最小化误差的平方和寻找数据的最佳函数匹配。最小二乘问题可以表述为:

在这里插入图片描述

4.3 高斯牛顿法原理

在这里插入图片描述

4.4 高斯牛顿法算法流程

在这里插入图片描述

4.5 高斯牛顿法缺点

  • 在求解增量 在这里插入图片描述 时候,我们需要计算 在这里插入图片描述,但是 在这里插入图片描述 只有半正定性质,在实际计算中可能会遇见 在这里插入图片描述 为奇异矩阵或者病态矩阵,从而导致增量不稳定,算法不收敛。出现这种现象的深层原因是 F(x) 在 在这里插入图片描述 处的近似不像一个二次函数。这也应该是牛顿法的缺点?

    • 奇异矩阵:不满秩的方阵

    • 病态矩阵:求解方程组时如果对数据进行较小的扰动,则得出的结果具有很大波动,这样的矩阵称为病态矩阵。

  • 当我们求得的增量 在这里插入图片描述 过大时,我们使用泰勒展开进行局部近似就会不准确。从而导致算法不收敛。

5、曲线拟合示例

5.1 C++代码


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



using namespace std;
using namespace Eigen;

int Test001LeastSquares();
int LeastSquare002();

int main(int argc, char **argv)
{  
  //在实际的项目中,不会有预设的真值,只有直接获取到的观测值,目的是为了依据观测值估算出真值。对于最小二乘法,是通过计算误差平方和最小来估算真值
  double a_real = 1.0, b_real = 2.0, c_real = 3.0;   // 真实参数值: 这里所谓真值,是为了模拟结合随机数用于构造实际观测值。
  double a_esti = 2.0, b_esti = -1.0, c_esti = 5.0;   // 估计参数值

  std::string str_init_value = std::to_string(a_esti) + ", " + std::to_string(b_esti) + ", " + std::to_string(c_esti) + "";

  int point_num = 100;                                     // 数据点
  double w_sigma = 1.0;                                    // 噪声Sigma(西格玛)值
  double inv_sigma = 1.0 / w_sigma;                        // 噪声Sigma(西格玛)的倒数???
  cv::RNG rng;                                             // OpenCV随机数产生器

  //创建模拟实际观测点
  vector<double> x_data, y_data;
  {
    for (int index_point = 0; index_point < point_num; index_point++)
    {
      double rng_value = rng.gaussian(w_sigma * w_sigma);

      //模拟实际观测点
      double x_temp = (double)index_point / (double)point_num;   //进行 point_num(100) 等分
      double y_temp = exp(a_real * x_temp * x_temp + b_real * x_temp + c_real) + rng_value;

      x_data.push_back(x_temp);
      y_data.push_back(y_temp);
    }
  }


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

  chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
  for (int index_iter = 0; index_iter < iterations; index_iter++)
  {
    Matrix3d hessian = Matrix3d::Zero();  //海森矩阵:计算所有点的累加和 Hessian = J^T W^{-1} J in Gauss-Newton
    Vector3d bias = Vector3d::Zero();     //bias: 计算所有点的累加和 bias 偏导?  斜的,偏动的
    cost = 0;                             //误差平方和: 计算所有点的累加和
    {
      //针对海森矩阵(hessian)、bias、误差平方和(cost) ,计算所有点的累加和
      for (int index_points = 0; index_points < point_num; index_points++)
      {
        double x_temp = x_data[index_points]; // 第i个数据点(实际观测点)
        double y_temp = y_data[index_points]; // 第i个数据点(实际观测点)

        Vector3d jacobian; //雅可比矩阵: 针对每个点,计算对应的雅可比矩阵
        {
          jacobian[0] = -x_temp * x_temp * exp(a_esti * x_temp * x_temp + b_esti * x_temp + c_esti);  //求解雅可比矩阵: de/da 对系数a求导, 参考: P133, (6.40)
          jacobian[1] = -x_temp * exp(a_esti * x_temp * x_temp + b_esti * x_temp + c_esti);           //求解雅可比矩阵: de/db 对系数b求导, 参考: P133, (6.40)
          jacobian[2] = -exp(a_esti * x_temp * x_temp + b_esti * x_temp + c_esti);                    //求解雅可比矩阵: de/dc 对系数c求导, 参考: P133, (6.40)
        }

        //海森矩阵:计算所有点的累加和
        hessian += inv_sigma * inv_sigma * jacobian * jacobian.transpose();                           //计算累加和: 高斯牛顿法的增量方程? P133, (6.41) 公式的左侧 ?

        //bias: 计算所有点的累加和
        double error = y_temp - exp(a_esti * x_temp * x_temp + b_esti * x_temp + c_esti);          //误差值
        bias += -inv_sigma * inv_sigma * error * jacobian;                                            //计算累加和: 高斯牛顿法的增量方程? P133, (6.41) 公式的右侧 ?

        //误差平方和: 计算所有点的累加和
        cost += error * error;  //求解最小二乘问题(误差平方和),估计曲线参数 ? P133, (6.38)
     
      } //end for : for (int index_points = 0; index_points < point_num; index_points++)
      
    }

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


    // 接下来,便是求解 (6.41) 公式 中的 X (delta_X_k) :  求解线性方程 Hx=b
    // 求解线性方程 Hx=b  P129, (公式 6.33)
    Vector3d deltaX = hessian.ldlt().solve(bias);
    if(std::isnan(deltaX[0]))
    {
      cout << "result is nan!" << endl;
      break;
    }

    a_esti += deltaX[0];
    b_esti += deltaX[1];
    c_esti += deltaX[2];

    lastCost = cost;

    cout << "iterations[" << index_iter << "/" << iterations << "] init = " << str_init_value << ", estimated: " << a_esti << ", " << b_esti << ", " << c_esti
         << "\t deltaX(has update estimate): " << deltaX.transpose() << ", "
         << "\t total cost: " << cost << endl;
         
  }//end for : for (int index_iter = 0; index_iter < iterations; index_iter++)

  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 = " << a_esti << ", " << b_esti << ", " << c_esti << endl;
  
  return 0;

}


5.2 运行结果

在这里插入图片描述

5.3 图形化显示

光滑曲线为拟合后的曲线。锯齿形的拟合前观测点。

在这里插入图片描述

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

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

相关文章

Vue+Element Plus实现自定义表单弹窗

目录 一、基本框架 1.父组件index.vue 2.子组件FormPop.vue 二、细节补充 1&#xff09;input、textarea、select、input number 2&#xff09;daterange、date、monthrange 3&#xff09;数据定义 4&#xff09;没改样式的效果 5&#xff09;最终效果 三、最终代码 …

VMware Workstation Pro下载安装及简单设置

VMware Workstation Pro下载 方法一&#xff1a;官网下载 https://support.broadcom.com/group/ecx/productdownloads?subfamilyVMwareWorkstationPro账号请自行注册&#xff0c;选择最新版本17.6.1 下载后用md5sum_x64.exe验证下载的文件完整性 方法二 百度网盘 通过网…

ospf协议(动态路由协议)

ospf基本概念 定义 OSPF 是典型的链路状态路由协议&#xff0c;是目前业内使用非常广泛的 IGP 协议之一。 目前针对 IPv4 协议使用的是 OSPF Version 2 &#xff08; RFC2328 &#xff09;&#xff1b;针对 IPv6 协议使用 OSPF Version 3 &#xff08; RFC2740 &#xff09;。…

数据结构之循环链表和栈

一、循环链表 1、概念 循环链表&#xff1a;就是首尾相连的链表&#xff0c;通过任意一个节点&#xff0c;都能将整个链表遍历一遍 分类&#xff1a;单向循环链表、双向循环链表 2、单向循环链表的类格式 单向循环链表也就是单向链表的最后一个节点的next域不再为None,而是…

linux安装部署mysql资料

安装虚拟机 等待检查完成 选择中文 软件选择 网络和主机名 开始安装 设置root密码 ADH-password 创建用户 等待安装完成 重启 接受许可证 Centos 7 64安装完成 安装mysql开始 Putty连接指定服务器 在 opt目录下新建download目录 将mysql文件传到该目录下 查看linux服务器的…

HTML 霓虹灯开关效果

HTML 霓虹灯开关效果 1.简介&#xff1a;该代码为纯html&#xff0c;CSS写在了内部&#xff0c;不需要额外引入&#xff0c;霓虹灯开关效果很漂亮&#xff0c;应用在个人物联网项目中是一个比较不错的选择。 2.运行效果&#xff1a; 3.源码&#xff1a; <!DOCTYPE html&g…

uniapp开发支付宝小程序自定义tabbar样式异常

解决方案&#xff1a; 这个问题应该是支付宝基础库的问题&#xff0c;除了依赖于官方更新之外&#xff0c;开发者可以利用《自定义 tabBar》曲线救国 也就是创建一个空内容的自定义tabBar&#xff0c;这样即使 tabBar 被渲染出来&#xff0c;但从视觉上也不会有问题 1.官方文…

24/11/26 视觉笔记 通过特征提取和透视变换查找对象

在本节中我们将检测和跟踪任意大小的对象&#xff0c;这些对象可能是在不同角度或者在部分遮挡的情况下观察到的。 为此我们将运用特征描述子&#xff08;Feature Descriptor&#xff09;&#xff0c;这是捕获感兴趣对象的重要属性的一种方式。我们这样是为了即使将对象嵌入繁…

【单片机毕业设计12-基于stm32c8t6的智能称重系统设计】

【单片机毕业设计12-基于stm32c8t6的智能称重系统设计】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇12-基于stm32c8t6的智能称重系统设计 &#x1f9ff;创作不易&#xff0c;拒绝白嫖可私 一、功能介绍 ----…

ubuntu中使用ffmpeg和nginx推http hls视频流

视频流除了rtmp、rtsp&#xff0c;还有一种是http的hls流&#xff0c;使用http协议传输hls格式的视频数据。 nginx支持推送hls视频流&#xff0c;使用的是rtmp模块&#xff0c;即rtmp流推送成功了&#xff0c;hls流也没问题。怎么推送rtmp流&#xff0c;请参考我的文章&#x…

5.2.机器学习--岭回归+局部线性回归

目录 1.岭回归 1.1代码示例 2.局部线性回归 2.1代码示例 1.最小二乘法&#xff1a; 平面几何表达直线(两个系数): 重新命名变量: 强行加一个x01&#xff1a; 向量表达&#xff1a; 2.损失函数&#xff1a; 矩阵表达&#xff1a; 矩阵展开&#xff1a; 推导&#xff1a; …

nvidia-container-toolkit安装问题(OpenPGP)

1.正常情况下 apt-get install -y nvidia-container-toolkit2.使用nvidia源 nvidia-container-toolkit官网有安装教程 2.1 配置生产存储库 curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-containe…

电脑上的ip地址可以改吗?如何改变ip地址

在现代网络环境中&#xff0c;IP地址作为设备在网络中的唯一标识&#xff0c;扮演着至关重要的角色。无论是日常上网冲浪&#xff0c;还是进行专业的网络操作&#xff0c;IP地址都与我们息息相关。那么&#xff0c;电脑上的IP地址可以改吗&#xff1f;答案是肯定的。接下来&…

org.apache.log4j的日志记录级别和基础使用Demo

org.apache.log4j的日志记录级别和基础使用Demo&#xff0c;本次案例展示&#xff0c;使用是的maven项目&#xff0c;搭建的一个简单的爬虫案例。里面采用了大家熟悉的日志记录插件&#xff0c;log4j。来自apache公司的开源插件。 package com.qian.test;import org.apache.log…

PHP 生成分享海报

因为用户端有多个平台&#xff0c;如果做分享海报生成&#xff0c;需要三端都来做&#xff0c;工作量比较大。 所以这个艰巨的任务就光荣的交给后端了。经过一定时间的研究和调试&#xff0c;最终圆满完成了任务&#xff0c;生成分享海报图片实现笔记如下。 目录 准备字体文件…

ASP.NET Core 入门

使用 .NET CLI 创建并运行 ASP.NET Core Web 应用。 文章目录 一、先决条件二、创建Web应用项目三、运行应用四、编辑Razor页面 一、先决条件 .NET 8.0 SDK 二、创建Web应用项目 打开命令行界面&#xff0c;然后输入以下命令&#xff1a; dotnet new webapp --output aspne…

基于 Flask 和 Socket.IO 的 WebSocket 实时数据更新实现

简介 随着现代化应用的快速发展&#xff0c;实时数据交互已经成为许多 Web 应用的核心需求&#xff0c;比如实时消息推送、数据监控大屏等。本文将基于一个完整的 WebSocket 实现示例&#xff0c;带你一步步理解如何使用 Flask 和 Socket.IO 构建实时数据更新的 Web 应用。 将…

十、Spring Boot集成Spring Security之HTTP请求授权

文章目录 往期回顾&#xff1a;Spring Boot集成Spring Security专栏及各章节快捷入口前言一、HTTP请求授权工作原理二、HTTP请求授权配置1、添加用户权限2、配置ExceptionTranslationFilter自定义异常处理器3、HTTP请求授权配置 三、测试接口1、测试类2、测试 四、总结 往期回顾…

详细介绍HTTP与RPC:为什么有了HTTP,还需要RPC?

目录 一、HTTP 二、RPC 介绍 工作原理 核心功能 如何服务寻址 如何进行序列化和反序列化 如何网络传输 基于 TCP 协议的 RPC 调用 基于 HTTP 协议的 RPC 调用 实现方式 优点和缺点 使用场景 常见框架 示例 三、问题 问题一&#xff1a;是先有HTTP还是先有RPC&…

【Linux】 进程是什么

0. 什么是进程&#xff0c;为什么要有进程&#xff1f; 1.操作系统为了更好的管理我们的软硬件&#xff0c;抽象出了许多概念&#xff0c;其中比较有代表的就是进程了。通俗的来说操作系统为了更好的管理加载到内存的程序&#xff0c;故引入进程的概念。 2.在操作系统学科中用P…