深度学习入门笔记 Day6/15 神经网络(四)

一、什么是数值微分

数值微分就是用\frac{\Delta f(x)}{\Delta x}f(x)导数近似值的方法。

取 \Delta x = 1e^{-4} 或其他较小的数,则函数在x点处的导数等于:

\frac{d f(x)}{dx} = \frac{f(x+\Delta x)-f(x)}{\Delta x}

用python等计算机语言实现时,要注意,\Delta x 并不是越小越好,因为计算机的存储空间有限,32位单精度浮点数可表达的数字范围在-3.40E+38 ~ +3.40E+38之间。

例子:f(x) = x^2,求其在x=1处的导数

# 函数表达式
def fx(x):
    return x**2


# 数值微分求导数
# 精度较低的前向差分的数值微分
def numerical_differential(x):
    dx = 10**(-4)
    return (fx(x+dx)-fx(x))/dx


# 求x=1处导数

if __name__ == '__main__':
    x = 1
    print(numerical_differential(x))

# 输出:2.000099999999172  误差:1e-4
----------------------------------------------------
# 精度更高的中心差分的数值微分
def numerical_diff(fx, x):
    dx = 10**(-4)
    return (fx(x+dx)-fx(x-dx))/(2*dx)


if __name__ == '__main__':
    x = 1
    print(numerical_diff(fx, x))
# 输出:1.9999999999992246  误差:1e-12

结果:(f(x)'=2x,f(1)'=2

二、什么是梯度?如何通过数值微分计算梯度?

梯度方向的反方向是函数值下降得最快速的方向。梯度是由偏导构成的向量:Gradient = ( \frac{\partial f }{\partial x_0}, \frac{\partial f }{\partial x_1},...,\frac{\partial f }{\partial x_n} ),比如函数 f(x_0,x_1) = x_0^2+x_1^2 的梯度为:(2x_0,2x_1)

深度学习入门笔记 Day6/15 神经网络(四)_第1张图片

用Matplotlib绘制上图代码为:

a = np.arange(-2, 2, 0.05)
b = np.arange(-2, 2, 0.05)
a, b = np.meshgrid(a, b)
y = function_2(a, b)

fig = plt.figure()
ax = Axes3D(fig)

ax.set_xlabel('x1', fontsize=14)
ax.set_ylabel('x2', fontsize=14)
ax.set_zlabel('y', fontsize=14)
# 具体函数方法可用 help(function) 查看,如:help(ax.plot_surface)
ax.plot_surface(a, b, y, cmap='rainbow',rcount=100, ccount= 100)

plt.show()


def function_2(a, b):
    return a**2 + b**2

用数值微分计算梯度:比如 x =[x_0, x_1],有两个变量,那么求点 [x_0=a,x_1=b] 处的梯度时,分别求出 \frac{\partial f }{\partial x_0}, \frac{\partial f }{\partial x_1}即可,其中 a,b为常量,是已知数。

那么这两个偏导数可以采用类似数值微分求导数的方式来求:

\frac{\partial f }{\partial x_0}=\frac{f(x_0+h,x_1)-f(x_0-h,x_1)}{2h}| _{x_0=a,x_1=b}

也就是说我们只要将numerical_diff函数稍作改变即可

def numerical_gradient(f, x):
    h = 1e-4 # 0.0001
    grad = np.zeros_like(x) # 生成和x形状相同的数组

    for idx in range(x.size):
        tmp_val = x[idx]
        # f(x+h)的计算
        x[idx] = tmp_val + h
        print("tempx = ", x)
        fxh1 = f(x)
        print("fh1 = ", fxh1)

        # f(x-h)的计算
        x[idx] = tmp_val - h
        print("tempx = ", x)
        fxh2 = f(x)
        print("fh2 = ", fxh2)

        grad[idx] = (fxh1 - fxh2) / (2*h)
        x[idx] = tmp_val # 还原值

    return grad

三、如何实现使用mini-bbatch数据的随机梯度下降法(stochastic gradient descent, SGD)?

回顾一下,神经网络的评价标准是“损失函数”,损失函数值越小表示网络的性能越好,利用随机梯度下降法可以在逐渐迭代中使“损失函数”值越来越小。损失函数一般是评价方差或者交叉熵误差函数,其变量是各层网络的权重W。

所以神经网络的损失函数E是关于权重变量W的函数,那么认为f(x)=E(W),每次迭代中计算出W的梯度\frac{\partial E}{\partial W},然后令W = W - \eta \frac{\partial E}{\partial W},迭代多次后可以使损失函数最小,即网络性能最优。

当然,也不是严格意义上的最优,很可能是次优。

如何求梯度呢?

在求每一个权重参数的梯度时,令其他参数不变,利用数值微分求其偏导即可。

你可能感兴趣的:(深度学习入门)