![0da2ea17e935291e5ace541818959a87.gif](https://i-blog.csdnimg.cn/blog_migrate/a4b3eea01242d8d1f85bf9fd9fda182e.gif)
![a6905e0ca19ee3ebaedf223a48db8e9d.png](https://i-blog.csdnimg.cn/blog_migrate/c9a7df846d651fe3672fa0f512d5214f.png)
CNN网络基础结构
![36fbabd135914d22402b88f366c186ae.png](https://i-blog.csdnimg.cn/blog_migrate/61b7508ab113c62743fecc3e29a26850.png)
神经网络-全连接层(3)
上一回我们聊完了算法,这回我们正式开始写代码。上回在做公式推导的时候,我们实际上只是针对一个数据样本进行推导,而实际中,计算和训练都是一批一批完成的。大多数机器学习训练都有batch的概念,而训练中batch的计算不是一个一个地算,而是一批数据集中算,那么就需要用上矩阵了。
首先给出Loss的代码,这里y和t都是按列存储的,每一列都是一个样本:
class SquareLoss:
def forward(self, y, t):
self.loss = y - t
return np.sum(self.loss * self.loss) / self.loss.shape[1] / 2
def backward(self):
return self.loss
为了代码的简洁,我们在前向运算的时候就把一些后向计算的信息都保存起来,这样在后向计算的时候就能简单点。这样这个类就不能具备多线程的特性了,不过想支持多线程的功能还有别的办法。后面的全连接层也会采用同样的思路——前向为后向准备运算数据。
上一节我们讲了1个例子,输入有2个元素,第一层有4个输出,第2层有1个输出。我们假设训练数据有N个,我们对所有相关的训练数据和参数做以下的约定:
所有的训练数据按列存储,也就是说如果把N个数据组成一个矩阵,那个矩阵的行等于数据特征的数目,矩阵的列等于N
线性部分的权值w由一个矩阵构成,它的行数为该层的输入个数,列数为该层的输出个数。如果该层的输入为2,输出为4,那么这个权值w的矩阵就是一个2*4的矩阵。
线性部分的权值b是一个行数等于输出个数,列数为1的矩阵。
基于上面的规则,我们把上一节的例子以批量数据的形式画成了下面一张图:
![bd9e5635b6b66d1dee94bd63c1803cba.png](https://i-blog.csdnimg.cn/blog_migrate/48a0e00404994eeae73db3f7b9140590.jpeg)
这张图从左往右有三个部分:
最左边是神经网络的结构图,可以看出里面的数据x,z和参数w,b都符合我们刚才对数据组织的定义。
中间是神经网络前向的过程。一共分为5步,其中最后一步用来计算Loss。
最右边是神经网络反向的过程。这里需要仔细看一下。为了表达上的简洁,我们用残差符号表达Loss对指定变量的偏导数。同时为了更加简洁地表达梯度计算的过程,在这个过程中我们