• BP算法和CNN算法推导过程

转载来源：
http://blog.csdn.net/walegahaha/article/details/51867904
http://blog.csdn.net/walegahaha/article/details/51945421
关于CNN推导可以参考文献: NotesonConvolutionalNeuralNetworks

对比两个推导过程，可以发现两者的思路完全相同，不同的是具体每一个求导的方法

2. CNN-BP-算法推导


展开全文
• 与深度神经网络DNN的反向传播算法一致，辅助变量： {δL=∂J∂zL=∂J∂aL⊙σ′(zL)δl=(Wl+1)Tδl+1⊙σ′(zl)\left\{\begin{aligned} &amp;\delta^L = \frac{\partial J}{\partial z^L} = \frac{\partial ...
文章目录1. 全连接层2. 池化层3. 卷积层4. 参考资料
1. 全连接层
与深度神经网络DNN的反向传播算法一致，辅助变量：
\left\{\begin{aligned} &\delta^L = \frac{\partial J}{\partial z^L} = \frac{\partial J}{\partial a^L} \odot \sigma'(z^L)\\ &\\ &\delta^l = (W^{l+1})^T\delta^{l+1}\odot \sigma'(z^l) \end{aligned}\right. \tag{1}
进而求得参数$W$，$b$的梯度：
\left\{\begin{aligned} &\frac{\partial J}{\partial W^l} = \frac{\partial J}{\partial z^l} \frac{\partial z^l}{\partial W^l} = \delta^l(a^{l-1})^T\\ &\\ & \frac{\partial J}{\partial b^l} = \frac{\partial J}{\partial z^l} \frac{\partial z^l}{\partial b^l} = \delta^l \end{aligned}\right.
解释一下式(1)中为何使用点乘：
以平方误差损失函数为例：
$J = \frac{1}{2}\left\Vert a^L - y\right\Vert_2^2= \frac{1}{2}\sum_{i=1}^N(a_i^L - y)^2= \frac{1}{2}\sum_{i=1}^N(\sigma(z_i^L) - y)^2$
则
\begin{aligned} &\delta^L = \frac{\partial J}{\partial z^L} =\begin{bmatrix} \frac{\partial J}{\partial z_1^L} \\ \\ \frac{\partial J}{\partial z_2^L} \\ \\ \vdots\\ \\ \frac{\partial J}{\partial z_N^L} \end{bmatrix}=\begin{bmatrix} (a_1^L-y)\sigma'(z_1^L) \\ \\ (a_2^L-y)\sigma'(z_2^L) \\ \\ \vdots\\ \\ (a_N^L-y)\sigma'(z_N^L) \end{bmatrix}=(a^L-y)\odot\sigma'(z^L)= \frac{\partial J}{\partial a^L} \odot \sigma'(z^L)\\ &\\ \end{aligned}
也可以从向量的维度上进行分析：
向量$a^L-y$和向量$\sigma'(z^L)$的维度相同，都属于$\mathbb{R}^{N\times1}$，因此只能是点乘。
如果是交叉熵损失函数：
$J= - \sum\limits_{i=1}^Ny_i\log a_i^L$
则
$\delta^L = \frac{\partial J}{\partial z^L} = a^L - y$
不存在$\sigma'(z^L)$这一项。

2. 池化层
设池化层的输入为$a^{l}$，输出为$z^{l+1}$，则有：
$z^{l+1} = \text{pool}(a^{l})$
则
$\delta^{l}= \frac{\partial J}{\partial z^{l}}= \frac{\partial J}{\partial z^{l+1}} \frac{\partial z^{l+1}}{\partial a^{l}}\frac{\partial a^{l}}{\partial z^{l}} = \text{upsample} (\delta^{l+1})\odot \sigma'(z^l)$
其中，upsample指在反向传播时，把$\delta^{l+1}$的矩阵大小还原成池化之前的大小，一共分为两种情况：

如果是Max，则把$\delta^{l+1}$的各元素值放在之前做前向传播算法得到最大值的位置，所以这里需要额外记录每个区块中最大元素的位置
如果是Average，则把$\delta^{l+1}$的各元素值取平均后，填入对应的区块位置。

举例，设池化层的核心大小是$2\times2$，则：
$\delta^{l+1} = \left( \begin{array}{ccc} 2& 8 \\ 4& 6 \end{array} \right) \xrightarrow{\text{Max upsample}} \left( \begin{array}{ccc} 2&0&0&0 \\ 0&0& 0&8 \\ 0&4&0&0 \\ 0&0&6&0 \end{array} \right)$
$\delta^{l+1} = \left( \begin{array}{ccc} 2& 8 \\ 4& 6 \end{array} \right) \xrightarrow{\text{Average upsample}} \left( \begin{array}{ccc} 0.5&0.5&2&2 \\ 0.5&0.5&2&2 \\ 1&1&1.5&1.5 \\ 1&1&1.5&1.5 \end{array} \right)$
注意，对于Average情况下的反向传播，容易误认为是把梯度值复制几遍之后直接填入对应的区块位置。其实很容易理解为什么要把梯度值求平均，我们用一个小例子来说明：
假设对四个变量$a, b, c, d$求平均，得到$z$，也即：
$z=\frac{1}{4}(a+b+c+d)$
那么，$z$关于每个变量的导数都是1/4。反向传播到$z$时，累积的梯度值为$\delta$，那么，
\left\{\begin{aligned} &\frac{\partial J}{\partial a} = \frac{\partial J}{\partial z}\frac{\partial z}{\partial a} = \frac{1}{4}\delta\\ &\frac{\partial J}{\partial b}= \frac{\partial J}{\partial z}\frac{\partial z}{\partial b} = \frac{1}{4}\delta\\ &\frac{\partial J}{\partial c}= \frac{\partial J}{\partial z}\frac{\partial z}{\partial c} = \frac{1}{4}\delta\\ &\frac{\partial J}{\partial d}= \frac{\partial J}{\partial z}\frac{\partial z}{\partial d} = \frac{1}{4}\delta \end{aligned}\right.
这样就很容易理解了。
3. 卷积层
卷积层的前向传播公式：
$a^{l+1} = \sigma(z^{l+1}) = \sigma(a^l*W^{l+1} + b^{l+1})$
则
$\delta^{l}= \frac{\partial J}{\partial z^{l}}= \frac{\partial J}{\partial z^{l+1}} \frac{\partial z^{l+1}}{\partial a^{l}}\frac{\partial a^{l}}{\partial z^{l}} = \delta^{l+1} *\text{Rotation180}(W^{l+1})\odot \sigma'(z^l)$
其中Rotation180意思是卷积核$W$被旋转180度，也即上下翻转一次，接着左右翻转一次。另外注意，这里需要对$\delta^{l+1}$进行适当的padding，当stride为1时，$p'=k-p-1$。
详细推导请参见 https://www.cnblogs.com/pinard/p/6494810.html
参数$W$，$b$的梯度：
\left\{\begin{aligned} &\frac{\partial J}{\partial W^l} = \frac{\partial J}{\partial z^l} \frac{\partial z^l}{\partial W^l} = a^{l-1}*\delta^l\\ &\\ & \frac{\partial J}{\partial b^l} = \frac{\partial J}{\partial z^l} \frac{\partial z^l}{\partial b^l} = \sum\limits_{u,v}(\delta^l)_{u,v} \end{aligned}\right.
其中，关于$W$的梯度没有旋转操作，$\sum\limits_{u,v}(\delta^l)_{u,v}$意思是把$\delta^l$的所有通道沿通道方向求和，累加成一个通道。
4. 参考资料
感谢 https://www.cnblogs.com/pinard/p/6494810.html


展开全文
•  这个文档讨论的是CNNs的推导和实现。CNN架构的连接比权值要多很多，这实际上就隐含着实现了某种形式的规则化。这种特别的网络假定了我们希望通过数据驱动的方式学习到一些滤波器，作为提取输入的特征的一种方法。 ...

《Notes on Convolutional Neural Networks》
一、介绍
这个文档讨论的是CNNs的推导和实现。CNN架构的连接比权值要多很多，这实际上就隐含着实现了某种形式的规则化。这种特别的网络假定了我们希望通过数据驱动的方式学习到一些滤波器，作为提取输入的特征的一种方法。
本文中，我们先对训练全连接网络的经典BP算法做一个描述，然后推导2D
CNN网络的卷积层和子采样层的BP权值更新方法。在推导过程中，我们更强调实现的效率，所以会给出一些Matlab代码。最后，我们转向讨论如何自动地学习组合前一层的特征maps，特别地，我们还学习特征maps的稀疏组合。

二、全连接的反向传播算法
典型的CNN中，开始几层都是卷积和下采样的交替，然后在最后一些层（靠近输出层的），都是全连接的一维网络。这时候我们已经将所有两维2D的特征maps转化为全连接的一维网络的输入。这样，当你准备好将最终的2D特征maps输入到1D网络中时，一个非常方便的方法就是把所有输出的特征maps连接成一个长的输入向量。然后我们回到BP算法的讨论。（更详细的基础推导可以参考UFLDL中“反向传导算法”）。
2.1、Feedforward Pass前向传播
在下面的推导中，我们采用平方误差代价函数。我们讨论的是多类问题，共c类，共N个训练样本。

这里表示第n个样本对应的标签的第k维。表示第n个样本对应的网络输出的第k个输出。对于多类问题，输出一般组织为“one-of-c”的形式，也就是只有该输入对应的类的输出节点输出为正，其他类的位或者节点为0或者负数，这个取决于你输出层的激活函数。sigmoid就是0，tanh就是-1.
因为在全部训练集上的误差只是每个训练样本的误差的总和，所以这里我们先考虑对于一个样本的BP。对于第n个样本的误差，表示为：

传统的全连接神经网络中，我们需要根据BP规则计算代价函数E关于网络每一个权值的偏导数。我们用l来表示当前层，那么当前层的输出可以表示为：

输出激活函数f(.)可以有很多种，一般是sigmoid函数或者双曲线正切函数。sigmoid将输出压缩到[0,
1]，所以最后的输出平均值一般趋于0 。所以如果将我们的训练数据归一化为零均值和方差为1，可以在梯度下降的过程中增加收敛性。对于归一化的数据集来说，双曲线正切函数也是不错的选择。

2.2、Backpropagation Pass反向传播
反向传播回来的误差可以看做是每个神经元的基的灵敏度sensitivities（灵敏度的意思就是我们的基b变化多少，误差会变化多少，也就是误差对基的变化率，也就是导数了），定义如下：（第二个等号是根据求导的链式法则得到的）

因为∂u/∂b=1，所以∂E/∂b=∂E/∂u=δ，也就是说bias基的灵敏度∂E/∂b=δ和误差E对一个节点全部输入u的导数∂E/∂u是相等的。这个导数就是让高层误差反向传播到底层的神来之笔。反向传播就是用下面这条关系式：（下面这条式子表达的就是第l层的灵敏度，就是）

公式（1）
这里的“◦”表示每个元素相乘。输出层的神经元的灵敏度是不一样的：

最后，对每个神经元运用delta（即δ）规则进行权值更新。具体来说就是，对一个给定的神经元，得到它的输入，然后用这个神经元的delta（即δ）来进行缩放。用向量的形式表述就是，对于第l层，误差对于该层每一个权值（组合为矩阵）的导数是该层的输入（等于上一层的输出）与该层的灵敏度（该层每个神经元的δ组合成一个向量的形式）的叉乘。然后得到的偏导数乘以一个负学习率就是该层的神经元的权值的更新了：

公式（2）
对于bias基的更新表达式差不多。实际上，对于每一个权值(W)ij都有一个特定的学习率ηIj。

三、Convolutional Neural Networks 卷积神经网络
3.1、Convolution Layers 卷积层
我们现在关注网络中卷积层的BP更新。在一个卷积层，上一层的特征maps被一个可学习的卷积核进行卷积，然后通过一个激活函数，就可以得到输出特征map。每一个输出map可能是组合卷积多个输入maps的值：

这里Mj表示选择的输入maps的集合，那么到底选择哪些输入maps呢？有选择一对的或者三个的。但下面我们会讨论如何去自动选择需要组合的特征maps。每一个输出map会给一个额外的偏置b，但是对于一个特定的输出map，卷积每个输入maps的卷积核是不一样的。也就是说，如果输出特征map
j和输出特征map k都是从输入map i中卷积求和得到，那么对应的卷积核是不一样的。
我们假定每个卷积层l都会接一个下采样层l+1 。对于BP来说，根据上文我们知道，要想求得层l的每个神经元对应的权值的权值更新，就需要先求层l的每一个神经节点的灵敏度δ（也就是权值更新的公式（2））。为了求这个灵敏度我们就需要先对下一层的节点（连接到当前层l的感兴趣节点的第l+1层的节点）的灵敏度求和（得到δl+1），然后乘以这些连接对应的权值（连接第l层感兴趣节点和第l+1层节点的权值）W。再乘以当前层l的该神经元节点的输入u的激活函数f的导数值（也就是那个灵敏度反向传播的公式（1）的δl的求解），这样就可以得到当前层l每个神经节点对应的灵敏度δl了。
然而，因为下采样的存在，采样层的一个像素（神经元节点）对应的灵敏度δ对应于卷积层（上一层）的输出map的一块像素（采样窗口大小）。因此，层l中的一个map的每个节点只与l+1层中相应map的一个节点连接。
为了有效计算层l的灵敏度，我们需要上采样upsample 这个下采样downsample层对应的灵敏度map（特征map中每个像素对应一个灵敏度，所以也组成一个map），这样才使得这个灵敏度map大小与卷积层的map大小一致，然后再将层l的map的激活值的偏导数与从第l+1层的上采样得到的灵敏度map逐元素相乘（也就是公式（1））。
在下采样层map的权值都取一个相同值β，而且是一个常数。所以我们只需要将上一个步骤得到的结果乘以一个β就可以完成第l层灵敏度δ的计算。
我们可以对卷积层中每一个特征map j重复相同的计算过程。但很明显需要匹配相应的子采样层的map（参考公式（1））：

up(.)表示一个上采样操作。如果下采样的采样因子是n的话，它简单的将每个像素水平和垂直方向上拷贝n次。这样就可以恢复原来的大小了。实际上，这个函数可以用Kronecker乘积来实现：

好，到这里，对于一个给定的map，我们就可以计算得到其灵敏度map了。然后我们就可以通过简单的对层l中的灵敏度map中所有节点进行求和快速的计算bias基的梯度了：

公式（3）
最后，对卷积核的权值的梯度就可以用BP算法来计算了（公式（2））。另外，很多连接的权值是共享的，因此，对于一个给定的权值，我们需要对所有与该权值有联系（权值共享的连接）的连接对该点求梯度，然后对这些梯度进行求和，就像上面对bias基的梯度计算一样：

这里，是中的在卷积的时候与逐元素相乘的patch，输出卷积map的(u,
v)位置的值是由上一层的(u, v)位置的patch与卷积核k_ij逐元素相乘的结果。
咋一看，好像我们需要煞费苦心地记住输出map（和对应的灵敏度map）每个像素对应于输入map的哪个patch。但实际上，在Matlab中，可以通过一个代码就实现。对于上面的公式，可以用Matlab的卷积函数来实现：

我们先对delta灵敏度map进行旋转，这样就可以进行互相关计算，而不是卷积（在卷积的数学定义中，特征矩阵（卷积核）在传递给conv2时需要先翻转（flipped）一下。也就是颠倒下特征矩阵的行和列）。然后把输出反旋转回来，这样我们在前向传播进行卷积的时候，卷积核才是我们想要的方向。

3.2、Sub-sampling Layers 子采样层
对于子采样层来说，有N个输入maps，就有N个输出maps，只是每个输出map都变小了。

down(.)表示一个下采样函数。典型的操作一般是对输入图像的不同nxn的块的所有像素进行求和。这样输出图像在两个维度上都缩小了n倍。每个输出map都对应一个属于自己的乘性偏置β和一个加性偏置b。

这里最困难的是计算灵敏度map。一旦我们得到这个了，那我们唯一需要更新的偏置参数β和b就可以轻而易举了（公式（3））。如果下一个卷积层与这个子采样层是全连接的，那么就可以通过BP来计算子采样层的灵敏度maps。
我们需要计算卷积核的梯度，所以我们必须找到输入map中哪个patch对应输出map的哪个像素。这里，就是必须找到当前层的灵敏度map中哪个patch对应与下一层的灵敏度map的给定像素，这样才可以利用公式（1）那样的δ递推，也就是灵敏度反向传播回来。另外，需要乘以输入patch与输出像素之间连接的权值，这个权值实际上就是卷积核的权值（已旋转的）。

在这之前，我们需要先将核旋转一下，让卷积函数可以实施互相关计算。另外，我们需要对卷积边界进行处理，但在Matlab里面，就比较容易处理。Matlab中全卷积会对缺少的输入像素补0 。
到这里，我们就可以对b和β计算梯度了。首先，加性基b的计算和上面卷积层的一样，对灵敏度map中所有元素加起来就可以了：

而对于乘性偏置β，因为涉及到了在前向传播过程中下采样map的计算，所以我们最好在前向的过程中保存好这些maps，这样在反向的计算中就不用重新计算了。我们定义：

这样，对β的梯度就可以用下面的方式计算：

3.3、Learning Combinations of Feature Maps 学习特征map的组合
大部分时候，通过卷积多个输入maps，然后再对这些卷积值求和得到一个输出map，这样的效果往往是比较好的。在一些文献中，一般是人工选择哪些输入maps去组合得到一个输出map。但我们这里尝试去让CNN在训练的过程中学习这些组合，也就是让网络自己学习挑选哪些输入maps来计算得到输出map才是最好的。我们用αij表示在得到第j个输出map的其中第i个输入map的权值或者贡献。这样，第j个输出map可以表示为：

需要满足约束：

这些对变量αij的约束可以通过将变量αij表示为一个组无约束的隐含权值cij的softmax函数来加强。（因为softmax的因变量是自变量的指数函数，他们的变化率会不同）。

因为对于一个固定的j来说，每组权值cij都是和其他组的权值独立的，所以为了方面描述，我们把下标j去掉，只考虑一个map的更新，其他map的更新是一样的过程，只是map的索引j不同而已。
Softmax函数的导数表示为：

这里的δ是Kronecker delta。对于误差对于第l层变量αi的导数为：

最后就可以通过链式规则去求得代价函数关于权值ci的偏导数了：

3.3.1、Enforcing Sparse Combinations 加强稀疏性组合
为了限制αi是稀疏的，也就是限制一个输出map只与某些而不是全部的输入maps相连。我们在整体代价函数里增加稀疏约束项Ω(α)。对于单个样本，重写代价函数为：

然后寻找这个规则化约束项对权值ci求导的贡献。规则化项Ω(α)对αi求导是：

然后，通过链式法则，对ci的求导是：

所以，权值ci最后的梯度是：

3.4、Making it Fast with MATLAB
CNN的训练主要是在卷积层和子采样层的交互上，其主要的计算瓶颈是：
1）前向传播过程：下采样每个卷积层的maps；
2）反向传播过程：上采样高层子采样层的灵敏度map，以匹配底层的卷积层输出maps的大小；
3）sigmoid的运用和求导。
对于第一和第二个问题，我们考虑的是如何用Matlab内置的图像处理函数去实现上采样和下采样的操作。对于上采样，imresize函数可以搞定，但需要很大的开销。一个比较快速的版本是使用Kronecker乘积函数kron。通过一个全一矩阵ones来和我们需要上采样的矩阵进行Kronecker乘积，就可以实现上采样的效果。对于前向传播过程中的下采样，imresize并没有提供在缩小图像的过程中还计算nxn块内像素的和的功能，所以没法用。一个比较好和快速的方法是用一个全一的卷积核来卷积图像，然后简单的通过标准的索引方法来采样最后卷积结果。例如，如果下采样的域是2x2的，那么我们可以用2x2的元素全是1的卷积核来卷积图像。然后再卷积后的图像中，我们每个2个点采集一次数据，y=x(1:2:end,1:2:end)，这样就可以得到了两倍下采样，同时执行求和的效果。
对于第三个问题，实际上有些人以为Matlab中对sigmoid函数进行inline的定义会更快，其实不然，Matlab与C/C++等等语言不一样，Matlab的inline反而比普通的函数定义更非时间。所以，我们可以直接在代码中使用计算sigmoid函数及其导数的真实代码。

《Notes on Convolutional Neural Networks》
一、介绍
这个文档讨论的是CNNs的推导和实现。CNN架构的连接比权值要多很多，这实际上就隐含着实现了某种形式的规则化。这种特别的网络假定了我们希望通过数据驱动的方式学习到一些滤波器，作为提取输入的特征的一种方法。
本文中，我们先对训练全连接网络的经典BP算法做一个描述，然后推导2D
CNN网络的卷积层和子采样层的BP权值更新方法。在推导过程中，我们更强调实现的效率，所以会给出一些Matlab代码。最后，我们转向讨论如何自动地学习组合前一层的特征maps，特别地，我们还学习特征maps的稀疏组合。

二、全连接的反向传播算法
典型的CNN中，开始几层都是卷积和下采样的交替，然后在最后一些层（靠近输出层的），都是全连接的一维网络。这时候我们已经将所有两维2D的特征maps转化为全连接的一维网络的输入。这样，当你准备好将最终的2D特征maps输入到1D网络中时，一个非常方便的方法就是把所有输出的特征maps连接成一个长的输入向量。然后我们回到BP算法的讨论。（更详细的基础推导可以参考UFLDL中“反向传导算法”）。
2.1、Feedforward Pass前向传播
在下面的推导中，我们采用平方误差代价函数。我们讨论的是多类问题，共c类，共N个训练样本。

这里表示第n个样本对应的标签的第k维。表示第n个样本对应的网络输出的第k个输出。对于多类问题，输出一般组织为“one-of-c”的形式，也就是只有该输入对应的类的输出节点输出为正，其他类的位或者节点为0或者负数，这个取决于你输出层的激活函数。sigmoid就是0，tanh就是-1.
因为在全部训练集上的误差只是每个训练样本的误差的总和，所以这里我们先考虑对于一个样本的BP。对于第n个样本的误差，表示为：

传统的全连接神经网络中，我们需要根据BP规则计算代价函数E关于网络每一个权值的偏导数。我们用l来表示当前层，那么当前层的输出可以表示为：

输出激活函数f(.)可以有很多种，一般是sigmoid函数或者双曲线正切函数。sigmoid将输出压缩到[0,
1]，所以最后的输出平均值一般趋于0 。所以如果将我们的训练数据归一化为零均值和方差为1，可以在梯度下降的过程中增加收敛性。对于归一化的数据集来说，双曲线正切函数也是不错的选择。

2.2、Backpropagation Pass反向传播
反向传播回来的误差可以看做是每个神经元的基的灵敏度sensitivities（灵敏度的意思就是我们的基b变化多少，误差会变化多少，也就是误差对基的变化率，也就是导数了），定义如下：（第二个等号是根据求导的链式法则得到的）

因为∂u/∂b=1，所以∂E/∂b=∂E/∂u=δ，也就是说bias基的灵敏度∂E/∂b=δ和误差E对一个节点全部输入u的导数∂E/∂u是相等的。这个导数就是让高层误差反向传播到底层的神来之笔。反向传播就是用下面这条关系式：（下面这条式子表达的就是第l层的灵敏度，就是）

公式（1）
这里的“◦”表示每个元素相乘。输出层的神经元的灵敏度是不一样的：

最后，对每个神经元运用delta（即δ）规则进行权值更新。具体来说就是，对一个给定的神经元，得到它的输入，然后用这个神经元的delta（即δ）来进行缩放。用向量的形式表述就是，对于第l层，误差对于该层每一个权值（组合为矩阵）的导数是该层的输入（等于上一层的输出）与该层的灵敏度（该层每个神经元的δ组合成一个向量的形式）的叉乘。然后得到的偏导数乘以一个负学习率就是该层的神经元的权值的更新了：

公式（2）
对于bias基的更新表达式差不多。实际上，对于每一个权值(W)ij都有一个特定的学习率ηIj。

三、Convolutional Neural Networks 卷积神经网络
3.1、Convolution Layers 卷积层
我们现在关注网络中卷积层的BP更新。在一个卷积层，上一层的特征maps被一个可学习的卷积核进行卷积，然后通过一个激活函数，就可以得到输出特征map。每一个输出map可能是组合卷积多个输入maps的值：

这里Mj表示选择的输入maps的集合，那么到底选择哪些输入maps呢？有选择一对的或者三个的。但下面我们会讨论如何去自动选择需要组合的特征maps。每一个输出map会给一个额外的偏置b，但是对于一个特定的输出map，卷积每个输入maps的卷积核是不一样的。也就是说，如果输出特征map
j和输出特征map k都是从输入map i中卷积求和得到，那么对应的卷积核是不一样的。
我们假定每个卷积层l都会接一个下采样层l+1 。对于BP来说，根据上文我们知道，要想求得层l的每个神经元对应的权值的权值更新，就需要先求层l的每一个神经节点的灵敏度δ（也就是权值更新的公式（2））。为了求这个灵敏度我们就需要先对下一层的节点（连接到当前层l的感兴趣节点的第l+1层的节点）的灵敏度求和（得到δl+1），然后乘以这些连接对应的权值（连接第l层感兴趣节点和第l+1层节点的权值）W。再乘以当前层l的该神经元节点的输入u的激活函数f的导数值（也就是那个灵敏度反向传播的公式（1）的δl的求解），这样就可以得到当前层l每个神经节点对应的灵敏度δl了。
然而，因为下采样的存在，采样层的一个像素（神经元节点）对应的灵敏度δ对应于卷积层（上一层）的输出map的一块像素（采样窗口大小）。因此，层l中的一个map的每个节点只与l+1层中相应map的一个节点连接。
为了有效计算层l的灵敏度，我们需要上采样upsample 这个下采样downsample层对应的灵敏度map（特征map中每个像素对应一个灵敏度，所以也组成一个map），这样才使得这个灵敏度map大小与卷积层的map大小一致，然后再将层l的map的激活值的偏导数与从第l+1层的上采样得到的灵敏度map逐元素相乘（也就是公式（1））。
在下采样层map的权值都取一个相同值β，而且是一个常数。所以我们只需要将上一个步骤得到的结果乘以一个β就可以完成第l层灵敏度δ的计算。
我们可以对卷积层中每一个特征map j重复相同的计算过程。但很明显需要匹配相应的子采样层的map（参考公式（1））：

up(.)表示一个上采样操作。如果下采样的采样因子是n的话，它简单的将每个像素水平和垂直方向上拷贝n次。这样就可以恢复原来的大小了。实际上，这个函数可以用Kronecker乘积来实现：

好，到这里，对于一个给定的map，我们就可以计算得到其灵敏度map了。然后我们就可以通过简单的对层l中的灵敏度map中所有节点进行求和快速的计算bias基的梯度了：

公式（3）
最后，对卷积核的权值的梯度就可以用BP算法来计算了（公式（2））。另外，很多连接的权值是共享的，因此，对于一个给定的权值，我们需要对所有与该权值有联系（权值共享的连接）的连接对该点求梯度，然后对这些梯度进行求和，就像上面对bias基的梯度计算一样：

这里，是中的在卷积的时候与逐元素相乘的patch，输出卷积map的(u,
v)位置的值是由上一层的(u, v)位置的patch与卷积核k_ij逐元素相乘的结果。
咋一看，好像我们需要煞费苦心地记住输出map（和对应的灵敏度map）每个像素对应于输入map的哪个patch。但实际上，在Matlab中，可以通过一个代码就实现。对于上面的公式，可以用Matlab的卷积函数来实现：

我们先对delta灵敏度map进行旋转，这样就可以进行互相关计算，而不是卷积（在卷积的数学定义中，特征矩阵（卷积核）在传递给conv2时需要先翻转（flipped）一下。也就是颠倒下特征矩阵的行和列）。然后把输出反旋转回来，这样我们在前向传播进行卷积的时候，卷积核才是我们想要的方向。

3.2、Sub-sampling Layers 子采样层
对于子采样层来说，有N个输入maps，就有N个输出maps，只是每个输出map都变小了。

down(.)表示一个下采样函数。典型的操作一般是对输入图像的不同nxn的块的所有像素进行求和。这样输出图像在两个维度上都缩小了n倍。每个输出map都对应一个属于自己的乘性偏置β和一个加性偏置b。

这里最困难的是计算灵敏度map。一旦我们得到这个了，那我们唯一需要更新的偏置参数β和b就可以轻而易举了（公式（3））。如果下一个卷积层与这个子采样层是全连接的，那么就可以通过BP来计算子采样层的灵敏度maps。
我们需要计算卷积核的梯度，所以我们必须找到输入map中哪个patch对应输出map的哪个像素。这里，就是必须找到当前层的灵敏度map中哪个patch对应与下一层的灵敏度map的给定像素，这样才可以利用公式（1）那样的δ递推，也就是灵敏度反向传播回来。另外，需要乘以输入patch与输出像素之间连接的权值，这个权值实际上就是卷积核的权值（已旋转的）。

在这之前，我们需要先将核旋转一下，让卷积函数可以实施互相关计算。另外，我们需要对卷积边界进行处理，但在Matlab里面，就比较容易处理。Matlab中全卷积会对缺少的输入像素补0 。
到这里，我们就可以对b和β计算梯度了。首先，加性基b的计算和上面卷积层的一样，对灵敏度map中所有元素加起来就可以了：

而对于乘性偏置β，因为涉及到了在前向传播过程中下采样map的计算，所以我们最好在前向的过程中保存好这些maps，这样在反向的计算中就不用重新计算了。我们定义：

这样，对β的梯度就可以用下面的方式计算：

3.3、Learning Combinations of Feature Maps 学习特征map的组合
大部分时候，通过卷积多个输入maps，然后再对这些卷积值求和得到一个输出map，这样的效果往往是比较好的。在一些文献中，一般是人工选择哪些输入maps去组合得到一个输出map。但我们这里尝试去让CNN在训练的过程中学习这些组合，也就是让网络自己学习挑选哪些输入maps来计算得到输出map才是最好的。我们用αij表示在得到第j个输出map的其中第i个输入map的权值或者贡献。这样，第j个输出map可以表示为：

需要满足约束：

这些对变量αij的约束可以通过将变量αij表示为一个组无约束的隐含权值cij的softmax函数来加强。（因为softmax的因变量是自变量的指数函数，他们的变化率会不同）。

因为对于一个固定的j来说，每组权值cij都是和其他组的权值独立的，所以为了方面描述，我们把下标j去掉，只考虑一个map的更新，其他map的更新是一样的过程，只是map的索引j不同而已。
Softmax函数的导数表示为：

这里的δ是Kronecker delta。对于误差对于第l层变量αi的导数为：

最后就可以通过链式规则去求得代价函数关于权值ci的偏导数了：

3.3.1、Enforcing Sparse Combinations 加强稀疏性组合
为了限制αi是稀疏的，也就是限制一个输出map只与某些而不是全部的输入maps相连。我们在整体代价函数里增加稀疏约束项Ω(α)。对于单个样本，重写代价函数为：

然后寻找这个规则化约束项对权值ci求导的贡献。规则化项Ω(α)对αi求导是：

然后，通过链式法则，对ci的求导是：

所以，权值ci最后的梯度是：

3.4、Making it Fast with MATLAB
CNN的训练主要是在卷积层和子采样层的交互上，其主要的计算瓶颈是：
1）前向传播过程：下采样每个卷积层的maps；
2）反向传播过程：上采样高层子采样层的灵敏度map，以匹配底层的卷积层输出maps的大小；
3）sigmoid的运用和求导。
对于第一和第二个问题，我们考虑的是如何用Matlab内置的图像处理函数去实现上采样和下采样的操作。对于上采样，imresize函数可以搞定，但需要很大的开销。一个比较快速的版本是使用Kronecker乘积函数kron。通过一个全一矩阵ones来和我们需要上采样的矩阵进行Kronecker乘积，就可以实现上采样的效果。对于前向传播过程中的下采样，imresize并没有提供在缩小图像的过程中还计算nxn块内像素的和的功能，所以没法用。一个比较好和快速的方法是用一个全一的卷积核来卷积图像，然后简单的通过标准的索引方法来采样最后卷积结果。例如，如果下采样的域是2x2的，那么我们可以用2x2的元素全是1的卷积核来卷积图像。然后再卷积后的图像中，我们每个2个点采集一次数据，y=x(1:2:end,1:2:end)，这样就可以得到了两倍下采样，同时执行求和的效果。
对于第三个问题，实际上有些人以为Matlab中对sigmoid函数进行inline的定义会更快，其实不然，Matlab与C/C++等等语言不一样，Matlab的inline反而比普通的函数定义更非时间。所以，我们可以直接在代码中使用计算sigmoid函数及其导数的真实代码。


展开全文
• 本文转自：机器学习算法那些事阅读本文之前，可以先阅读之前讲述的全连接层的反向传播算法详细推导过程，已经了解反向传播算法的请自动忽略。1. 卷积层的反向传播废话不说，直接上图：假设输入为一张...


本文转自：机器学习算法那些事阅读本文之前，可以先阅读之前讲述的全连接层的反向传播算法详细推导过程，已经了解反向传播算法的请自动忽略。1. 卷积层的反向传播废话不说，直接上图：假设输入为一张单通道图像  ，卷积核大小为  ，输出为  。为了加速计算，首先将 按卷积核滑动顺序依次展开，如上图所示。其中，  中的红色框代表  中的红色框展开后的结果，将  依次按照此方式展开，可得  。同理可得  ，然后通过矩阵相乘可得输出  （与  等价）。此时，已经将CNN转化为FC，与反向传播算法完全一致，这里不再做详细介绍。当有 N 个样本，做一个batch训练,即channel=N时，前向与反向传播方式如下图所示：其中，输入图像channel=3,使用2个  的卷积核，输出两张图像，如图所示。红色框、黄色框代表的是卷积核以及使用该卷积核得到的输出图像  。当输入图像为一个batch时，  的转化方式如上图，首先将输入图像与卷积核分别按单通道图像展开，然后将展开后的矩阵在行方向级联。此时，已经将CNN转化为了FC，与反向传播算法完全一致，这里不再做详细介绍。2. Average pooling的反向传播 不用求，因为  为常数。 3. Max-pooling的反向传播遍历  的每一行，找出此行最大值的索引  ，然后将  中索引为  的值设为  对应行的值，将此行其余列的值设为  ，如上图所示红框所示。假设  中(1,1)处的值是第一行中最大的值，则将  赋值给  中索引为  的位置。最后计算:  。

展开全文
• 反向传播算法是人工神经网络训练时采用的一种通用方法，在现代深度学习中得到了大 规模的应用。全连接神经网络(多层感知器模型，MLP)，卷积神经网络(CNN)，循环神 经网络(RNN)中都有它的实现版本。算法从多元复合...
• ## CNN反向传播推导

千次阅读 2018-03-23 18:23:31
做CS231n作业碰到要实现CNN，在反向传播部分卡住，找了...参考：Convolutional Neural Networks backpropagation:from intuition to derivation CNN反向传播算法 主要借鉴了这一篇博客，再拜，主要在此为基础上做...
• 反向传播算法是人工神经网络训练时采用的一种通用方法，在现代深度学习中得到了大规模的应用。全连接神经网络（多层感知器模型，MLP），卷积神经网络（CNN），循环神经网络（RNN）中都有它的实现版本。算法从多元...
• 点击上方“小白学视觉”，选择加"星标"或“置顶”重磅干货，第一时间送达 本文转自：机器学习算法那些事阅读本文之前，可以先阅读之前讲述的全连接层的反向传播算法详细推导过程，...
• 在看本篇博文之前，你需要对卷积神经网络有一定的理解，并且能够自主推导出经典BP神经网络反向传播的相关公式。
• BP网络的反向传播CNN/DCNN的基础，只要明白了BP反向传播原理以及推导过程CNN便迎刃而解。因为BP网络的递推特点使得根据损失函数来推导权重W比较繁琐，很多博客都进行了详细推理。有的推导比较抽象但逻辑清晰、有的...
• 1 回顾DNN的反向传播算法 2 CNN的反向传播算法思想 3. 已知池化层的δl\delta_{l}δl​，推导上一隐藏层的δl−1\delta_{l-1}δl−1​ 4. 已知卷积层的δl\delta^lδl，推导上一...6 CNN反向传播算法总结 ...
• 本文主要是通过阅读相关论文和一些辅助的博文来理解卷积神经网络里面的反向传播算法；相关的论文可以查看Notes on Convolutional Neural Networks, Jake Bouvrie 准备工作 首先呢，我们还是先回顾下在深度学习...
• 实际上就是一个：梯度下降反向传播更新 如果熟知高数和懂最优化的梯度下降理论，可以直接跳到 四 一、反向传播的由来 在我们开始DL的研究之前，需要把ANN—人工神经元网络以及bp算法做一个简单解释。 输入层...
• 卷积神经网络前向传播与反向传播算法 公式推导1、前向传播1.1卷积层前向传播1.2池化层前向传播1.3全连接层前向传播2、损失函数3、反向传播已知池化层δl\delta^lδl,推导上一层的δl−1\delta^{l-1}δl−1已知卷积层...
• DNN反向传播算法 CNN反向传播算法 DNN和CNN反向传播总结
• 最近学习CNN时，对反向传播算法模棱两可，公式经常是提起笔就忘记，而且网上的推导看着就烦。于是趁着现在明白了，赶紧写篇博文，留作日后参考。
• 要套用DNN的反向传播算法CNN，有几个问题需要解决： 池化层没有激活函数，我们可以令池化层的激活函数为 g(z)=zg(z) = zg(z)=z，即激活后输出本身，激活函数的导数为1。 池化层在前向传播的时候，对输入矩阵进行...
• 最近在对卷积神经网络（CNN）进行学习的过程中，发现自己之前对反向传播算法的理解不够透彻，所以今天专门写篇博客记录一下反向传播算法推导过程，算是一份备忘录吧，有需要的朋友也可以看一下这篇文章，写的挺...
• 最近在对卷积神经网络（CNN）进行学习的过程中，发现自己之前对反向传播算法的理解不够透彻，所以今天专门写篇博客记录一下反向传播算法推导过程，算是一份备忘录吧，有需要的朋友也可以看一下这篇文章，写的挺...
• 最近在对卷积神经网络（CNN）进行学习的过程中，发现自己之前对反向传播算法的理解不够透彻，所以今天专门写篇博客记录一下反向传播算法推导过程，算是一份备忘录吧，有需要的朋友也可以看一下这篇文章，写的挺...
• 前面已经推导学习了卷积神经网络之前向传播算法，本篇文章将推导卷积神经网络之反向传播算法。在学习卷积神经网络算法之前，希望你对深度神经网络有一定程度的了解，我在之前也有写过相关的文章，包括深度神经网络...
• CNN反向传播求导时的具体过程可以参考论文Notes on Convolutional Neural Networks, Jake Bouvrie，该论文讲得很全面，比如它考虑了pooling层也加入了权值、偏置值及非线性激发(因为这2种值也需要learn)，对该...
• 裂墙推荐这个篇博客神经网络BP反向传播算法原理和详细推导流程，保证博到病除。 CNN 中的卷积操作则不再是全连接的形式，因此 CNN 的 BP 算法需要在原始的算法上稍作修改。这篇文章主要讲一下 BP 算法在卷积层和 ...
• 前面五小节，我们简单学习了卷积神经网络（CNN反向传播算法推导，然后我们自己实现了一个浅层卷积神经网络。卷积神经网络在本系列中先告一段落，我们开始学习循环神经网络的相关知识。本系列的主旨是基础学习，...
• 而本文的主要目的是介绍CNN参数在使用bp算法时该怎么训练，毕竟CNN中有卷积层和下采样层，虽然和MLP的bp算法本质上相同，但形式上还是有些区别的，很显然在完成CNN反向传播前了解bp算法是必须的。
• 反向传播算法是神经网络中用来学习的算法，从网络的输出一直往输出方向计算梯度来更新网络参数，达到学习的目的，而因为其传播方向与网络的推理方向相反，因此成为反向传播。神经网络有很多种，那么它们还有其中包含...