清溪算法君老号 2019-03-12
本文中,我们将详细讨论sigmoid神经元学习算法背后的数学直觉。
引文注:本文的内容和结构基于 One-Fourth Labs — Padhai的深度学习讲座 。
Sigmoid Neuron Recap
Sigmoid神经元类似于感知神经元,对于每个输入Xi都具有与输入相关的权重Wi。权重表明了输入在决策过程中的重要性。sigmoid的输出不像感知器模型那样是0或1,而是0-1之间的实数值,可以解释为概率。最常用的sigmoid函数是逻辑函数,其具有“ S ”形曲线的特征。
Sigmoid神经元表示学习算法
学习算法的目的是确定参数(w和b)的最佳可能值,使得模型的总体损失(平方误差损失)尽可能最小化。
学习算法
我们随机初始化w和b。然后我们遍历数据中的所有观察值,对于每个观察值,使用sigmoid函数找到相应的预测结果并计算平方误差损失。根据损失值,我们将更新权重,使模型在新参数下的总体损失小于当前的模型损失。
学习算法:数学部分
我们看到了权重如何根据损失值进行更新。在本节中,我们将了解为什么这个特定更新规则可以减少模型的损失。要了解更新工作规则的工作原理,我们需要了解其背后的数学原理。
在sigmoid神经元函数中,我们有两个参数w和b。我将以向量θ的形式表示这些参数,θ是属于R²的参数向量。目的是找出损失函数最小化的θ的最优值。
参数的向量符号
我们达到目标的方法是更新一些小的随机值θ, Δθ是w变化量和b变化量的集合。Δθ也是属于R²的向量。让我们看一下θ和Δθ的几何表示,
几何表示
我们有一个向量θ,我们正在向它添加另一个向量Δθ。根据向量的平行四边形定律,我们得到我们的合成向量θnew,它只是平行四边形的对角线。从几何表示,我们可以看出θ和θnew之间的θ值有很大的变化。我们不是在学习θ时采取大步骤,而是保守一点并且只朝同一方向移动一小部分。
几何表示与学习率
请记住,Δθ是一个向量,以便在相同的方向上采取小步骤,我需要对Δθ具有较小的幅度。为了得到一个小幅度,我将Δθ乘以学习速率(一个非常小的值)。现在,合成向量是红色的向量表示θnew。新的θ将是向量θ从其初始位置的移动。
使用泰勒级数
但是,我们如何决定Δθ的值,如何正确的使用Δθ?我们如何得到正确的Δθ,这样新的损失(w和b的函数)应小于旧的损失。这个问题的答案来自泰勒级数。
泰勒级数告诉我们的是,如果我们有一个函数f并且我们知道函数在特定点x的值,那么函数f在非常接近x的新点处的值由下面的公式给出,
泰勒级数综合表示法
在靠近x的小步骤之后的函数值等于x处的函数值和其他一些量(在红色框中)。如果我们查看红色框中的量,它的值完全取决于Δx。如果我能够找到Δx,红色框中表示的量将是负数,那么我就会知道新x处的新损失小于旧x处的损失。
根据sigmoid神经元参数和损失函数表示泰勒级数。为了便于表示,让Δθ = u然后我们有,
用参数θ替换了x
将其与一般的泰勒级数等式进行比较,新θ的损失等于旧θ的损失和其他一些量(在红色框中显示)。框中存在的量的值取决于变化向量uᵀ。所以我们需要找到变化向量uᵀ,使红色框中的量变为负数。如果是负数,那么我们就会知道θnew的损失小于θold的损失。
为了找到最优变化向量uᵀ,为了简单起见,让我们删除泰勒级数中的一些术语。我们知道学习率η非常小,然后η²,η³等......通过使用这个逻辑可以非常接近于零,泰勒级数可以简化为,
删减泰勒级数
只有当新θ的损失小于旧θ时,变化向量uᵀ才是最优的,
最优变化向量
通过比较上述两个等式(变化向量uᵀ优化方程和删减泰勒级数等式),我们可以暗示,
为了解决上面的等式,让我们回到线性代数,特别是两个向量之间的余弦角。我们知道cos(θ)的范围是-1到1。
向量之间的余弦角由于余弦角公式的分母是一个量级并且它总是正的,我们可以将余弦公式乘以k(分母)而不影响不等式的符号。我们希望量存在中间(在蓝框中标记)不等式为负,这只有在如果uᵀ之间的余弦角和∇=-1时才有可能。如果余弦角等于-1,那么我们知道向量之间的角度等于180°。
如果角度等于180⁰,这意味着我们选择的变化的向量uᵀ的方向应该与梯度向量相反。
我们可以编写参数更新规则,如下所示,
计算偏导数
到目前为止,在前面的部分中,我们已经看到了如何使用泰勒级数和向量之间的余弦角来得到一个参数更新规则。但是我们如何计算w和b的偏导数呢?
为简单起见,我们假设只有一个点适合sigmoid神经元。所以一个点的损失函数可以写成,
一个点的损失函数
我们需要计算w和b相对于损失函数的偏导数。让我们得出这些导数,
w偏导的求导
首先,我们将偏导数推到括号内,我们有y是常数,其偏导数将为零。在f(x)的位置,我们将用逻辑函数代替f(x)求关于w的logistic函数的偏导。上图的右侧部分解释了逻辑函数的偏导数。上面的最终表达式(标记为红色)仅对一个观察结果有效,对于两个观察结果表达式更改为
同样,我们可以计算b相对于损失的偏导数,
梯度下降规则
现在我们拥有了使用梯度下降实现参数更新规则所需的一切。让我们举个例子,看看我们如何使用我们刚刚推导出的参数更新规则来实现梯度下降,以最大限度地减少模型的损失。
我已经采取了一些玩具数据并将参数初始化为w = 0,b = -8并设置学习率= 1.0,然后迭代所有观察1000个周期的所有观测和计算损失不同的w值(-2到6)和b(-10到2)。一旦我得到的所有可能组合的损失值w和b,我是能够生成下面的3D轮廓图,以显示损失值的变化。
不同w和b的损失值
#toy data X = [0.5,2.5] Y = [0.2,0.9] import numpy as np import matplotlib.pyplot as plt w_values = [] b_values = [] loss_values = [] def f(w,b,x): return 1. / (1. + np.exp(-(w*x)+b)) def error(w,b): err = 0.0 for x,y in zip(X,Y): fx = f(w,b,x) err += 0.5*(fx-y)**2 return(err) def grad_w(w,b, x, y): y_pred = f(w,b,x) return (y_pred - y) * y_pred * (1 - y_pred) * x def grad_b(w,b, x, y): y_pred = f(w,b,x) return (y_pred - y) * y_pred * (1 - y_pred) def gradient_descent(): w,b,eta = 0, -8, 1.0 #values for illustration, we can choose randomly for i in range(1000): #iterating for 1000 epochs dw, db = 0, 0 for x, y in zip(X, Y): dw += grad_w(w,b,x, y) db += grad_b(w,b,x, y) w -= eta*dw b -= eta*db w_values.append(w) b_values.append(b) loss_values.append(error(w,b)) #call the gradient descent function to find #the best values for w and b gradient_descent() #plotting the surface plot fig = plt.figure() ax = plt.axes(projection='3d') ax.plot_surface(w_values, b_values,loss_values, cmap='seismic') ax.set_xlabel('w') ax.set_ylabel('b') ax.set_zlabel('loss') plt.show()
上面的代码片段显示了在2D玩具数据的情况下,参数w和b的梯度下降更新规则的实现。我们可以随机初始化参数值,但在本例中,我只是为了更好的说明目的而采用这些特定值。
图中较深的红色阴影表示损失值较高的区域,较深的蓝色阴影表示损失的最低点。下图为固定迭代时的梯度下降规律,底部的点表示w和b的不同组合,轮廓上的点表示对应参数值的损失值。
损失变化的动画我们已经成功地推导出梯度下降更新规则,该规则保证只要我们在与梯度相反的方向上移动,就可以为w和b找到函数损失最小的最佳参数值。
结论
在这篇文章中,我们简要地看了一下sigmoid神经元。我们继续使用泰勒级数,线性代数和偏微分,详细了解了学习算法背后的数学直觉。最后,我们已经证明使用梯度下降法得到的更新规则能够保证利用玩具数据找到最优参数。