实现多层神经网络

在前面,我们使用了单层神经网络实现了对鸢尾花数据集的分类,
在这里插入图片描述
下面,将使用多层神经网络来实现对鸢尾花数据集的分类。

第一层是输入层到隐含层,相应的权值矩阵为 W1
在这里插入图片描述
隐含层中的阈值是 B1 ,隐含层的输出是:
在这里插入图片描述
假设增加的隐含层中有 16 个神经元(结点),那么 B1 的形状就是 (16,),因为输入层中有四个结点,因此, W1 的形状是 (4,16),

第二层是隐含层到输出层,
在这里插入图片描述
从隐含层到输出层的权值矩阵为 W2 ,输出层中的阈值是 B2 ,因为输出层中有三个节点,所以B2 的形状是(3,),W2 的形状是(16,3)。

这个增加的隐含层,使用上节课中介绍的 Relu 函数作为激活函数,
在这里插入图片描述
因为是多分类问题,因此,输出层的激活函数仍然使用 Softmax 函数,损失函数仍然使用交叉熵损失函数。

下面,我们来看下代码实现。

import pandas as pd
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = "SimHei"
plt.rcParams['axes.unicode_minus'] = False

# 目标:使用花萼长度、花萼宽度、花瓣长度、花瓣宽度四种属性将三种鸢尾花区分开

# 第一步:加载数据集
TRAIN_URL = "http://download.tensorflow.org/data/iris_training.csv"
train_path = tf.keras.utils.get_file(TRAIN_URL.split('/')[-1], TRAIN_URL)
df_iris_train = pd.read_csv(train_path, header=0)  # 表示第一行数据作为列标题

TEST_URL = "http://download.tensorflow.org/data/iris_test.csv"
test_path = tf.keras.utils.get_file(TEST_URL.split('/')[-1], TEST_URL)
df_iris_test = pd.read_csv(test_path, header=0)

# 第二步:数据处理
# 2.1 转化为NumPy数组
iris_train = np.array(df_iris_train)  # 将二维数据表转换为 Numpy 数组, (120, 5), iris的训练集中有120条样本,
iris_test = np.array(df_iris_test)  # 将二维数据表转换为 Numpy 数组, (30, 5), iris的测试集中有30条样本,

# 2.2 提取属性和标签
train_x = iris_train[:, 0:4]  # 取出鸢尾花训练数据集中属性列
train_y = iris_train[:, 4]  # 取出最后一列作为标签值, (120,)

test_x = iris_test[:, 0:4]  # 取出鸢尾花训练数据集中属性列
test_y = iris_test[:, 4]  # 取出最后一列作为标签值, (30, )

# 2.3 数据归一化
# 可以看出这两个属性的尺寸相同,因此不需要进行归一化,可以直接对其进行中心化处理
# 对每个属性进行中心化, 也就是按列中心化, 所以使用下面这种方式
train_x = train_x - np.mean(train_x, axis=0)
test_x = test_x - np.mean(test_x, axis=0)
# 此时样本点的横坐标和纵坐标的均值都是0

# 2.4 生成多元模型的属性矩阵和标签列向量
X_train = tf.cast(train_x, tf.float32)
# 创建张量函数tf.constant()
Y_train = tf.one_hot(tf.constant(train_y, dtype=tf.int32), 3)  # 将标签值转换为独热编码的形式
print(X_train.shape)  # (120, 4)
print(Y_train.shape)  # (120, 3)

X_test = tf.cast(test_x, tf.float32)
# 创建张量函数tf.constant()
Y_test = tf.one_hot(tf.constant(test_y, dtype=tf.int32), 3)  # 将标签值转换为独热编码的形式
print(X_test.shape)  # (30, 4)
print(Y_test.shape)  # (30, 3)

# 第三步:设置超参数和显示间隔
learn_rate = 0.5
itar = 50

display_step = 10

# 第四步:设置模型参数初始值
np.random.seed(612)
# 隐含层
# 这里的 W1 是一个(4, 16) 的矩阵
W1 = tf.Variable(np.random.randn(4, 16), dtype=tf.float32)
# 这里的 B1 是一个(16, ) 的一维张量, 初始化为 0
B1 = tf.Variable(np.zeros([16]), dtype=tf.float32)
# 输出层
# 这里的 W2 是一个(16, 3) 的矩阵
W2 = tf.Variable(np.random.randn(16, 3), dtype=tf.float32)
# 这里的 B2 是一个(3, ) 的一维张量, 初始化为 0
B2 = tf.Variable(np.zeros([3]), dtype=tf.float32)

# 第五步:训练模型
cross_train = []  # 列表cross_train用来保存每一次迭代的交叉熵损失
acc_train = []  # 用来存放训练集的分类准确率

