深度学习入门:基于 Python 的理论与实现 (16):神经网络 3.4.2

阅读数:31 2019 年 11 月 13 日 15:07

深度学习入门:基于Python的理论与实现(16):神经网络 3.4.2

内容简介
本书是深度学习真正意义上的入门书,深入浅出地剖析了深度学习的原理和相关技术。书中使用 Python3,尽量不依赖外部库或工具,从基本的数学知识出发,带领读者从零创建一个经典的深度学习网络,使读者在此过程中逐步理解深度学习。书中不仅介绍了深度学习和神经网络的概念、特征等基础知识,对误差反向传播法、卷积神经网络等也有深入讲解,此外还介绍了深度学习相关的实用技巧,自动驾驶、图像生成、强化学习等方面的应用,以及为什么加深层可以提高识别精度等疑难的问题。
本书适合深度学习初学者阅读,也可作为高校教材使用。

(各层间信号传递的实现)

现在看一下从输入层到第 1 层的第 1 个神经元的信号传递过程,如图 3-17 所示。

图 3-17 从输入层到第 1 层的信号传递

图 3-17 中增加了表示偏置的神经元“1”。请注意,偏置的右下角的索引号只有一个。这是因为前一层的偏置神经元(神经元“1”)只有一个 1

1 任何前一层的偏置神经元“1”都只有一个。偏置权重的数量取决于后一层的神经元的数量(不包括后一层的偏置神经元“1”)。——译者注

为了确认前面的内容,现在用数学式表示 $a^{(1)}{1}$。$a^{(1)}{1}$ 通过加权信号和偏置的和按如下方式进行计算。

$a^{(1)}{1}=w^{(1)}{11}x_1+w^{(1)}{12}x_2+b^{(1)}{1}\quad\quad\quad\quad\quad(3.8)$

此外,如果使用矩阵的乘法运算,则可以将第 1 层的加权和表示成下面的式(3.9)。

$\boldsymbol{A}^{(1)}=\boldsymbol{XW}^{(1)}+\boldsymbol{B}^{(1)}\quad\quad\quad\quad\quad(3.9)$

其中,$\boldsymbol{A}^{(1)}$、$\boldsymbol{X}$、$\boldsymbol{B}^{(1)}$、$\boldsymbol{W}^{(1)}$ 如下所示。

$\begin{aligned}&\boldsymbol{A}^{(1)}=\Bigl(a_1^{(1)}~~~a_2^{(1)}~a_3^{(1)}\Bigr),~\boldsymbol{X}=\Bigl(x_1~x_2\Bigr),~\boldsymbol{B}^{(1)}=\Bigl(b_1^{(1)}~~~b_2^{(1)}~~~b_3^{(1)}\Bigr)\&\boldsymbol{W}^{(1)}=\begin{pmatrix}w^{(1)}{11}&w^{(1)}{21}&w^{(1)}{31}\w^{(1)}{12}&w^{(1)}{22}&w^{(1)}{32}\end{pmatrix}\end{aligned}$

下面我们用 NumPy 多维数组来实现式(3.9),这里将输入信号、权重、偏置设置成任意值。

X = np.array([1.0, 0.5])
W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
B1 = np.array([0.1, 0.2, 0.3])

print(W1.shape) #  (2, 3)
print(X.shape) #  (2,)
print(B1.shape) #  (3,)

A1 = np.dot(X, W1) + B1

这个运算和上一节进行的运算是一样的。W1 是 2 × 3 的数组,X 是元素个数为 2 的一维数组。这里,W1X 的对应维度的元素个数也保持了一致。

接下来,我们观察第 1 层中激活函数的计算过程。如果把这个计算过程用图来表示的话,则如图 3-18 所示。

图 3-18 从输入层到第 1 层的信号传递

如图 3-18 所示,隐藏层的加权和(加权信号和偏置的总和)用 $a$ 表示,被激活函数转换后的信号用 $z$ 表示。此外,图中 $h()$ 表示激活函数,这里我们使用的是 sigmoid 函数。用 Python 来实现,代码如下所示。

Z1 = sigmoid(A1)

print(A1) #  [0.3, 0.7, 1.1]
print(Z1) #  [0.57444252, 0.66818777, 0.75026011]

这个 sigmoid() 函数就是之前定义的那个函数。它会接收 NumPy 数组,并返回元素个数相同的 NumPy 数组。

下面,我们来实现第 1 层到第 2 层的信号传递(图 3-19)。

W2 = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
B2 = np.array([0.1, 0.2])

print(Z1.shape) #  (3,)
print(W2.shape) #  (3, 2)
print(B2.shape) #  (2,)

A2 = np.dot(Z1, W2) + B2
Z2 = sigmoid(A2)

除了第 1 层的输出(Z1)变成了第 2 层的输入这一点以外,这个实现和刚才的代码完全相同。由此可知,通过使用 NumPy 数组,可以将层到层的信号传递过程简单地写出来。

图 3-19 第 1 层到第 2 层的信号传递

最后是第 2 层到输出层的信号传递(图 3-20)。输出层的实现也和之前的实现基本相同。不过,最后的激活函数和之前的隐藏层有所不同。

def identity_function(x):
    return x

W3 = np.array([[0.1, 0.3], [0.2, 0.4]])
B3 = np.array([0.1, 0.2])

A3 = np.dot(Z2, W3) + B3
Y = identity_function(A3) #  或者 Y = A3

这里我们定义了 identity_function() 函数(也称为“恒等函数”),并将其作为输出层的激活函数。恒等函数会将输入按原样输出,因此,这个例子中没有必要特意定义 identity_function()。这里这样实现只是为了和之前的流程保持统一。另外,图 3-20 中,输出层的激活函数用 $\sigma$ 表示,不同于隐藏层的激活函数 $h()$($\sigma$ 读作 sigma)。

图 3-20 从第 2 层到输出层的信号传递

输出层所用的激活函数,要根据求解问题的性质决定。一般地,回归问题可以使用恒等函数,二元分类问题可以使用 sigmoid 函数,多元分类问题可以使用 softmax 函数。关于输出层的激活函数,我们将在下一节详细介绍。

评论

发布