单隐藏层神经网络的实现
用Python实现用于分类任务的简单神经网络
一年前接触 PyTorch \text{PyTorch} PyTorch的时候,便有了手动构建神经网络的想法,但囿于编程技术和机器学习知识的匮乏,无法将想法变成现实。在学习了《机器学习》的神经网络章节后,便打算将其用Python
实现出来一个单隐层的神经网络.
本文转载自我的博客:Welt Xing’s blog
神经网络简述
神经网络是由具有自适应的简单单元组成的广泛并行互联的网络,它的组织能够模拟生物神经对真实世界的物体所作出的交互反应 —— Kohonen , 1988 \text{Kohonen},1988 Kohonen,1988.
一个典型的神经网络如下面所示:
其中每一个圆圈都是一个下面这样的 m m m输入1输出的神经元:
它将多输入进行线性组合,加以偏置,通过激活函数输出信号
y = φ ( ∑ i = 1 m ω i x i − b ) y=\varphi(\sum_{i=1}^m\omega_ix_i-b) y=φ(i=1∑mωixi−b)
编程弯路
在经过上面的神经网络的介绍后,我们一个简单的想法是先写一个Neuron
类,用来模拟神经元的行为:
class Neuron:
'''
The class is used to imitate the behavior of neuron
'''
def __init__(self, input:int):
self.input = input
self.weight = np.random.rand(1, input)
self.bias = np.random.rand(1, 1)
@staticmathod
def ReLU(x):
'''
激活函数使用ReLU
'''
return x>0? x : np.zeros(x.shape)
def output(x):
'''
计算输出
'''
return Neuron.ReLU(self.weight @ x.T - self.bias)
然后一层神经元NeuronLayer
就是一个Neuron
数组,神经网络NeuronNetwork
就是神经元层的数组. 这种设计是可行的,但难在层与层之间的交互:上一层的信号传导到下一层的信号要考虑同步,更新等问题,难度过大,我们会提出更简单可靠的实现方法. 事实上,越形象的模型,实现起来越复杂,越抽象的模型,越能够用数学模型去模拟.
从矩阵视角看神经网络
为了便于书写和讨论,我们选择去实现一个 3 3 3输入, 4 4 4个隐层神经元和 2 2 2输出的神经网络;此外,选用 Sigmoid \text{Sigmoid} Sigmoid作为激活函数:
Sigmoid ( x ) = 1 1 + exp ( − x ) \text{Sigmoid}(x)=\dfrac{1}{1+\exp(-x)} Sigmoid(x)=1+exp(−x)1
也就是下面的网络:
该网络中的参数有哪些?我们从左往右看:
- 输入层到中间层的边上的权重,如果我们设连接输入层中第 i i i个神经元和隐藏层中第 j j j个神经元的边上的权重为 v i j v_{ij} vij,那么就可以将输入层到隐藏层上的边权用矩阵写出来:
V = [ v 11 v 12 v 13 v 14 v 21 v 22 v 23 v 24 v 31 v 32 v 33 v 34 ] V=\begin{bmatrix} v_{11}&v_{12}&v_{13}&v_{14}\\ v_{21}&v_{22}&v_{23}&v_{24}\\ v_{31}&v_{32}&v_{33}&v_{34}\\ \end{bmatrix} V=⎣⎡v11v21v31v12v22v32v13v23v33v14v24v34⎦⎤
v i j v_{ij} vij表示第 i i i个神经元到第 j j j个神经元的权重.
- 中间层的偏置:
B = [ b 1 b 2 b 3 b 4 ] B=\begin{bmatrix} b_1&b_2&b_3&b_4 \end{bmatrix} B=[b1b2b3b4]
b i b_i bi表示中间层第 i i i的神经元的偏置.
- 中间层到输出层的权重矩阵:
W = [ w 11 w 12 w 21 w 22 w 31 w 32 w 41 w 42 ] W=\begin{bmatrix} w_{11}&w_{12}\\ w_{21}&w_{22}\\ w_{31}&w_{32}\\ w_{41}&w_{42}\\ \end{bmatrix} W=⎣⎢⎢<