5.1 神经元模型
定义:神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够模拟生物神经系统对真实世界物体所作出的交互反应。
比较具有代表性的模型就是"M-P神经元模型",如图5.1所示,中间的圆圈表示当前神经元,而该神经元又与其他n个神经元连接,并且产生一个输出y。该"M-P神经元模型"的实现流程如下:
神经元接收n个其他神经元出来的输入信号,每个输入信号乘以相应的连接权重;
将以上结果进行求和,再和当前神经元的阈值比较;
若大于,则通过"激活函数"产生输出,否则,不产生输出。
理想中的激活函数是阶跃函数,"1"表示神经元兴奋,"0"表示神经元抑制。由于该阶跃函数不连续不光滑,所以一般用函数来替代,如下图所示。
5.2 感知机与多层网络
定义:感知机由两层神经元组成,分别为输入层和输出层,输入层接收输入信号并且传送给输出层,输出层则是M-P神经元。
作用:能够简易地实现与、或、非逻辑运算。
一般地,给定训练数据集,权重以及阈值已知,感知机学习规则就是对于训练样例,如果当前的感知机输出为,那么权重将如此调整
其中是学习率。从上面的式子可以看出,当,感知机预测正确,感知机没变化;否则要根据错误程度进行权重调整。
如图5.6所示,常见神经网络分为以下两种层级结构。
单隐层前馈网络:输入层只是接受输入,不进行函数处理,隐层与输出层包含功能神经元,且隐层只有一层;
单隐层前馈网络:隐层含有多层,神经元之间不存在同层连接,也不存在跨层连接。
神经网络的学习过程其实就是根据训练数据来调整"连接权"以及每个神经元的阈值,也就是说神经网络学习的就是连接权和阈值的合理调整,使得模型可以比较精准地完成任务。
5.3 误差逆传播算法
感知机学习规则不足以应付多层网络的学习,需要足够强大的学习算法误差逆传播算法,简称BP算法。给定训练集,,即输入示例由d个属性描述,输出l维实值向量。如图5.7所示,由d个输入神经元、l个输出神经元、q个隐层神经元组成的多层前馈网络结构,其中输出层阈值用表示,隐层阈值用表示,输入层与隐层连接权用表示,隐层与输出层连接权用表示,则隐层第h个神经元收到的输入为
,
输出层第j个神经元接收到的输入为
对训练例,神经网络的输出为,其中
均方误差为
BP算法基于梯度下降策略,对目标的负梯度方向对参数进行调整,有
根据的定义,显然有
Sigmoid函数有一个很好的性质
有
得到BP算法中关于的更新公式
类似的
其中
图5.8给出了BP算法的工作流程
值得注意的是,BP算法的主要目标是最小化训练集D的累积误差,即
,
累积BP算法与标准BP算法都很常用。一般来说,标准BP算法每次更新只针对单个样例,为了达到相同的累积误差极小点,需要更多次数的迭代。累积BP算法直接针对累积误差最小化,其参数更新的频率低得多。但在很多任务中,往往是累积BP算法和标准BP算法混合使用。
由于BP神经网络强大的表示能力,经常导致过拟合,训练误差降低同时,测试误差也可能上升,为此,有两种策略可以缓解BP网络的过拟合。
"早停":将数据分成训练集和验证集,训练集计算梯度、连接权和阈值,验证集估计误差。若训练误差连续a轮的变化小于b,则停止训练;若训练误差降低、验证误差升高,则停止训练。
正则化:其基本思想是在误差目标函数中增加一个用于描述网络复杂度的部分。
令表示第k个训练样例上的误差,表示连接权和阈值,则误差目标函数改变为
通过以下代码,我们将实现一个具有单个隐藏层的神经网络,并使用Sigmoid激活函数。这个示例将包括前向传播、计算损失、反向传播和参数更新。
python
import numpy as np
# Sigmoid激活函数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# Sigmoid函数的导数
def sigmoid_derivative(x):
return x * (1 - x)
class SimpleNeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
# 初始化权重
self.input_size = input_size
self.hidden_size = hidden_size
self.output_size = output_size
# 权重初始化
self.weights_input_hidden = np.random.rand(self.input_size, self.hidden_size)
self.weights_hidden_output = np.random.rand(self.hidden_size, self.output_size)
# 偏置初始化
self.bias_hidden = np.random.rand(1, self.hidden_size)
self.bias_output = np.random.rand(1, self.output_size)
def forward(self, X):
# 前向传播
self.hidden_layer_activation = np.dot(X, self.weights_input_hidden) + self.bias_hidden
self.hidden_layer_output = sigmoid(self.hidden_layer_activation)
self.output_layer_activation = np.dot(self.hidden_layer_output, self.weights_hidden_output) + self.bias_output
output = sigmoid(self.output_layer_activation)
return output
def backward(self, X, y, output, learning_rate):
# 反向传播
output_error = y - output
output_delta = output_error * sigmoid_derivative(output)
hidden_layer_error = output_delta.dot(self.weights_hidden_output.T)
hidden_layer_delta = hidden_layer_error * sigmoid_derivative(self.hidden_layer_output)
# 更新权重和偏置
self.weights_hidden_output += self.hidden_layer_output.T.dot(output_delta) * learning_rate
self.bias_output += np.sum(output_delta, axis=0, keepdims=True) * learning_rate
self.weights_input_hidden += X.T.dot(hidden_layer_delta) * learning_rate
self.bias_hidden += np.sum(hidden_layer_delta, axis=0, keepdims=True) * learning_rate
def train(self, X, y, epochs, learning_rate):
for epoch in range(epochs):
output = self.forward(X)
self.backward(X, y, output, learning_rate)
# 每1000次epoch打印损失
if epoch % 1000 == 0:
loss = np.mean(np.square(y - output)) # 均方误差
print(f'Epoch {epoch}, Loss: {loss}')
# 示例训练数据
if __name__ == "__main__":
# 输入数据(XOR数据集)
X = np.array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
# 目标输出
y = np.array([[0],
[1],
[1],
[0]])
# 创建神经网络
nn = SimpleNeuralNetwork(input_size=2, hidden_size=2, output_size=1)
# 训练神经网络
nn.train(X, y, epochs=10000, learning_rate=0.1)
# 测试模型
print("预测结果:")
print(nn.forward(X))
首先,对以上代码进行说明,Sigmoid函数及其导数用于激活神经元,SimpleNeuralNetwork类实现了神经网络的结构与训练方法,使用XOR数据集训练模型,并输出预测结果。
__init__
:初始化网络的参数(权重和偏置)。forward
:前向传播,用于计算网络的输出。backward
:误差反向传播,并更新网络参数。train
:训练网络,进行多次迭代以拟合数据。
将代码保存到文件中并运行,结果将展示模型如何学习并打印出每千个epochs的损失和最终的预测结果。通过调节隐层大小、学习率和训练轮数,可以观察不同设置下模型的表现。
参考文献:《机器学习》周志华