Deep Learning Note: 1-9 深度神经网络
前面以一个简单的 2 层神经网络为例,介绍了前向传播和反向传播的计算过程。下面扩展到 L 层神经网络的情况。
以图 1 所示的网络为例,记网络的层数为 $L$,此时 $L = 4$。使用 $n^{[l]}$ 表示第 $l$ 层中节点的个数,记输入层为第 0 层,输入有三个特征,故 $n^{[0]} = n_x = 3$;第一个隐藏层有 5 个节点,故 $n^{[1]} = 5$,以此类推,$n^{[2]} = 5$,$n^{[3]} = 3$,$n^{[4]} = n^{[L]} = 1$。使用 $a^{[l]}$ 表示第 $l$ 层的激活值,则有 $a^{[l]} = g^{[l]}(z^{[l]})$,其中 $g^{[l]}$ 为第 $l$ 层的激活函数。使用 $W^{[l]}$、$b^{[l]}$ 分别表示第 $l$ 层的权重和偏置。
1. 计算网络输出
对于图 1 所示的网络,单个样本前向传播的计算步骤为:
- 第一层:
\begin{equation}
z^{[1]} = W^{[1]}x + b^{[1]} = W^{[1]}a^{[0]} + b^{[1]}
\end{equation}
\begin{equation}
a^{[1]} = g^{[1]}(z^{[1]})
\end{equation}
- 第二层:
\begin{equation}
z^{[2]} = W^{[2]}a^{[1]} + b^{[2]}
\end{equation}
\begin{equation}
a^{[2]} = g^{[2]}(z^{[2]})
\end{equation}
- 第三层:
\begin{equation}
z^{[3]} = W^{[3]}a^{[2]} + b^{[3]}
\end{equation}
\begin{equation}
a^{[3]} = g^{[3]}(z^{[3]})
\end{equation}
- 第四层(输出层):
\begin{equation}
z^{[4]} = W^{[4]}a^{[3]} + b^{[4]}
\end{equation}
\begin{equation}
a^{[4]} = g^{[4]}(z^{[4]})
\end{equation}
更一般地,可以将单个样本前向传播第 $l$ 层的计算写为如下的形式:
\begin{equation}
z^{[l]} = W^{[l]}a^{[l-1]} + b^{[l]} \tag{1}
\end{equation}
\begin{equation}
a^{[l]} = g^{[l]}(z^{[l]}) \tag{2}
\end{equation}
$m$ 个样本前向传播的向量化实现形式为:
\begin{equation}
Z^{[l]} = W^{[l]}A^{[l-1]} + b^{[l]} \tag{3}
\end{equation}
\begin{equation}
A^{[l]} = g^{[l]}(Z^{[l]}) \tag{4}
\end{equation}
式 (3)、(4) 向量化地计算了 $m$ 个样本在第 $l$ 层上的前向传播,但无法向量化整个 $L$ 层网络的计算,仍需要逐层计算各层的激活值,作为下一层的输入,逐层向前传播到输出层。
2. 检查矩阵的维数
如前所示的计算涉及大量的矩阵运算,通过检查各矩阵的维数是否匹配,可以快速地对计算的合法性和正确性进行初步校验。
以图 2 所示的网络为例,首先看第 1 层,有:
\begin{equation}
z^{[1]} = W^{[1]}x + b^{[1]}
\end{equation}
上式中 $z^{[1]}$ 的大小与第一层节点数相同,是一个 $n^{[1]} \times 1$ 即 $3 \times 1$ 的向量;$x$ 是一个 $n^{[0]} \times 1$ 即 $2 \times 1$ 的向量;$W^{[1]}$ 是一个 $n^{[1]} \times n^{[0]}$ 即 $3 \times 2$ 的矩阵,它与 $2 \times 1$ 的 $x$ 相乘得到一个 $3 \times 1$ 的向量,与 $z^{[1]}$ 的大小相符。$b^{[1]}$ 的大小与 $W^{[1]}x$ 和 $z^{[1]}$ 相同,是一个 $n^{[1]} \times 1$ 即 $3 \times 1$ 的向量。
一般的,对于第 $l$ 层,$z^{[l]}$ 和 $a^{[l]}$ 都是 $n^{[l]} \times 1$ 的向量,权重 $W^{[l]}$ 是一个 $n^{[l]} \times n^{[l-1]}$ 的矩阵,偏置 $b^{[l]}$ 是一个 $n^{[l]} \times 1$ 的向量。
由此可以快速得到各层参数的大小为:
- $W^{[2]}$:$5 \times 3$,$b^{[2]}$:$5 \times 1$
- $W^{[3]}$:$4 \times 5$,$b^{[3]}$:$4 \times 1$
- $W^{[4]}$:$2 \times 4$,$b^{[4]}$:$2 \times 1$
- $W^{[5]}$:$1 \times 2$,$b^{[5]}$:$1 \times 1$
在进行反向传播时,$dW^{[l]}$ 和 $db^{[l]}$ 的大小与 $W^{[l]}$ 和 $b^{[l]}$ 相同,分别为 $n^{[l]} \times n^{[l-1]}$ 和 $n^{[l]} \times 1$。
下面考虑向量化计算 $m$ 个样本的情况,对第一层,有:
\begin{equation}
Z^{[1]} = W^{[1]}X + b^{[1]}
\end{equation}
上式中 $Z^{[1]}$ 的大小为 $n^{[1]} \times m$;$W^{[1]}$ 的大小不变,仍为 $n^{[1]} \times n^{[0]}$;$X^{[1]}$ 的大小为 $n^{[0]} \times m$;对于 $b^{[1]}$,仍可以将它看成是 $n^{[1]} \times 1$ 的向量,但在实际运算中,要把它复制并水平叠加成 $n^{[1]} \times m$ 的形式,才能与 $W^{[1]}X$ 相加,在 Python 中可以利用其广播机制自动完成这一操作。
在向量化计算 $m$ 个样本的时候,对于第 $l$ 层,$W^{[l]}$ 和 $b^{[l]}$ 的大小与计算单个样本的情况一致,分别为 $n^{[l]} \times n^{[l-1]}$ 和 $n^{[l]} \times 1$。而对于 $Z^{[l]}$ 和 $A^{[l]}$,以及反向传播时的偏导 $dZ^{[l]}$ 和 $dA^{[l]}$,都是 $n^{[l]} \times m$ 的矩阵。
3. 深度神经网络的构造块
对于网络的第 $l$ 层,参数为权重 $W^{[l]}$ 和偏置 $b^{[l]}$。前向传播时,输入为 $a^{[l-1]}$,输出为 $a^{[l]}$,计算过程为:
\begin{equation}
Z^{[l]} = W^{[l]}a^{[l-1]} + b^{[l]} \tag{5}
\end{equation}
\begin{equation}
a^{[l]} = g^{[l]}(Z^{[l]}) \tag{6}
\end{equation}
在计算式 (5) 时,通常会缓存 $Z^{[l]}$ 的结果,直接用于后续的反向传播。在进行反向传播时,输入为 $da^{[l]}$,以及前面缓存的 $Z^{[l]}$。输出为 $da^{[l-1]}$,以及参数的梯度 $dW^{[l]}$、$db^{[l]}$。
由此得到神经网络的基本结构如图 3 所示。
图 3 中,对于神经网络的第 $l$ 层,首先通过前向传播,由第 $l-1$ 层的激活值 $a^{[l-1]}$ 和第 $l$ 层的参数 $W^{[l]}$、$b^{[l]}$,计算得到第 $l$ 层的激活值 $a^{[l]}$,并缓存中间结果 $Z^{[l]}$。然后通过反向传播,由第 $l$ 层的激活值的导数 $da^{[l]}$ 和参数 $W^{[l]}$、$b^{[l]}$,计算得到第 $l$ 层各参数的梯度 $dW^{[l]}$、$db^{[l]}$,以及第 $l-1$ 层的激活值的导数 $da^{[l-1]}$。使用梯度 $dW^{[l]}$、$db^{[l]}$ 更新该层的参数 $W^{[l]}$、$b^{[l]}$:
\begin{equation}
W^{[l]} = W^{[l]} – \alpha dW^{[l]} \tag{7}
\end{equation}
\begin{equation}
b^{[l]} = b^{[l]} – \alpha db^{[l]} \tag{8}
\end{equation}
以图 3 所示的结构为基础,可以将神经网络抽象为如图 4 所示的形式。
4. 前向传播
结合前面计算网络输出的过程和网络的基本结构,可以得到第 $l$ 层前向传播的计算过程为:
- 输入:$a^{[l-1]}$
- 输出:$a^{[l]}$,缓存 $z^{[l]}$
- 单个样本的计算:
\begin{equation}
z^{[l]} = W^{[l]}a^{[l-1]} + b^{[l]} \tag{9}
\end{equation}
\begin{equation}
a^{[l]} = g^{[l]}(z^{[l]}) \tag{10}
\end{equation}
- 向量化计算 $m$ 个样本:
\begin{equation}
Z^{[l]} = W^{[l]}A^{[l-1]} + b^{[l]} \tag{11}
\end{equation}
\begin{equation}
A^{[l]} = g^{[l]}(Z^{[l]}) \tag{12}
\end{equation}
5. 反向传播
结合前文反向传播的推导和网络的基本结构,可以得到第 $l$ 层前向传播的计算过程为:
- 输入:$da^{[l]}$
- 输出:$da^{[l-1]}$,$dW^{[l]}$,$db^{[l]}$
- 单个样本的计算:
\begin{equation}
dz^{[l]} = da^{[l]} * g^{[l]\prime}(z^{[l]}) \tag{13}
\end{equation}
\begin{equation}
dW^{[l]} = dz^{[l]} a^{[l-1]} \tag{14}
\end{equation}
\begin{equation}
db^{[l]} = dz^{[l]} \tag{15}
\end{equation}
\begin{equation}
da^{[l-1]} = W^{[l]T} dz^{[l]} \tag{16}
\end{equation}
- 向量化计算 $m$ 个样本:
\begin{equation}
dZ^{[l]} = dA^{[l]} * g^{[l]\prime}(Z^{[l]}) \tag{17}
\end{equation}
\begin{equation}
dW^{[l]} = \frac{1}{m} dZ^{[l]} A^{[l-1]T} \tag{18}
\end{equation}
\begin{equation}
db^{[l]} = \frac{1}{m} np.sum(dZ^{[l]}, axis = 1, keepdims = True) \tag{19}
\end{equation}
\begin{equation}
dA^{[l-1]} = W^{[l]T} dZ^{[l]} \tag{20}
\end{equation}
如果使用式 (21) 作为损失函数,其中 $\hat{y}$ 为第 $L$ 层的输出,即 $a^{[L]}$,则 $da^{[L]}$ 如式 (22) 所示。
\begin{equation}
L(\hat{y}, y) = -y\log{\hat{y}} – (1 – y)log(1- \hat{y}) \tag{21}
\end{equation}
\begin{equation}
da^{[L]} = d\hat{y} = -\frac{y}{\hat{y}} + \frac{1-y}{1-\hat{y}} \tag{22}
\end{equation}
6. 参数和超参数
训练神经网络时涉及到的参数除了模型本身的参数 $W$ 和 $b$,还有其他一些参数,如学习率 $\alpha$、迭代次数、隐藏层数量 $L$、隐藏单元数量 $n^{[l]}$、激活函数等,这些参数并不直接作用于预测,但它们会在一定程度上控制或影响 $W$ 和 $b$ 的学习过程和结果,这些参数称为超参数(Hyperparameter)。
除了上面提到的,在训练神经网络的过程中涉及的超参数还有很多,比如动量(Momentum)项、最小批大小(Minibatch Size)、正则化(Regularization)形式等等。
由于涉及到众多的超参数,通常很难在一开始就找到最佳的选择,往往需要尝试各种选择和取值,进行比较。应用机器学习是一个非常依赖经验的过程,比如对某个超参数的取值有了一个猜想,那么接下来就要把它实现出来,进行实验,根据实验结果对超参数进行必要的调整,再进行实现···如此循环。
另一方面,即便找到了较好的超参数,随着外界条件的变化,比如计算环境的变化,原有的超参数不再适用于新的环境,无法达到原来的性能。所以通常每隔一段时间,比如几个月或几年,需要重新尝试各种不同的超参数,检查是否有新的更好的参数选择。