激励函数 隐含层tanh;输出层sigmoid;
目标函数 MSE准则
训练集
代码思路
readData.py 从txt中读取数据集,并把标签转化成one-hot矩阵
import pandas as pd
import numpy as np
class readData(object):
def __init__(self, io='../数据集.xlsx'):
"""
io:数据集路径 excel格式
"""
df = pd.read_excel(io='../数据集.xlsx')
all_data = df.values # 所有数据 特征+标签
permutation = np.random.permutation(all_data.shape[0])
all_data = all_data[permutation, :]
self.data = all_data[:, 0:3] # 提取特征集
self.label = all_data[:, 3] # 提取标签
def get_train_data(self):
train_data = np.hstack((np.ones((self.data.shape[0], 1)), self.data)) # 每个样本的特征最前面都插入1维阈值 1(偏置)
train_label = self.label.reshape(-1).astype(int) - 1 # 类别标签从1-3变为0-2,便于转成onw-hot矩阵进行计算
# print(train_label)
train_y = np.eye(3)[train_label] # one-hot向量矩阵
return train_data, train_y
stimulateFunc.py 激励函数及其导数
import numpy as np
class stimulateFunc(object):
def __init__(self):
"""初始化函数 没有任何操作"""
pass
def sigmoid(self, x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(self, x):
return self.sigmoid(x) * (1 - self.sigmoid(x))
def tanh(self, x):
return np.tanh(x)
def tanh_derivative(self, x):
return 1 - np.power(self.tanh(x), 2)
inputLayer.py 输入层
import numpy as np
from stimulateFunc import stimulateFunc
class inputLayer(object):
def __init__(self, input_num=4, hidden_num=3, learning_rate=0.1):
"""
搭建神经网络输入层到隐含层的映射
采用tanh函数激励
需要参数:
X:输入的特征矩阵
input_num:输入数据维度
hidden_num:隐含层节点数
learning_rate:学习率/更新步长
W_ih:权重矩阵
Y_h:激活后输出到隐含层的特征矩阵
"""
self.X = [] # 输入矩阵
self.input_num = input_num # 需要注意,输入要多一个偏置项
self.hidden_num = hidden_num
self.learning_rate = learning_rate
self.W_ih = np.random.rand(self.input_num, self.hidden_num) # 随机初始化权重 [0,1)之间 包括偏置的权重
self.net = [] # 输入矩阵*当前权重所得节点
self.Y_h = []
def forward(self, X): # X:输入矩阵(特征+1维偏置)
"""前向传播"""
self.X = X
self.net = np.dot(self.X, self.W_ih) # 乘上权重矩阵
self.Y_h = stimulateFunc().tanh(self.net) # 激励结果
return self.Y_h # 返回激励结果
def backward(self, delta):
"""反向传播"""
"""delta:后一层收集的误差"""
temp = stimulateFunc().tanh_derivative(self.net)
d_W_ih = np.dot(self.X.T, (delta*temp)) # 计算更新量
self.W_ih = self.W_ih + self.learning_rate * d_W_ih # 更新权重
return self.W_ih # 返回更新后的权重
hiddenLayer.py 隐含层
import numpy as np
from stimulateFunc import stimulateFunc
class hiddenLayer(object):
def __init__(self, hidden_num=3, output_num=3, learning_rate=0.1):
"""
搭建神经网络隐含层到输出层的映射
采用sigmoid函数激励
需要参数:
Y:输入层传进来的特征矩阵
hidden_num:隐含层节点数
output_num:输出层节点数
learning_rate:学习率/更新步长
W_ho:权重矩阵
Z_o:输出到输出层的特征矩阵
"""
self.hidden_num = hidden_num # 获得隐含层节点数
self.output_num = output_num
self.learning_rate = learning_rate
self.W_ho = np.random.rand(self.hidden_num, self.output_num) # 随机初始化权重 [0,1)之间 包括偏置的权重
self.net = []
self.Z_o = []
def forward(self, Y): # Y:上一层输入矩阵
"""前向传播"""
self.Y = Y
self.net = np.dot(Y, self.W_ho) # 乘上权重矩阵
# print(temp)
self.Z_o = stimulateFunc().sigmoid(self.net) # 激励结果
return self.Z_o # 返回激励结果
def backward(self, delta):
"""反向传播"""
"""delta:后一层收集的误差"""
temp = stimulateFunc().sigmoid_derivative(self.net)
delta_ho = delta * temp
d_W_ho = np.dot(self.Y.T, delta_ho) # 计算更新量
self.W_ho = self.W_ho + self.learning_rate * d_W_ho # 更新权重
back_delta = np.dot(delta_ho, self.W_ho.T)
return back_delta # 返回传到前一层的误差
BP_model.py 三层前向神经网络
超参数 epoch:迭代次数
learning_rate:学习率
hidden_num:隐含层节点
batch_size:批量更新大小
import numpy as np
from inputLayer import inputLayer
from hiddenLayer import hiddenLayer
class bp_model(object):
def __init__(self, X, y, epoch, learning_rate, batch_size, hidden_num):
"""
X:特征
y:标签(one-hot矩阵
epoch:迭代次数
learning_rate:更新步长/学习率
batch_size:批量更新数。为1则为单样本更新
hidden_num:隐含层节点数
"""
self.X = X
self.y = y
self.epoch = epoch
self.learning_rate = learning_rate
self.batch_size = batch_size
self.hidden_num = hidden_num
self.input_num = X.shape[1]
self.output_num = y.shape[1]
def train(self):
X_ = self.X
Y_ = self.y
loss_ = []
acc_ = []
epoch_ = 0
bp = BP_once(self.input_num, self.output_num, self.hidden_num, self.learning_rate) # 搭建神经网络
for i in range(self.epoch):
for j in range(X_.shape[0] // self.batch_size): # 批量更新大小
x_ = X_[j * self.batch_size:(j + 1) * self.batch_size, :]
y_ = Y_[j * self.batch_size:(j + 1) * self.batch_size, :]
bp.training(x_, y_)
acc = bp.acc(X_, Y_)
loss = bp.MSEloss(X_, Y_)
acc_.append(acc)
loss_.append(loss)
# if i % 100 == 0:
# print('epoch=', i)
# print('loss = %.10f, acc=%.1f' % (loss, acc))
if acc == 100:
epoch_ = i # 记录下训练完全正确的迭代次数
if loss <= 0.01:
print('>>>>>loss has already down to 0.01! Training Terminated!<<<<<')
break
return loss_, acc_, epoch_
class BP_once(object):
def __init__(self, input_num=4, output_num=3, hidden_num=3, learning_rate=0.01):
"""
构造三层前向神经网络
进行一次反向传播更新权重
误差准则 MSE
所需参数:
iteration_num:迭代次数
learning_rate:更新步长/学习率
hidden_num:隐含层节点数
"""
self.input_num = input_num
self.hidden_num = hidden_num
self.output_num = output_num
self.learning_rate = learning_rate
# 搭建神经网络
self.input = inputLayer(self.input_num, self.hidden_num, self.learning_rate)
self.hidden = hiddenLayer(self.hidden_num, self.output_num, self.learning_rate)
# 误差函数 MSE准则
def MSEloss(self, X, Y):
return np.sum(np.power(self.predict(X) - Y, 2) / 2)
# 预测准确率
def acc(self, X, Y):
count = (np.sum(np.argmax(Y, axis=1) == np.argmax(self.predict(X), axis=1)))
return count / X.shape[0] * 100
# 前向传播获得预测情况
def predict(self, X):
x = X
y = self.input.forward(x)
z = self.hidden.forward(y)
return z
# 反向传播更新权重
def update(self, X, y):
z = self.predict(X) # 一次前向传播
delta = y - z # 计算最后一层误差
delta = self.hidden.backward(delta) # 向前传播误差
self.input.backward(delta)
return 1
def training(self, X, y):
"""进行一次前向-反向传播"""
# self.model_builder()
self.update(X, y)
# loss = self.MSEloss()
# acc = self.acc()
return 1
main.py 主函数,绘制acc和loss图像
import numpy as np
from BP_model import bp_model
from readData import readData
import time
import matplotlib as mpl
import matplotlib.pyplot as plt
if __name__ == '__main__':
np.random.seed(10)
data = readData()
X, y = data.get_train_data()
hidden_num = [3, 5, 10, 20]
batch_size = [1, 5, 10]
learning_rate = [0.01, 0.05, 0.1, 1]
running_time = []
stop_epoch = []
each_loss = []
each_acc = []
# """开始计算运行时间"""
# for i in range(len(learning_rate)):
#
# start = time.time()
# my_model = bp_model(X, y, epoch=5000, batch_size=batch_size[0],
# learning_rate=learning_rate[i], hidden_num=hidden_num[2])
# loss, acc, full_epoch = my_model.train()
# each_acc.append(acc[-1])
# each_loss.append(loss[-1])
# end = time.time()
# running_time.append(end - start)
# stop_epoch.append(full_epoch)
# # print('time cost : %.5f sec' % running_time[i])
# # print('epoch reach to %d, acc=100' % stop_epoch[i])
#
# print('time cost : ', running_time)
# print('stop_epoch: ', stop_epoch)
# print('loss: ', each_loss)
# print('acc: ', each_acc)
# # print(stop_epoch)
"""分别绘制acc和loss图像"""
my_model = bp_model(X, y, epoch=5000, batch_size=batch_size[1],
learning_rate=learning_rate[2], hidden_num=hidden_num[2])
loss, acc, full_epoch = my_model.train()
plt.figure(1)
plt.plot(loss)
plt.grid(True) # 增加格点
plt.axis('tight') # 坐标轴适应数据量 axis 设置坐标轴
plt.xlabel("epoch") # x轴label
plt.title('LOSS')
# plt.scatter(x=0:len(last_loss), y=last_loss, color='red')
plt.figure(2)
plt.plot(acc)
plt.grid(True) # 增加格点
plt.axis('tight') # 坐标轴适应数据量 axis 设置坐标轴
plt.title('ACC')
plt.xlabel("epoch") # x轴label
plt.show()