通过前面的学习,我们知道了多维变量下的偏导数的计算方法。神经网络学习的过程是不断追求最优参数的过程,而计算偏导数和梯度就是追求最优参数的最快路径。
什么是梯度梯度,就是多维自变量的偏导数构成的向量集合。例如对于下面的函数:
对x0的偏导计算:
对x1的偏导计算:
那么梯度就是两个偏导数一起构成的向量:
根据前面的学习,偏导数的计算可以采用中心差分的方式计算,而就某一维自变量的计算时,其他维度的自变量视为常量:
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
fxh1 = f(x)
# f(x-h)的计算
x[idx] = tmp_val - h
fxh2 = f(x)
# 差分计算
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val # 还原值
return grad
那么计算函数在某些位置的偏导、梯度就很方便了:
def function_2(x):
return x[0]**2 + x[1]**2
>>> numerical_gradient(function_2, np.array([3.0, 4.0])) array([ 6., 8.])A >>> numerical_gradient(function_2, np.array([0.0, 2.0])) array([ 0., 4.]) >>> numerical_gradient(function_2, np.array([3.0, 0.0])) array([ 6., 0.])
我们看到函数在不同的位置,他们的偏导数各不相同,那么这些偏导数和梯度有什么含义呢?
如果按照负梯度作为向量绘制到图像中的时候,我们得到上面的图像。我们发现,箭头都指向函数最小值的位置,就像我们三维图像一样,他们都指向凹槽的底部:
实际上,负梯度所指向的方向,就是函数在该位置减小幅度最大的方向。
梯度下降法既然负梯度指向的是函数在该位置减小幅度最大的方向,我们就可以利用这一特性,慢慢的调整参数,使之达到最优(达到代价函数的最低点)。
也就是说,每次我们计算该位置的梯度,然后在此处向梯度下降的位置移动一个小单位,这样我们一步步地接近目标。
这里的η是学习率,觉得我们每一步迈进的大小。学习率不宜过大,否则容易来回跳,找不到最优的值;学习率也不宜过小,否则学习速度太慢,效率低。
(一般动态调整学习率,前面的步骤使用较大的学习率,速度快,后面的步骤使用较小的学习率,速度慢但是可以避免越过最优值。)
我们先来实现梯度下降过程中的位置更新:
def gradient_descent(f, init_x, lr=0.01, step_num=100):
x = init_x
# 开始迭代更新
for i in range(step_num):
# 计算梯度
grad = numerical_gradient(f, x)
# 移动位置
x -= lr * grad
return x
我们尝试计算一下最小值:
>>> def function_2(x): ... return x[0]**2 + x[1]**2 ... >>> init_x = np.array([-3.0, 4.0]) >>> gradient_descent(function_2, init_x=init_x, lr=0.1, step_num=100) array([ -6.11110793e-10, 8.14814391e-10])
我们发现得到的结果非常接近(0,0)这说明真的找到了函数的最低点
而实际上,自变量也真的是沿着负梯度的方向一步步地移动到最低处。
神经网络中的梯度在学习过程中的梯度就是代价函数与权重矩阵的偏导向量。
权重更新



