[深度学习-1.4] 构建深层神经网络并实现MNIST手写数字识别

许多情况下浅层神经网络(包括之前的逻辑回归单隐层神经网络)效果可能并不理想,这就是为什么要用深层神经网络的原因。

  前面Logistic回归和单隐层神经网络都是解决二分类问题,学习完深层神经网络之后我想尝试一下解决复杂一点的问题,因此选择了MNIST数据集的识别。

深层网络模型以及符号约定

下面以一个五层神经网络为例,先简单介绍一下网络模型以及对参数符号做一些约定。

  图中输入层定义为L0,从第一个隐藏层开始标记为L1,一直到输出层L5,定义为一个五层的神经网络。所以,其实前面的Logistic回归就可以看作一个一层神经网络,单隐层神经网络就是一个两层的神经网络。

  • 符号约定
符号意义备注
L L L网络的总层数-
n [ l ] n^{[l]} n[l] l l l 层的节点(神经元)数 0 ≤ l ≤ L 0\leq l \leq L 0lL
W [ l ] \bold{W}^{[l]} W[l] l − 1 l-1 l1 层到 l l l 层连接的权重矩阵 W [ l ] ⊆ R n [ l ] × n [ l − 1 ] \bold{W}^{[l]}\subseteq \bold{R}^{n^{[l]}\times{n^{[l-1]}}} W[l]Rn[l]×n[l1]
b [ l ] \bold{b}^{[l]} b[l] l l l 层的阈值 b [ l ] ⊆ R n [ l ] × 1 \bold{b}^{[l]}\subseteq \bold{R}^{n^{[l]}\times1} b[l]Rn[l]×1
Z [ l ] \bold{Z}^{[l]} Z[l] Z [ l ] = W [ l ] A [ l − 1 ] + b [ l ] \bold{Z}^{[l]}=\bold{W}^{[l]}\bold{A}^{[l-1]}+\bold{b}^{[l]} Z[l]=W[l]A[l1]+b[l] Z [ l ] ⊆ R n [ l ] × 1 \bold{Z}^{[l]}\subseteq \bold{R}^{n^{[l]}\times1} Z[l]Rn[l]×1
A [ l ] \bold{A}^{[l]} A[l] l l l 层的激活值(第 l l l 层的输出), A [ l ] = g [ l ] ( Z [ l ] ) \bold{A}^{[l]}=g^{[l]}(\bold{Z}^{[l]}) A[l]=g[l](Z[l]) A [ l ] ⊆ R n [ l ] × 1 \bold{A}^{[l]}\subseteq \bold{R}^{n^{[l]}\times1} A[l]Rn[l]×1
g [ l ] ( ⋅ ) g^{[l]}(·) g[l]() l l l 层的激活函数-

  以上图为例, n [ 0 ] = 2 n^{[0]}=2 n[0]=2 n [ 2 ] = 5 n^{[2]}=5 n[2]=5 W [ 2 ] ⊆ R 5 × 3 \bold{W}^{[2]}\subseteq \bold{R}^{5\times3} W[2]R5×3 b [ 3 ] ⊆ R 4 × 1 \bold{b}^{[3]}\subseteq \bold{R}^{4\times1} b[3]R4×1。此外输入可以看作 A [ 0 ] \bold{A}^{[0]} A[0],即 A [ 0 ] = X \bold{A}^{[0]}=\bold{X} A[0]=X。此外需要注意的是,上面只考虑了单个样本输入的情况,对于 m m m 个样本输入的情况, Z [ l ] ⊆ R n [ l ] × m \bold{Z}^{[l]}\subseteq \bold{R}^{n^{[l]}\times{m}} Z[l]Rn[l]×m A [ l ] ⊆ R n [ l ] × m \bold{A}^{[l]}\subseteq \bold{R}^{n^{[l]}\times{m}} A[l]Rn[l]×m,后面会具体讲到。

MNIST数据集

