一、数学推导过程
特别详细的数学推导过程,简单易懂。
二程序代码
特别好的程序结构,值得学习
三、代码和公式对应
大家一定要先自己看看数学推导过程,代码都可以不看。但是推导过程一定得看。
1.BP算法四个核心公式
参数列表
x = np.array(x)
y = np.array(y)
weights = [] # 权重列表
bias = [] # 偏置列表
其中x为输入变量,y为输出变量
x为33555个样本值,一个x有784个变量相当于[x1,x2,x3,…,x784]
y也为33555个样本值,一个y有一个输出对应于0-9中的一个数字
weights为权重,bias为偏置
类似于 y = ax+b ,a相当于weight,bias相当于b。
weights为权重,从上面的图片中看出有2 elements,分别对应第一层(输入层)->第二层(隐藏层),第二层(隐藏层)->第三层(输出层),由此可知这是一个具有三层感知层的神经网络。
注:weight,bias,都是随机初始化的。例如
layers = [784,784,10]
for i in range(1, len(layers)): # 正态分布初始化
self.weights.append(np.random.randn(layers[i-1], layers[i]))
self.bias.append(np.random.randn(layers[i]))
激活函数
def sigmoid(x): # 激活函数采用Sigmoid
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x): # Sigmoid的导数
return sigmoid(x) * (1 - sigmoid(x))
一、反向传播算法
a = [x[k % n]] # 保存各层激活值的列表
a代表神经元的输出,对于第一层输入层对应的就是神经元输出就是x样本值
正向传播开始
for lay in range(len(self.weights)):
a.append(self.activation(np.dot(a[lay], self.weights[lay]) + self.bias[lay]))
其中activation是激活函数,上述代码循环意思是将每一层的神经元的输出乘以对应的权重加上偏置。通过激活函数得到的值
反向传播开始
label = np.zeros(a[-1].shape)#shape得到a[-1]的维度
label[y[k % n]] = 1 # 根据类号生成标签
error = label - a[-1] # 误差值
#a[-1]从后往前第一组数据
deltas = [error * self.activation_deriv(a[-1])] # 保存各层误差值的列表
layer_num = len(a) - 2 # 导数第二层开始
for j in range(layer_num, 0, -1):
deltas.append(deltas[-1].dot(self.weights[j].T) * self.activation_deriv(a[j])) # 误差的反向传播
deltas.reverse()
for迭代里的-1意思是逆序向回推导deltas,这个正是反向推导的重点所在。
正向更新权值
for i in range(len(self.weights)): # 正向更新权值
layer = np.atleast_2d(a[i])
delta = np.atleast_2d(deltas[i])
self.weights[i] += learning_rate * layer.T.dot(delta)
self.bias[i] += learning_rate * deltas[i]
代码中
self.weights[i] += learning_rate * layer.T.dot(delta)
self.bias[i] += learning_rate * deltas[i]
对应了参数求解,其中layer.T指的是layer的矩阵转至
到此为止基本就介绍完程序和公式的对应方面,如果有理解错的地方请大佬指点一二。
最后感谢提供公式推导和写代码的大佬们。