【深蓝学院第三章作业】

1 LM算法的实现

1.1 LM算法的原理

LM算法的推导有两种:阻尼法(Damped Method)与置信域法(Trust-Region Methods)。其中PPT中介绍了阻尼法,SLAM十四讲中介绍了置信域法。而论文METHODS FOR NON-LINEAR LEAST SQUARES PROBLEMS.中则将两种方法划分为一节内容,即2.4节Trust Region and Damped Methods。

1.1.1 阻尼法(包含作业三——见(5)式)

阻尼法最早由Levenberg和Marquardt提出,其初衷为构造一个既有优良的前期性质又可在后期接近收敛点的收敛过程中保持较快的速度。由此,其在正规方程(normal equation)中添加了一个阻尼项:当阻尼因子(damping parameter)较大时,正规方程退化为最速下降法(steepest descent method)表达式;当阻尼因子较小时,正规方程则退化为高斯牛顿方法的正规方程形式。因而,对于阻尼因子的选取应当保证,在前期收敛过程中较大,后期收敛过程中较小的趋势。那么如何设计阻尼因子以保证能够获得前述的性质?

L-M方法正规方程:
( J T J + μ I ) Δ l m = − J T f ( 1 ) (J^TJ+\mu I)\Delta_{lm}=-J^Tf \qquad(1) (JTJ+μI)Δlm=JTf(1)
Guass-Newton方法正规方程:
( J T J ) Δ g n = − J T f ( 2 ) (J^TJ)\Delta_{gn}=-J^Tf\qquad(2) (JTJ)Δgn=JTf(2)
最速下降法正规方程:
Δ s d = − J T f ( 3 ) \Delta_{sd}=-J^Tf\qquad(3) Δsd=JTf(3)
为了获得合理的阻尼因子设计,首先是阻尼因子的初始值如何选取;其次是在算法收敛的过程中,阻尼因子能够以我们上面所期望的样子使算法发生变化。

  • 阻尼因子的初始值选取:

阻尼因子的初始值,我们不希望过小,也不希望会过大。在初始状态下,希望 μ \mu μ能够与 J T J J^TJ JTJ中的元素保持一致的数量级。因此,对 J T J J^TJ JTJ进行QR分解获得对应的特征值,使得最大的特征值与 μ \mu μ为相同的数量级即可。然而,每一次迭代均对 J T J J^TJ JTJ进行特征值分解将造成巨大的计算复杂度,幸而矩阵最大的特征值与矩阵对角线上最大的元素是处于相同数量级的,因此将 μ \mu μ取值为 τ ⋅ m a x { ( J T J ) i i } \tau\cdot max\{(J^TJ)_{ii}\} τmax{(JTJ)ii}。其中, τ ∼ [ 1 0 − 8 , 1 ] \tau\sim[10^{-8},1] τ[108,1]