cross_test = []  # 列表cross_test用来保存每一次迭代的交叉熵损失
acc_test = []  # 用来存放测试集的分类准确率

for i in range(0, itar + 1):

    with tf.GradientTape() as tape:

        # 5.1:定义网络结构
        # H = X*W1 + B1
        Hidden_train = tf.nn.relu(tf.matmul(X_train, W1) + B1)
        # Y = H*W2 + B2
        Pred_train = tf.nn.softmax(tf.matmul(Hidden_train, W2) + B2)
        # 计算训练集的平均交叉熵损失函数
        Loss_train = tf.reduce_mean(tf.keras.losses.categorical_crossentropy(y_true=Y_train, y_pred=Pred_train))

        # H = X*W1 + B1
        Hidden_test = tf.nn.relu(tf.matmul(X_test, W1) + B1)
        # Y = H*W2 + B2
        Pred_test = tf.nn.softmax(tf.matmul(Hidden_test, W2) + B2)
        # 计算测试集的平均交叉熵损失函数
        Loss_test = tf.reduce_mean(tf.keras.losses.categorical_crossentropy(y_true=Y_test, y_pred=Pred_test))

    # 计算准确率函数 -- 因为不需要对其进行求导运算, 因此也可以把这条语句写在 with 语句的外面
    Accuarcy_train = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(Pred_train.numpy(), axis=1), train_y), tf.float32))
    Accuarcy_test = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(Pred_test.numpy(), axis=1), test_y), tf.float32))

    # 记录每一次迭代的交叉熵损失和准确率
    cross_train.append(Loss_train)
    cross_test.append(Loss_test)
    acc_train.append(Accuarcy_train)
    acc_test.append(Accuarcy_test)

    # 对交叉熵损失函数 WB 求偏导
    grads = tape.gradient(Loss_train, [W1, B1, W2, B2])
    # 函数assign_sub的作用是实现 Variable 变量的减法赋值
    # 更新模型参数 W1
    W1.assign_sub(learn_rate * grads[0])  # grads[0] 是 dL_dw1, 形状为(4, 16)
    # 更新模型偏置项参数 B1
    B1.assign_sub(learn_rate * grads[1])  # grads[1] 是 dL_db1, 形状为(16, )
    # 更新模型参数 W2
    W2.assign_sub(learn_rate * grads[2])  # grads[0] 是 dL_dw2, 形状为(16, 3)
    # 更新模型偏置项参数 B2
    B2.assign_sub(learn_rate * grads[3])  # grads[1] 是 dL_db2, 形状为(3, )

    if i % display_step == 0:
        print("i: %i, TrainLoss: %f, TrainAccuracy: %f, TestLoss: %f, TestAccuracy: %f"
              % (i, Loss_train, Accuarcy_train, Loss_test, Accuarcy_test))

"""
i: 0, TrainLoss: 2.205641, TrainAccuracy: 0.433333, TestLoss: 1.721138, TestAccuracy: 0.400000
i: 10, TrainLoss: 0.205314, TrainAccuracy: 0.941667, TestLoss: 0.249661, TestAccuracy: 0.966667
i: 20, TrainLoss: 0.149540, TrainAccuracy: 0.950000, TestLoss: 0.167103, TestAccuracy: 1.000000
i: 30, TrainLoss: 0.122346, TrainAccuracy: 0.958333, TestLoss: 0.124693, TestAccuracy: 1.000000
i: 40, TrainLoss: 0.105099, TrainAccuracy: 0.958333, TestLoss: 0.099869, TestAccuracy: 1.000000
i: 50, TrainLoss: 0.092934, TrainAccuracy: 0.958333, TestLoss: 0.084885, TestAccuracy: 1.000000
"""
# 第六步:数据可视化
plt.figure(figsize=(12, 5))
plt.subplot(121)
plt.plot(acc_train, color="blue", label="train")
plt.plot(acc_test, color="red", label="test")
plt.title("迭代次数和损失值曲线图", fontsize=22)
plt.xlabel('迭代次数', color='r', fontsize=16)
plt.ylabel('损失值', color='r', fontsize=16)
plt.legend()

plt.subplot(122)
plt.plot(cross_train, color="blue", label="train")
plt.plot(cross_test, color="red", label="test")
plt.title("迭代次数和准确率曲线图", fontsize=22)
plt.xlabel('迭代次数', color='r', fontsize=16)
plt.ylabel('准确率', color='r', fontsize=16)
plt.legend()

plt.show()

运行效果如下,
在这里插入图片描述
对比单层神经网络和多层神经网络实现的对鸢尾花数据集的分类的效果。
在这里插入图片描述

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xuechanba

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值