深度解剖(4):DNN反向传播-bp算法,矩阵偏导传递

news/2024/7/6 6:00:38 标签: 反向传播, 深度学习, bp算法

以下是链接我个人关于深度学习的所有见解,其后会对深度学习思想,正反向传播,损失函数,正则惩罚,梯度下降,矩阵求导,网络搭建,等等都进行详细的讲解!只有你想不到的,没有我讲不到的。让我用最通俗的语言,为你留下最深刻的印象,后来的年轻人以及我徒弟,好好加油!
深度解剖(0):最通俗易懂,详细无死角的深度学习讲解(目录)
如果有说得不对的地方,欢迎大家指出,我会第一时间进行更正,有兴趣可以加微信a944284742一起讨论技术,如果觉得喜欢,一定要点赞,因为这是对我最大的鼓励。

损失函数

先来看看我们上小节辛苦推导出来的公式:
a ( i , L ) = σ ( z L ) = σ ( a ( i , L − 1 ) ⋅ w ( i , L ) + b ( L ) ) a^{(i,L)} =\sigma (z^{L}) = \sigma(a^{(i,L-1)}·w^{(i,L)} + b^{(L)}) a(i,L)=σ(zL)=σ(a(i,L1)w(i,L)+b(L))通过这个公式,我们可以进行前向传播,简单的说,给定一个输入,通过前向传播就能获得一个预测值,这里说到预测值,我们肯定会联想到 l o s s loss loss,其代表的是损失,前面为了方便理解,我给大家说:
l o s s = 预测值 − 真实值 loss = 预测值 - 真实值 loss=预测值真实值,通过链式法则反向传播更新参数 w , b w,b w,b之后,通过多次迭代,loss会减少。在实际中,我们的损失函数是这样定义的:
单个样本: l o s s ( L ) ( x , w , b , y ) = 1 2 ∣ ∣ a L − y ∣ ∣ 2 2 单个样本:loss^{(L)}(x,w,b,y) = \frac{1}{2}||a^L-y||_2^2 单个样本:loss(L)(x,w,b,y)=21∣∣aLy22

多个样本: l o s s ( n , L ) ( x , w , b , y ) = 1 n ∑ i = 0 n 1 2 ∣ ∣ a L − y ∣ ∣ 2 2 多个样本:loss^{(n,L)}(x,w,b,y) = \frac{1}{n}∑ _{i=0}^n \frac{1}{2}||a^L-y||_2^2 多个样本:loss(n,L)(x,w,b,y)=n1i=0n21∣∣aLy22
大家不要觉得这个 1 2 \frac{1}{2} 21很奇怪,其是为了后面反向求导的方便,为了容易理解,假设我们使用单个样本进行训练,即使用下面的推导 l o s s ( L ) ( x , w , b , y ) = 1 2 ∣ ∣ a L − y ∣ ∣ 2 2 loss^{(L)}(x,w,b,y) = \frac{1}{2}||a^L-y||_2^2 loss(L)(x,w,b,y)=21∣∣aLy22大家需要注意的是, ∣ ∣ a L − y ∣ ∣ 2 ||a^L-y||_2 ∣∣aLy2,表示是L2范数,因为我们的输出 a L a^L aL虽然是一个样本训练的结果,但是这个结果可能是多列的,即不单单是一维的。但是计算得到 l o s s loss loss,一般都是一个数值。并且也请大家注意到 l o s s ( L ) ( x , w , b , y ) loss^{(L)}(x,w,b,y) loss(L)(x,w,b,y),其大小只与 x , w , b , y x,w,b,y x,w,b,y相关,同时,这里的 w , b w,b w,b是没有上标的,其代表的并不是某一层的 w w w,而是所有网络结构 w w w的综合,当然 b b b也是一样。

bp算法单层公式推导

