一、什么是数值微分
数值微分就是用求
导数近似值的方法。
取 或其他较小的数,则函数在x点处的导数等于:
用python等计算机语言实现时,要注意, 并不是越小越好,因为计算机的存储空间有限,32位单精度浮点数可表达的数字范围在-3.40E+38 ~ +3.40E+38之间。
例子:,求其在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
结果:()
二、什么是梯度?如何通过数值微分计算梯度?
梯度方向的反方向是函数值下降得最快速的方向。梯度是由偏导构成的向量:,比如函数
的梯度为:
用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
用数值微分计算梯度:比如 ,有两个变量,那么求点
处的梯度时,分别求出
即可,其中 a,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的函数,那么认为,每次迭代中计算出W的梯度
,然后令
,迭代多次后可以使损失函数最小,即网络性能最优。
当然,也不是严格意义上的最优,很可能是次优。
如何求梯度呢?
在求每一个权重参数的梯度时,令其他参数不变,利用数值微分求其偏导即可。