梯度下降法(Gradient descent)
1.梯度下降理解
可以用山的高度来解释,假设有一个人站在山上的某一点,他通过观察发现了一条“最陡”的路,那么这条路的方向就是梯度所指的方向。梯度是一个矢量,方向导数是一个标量,梯度所指向的方向是方向导数最大的方向,且梯度的模和方向导数的最大值相等。求梯度的方法很简单,对每一个自变量求偏导数,然后将其偏导数作为自变量方向的坐标即可。梯度的符号为∇,则函数f(x,y)的梯度为:
梯度下降法是一个最优化算法,通常也称为最速下降法。最速下降法是用负梯度方向为搜索方向的,最速下降法越接近目标值,步长越小,前进越慢,梯度下降法的计算过程就是沿梯度下降的方向求解极小值。
2.如何使用梯度下降法
以函数f(x)为例,先选择一个初始点,计算该点的梯度,然后按照梯度的方向更新自变量。若第k次迭代值为x(k),则
其中α称作步长或者学习率,表示自变量每次迭代变化的大小。一直按照上式更新自变量,直到当函数值变化非常小(如3%以内)或者达到最大迭代次数时停止,此时认为自变量更新到函数的极小值点。
3.梯度下降法求极值点示范
eg.求解下列函数在(0,0)(-1,-1)(-1,-2)(-2,-1)点对应的区域极值点,并输出函数值:
f=sin(y)*exp((1-cos(x))^2)+cos(x)*exp((1-sin(y))^2)+(x-y)^2;
1.matlab实现
gradient.m
clc;
syms x y;
f=func(x,y);
ezmesh(x,y,f,[-5,0],[-5,0]);
hold on;
step=0.001;
x0=0;y0=0;
i = 0;
while i<100000 && x0>-5 && x0<=0 && y0<=0 && y0>-5
x0 = x0 - step*dfx(x0,y0);
y0 = y0 - step*dfy(x0,y0);
f = func(x0,y0);
plot3(x0,y0,f,'.r');
if dfx(x0,y0)<0.1&&dfy(x0,y0)<0.1
break;
end
i = i+1;
end
function [ f ] = func( x,y )
f=sin(y).*exp((1-cos(x)).^2)+cos(x).*exp((1-sin(y)).^2)+(x-y).^2;
end
function [ dfx ] = dfx( x1,y1 )
syms x y;
f=func(x,y);
dfx=diff(f,x);
dfx=subs(dfx,x,x1);
dfx=subs(dfx,y,y1);
dfx=eval(dfx);
end
function [ dfy ] = dfy( x1,y1 )
syms x y;
f=func(x,y);
dfy=diff(f,y);
dfy=subs(dfy,x,x1);
dfy=subs(dfy,y,y1);
dfy=eval(dfy);
end
示意结果图
2.c/c++实现
#include<stdio.h>
#include<math.h>
double Func(double x, double y)
{
double cosx = cos(x), siny = sin(y);
double a = 1 - cosx, b = 1 - siny, c = x - y;
return siny*exp(a*a) + cosx*exp(b*b) + c*c;
}
double Dfx(double x, double y)
{
double dfx;
dfx = 2*x - 2*y - exp((sin(y) - 1)*(sin(y) - 1))*sin(x) - 2*exp((cos(x) - 1)*(cos(x) - 1))*sin(x)*sin(y)*(cos(x) - 1);
return dfx;
}
double Dfy(double x, double y)
{
double dfy;
dfy = 2*y - 2*x + exp((cos(x) - 1)*(cos(x) - 1))*cos(y) + 2*exp((sin(y) - 1)*(sin(y) - 1))*cos(x)*cos(y)*(sin(y) - 1);
return dfy;
}
void main()
{
double x,y,f,i,step=0.001;
double dfx, dfy;
printf("请输入x y\n");
scanf_s("%lf %lf", &x, &y);
printf("x=%.3lf ,y=%.3lf \n",x,y);
for (i = 0;i < 10000;i++)
{
dfx = Dfx(x, y);
dfy = Dfy(x, y);
if ((x > 0 || x < -5) && (y > 0 || y < -5))
break;
else if (dfx < 0.001&&dfy < 0.001)
break;
x = x - step*Dfx(x, y);
y = y - step*Dfy(x, y);
f = Func(x, y);
}
printf("i=%lf\n", i);
printf("x=%.3lf y=%.3lf f=%.3lf\n",x,y,f);
}
运行
第一次写博客不足之处敬请谅解,期待您的建议与问题。