python 拟牛顿法 求非线性方程_[优化] GaussNewton非线性最小二乘算法

点击上方“计算机视觉社区”,选择加"星标"

重磅干货,第一时间送达9fec868cd1b630faadfe435948e23e00.png

76871e09c8ce08192add7c1bdb05745c.gif推导

对于一个非线性最小二乘问题:

d080b893-fc2c-eb11-8da9-e4434bdf6706.svg

高斯牛顿的思想是把 d380b893-fc2c-eb11-8da9-e4434bdf6706.svg 利用泰勒展开,取一阶线性项近似。

d780b893-fc2c-eb11-8da9-e4434bdf6706.svg

带入到(1)式:

db80b893-fc2c-eb11-8da9-e4434bdf6706.svg

对上式求导,令导数为0。

e080b893-fc2c-eb11-8da9-e4434bdf6706.svg

令 e280b893-fc2c-eb11-8da9-e4434bdf6706.svg , e480b893-fc2c-eb11-8da9-e4434bdf6706.svg , 式(4)即为

e980b893-fc2c-eb11-8da9-e4434bdf6706.svg

求解式(5),便可以获得调整增量 eb80b893-fc2c-eb11-8da9-e4434bdf6706.svg 。这要求 ec80b893-fc2c-eb11-8da9-e4434bdf6706.svg可逆(正定),但实际情况并不一定满足这个条件,因此可能发散,另外步长eb80b893-fc2c-eb11-8da9-e4434bdf6706.svg可能太大,也会导致发散。

综上,高斯牛顿法的步骤为

STEP1. 给定初值 ef80b893-fc2c-eb11-8da9-e4434bdf6706.svg STEP2. 对于第k次迭代,计算 雅克比 f480b893-fc2c-eb11-8da9-e4434bdf6706.svg , 矩阵ec80b893-fc2c-eb11-8da9-e4434bdf6706.svg , f980b893-fc2c-eb11-8da9-e4434bdf6706.svg ;根据(5)式计算增量 fc80b893-fc2c-eb11-8da9-e4434bdf6706.svg ; STEP3. 如果 fc80b893-fc2c-eb11-8da9-e4434bdf6706.svg 足够小,就停止迭代,否则,更新 ff80b893-fc2c-eb11-8da9-e4434bdf6706.svg . STEP4. 循环执行STEP2. SPTE3,直到达到最大循环次数,或者满足STEP3的终止条件。

编程实现

问题:非线性方程: 0181b893-fc2c-eb11-8da9-e4434bdf6706.svg ,给定n组观测数据 0381b893-fc2c-eb11-8da9-e4434bdf6706.svg ,求系数 0481b893-fc2c-eb11-8da9-e4434bdf6706.svg .

分析:令 0781b893-fc2c-eb11-8da9-e4434bdf6706.svg ,N组数据可以组成一个大的非线性方程组

0881b893-fc2c-eb11-8da9-e4434bdf6706.svg

我们可以构建一个最小二乘问题:

0b81b893-fc2c-eb11-8da9-e4434bdf6706.svg .

要求解这个问题,根据推导部分可知,需要求解雅克比。

1081b893-fc2c-eb11-8da9-e4434bdf6706.svg

使用推导部分所述的步骤就可以进行解算。代码实现:

https://github.com/ydsf16/Gauss_Newton_solver

