天天看点

TensorFlow2编程练习——多层感知机MLP多层感知机MLP/全连接神经网络FC机器学习编程练习

多层感知机MLP/全连接神经网络FC机器学习编程练习

说明

  • 参考教程:简单粗暴TensorFlow 2-TensorFlow模型建立与训练-基础示例:多层感知机(MLP)
  • 本文为对教程学习后上机所编写的实践程序,并增加了对大部分语句的个人理解与总结,补充在程序注释中。可作为对参考教程的进一步理解与解释,也可用于对编程环境的可行性评估。欢迎读者交流与沟通,同时支持教程原作者,为大家提供更优质的教程。

编程环境

  • OS: Win10 Professional
  • IDE: Pycharm Community 2021.1
  • Complier: MSVC2019
  • Python: 3.9
  • TensorFlow: 2.5.0
  • CUDA: 10.0
  • cuDNN: 7.4.2

程序详情

import numpy as np
import tensorflow as tf
import os
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"                  #运行硬件选择
os.environ["CUDA_VISIBLE_DEVICES"] = "0"                        #-1为CPU,0为GPU1,1为GPU2,以此类推

'''数据获取及预处理'''
class MNISTLoader():
    # 从网络上自动下载MNIST数据集并加载。如果运行时出现网络连接错误,可以从
    # https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
    # 或
    # https://s3.amazonaws.com/img-datasets/mnist.npz
    # 下载MNIST数据集mnist.npz文件,并放置于用户目录的.keras/dataset目录下(Windows下用户目录为C:\Users\用户名 ,
    # Linux下用户目录为 /home/用户名 )

    def __init__(self):
        mnist = tf.keras.datasets.mnist
        (self.train_data, self.train_label), (self.test_data, self.test_label) = mnist.load_data()
        # MNIST中的图像默认为uint8(0-255的数字)。以下代码将其归一化到0-1之间的浮点数,并在最后增加一维作为颜色通道
        self.train_data = np.expand_dims(self.train_data.astype(np.float32)/255.0, axis=-1)  # [60000, 28, 28, 1]
        # 保存训练数据,手动增加一个张量维度给通道数(size=-1)
        self.test_data = np.expand_dims(self.test_data.astype(np.float32)/255.0, axis=-1)  # [10000, 28, 28, 1]
        # 保存测试数据,手动增加一个张量维度给通道数(size=-1)
        self.train_label = self.train_label.astype(np.float32)  # [60000]
        self.test_label = self.test_label.astype(np.float32)  # [10000]
        self.num_train_data, self.num_test_data = self.train_data.shape[0],self.test_data.shape[0]  
        # 提取训练集和测试集图片数量

    def get_batch(self, batch_size):
        index = np.random.randint(0, self.num_train_data, batch_size)
        return self.train_data[index, :], self.train_label[index]

'''end'''

'''模型构建'''

class MLP(tf.keras.Model):
    def __init__(self):
        super().__init__()
        self.flatten = tf.keras.layers.Flatten()  # 将28*28的图片拉直成1*784向量
        self.dense1 = tf.keras.layers.Dense(units=100, activation=tf.nn.relu)  # 增加隐层1,100个神经元,激活函数ReLu
        self.dense2 = tf.keras.layers.Dense(units=10)  # 增加隐层2,10个神经元, 无激活函数

    def call(self, inputs):  # 调用数据运算,输入张量[batch_size, 28, 28, 1]
        x = self.flatten(inputs)  # 拉直输入[batch_size, 784]
        x = self.dense1(x)  # 隐层1[batch_size, 100]
        x = self.dense2(x)  # 隐层2[batch_size, 10]
        output = tf.nn.softmax(x)  # 输出softmax分类
        return output

'''end'''

'''模型训练'''

# 定义超参数,参数定义参见https://blog.csdn.net/u013041398/article/details/72841854/
num_epochs = 5  # 轮次、周期,完整遍历数据集的次数,过小可能会欠拟合,过大可能会过拟合
batch_size = 50  # 批次,通常使用mini-batch方法,训练一批后计算损失函数进行梯度下降和权重更新
learning_rate = 0.001  # 学习率
# 实例化
model = MLP()  #实例化模型
data_loader = MNISTLoader()  # 实例化数据读取类
optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)  # 实例化优化器,使用Adam优化器,算法讲解
# 参见https://www.jianshu.com/p/aebcaf8af76e

'''end'''

'''训练与迭代'''

num_batches = int(data_loader.num_train_data // batch_size * num_epochs)  # 求训练集batch总个数,即训练总周期数
for batch_index in range(num_batches):
    X, Y = data_loader.get_batch(batch_size)  # 提取输入输出
    with tf.GradientTape() as tape:
        y_pred = model(X)  # 计算模型输出
        loss = tf.keras.losses.sparse_categorical_crossentropy(y_true=Y, y_pred=y_pred)  # 使用交叉熵函数做损失函数,
        # 算法讲解参见https://blog.csdn.net/tsyccnh/article/details/79163834
        # loss = tf.keras.losses.categorical_crossentropy(
        #     y_true=tf.one_hot(Y, depth=tf.shape(y_pred)[-1]),
        #     y_pred=y_pred
        # )  # 与上式等效
        loss = tf.reduce_mean(loss)  # 求一维均方误差MSE
        print("batch %d: loss %f" % (batch_index, loss.numpy()))
    grads = tape.gradient(loss, model.variables)  # 损失函数关于自变量的梯度自动计算,
    # 使用model.variables属性直接获得模型中所有变量
    optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))  # 根据梯度自动更新参数,
    # zip()为拼装成元组函数

'''end'''

'''模型评估'''

sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()  # 计算预测正确样本数占总样本数的比例实例化
num_batches = int(data_loader.num_test_data // batch_size)  # 计算测试集批次batch数
for batch_index in range(num_batches):
    start_index, end_index = batch_index * batch_size, (batch_index + 1) * batch_size  # 每个batch逐个样本标号
    y_pred = model.predict(data_loader.test_data[start_index: end_index])  # 计算一个batch预测模型输出
    sparse_categorical_accuracy.update_state(y_true=data_loader.test_label[start_index: end_index], y_pred=y_pred)  
    # 更新预测精度
    print("test accuracy: %f" % sparse_categorical_accuracy.result())

'''end'''
           

输出结果

。。。

。。。