TA的每日心情 | 无聊 2021-4-7 11:23 |
---|
签到天数: 27 天 连续签到: 1 天 [LV.4]偶尔看看III
|
BP网络(Back Propagation),是1986年由Rumelhart和McCelland为首的科学家小组提出,是一种按误差逆传播算法训练的多层前馈网络,是目前应用最广泛的神经网络模型之一。BP网络能学习和存贮大量的输入-输出模式映射关系,而无需事前揭示描述这种映射关系的数学方程。了解BP神经网络的工作过程,对入门人工神经网络有很大帮助。 本文通过python编程实现含有一层和两层隐藏层的神经网络模型,实现正弦函数预测。
采用80个点进行训练。这个可以自己修改。
# -*- coding: utf-8 -*-
"""
Created on Tue May 15 16:39:55 2018
@author: Administrator
"""
import math
import random
import numpy
import matplotlib.pyplot as plt
random.seed(0) # 使random函数每一次生成的随机数值都相等
def rand(a, b):
return (b - a) * random.random() + a # 生成a到b的随机数
def make_matrix(m, n, fill=0.0): # 创建一个指定大小的矩阵
mat = []
for i in range(m):
mat.append([fill] * n)
return mat
# 定义tanh函数和它的导数
def tanh(x):
return numpy.tanh(x)
def tanh_derivate(x):
return 1 - numpy.tanh(x) * numpy.tanh(x) # tanh函数的导数
class BPNeuralNetwork:
def __init__(self): # 初始化变量
self.input_n = 0
self.hidden1_n = 0
self.output_n = 0
self.input_cells = []
self.hidden1_cells = []
self.output_cells = []
self.input_weights = []
self.hidden_weights = []
self.output_weights = []
self.input_correction = []
self.hidden_correction = []
self.output_correction = []
# 三个列表维护:输入层,隐含层,输出层神经元
def setup(self, ni, nh1, no):
self.input_n = ni + 1 # 输入层+偏置项
self.hidden1_n = nh1 + 1 # 隐含层 1
self.output_n = no # 输出层
# 初始化神经元
self.input_cells = [1.0] * self.input_n
self.hidden1_cells = [1.0] * self.hidden1_n
self.output_cells = [1.0] * self.output_n
# 初始化连接边的边权
self.input_weights = make_matrix(self.input_n, self.hidden1_n) # 邻接矩阵存边权:输入层->隐藏层
self.output_weights = make_matrix(self.hidden1_n, self.output_n) # 邻接矩阵存边权:隐藏层->输出层
# 初始化bias
self.h1_b = make_matrix(self.hidden1_n, 1)
self.o_b = make_matrix(self.output_n, 1)
# 随机初始化边权:为了反向传导做准备--->随机初始化的目的是使对称失效
for i in range(self.input_n):
for h in range(self.hidden1_n):
self.input_weights[h] = rand(-1, 1) # 由输入层第i个元素到隐藏层1第j个元素的边权为随机值
for h in range(self.hidden1_n):
for o in range(self.output_n):
self.output_weights[h][o] = rand(-1, 1) # 由隐藏层2第i个元素到输出层第j个元素的边权为随机值
# 随机初始化bias
for i in range(self.hidden1_n):
self.h1_b = rand(-1, 1)
for i in range(self.output_n):
self.o_b = rand(-1, 1)
# 保存校正矩阵,为了以后误差做调整
self.input_correction = make_matrix(self.input_n, self.hidden1_n)
self.output_correction = make_matrix(self.hidden1_n, self.output_n)
# 输出预测值
def predict(self, inputs):
# 对输入层进行操作转化样本
for i in range(self.input_n - 1):
self.input_cells = inputs # n个样本从0~n-1
# 计算隐藏层的输出,每个节点最终的输出值就是权值*节点值的加权和
for j in range(self.hidden1_n):
total = 0.0
for i in range(self.input_n):
total += self.input_cells * self.input_weights[j]
# 此处为何是先i再j,以隐含层节点做大循环,输入样本为小循环,是为了每一个隐藏节点计算一个输出值,传输到下一层
self.hidden1_cells[j] = tanh(total - self.h1_b[j]) # 此节点的输出是前一层所有输入点和到该点之间的权值加权和
for k in range(self.output_n):
total = 0.0
for j in range(self.hidden1_n):
total += self.hidden1_cells[j] * self.output_weights[j][k]
self.output_cells[k] = tanh(total - self.o_b[k]) # 获取输出层每个元素的值
return self.output_cells[:] # 最后输出层的结果返回
# 反向传播算法
def back_propagate(self, case, label, learn, correct):
self.predict(case) # 对实例进行预测
output_deltas = [0.0] * self.output_n # 初始化矩阵
for o in range(self.output_n):
error = label[o] - self.output_cells[o] # 正确结果和预测结果的误差:0,1,-1
output_deltas[o] = tanh_derivate(self.output_cells[o]) * error # 误差稳定在0~1内
# 隐含层误差
hidden1_deltas = [0.0] * self.hidden1_n
for h in range(self.hidden1_n):
error = 0.0
for o in range(self.output_n):
error += output_deltas[o] * self.output_weights[h][o]
hidden1_deltas[h] = tanh_derivate(self.hidden1_cells[h]) * error
# 反向传播算法求W
# 更新隐藏层->输出权重
for h2 in range(self.hidden1_n):
for o in range(self.output_n):
change = output_deltas[o] * self.hidden1_cells[h2]
# 调整权重:上一层每个节点的权重学习*变化+矫正率
self.output_weights[h2][o] += learn * change + correct * self.output_correction[h2][o]
self.output_correction[h2][o] = change
# 更新输入->隐藏层的权重
for i in range(self.input_n):
for h in range(self.hidden1_n):
change = hidden1_deltas[h] * self.input_cells
self.input_weights[h] += learn * change + correct * self.input_correction[h]
self.input_correction[h] = change
# 更新bias
for o in range(self.output_n):
self.o_b[o] = self.o_b[o] - learn * output_deltas[o]
for h1 in range(self.hidden1_n):
self.h1_b[h1] = self.h1_b[h1] - learn * hidden1_deltas[h1]
error = 0.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=10000, learn=0.05, correct=0.1):
for i in range(limit): # 设置迭代次数
error = 0.0
for j in range(len(cases)): # 对输入层进行访问
label = labels[j]
case = cases[j]
error += self.back_propagate(case, label, learn, correct) # 样例,标签,学习率,正确阈值
def test(self): # 学习正弦函数
cases = [] # 采样训练样
for i in range(0, 80, 1):
cases.append([i * (2 * math.pi / 80)])
labels = numpy.sin(cases)
NUM_neurons=10
self.setup(1, NUM_neurons, 1) # 初始化神经网络:输入层,隐藏层,输出层元素个数
train_num = 800
lr=0.08
self.train(cases, labels, train_num, lr, 0.1) # 50个训练
test = [] # 训练范围外的数据
yables = []
for i in range(0, 30, 1):
test.append([i * (2 * math.pi / 30)])
for case in test:
yables.append(self.predict(case))
x = numpy.arange(0.0, 2.0, 0.01)
fig=plt.figure()
ax = fig.add_subplot(1, 1, 1) # 获得Axes对象
ax.set_title('epochs:'+str(train_num)+',lr:'+str(lr)+',neurons_num:'+str(NUM_neurons)) # 设置标题
l1, = plt.plot(x * math.pi, numpy.sin(x * math.pi), color='red')
l2, = plt.plot(test, yables, color='green')
point1 = plt.scatter(test, yables, color='blue', s=5)
plt.legend(handles=[l1, l2, point1], labels=['original data', 'test data', 'point=30'], loc='best')
plt.xticks([0, numpy.pi / 2, numpy.pi, 3 * numpy.pi / 2, 2 * numpy.pi],
[r'$0$', r'$\pi/2$', r'$\pi$', r'$\pi*3/2$', r'$2\pi$'])
plt.show()
if __name__ == '__main__':
nn = BPNeuralNetwork()
nn.test()
|
|