SGD
是梯度下降法的改进,无需对每一组数据进行运算,而是随机抽取一组数据进行运算
学习率(步长):每次前进的距离,设为 lr
梯度(方向向量):每次前进的方向,设为 grad;
此处将参数设为 x
损失函数:
x_{t+1}=x_t-lr\times \rho F/\rho x_txt+1=xt−lr×ρF/ρxt
例题:求F=pow(sin(x),2)+cos(x)+5最靠近6的极值点;
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void main(){
double lr=1e-2;
double x=6,y=6,x_new,x1,y1;
double eps=1e-5;
double grad=2*sin(x)*cos(x)-sin(x);
double F;
int t=0;
while(fabs(grad)>eps){
grad=2*sin(x)*cos(x)-sin(x);
x_new=x-grad*lr;
x=x_new;
t++;
}
x1=x;
y1=pow(sin(x1),2)+cos(x)+5;
printf("(%.5lf , %.5lf)\n",x1,y1);
printf("%d",t);
}
最终结果为:
(6.28318 , 6.00000)
1026
Adam(自适应性梯度算法)
Adam是梯度下降法的变种,用来更新神经网络的权重
通过计算梯度的一阶矩估计和二阶矩估计而为不同参数设计独立的自适应性学习率
加大的学习率(lr)会导致更新速度之前的初始学习速度更快,较小的则会降低。
\beta _1 一阶矩估计的指数衰减率估算值 \beta _2阶矩估计的指数衰减率。对于梯度稀疏的问题,应设为接近1.0 \epsilon 是一个很小的值,以防止在实现中被零除β1一阶矩估计的指数衰减率估算值β2阶矩估计的指数衰减率。对于梯度稀疏的问题,应设为接近1.0ϵ是一个很小的值,以防止在实现中被零除
Adam更新公式:
m_{t+1}=\beta _1\times m_t+(1-\beta _1)grad_tmt+1=β1×mt+(1−β1)gradt
v_{t+1}=\beta _2\times m_t+(1-\beta _2){grad_t}^2vt+1=β2×mt+(1−β2)gradt2
m_{t+1}=m_t/(1-{\beta _1}^t)mt+1=mt/(1−β1t)
v_{t+1}=v_t/(1-{\beta _2}^t)vt+1=vt/(1−β2t)
x_{t+1}=x_t-(lr\times m_t)/(\sqrt[]{v_t} +\epsilon )xt+1=xt−(lr×mt)/(vt+ϵ)
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void main(){
double lr=1e-2,eps=1e-5,beta_1=0.9,beta_2=0.991,m=1,v=1,mt,vt,m_t,v_t,x=6,x_new,y=6,epsilon =1e-7;
int t=0;
double grad=2*sin(x)*cos(x)-sin(x);
while(fabs(grad)>eps){
t++;
grad=2*sin(x)*cos(x)-sin(x);
mt=beta_1*m+(1-beta_1)*grad;
m=mt;
vt=beta_2*v+(1-beta_2)*grad*grad;
v=vt;
m_t=mt/(1-pow(beta_1,t));
v_t=vt/(1-pow(beta_2,t));
x_new=x-lr*mt/(sqrt(vt)+epsilon);
x=x_new;
}
printf("x=%.5lf y=%.5lf\n",x,pow(sin(x),2)+cos(x)+5);
printf("%d\n",t);
}
结果为:
x=6.28318 y=6.00000
300
Adamw
相对于Adam多了一个L2正则化
一般在以下位置加入\lambda x_t一般在以下位置加入λxt
x_{t+1}=x_t-lr(m_t/( \sqrt[2]{v_t} +\epsilon) +\lambda x_t)xt+1=xt−lr(mt/(2vt+ϵ)+λxt)
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void main(){
double lr=1e-2,eps=1e-5,lambda=0.0001,beta_1=0.9,beta_2=0.999,m=0.1,v=0.1,mt,vt,m_t,v_t,x=6,x_new,y=6,epsilon =1e-7;
int t=0;
double grad=2*sin(x)*cos(x)-sin(x);
while(fabs(grad)>eps){
t++;
grad=2*sin(x)*cos(x)-sin(x);
mt=beta_1*m+(1-beta_1)*grad;
m=mt;
vt=beta_2*v+(1-beta_2)*grad*grad;
v=vt;
m_t=mt/(1-pow(beta_1,t));
v_t=vt/(1-pow(beta_2,t));
x_new=x-lr*mt/(sqrt(vt)+epsilon +lambda*x);
x=x_new;
}
printf("x=%.5lf y=%.5lf\n",x,pow(sin(x),2)+cos(x)+5);
printf("%d\n",t);
}
结果为:
x=6.28284 y=6.00000
13