3.2 数值微分

损失函数的值越小,代表我们选取的参数越适合;想要求得损失函数的最小值,最基本的想法就是对函数求导,解出导数值为0的点,并判断它是否为极小值/最小值。

然而,实际的函数直接求导,不容易得到解析解。这时可以用数值微分的方式来求某点处的导数,这在工程上应用非常广泛。

3.2.1 导数和数值微分

图片[1]-3.2 数值微分-大赛人网
图片[2]-3.2 数值微分-大赛人网

利用这个定义,我们可以直接以数值计算的方式,利用微小的差分来求函数某点处的导数值,这种方法称为 数值微分。

数值微分可以用代码实现非常方便地实现:

def numerial_diff(f, x):
    h = 1e-4  # 微小值 0.0001
    return (f(x+h) - f(x-h)) / (2 * h)

在这里,我们以x为中心,计算它两边各发生微小变化后的差分,可以避免只计算单向增大时的误差。这种方法称为 中心差分。

另外,取微小值h时不能太小,这会导致计算机浮点数表示的精度不够,出现舍入误差。

3.2.2 偏导数

图片[3]-3.2 数值微分-大赛人网
图片[4]-3.2 数值微分-大赛人网
图片[5]-3.2 数值微分-大赛人网

3.2.3 梯度

图片[6]-3.2 数值微分-大赛人网
图片[7]-3.2 数值微分-大赛人网

在函数的极小值、极大值和鞍点处,梯度为0。

需要注意的是,梯度代表的其实是函数值增大最快的方向;在实际应用中,我们需要寻找损失函数的最小值,所以一般选择 负梯度 向量。同样地,负梯度代表的是函数值减小最快的方向,并不一定直接指向函数图像的最低点。

利用数值微分,我们可以在代码中实现梯度的计算:

def _numerical_gradient(f, x):
    h = 1e-4 # 0.0001
    grad = np.zeros_like(x)
    
    for idx in range(x.size):
        tmp_val = x[idx]
        x[idx] = float(tmp_val) + h
        fxh1 = f(x) # f(x+h)
        
        x[idx] = tmp_val - h 
        fxh2 = f(x) # f(x-h)
        grad[idx] = (fxh1 - fxh2) / (2*h)
        
        x[idx] = tmp_val # 还原值
        
    return grad
© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发
头像-大赛人网
欢迎您留下宝贵的见解!
提交
头像-大赛人网

昵称

取消
昵称

    请登录后查看评论内容