最优化方法:无约束梯度问题----最速下降法理论与C++实现

背景

优化问题的关键在于每次更新时方向、步长的选择(比较简单的方式是固定步长,缺陷步长选太小收敛速度慢,太大则在靠近最优值时剧烈震荡)。

最速下降方法:方向选择的是负梯度方向,步长通过极小化 g(k) = f(x0+k*dx) 确定(这里 g(k) 是关于k这个常数的一元函数,可以通过求导等于零求解析解,也可以使用一元搜索方法:斐波那契、黄金分割法迭代计算)。

由于函数的二阶泰勒展开式(忽略无穷小项)形如:f(x) = 1/2*X'AX+X'B+C   (其中X是nx1的列向量,X’是X的转置,A是nxn矩阵,B是nx1列向量,C是常数),所以以解二阶多项式函数最优化问题为例

如何求解梯度、确定步长参考https://www.bilibili.com/video/av14666879/?p=9

最优梯度的缺陷是不能在有限步达到最优值,共轭梯度下降在理论上可以保证N步就收敛(N是未知变量X的维度)

问题

                 min 2*x^2+2*x*y + 5*y^2      初始点 z = [2,-2]'

 

代码实现

#include<iostream>
#include<vector>
using namespace std;

vector<vector<double>> A = {{4.0,2.0},{2.0,10.0}};
vector<double> B = {0.0,0.0};
double C = 0.0;

vector<double> mat_vect(const vector<vector<double>>& arr,const vector<double>& vect){
    int m = arr.size(),n = arr[0].size();
    vector<double> ans;
    for(int i=0;i<m;++i){
        for(int j=0;j<1;++j){
            double tmp = 0;
            for(int p=0;p<n;++p) tmp += arr[i][p]*vect[p];
            ans.push_back(tmp);
        }
    }
    return ans;
}

vector<double> mat_vect(const vector<double>& vect,const vector<vector<double>>& arr){
    int a_n = arr.size(),k = arr[0].size();
    vector<double> ans;
    for(int i=0;i<1;++i){
        for(int j=0;j<k;++j){
            double tmp = 0;
            for(int p=0;p<a_n;++p) tmp += vect[p]*arr[p][j];
            ans.push_back(tmp);
        }
    }
    return ans;
}

double mat_double(const vector<double>& vect1,const vector<double>& vect2){
    double ans = 0.0;
    for(int i=0;i<vect1.size();++i) ans += vect1[i]*vect2[i];
    return ans;
}

double get_func(const vector<double>& x){
    double ans = 0;
    auto tmp = mat_vect(x,A);
    ans = mat_double(tmp,x);
    ans/=2.0;
    ans += mat_double(x,B);
    return ans+C;
}

vector<double> get_grad(const vector<double>& x){
    auto tmp = mat_vect(A,x);
    for(int i=0;i<x.size();++i) tmp[i]+=B[i];
    return tmp;
}

double get_k_star(const vector<double>& x,vector<double>& grad){
    grad = get_grad(x);
    double ans = mat_double(grad,grad);
    auto vect = mat_vect(grad,A);
    double tmp = mat_double(vect,grad);
    return -(ans/tmp);
}

void upgrade(vector<double>& x){
    vector<double> grad;
    double k = get_k_star(x,grad);
    cout<<"k_star: "<<k<<endl<<"X: ";
    for(int i=0;i<x.size();++i){
        x[i] = x[i]+k*grad[i];
        cout<<x[i]<<" ";
    }
    cout<<endl;
    cout<<"f(x): "<<get_func(x)<<endl;
}

int main(){
    vector<double> x = {2.0,-2.0};
    cout<<"f(x): "<<get_func(x)<<endl;
    for(int i=1;i<=8;++i){
        cout<<"----------------------------------"<<i<<endl;
        upgrade(x);
    }
    return 0;
}

运行结果

运行结果与视频中每次迭代求得的值存在误差,可能是计算误差也可能是代码存在问题。期待并欢迎大佬指出

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值