numpy实现神经网络系列
工程地址:https://github.com/yizt/numpy_neuron_network
基础知识
0_1-全连接层、损失函数的反向传播
0_2_1-卷积层的反向传播-单通道、无padding、步长1
0_2_2-卷积层的反向传播-多通道、无padding、步长1
0_2_3-卷积层的反向传播-多通道、无padding、步长不为1
0_2_4-卷积层的反向传播-多通道、有padding、步长不为1
0_2_5-池化层的反向传播-MaxPooling、AveragePooling、GlobalAveragePooling、GlobalMaxPooling
0_3-激活函数的反向传播-ReLU、LeakyReLU、PReLU、ELU、SELU
0_4-优化方法-SGD、AdaGrad、RMSProp、Adadelta、Adam
DNN练习
1_1_1-全连接神经网络做线性回归
1_1_2-全连接神经网络做mnist手写数字识别
CNN练习
2_1-numpy卷积层实现
2_2-numpy池化层实现
2_3-numpy-cnn-mnist手写数字识别
本文目录
-
- numpy实现神经网络系列
- 依赖知识
- 约定说明
- 误差反向
- 常用损失函数
本文下载地址:0_1-全连接层、损失函数的反向传播
依赖知识
a) 了解神经网络的基础知识
b) 熟悉导数的链式法则及常见函数的导数
c) 熟悉常见的优化方法,梯度下降,随机梯度下降等
d) 熟悉矩阵和向量的乘加运算
约定说明
a) 对于一个 n n 层神经网络,第 i i 层表示为 li, 1≤i≤n l i , 1 ≤ i ≤ n ,第 i i 神经元个数为 |li| | l i | ; 注意 li l i 是输入层, ln l n 是输出层。
b) 对于神经网络的一个输入样本 x x ,其维度为 (1,|l1|) ( 1 , | l 1 | ) ,也就是一个行向量;对应的输出 y y 也是一个行向量,维度为 (1,|ln|) ( 1 , | l n | ) 。(注:也可以将 x x 和 y y 表示为列向量,这里预先说明好为行向量,避免后面有歧义)
c) 设神经网络中第i层的输出为 zi z i ,( zi z i 都是行向量)则 x=z1,y=zn x = z 1 , y = z n ; 第 i i 层的权重和偏置分别为 Wi,bi W i , b i ;则对于全连接层 zi+1=ziWi+bi z i + 1 = z i W i + b i ; 其中 Wi W i 和 bi b i 的维度分别为为 (|li|,|li+1|),(1,|li+1|) ( | l i | , | l i + 1 | ) , ( 1 , | l i + 1 | )
d) 定义损失函数为 L(y,y∗) L ( y , y ∗ ) ;其中 y∗ y ∗ 为样本的真实 y y 值
误差反向
a) 记损失函数L关于第 i i 层神经元的输出 zi z i 的偏导为 δi=∂L∂zi (1) δ i = ∂ L ∂ z i ( 1 )
b) 首先我们来看看损失函数L在最后一层参数上的偏导;也就是 ∂L∂Wn−1 ∂ L ∂ W n − 1 和 ∂L∂bn−1 ∂ L ∂ b n − 1
∂L∂Wn−1i,j =∂Lznj∗∂znj∂Wn−1i,j (2) //Wn−1i,j是第n−1层的第i个神经元和第n层的第j个神经元的连接,所以只有znj的误差经过Wn−1i,j反向传播=δnj∗∂(∑|ln−1|k=1zn−1kWn−1k,j+bn−1j)∂Wn−1i,j (3) //znj是zn−1这个行向量与权重矩阵Wn−1的第j列向量的乘积,加上偏置bn−1j=δnj∗zn−1i (4) ∂ L ∂ W i , j n − 1 = ∂ L z j n ∗ ∂ z j n ∂ W i , j n − 1 ( 2 ) / / W i , j n − 1 是 第 n − 1 层 的 第 i 个 神 经 元 和 第 n 层 的 第 j 个 神 经 元 的 连 接 , 所 以 只 有 z j n 的 误 差 经 过 W i , j n − 1 反 向 传 播 = δ j n ∗ ∂ ( ∑ k = 1 | l n − 1 | z k n − 1 W k , j n − 1 + b j n − 1 ) ∂ W i , j n − 1 ( 3 ) / / z j n 是 z n − 1 这 个 行 向 量 与 权 重 矩 阵 W n − 1 的 第 j 列 向 量 的 乘 积 , 加 上 偏 置 b j n − 1 = δ j n ∗ z i n − 1 ( 4 )
对等式(4)一般化的向量表示为:
∂L∂Wn−1=(zn−1)Tδnj(5) (5) ∂ L ∂ W n − 1 = ( z n − 1 ) T δ j n
同理可得:
∂L∂bn−1=δn(6) (6) ∂ L ∂ b n − 1 = δ n
c) 更一般的损失函数L关于第 l l 层(这里没有用索引 i i ,避免跟等式1~4中的索引名相同,引起理解障碍)的参数上的偏导,也就是 ∂L∂Wl ∂ L ∂ W l 和 ∂L∂bl ∂ L ∂ b l
∂L∂Wl=∂L∂zl+1∗∂zl+1∂Wl (7)=(zl)Tδl+1 (8) ∂ L ∂ W l = ∂ L ∂ z l + 1 ∗ ∂ z l + 1 ∂ W l ( 7 ) = ( z l ) T δ l + 1 ( 8 )
同理可得:
∂L∂bl=δl+1(9) (9) ∂ L ∂ b l = δ l + 1
d) 现在我们来看a)中定义的损失函数L关于第
l l 层输出的偏导
δl=∂L∂zl δ l = ∂ L ∂ z l
δli=∂L∂zli =∂L∂zl+1∗∂zl+1∂zli (10) //导数的链式法则=∂L∂zl+1∗∂(zlWl+bl)∂zli (11) //zl的定义=∑j=1|ll+1|∂L∂zl+1j∗∂(∑|ll|k=1zlkWlk,j+blj)∂zli (12) //第l+1层的每个节点都有梯度专递到l层的第i个节点=∑j=1|ll+1|δl+1j∗Wli,j (13) //只有k=i时有梯度=δl+1((Wl)T)i (14) //可以表示为l+1层梯度的行向量与权重Wl的转置的第i个列向量的乘积(1)(2)(3)(4)(5)(6) (1) δ i l = ∂ L ∂ z i l (2) = ∂ L ∂ z l + 1 ∗ ∂ z l + 1 ∂ z i l ( 10 ) / / 导 数 的 链 式 法 则 (3) = ∂ L ∂ z l + 1 ∗ ∂ ( z l W l + b l ) ∂ z i l ( 11 ) / / z l 的 定 义 (4) = ∑ j = 1 | l l + 1 | ∂ L ∂ z j l + 1 ∗ ∂ ( ∑ k = 1 | l l | z k l W k , j l + b j l ) ∂ z i l ( 12 ) / / 第 l + 1 层 的 每 个 节 点 都 有 梯 度 专 递 到 l 层 的 第 i 个 节 点 (5) = ∑ j = 1 | l l + 1 | δ j l + 1 ∗ W i , j l ( 13 ) / / 只 有 k = i 时 有 梯 度 (6) = δ l + 1 ( ( W l ) T ) i ( 14 ) / / 可 以 表 示 为 l + 1 层 梯 度 的 行 向 量 与 权 重 W l 的 转 置 的 第 i 个 列 向 量 的 乘 积
一般化的表示如下:
δl=∂L∂zl=δl+1(Wl)T (15) δ l = ∂ L ∂ z l = δ l + 1 ( W l ) T ( 15 )
结论
以上的证明就是为了说明下面的结论,所以请牢记以下的结论,后续自己写神经网络的反向传播都会用到以下结论
a) 根据公式15,损失函数L关于第 l l 层神经元的偏导,就是第 l+1 l + 1 层的偏导乘上第l层权重矩阵的转置。我们将公式(15)递归一下, δl=δl+1(Wl)T=δl+2(Wl+1)T(Wl)T=δn(Wn−1)T(Wn−2)T...(Wl)T (16) δ l = δ l + 1 ( W l ) T = δ l + 2 ( W l + 1 ) T ( W l ) T = δ n ( W n − 1 ) T ( W n − 2 ) T . . . ( W l ) T ( 16 )
也就是说,只要求得损失函数L关于最后一层(n)的偏导 δn δ n ,其它任意层的偏导,直接用最后一层的偏导逐层乘上权重的转置即可。很简单,很对称,有木有?
b) 根据公式(8) ,损失函数L关于第 l l 层权重 Wl W l 的偏导为,第 l l 层输出的转置乘第 l+1 l + 1 层的偏导 ∂L∂Wl=(zl)Tδl+1 (8) ∂ L ∂ W l = ( z l ) T δ l + 1 ( 8 )
c) 根据公式(9) ,损失函数L关于第 l l 层偏置 bl b l 的偏导,就是第 l+1 l + 1 层的偏导: ∂L∂bl=δl+1 (9) ∂ L ∂ b l = δ l + 1 ( 9 )
由以上可知对任意的全连接层,我们只需要只到它后一层的偏导,就可以求得当前层参数(权重、偏置)的偏导; 就可以使用梯度下降算法更新参数了
w=w−η∗∂L∂w //η为学习率(17) (17) w = w − η ∗ ∂ L ∂ w / / η 为 学 习 率
b=b−η∗∂L∂b(18) (18) b = b − η ∗ ∂ L ∂ b
根据公式(16), 损失函数L关于任何一层的偏导,只需要求导损失函数关于最后一层的偏导 δn δ n 即可。 δn δ n 与损失函数的定义有关,下一节介绍常用损失函数的偏导计算。
常用损失函数
以下说明损失函数的偏导的计算
均方差损失
对于单个样本 (x,y∗) ( x , y ∗ ) ,定义如下:
L(y,y∗)=12(y−y∗)2(19) (19) L ( y , y ∗ ) = 1 2 ( y − y ∗ ) 2
其中 y y 是神经网络最后一层的输出 y=zn y = z n ,就是预测值
∂L∂yi=∂(12(yi−y∗i)2)∂yi=(yi−y∗i)∗∂(yi−y∗i)∂yi=(yi−y∗i) (20)(7)(8)(9) (7) ∂ L ∂ y i = ∂ ( 1 2 ( y i − y i ∗ ) 2 ) ∂ y i (8) = ( y i − y i ∗ ) ∗ ∂ ( y i − y i ∗ ) ∂ y i (9) = ( y i − y i ∗ ) ( 20 )
更一般的表示为
∂L∂y=y−y∗ ∂ L ∂ y = y − y ∗ ; 也就是
δn=∂L∂y=y−y∗=zn−y∗(21) (21) δ n = ∂ L ∂ y = y − y ∗ = z n − y ∗
即使用均方误差情况下,损失函数L关于网络最后一层的导数就是预测值减实际值
交叉熵损失
交叉熵用于度量两个概率分布的差异;一般使用交叉熵损失前,会对网络输出做softmax变换进行概率归一化;所以我们这里介绍的交叉熵损失是带softmax变换的交叉熵。
softmax变换定义如下:
ai=eyi/∑keyk(22) (22) a i = e y i / ∑ k e y k
交叉熵损失定义如下:
L(y,y∗)=−∑iy∗ilogai(23) (23) L ( y , y ∗ ) = − ∑ i y i ∗ log a i
a) 我们先来求
ai a i 关于
yj y j 的偏导
∂ai∂yj=∂(eyi/∑keyk)∂yj=∂eyi∂yj∗1∑keyk+eyi∗−1(∑keyk)2∗∂(∑keyk)∂yj=∂eyi∂yj∗1∑keyk−eyi(∑keyk)2∗eyj=⎧⎩⎨⎪⎪eyj∑keyk−(eyj)2(∑keyk)2−eyieyj(∑keyk)2i=ji≠ j={ai(1−ai)−aiaji=ji≠ j(24) ∂ a i ∂ y j = ∂ ( e y i / ∑ k e y k ) ∂ y j = ∂ e y i ∂ y j ∗ 1 ∑ k e y k + e y i ∗ − 1 ( ∑ k e y k ) 2 ∗ ∂ ( ∑ k e y k ) ∂ y j = ∂ e y i ∂ y j ∗ 1 ∑ k e y k − e y i ( ∑ k e y k ) 2 ∗ e y j = { e y j ∑ k e y k − ( e y j ) 2 ( ∑ k e y k ) 2 i = j − e y i e y j ( ∑ k e y k ) 2 i ≠ j (24) = { a i ( 1 − a i ) i = j − a i a j i ≠ j
b) 然后我们来求L关于 yj y j 的偏导
∂L∂yj=−∑i∂(y∗ilogai)∂ai∗∂ai∂yj=−∑iy∗iai∗∂ai∂yj=−y∗jaj∗aj(1−aj)+∑i≠ jy∗iai∗aiaj=−y∗j(1−aj)+∑i≠ jy∗iaj=−y∗j+∑iy∗iaj=aj−y∗j//注意这里i是变量,j是固定的//所有真实标签的概率之和为1(10)(11)(12)(13)(14)(15) (10) ∂ L ∂ y j = − ∑ i ∂ ( y i ∗ log a i ) ∂ a i ∗ ∂ a i ∂ y j (11) = − ∑ i y i ∗ a i ∗ ∂ a i ∂ y j (12) = − y j ∗ a j ∗ a j ( 1 − a j ) + ∑ i ≠ j y i ∗ a i ∗ a i a j / / 注 意 这 里 i 是 变 量 , j 是 固 定 的 (13) = − y j ∗ ( 1 − a j ) + ∑ i ≠ j y i ∗ a j (14) = − y j ∗ + ∑ i y i ∗ a j / / 所 有 真 实 标 签 的 概 率 之 和 为 1 (15) = a j − y j ∗
更一般的表示为 :
∂L∂y=a−y∗(25) (25) ∂ L ∂ y = a − y ∗
所以使用带softmax变换的交叉熵损失函数,损失函数L关于网络最后一层的导数就是预测值经softmax变换后的值减去真实值。(是不是跟均方差损失函数很相似,注意还是有差异的噢)