ガウス・ニュートン法と LM アルゴリズムの類似点と相違点の例

LM (レーベンバーグ-マルカート) アルゴリズムとガウス-ニュートン アルゴリズムは、非線形最小二乗問題の 2 つの最適化アルゴリズムであり、いくつかの類似点もあります。

  1. 反復最適化: LM アルゴリズムとガウス ニュートン アルゴリズムはどちらも反復手法を使用してパラメーター値を最適化し、フィッティング残差を徐々に減らします。

  2. 非線形フィッティング: どちらのアルゴリズムも非線形関数をフィッティングするタスクに適しており、パラメーター化されたモデルと観測データの間の差異をフィッティングする際に良好な結果を示します。

  3. 勾配ベースの最適化: ガウス・ニュートン アルゴリズムと LM アルゴリズムは両方とも、目的関数の勾配情報を利用します。ガウス ニュートン アルゴリズムは目的関数を近似するために一次導関数 (ヤコビ行列) を使用しますが、LM アルゴリズムは勾配降下方向に調整係数を導入します。

  4. ローカル検索: どちらのアルゴリズムもローカル検索方法です。つまり、パラメーター値は反復ごとに更新され、局所的な最適解に近づきます。

LM アルゴリズムとガウス ニュートン アルゴリズムの間には実装の詳細と収束特性に違いがありますが、どちらも非線形最小二乗最適化問題の一般的な方法であり、いくつかの同様のアイデアと原則を共有しています。

LM (Levenberg-Marquardt) アルゴリズムと Gauss-Newton アルゴリズムはどちらも非線形最小二乗問題の最適化アルゴリズムであり、計算方法や収束特性にいくつかの違いがあります

  1. 計算:

    • ガウス ニュートン アルゴリズムは、非線形関数を反復的に線形近似することによって、非線形最小二乗問題を一連の線形最小二乗部分問題に変換します。反復ごとに、線形システムを解くことによってパラメーター値が更新されます。
    • LM アルゴリズムは、ガウス ニュートン アルゴリズムと勾配降下法アルゴリズムの考え方を組み合わせたものです。各反復において、LM アルゴリズムは、ガウス ニュートン アルゴリズムと勾配降下法アルゴリズムの更新ステップ サイズのバランスをとり、さまざまな状況の問題によりよく適応します。
  2. 収束プロパティ:

    • ガウス ニュートン アルゴリズムは 2 次微分情報に依存しており、2 次微分行列の正の確実性は必ずしも保持されないため、パラメーター空間の極小値に収束する可能性があります。
    • LM アルゴリズムでは、最小値に近づくときにパラメーター空間をより適切に探索するために、調整係数 (減衰係数とも呼ばれます) が導入されています。このようなメカニズムは、より優れたグローバル収束を提供し、初期パラメーターの選択に対する感度を低くすることができます。

要約すると、ガウス ニュートン アルゴリズムはより単純で高速な反復法ですが、極小値に収束する可能性があります。LM アルゴリズムはより複雑で、計算にわずかに時間がかかりますが、より優れたグローバル収束パフォーマンスを備えています。実際のアプリケーションでは、問題の特性に応じて適切な最適化アルゴリズムを選択できます。

以下は、C++ を使用してガウス・ニュートン法を実装し、一連のデータを近似するコード例です。

#include <iostream>
#include <Eigen/Dense>

using namespace Eigen;

// 高斯函数模型
double gaussian(double x, double a, double b, double c) {
    
    
    return a * exp(-(x - b) * (x - b) / (2 * c * c));
}

// 高斯牛顿拟合算法
void fitGaussian(const VectorXd& xData, const VectorXd& yData, double& a, double& b, double& c) {
    
    
    int n = xData.size();
    int m = 3; // 参数个数

    MatrixXd J(n, m);   // 雅可比矩阵
    VectorXd residual(n);  // 残差向量
    VectorXd delta(m);  // 参数增量向量

    // 设定初始参数值
    a = 1.0;
    b = 0.0;
    c = 1.0;

    // 设置最大迭代次数和收敛阈值
    int maxIter = 100;
    double epsilon = 1e-6;

    for (int iter = 0; iter < maxIter; ++iter) {
    
    
        // 构造雅可比矩阵和残差向量
        for (int i = 0; i < n; ++i) {
    
    
            double xi = xData(i);
            double residual_i = yData(i) - gaussian(xi, a, b, c);

            J(i, 0) = -residual_i / a;
            J(i, 1) = residual_i * (xi - b) / (c * c);
            J(i, 2) = residual_i * (xi - b) * (xi - b) / (c * c * c);
            residual(i) = residual_i;
        }

        // 计算参数增量
        delta = (J.transpose() * J).inverse() * J.transpose() * residual;

        // 更新参数估计值
        a += delta(0);
        b += delta(1);
        c += delta(2);

        // 判断是否收敛
        if (delta.norm() < epsilon)
            break;
    }
}

