zoukankan      html  css  js  c++  java
  • 【原】手写梯度下降《一》之

    为什么要梯度下降,因为在机器学习与视觉SLAM中,有关目标函数的最优值求解过程,都会涉及到目标函数求解,这个过程需要梯度下降。今天我们从最简单,最古老,最经典的最小二乘开始。本文以线性最小二乘为例子,至于非线性最小二乘问题,其中增量方程的求解算法很多,以后再更新。

     

     下面我们借助 opencv, 将 最小二乘算法应用于直线拟合。

     

      1 #define _CRT_SECURE_NO_WARNINGS
      2 #include<vector>
      3 #include<iostream>
      4 #include<algorithm>
      5 using namespace std;
      6 
      7 #include<opencv2/opencv.hpp>
      8 using namespace cv;
      9 
     10 // 功能:打印数组
     11 void printVec(vector<double>& vec)
     12 {
     13     for (auto& ele:vec)
     14     {
     15         cout << ele << " ";
     16     }
     17     cout << endl;
     18 }
     19 
     20 // 功能:打印Mat
     21 void printMat(Mat& mat)
     22 {
     23     for (int j = 0; j < mat.rows; j++)
     24     {
     25         for (int i = 0; i < mat.cols; i++)
     26         {
     27             cout.width(10);
     28             if (abs(mat.ptr<double>(j)[i]) < 1e-5)
     29             {
     30                 cout << "0";
     31             }
     32             else
     33             {
     34                 cout << mat.ptr<double>(j)[i];
     35             }    
     36         }
     37         cout << endl;
     38     }
     39     cout << endl;
     40 }
     41 
     42 // 功能: 计算误差平方和
     43 double SSE(vector<double> x, vector<double> y , Mat ANSS)
     44 {
     45     double errors = 0;
     46     for (size_t i = 0; i < y.size(); i++) // 0
     47     {
     48         double y_predict = 0;
     49         for (size_t j = ANSS.rows; j > 0; j--) // 0
     50         {
     51             y_predict += ANSS.ptr<double>(ANSS.rows - j)[0]*pow(x[i], j - 1);
     52         }
     53         errors  += pow(y[i] - y_predict, 2);
     54     }
     55     return errors;
     56 }
     57 int main()
     58 {
     59     fstream f("least_square.txt", ios::out);
     60     vector<double> x{ 2,4,5,6,6.8,7.5,9,12,13.3,15};
     61     vector<double> y{ -10,-6.9,-4.2,-2,0,2.1,3,5.2,6.4,4.5 };
     62     //<1>写入 x、y
     63     for (auto& ele : x)
     64     {
     65         f << ele << " ";
     66     }
     67     f << endl;
     68     for (auto& ele : y)
     69     {
     70         f << ele << " ";
     71     }
     72     f << endl;
     73 
     74     int k = x.size();
     75     for (int n = 1; n <= 10; n++)
     76     {
     77         //int n = 1;
     78         Mat X0 = Mat::zeros(k, n + 1, CV_64F); // 这里需要注意 CV_64F <-- double
     79         X0 = X0.t();
     80         //<2>构建矩阵x0
     81         for (int j = 0; j <= X0.rows - 1; j++) // [0, 1]
     82         {
     83             for (int i = 0; i <= X0.cols - 1; i++)//[0, 9]
     84             {
     85                 X0.ptr<double>(j)[i] = pow(x[i], X0.rows - j - 1);
     86             }
     87         }    
     88         Mat ANSS = Mat::zeros(n + 1, 1, CV_64F);
     89         Mat y_ = Mat::zeros(y.size(), 1, CV_64F);
     90         for (int i = 0; i < y.size(); i++)
     91         {
     92             y_.ptr<double>(i)[0] = y[i];
     93         }
     94         ANSS = (X0*X0.t()).inv()*X0*y_;
     95     printMat(ANSS);
     96     cout << "SSE = " << SSE(x, y, ANSS) << endl;
     97     // < >写入拟合参数
     98     for (int j = 0; j < ANSS.rows; j++)
     99     {
    100         f << ANSS.ptr<double>(j)[0] << " ";
    101     }
    102     f << endl;
    103     cout << "----------" << endl;
    104     }
    105     return 0;
    106 }

    看到上述代码计算出来 4次拟合结果和matlab拟合工具箱计算结果基本一致,OK,再看 10 次拟合 的最小误差平方和是最小的,一般次数过高导致过拟合。

    【后续增加置信度等等拟合结果评价参数】 

    现在我们在Matlab键入如下数据并拟合

    x = 1:1:10;

    y = 1:1:10;

    我们用拟合工具箱,一次拟合如下图:

    现在假设x = 11的时候,传感器故障了,采回的数据出现错误,y = 100;此时,我们还用上面拟合工具箱进行拟合,得出效果如下:

    显然,拟合效果非常差,因为最小二乘将错误的样本数据对参数的估计也引入了;此时,这种方法失效,我们下一节介绍Ransac算法来进行改进“最小二乘的抗噪性”不足这一缺点。 

    参考:https://blog.csdn.net/StupidAutofan/article/details/78924601

  • 相关阅读:
    使用Navicat for Oracle新建表空间、用户及权限赋予---来自烂泥
    NonAction与ChildActionOnly
    C# Monitor的Wait和Pulse方法使用详解
    机械键盘简介
    【转载】 中小型研发团队架构实践
    BinaryReader 自己写序列化
    显式接口实现
    AssemblyVersion和AssemblyFileVersion的区别
    自定义设置程序集版本重定向和程序集位置的信息
    单例模式中的属性实现
  • 原文地址:https://www.cnblogs.com/winslam/p/9815483.html
Copyright © 2011-2022 走看看