机器学习入门(05)— 使用 NumPy 实现 3 层简单神经网络

我们以图 3-15 的3 层神经网络为对象,实现从输入到输出的(前向)处理。在代码实现方面,使用上一节介绍的 NumPy 多维数组。

3 层神经网络

1. 符号定义

符号定义

2. 各层之间信号传递

从输入层到第 1 层的 第1 个神经元的信号传递过程,如图 3-17 所示。
输入层到 1 层传递
图 3-17 中增加了表示偏置的神经元 “1”。请注意,偏置的右下角的索引号只有一个。这是因为前一层的偏置神经元(神经元“1”)只有一个。

神经元关系
矩阵表示
用代码实现上述过程:

In [1]: import numpy as np

In [2]: X = np.array([1.0, 0.5])

In [3]: W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])

In [5]: B1 = np.array([0.1, 0.2, 0.3])

In [6]: A1 = np.dot(X, W1) + B1

In [7]: A1
Out[7]: array([0.3, 0.7, 1.1])

In [8]: 

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

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

输入层到第1层信号传递

In [8]: def sigmoid(x):
   ...:     return 1/(1+np.exp(-x))
   ...:     

In [12]: Z1 = sigmoid(A1)

In [13]: Z1
Out[13]: array([0.57444252, 0.66818777, 0.75026011])

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

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

In [15]: B2 = np.array([0.1, 0.2])

In [16]: A2 = np.dot(Z1, W2) + B2 

In [17]: Z2 = sigmoid(A2)

In [18]: Z2
Out[18]: array([0.62624937, 0.7710107 ])

In [19]: 

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

第 2 层到输出层信号传递

In [18]: def identity_function(x):
   ...:     return x
In [19]: 
In [20]: W3 = np.array([[0.1, 0.3], [0.2, 0.4]])

In [21]: B3 = np.array([0.1, 0.2])

In [22]: Z3 = np.dot(Z2, W3) + B3

In [23]: Z3
Out[23]: array([0.31682708, 0.69627909])

In [24]: Y = identify_function(Z3)

In [25]: Y
Out[25]: array([0.31682708, 0.69627909])

In [26]: 

这里我们定义了 identity_function() 函数(也称为“恒等函数”),并将其作为输出层的激活函数。恒等函数会将输入按原样输出,因此,这个例子中没有必要特意定义identity_function() 。这里这样实现只是为了和之前的流程保持统一。

另外,图 3-20 中,输出层的激活函数用 σ() 表示,不同于隐藏层的激活函数 h()σ 读作 sigma )。

输出层所用的激活函数,要根据求解问题的性质决定。一般地,

  • 回归问题可以使用恒等函数;
  • 二元分类问题可以使用 sigmoid 函数;
  • 多元分类问题可以使用 softmax 函数;

3. 代码实现总结

import numpy as np

network = {}

def sigmoid(x):
    return 1/(1+np.exp(-x))

def identity_function(x):
    return x

def init_work():
    network["W1"] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    network["b1"] = np.array([0.1, 0.2, 0.3])
    network["W2"] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
    network["b2"] = np.array([0.1, 0.2])
    network["W3"] = np.array([[0.1, 0.3], [0.2, 0.4]])
    network["b3"] = np.array([0.1, 0.2])

    return network

def forward(nt, x):
    W1, W2, W3 = nt["W1"], nt["W2"], nt["W3"]
    b1, b2, b3 = nt["b1"], nt["b2"], nt["b3"]

    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)

    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)

    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)

    return y

network = init_work()
x = np.array([1.0, 0.5])
y = forward(network, x)
print("y is {}".format(y))	# y is [0.31682708 0.69627909]
  • init_network() 函数会进行权重和偏置的初始化,并将它们保存在字典变量 network中。这个字典变量 network 中保存了每一层所需的参数(权重和偏置)。
  • forward() 函数中则封装了将输入信号转换为输出信号的处理过程。

forward (前向)一词,它表示的是从输入到输出方向的传递处理。与之对应的backward 表示从输出到输入方向的处理。

参考:《深度学习入门:基于Python的理论与实现》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章