最近给学院老师的一篇论文帮忙改进BP神经网络,由于最后要发表论文,神经网络必须自己手写,搞了几个晚上,总算把基础的BP神经网络写出来,接下来再把老师的改进算法实现就ok了。(当然那代码不能公开了)我这里用的是《MATLAB神经网络43个案例分析》这本书中的语音特征信号数据集。该数据就是普通的结构化数据,分为民歌、古筝、摇滚和流行四类不同音乐类别。(PS:神经网络的学习笔记没时间整理,马上蓝桥杯国赛,比赛结束回学校又是课设,这学期为了机器学习专业课也就是上课听听,还要火线复习把不喜欢的嵌入式专业课给应付过去,估计只有暑假再整理写博客发表了!!!!!)
Python代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2017/5/14 17:13
# @Author : DaiPuWei
# @Site : 计通303实验室
# @File : BPNN.py
# @Software: PyCharm Community Edition
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from copy import deepcopy
from sklearn.preprocessing import MinMaxScaler
class BPNN:
def __init__(self,Train_Data,Train_Label):
"""
这是BPNN类的构造函数
:param Train_Data:训练数据集
:param Train_Label: 训练数据集标记
:param Test_Label: 测试数据集标记
"""
self.Train_Data = Train_Data #训练数据
self.Train_Label = Train_Label #训练数据标签
self.input_n = np.shape(Train_Data)[1] #输入层神经元个数
self.hidden_n = self.input_n - 2 #隐含层神经元个数
self.output_n = np.shape(Train_Label)[1] #输出层神经元个数
self.input_cells = np.zeros(self.input_n) #输入层神经元
self.hidden_cells = np.zeros(self.hidden_n) #隐含层神经元
self.hidden_cells_input = np.zeros(self.hidden_n) #隐含层的输入(不含阈值后进行sigmoid)
self.output_cells = np.zeros(self.output_n) #输出层神经元
self.output_cells_input = np.zeros(self.hidden_n) #输出层的输入(不含阈值后进行sigmoid)
self.input_weights = np.random.randn(self.input_n,self.hidden_n) # 输入层与隐含层之间的权重
self.hidden_weights = np.random.randn(self.hidden_n,self.output_n) # 隐含层与输出层之间的权重
self.hidden_threshold = np.random.randn(1, self.hidden_n) # 隐含层的阈值
self.output_threshold = np.random.randn(1, self.output_n) # 输出层的阈值
self.input_weights_copy = deepcopy(self.input_weights) #输入层与隐含层之间的权重备份
self.hidden_weights_copy = deepcopy(self.hidden_weights) #隐含层与输出层之间的权重备份
self.hidden_threshold_copy = deepcopy(self.hidden_threshold) #隐含层的阈值备份
self.output_threshold_copy = deepcopy(self.output_threshold) #输出层的阈值备份
def Print(self):
print("训练数据集为:")
print(self.Train_Data)
print("训练数据集标记为:")
print(self.Train_Label)
print("测试数据集为:")
print("输入层神经元个数:")
print(self.input_n)
print("隐含层神经元个数:")
print(self.hidden_n)
print("输出层神经元个数:")
print(self.output_n)
print("输入层与隐含层之间的权重的形状:")
print(np.shape(self.input_weights))
print(self.input_weights)
print("隐含层与输出层之间的权重的形状:")
print(np.shape(self.hidden_weights))
print(self.hidden_weights)
def predict(self,input):
"""
这是BP神经网络向前学习传递的函数
:param input: 输入神经元的数据
:return: 更新相应的参数
"""
#输入层输入数据
self.input_cells = deepcopy(input)
#隐含层输出
self.hidden_cells_input = self.input_cells.dot(self.input_weights)
self.hidden_cells = self.hidden_cells_input+self.hidden_threshold
self.hidden_cells = Sigmoid(self.hidden_cells)
#print("隐含层输出为:\n",self.hidden_cells)
#输出层输出
self.output_cells_input = self.hidden_cells.dot(self.hidden_weights)
self.output_cells = self.output_cells_input+self.output_threshold
self.output_cells = Sigmoid(self.output_cells)
#print("输出层输出为:\n", self.output_cells)
return self.output_cells
def back_propagate(self,ideal_output,learn_rate):
"""
这是向后误差传递函数,进行参数调整
:param ideal_output: 理想输出
:param learn_rate: 学习率
"""
# 隐含层与输出层之间的权重的更新
error = ideal_output - self.output_cells
derivative = Sigmoid_Derivative(self.output_cells)
g = derivative*error
self.hidden_weights = self.hidden_weights + self.hidden_cells.T.dot(g)*learn_rate
#输出层的阈值更新
self.output_threshold = self.output_threshold - g*learn_rate
#输入层与隐含层之 间的权重更新
e = g.dot(self.hidden_weights.T)*Sigmoid_Derivative(self.hidden_cells)
self.input_weights = self.input_weights + learn_rate*(self.input_cells.T.dot(e))
#隐含层的阈值更新
self.hidden_threshold = self.hidden_threshold - e*learn_rate
def reset(self):
"""
这是BPNN的重置函数,是在改变一次迭代过程后回复相关参数的初始值
"""
self.input_weights = deepcopy(self.input_weights_copy) # 输入层与隐含层之间的权重备份
self.hidden_weights = deepcopy(self.hidden_weights_copy) # 隐含层与输出层之间的权重备份
self.hidden_threshold = deepcopy(self.hidden_threshold_copy) # 隐含层的阈值备份
self.output_threshold = deepcopy(self.output_threshold_copy) # 输出层的阈值备份
def train_batch(self,input,output,learn_rate):
"""
这是对一次一组数据进行训练的函数
:param input: 组输入数据
:param output: 输入数据标记
:param learn_rate: 学习率
"""
input = input.reshape(1, len(input))
output = output.reshape(1, len(output))
self.output_cells = self.predict(input)
self.back_propagate(output,learn_rate)
def train_dataset(self,inputs,outputs,learn_rate):
"""
这是对一个数据集进行一次训练的函数
:param input: 输入数据集
:param output: 输入数据集对应的标记集
:param learn_rate: 学习率
"""
for j in range(len(inputs)):
self.train_batch(inputs[j],outputs[j],learn_rate)
def train(self,limitation,learn_rate):
"""
这是BP神经网络的训练函数
:param limitaion: 迭代次数
:param learn_rate: 学习率
"""
for j in range(limitation):
self.train_dataset(self.Train_Data,self.Train_Label,learn_rate)
def test(self,Test_Data):
"""
这是BP神经网络测试函数
:param Test_Data: 测试数据
"""
predict_labels = []
for i in range(len(Test_Data)):
input = Test_Data[i]
predict_output = self.predict(input)
#print("预测输出为:\n",predict_output)
index = np.argmax(predict_output)
#print(index)
tmp = [0,0,0,0]
#print("实际输出为:\n",outputs[i])
tmp[index] = 1
predict_labels.append(tmp)
predict_labels = np.array(predict_labels)
return predict_labels
def Load_Data(path):
"""
这是导入数据的函数
:param path: 数据文件的路径
:return: 数据集
"""
data = []
label = []
with open(path) as f:
for line in f.readlines():
str = line.strip().split("\t")
tmp = []
for i in range(1,len(str)):
tmp.append(float(str[i]))
data.append(tmp)
if 1 == int(str[0]):
label.append([1,0,0,0])
elif 2 == int(str[0]):
label.append([0,1,0,0])
elif 3 == int(str[0]):
label.append([0,0,1,0])
else:
label.append([0,0,0,1])
data = np.array(data).reshape(len(data),len(data[0]))
label = np.array(label)
return data,label
def Sigmoid(x):
"""
这是S型激活函数计算公式
:param x: 需要进行计算的数据
:return: S型激活函数的函数值
"""
function = 1.0 / (1 + np.exp(-x))
return function
def Sigmoid_Derivative(x):
"""
这是S型激活函数的导数计算公式
:param x: 需要进行计算的数据
:return: S型激活函数的导数的函数值
"""
f = Sigmoid(x)
derivative = f*(1-f)
return derivative
def run_main():
"""
这是主函数
"""
#导入数据
path = "./data.txt"
Data,Label = Load_Data(path)
#数据归一化
Data = MinMaxScaler().fit_transform(Data)
#数据集分割成训练数据与测试数据
Train_Data,Test_Data,Train_Label,Test_Label = train_test_split(Data,Label,test_size=1/4,random_state=10)
#构建BPNN
bpnn = BPNN(Train_Data,Train_Label)
# 解决画图是的中文乱码问题
mpl.rcParams['font.sans-serif'] = [u'simHei']
mpl.rcParams['axes.unicode_minus'] = False
#迭代次数增加,测试神经网络的准确性
limitations = np.ones(100000)
print(limitations)
Limitations = np.cumsum(limitations)
print(Limitations)
bpnn_accuracy = []
bpnn_accuracy1 = []
bpnn_accuracy2 = []
bpnn_accuracy3 = []
bpnn_accuracy4 = []
Test_Data1 = Test_Data[np.where((Test_Label == np.array([1, 0, 0, 0])).all(1))]
Test_Data2 = Test_Data[np.where((Test_Label == np.array([0, 1, 0, 0])).all(1))]
Test_Data3 = Test_Data[np.where((Test_Label == np.array([0, 0, 1, 0])).all(1))]
Test_Data4 = Test_Data[np.where((Test_Label == np.array([0, 0, 0, 1])).all(1))]
Test_Label1 = Test_Label[np.where((Test_Label == np.array([1, 0, 0, 0])).all(1))]
Test_Label2 = Test_Label[np.where((Test_Label == np.array([0, 1, 0, 0])).all(1))]
Test_Label3 = Test_Label[np.where((Test_Label == np.array([0, 0, 1, 0])).all(1))]
Test_Label4 = Test_Label[np.where((Test_Label == np.array([0, 0, 0, 1])).all(1))]
for i in range(len(limitations)):
limitation = int(limitations[i])
bpnn.train(limitation,0.1)
print("迭代次数为limitation = ",int(Limitations[i]))
predict_outputs = bpnn.test(Test_Data)
predict_outputs1 = bpnn.test(Test_Data1)
predict_outputs2 = bpnn.test(Test_Data2)
predict_outputs3 = bpnn.test(Test_Data3)
predict_outputs4 = bpnn.test(Test_Data4)
accuracy = accuracy_score(Test_Label,predict_outputs)
accuracy1 = accuracy_score(Test_Label1, predict_outputs1)
accuracy2 = accuracy_score(Test_Label2, predict_outputs2)
accuracy3 = accuracy_score(Test_Label3, predict_outputs3)
accuracy4 = accuracy_score(Test_Label4, predict_outputs4)
bpnn_accuracy.append(accuracy)
bpnn_accuracy1.append(accuracy1)
bpnn_accuracy2.append(accuracy2)
bpnn_accuracy3.append(accuracy3)
bpnn_accuracy4.append(accuracy4)
print("bpnn的数据总精度是:",accuracy)
print("bpnn的第一类数据精度是:", accuracy1)
print("bpnn的第二类数据精度是:", accuracy2)
print("bpnn的第三类数据精度是:", accuracy3)
print("bpnn的第四类数据精度是:", accuracy4)
plt.plot(Limitations,bpnn_accuracy)
plt.xlabel("迭代次数")
plt.ylabel("精度")
plt.title("不同迭代次数下的精度")
plt.grid(True)
plt.savefig("learn_rate=0.1不同迭代次数的精度.jpg")
#plt.show()
#plt.close()
plt.subplot(221)
plt.plot(Limitations, bpnn_accuracy1)
plt.ylabel("精度")
plt.title("第一类数据精度")
plt.grid(True)
plt.subplot(222)
plt.plot(Limitations, bpnn_accuracy2)
plt.title("第二类数据精度")
plt.grid(True)
plt.subplot(223)
plt.plot(Limitations, bpnn_accuracy3)
plt.ylabel("精度")
plt.xlabel("迭代次数")
plt.title("第三类数据精度")
plt.grid(True)
plt.subplot(224)
plt.plot(Limitations, bpnn_accuracy4)
plt.xlabel("迭代次数")
plt.title("第四类数据精度")
plt.grid(True)
plt.subplots_adjust(hspace=0.3)
plt.savefig("learn_rate=0.1不同迭代次数的各类数据精度.jpg")
# 学习率增加,测试神经网络的准确性
bpnn_accuracy = []
bpnn_accuracy1 = []
bpnn_accuracy2 = []
bpnn_accuracy3 = []
bpnn_accuracy4 = []
learn_rates = np.array([0.001,0.005,0.01,0.05,0.1,0.2,0.3,0.5,0.7])
for learn_rate in learn_rates:
bpnn.reset()
bpnn.train(5000,learn_rate)
print("学习率为learn_rate = ", learn_rate)
predict_outputs = bpnn.test(Test_Data)
predict_outputs1 = bpnn.test(Test_Data1)
predict_outputs2 = bpnn.test(Test_Data2)
predict_outputs3 = bpnn.test(Test_Data3)
predict_outputs4 = bpnn.test(Test_Data4)
accuracy = accuracy_score(Test_Label,predict_outputs)
accuracy1 = accuracy_score(Test_Label1, predict_outputs1)
accuracy2 = accuracy_score(Test_Label2, predict_outputs2)
accuracy3 = accuracy_score(Test_Label3, predict_outputs3)
accuracy4 = accuracy_score(Test_Label4, predict_outputs4)
bpnn_accuracy.append(accuracy)
bpnn_accuracy1.append(accuracy1)
bpnn_accuracy2.append(accuracy2)
bpnn_accuracy3.append(accuracy3)
bpnn_accuracy4.append(accuracy4)
print("bpnn的数据总精度是:",accuracy)
print("bpnn的第一类数据精度是:", accuracy1)
print("bpnn的第二类数据精度是:", accuracy2)
print("bpnn的第三类数据精度是:", accuracy3)
print("bpnn的第四类数据精度是:", accuracy4)
plt.plot(learn_rates,bpnn_accuracy)
plt.xlabel("学习率")
plt.ylabel("精度")
plt.title("不同学习率下的精度")
plt.grid(True)
plt.savefig("limitation=15000"+"不同学习率下的精度.jpg")
#plt.show()
plt.close()
plt.subplot(221)
plt.plot(learn_rates, bpnn_accuracy1)
plt.ylabel("精度")
plt.title("第一类数据精度")
plt.grid(True)
plt.subplot(222)
plt.plot(learn_rates, bpnn_accuracy2)
plt.title("第二类数据精度")
plt.grid(True)
plt.subplot(223)
plt.plot(learn_rates, bpnn_accuracy3)
plt.xlabel("学习率")
plt.ylabel("精度")
plt.title("第三类数据精度")
plt.grid(True)
plt.subplot(224)
plt.plot(learn_rates, bpnn_accuracy4)
plt.xlabel("学习率")
plt.title("第四类数据精度")
plt.grid(True)
plt.subplots_adjust(hspace=0.3)
plt.savefig("limitation=5000" + "不同学习率下的各类数据精度.jpg")
if __name__ == '__main__':
run_main()
下面是学习率为0.1时不同迭代次数下总体分类误差:
下面是学习率为0.1时不同迭代次数下4类语音数据的分类误差:
下面是迭代次数为5000是时不同学习率下总体分类误差:
下面是迭代次数为5000是时不同学习率下4类语音数据的分类误差: