《机器学习》实验三:利用BP神经网络实现鲍鱼的性别分类
《机器学习》实验三:利用BP神经网络实现鲍鱼的性别分类
《机器学习》实验三:利用BP神经网络实现鲍鱼的性别分类
《机器学习》实验三:利用BP神经网络实现鲍鱼的性别分类
实验目的
- 掌握BP神经网络的基本原理;
- 了解TensorFlow框架。
实验原理
- BP神经网络
BP(Back Propagation)神经网络是一种按照误差反向传播算法训练的多层前馈网络,也是目前应用最广泛的神经网络模型之一。BP神经网络包含多层神经元,如图1所示。输入层的神经元负责接受外界发来的各种信息,并将信息传递给中间层神经元,中间隐含层神经元负责将接收到的信息进行处理变换,根据需求处理信息,实际应用中可将中间隐含层设置为一层或者多层隐含层结构,并通过最后一层的隐含层将信息传递到输出层。
图1 BP神经网络结构
BP神经网络的计算过程由正向计算过程和反向计算过程组成。正向传播过程,输入模式从输入层经隐单元层逐层处理,并转向输出层,每一层神经元的状态只影响下一层神经元的状态。如果在输出层不能得到期望的输出,则转入反向传播,将误差信号沿原来的连接通路返回,通过修改各神经元的权值,使得误差信号最小。当输出的误差减小到期望程度或者预先设定的学习迭代次数时,训练结束,BP神经网络完成学习。
2. TensorFlow框架
TensorFlow是由Google团队开发的深度学习框架之一,它是一个完全基于Python语言设计的开源的软件。TensorFlow的初衷是以最简单的方式实现机器学习和深度学习的概念,它结合了计算代数的优化技术,使它便计算许多数学表达式。
TensorFlow可以训练和运行深度神经网络,它能应用在许多场景下,比如,图像识别、手写数字分类、递归神经网络、单词嵌入、自然语言处理、视频检测等等。TensorFlow可以运行在多个CPU或GPU上,同时它也可以运行在移动端操作系统上(如安卓、IOS 等),它的架构灵活,具有良好的可扩展性,能够支持各种网络模型(如OSI七层和TCP/IP四层)。
TensorFlow这个词由Tensor和Flow两个词组成,这两者是TensorFlow最基础的要素。Tensor代表张量(也就是数据),它的表现形式是一个多维数组;而Flow意味着流动,代表着计算与映射,它用于定义操作中的数据流。
实验内容与要求
- 数据预处理;
- 构造BP神经网络模型;
- 训练模型,迭代计算训练损失、测试损失和测试集的准确率;
- 绘制图像。
实验器材(设备、元器件)
处理器:Intel® Core™ i5-8300H CPU @ 2.30GHz
Python 3.9.0
matplotlib 3.4.0
tensorflow 2.11.0rc1
xlrd 1.2.0
实验步骤
- 数据预处理
给定的训练集和测试集是data文件,先把它们改为xlsx文件。设计一个LoadData函数,输入为abalone_train.xlsx和abalone_test.xlsx的文件路径,再调用Python第三方库——xlrd,将当中的数据转换为列表x_train、y_train、x_test、y_test,最后返回这四个列表。代码如下:
def LoadData(trainpath, testpath):
file_train_path = trainpath
file_train_xlsx = xd.open_workbook(file_train_path)
file_train_sheet = file_train_xlsx.sheet_by_name('Sheet1')
x_train = []
y_train = []
for row in range(file_train_sheet.nrows):
x_data = []
for col in range(file_train_sheet.ncols):
if col == 0:
if file_train_sheet.cell_value(row, col) == 'M':
y_train.append(1)
elif file_train_sheet.cell_value(row, col) == 'F':
y_train.append(-1)
else:
y_train.append(0)
else:
x_data.append(file_train_sheet.cell_value(row, col))
x_train.append(list(x_data))
file_test_path = testpath
file_test_xlsx = xd.open_workbook(file_test_path)
file_test_sheet = file_test_xlsx.sheet_by_name('Sheet1')
x_test = []
y_test = []
for row in range(file_test_sheet.nrows):
x_data = []
for col in range(file_test_sheet.ncols):
if col == 0:
if file_test_sheet.cell_value(row, col) == 'M':
y_test.append(1)
elif file_test_sheet.cell_value(row, col) == 'F':
y_test.append(-1)
else:
y_test.append(0)
else:
x_data.append(file_test_sheet.cell_value(row, col))
x_test.append(list(x_data))
# print(x_train)
# print(y_train)
# print(x_test)
# print(y_test)
# 将特征值的类型转换为tensor类型,避免后面的矩阵乘法报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)
return x_train, x_test, y_train, y_test
- 构造BP神经网络模型
在BP.py中构造一个BP神经网络类。类中包含BP神经网络类的构造函数、训练函数和测试函数。构造函数定义了输入层神经元个数、隐藏层神经元个数、输出层层神经元个数和正则化系数等参数,还定义了损失函数,均方误差加入L2正则化。训练函数定义了训练数据集及其标签、测试数据集及其标签、学习率、训练趟数、样本规模等超参数。测试函数用于计算测试集的测试精度。代码如下:
import numpy as np
import tensorflow as tf
from sklearn.metrics import accuracy_score
class BP(object):
def __init__(self, input_n, hidden_n, output_n, lambd):
"""
这是BP神经网络类的构造函数
:param input_n:输入层神经元个数
:param hidden_n: 隐藏层神经元个数
:param output_n: 输出层神经元个数
:param lambd: 正则化系数
"""
self.Train_Data = tf.placeholder(tf.float64, shape=(None, input_n), name='input_dataset') # 训练数据集
self.Train_Label = tf.placeholder(tf.float64, shape=(None, output_n), name='input_labels') # 训练数据集标签
self.input_n = input_n # 输入层神经元个数
self.hidden_n = hidden_n # 隐含层神经元个数
self.output_n = output_n # 输出层神经元个数
self.lambd = lambd # 正则化系数
self.input_weights = tf.Variable(
tf.random_normal((self.input_n, self.hidden_n), mean=0, stddev=1, dtype=tf.float64),
trainable=True) # 输入层与隐含层之间的权重
self.hidden_weights = tf.Variable(
tf.random_normal((self.hidden_n, self.output_n), mean=0, stddev=1, dtype=tf.float64),
trainable=True) # 隐含层与输出层之间的权重
self.hidden_threshold = tf.Variable(tf.random_normal((1, self.hidden_n), mean=0, stddev=1, dtype=tf.float64),
trainable=True) # 隐含层的阈值
self.output_threshold = tf.Variable(tf.random_normal((1, self.output_n), mean=0, stddev=1, dtype=tf.float64),
trainable=True) # 输出层的阈值
# 将层与层之间的权重与偏置项加入损失集合
tf.add_to_collection('loss', tf.contrib.layers.l2_regularizer(self.lambd)(self.input_weights))
tf.add_to_collection('loss', tf.contrib.layers.l2_regularizer(self.lambd)(self.hidden_weights))
tf.add_to_collection('loss', tf.contrib.layers.l2_regularizer(self.lambd)(self.hidden_threshold))
tf.add_to_collection('loss', tf.contrib.layers.l2_regularizer(self.lambd)(self.output_threshold))
# 定义前向传播过程
self.hidden_cells = tf.sigmoid(tf.matmul(self.Train_Data, self.input_weights) + self.hidden_threshold)
self.output_cells = tf.sigmoid(tf.matmul(self.hidden_cells, self.hidden_weights) + self.output_threshold)
# 定义损失函数,并加入损失集合
self.MSE = tf.reduce_mean(tf.square(self.output_cells - self.Train_Label))
tf.add_to_collection('loss', self.MSE)
# 定义损失函数,均方误差加入L2正则化
self.loss = tf.add_n(tf.get_collection('loss'))
def train_test(self, Train_Data, Train_Label, Test_Data, Test_Label, learn_rate, epoch, iteration, batch_size):
"""
这是BP神经网络的训练函数
:param Train_Data: 训练数据集
:param Train_Label: 训练数据集标签
:param Test_Data: 测试数据集
:param Test_Label: 测试数据集标签
:param learn_rate: 学习率
:param epoch: 时期数
:param iteration: 一个epoch的迭代次数
:param batch_size: 小批量样本规模
"""
train_loss = [] # 训练损失
test_loss = [] # 测试损失
test_accarucy = [] # 测试精度
with tf.Session() as sess:
datasize = len(Train_Label)
self.train_step = tf.train.GradientDescentOptimizer(learn_rate).minimize(self.loss)
sess.run(tf.global_variables_initializer())
for e in np.arange(epoch):
for i in range(iteration):
start = (i * batch_size) % datasize
end = np.min([start + batch_size, datasize])
sess.run(self.train_step,
feed_dict={self.Train_Data: Train_Data[start:end],
self.Train_Label: Train_Label[start:end]})
if i % 10000 == 0:
total_MSE = sess.run(self.MSE,
feed_dict={self.Train_Data: Train_Data, self.Train_Label: Train_Label})
print("第%d个epoch中,%d次迭代后,训练MSE为:%g" % (e + 1, i + 10000, total_MSE))
# 训练损失
_train_loss = sess.run(self.MSE, feed_dict={self.Train_Data: Train_Data, self.Train_Label: Train_Label})
train_loss.append(_train_loss)
# 测试损失
_test_loss = sess.run(self.MSE, feed_dict={self.Train_Data: Test_Data, self.Train_Label: Test_Label})
test_loss.append(_test_loss)
# 测试精度
test_result = sess.run(self.output_cells, feed_dict={self.Train_Data: Test_Data})
test_accarucy.append(self.Accuracy(test_result, Test_Label))
return train_loss, test_loss, test_accarucy
def Accuracy(self, test_result, test_label):
"""
这是BP神经网络的测试函数
:param test_result: 测试集预测结果
:param test_label: 测试集真实标签
"""
predict_ans = []
label = []
for (test, _label) in zip(test_result, test_label):
test = np.exp(test)
test = test / np.sum(test)
predict_ans.append(np.argmax(test))
label.append(np.argmax(_label))
return accuracy_score(label, predict_ans)
- 训练模型
在run.py中创建一个主函数run_main(),首先实现导入数据,设置abalone_train.xlsx和abalone_test.xlsx的文件路径,调用LoadData函数得到训练集和测试集的样本与标签。接着设置神经网络参数,学习率为0.01,训练趟数为1000,然后训练并测试网络。代码如下:
# 导入数据
trainpath = 'data/abalone_train.xlsx'
testpath = 'data/abalone_test.xlsx'
Train_Data, Test_Data, Train_Label, Test_Label = LoadData(trainpath, testpath)
Train_Data = Normalizer().fit_transform(Train_Data)
Test_Data = Normalizer().fit_transform(Test_Data)
# 设置网络参数
input_n = np.shape(Train_Data)[1] + np.shape(Test_Data)[1]
output_n = np.shape(Train_Label)[1] + np.shape(Test_Label)[1]
hidden_n = int(np.sqrt(input_n * output_n))
lambd = 0.001
batch_size = 64
learn_rate = 0.01
epoch = 1000
iteration = 10000
# 训练并测试网络
bp = BP(input_n, hidden_n, output_n, lambd)
train_loss, test_loss, test_accuracy = bp.train_test(Train_Data, Train_Label, Test_Data, Test_Label, learn_rate,
epoch, iteration, batch_size)
- 绘制图像
在run.py的run_main函数中绘制训练与测试损失和测试集的测试精度2张图像。代码如下:
# 解决画图是的中文乱码问题
mpl.rcParams['font.sans-serif'] = [u'simHei']
mpl.rcParams['axes.unicode_minus'] = False
# 结果可视化
col = ['Train_Loss', 'Test_Loss']
epoch = np.arange(epoch)
plt.plot(epoch, train_loss, 'r')
plt.plot(epoch, test_loss, 'b-.')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.grid(True)
plt.legend(labels=col, loc='best')
plt.savefig('./训练与测试损失.jpg')
plt.show()
plt.close()
plt.plot(epoch, test_accuracy, 'r')
plt.xlabel('Epoch')
plt.ylabel('Test Accuracy')
plt.grid(True)
plt.legend(loc='best')
plt.savefig('./测试精度.jpg')
plt.show()
plt.close()
- 实验结果
编写好代码后,运行run.py。
训练与测试过程中损失随训练趟数的曲线如图2所示。
图2 训练与测试损失
测试过程中测试集的准确率随训练趟数增加的折线如图3所示。其中,每一个点的横坐标是训练趟数,纵坐标是该趟时的测试集的准确率。
图3 测试集准确率
在本次实验中,预设的学习率为0.01。从图2中我们可以看出,训练与测试损失随迭代趟数的增加而降低;而从图3中我们可以看出,当训练趟数很小时,测试集的准确率随迭代趟数的增加而增加,小幅降低后,当训练趟数超过70轮后,测试集的准确率稳定在72.1%。
心得体会
本实验利用BP神经网络实现了鲍鱼的性别分类,使用了TensorFlow框架,用张量表示数据,用计算图搭建神经网络,用会话执行计算图,优化线上的权重(参数),最后得到模型。测试集的准确率为0.7214,达到预期目标。通过此次实验,很好地掌握了BP神经网络前向传播和反向传播的原理,熟悉了Python第三方库——tensorflow、matplotlib和xlrd的使用。
更多推荐
所有评论(0)