深度学习5:神经网络学习2:数值微分,偏导,梯度

目录标题

一、数值微分概念

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

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

二、数值微分代码

python 复制代码
# 数值微分求导,传入x时一个标量
def numerical_diff(f, x):
    h = 1e-4  # 微小值 0.0001
    return (f(x+h) - f(x-h)) / (2 * h)

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

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

利用数值微分求导,测试代码

函数y = 0.01x^2 + 0.1x 在 x=5 处的导数

y ′ = 0.02 x + 0.1 y' = 0.02x + 0.1 y′=0.02x+0.1

(箭头指向 0.02 x 0.02x 0.02x 处)

x = 5 x = 5 x=5

python 复制代码
import numpy as np

import matplotlib.pyplot as plt

from common.gradient import numerical_diff

# 原函数 y = 0.01x^2 + 0.1x
def f(x):
    return 0.01 * x**2 + 0.1 * x

# 切线方程函数,返回切线函数 y  = ax + b
def tangent_line(f, x):
    y = f(x)
    # 计算x处切线的斜率(利用数值微分计算x处的导数)
    a = numerical_diff(f, x)
    print("切线斜率为: ", a)
    # 根据切线过(x, y)点,计算截距
    b = y - a * x
    return lambda x: a * x + b

# 定义画图范围
x = np.arange(0.0, 20.0, 0.1)
y = f(x)

# 计算x=5处的切线方程
f_line = tangent_line(f, x=5)
y_line = f_line(x)

plt.plot(x, y)  # 原函数曲线
plt.plot(x, y_line)  # 切线
# plt.show()
plt.savefig('tangent_line_result.png')

三、偏导数

可将其中一个元素 x x x 看作参数,此时 f f f 可看作关于另一元素 y y y 的函数。

f a ( y ) = x 2 + x y + y 2 f_a(y) = x^2 + xy + y^2 fa(y)=x2+xy+y2

在 x = a x = a x=a 固定的情况下,可计算 f x f_x fx 关于 y y y 的导数。

f a ′ ( y ) = a + 2 y f_a'(y) = a + 2y fa′(y)=a+2y

这种导数称为偏导数,一般记作:

∂ f ∂ y ( x , y ) = x + 2 y \frac{\partial f}{\partial y}(x, y) = x + 2y ∂y∂f(x,y)=x+2y

更一般地来说,一个多元函数 f ( x 1 , x 2 , ⋯   , x n ) f(x_1, x_2, \cdots, x_n) f(x1,x2,⋯,xn) 在点 ( a 1 , a 2 , ⋯   , a n ) (a_1, a_2, \cdots, a_n) (a1,a2,⋯,an) 处对 x i x_i xi 的偏导数定义为:

∂ f ∂ x i ( a 1 , a 2 , ⋯   , a n ) = lim ⁡ Δ x i → 0 f ( a 1 , ⋯   , a i + Δ x i , ⋯   , a n ) − f ( a 1 , ⋯   , a i , ⋯   , a n ) Δ x i \frac{\partial f}{\partial x_i}(a_1, a_2, \cdots, a_n) = \lim_{\Delta x_i \to 0} \frac{f(a_1, \cdots, a_i + \Delta x_i, \cdots, a_n) - f(a_1, \cdots, a_i, \cdots, a_n)}{\Delta x_i} ∂xi∂f(a1,a2,⋯,an)=Δxi→0limΔxif(a1,⋯,ai+Δxi,⋯,an)−f(a1,⋯,ai,⋯,an)

偏导数同样也可以用数值微分的方式来求,即只改变一个自变量、其它不变,做差分考察函数值的变化率。

四、梯度(基础知识在机器学习就该知道了)

多元函数 f ( x 1 , ... , x n ) f(x_1, \dots, x_n) f(x1,...,xn) 关于每个变量 x i x_i xi 都有偏导数 ∂ f ∂ x i \frac{\partial f}{\partial x_i} ∂xi∂f,在点 a a a 处,这些偏导数定义了一个向量。

