通过前面几篇建立的神经网络以上一层的输出作为下一层的输入。这种⽹络被称为前馈神经网络。这意味着网络中是没有回路的 —— 信息总是向前传播,从不反向回馈。如果确实有回路,我们最终会有这样的情况:σ 函数的输⼊依赖于输出。这将难于理解,所以我们不允许这样的环路。(前馈 指的是拓扑学上的向前单向传播)
BP神经网络是一种多层的前馈神经网络,其主要的特点是:信号是前向传播的,而误差是反向传播的。BP神经网络的过程主要分为两个阶段,第一阶段是信号的前向传播,从输入层经过隐含层,最后到达输出层;第二阶段是误差的反向传播,从输出层到隐含层,最后到输入层,依次调节隐含层到输出层的权重和偏置,输入层到隐含层的权重和偏置
呢么怎样修正权值呢?
这需要将误差逐层向前传递优化整个神经网络的每一个神经元
由此,我们得到权重更新公式
下面我们来完成一个BP神经网络:
import numpy as np
import math
import random
def rand(a , b):
return (b - a) * random.random() + a #random.random()返回随机生成的一个实数,它在[0,1)范围内
#生成一个m * n的矩阵
def make_matrix(m , n , fill = 0.0):
mat = []
for i in range(m):
mat.append([fill] * n)
return mat
#定义sigmoid函数
def sigmoid(x):
return 1.0 / (1.0 + math.exp(-x))
#定义sigmoid导函数 sigmoid具有f'(x) = f(x)(1 - f(x))的性质
def sigmoid_derivate(x):
return x * (1 - x)
class BPNeuralNetwork:
def __init__(self):
self.input_n = 0
self.hidden_n = 0
self.output_n = 0
self.input_cells = []
self.hidden_cells = []
self.output_cells = []
self.input_weights = []
self.output_weights = []
def setup(self , ni , nh , no):
self.input_n = ni + 1
self.hidden_n = nh
self.output_n = no
self.input_cells = [1.0] * self.input_n
self.hidden_cells = [1.0] * self.hidden_n
self.output_cells = [1.0] * self.output_n
self.input_weights = make_matrix(self.input_n , self.hidden_n)
self.output_weights = make_matrix(self.hidden_n , self.output_n)
# 生成随机权值
for i in range(self.input_n):
for h in range(self.hidden_n):
self.input_weights[i][h] = rand(-0.2 , 0.2)
for h in range(self.hidden_n):
for o in range(self.output_n):
self.output_weights[h][o] = rand(-2.0 , 2.0)
#完成前向计算
def predict(self , inputs):
for i in range(self.input_n - 1):
self.input_cells[i] = inputs[i]
for j in range(self.hidden_n):
total = 0.0
#完成矩阵的乘法
for i in range(self.input_n):
total += self.input_cells[i] * self.input_weights[i][j]
self.hidden_cells[j] = sigmoid(total)
for k in range(self.output_n):
total = 0.0
for j in range(self.hidden_n):
total += self.hidden_cells[j] * self.output_weights[j][k]
self.output_cells[k] = sigmoid(total)
return self.output_cells[:]
def back_propagate(self , case , label , learn):
#输入 得到 运算结果
self.predict(case)
#计算输出层的误差
output_deltas = [0.0] * self.output_n
for k in range(self.output_n):
error = label[k] - self.output_cells[k]
output_deltas[k] = sigmoid_derivate(self.output_cells[k]) * error
#计算隐藏层误差
hidden_deltas = [0.0] * self.hidden_n
for j in range(self.hidden_n):
error = 0.0
for k in range(self.output_n):
error += output_deltas[k] * self.output_weights[j][k]
hidden_deltas[j] = sigmoid_derivate(self.hidden_cells[k]) * error
#更新输出层权重
for j in range(self.hidden_n):
for k in range(self.output_n):
self.output_weights[j][k] += learn * output_deltas[k] * self.hidden_cells[j]
#更新隐藏层权重
for i in range(self.input_n):
for j in range(self.hidden_n):
self.input_weights[i][j] += learn * hidden_deltas[j] * self.input_cells[i]
error = 0
for o in range(len(label)):
error += 0.5 * (label[o] - self.output_cells[o]) ** 2
return error
#使用前馈训练模型
def train(self , cases , labels , limit = 100 , learn = 0.05):
for i in range(limit):
error = 0
for i in range(len(cases)):
label = labels[i]
case = cases[i]
error += self.back_propagate(case , label , learn)
pass
def test(self):
#训练BP神经网络
#输入
cases = [
[0 , 0],
[0 , 1],
[1 , 0],
[1 , 1],
]
#正确输出
labels = [[0] , [0.5] , [0.5] , [1]]
self.setup(2 , 5 , 1)
self.train(cases , labels , 10000 , 0.05)
#将测试集输入测试
for case in cases:
print(self.predict(case))
if __name__ == '__main__':
nn = BPNeuralNetwork()
nn.test()
输出为:
可以看到与测试的label接近 可以说说明这个神经网络是有效的