2层神经网络的实现
使用Numpy矩阵来实现神经网络。我们先使用最简单的网络去实现,这个神经网络去掉了偏置和激活函数,只有权重。
这里我们假设每条线上对应的权重就是各自的数字,那么如果用函数来表示的话,应该是
可以看到,这样的表示方法非常的复杂,不方便,因此我们把神经网络的表示方法,改变成矩阵的乘法形式:
实现该神经网络时,要注意X ,W ,Y 的形状,特别是X和W的对应维度的元素个数是否一致。假设我们的输入数据为(2,4),那么神经网络的输出为:
# 矩阵形式
X = np.array([2,4])
W = np.array([[1,3,5],[2,4,6]])
Y = np.dot(X,W)
Y
array([10, 22, 34])
返回的结果为array([10,22,34]) ,也就是Y 的输出结果为y1=10,y2=22,y3=34,这样一来,我们就通过一次运算,算出了三个输出节点的输出值。而这种计算方法,即使我们在输出层有几百个几千个元素,也都可以通过一次运算就计算出结果,大大简化了运算的复杂程度。
3层神经网络的实现
现在我们来进行的是一个三层的复杂神经网络的实现。这里我们以下图的神经网络为对象,实现从输入到输出的处理。如图所示:
3层神经网络:输入层(第0层)有2个神经元,第1个隐藏层(第1层)有3个神经元,第2个隐藏层(第2层)有2个神经元,输出层(第3层)有2个神经元。为了进行复杂的线性代数运算,我们需要先规定符号,这些符号看起来会比较复杂:
我们首先来进行符号的定义:
α1(1)表示的是第1层的第1个神经元。具体来说,这个符号中的(1)表示的是神经元所在的层号,而下标1表示的是本层的第几个神经元。
ω12(1)的右下角的两个数字12,分别代表的是这个权重所表示的后一层第1个神经元和前一层第2个神经元(也就是说,权重右下角按照“后一层的索引号、前一层的索引号”的顺序排列)。右上角(1) 也是表示这个权重所处的层号。具体说明如下图:
各层之间信号的传递
有了上面规定的这种表示方式,就可以方便的用公式来表示各层之间的计算公式了。首先,来看第一层,也就是从输入层到第一层的第1个神经元的信号传递过程是怎样的。如下图:
在每一层的计算过程中,都在已有的神经元的基础上添加一个偏置神经元"1",对于偏置神经元,因为本身没有神经元的序号,所以我们省略一个序号的标识。在α1(1)这个神经元中,它的信号计算公式如下:
那么,依然是如果使用矩阵乘法去进行运算,整个第一层神经元的加权和计算结果可以通过这个公式进行计算:
其中每一部分是如下的内容:
输入层到第1层的信号传递:
#输入层到第1层的信号传递
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