梯度下降算法:
X(n+1) = X(n) - ηf'(X)
该算法可以用在求一元凸函数的极值(当然也可以求多元凸函数),前提是凸函数。这里使用一元二次方程为例。
// 梯度下降算法求一元凸函数的最优解(极值点)
// 梯度下降算法 X(n+1) = X(n) - ηf'(X)
// 设一元凸函数 y = ax^2 + bx + c (a > 0)
// 1.构造一元凸函数
float a = 1; // a > 0
float b = 2;
float c = 3;
// 2.设置下降起点和下降率(学习率)
float Xn1, Xn0; // X(n+1) 和 X(n)
Xn0 = 10; // 下降起点
// 下降率yita,该值越小,下降越慢(训练过程越慢),结果越准确,该值越大,下降越快(训练过程越快),结果越不准确,
// 当值超过一定的值时,结果无法收敛,将发散。
float yita = 0.001;
float det = 0.001; // 用于利用极限求导数
float thresh = 0.000001; // 判断收敛的阈值
int times = 0; // 迭代次数
// 3.开始梯度迭代
while (1)
{
// 极限法求导数(不使用解析解,因为大部分情况下无法直接求得解析解)
// f(x+det) - f(x)
// lim = -----------------------
//(det->0) det
//
float Xgap = Xn0 + det;
float Fdiv = (((a * Xgap * Xgap) + (b * Xgap) + c) - ((a * Xn0 * Xn0) + (b * Xn0) + c)) / det; // 在Xn0处的导数
Xn1 = Xn0 - yita * Fdiv;
times++;
// 如果梯度下降趋于稳定(下降幅度基本不变),就认为下降已经收敛,找到最优解。
if (fabs(Xn1 - Xn0) < thresh){
cout << "yita = " << yita << endl;
cout << "Best value: " << Xn1 << endl;
cout << "Iteration times: " << times << endl;
break;
}
Xn0 = Xn1;
}
实验结果:
(1)当yita = 0.001时yita = : 0.001
Best value: -0.999952
Iteration times: 4942
(2)当yita = 0.01时
yita = : 0.01
Best value: -1.00043
Iteration times: 567
(3)当yita = 0.1时
yita = : 0.1
Best value: -1.00044
Iteration times: 53
(4)当yita = 1时
结果发散。
结论:
可以看出:下降率yita,该值越小,下降越慢(训练过程越慢),结果越准确,该值越大,下降越快(训练过程越快),结果越不准确,当值超过一定的值时,结果无法收敛,将发散。