上面我们通过前向传播,得到 a L a^L aL,然后计算得到损失 l o s s loss loss,并且告诉大家其 l o s s loss loss只和参数 ( x , w , b , y ) (x,w,b,y) (x,w,b,y)相关,为了直接的体现出来我在这里把公式代入展开:
l o s s ( L ) ( x , w , b , y ) = 1 2 ∣ ∣ σ ( z L ) − y ∣ ∣ 2 2 = 1 2 ∣ ∣ σ ( a L − 1 ⋅ w L + b L ) − y ∣ ∣ 2 2 loss^{(L)}(x,w,b,y) = \frac{1}{2}||\sigma (z^L)-y||_2^2=\frac{1}{2}|| \sigma(a^{L-1}·w^{L} + b^{L}) -y||_2^2 loss(L)(x,w,b,y)=21∣∣σ(zL)y22=21∣∣σ(aL1wL+bL)y22这个样子展开之后,大家应该和能感受到, l o s s loss loss是直接受到 x , w , b , y x,w,b,y x,w,b,y参数的影响的,但是我们要更新的只有 w , b w,b w,b。通过前面的小节我们知道 σ \sigma σ表示的是激活函数,但是激活函数有很多种类,如sigmod,rule,softmax,prule等等。在这里不做详细的讲解,后续有专门的章节,进行详细解说。

好了,现在正式进入反向传播,根据上面的公式,我们要对 w w w进行更新,那么我们就需要知道更新多大的值才比较合适。前面提到,我们训练网络就是为了让 l o s s loss loss接近0,也就是现在我们要想办法改变 w , b w,b w,b l o s s loss loss变得更加小。也就是说,我们需要对 w , b w,b w,b求偏导,