/** * This file is part of Gauss-Newton Solver. * * Copyright (C) 2018-2020 Dongsheng Yang  (Beihang University) * For more information see  * * Gauss_Newton_solver is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Gauss_Newton_solver is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Gauss_Newton_solver. If not, see . */#include #include #include #include #include #include #include #include /* 计时类 */class Runtimer{public:    inline void start(){        t_s_  = std::chrono::steady_clock::now();    }        inline void stop(){        t_e_ = std::chrono::steady_clock::now();    }        inline double duration(){        return std::chrono::duration_cast<std::chrono::duration<double>>(t_e_ - t_s_).count() * 1000.0;    }    private:    std::chrono::steady_clock::time_point t_s_; //start time ponit    std::chrono::steady_clock::time_point t_e_; //stop time point};/*  优化方程 */class CostFunction{public:        CostFunction(double* a, double* b, double* c, int max_iter, double min_step, bool is_out):        a_(a), b_(b), c_(c), max_iter_(max_iter), min_step_(min_step), is_out_(is_out)        {}                void addObservation(double x, double y){            std::vector<double> ob;            ob.push_back(x);            ob.push_back(y);            obs_.push_back(ob);        }                void calcJ_fx(){            J_ .resize(obs_.size(), 3);            fx_.resize(obs_.size(), 1);                        for ( size_t i = 0; i < obs_.size(); i ++)            {                std::vector<double>& ob = obs_.at(i);                double& x = ob.at(0);                double& y = ob.at(1);                double j1 = -x*x*exp(*a_ * x*x + *b_*x + *c_);                double j2 = -x*exp(*a_ * x*x + *b_*x + *c_);                double j3 = -exp(*a_ * x*x + *b_*x + *c_);                J_(i, 0 ) = j1;                J_(i, 1) = j2;                J_(i, 2) = j3;                fx_(i, 0) = y - exp( *a_ *x*x + *b_*x +*c_);            }        }              void calcH_b(){            H_ = J_.transpose() * J_;            B_ = -J_.transpose() * fx_;        }                void calcDeltax(){            deltax_ = H_.ldlt().solve(B_);         }              void updateX(){            *a_ += deltax_(0);            *b_ += deltax_(1);            *c_ += deltax_(2);        }                double getCost(){            Eigen::MatrixXd cost= fx_.transpose() * fx_;            return cost(0,0);        }                void solveByGaussNewton(){            double sumt =0;            bool is_conv = false;            for( size_t i = 0; i < max_iter_; i ++)            {                Runtimer t;                t.start();                calcJ_fx();                calcH_b();                calcDeltax();                double delta = deltax_.transpose() * deltax_;                t.stop();                if( is_out_ )                {                    std::cout << "Iter: " << std::left <<std::setw(3) << i << " Result: "<< std::left <<std::setw(10)  << *a_ << " " << std::left <<std::setw(10)  << *b_ << " " << std::left <<std::setw(10) << *c_ <<                     " step: " << std::left <<std::setw(14) << delta << " cost: "<< std::left <<std::setw(14)  << getCost() << " time: " << std::left <<std::setw(14) << t.duration()  <<                    " total_time: "<< std::left <<std::setw(14) << (sumt += t.duration()) << std::endl;                }                if( delta < min_step_)                {                    is_conv = true;                    break;                }                updateX();            }                      if( is_conv  == true)                std::cout << "\nConverged\n";            else                std::cout << "\nDiverged\n\n";        }                Eigen::MatrixXd fx_;        Eigen::MatrixXd J_; // 雅克比矩阵        Eigen::Matrix3d H_; // H矩阵        Eigen::Vector3d B_;        Eigen::Vector3d deltax_;        std::vector< std::vector<double>  > obs_; // 观测        double* a_, *b_, *c_;                int max_iter_;        double min_step_;        bool is_out_;};//class CostFunctionint main(int argc, char **argv) {        const double aa = 0.1, bb = 0.5, cc = 2; // 实际方程的参数    double a =0.0, b=0.0, c=0.0; // 初值        /* 构造问题 */    CostFunction cost_func(&a, &b, &c, 50, 1e-10, true);        /* 制造数据 */    const size_t N = 100; //数据个数    cv::RNG rng(cv::getTickCount());    for( size_t i = 0; i < N; i ++)    {        /* 生产带有高斯噪声的数据 */       double x = rng.uniform(0.0, 1.0) ;       double y = exp(aa*x*x + bb*x + cc) + rng.gaussian(0.05);              /* 添加到观测中 */       cost_func.addObservation(x, y);    }    /* 用高斯牛顿法求解 */    cost_func.solveByGaussNewton();    return 0;}

申明:原文来源网络,由《计算机视觉社区》公众号整理分享大家,仅供参考学习使用,不得用于商用,引用或转载请注明出处!如有侵权请联系删除!

695b631e51d3ad135baf62b8a7d94bc0.png           1f3e3caf63bb93b361e57cda2376cca8.png

长按关注▲                  长按加微信▲

为第一时间送达推文,请加小编微信喔,备注:研究方向+地点+学校/公司+昵称,更快通过申请,实时分享CVPR、ECCV、ICCV等计算机视觉顶级会议,关注深度学习、AR/VR/MR、计算机视觉、自动驾驶、图像分割、目标检测、论文写作、顶会论文解读、算法理论、车道检测、模型优化、目标跟踪、SLAM、点云处理(分割检测)、深度学习。领域,我们期待你的加入。

整理不易,请给  点赞  和  在看  

05403583f2c1fd1142c8c7f7d217af5c.gif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值