使用非线性函数变换的多层感知机又称深度前馈网络、 深度神经网络 。
这种网络的目的是使得整个模型近似于某个函数 f ∗ f^{*} f∗ 。在前馈神经网络中定义了一个 y = f ( x ; θ ) y = f(x;\theta) y=f(x;θ),并且学习参数 θ \theta θ的值,使得它能够到最佳的函数近似。
前馈神经网络结构:
网络结构: 许多函数复合在一起表示,
链式结构是神经网络中最经常用的结构 f ( x ) = f ( 3 ) ( f ( 2 ) ( f ( 1 ) ( x ) ) ) f(x) = f^{(3)}(f^{(2)}(f^{(1)}(x))) f(x)=f(3)(f(2)(f(1)(x)))
深度: 链的全部长度
输出层: 前馈神经网络的最后一层
隐藏层: 中间层
宽度: 隐藏层的维数决定模型的宽度
神经元(单元) : 表示一个从向量到标量的函数,持有一定的模型参数值。接受
训练数据中的标签只是指导了最后一层的输出,由学习算法来制定中间层产生的输出
激活函数引入了非线性的拟合能力。
不加非线性激活函数的多层感知器只能解决多条直线相交划分的类的问题,而且层数越多,相对复杂。相反,加入了非线性激活函数的多层感知器可以解决分界线为曲线、圆等分类问题,从而能够真正解决非线性的分类问题。
我们通常定义: 每一个输入数据为n维向量,
w i j ( l ) w_{ij}^{(l)} wij(l) 为 第 l 层 第 i 个神经元 与 第 j 个 输入相连的权重,第 l 层中每个神经元的权重为 k 维向量, k 为 (l -1) 层神经元的数量
第 l 层中所有 p 个神经元的权重组成矩阵 W l ∈ R [ p , k ] W^{l} \in \mathbb{R}[p,k] Wl∈R[p,k]
y ( l ) ) = o u t p u t ( l ) = f ( W ( l ) ⋅ o u t p u t ( l − 1 ) + b ) y^{(l))} = output^{(l)} = f(W^{(l)} \cdot output^{(l-1)}+b) y(l))=output(l)=f(W(l)⋅output(l−1)+b)
反向传播算法的核心通过比较输出 y 和期望输出t , 向输入层方向逐层计算梯度并更新权值,与前馈运算正好相反。
如果训练得到的结果和期望值不一致,说明权重 w 不恰当,这里使用的调整的手法就是反向传播。
向前解释: 从输入到输出的方向
向后解释 : 从输出到输入的方向
外国文献: bottom 输入,top 输出 。 top to bottom 从输入到输出
写激活函数或者代价函数的话 ,要理解反向传播的概念。
C o s t ( x ) = 1 2 ( t − y ) 2 Cost(x) = \frac{1}{2}(t -y)^{2} Cost(x)=21(t−y)2 – 损失函数定义
σ ( x ) = s i g m o i d ( x ) = 1 1 + e − x \sigma(x) = sigmoid(x) = \frac{1}{1+ e^{-x}} σ(x)=sigmoid(x)=1+e−x1 – 激活函数定义
h j ( l ) = σ ( ∑ j w i j ( l ) h j ( l − 1 ) + b i a s i ( l ) ) h_j^{(l)}= \sigma(\sum_{j} w^{(l)}_{ij}h_{j}^{(l-1)}+bias_{i}^{(l)}) hj(l)=σ(∑jwij(l)hj(l−1)+biasi(l)) – 经过激活函数的隐层输出
l o g i t ( i ) l = ∑ j w i j ( l ) h j ( l − 1 ) + b i a s i ( l ) logit_{(i)}^{l} = \sum_{j} w^{(l)}_{ij}h^{(l-1)}_{j}+bias_{i}^{(l)} logit(i)l=∑jwij(l)hj(l−1)+biasi(l) – 未经过激活函数的隐层计算
δ j ( l ) = ∂ C o s t ∂ l o g i t j ( l ) \delta_{j} ^{(l)} = \frac{\partial Cost}{\partial logit_{j}^{(l)}} δj(l)=∂logitj(l)∂Cost – 神经元固有的参数
∂ C o s t ∂ w i j ( l ) = δ j ( l ) × h j ( h − 1 ) \frac{\partial Cost}{\partial w_{ij}^{(l)}} = \delta_{j}^{(l)} \times h_{j}^{(h-1)} ∂wij(l)∂Cost=δj(l)×hj(h−1)
推导出第一个重要的公式:
δ i ( L ) = ∂ C o s t ∂ l o g i t i ( L ) = ▽ y C o s t × σ ′ ( l o g i t i ( L ) ) \delta_{i}^{(L)} = \frac{\partial Cost}{\partial logit_{i}^{(L)}} = \triangledown_{y}Cost \times \sigma'(logit_{i}^{(L)}) δi(L)=∂logiti(L)∂Cost=▽yCost×σ′(logiti(L)) (1)
计算最后一层神经元的固有参数的更新
固有参数层与层之间关系重要公式
δ i ( l ) = ∑ j δ i ( l + 1 ) w j i ( l + 1 ) σ ′ ( l o g i t i ( l ) ) \delta_{i}^{(l)} = \sum_{j}\delta_{i}^{(l+1) }w_{ji}^{(l+1)}\sigma'(logit_{i}^{(l)}) δi(l)=∑jδi(l+1)wji(l+1)σ′(logiti(l)) (2)
当前神经元固有函数的更新是以下两部分的乘积
1.下一层所有神经元与当前神经元和下一层神经元的权重相乘之和
2.当前神经元输出的激活函数的导数
损失函数对于权重、偏置的偏导数,求取变化量的重要公式:
∂ C o s t ∂ w i j ( l ) = h j ( l − 1 ) δ i ( l ) \frac{\partial Cost}{\partial w_{ij}^{(l)}} = h_{j}^{(l-1)}\delta_{i}^{(l)} ∂wij(l)∂Cost=hj(l−1)δi(l) (3)
∂ C o s t ∂ b i a s i ( l ) = δ i ( l ) \frac{\partial Cost}{\partial bias_{i}^{(l)}} = \delta_{i}^{(l)} ∂biasi(l)∂Cost=δi(l) (4)
权重、偏置的更新公式同单个神经元公式:
w n e w = w o l d + η ( t − y ) w , b n e w = b o l d + η ( t − y ) w_{new} = w_{old} + \eta(t-y)w, \quad b_{new} = b_{old} + \eta(t-y) wnew=wold+η(t−y)w,bnew=bold+η(t−y)
感知器的梯度下降和神经网络的反向传播方法的对比:
反向传播算法也是利用了梯度下降的方法,从输出层逐层向前进行权值、偏置的更新。每轮迭代每一层更新一次。感知器一轮迭代这个神经元更新一次。
使用 sigmoid 函数 时,它的导数为
σ ′ ( x ) = σ ( x ) ( 1 − σ ( x ) ) δ i ( l ) = ∑ j δ i ( l + 1 ) w j i ( l + 1 ) σ ′ ( l o g i t i ( l ) ) \sigma'(x) = \sigma(x)(1 - \sigma(x)) \\ \delta_{i}^{(l)} = \sum_{j}\delta_{i}^{(l+1) }w_{ji}^{(l+1)}\sigma'(logit_{i}^{(l)}) σ′(x)=σ(x)(1−σ(x))δi(l)=j∑δi(l+1)wji(l+1)σ′(logiti(l))
sigmoid 导数最大值为0.25,它是关于y轴对称的二次曲线 每一次传播都会是原来的 1 4 \frac{1}{4} 41,越靠近输入端的层上的 δ \delta δ越小。因此,越靠近输入层的神经元对应的权重更新就会越小,很可能就几乎为0。
由于sigmoid 激活函数输出为正数,由之前的公式可以得到 经过激活函数的隐层输出 h i > 0 h_{i} >0 hi>0 。同一层某个神经元的 δ \delta δ 是固定的,对于前一层连接这个神经元的权重的更新值。所以 ∂ C o s t ∂ w i j ( l ) = h j ( l − 1 ) δ i ( l ) \frac{\partial Cost}{\partial w_{ij}^{(l)}} = h_{j}^{(l-1)}\delta_{i}^{(l)} ∂wij(l)∂Cost=hj(l−1)δi(l) 总是同正,或者同负。 不可能出现某个权重增加,某个权重减小这种情况。 如果是有 w 11 , w 12 w_{11},w_{12} w11,w12 他们的更新的梯度 Δ w 11 , Δ w 12 \Delta w_{11}, \Delta w_{12} Δw11,Δw12 总会出现在1,3象限。
所以梯度更新有可能出现拉链状更新的情况,由下图可知。这样会极大增长优化时长。
ReLu 函数如果落入x轴的负半轴上。神经元输出为 0。 会造成:
工业经验,如果学习率设置过大。神经元死亡过多,基本就没办法挽救了。所以可以根据神经元死亡数量来调整学习率。
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def sigmoidDerivationx(y):
return y * (1 - y)
if __name__ == '__main__':
# 初始化一些参数
alpha = 0.5
numIter = 1000000 #迭代次数
w1 = [[0.15, 0.20], [0.25, 0.30]] # Weight of input layer
w2 = [[0.40, 0.45], [0.50, 0.55]]
# print(np.array(w2).T)
b1 = 0.35
b2 = 0.60
x = [0.05, 0.10]
y = [0.01, 0.99]
# 前向传播
z1 = np.dot(w1, x) + b1 # dot函数是常规的矩阵相乘
a1 = sigmoid(z1)
z2 = np.dot(w2, a1) + b2
a2 = sigmoid(z2)
for n in range(numIter):
# 反向传播 使用代价函数为C=1 / (2n) * sum[(y-a2)^2]
# 分为两次
# 一次是最后一层对前面一层的错误
delta2 = np.multiply(-(y-a2), np.multiply(a2, 1-a2))
# for i in range(len(w2)):
# print(w2[i] - alpha * delta2[i] * a1)
#计算非最后一层的错误
# print(delta2)
delta1 = np.multiply(np.dot(np.array(w2).T, delta2), np.multiply(a1, 1-a1))
# print(delta1)
# for i in range(len(w1)):
# print(w1[i] - alpha * delta1[i] * np.array(x))
#更新权重
for i in range(len(w2)):
w2[i] = w2[i] - alpha * delta2[i] * a1
for i in range(len(w1)):
w1[i] = w1[i] - alpha * delta1[i] * np.array(x)
#继续前向传播,算出误差值
z1 = np.dot(w1, x) + b1
a1 = sigmoid(z1)
z2 = np.dot(w2, a1) + b2
a2 = sigmoid(z2)
print(str(n) + " result:" + str(a2[0]) + ", result:" +str(a2[1]))
# print(str(n) + " error1:" + str(y[0] - a2[0]) + ", error2:" +str(y[1] - a2[1]))
参考博客:
https://www.cnblogs.com/fuqia/p/8982405.html