为什么希望阻尼因子有着与 J T J J^TJ JTJ元素有相同的数量级?这可能需要介绍另一种更新方式:
Δ X l m = − ∑ j = 1 n v j T F ′ T v j λ j + μ ( 4 ) \Delta X_{lm}=-\sum_{j=1}^n \frac{v_j^TF'^Tv_j}{\lambda_j+\mu}\qquad(4) ΔXlm=j=1nλj+μvjTFTvj(4)
那么如何用(1)式得到(4)式呢?我们可以进行以下推导:
( J T J + μ I ) Δ l m = − J T f ( V Λ V T + μ I ) Δ l m = − F ′ ( V Λ V T + μ V V T ) Δ l m = − F ′ V ( Λ + μ I ) V T Δ l m = − F ′ Δ l m = − V ( Λ + μ I ) − 1 V T F ′ = − [ v 1 , . . . , v n ] [ 1 λ 1 + μ 1 λ 2 + μ . . . 1 λ n + μ ] [ v 1 T v 2 T . . . v n T ] F ′ T ( 5 ) = − [ v 1 , . . . , v n ] [ v 1 T F ′ T λ 1 + μ v 2 T F ′ T λ 2 + μ . . . v n T F ′ T λ n + μ ] = − ( v 1 T F ′ T λ 1 + μ v 1 + v 2 T F ′ T λ 2 + μ v 2 + . . . + v n T F ′ T λ n + μ v n ) = − ∑ j = 1 n v j T F ′ T λ j + μ v j (J^TJ+\mu I)\Delta_{lm}=-J^Tf\\ (V\Lambda V^T+\mu I)\Delta_{lm}=-F'\\ (V\Lambda V^T+\mu VV^T)\Delta_{lm}=-F'\\ V(\Lambda+\mu I)V^T\Delta_{lm}=-F'\\ \Delta_{lm}=-V(\Lambda+\mu I)^{-1}V^TF'\\ =-\left[v_1,...,v_n\right] \left[ \begin{matrix} \frac{1}{\lambda_1+\mu}&&&\\ &\frac{1}{\lambda_2+\mu}&&\\ &&...&\\ &&&\frac{1}{\lambda_n+\mu} \end{matrix} \right] \left[ \begin{matrix} v_1^T\\ v_2^T\\ ...\\ v_n^T \end{matrix} \right]F'^T\qquad(5)\\ =-\left[v_1,...,v_n\right] \left[ \begin{matrix} \frac{v_1^TF'^T}{\lambda_1+\mu}\\ \frac{v_2^TF'^T}{\lambda_2+\mu}\\ ...\\ \frac{v_n^TF'^T}{\lambda_n+\mu} \end{matrix} \right]\\ =-(\frac{v_1^TF'^T}{\lambda_1+\mu}v_1+ \frac{v_2^TF'^T}{\lambda_2+\mu}v_2+ ...+\frac{v_n^TF'^T}{\lambda_n+\mu}v_n) =-\sum_{j=1}^{n}\frac{v_j^TF'^T}{\lambda_j+\mu}v_j (JTJ+μI)Δlm=JTf(VΛVT+μI)Δlm=F(VΛVT+μVVT)Δlm=FV(Λ+μI)VTΔlm=FΔlm=V(Λ+μI)1VTF=[v1,...,vn]λ1+μ1λ2+μ1...λn+μ1v1Tv2T...vnTFT(5)=[v1,...,vn]λ1+μv1TFTλ2+μv2TFT...λn+μvnTFT=(λ1+μv1TFTv1+λ2+μv2TFTv2+...+λn+μvnTFTvn)=j=1nλj+μvjTFTvj
通过(5)式中的推导能够得到(4)式中的结论,从(4)式中能够看出当阻尼因子 μ \mu μ与特征值 λ \lambda λ保持相同的数量级时,能够达到综合sgd和guass-newton的结果。
此外,有时我们觉得自己的结果离最终的收敛状态较近,因此需要将阻尼值调小以期达到更加接近高斯牛顿收敛的方法,因为高斯牛顿在后期收敛过程中效果较好(即接近最终值的时候)。
基于上述描述,我们可以理解 τ ∼ [ 1 0 − 8 , 1 ] \tau\sim[10^{-8},1] τ[108,1]的含义。

  • 阻尼因子在收敛过程中的设置:
    设置一个比例因子 ρ \rho ρ来定量分析阻尼因子的更新,在前面已经给出了定性分析的方法,我们来分析定量如何进行表示。

这里设置 ρ \rho ρ为实际下降与近似下降之比,其中实际下降为目标函数 F ( x ) F(x) F(x)与其在 Δ \Delta Δ作用下的更新 F ( X + Δ l m ) F(X+\Delta_{lm}) F(X+Δlm)之差,近似下降为依据高斯牛顿法近似后的目标函数 F ( x ) F(x) F(x)(记作 L ( 0 ) L(0) L(0))与其在 Δ \Delta Δ作用下的更新 L ( Δ l m ) L(\Delta_{lm}) L(Δlm)之差。所以 ρ \rho ρ可以表示为如(6)式所示的形式。
ρ = F ( x ) − F ( x + Δ X l m ) L ( 0 ) − L ( Δ X l m ) ( 6 ) \rho=\frac{F(x)-F(x+\Delta X_{lm})}{L(0)-L(\Delta X_{lm})}\qquad(6) ρ=L(0)L(ΔXlm)F(x)F(x+ΔXlm)(6)
那么可以做出如下决策:

  • ρ < 0 \rho<0 ρ<0:说明 F ( x ) F(x) F(x)增大了,因此需要将这次更新舍弃,并且增大阻尼因子,以达到SGD的效果,即更快速地降低目标函数的值;
  • ρ > 0 \rho>0 ρ>0且较大:说明实际下降太快,希望将下降速度调低,因此需要减小阻尼因子,以趋向于高斯牛顿;
  • ρ > 0 \rho>0 ρ>0且较小:说明实际下降太慢,希望将下降速度调高,以更快地达到最终目标,即趋向于SGD。

于是有如下的调整策略:

  • 1963 M a r q u a r d t 1963\quad Marquardt 1963Marquardt
    i f , ρ < 0.25 μ = μ ∗ 2 e l i f , ρ > 0.75 μ = μ ∗ 1 3 if,\rho<0.25\\ \mu=\mu*2\\ elif,\rho>0.75\\ \mu=\mu*\frac{1}{3} if,ρ<0.25μ=μ2elif,ρ>0.75μ=μ31
  • 1999 N i e l s e n 1999\quad Nielsen 1999Nielsen
    i f , ρ > 0 : μ = μ ∗ m a x { 1 3 , 1 − ( 2 ρ − 1 ) 3 } , v = 2 e l s e : μ = μ ∗ v , v = 2 ∗ v if,\rho>0:\\ \mu=\mu*max\{\frac{1}{3},1-(2\rho-1)^3\},v=2\\ else:\\ \mu=\mu*v,v=2*v if,ρ>0:μ=μmax{31,1(2ρ1)3},v=2else:μ=μv,v=2v

两种策略无所谓最优,对于Marquardt会有目标函数值上下跳跃的情况,而Nielson策略则回避了这一点,或许在某些情况下使用Nielson策略会更好一些?

1.1.2 置信域法

置信域法只是在推导思路方面与阻尼法有所不同,但是结论是一致的。阻尼法直接在正规方程上做文章,而置信域法则在目标函数上做文章。其在高斯牛顿法的基础上加上了信赖区域,即最终为求解:
min ⁡ Δ x k 1 2 ∥ f ( x k ) + J ( x k ) T Δ x k ∥ 2 , s . t . ∥ D Δ x k ∥ 2 ≤ μ ( 7 ) \min_{\Delta x_k}\frac{1}{2}\|f(x_k)+J(x_k)^T\Delta x_k\|^2,\quad s.t.\quad \|D\Delta x_k\|^2\le\mu\quad(7) Δxkmin21f(xk)+J(xk)TΔxk2,s.t.DΔxk2μ(7)
用拉格朗日乘子将约束项放到目标函数中,构成拉格朗日函数,之后求导能够得到类似于正规方程的形式:
( H + λ D T D ) Δ x k = g ( 8 ) (H+\lambda D^TD)\Delta x_k=g\qquad(8) (H+λDTD)Δxk=g(8)
若将 D D D认为是单位阵,那么就能够得到(1)式。

1.2 作业一

1.2.1 绘制阻尼因子随迭代变化的曲线图
  • 第一步:输出阻尼因子信息以及cost变化

对problem.cc的solve函数进行如下改变:

	ostringstream csvfilename;
    std::ofstream Lambda_data;
    csvfilename << "/home/tiandao/CLionProjects/course_vio/lecture3/result/Lambda.csv";
    Lambda_data.open(csvfilename.str(), ios_base::out);
    while (!stop && (iter < iterations)) {
        std::cout << "iter: " << iter << " , chi= " << currentChi_ << " , Lambda= " << currentLambda_
                  << std::endl;
        Lambda_data << currentChi_ << "," << currentLambda_ << endl;

则能够在对应的路径下获得.csv文件,其中包含了阻尼因子信息以及cost变化。

  • 第二步:用python绘制阻尼因子随迭代的变化曲线图,以及cost随迭代的变化曲线图

这里采用python3的matplotlib和pandas绘制,代码如下:

import matplotlib.pyplot as plt
import os
import pandas as pd

filepath = os.path.abspath('.')
Chi = []
Lambda = []

result_list = pd.read_csv('/home/tiandao/CLionProjects/course_vio/lecture3/result/Lambda.csv')
Lambda = result_list['Lambda']
Chi = result_list['Chi']
print(result_list)

fig1 = plt.figure(1)
plt.plot(Lambda)
fig1.savefig('./result/lambda.png')

fig2 = plt.figure(2)
plt.plot(Chi)
fig2.savefig('./result/Chi.png')

阻尼因子随迭代次数变化的结果如下所示:
在这里插入图片描述
cost随迭代次数变化的结果如下所示:
在这里插入图片描述
可以看出,cost值一直减小,直至收敛;而阻尼因子则会在初始迭代过程中上升以获得前期的sgd特性,而后期阻尼因子则会减小以获得后期的guass-newton特性。

1.2.2 获得修改后曲线的参数估计

对CurveFitting.cpp进行如下修改。
第一处:构造残差部分

//residual_(0) = std::exp(abc(0)*x_*x_ + abc(1)*x_ + abc(2)) - y_;
        residual_(0) = abc(0)*x_*x_ + abc(1)*x_ + abc(2) - y_;  // 构建残差

第二处:雅可比部分

//jaco_abc << x_ * x_ * exp_y, x_ * exp_y , 1 * exp_y;
        jaco_abc << x_ * x_, x_, 1;

第三处:观测部分

// 观测 y
        double y = a*x*x + b*x + c + n;
        // double y = std::exp(a*x*x + b*x + c) + n;

经过修改后能够输出如下结果
在这里插入图片描述
我们发现优化的结果很差,离ground truth还差了很远,分析原因应该是数据点过少,所以增加数据点看看是否能够提升效果。将数据点数从100修改为1000个,能够得到如下的结果:
在这里插入图片描述
可以明显看到精度的提升。

1.2.3 其他更优秀策略的尝试

在论文“The Levenberg-Marquardt method for nonlinear least squares curve-fitting problems”中涉及到三种策略,其中前两种策略为需要实现的策略,第三种策略为Nielson策略,在原代码中已经进行了实现,下面对前两种策略进行实现。

  • 策略一:

初值选取不一致,且阻尼因子更新策略不一致。修改AddLambdatoHessianLM()、RemoveLambdaHessianLM()和IsGoodStepinLM()函数。

策略如下:

在这里插入图片描述
在这里插入图片描述
代码修改:

void Problem::AddLambdatoHessianLM() {
    ulong size = Hessian_.cols();
    assert(Hessian_.rows() == Hessian_.cols() && "Hessian is not square");
    for (ulong i = 0; i < size; ++i) {
        Hessian_(i, i) *= (1.+currentLambda_);//修改处
    }
}

void Problem::RemoveLambdaHessianLM() {
    ulong size = Hessian_.cols();
    assert(Hessian_.rows() == Hessian_.cols() && "Hessian is not square");
    // TODO:: 这里不应该减去一个,数值的反复加减容易造成数值精度出问题?而应该保存叠加lambda前的值,在这里直接赋值
    for (ulong i = 0; i < size; ++i) {
        Hessian_(i, i) /= (1.+currentLambda_);//修改处
    }
}
bool Problem::IsGoodStepInLM() {

    // recompute residuals after update state
    // 统计所有的残差
    double tempChi = 0.0;
    for (auto edge: edges_) {
        edge.second->ComputeResidual();
        tempChi += edge.second->Chi2();
    }

    ulong size = Hessian_.cols();
    MatXX diag_hessian(MatXX::Zero(size, size));
    for (ulong i = 0; i < size; ++i) {
        diag_hessian(i, i) = Hessian_(i, i);
    }

    double scale = 0;
    scale = delta_x_.transpose() * (currentLambda_ * diag_hessian * delta_x_ + b_);
    scale += 1e-3;    // make sure it's non-zero :)

    double rho = (currentChi_ - tempChi) / scale;
//    std::cout << "rho = " << rho << std::endl;

    double L_down = 9.0;
    double L_up = 11.0;

    if (rho > 0 && isfinite(tempChi))
    {// last step was good, 误差在下降{
        currentLambda_ = std::max(currentLambda_ / L_down, 1e-7);
        currentChi_ = tempChi;
        return true;
    } else {
        currentLambda_ = std::min(currentLambda_ * L_up, 1e7);
        return false;
    }
}

结果:

在这里插入图片描述

  • 策略二:

初值选取一致,阻尼因子更新策略不一致。只需修改IsGoodStepInLM()函数。

策略如下:

在这里插入图片描述
修改部分:

bool Problem::IsGoodStepInLM() {

    // recompute residuals after update state
    // 统计所有的残差
    double tempChi = 0.0;
    for (auto edge: edges_) {
        edge.second->ComputeResidual();
        tempChi += edge.second->Chi2();
    }
//    cout << "currentChi_:" << currentChi_ << endl;
//    cout << "tempChi:" << tempChi << endl;

    double Numerator = b_.transpose() * delta_x_;
        double alpha = Numerator / ((currentChi_ - tempChi)/2. + 2.*Numerator);
        alpha = std::max(alpha, 1e-1);
    //    cout << "Numerator:" << Numerator << endl;
    //    cout << "alpha:" << alpha << endl;

    RollbackStates();
    delta_x_ *=alpha;
    UpdateStates();

    tempChi = 0.0;
    for (auto edge: edges_) {
        edge.second->ComputeResidual();
        tempChi += edge.second->Chi2();
    }

    double scale = 0;
    scale = delta_x_.transpose() * (currentLambda_ * delta_x_ + b_);
    scale += 1e-3;    // make sure it's non-zero :)
    double rho = (currentChi_ - tempChi) / scale;
    //    std::cout << "rho = " << rho << std::endl;

    if (rho > 0 && isfinite(tempChi))   // last step was good, 误差在下降
        {
        currentLambda_ = std::max(currentLambda_ / (1.+alpha), 1e-7);
        currentChi_ = tempChi;
        return true;
        } else {
        currentLambda_ += abs(currentChi_ - tempChi)/(2.*alpha);
        return false;
    }
}

结果:
在这里插入图片描述

2 作业二——雅可比公式推导

作业所示的两项如下图所示:
在这里插入图片描述

### 深蓝学院路径规划课程第三章PPT下载指南 对于希望获取深蓝学院关于路径规划课程第三章基于采样的路径规划相关内容的学生而言,通常这类资源会通过官方渠道提供给注册学员。如果学生已经报名参加此课程,则可以直接登录深蓝学院的学习平台,在对应章节页面寻找资料下载链接[^1]。 假设当前无法直接访问或未找到特定的PPT文件,建议采取如下方法: #### 方法一:联系客服支持 利用官方网站提供的联系方式,向深蓝学院的教学团队发送邮件询问所需材料的具体位置或者请求发送电子版副本。 #### 方法二:加入学习社区交流群组 许多在线教育机构都会建立QQ群、微信群或者其他形式的学习小组供同学们讨论问题并分享有用的信息。加入这些社群可能会更快捷地获得帮助和支持。 #### 方法三:查阅公告区通知 有时教师会在平台上发布额外的通知说明如何获取补充教学材料。定期查看课程首页及其下方的相关板块有助于及时掌握最新消息。 需要注意的是,未经授权擅自传播受版权保护的内容可能违反法律法规和服务条款。因此,在寻求外部途径之前应优先考虑合法合规的方式取得授权使用的教材。 ```python # 示例代码用于展示如何模拟网页抓取(仅供理解概念用途) import requests url = "https://www.deepblueschool.com/course/robotics/path-planning/chapter3" response = requests.get(url) if response.status_code == 200: print("成功连接至目标网站") else: print(f"未能正常加载页面, 错误码:{response.status_code}") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值