1鸢尾花数据
回顾鸢尾花数据集,其提供了150组鸢尾花数据,每组包括鸢尾花的花萼长、花萼宽、花瓣长、花瓣宽 4个输入特征,同时还给出了这一组特征对应的鸢尾花类别。类别包括狗尾鸢尾、杂色鸢尾、弗吉尼亚鸢尾三类, 分别用数字0、1、2表示。可以使用sklearn来导入其数据。
2. 流程分析
① 准备数据。数据集读入;数据集乱序;生成训练集和测试集;配对。
② 搭建网络。定义神经网络中所有可训练的参数。
③ 参数优化。嵌套循环迭代,with结构更新参数,显示当前loss。
④ 测试效果。计算当前参数前向传播后的准确率,显示当前acc
3. 代码实现(手撕神经网络)
import tensorflow as tf
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from matplotlib import pyplot as plt
def demo16():
"""
神经网络实现鸢尾花分类
:return:
"""
# 数据集读入
data_iris = load_iris()
# 获取鸢尾花数据集的特征矩阵
x_data = data_iris.data
# 获取鸢尾花数据集的目标值
y_data = data_iris.target
# 数据集乱序
np.random.seed(116) # 使用相同的seed,使特征/标签一一对应。
np.random.shuffle(x_data)
np.random.seed(116)
np.random.shuffle(y_data)
tf.random.set_seed(116)
# 分出训练集和测试集
# x_train, x_test, y_train, y_test = train_test_split(x_data,y_data,test_size=0.2,random_state=116)
x_train = x_data[:-30]
y_train = y_data[:-30]
x_test = x_data[-30:]
y_test = y_data[-30:]
# 转换x的数据类型,否则后面矩阵相乘会因数据类型不一致而报错
x_train = tf.cast(x_train, tf.float32)
x_test = tf.cast(x_test, tf.float32)
# 特征值和目标值配对 每次喂入一小batch
train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32)
# 生成神经网络的参数,4个输入特征,故输入层为4个输入节点;因为3分类,故输出层为3个神经元
w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev=0.1, seed=1))
b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1, seed=1))
lr = 0.1 # 学习率为0.1
train_loss_results = [] # 将每轮的loss记录在此列表中,方便后续画图
test_acc = [] # 将每轮的acc记录在此列表中,方便后续画图
epoch = 500 # 循环500轮
loss_all = 0 # 每轮分4个step,loss_all记录着4个step生成的4个loss的和
# 训练部分
for epoch in range(epoch): # 数据集级别的循环
for step, (x_train, y_train) in enumerate(train_db): # batch级别的循环
with tf.GradientTape() as tape: # 记录梯度信息
y = tf.matmul(x_train, w1) + b1 # 神经网络的乘加运算
y = tf.nn.softmax(y) # 使y符合概率分布
y_ = tf.one_hot(y_train, depth=3)
loss = tf.reduce_mean(tf.square(tf.subtract(y_, y))) # 采用均方差损失函数
loss_all += loss.numpy() # 将每一步计算的loss累加
# 计算loss对各个参数的梯度
grads = tape.gradient(loss, [w1, b1])
# 实现梯度更新
w1.assign_sub(lr * grads[0])
b1.assign_sub(lr * grads[1])
# 每个epoch,打印loss信息
print("Epoch{},loss:{}".format(epoch, loss_all / 4))
train_loss_results.append(loss_all / 4) # 将4step的loss求的平均记录在此变量中
loss_all = 0 # 归零
# 测试部分
total_corrent, total_number = 0, 0
for x_test, y_test in test_db: # 遍历batch
# 使用更新后的参数进行预测
y = tf.matmul(x_test, w1) + b1
y = tf.nn.softmax(y)
pred = tf.argmax(y, axis=1) # 返回y中最大值的索引,即预测的分类
# 将pred转换为y_test数据类型
pred = tf.cast(pred, dtype=y_test.dtype)
correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32)
# 将每个batch的correct数加起来
correct = tf.reduce_sum(correct)
total_corrent += int(correct)
total_number += x_test.shape[0]
acc = total_corrent / total_number
test_acc.append(acc)
print("Test_acc", acc)
print("-----------------------------")
# 绘制loss曲线
plt.title("loss function curve")
plt.xlabel("epoch")
plt.ylabel("loss")
plt.plot(train_loss_results, label="$loss$")
plt.legend()
plt.show()
# 绘制acc曲线
plt.title("acc curve")
plt.xlabel("epoch")
plt.ylabel("acc")
plt.plot(test_acc, label="$acc$")
plt.legend()
plt.show()
if __name__ == '__main__':
demo16()
结果如下:
准确率如图所示:
损失函数值如下图所示: