梯度下降算法在神经网络的训练中扮演着非常重要的角色,在本文中,我们来仔细介绍一下梯度下降算法。假设我们遇到了一个函数,其方程为F(x)=x2+10x+5,现在我们要去求它的最值(最大值或者最小值),如果让我们自己来求,我们可以很容易看出该函数存在最小值,并且在对称轴x=-b/2a=-5处取得最小值,最小值为-20。但是如果让计算机去求它的最小值应该怎样做呢?这就是我们今天要介绍的内容。

  我们画出该方程的图像,如图1-2所示:

图1-2  函数F(x)=x2+10x+5的图像

从图中可以看出,函数的最小值就是M点处,但是计算机应该怎样找到M点,首先我们在该图上随便找一点,该点为A点,然后沿着A点,往下走一步,此时就到了B点,紧接着再往下走一点,就回到达C点,就这样一步一步地走,总会到达我们要找的最小值点,也就是M点。可能这时候有人会问,在找到A点后,我们怎么能够判断往哪边走是向下走?如果往A的左边走一直就会向上,这样永远就走不到M点了啊,此时我们需要考虑一下,怎样才能保证每一步都是在向下走呢?这时候就轮到你在学校时天天抱怨学了没用的导数起作用了,可能有人疑惑,导数在这里有什么用呢,那让我们回忆一下导数的几何意义,导数就是图像在该点处切线的斜率,也就是函数值上升的方向。等等,上升的方向?那么给它添负号不就变成了函数值下降的方向,没错函数的导数,也称为梯度,加负号就是函数值下降的方向。方向问题解决了,但还有一个问题,每次向下走一步,这一步到底是多大,在这里我们会用一个常数a来表示这一步的大小,a被称为学习率,是人为给定的,这个值不能太大也不能太小,太大了容易跨过最小值M,太小了向下走次数太多,不容易在短时间内找到M点。我们怎样知道要找的M是否已经找到呢?当然是当该点的导数是否为0来决定,下面我们简述一下梯度下降算法:

1.随便取一个值x0。

2.判断函数在x0处的导数是否为0。

3.如果为0,函数的最小值点就是x0,如果不等于0,x0=x0-a*F1(x0)返回第2步。

接下来我们使用程序来实现:

 

 

public class Gradient {
    public static void main(String[] args) {
        float x0 = 1.0f;
        //学习率
        float a = 0.3f;
        int i=0;
        while (true) {
            //求函数F(x)=x2+10x+5在x0处的导数
            float g=2*x0+10;
            System.out.println(""+i+"次的导数(梯度)为"+g);
            //一般不能精确到0,足够小即可认为等于0
            if (Math.abs(g)<0.001) {
                break;
            }
            x0=(x0-a*g);
            i++;
        }
        System.out.println("函数的最小值点为"+x0+",最小值为"+(x0*x0+10*x0+5));
    }
}

 

程序运行结果如下:

 

从图中我们可以看到程序运行的结果很接近最小值点-5和最小值-20,随着迭代次数的增加,结果会越来越准确。

 

posted on 2020-11-29 22:16  梦想不大的小菜鸟  阅读(309)  评论(0编辑  收藏  举报