∇ f ( a ) = ∂ f ∂ x 1 ( a ) , ... , ∂ f ∂ x n ( a ) \nabla f(a) = \left \\frac{\\partial f}{\\partial x_1}(a), \\dots, \\frac{\\partial f}{\\partial x_n}(a) \\right ∇f(a)=∂x1∂f(a),...,∂xn∂f(a)

这个向量称为 f f f 在点 a a a 的梯度。

例如: f ( x , y ) = x 2 + x y + y 2 f(x, y) = x^2 + xy + y^2 f(x,y)=x2+xy+y2 在 ( 1 , 1 ) (1,1) (1,1) 处的梯度为 3 , 3 3, 3 3,3。

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

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

五、利用数值微分求梯度代码

python 复制代码
import numpy as np

# 数值微分求梯度,传入x是一个向量
# 这个函数其实是在做多元函数的数值偏导,每次只针对一个维度做微小的改变,其他维度保持原样
# 比如传入 x = [3,4,6,77] , x.size = 4,循环四次, 以i=0为例
# *   `tmp = x[0]`,此时 `tmp` 保存了 3(为了后面恢复用)。
# *   `x[0] = tmp + h`,现在 `x` 变成了 `[3 + h, 4, 6, 77]`。
# *   `fxh1 = f(x)`,算出了点 `x[0] + h` 处的函数值。
# *   `x[0] = tmp - h`,现在 `x` 变成了 `[3 - h, 4, 6, 77]`。
# *   `fxh2 = f(x)`,算出了点 `x[0] - h` 处的函数值。
# *   `grad[0] = (fxh1 - fxh2) / (2 * h)`,用中心差分公式算出了对第一个变量 $x_1$ 的偏导数。
# *   `x[0] = tmp`,把 `x` 恢复成 `[3, 4, 6, 77]`。
def _numerical_gradient(f, x):
    h = 1e-4
    grad = np.zeros_like(x)
    # 遍历x中的特征xi(在求偏导时候,要改变当前xi,改完要还原不防止可能影响别的偏导)
    for i in range(x.size):
        tmp = x[i]
        x[i] = tmp + h
        fxh1 = f(x)
        x[i] = tmp - h
        fxh2 = f(x)
        # 利用中心差分公式计算偏导数
        grad[i] = (fxh1 - fxh2) / (2*h)
        # 恢复x[i]的值
        x[i] = tmp
    return grad

# 传入X是一个矩阵
# 加入传入的是 W 是(2,4)矩阵, 调用两次_numerical_gradient,每次传入向量(4,)就是一维数组里面四个权重,参考_numerical_gradient的举例。
# 也就说一个W (2,4)矩阵算梯度要循环8次,每次执行两次前向传播
def numerical_gradient(f, X):
    # 判断维度
    if X.ndim == 1:
        return _numerical_gradient(f, X)
    else:
        grad = np.zeros_like(X)
        # 遍历X中的每一行数据,分别求梯度
        for i, x in enumerate(X):
            grad[i] = _numerical_gradient(f, x)
        return grad
相关推荐
艾莉丝努力练剑1 小时前
【AI大模型接入SDK】Trae生成代码介绍
网络·c++·人工智能·学习·架构
辣知1 小时前
辣知·化智88 为民族示范变革代价与价值
学习
panpan16191 小时前
中考、高考、KET、PET高效学习工具
学习·高考
liwulin05061 小时前
【PYTORCH】迷你DECODER-ONLY模型
pytorch·python·深度学习
旖旎夜光2 小时前
LeetCode 215: 数组中的第K个最大元素 (快速排序) —— 题解
c++·学习·算法·leetcode·力控
高洁012 小时前
边缘AI与大模型轻量化:让智能跑进每一个终端
人工智能·python·深度学习·机器学习·迁移学习
拜小白10 小时前
【论文解读】DMH-Net:用深度曼哈顿霍夫变换从全景立方图估计3D房间布局
深度学习·计算机视觉·全景图
ViperL113 小时前
[智能计算]AutoDiffusion-基于进化NAS的扩散模型
人工智能·深度学习·计算机视觉
外收内放13 小时前
面向对象高级(实战案例)
开发语言·python·学习