目录
神经网络
神经元模型
感知机与多层网络
感知机
感知机学习规则
功能神经元
线性可分问题
非线性可分问题
多层前馈神经网络
误差逆传播算法(反向传播算法)-BP算法
实例
相关解释
阶跃函数具有不连续、不光滑等不太好的性质。sigmoid函数也叫挤压函数。
许多的神经元按照一定的层次连接起来就得到了神经网络。
Example:20个神经元每层10个,则有 100个连接权和 10 个阈值
感知机由两层神经元组成。
输出层是M-P神经元
感知机能够实现与或非操作。
output = activation_function(sum(weight_i * input_i) - bias)
例如,我们有一个节点,其输入是 [0.5, 0.6],权重是 [0.1, 0.2],阈值是 0.3。按照公式,输出为 activation_function(0.5*0.1 + 0.6*0.2 - 0.3)
。
如果将阈值视为权重,我们将输入增加一个常数项 -1,权重增加一项(即阈值)。输入变为 [0.5, 0.6, -1],权重变为 [0.1, 0.2, 0.3]。计算变为 activation_function(0.5*0.1 + 0.6*0.2 + -1*0.3)
,得到的结果与之前相同。这样阈值的学习和权重的学习就相统一了。
称为学习率,将根据错误的程度进行调整权重。
功能神经元(functional neuron)是指在神经网络中执行特定计算功能的单元,包括接收输入、通过激活函数处理,并输出结果。每个神经元都与其他神经元相连,通过权重调整这些连接的强度。功能神经元可以用于实现神经网络的各种功能,包括分类、回归、聚类等。
线性可分问题是指一个分类问题,其中两个类别可以通过一个直线(在二维空间)、平面(在三维空间)或一个超平面(在更高维度空间)完全分隔开。例如,如果你有两类点在二维平面上,且你可以画一条直线将这两类点完全分开,那么这个分类问题就是线性可分的。
与、或、非问题都是线性可分的。
要解决此类问题需要使用多层功能神经元。
下面以输入层第i个神经元与隐层第h个神经元之间的连接权为例推导一下:
或者基本步骤:
随机初始化神经网络的权重。
前向传播:输入样本,通过计算每一层的输出,最终得到预测值。
计算误差:预测值与实际值之间的差距。
反向传播:从输出层开始,逐层向后计算误差的梯度,并更新每一层的权重。
迭代:反复执行步骤2-4,直至达到预设的迭代次数,或者误差满足设定的阈值。
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x):
return x * (1 - x)
# 输入数据
training_inputs = np.array([[0,0,1],
[1,1,1],
[1,0,1],
[0,1,1]])
# 输出数据
training_outputs = np.array([[0,1,1,0]]).T
np.random.seed(1)
synaptic_weights = 2 * np.random.random((3, 1)) - 1
print('随机初始化的权重: ')
print(synaptic_weights)
for iteration in range(20000):
input_layer = training_inputs
outputs = sigmoid(np.dot(input_layer, synaptic_weights))
# 计算误差
error = training_outputs - outputs
# 进行权值调整
adjustments = error * sigmoid_derivative(outputs)
synaptic_weights += np.dot(input_layer.T, adjustments)
print('权重更新后:')
print(synaptic_weights)
print("训练后的输出 : ")
print(outputs)
输出:
synaptic_weights = 2 * np.random.random((3, 1)) - 1
这是在对神经网络中的权重进行随机初始化。
np.random.random((3, 1))
:生成一个3行1列的数组,数组中的元素是[0, 1)之间的随机数。2 * np.random.random((3, 1))
:将这个数组中的所有元素乘以2,得到的新数组中的元素位于[0, 2)之间。2 * np.random.random((3, 1)) - 1
:从这个新数组中的所有元素中减去1,得到的最终数组中的元素位于[-1, 1)之间。神经网络的权重通常需要进行随机初始化,以打破对称性并确保每个神经元学习不同的特性。这行代码使用了在[-1, 1)范围内的随机数进行权重初始化。
np.random()
np.random
是numpy库中的一个模块,主要用于生成各种类型的随机数。
常用的函数:
np.random.rand
:生成均匀分布的随机数。np.random.randn
:生成标准正态分布(均值为0,标准差为1)的随机数。np.random.randint
:生成指定范围内的随机整数。np.random.choice
:从指定的一维数组中生成随机数。np.random.shuffle
:对数组进行随机排列。adjustments = error * sigmoid_derivative(outputs)
实际上是利用链式法则进行微分,计算出误差函数关于权重的梯度。这是因为,权重的微小变化会导致网络输出的微小变化,进而导致误差的变化。链式法则允许我们将这些效应相乘,得到权重变化对误差的最终影响,也就是误差函数关于权重的梯度。
梯度在数学上代表了函数值变化最快的方向。在神经网络中,误差函数关于权重的负梯度,就代表了调整权重能够最快减小误差的方向。因此,按照误差的梯度进行权重的更新,就可以在每次迭代中,尽可能快地减小误差,优化神经网络的性能。
synaptic_weights += np.dot(input_layer.T, adjustments)
在这个特定的实现中,已经考虑了调整方向的问题。在adjustments = error * sigmoid_derivative(outputs)
这一行。这里的 error
已经是实际值与预测值之间的差值,所以它已经包含了方向性:如果预测值小于实际值,误差是正的,我们需要增加权重;如果预测值大于实际值,误差是负的,我们需要减小权重。
在深度学习中,通常的表述是权重更新的规则是 weights = weights - learning_rate * gradient
,这里的 gradient
是损失函数关于权重的梯度,learning_rate
是一个正数,所以 - learning_rate * gradient
表明我们在向损失函数减小的方向更新权重。但在这个例子中,由于已经在 adjustments
中考虑了方向性,所以直接使用加法操作。