应用背景:
根据提供的一个鸢尾花数据集,通过数据集提供的花萼长度、花萼宽度、花瓣长度、花瓣宽度和标签来进行训练,得到一个适宜的权值来判断鸢尾花属于什么品质
算法优化
这里使用python作为主要编程语言进行优化,与一般的写法不同,python除了代码简单可视化以外,还拥有对矩阵算法的优化,使训练数据集的时间大大优化,避免了BP算法训练时间慢的缺点,有时间的话,我会写一个JAVA和C++的BP鸢尾花训练,可以很明显比较出python处理矩阵算法的时间快,代码简单的特点
鸢尾花数据集
由于鸢尾花数据集是神经网络学习的一个常用数据集,在网上就可以找到很多此数据集链接,有需要的可以联系
BP算法公式推导
代码展示
import numpy as np
import pandas as pd
# 格式
flowerLables = {0: 'Iris-setosa',
1: 'Iris-versicolor',
2: 'Iris-virginica'}
# 读取数据
def read():
# 读取csv数据
csv_data = pd.read_csv(r"./Iris.csv").values
# 随机打乱数据
np.random.shuffle(csv_data)
# 取数据集
inputs = csv_data[:, 1:5]
# 获取标签
targets = csv_data[:, -1]
# 将标签转码为one-hot形式
t = []
for i in range(targets.shape[0]):
if csv_data[i][-1] == flowerLables[0]:
t.append([1, 0, 0])
elif csv_data[i][-1] == flowerLables[1]:
t.append([0, 1, 0])
elif csv_data[i][-1] == flowerLables[2]:
t.append([0, 0, 1])
targets = np.array(t)
# 转化格式
inputs = inputs.astype("float64")
targets = targets.astype("float64")
return inputs, targets
class BP:
# 构造函数
def __init__(self, ni, nh, no):
self.ni = ni
self.nh = nh
self.no = no
self.V = (np.random.random([ni + 1, nh]) * 2 - 1) * 0.2
self.W = (np.random.random([nh + 1, no]) * 2 - 1) * 2
# 激活函数
def sigmoid(self, x):
return 1.0 / (1 + np.exp(-x))
# 激活函数求导
def dsigmoid(self, x):
return x * (1 - x)
# 正向传播
def updata(self, inputs):
# 插入x的偏正值
inputs = np.column_stack((np.ones([inputs.shape[0], 1]), inputs))
# 正向传播入隐藏层
net1 = np.dot(inputs, self.V)
out1 = self.sigmoid(net1)
# 插入out1的偏正值
out1 = np.column_stack((np.ones([out1.shape[0], 1]), out1))
# 正向传播入输出层
net2 = np.dot(out1, self.W)
out2 = self.sigmoid(net2)
return out1, out2
# 反向传播
def backPropage(self, inputs, targets, out1, out2, lr):
# 计算输出层误差
out2_delta = (out2 - targets) * self.dsigmoid(out2)
# 计算W误差
W_delta = out1.T.dot(out2_delta) * lr
# 计算隐藏层误差
out1_delta = out2_delta.dot(self.W.T) * self.dsigmoid(out1)
# 计算V误差
inputs = np.column_stack((np.ones([inputs.shape[0], 1]), inputs))
V_delta = inputs.T.dot(out1_delta[:, 1:]) * lr
# 更新权值
self.V = self.V - V_delta
self.W = self.W - W_delta
# 训练
def train(self, inputs, targets):
# 学习率
lr = 0.05
# 迭代次数
epoch = 20000
# 训练
for i in range(epoch):
# 正向传播
out1, out2 = self.updata(inputs)
# 反向传播
self.backPropage(inputs, targets, out1, out2, lr)
#测试
def test(self, inputs, targets):
#获取测试的值
out1, out2 = self.updata(inputs)
#找到测试和实际值的最大数的下标
result_inputs = out2.argmax(axis=1)
result_targets = targets.argmax(axis=1)
count = 0
for i in range(inputs.shape[0]):
print(f"数据 {inputs[i]} -> 预测{flowerLables[result_inputs[i]]} 实际{flowerLables[result_targets[i]]}")
count += (result_targets[i] == result_inputs[i])
#正确率
accuracy = float(count / len(inputs))
print(f'正确率为: {accuracy * 100}%')
# 主函数
def Iris():
# 获取数据
inputs, targets = read()
# 创建算法
bp = BP(inputs.shape[1], 7, targets.shape[1])
# 训练(前100个数据)
bp.train(inputs[:100], targets[:100])
# 测试(后50个数据)
bp.test(inputs[:50], targets[:50])
if __name__ == '__main__':
Iris()