∂ [ l o s s ( L ) ( x , w , b , y ) ] ∂ w L = [ ( a L − y ) ⊙ σ ′ ( z L ) ] ( a L − 1 ) T \frac {\partial [loss^{(L)}(x,w,b,y)]}{\partial w^L} =[(a^L-y) ⊙\sigma'(z^L)](a^{L-1})^{T} wL[loss(L)(x,w,b,y)]=[(aLy)σ(zL)](aL1)T
注意上式中有一个符号⊙⊙,它代表Hadamard积,对于两个维度相同的向量 A ( a 1 , a 2 , . . . a n ) T A(a_1,a_2,...a_n)^{T} A(a1,a2,...an)T B ( b 1 , b 2 , . . . b n ) T B(b_1,b_2,...bn)^{T} B(b1,b2,...bn)T ,则 A ⊙ B = ( a 1 b 1 , a 2 b 2 , . . . a n b n ) T A⊙B=(a_1b_1,a_2b_2,...a_nb_n)^T AB=(a1b1,a2b2,...anbn)T。直白的说就是对应的相乘就可以了。因为上述公式中的 a L , y , σ ′ ( z L ) a^L,y,\sigma'(z^L) aL,y,σ(zL)表示的不是一个数,而是一个多维的数组,但是 σ ′ ( z L ) \sigma'(z^L) σ(zL) a L , y a^L,y aL,y维度都是相同的,单个样本的时候,一般为1*n维的数组。那么为什么乘以 ( a L − 1 ) T (a^{L-1})^{T} (aL1)T的时候,需要进行转置(符号T,表示行列互换,可以百度一下矩阵转置)呢?,首先注意, a L − 1 与 a L a^{L-1}与a^{L} aL1aL的维度不一定相同的,[(a^L-y) ⊙\sigma’(zL)]与(a{L-1})^{T}表示的也不是矩阵相乘。而是普通的数组相乘。如下面两个矩阵相乘:
{ [ a 11 L − 1 a 12 L − 1 a 13 L − 1 ] } ⋅ { [ w 11 L w 12 L ] [ w 21 L w 22 L ] [ w 31 L w 32 L ] } = { [ a 11 L a 12 L ] } \left\{ \begin{matrix} [a_{11}^{L-1} & a_{12}^{L-1}& a_{13}^{L-1}]\\ \end{matrix} \right\}· \left\{ \begin{matrix} [w_{11}^L& w_{12}^L ]\\ \\ [w_{21}^L & w_{22}^L]\\ \\ [w_{31}^L & w_{32}^L]\\ \end{matrix} \right\} = \left\{ \begin{matrix} [a_{11}^{L} & a_{12}^{L}]\\ \end{matrix} \right\} {[a11L1a12L1a13L1]} [w11L[w21L[w31Lw12L]w22L]w32L] ={[a11La12L]}
那么计算的过程:
a 11 L = a 11 L − 1 w 11 + a 12 L − 1 w 21 + a 13 L − 1 w 31 a_{11}^{L} = a_{11}^{L-1}w_{11} + a_{12}^{L-1}w_{21} + a_{13}^{L-1}w_{31} a11L=a11L1w11+a12L1w21+a13L1w31 a 12 L = a 11 L − 1 w 12 + a 12 L − 1 w 22 + a 13 L − 1 w 32 \\a_{12}^{L} = a_{11}^{L-1}w_{12} + a_{12}^{L-1}w_{22} + a_{13}^{L-1}w_{32} a12L=a11L1w12+a12L1w22+a13L1w32
这是正向传播的过程,我们反向传播是为了求
{ [ ∂ a 11 L ∂ w 11 L ∂ a 12 L ∂ w 12 L [ ∂ a 11 L ∂ w 21 L ∂ a 12 L ∂ w 22 L [ ∂ a 11 L ∂ w 31 L ∂ a 12 L ∂ w 32 L } = { [ a 11 L − 1 a 12 L − 1 ] [ a 11 L − 1 a 12 L − 1 ] [ a 11 L − 1 a 12 L − 1 ] } \left\{ \begin{matrix} [\frac{\partial a_{11}^L}{\partial w_{11}^L} & \frac{\partial a_{12}^L}{\partial w_{12}^L} \\ \\ [\frac{\partial a_{11}^L}{\partial w_{21}^L} & \frac{\partial a_{12}^L}{\partial w_{22}^L} \\ \\ [\frac{\partial a_{11}^L}{\partial w_{31}^L} & \frac{\partial a_{12}^L}{\partial w_{32}^L} \\ \end{matrix} \right\} = \left\{ \begin{matrix} [a_{11}^{L-1}& a_{12}^{L-1}]\\ \\ [a_{11}^{L-1} & a_{12}^{L-1}]\\ \\ [a_{11}^{L-1} & a_{12}^{L-1}]\\ \end{matrix} \right\} [w11La11L[w21La11L[w31La11Lw12La12Lw22La12Lw32La12L = [a11L1[a11L1[a11L1a12L1]a12L1]a12L1] ,那么如何才能得到这个呢,那就是使用数组乘法, [ ( a L − y ) ⊙ σ ′ ( z L ) ] [(a^L-y) ⊙\sigma'(z^L)] [(aLy)σ(zL)] ( a L − 1 ) T (a^{L-1})^{T} (aL1)T相乘,如下面是使用np一个简单的例子:

import numpy as np

A = [[1,2]]
A = np.array(A)

B = [[1,2,3]]
B = np.array(B)

print(np.multiply(A,B.T))

输出结果:

[[1 2]
 [2 4]
 [3 6]]

上面是对 w w w数组求偏导的过程,现在我们对 b b b求偏导:
∂ [ l o s s ( L ) ( x , w , b , y ) ] ∂ b L = [ ( a L − y ) ⊙ σ ′ ( z L ) ] \frac {\partial [loss^{(L)}(x,w,b,y)]}{\partial b^L} =[(a^L-y) ⊙\sigma'(z^L)] bL[loss(L)(x,w,b,y)]=[(aLy)σ(zL)]
这里的由来,就不再进行解释了,因为按照前面求 w w w的思路就可以了。

bp算法多层公式推导

经过上面我们得到两个公式:

∂ [ l o s s ( L ) ( x , w , b , y ) ] ∂ w L = [ ( a L − y ) ⊙ σ ′ ( z L ) ] ( a L − 1 ) T \frac {\partial [loss^{(L)}(x,w,b,y)]}{\partial w^L} =[(a^L-y) ⊙\sigma'(z^L)](a^{L-1})^{T} wL[loss(L)(x,w,b,y)]=[(aLy)σ(zL)](aL1)T ∂ [ l o s s ( L ) ( x , w , b , y ) ] ∂ b L = [ ( a L − y ) ⊙ σ ′ ( z L ) ] \frac {\partial [loss^{(L)}(x,w,b,y)]}{\partial b^L} =[(a^L-y) ⊙\sigma'(z^L)] bL[loss(L)(x,w,b,y)]=[(aLy)σ(zL)]
但是上面这个公式有个缺陷,其反向传播过程,只传递了一层,即从L层传到了L-1,假设我们的网络结构现在一共有L,我们就要把 l o s s loss loss从第L层传递到第一层,即要传递给网络中所有的 w w w b b b

其上公式我们可以注意到,在求解输出层的 w , b w,b w,b,有中间依赖部分 ∂ [ l o s s ( L ) ( x , w , b , y ) ] ∂ z L \frac {\partial [loss^{(L)}(x,w,b,y)]}{\partial z^L} zL[loss(L)(x,w,b,y)],我们可以先把对 z L z^L zL的偏导求出来:
δ L = ∂ [ l o s s ( L ) ( x , w , b , y ) ] ∂ z L = ( a L − y ) ⊙ σ ′ ( z L ) \delta^L = \frac {\partial [loss^{(L)}(x,w,b,y)]}{\partial z^L}=(a^L-y) ⊙\sigma'(z^L) δL=zL[loss(L)(x,w,b,y)]=(aLy)σ(zL)
在这里插入图片描述
首先这里要明确一个东西,求输出层L中 w , b w,b w,b的梯度,是为了更新L层的 w , b w,b w,b,上面求 δ L \delta^L δL得梯度,是为了传递给前面得网络层,所以这三个都是有必要的,如下图标记:
在这里插入图片描述
三种颜色分别表示要求的3种梯度。现在我们终于把梯度 δ L \delta^L δL求出来了,根据链式法则,有如下公式:

δ l = ∂ [ l o s s ( L ) ( x , w , b , y ) ] ∂ z l = ( ∂ z L ∂ z L − 1 ∂ z L − 1 ∂ z L − 2 ⋅ ⋅ ⋅ ⋅ ∂ z l + 1 ∂ z l ) T ∂ [ l o s s ( L ) ( x , w , b , y ) ] ∂ z L \delta^l = \frac {\partial [loss^{(L)}(x,w,b,y)]}{\partial z^l}= (\frac {\partial z^L}{\partial z^{L-1}} \frac {\partial z^{L-1}}{\partial z^{L-2}}····\frac {\partial z^{l+1}}{\partial z^{l}})^T\frac {\partial [loss^{(L)}(x,w,b,y)]}{\partial z^L} δl=zl[loss(L)(x,w,b,y)]=(zL1zLzL2zL1⋅⋅⋅⋅zlzl+1)TzL[loss(L)(x,w,b,y)]看到上面的公式,大家要注意下大L和小 l l l的区分,大L表示的输出层,小 l l l表示的是中间层次。也就是说通过上面的公式,我们就能求出中间任意层次的梯度的(通过链式法则)。我们求出了中间任意层次的梯度,但是还是不够的,因为我们最终是为了作用于 w , b w,b w,b,也就是说,求出之前层数 z l z^l zl(此时没有经过激活函数)的梯度,然后还要传递给对应层数的 w , b w,b w,b,其实传递的方式是很简单的,因为:
z l = w a l − 1 + b l z^l = wa^{l-1}+b^l zl=wal1+bl
所以根据链式法则:
∂ [ l o s s ( x , w , b , y ) ] ∂ w l = δ l ( a l − 1 ) T \frac {\partial [loss(x,w,b,y)]}{\partial w^l}= \delta^l(a^{l-1})^T wl[loss(x,w,b,y)]=δl(al1)T ∂ [ l o s s ( x , w , b , y ) ] ∂ b l = δ l \frac {\partial [loss(x,w,b,y)]}{\partial b^l}= \delta^l bl[loss(x,w,b,y)]=δl那么和明显的感觉到,我们要更新某一层的 w , b w,b w,b,就要求出该层的 δ l \delta^l δl,现在我们对前面的公式:
δ l = ∂ [ l o s s ( L ) ( x , w , b , y ) ] ∂ z l = ( ∂ z L ∂ z L − 1 ∂ z L − 1 ∂ z L − 2 ⋅ ⋅ ⋅ ⋅ ∂ z l + 1 ∂ z l ) T ∂ [ l o s s ( L ) ( x , w , b , y ) ] ∂ z L \delta^l = \frac {\partial [loss^{(L)}(x,w,b,y)]}{\partial z^l}= (\frac {\partial z^L}{\partial z^{L-1}} \frac {\partial z^{L-1}}{\partial z^{L-2}}····\frac {\partial z^{l+1}}{\partial z^{l}})^T\frac {\partial [loss^{(L)}(x,w,b,y)]}{\partial z^L} δl=zl[loss(L)(x,w,b,y)]=(zL1zLzL2zL1⋅⋅⋅⋅zlzl+1)TzL[loss(L)(x,w,b,y)]
进行简化得到:
δ l = ∂ [ l o s s ( x , w , b , y ) ] ∂ z l = ( ∂ z l + 1 ∂ z l ) T ∂ [ l o s s ( x , w , b , y ) ] ∂ z l + 1 = ( ∂ z l + 1 ∂ z l ) T δ l + 1 \delta^l = \frac {\partial [loss^{}(x,w,b,y)]}{\partial z^l}= (\frac {\partial z^{l+1}}{\partial z^l})^T\frac {\partial [loss(x,w,b,y)]}{\partial z^{l+1}}=(\frac {\partial z^{l+1}}{\partial z^l})^T\delta^{l+1} δl=zl[loss(x,w,b,y)]=(zlzl+1)Tzl+1[loss(x,w,b,y)]=(zlzl+1)Tδl+1
简介如下:
δ l = ( ∂ z l + 1 ∂ z l ) T δ l + 1 \delta^l =(\frac {\partial z^{l+1}}{\partial z^l})^T\delta^{l+1} δl=(zlzl+1)Tδl+1
这样就变成了一个递推模型,即重点在于求解 ( ∂ z l + 1 ∂ z l ) (\frac {\partial z^{l+1}}{\partial z^l}) (zlzl+1),其求解又非常的简单

z l + 1 = w l + 1 a l + b l + 1 = w l + 1 σ ( z l ) + b l + 1 z^{l+1} = w^{l+1}a^l+b^{l+1} = w^{l+1}\sigma(z^l) +b^{l+1} zl+1=wl+1al+bl+1=wl+1σ(zl)+bl+1所以:
( ∂ z l + 1 ∂ z l ) = w l + 1 d i a g ( σ ′ ( z l ) ) (\frac {\partial z^{l+1}}{\partial z^l}) = w^{l+1}diag(\sigma'( z^l)) (zlzl+1)=wl+1diag(σ(zl))
前面为大家简介了很多次矩阵的运算,这里的diag表示处对角线之外,其余都为0,至于为什么要这样,大家可以去推导一下,如果没有先明白,可以看文章开头,添加我的微信一起探讨。现在我们带入前面的式子
δ l = ∂ [ l o s s ( x , w , b , y ) ] ∂ z l = ( ∂ z l + 1 ∂ z l ) T ∂ [ l o s s ( x , w , b , y ) ] ∂ z l + 1 = ( w l + 1 d i a g ( σ ′ ( z l ) ) ) T δ l + 1 = ( w l + 1 ) T δ l + 1 ⊙ σ ′ ( z l ) \delta^l = \frac {\partial [loss^{}(x,w,b,y)]}{\partial z^l}= (\frac {\partial z^{l+1}}{\partial z^l})^T\frac {\partial [loss(x,w,b,y)]}{\partial z^{l+1}}=(w^{l+1}diag(\sigma'( z^l)))^T\delta^{l+1}= (w^{l+1})^T\delta^{l+1}⊙\sigma'(z^l) δl=zl[loss(x,w,b,y)]=(zlzl+1)Tzl+1[loss(x,w,b,y)]=(wl+1diag(σ(zl)))Tδl+1=(wl+1)Tδl+1σ(zl)
到这里,反向传播算是推导完成了,也就是说,我们只要知道了某一层的 δ l \delta^l δl,我们就能得到其对应需要更新$ Δ \Delta Δw, Δ \Delta Δb$。

反向传播已经简介完成,暂时还没有想到接下来讲解什么内容,敬请期待!


http://www.niftyadmin.cn/n/915939.html

相关文章

module_init宏

我们在学习Linux驱动开发时&#xff0c;首先需要了解Linux的模块化机制&#xff08;module&#xff09;&#xff0c;但是module并不仅仅用于支撑驱动的加载和卸载。一个最简单的模块例子如下&#xff1a;// filename: HelloWorld.c#include <linux/module.h> #include &l…

常见的网站服务器架构有哪些?

最近抽空整理了一份性能测试参数指导表,通俗点来讲就是那些在Linux下的vmstat,top,iostat命令中经常看到的那些参数究竟怎么看,我们在测试工作中经常需要他们。个人对性能测试工作的理解是:从打牢基础做起,不断学习新架构(大数据,队列,缓存技术,集群等),只有有了这些基础你才能…

风格迁移0-11:stylegan-源码无死角解读(7)-图片生成与融合

以下链接是个人关于stylegan所有见解&#xff0c;如有错误欢迎大家指出&#xff0c;我会第一时间纠正&#xff0c;如有兴趣可以加微信&#xff1a;17575010159 相互讨论技术。若是帮助到了你什么&#xff0c;一定要记得点赞奥&#xff01;因为这是对我最大的鼓励。 风格迁移0-0…

获取CPU信息

1 查看手机CPU信息 cmd——adb shell——cd /proc------cat cpuinfo 2 获取cpu的是arm指令集&#xff0c;armv7指令集、还是neon指令集 /** * * [获取cpu类型和架构] * * return * 三个参数类型的数组&#xff0c;第一个参数标识是不是ARM架构&#xff0c;第二个参数标…

204. Count Primes

不解释了 1 public int countPrimes(int n) {2 if(n < 0) {3 return 0;4 }5 boolean[] isPrime new boolean[n];6 for(int i 1; i < n; i) {7 isPrime[i] true;8 }9 for(int i 2; i * …

行人重识别0-01:DG-Net(ReID)-论文翻译,详细解说(1)

以下链接是个人关于DG-Net(行人重识别ReID)所有见解&#xff0c;如有错误欢迎大家指出&#xff0c;我会第一时间纠正。有兴趣的朋友可以加微信&#xff1a;17575010159 相互讨论技术。若是帮助到了你什么&#xff0c;一定要记得点赞&#xff01;因为这是对我最大的鼓励。文末附…

struct fb_bitfield

struct fb_bitfield { /*fb缓存的RGB位域&#xff0c;该结构描述每一个像素显示缓冲区的组织方式&#xff0c;假如为RGB565模式&#xff0c;R占5位bit[11:15] G占6位bit[10:5] B占5位bit[4:0] */__u32 offset; /* beginning of bitfield */ /*位域偏移:red11 ,green5…

fb_var_screeninfo 和fb_fix_screeninfo

struct fb_var_screeninfo { //struct fb_info的成员&#xff08;可变参数&#xff09;&#xff0c;其记录用户可修改的显示控制器的参数&#xff0c;包括分//辨率和每个像素点的比特数&#xff0c;其成员需要在驱动程序中初始化和设置/********可见解析度&#xff08;实际屏幕…