int main() {
    
    
    // 原始数据
    VectorXd xData(10);
    VectorXd yData(10);
    xData << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
    yData << 0.98, 1.89, 3.02, 4.15, 4.97, 6.05, 6.92, 8.01, 8.94, 10.02;

    // 拟合参数
    double a, b, c;
    fitGaussian(xData, yData, a, b, c);

    // 输出拟合结果
    std::cout << "Fitted parameters:\n";
    std::cout << "a = " << a << "\n";
    std::cout << "b = " << b << "\n";
    std::cout << "c = " << c << "\n";

    return 0;
}

出力: 1 3 2

gaussian()この例では、ガウス関数モデルを記述するためにガウス関数を定義します。fitGaussian()この関数は、ガウス ニュートン フィッティング アルゴリズムを実装します。このアルゴリズムでは、パラメーターの増分がヤコビアン行列と残差に基づいて計算され、パラメーターの推定値が増分に基づいて更新されます。元のデータのセットが main 関数で与えられ、その後、fitGaussian()フィッティングのために関数が呼び出されます。最後にフィッティング結果を出力します。

なお、これは単純な例であり、実際のアプリケーションでは、状況に応じて適切なモデルとパラメータの最適化計算を選択する必要がある場合があります。

以下は、Levenberg-Marquardt (LM) アルゴリズムを使用したガウス関数フィッティングのサンプル コードです。

#include <iostream>
#include <Eigen/Dense>
#include <unsupported/Eigen/LevenbergMarquardt>

using namespace Eigen;

// 高斯函数模型
struct GaussianModel {
    
    
    template<typename T>
    bool operator()(const T* const x, T* residual) const {
    
    
        T a = params[0];
        T b = params[1];
        T c = params[2];

        residual[0] = y - a * exp(-(x[0] - b) * (x[0] - b) / (2 * c * c));
        
        return true;
    }

    double y;
    Vector3d params;
};

// 高斯牛顿拟合算法
void fitGaussian(const VectorXd& xData, const VectorXd& yData, double& a, double& b, double& c) {
    
    
    int n = xData.size();

    Vector3d params;
    params << 1.0, 0.0, 1.0; // 初始参数值

    // 定义 LM 算法参数
    NumericalDiff<GaussianModel> numericalDiff;
    LevenbergMarquardt<NumericalDiff<GaussianModel>> lm(numericalDiff);
    lm.parameters.maxfev = 100; // 最大迭代次数
    lm.parameters.xtol = 1e-6; // 收敛阈值

    // 构造问题并求解
    GaussianModel model;
    model.params = params;
    
    for (int i = 0; i < n; ++i) {
    
    
        model.y = yData(i);
        VectorXd x(1);
        x << xData(i);
        lm.minimize(x, model);
        params = model.params;
    }

    // 更新拟合结果
    a = params[0];
    b = params[1];
    c = params[2];
}

int main() {
    
    
    // 原始数据
    VectorXd xData(10);
    VectorXd yData(10);
    xData << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
    yData << 0.98, 1.89, 3.02, 4.15, 4.97, 6.05, 6.92, 8.01, 8.94, 10.02;

    // 拟合参数
    double a, b, c;
    fitGaussian(xData, yData, a, b, c);

    // 输出拟合结果
    std::cout << "Fitted parameters:\n";
    std::cout << "a = " << a << "\n";
    std::cout << "b = " << b << "\n";
    std::cout << "c = " << c << "\n";

    return 0;
}

この例では、LevenbergMarquardtEigen ライブラリのクラスを使用して LM アルゴリズムを実装しました。GaussianModelまず、ブラケット演算子がオーバーロードされる構造が定義され、残差が計算されて LM アルゴリズムに返されます。次に、fitGaussian()関数内でオブジェクトが構築され、LevenbergMarquardt最大反復回数と収束しきい値が設定されます。次に、このオブジェクトを使用して各データ ポイントを近似し、パラメーター推定値を更新します。最後に、フィッティング結果が出力されます。

LM アルゴリズムを使用するには、Eigen ライブラリの関連ヘッダー ファイルをコードに追加し、コマンド `-I /path を使用する必要があることに注意してください。

具体的な原則については、https: //zhuanlan.zhihu.com/p/421272861 ?utm_id=0 を参照してください。

おすすめ

転載: blog.csdn.net/xiaojinger_123/article/details/132467683