最近学习神经网络,自己参照源代码把误差逆传播重新写了一遍,其实挺简单的,关键是要把逆传播的几个过程搞清楚以及每一步是为了得到什么,然后知道numpy的矩阵运算操作,废话不多说,直接上代码:
# 反向传播算法
def backpro(weights, bs, x, y, nums):
"""
逆传播计算参数的梯度
:param weights: 权重矩阵列表,每一层一个权重矩阵,直到最后一层,整个网络构成一个矩阵集合
:param bs: 偏置向量列表,每一层一个偏置列向量
:param x: 输入
:param y: 期望输出
:param nums: 网络层数
:return:
"""
# 构造两个空的梯度列表,形状跟每一层权重矩阵和列向量形状相同
nabla_weight = [np.zeros(z.shape) for z in weights] # 每一层权重的梯度矩阵跟权重矩阵的形状相同
nabla_b = [np.zeros(b.shape) for b in bs] # 同理,每一层偏置的梯度列向量跟偏置列向量的形状相同
# 定义带权输入列表,保存每一层的带权输入列向量
zs = []
# 定义激活值列表,保存激活值
activation = x
activations = [x]
# 第一步,前向传播,计算带权输入和激活值
for w, b in zip(weights, bs):
# 计算当前层的带权输入z
z = np.dot(w, activation) + b
# 计算当前层的激活值
activation = f(z)
zs.append(z)
activations.append(activation)
# 第二步,计算输出层的误差
delta = g(activations[-1]) * h(zs[-1])
nabla_b[-1] = delta # 输出层的偏置梯度即为其误差
nabla_weight[-1] = np.dot(delta, activations[-2].transpose())
# 第三步,误差逆传播,计算倒数第二层到第二层的误差
for l in range(2, nums):
# 逆传播公式,-l+1层的误差得到-l层的误差
delta = np.dot(weights[-l+1].transpose(), delta) * h(zs[-l])
nabla_b[-l] = delta
nabla_weight[-l] = np.dot(delta, activations[-l-1].transpose())
return nabla_weight, nabla_b
# 定义一个激活函数
def f(z):
return z
# 定义一个激活函数的导函数
def h(z):
return z
# 定义一个代价函数的导函数
def g(a):
return a
注意:其中的激活函数及其导数,以及代价函数都没有具体的形式,自己可以根据具体情况把这是哪个函数进行修改
最后在具体操作的过程在有什么问题,欢迎大家一起交流讨论。
在下编程小白,如果有什么错误欢迎大家批评指正!
邮箱:1916728303@qq.com