MISIST数据集是一个手写数字图片数据集,可以在 http://yann.lecun.com/exdb/mnist/ 免费获取。数据包含了四部分:

  • train-images.idx3-ubyte : 60000个训练样本
  • train-labels.idx1-ubyte : 60000个训练样本的标签
  • t10k-images.idx3-ubyte : 10000个测试样本
  • t10k-labels.idx1-ubyte : 10000个测试样本的标签

  样本及其标签都是用字节方式存储的。每个样本是一张28*28像素的图片,标签为图片所表示的手写数字的值(0-9)。在编程实现的时候,将每个样本图片读取为长度784(28*28)的向量,这样,训练集样本被表示为784*60000的矩阵,测试集样本被表示为784*10000的矩阵。
  在二分类问题中输出层只用一个神经元就可以,因为通过sigmoid函数输出的值就可以直接确定输入样本属于类别1( y ^ > 0.5 \hat{y}>0.5 y^>0.5)还是属于类别0( y ^ ≤ 0.5 \hat{y}\leq0.5 y^0.5)。但是对于MNIST数据识别,共有十类标签,显然输出层用一个神经元已经不合适了(或许依旧是可行的)。因此,输出层用十个神经元来表示,每个神经元的输出表示判定为此类的概率,这样概率最大的即为预测的标签值。
  网络输出层结构确定之后,别忘了训练标签也要做相应处理。直接从文件读取到的值为图片对应的数字的值,为了和网络输出层结构匹配,需要将每个标签转化为一个10*1的向量,真实值对应的位置为1,其他位置为0。例如,标签“5”对应的向量应为 [ 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 ] T [0,0,0,0,0,1,0,0,0,0]^T [0,0,0,0,0,1,0,0,0,0]T。这样训练集标签就被表示为10*60000的矩阵,测试集标签就被表示为10*10000的矩阵。
  总结一下就是,在进行MNIST数据识别时, A [ 0 ] = X ⊆ R n [ 0 ] × m \bold{A}^{[0]}=\bold{X}\subseteq \bold{R}^{n^{[0]}\times{m}} A[0]=XRn[0]×m A [ l ] ⊆ R n [ l ] × m \bold{A}^{[l]}\subseteq \bold{R}^{n^{[l]}\times{m}} A[l]Rn[l]×m A [ L ] = X ⊆ R n [ L ] × m \bold{A}^{[L]}=\bold{X}\subseteq \bold{R}^{n^{[L]}\times{m}} A[L]=XRn[L]×m,其中 n [ 0 ] = 784 n^{[0]}=784 n[0]=784 n [ L ] = 10 n^{[L]}=10 n[L]=10 m = 60000 m=60000 m=60000(训练集)或 m = 10000 m=10000 m=10000(测试集)。

  关于MINIST的更详细介绍以及数据读取等可以看详解MNIST数据集这篇文章,我觉得博主大佬讲的超级详细!

构建和训练用于手写数字识别的深层神经网络

与Logistic回归和单隐层神经网络类似,训练一个深层神经网络也可以归纳为以下几个步骤:

  1. 前向传播:根据输入样本计算预测值;
  2. 计算损失函数;
  3. 反向传播:反向逐层计算梯度值( d W d\bold{W} dW d b d\bold{b} db);
  4. 利用梯度信息更新权重和阈值。
  5. 重复步骤1-5,直到停止条件满足(可以认为停止条件就是达到最大迭代次数)。

