Levenberg-Marquardt算法詳解和C++代碼示例

Levenberg-Marquardt(LM)算法是非線性最小二乘問題中常用的一種優化算法,它融合了高斯-牛頓法梯度下降法的優點,在數值計算與SLAM、圖像配準、機器學習等領域中應用廣泛。


一、Levenberg-Marquardt算法基本原理

1.1 問題定義

我們希望最小化一個非線性殘差平方和目標函數:

min ? x f ( x ) = 1 2 ∑ i = 1 m r i ( x ) 2 = 1 2 ∥ r ( x ) ∥ 2 \min_{\mathbf{x}} \, f(\mathbf{x}) = \frac{1}{2} \sum_{i=1}^m r_i(\mathbf{x})^2 = \frac{1}{2} \| \mathbf{r}(\mathbf{x}) \|^2 xmin?f(x)=21?i=1m?ri?(x)2=21?r(x)2

其中,

  • x ∈ R n \mathbf{x} \in \mathbb{R}^n xRn:參數向量
  • r ( x ) = [ r 1 ( x ) , … , r m ( x ) ] T \mathbf{r}(\mathbf{x}) = [r_1(\mathbf{x}), \ldots, r_m(\mathbf{x})]^T r(x)=[r1?(x),,rm?(x)]T:殘差向量

我們要最小化的是殘差的平方和。


二、高斯-牛頓法回顧

在當前點 x k \mathbf{x}_k xk? 處,對殘差函數進行一階泰勒展開:

r ( x k + Δ x ) ≈ r ( x k ) + J ( x k ) Δ x \mathbf{r}(\mathbf{x}_k + \Delta \mathbf{x}) \approx \mathbf{r}(\mathbf{x}_k) + J(\mathbf{x}_k) \Delta \mathbf{x} r(xk?+Δx)r(xk?)+J(xk?)Δx

其中 J ∈ R m × n J \in \mathbb{R}^{m \times n} JRm×n 是 Jacobian:

J i j = ? r i ? x j J_{ij} = \frac{\partial r_i}{\partial x_j} Jij?=?xj??ri??

代入目標函數:

min ? Δ x 1 2 ∥ r + J Δ x ∥ 2 \min_{\Delta \mathbf{x}} \frac{1}{2} \| \mathbf{r} + J \Delta \mathbf{x} \|^2 Δxmin?21?r+JΔx2

導出正規方程(Normal Equation):

J T J Δ x = ? J T r J^T J \Delta \mathbf{x} = - J^T \mathbf{r} JTJΔx=?JTr

這就是高斯-牛頓法。


三、LM算法推導:阻尼的高斯-牛頓

LM法通過引入一個阻尼因子 λ \lambda λ 來平衡 Gauss-Newton 與 Gradient Descent:

( J T J + λ I ) Δ x = ? J T r (J^T J + \lambda I) \Delta \mathbf{x} = - J^T \mathbf{r} (JTJ+λI)Δx=?JTr

  • λ → 0 \lambda \to 0 λ0,接近高斯-牛頓法;
  • λ → ∞ \lambda \to \infty λ,趨于梯度下降法。

為了更穩定地調整 λ \lambda λ,可以采用如下對角矩陣:

( J T J + λ ? diag ( J T J ) ) Δ x = ? J T r (J^T J + \lambda \cdot \text{diag}(J^T J)) \Delta \mathbf{x} = - J^T \mathbf{r} (JTJ+λ?diag(JTJ))Δx=?JTr

這種處理使 LM 更具有數值穩定性。


四、LM算法偽代碼

x = x0
lambda = lambda_initwhile not converged:r = residual(x)J = jacobian(x)H = J^T * Jg = J^T * rsolve (H + lambda * diag(H)) * dx = -gif cost(x + dx) < cost(x):x = x + dxlambda = lambda / factorelse:lambda = lambda * factor

五、Levenberg-Marquardt 算法實現步驟