下面逐步进行解释及推导。

  • 前向传播
      前向传播就是根据样本的输入特征计算对应的输出,称这个输出为“预测值”。训练网络的目的就是使这个预测值尽可能和对应的真实值一致。前向传播的过程简单来说就是 X → A [ 1 ] → A [ 2 ] → ⋅ ⋅ ⋅ → A [ L ] \bold{X}\rightarrow\bold{A}^{[1]}\rightarrow\bold{A}^{[2]}\rightarrow···\rightarrow\bold{A}^{[L]} XA[1]A[2]A[L]  事实上,如果隐藏层的激活函数采用sigmoid函数,那么深层神经网络前向传播的过程只不过是Logistic回归的过程重复计算了 L L L 次而已,也就是重复以下过程:
    (1) Z [ l ] = W [ l ] A [ l − 1 ] + b [ l ] \bold{Z}^{[l]}=\bold{W}^{[l]}\bold{A}^{[l-1]}+\bold{b}^{[l]}\tag1 Z[l]=W[l]A[l1]+b[l](1) (2) A [ l ] = g [ l ] ( Z [ l ] ) \bold{A}^{[l]}=g^{[l]}(\bold{Z}^{[l]})\tag2 A[l]=g[l](Z[l])(2)但实际实现时,激活函数全部使用sigmoid并不是个很好的选择,建议除了输出层使用sigmoid函数之外,其余层均使用ReLU函数作为激活函数。

  • 计算损失函数
      损失函数仍旧使用交叉熵损失函数,不同于之前的二分类网络,用于MNIST数据识别的网络输出层有十个神经元,计算损失函数的时候和前面稍微有点不同。首先考虑单个样本和单个输出神经元,损失值为
    (3) L 0 = − ( y j ( i ) log ⁡ ( a j [ L ] ( i ) ) + ( 1 − y j ( i ) ) log ⁡ ( 1 − a j [ L ] ( i ) ) ) L_0=- (y_j^{(i)}\log(a_j^{[L] (i)}) + (1-y_j^{(i)})\log(1- a_j^{[L](i)})) \tag{3} L0=(yj(i)log(aj[L](i))+(1yj(i))log(1aj[L](i)))(3)其中 y j ( i ) y_j^{(i)} yj(i) 表示第 i i i 个样本的第 j j j 个标签值(即前面将标签转化为向量后的向量第 j j j 个值), a j [ L ] ( i ) a_j^{[L](i)} aj[L](i)表示对应样本在输出层第 j j j 个神经元得到的输出值。
      那么单个样本考虑所有的输出层神经元,损失值就是
    (4) L = − ∑ j = 1 n [ L ] ( y j ( i ) log ⁡ ( a j [ L ] ( i ) ) + ( 1 − y j ( i ) ) log ⁡ ( 1 − a j [ L ] ( i ) ) ) L=-\sum_{j=1}^{n^{[L]}} (y_j^{(i)}\log(a_j^{[L] (i)}) + (1-y_j^{(i)})\log(1- a_j^{[L](i)})) \tag{4} L=j=1n[L](yj(i)log(aj[L](i))+(1yj(i))log(1aj[L](i)))(4)进而考虑所有 m m m 个样本,得到总的损失值为
    (5) J = − 1 m ∑ i = 1 m ∑ j = 1 n [ L ] ( y j ( i ) log ⁡ ( a j [ L ] ( i ) ) + ( 1 − y j ( i ) ) log ⁡ ( 1 − a j [ L ] ( i ) ) ) J=-\frac1m\sum_{i=1}^{m}\sum_{j=1}^{n^{[L]}} (y_j^{(i)}\log(a_j^{[L] (i)}) + (1-y_j^{(i)})\log(1- a_j^{[L](i)})) \tag{5} J=m1i=1mj=1n[L](yj(i)log(aj[L](i))+(1yj(i))log(1aj[L](i)))(5)用矩阵的形式就可以表示为
    (6) J = − 1 m ∑ i , j ( Y ∗ log ⁡ ( A [ L ] ) + ( 1 − Y ) ∗ ( 1 − log ⁡ ( A [ L ] ) ) J=-\frac1m\sum_{i,j} (\bold{Y}*\log(\bold{A}^{[L]})+(1-\bold{Y})*(1-\log(\bold{A}^{[L]}))\tag{6} J=m1i,j(Ylog(A[L])+(1Y)(1log(A[L]))(6)其中 ∗ * 表示矩阵的数乘运算(两个矩阵对应元素相乘),能进行这个运算的前提是 Y \bold{Y} Y A [ L ] \bold{A}^{[L]} A[L]同型矩阵,上面已经讨论过 A [ L ] ⊆ R n [ L ] × m \bold{A}^{[L]}\subseteq \bold{R}^{n^{[L]}\times{m}} A[L]Rn[L]×m Y ⊆ R n [ L ] × m \bold{Y}\subseteq \bold{R}^{n^{[L]}\times{m}} YRn[L]×m,所以这里是没毛病的。

  • 反向传播
      损失函数实际上就是一个对当前网络的好坏的评价,在得到这个“评价指标”后,接下来需要做的就是计算损失函数的梯度并逐层反向传播,用于接下来进行阈值和权重的更新。如果高数里面求导的链式法则还记得的话,其实求导的过程也不是非常难。
    下面以网络后两层为例来进行推导(看着头晕的话可以直接跳过这部分推导直接看后面的果部分,式15-18)
    (7) d A [ L ] = ∂ J ∂ A [ L ] = ( 1 − Y ) ( 1 − A [ L ] ) − Y A [ L ] d\bold{A}^{[L]}=\frac{\partial J}{\partial \bold{A}^{[L]}}=\frac{(1-\bold{Y})} {(1-\bold{A}^{[L]})}-\frac{\bold{Y}} {\bold{A}^{[L]}}\tag{7} dA[L]=A[L]J=(1A[L])(1Y)A[L]Y(7) (8) d Z [ L ] = ∂ J ∂ Z [ L ] = ∂ J ∂ A [ L ] ⋅ ∂ A [ L ] ∂ Z [ L ] = d A [ L ] ∗ g [ L ] ′ ( Z [ L ] ) d\bold{Z}^{[L]}=\frac{\partial J}{\partial \bold{Z}^{[L]}}=\frac{\partial J}{\partial \bold{A}^{[L]}}·\frac{\partial \bold{A}^{[L]}}{\partial \bold{Z}^{[L]}}=d\bold{A}^{[L]}*g^{[L]'}(\bold{Z}^{[L]})\tag{8} dZ[L]=Z[L]J=A[L]JZ[L]A[L]=dA[L]g[L](Z[L])(8) (9) d W [ L ] = ∂ J ∂ W [ L ] = ∂ J ∂ A [ L ] ⋅ ∂ A [ L ] ∂ Z [ L ] ⋅ ∂ Z [ L ] ∂ W [ L ] = 1 m d Z [ L ] ( A [ L − 1 ] ) T d\bold{W}^{[L]}=\frac{\partial J}{\partial \bold{W}^{[L]}}=\frac{\partial J}{\partial \bold{A}^{[L]}}·\frac{\partial \bold{A}^{[L]}}{\partial \bold{Z}^{[L]}}·\frac{\partial \bold{Z}^{[L]}}{\partial \bold{W}^{[L]}}=\frac1md\bold{Z}^{[L]}(\bold{A}^{[L-1]})^T\tag{9} dW[L]=W[L]J=A[L]JZ[L]A[L]W[L]Z[L]=m1dZ[L](A[L1])T(9) (10) d b [ L ] = ∂ J ∂ b [ L ] = ∂ J ∂ A [ L ] ⋅ ∂ A [ L ] ∂ Z [ L ] ⋅ ∂ Z [ L ] ∂ b [ L ] = 1 m ∑ i = 1 m d Z [ L ] d\bold{b}^{[L]}=\frac{\partial J}{\partial \bold{b}^{[L]}}=\frac{\partial J}{\partial \bold{A}^{[L]}}·\frac{\partial \bold{A}^{[L]}}{\partial \bold{Z}^{[L]}}·\frac{\partial \bold{Z}^{[L]}}{\partial \bold{b}^{[L]}}=\frac1m\sum_{i=1}^{m}d\bold{Z}^{[L]}\tag{10} db[L]=b[L]J=A[L]JZ[L]A[L]b[L]Z[L]=m1i=1mdZ[L](10) (11) d A [ L − 1 ] = ∂ J ∂ A [ L − 1 ] = ∂ J ∂ Z [ L ] ⋅ ∂ Z [ L ] ∂ A [ L − 1 ] = ( W [ L ] ) T d Z [ L ] d\bold{A}^{[L-1]}=\frac{\partial J}{\partial \bold{A}^{[L-1]}}=\frac{\partial J}{\partial \bold{Z}^{[L]}}·\frac{\partial \bold{Z}^{[L]}}{\partial \bold{A}^{[L-1]}}=(\bold{W}^{[L]})^Td\bold{Z}^{[L]}\tag{11} dA[L1]=A[L1]J=Z[L]JA[L1]Z[L]=(W[L])TdZ[L](11) (12) d Z [ L − 1 ] = ∂ J ∂ Z [ L − 1 ] = ∂ J ∂ A [ L − 1 ] ⋅ ∂ A [ L − 1 ] ∂ Z [ L − 1 ] = d A [ L − 1 ] ∗ g [ L − 1 ] ′ ( Z [ L − 1 ] ) d\bold{Z}^{[L-1]}=\frac{\partial J}{\partial \bold{Z}^{[L-1]}}=\frac{\partial J}{\partial \bold{A}^{[L-1]}}·\frac{\partial \bold{A}^{[L-1]}}{\partial \bold{Z}^{[L-1]}}=d\bold{A}^{[L-1]}*g^{[L-1]'}(\bold{Z}^{[L-1]})\tag{12} dZ[L1]=Z[L1]J=A[L1]JZ[L1]A[L1]=dA[L1]g[L1](Z[L1])(12) (13) d W [ L − 1 ] = ∂ J ∂ W [ L − 1 ] = ∂ J ∂ Z [ L − 1 ] ⋅ ∂ Z [ L − 1 ] ∂ W [ L − 1 ] = 1 m d Z [ L − 1 ] ( A [ L − 2 ] ) T d\bold{W}^{[L-1]}=\frac{\partial J}{\partial \bold{W}^{[L-1]}}=\frac{\partial J}{\partial \bold{Z}^{[L-1]}}·\frac{\partial \bold{Z}^{[L-1]}}{\partial \bold{W}^{[L-1]}}=\frac1md\bold{Z}^{[L-1]}(\bold{A}^{[L-2]})^T\tag{13} dW[L1]=W[L1]J=Z[L1]JW[L1]Z[L1]=m1dZ[L1](A[L2])T(13) (14) d b [ L − 1 ] = ∂ J ∂ b [ L − 1 ] = ∂ J ∂ Z [ L − 1 ] ⋅ ∂ Z [ L − 1 ] ∂ b [ L − 1 ] = 1 m ∑ i = 1 m d Z [ L − 1 ] d\bold{b}^{[L-1]}=\frac{\partial J}{\partial \bold{b}^{[L-1]}}=\frac{\partial J}{\partial \bold{Z}^{[L-1]}}·\frac{\partial \bold{Z}^{[L-1]}}{\partial \bold{b}^{[L-1]}}=\frac1m\sum_{i=1}^{m}d\bold{Z}^{[L-1]}\tag{14} db[L1]=b[L1]J=Z[L1]Jb[L1]Z[L1]=m1i=1mdZ[L1](14)其中 g [ L ] ′ ( ⋅ ) g^{[L]'}(·) g[L]() 表示第 L L L 层激活函数的导函数。这样通过推导后两层其实很容易就可以发现规律。直接说结果吧
    (15) d Z [ l ] = d A [ l ] ∗ g [ l ] ′ ( Z [ l ] ) d\bold{Z}^{[l]}=d\bold{A}^{[l]}*g^{[l]'}(\bold{Z}^{[l]})\tag{15} dZ[l]=dA[l]g[l](Z[l])(15) (16) d W [ l ] = 1 m d Z [ l ] ( A [ l − 1 ] ) T d\bold{W}^{[l]}=\frac1md\bold{Z}^{[l]}(\bold{A}^{[l-1]})^T\tag{16} dW[l]=m1dZ[l](A[l1])T(16) (17) d b [ l ] = 1 m ∑ i = 1 m d Z [ l ] d\bold{b}^{[l]}=\frac1m\sum_{i=1}^{m}d\bold{Z}^{[l]}\tag{17} db[l]=m1i=1mdZ[l](17) (18) d A [ l − 1 ] = ( W [ l ] ) T d Z [ l ] d\bold{A}^{[l-1]}=(\bold{W}^{[l]})^Td\bold{Z}^{[l]}\tag{18} dA[l1]=(W[l])TdZ[l](18)
    总结一下反向传播的过程就是以下这个过程,每一步按照上面推导的结果进行计算就可以了,通过这种一层一层的反向计算我们就得到了每一层的 d W d\bold{W} dW d b d\bold{b} db,进而进行参数更新。到这里,最难推导和理解的部分就结束了,松一口气哈哈哈。

  • 更新权重和阈值
      得到了梯度信息之后,剩下就自然而然是更新 W \bold{W} W b \bold{b} b 了,这里没有什么需要理解的。当学习率 α \alpha α 确定了之后,权重和阈值按照以下方式进行更新
    (19) W [ l ] = W [ l ] − α ⋅ d W [ l ] \bold{W}^{[l]}=\bold{W}^{[l]}-\alpha·d\bold{W}^{[l]}\tag{19} W[l]=W[l]αdW[l](19) (20) b [ l ] = b [ l ] − α ⋅ d b [ l ] \bold{b}^{[l]}=\bold{b}^{[l]}-\alpha·d\bold{b}^{[l]}\tag{20} b[l]=b[l]αdb[l](20)

  到此,一个深度神经网络的前向传播、计算损失函数、反向传播和参数更新的整个过程就完了,训练过程就是在设定的训练条件内,不断地重复这几个过程以不断降低损失函数值,最终得到一个比较好的分类器。

程序和结果

Python程序已经上传到GitHub了。实现过程中发现了一个问题,层数的变化对结果影响不是很大,但是每一层的神经元数量对于识别准确率有很大影响,具体的原因我现在还想不出来什么比较合理的解释。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值