步驟 1:初始化

  • 初始化參數向量 x 0 \mathbf{x}_0 x0?
  • 設置初始阻尼系數 λ \lambda λ,通常取 10 ? 3 ~ 10 ? 1 10^{-3} \sim 10^{-1} 10?310?1
  • 設置調整系數(如增長因子 ν = 2 \nu = 2 ν=2
  • 設置收斂條件(如最大迭代次數、步長閾值、誤差閾值)

步驟 2:計算當前殘差與 Jacobian

  • 在當前參數 x \mathbf{x} x 處計算殘差向量 r ( x ) \mathbf{r}(\mathbf{x}) r(x)
  • 計算殘差的 Jacobian 矩陣 J ( x ) J(\mathbf{x}) J(x)

步驟 3:構建 LM 修正的正規方程

構造修正的線性系統:

( J T J + λ ? diag ( J T J ) ) Δ x = ? J T r (J^T J + \lambda \cdot \text{diag}(J^T J)) \Delta \mathbf{x} = -J^T \mathbf{r} (JTJ+λ?diag(JTJ))Δx=?JTr

  • J T J J^T J JTJ:近似 Hessian 矩陣
  • λ ? diag ( J T J ) \lambda \cdot \text{diag}(J^T J) λ?diag(JTJ):用于平滑(阻尼),避免步長過大

步驟 4:求解增量 Δ x \Delta \mathbf{x} Δx

  • 使用 Cholesky / LDLT 分解求解線性方程組,得到參數增量 Δ x \Delta \mathbf{x} Δx
  • 可選:添加線性求解器條件數檢查以保證穩定性

步驟 5:評估新參數點

  • 更新新參數: x new = x + Δ x \mathbf{x}_{\text{new}} = \mathbf{x} + \Delta \mathbf{x} xnew?=x+Δx

  • 計算新誤差 ∥ r ( x new ) ∥ 2 \| \mathbf{r}(\mathbf{x}_{\text{new}}) \|^2 r(xnew?)2

  • 如果誤差變小,接受更新,并降低 λ \lambda λ

    λ ← λ / factor \lambda \leftarrow \lambda / \text{factor} λλ/factor

  • 否則,拒絕更新,提高阻尼系數以減小步長:

    λ ← λ × factor \lambda \leftarrow \lambda \times \text{factor} λλ×factor


步驟 6:檢查收斂條件

  • 如果滿足以下任一條件,則終止:

    • 殘差變化非常小: ∥ Δ x ∥ < ? \| \Delta \mathbf{x} \| < \epsilon ∥Δx<?
    • 最大迭代次數達到
    • 梯度足夠小: ∥ J T r ∥ < ? \| J^T \mathbf{r} \| < \epsilon JTr<?
  • 否則返回步驟 2,繼續迭代


六、總結為流程圖結構

初始化 x, lambda↓
計算殘差 r(x), Jacobian J↓
構建系統 (J?J + λI)Δx = -J?r↓
求解 Δx↓
計算新誤差 cost(x + Δx)↓
誤差減少?┌─────────────┐↓             ↓
Yes           No
↓              ↓
x ← x + Δx     λ ← λ × factor
λ ← λ / factor ↓↓
滿足終止條件?↓Yes → 退出No  → 回到迭代

七、應用示例:擬合二次函數 y = a x 2 + b x + c y = ax^2 + bx + c y=ax2+bx+c

我們以擬合二次函數為例,給定數據點 ( x i , y i ) (x_i, y_i) (xi?,yi?),最小化以下殘差:

r i ( a , b , c ) = y i ? ( a x i 2 + b x i + c ) r_i(a, b, c) = y_i - (a x_i^2 + b x_i + c) ri?(a,b,c)=yi??(axi2?+bxi?+c)

Jacobian:

J i = [ ? x i 2 , ? x i , ? 1 ] J_i = \left[ -x_i^2, -x_i, -1 \right] Ji?=[?xi2?,?xi?,?1]


八、C++代碼實現

#include <iostream>
#include <vector>
#include <Eigen/Dense>using namespace Eigen;
using namespace std;struct DataPoint {double x, y;
};struct LMResult {Vector3d params;double final_cost;int iterations;
};LMResult LevenbergMarquardt(const vector<DataPoint>& data, Vector3d init, int max_iter = 100) {Vector3d x = init;double lambda = 1e-3;double v = 2.0;int n = data.size();double last_cost = 1e20;for (int iter = 0; iter < max_iter; ++iter) {MatrixXd J(n, 3);VectorXd r(n);for (int i = 0; i < n; ++i) {double xi = data[i].x;double yi = data[i].y;double yi_est = x(0) * xi * xi + x(1) * xi + x(2);r(i) = yi - yi_est;J(i, 0) = -xi * xi;J(i, 1) = -xi;J(i, 2) = -1.0;}Matrix3d H = J.transpose() * J;Vector3d g = J.transpose() * r;Matrix3d H_lm = H + lambda * H.diagonal().asDiagonal();Vector3d dx = H_lm.ldlt().solve(-g);Vector3d x_new = x + dx;// compute new costdouble new_cost = 0.0;for (int i = 0; i < n; ++i) {double xi = data[i].x;double yi = data[i].y;double yi_est = x_new(0) * xi * xi + x_new(1) * xi + x_new(2);double ri = yi - yi_est;new_cost += ri * ri;}if (new_cost < last_cost) {x = x_new;lambda *= 0.8;last_cost = new_cost;} else {lambda *= 2.0;}if (dx.norm() < 1e-6) break;}return {x, last_cost, max_iter};
}

九、輸出與測試

int main() {vector<DataPoint> data;for (int i = 0; i <= 10; ++i) {double x = i;double y = 2.0 * x * x + 3.0 * x + 1.0 + ((rand() % 100) / 50.0 - 1.0); // 加噪聲data.push_back({x, y});}Vector3d init(0.0, 0.0, 0.0);auto result = LevenbergMarquardt(data, init);cout << "Estimated parameters: " << result.params.transpose() << endl;cout << "Final cost: " << result.final_cost << endl;return 0;
}

十、總結

方法特點
梯度下降法收斂穩定但慢
高斯-牛頓法快速但易發散
Levenberg-Marquardt二者結合,自動調節,收斂穩定

實用建議

  • 阻尼初始化值 λ \lambda λ:設置為初始 Hessian 的最大對角元素的某個比例(如 λ = τ ? max ? ( diag ( J T J ) ) \lambda = \tau \cdot \max(\text{diag}(J^T J)) λ=τ?max(diag(JTJ))

  • 梯度與步長判斷條件

    • 使用 ∥ Δ x ∥ < 1 e ? 6 \| \Delta \mathbf{x} \| < 1e{-6} ∥Δx<1e?6 ∥ g ∥ < 1 e ? 6 \| g \| < 1e{-6} g<1e?6

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/83775.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/83775.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/83775.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

理解網絡協議

1.查看網絡配置 : ipconfig 2. ip地址 : ipv4(4字節, 32bit), ipv6, 用來標識主機的網絡地址 3.端口號(0~65535) : 用來標識主機上的某個進程, 1 ~ 1024 知名端口號, 如果是服務端的話需要提供一個特定的端口號, 客戶端的話是隨機分配一個端口號 4.協議 : 簡單來說就是接收數據…

如何計算光伏工程造價預算表?

在光伏工程的推進過程中&#xff0c;造價預算表的編制是至關重要的環節&#xff0c;傳統的光伏工程造價預算編制方法&#xff0c;往往依賴人工收集數據、套用定額&#xff0c;再進行繁瑣的計算與匯總&#xff0c;不僅效率低下&#xff0c;而且容易出現人為誤差&#xff0c;導致…

新聞速遞|Altair 與佐治亞理工學院簽署合作備忘錄,攜手推動航空航天領域創新

近日&#xff0c;全球計算智能領域領先企業 Altair 與佐治亞理工學院正式簽署合作備忘錄&#xff0c;旨在深化航空航天領域的技術創新合作。 根據協議&#xff0c;佐治亞理工學院的航空航天系統設計實驗室 (ASDL) 將獲得 Altair 的技術支持&#xff0c;運用仿真與數據分析 (DA)…

PLSQLDeveloper配置OracleInstantClient連接Oracle數據庫

PL/SQLDeveloper配置Oracle Instant Client連接Oracle數據庫 文章目錄 PL/SQLDeveloper配置Oracle Instant Client連接Oracle數據庫 1. Oracle Instant Client下載與配置1. Oracle Instant Client下載2. Oracle Instant Client解壓配置1. 解壓2. 配置 2. PL/SQL Developer下載、…

數據庫系統學習

關系型數據庫 關系型數據庫建立在關系模型基礎上的數據庫&#xff0c;關系型數據庫是由多張能相互相連的二維表組成的數據庫 優點&#xff1a; 都是使用表結構&#xff0c;格式一致&#xff0c;易于維護使用通用的sql語言操作&#xff0c;使用方便&#xff0c;可用于復雜查詢…

美國大休斯頓都會區電網數據

美國大休斯頓都會區&#xff08;Houston-The Woodlands-Sugar Land Metropolitan Area&#xff09;電網數據。數據包括&#xff1a;發電、輸電、變電、配電。而且配電線路也很完善&#xff01;下面是截圖&#xff1a; 輸電線路 配電線路 變電站 開關站 電廠

信創主機性能測試實例(升騰P860)

文章目錄 一、引言二、基準測試&#xff08;Unixbench &#xff09;三、CPU測試&#xff08;SPEC CPU 2006&#xff09;四、GPU測試&#xff08;Glmark2&#xff09;五、IO測試&#xff08;Iozone &#xff09;六、內存基準測試&#xff08;Stream &#xff09;七、網絡性能基準…

Web前端基礎:HTML-CSS

1.標題 1.1標題排版 超鏈接 a 標簽&#xff1a; 標簽&#xff1a;<a href"....." target".....">央視網</a> 屬性&#xff1a; href: 指定資源訪問的urltarget: 指定在何處打開資源鏈接 _self: 默認值&#xff0c;在當前頁面打開_blank: 在…

Python數學可視化:3D參數曲面與隱式曲面繪制技術

Python數學可視化&#xff1a;3D參數曲面與隱式曲面繪制技術 引言 在科學研究、工程設計和數學教學中&#xff0c;3D可視化技術是理解復雜幾何形狀和空間關系的重要工具。本文將介紹如何使用Python實現參數曲面和隱式曲面的3D可視化&#xff0c;通過數學公式和代碼示例展示球…

傳輸層:udp與tcp協議

目錄 再談端口號 端口號范圍劃分 認識知名端口號(Well-Know Port Number) 兩個問題 netstat pidof 如何學習下三層協議 UDP協議 UDP協議端格式 UDP的特點 面向數據報 UDP的緩沖區 UDP使用注意事項 基于UDP的應用層協議 TCP協議 TCP協議段格式 1.源端口號…

java 實現excel文件轉pdf | 無水印 | 無限制

文章目錄 目錄 文章目錄 前言 1.項目遠程倉庫配置 2.pom文件引入相關依賴 3.代碼破解 二、Excel轉PDF 1.代碼實現 2.Aspose.License.xml 授權文件 總結 前言 java處理excel轉pdf一直沒找到什么好用的免費jar包工具,自己手寫的難度,恐怕高級程序員花費一年的事件,也…

Keil調試模式下,排查程序崩潰簡述

在Keil調試模式下&#xff0c;若程序崩潰&#xff0c;可以通過以下步驟來定位崩潰的位置&#xff1a; 一、查看調用棧&#xff08;Call Stack&#xff09; 打開調用棧窗口&#xff1a; 在Keil的調試模式下&#xff0c;點擊菜單欄的“View” -> “Call Stack Window”&…

深度解析Mysql中MVCC的工作機制

MVCC,多版本并發控制 定義&#xff1a;維護一個數據的多個版本&#xff0c;使讀寫操作沒有沖突&#xff0c;依賴于&#xff1a;隱藏字段&#xff0c;undo log日志&#xff0c;readView MVCC會為每條版本記錄保存三個隱藏字段 DB_TRX_ID: 記錄最近插入或修改該記錄的事務IDDB_R…

uniapp+vue3實現CK通信協議(基于jjc-tcpTools)

1. TCP 服務封裝 (tcpService.js) export class TcpService {constructor() {this.connections uni.requireNativePlugin(jjc-tcpTools)this.clients new Map() // 存儲客戶端連接this.servers new Map() // 存儲服務端實例}// 創建 TCP 服務端 (字符串模式)createStringSe…

學習設計模式《十二》——命令模式

一、基礎概念 命令模式的本質是【封裝請求】命令模式的關鍵是把請求封裝成為命令對象&#xff0c;然后就可以對這個命令對象進行一系列的處理&#xff08;如&#xff1a;參數化配置、可撤銷操作、宏命令、隊列請求、日志請求等&#xff09;。 命令模式的定義&#xff1a;將一個…

Webpack的基本使用 - babel

Mode配置 Mode配置選項可以告知Webpack使用相應模式的內置優化 默認值是production&#xff08;什么都不設置的情況下&#xff09; 可選值有&#xff1a;none | development | production; 這幾個選項有什么區別呢&#xff1f; 認識source-map 我們的代碼通常運行在瀏覽器…

「基于連續小波變換(CWT)和卷積神經網絡(CNN)的心律失常分類算法——ECG信號處理-第十五課」2025年6月6日

一、引言 心律失常是心血管疾病的重要表現形式&#xff0c;其準確分類對臨床診斷具有關鍵意義。傳統的心律失常分類方法主要依賴于人工特征提取和經典機器學習算法&#xff0c;但這些方法往往受限于特征選擇的主觀性和模型的泛化能力。 隨著深度學習技術的發展&#xff0c;基于…

C++.OpenGL (11/64)材質(Materials)

材質(Materials) 真實感材質系統 #mermaid-svg-NjBjrmlcpHupHCFQ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-NjBjrmlcpHupHCFQ .error-icon{fill:#552222;}#mermaid-svg-NjBjrmlcpHupHCFQ .error-text{fill:…

P1345 [USACO5.4] 奶牛的電信Telecowmunication

P1345 [USACO5.4] 奶牛的電信Telecowmunication 突然發現 USACO 好喜歡玩諧音梗。 題意就是給定一個無向圖&#xff0c;問你要刪多少點才能使 s , t s,t s,t 不連通。 注意是刪點而不是刪邊&#xff0c;所以不能直接使用最小割來求。所以考慮變換一下題目模型。 經典 tric…

EXCEL如何快速批量給兩字姓名中間加空格

EXCEL如何快速批量給姓名中間加空格 優點&#xff1a;不會導致排版混亂 缺點&#xff1a;無法輸出在原有單元格上&#xff0c;若需要保留原始數據&#xff0c;可將公式結果復制后“選擇性粘貼為值” 使用場景&#xff1a;在EXCEL中想要快速批量給兩字姓名中間加入空格使姓名對…