Tensorflow2.0:加载与识别经典数据集MINIST

一 实现思路

1. 加载 MNIST 数据集,得到训练集与测试集
2. 将训练集与测试集转换为DataSet对象
3. 将数据顺序打散
避免每次读取数据顺序相同,使得模型记住训练集的一些特点,降低模型泛化能力。
4. 设置批训练
从训练集总数中随机抽取batchsize个样本,来进行模型训练,相比于使用所用样本构建模型,批训练花费的时间更少,计算效率更高。每训练一个次,就叫一个step,当经历若干个step使得把训练集所有样本训练过以后,那叫一个epoch
5. 数据预处理

图片像素值进行标准化,使得处于0到1的区间
图片的类别转化成one-hot编码

图片的标签是数字0到数字10,是属于多分类问题,为了能够量化类别,将图片的类别转化成长度为10位数字的one-hot编码,便于和神经网络输出结果比较,计算其损失。
6. 神经网络构建
其主要的流程为:

设置学习率
网络结构参数初始化
计算前向传播
计算损失函数
计算梯度
根据梯度更新参数(梯度下降法)
每经过固定的step记录和输出训练误差,即均方根误差
每经过固定的step,输出测试误差,即分类正确率

二 实现方式

1.数据处理阶段

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets  # 导入经典数据集加载模块
# 1. 加载 MNIST 数据集
(x, y), (x_test, y_test) = datasets.mnist.load_data()   # 返回数组的形状
# 2. 将数据集转换为DataSet对象,不然无法继续处理
train_db = tf.data.Dataset.from_tensor_slices((x, y))
# print(train_db)  # 
# 3. 将数据顺序打散
train_db = train_db.shuffle(10000)  # 数字为缓冲池的大小
# print(train_db)  # 
# 4. 设置批训练
train_db = train_db.batch(512)  # batch size 为 128
# print(train_db)   # 

# 5. 预处理函数
def preprocess(x, y):   # 输入x的shape 为[b, 32, 32], y为[b]
    # 将像素值标准化到 0~1区间
    x = tf.cast(x, dtype=tf.float32) / 255.
    # 将图片改为28*28大小的
    x = tf.reshape(x, [-1, 28 * 28])
# 这个reshape我认为是和数据的存储顺序发生冲突,读取的数据应该不是原图的数据,而是被打乱的数据
    # 将数据集的类别标签(数字0-10)转换为one-hot 编码
    y = tf.cast(y, dtype=tf.int32)  # 转成整型张量
    y = tf.one_hot(y, depth=10)
    return x, y
# 将数据集传入预处理函数,train_db支持map映射函数
train_db = train_db.map(preprocess)
# print(train_db)  # 
# 设置训练20个epoch
train_db = train_db.repeat(20)  # 将train_db在内部迭代20遍
# 查看train_db的结构
x, y = next(iter(train_db))
print(x, y)
print('train sample:', x.shape, y.shape)   # (512, 784) (512, 10)
# 从上面可以看出,现在的train_db已经变成可每份512*784的矩阵,有变成了每份512*10的矩阵,784表示输入的特征数,10表示输出的类别所对应的向量,即one-hot编码

# 以同样的方式处理测试集
# 转换对象
test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test))
# 打乱排序,设置batchSize为128,进行预处理
test_db = test_db.shuffle(1000).batch(512).map(preprocess)

总结:tf.shuffle和tf.batch起到了打散数据顺序和设置批训练的作用,对于任何类型数据而言,在数据处理上是不可或缺的环节。对于图片数据而言,tf.one_hot可以将图片的类别进行转码,生成向量,是一个非常有用的工具。

2.构建并训练神经网络

# 7.神经网络训练
def main():
    # 设置学习率
    lr = 1e-2
    accs, losses = [], []
    # 手动设置网络层参数
    # 784个节点输入 => 512个节点输出
    w1, b1 = tf.Variable(tf.random.normal([784, 256], stddev=0.1)), tf.Variable(tf.zeros([256]))
    # 512个节点输入 => 256个节点输出
    w2, b2 = tf.Variable(tf.random.normal([256, 128], stddev=0.1)), tf.Variable(tf.zeros([128]))
    # 256个节点输入 => 10个节点输入
    w3, b3 = tf.Variable(tf.random.normal([128, 10], stddev=0.1)), tf.Variable(tf.zeros([10]))
    #
    for step, (x,  y) in enumerate(train_db):  #  enumerate提供train_db的索引值step,表明是第几个step

        # [b, 28, 28] => [b, 784]
        x = tf.reshape(x, (-1, 784))

        with tf.GradientTape() as tape:
            # 进行前向传播
            # 第一层
            h1 = x @ w1 + b1
            h1 = tf.nn.relu(h1)
            # 第二层
            h2 = h1 @ w2 + b2
            h2 = tf.nn.relu(h2)
            # 第三层
            out = h2 @ w3 + b3
            # 直接输出,计算损失函数
            loss = tf.square(y - out)   # 10个数的方差
            loss = tf.reduce_mean(loss)  # 均方差
        # 计算损失函数对各个参数的梯度
        grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])
        # 更新网络参数
        for p, g in zip([w1, b1, w2, b2, w3, b3], grads):  # 这里zip的妙用
            p.assign_sub(lr * g)
        # step为80次时,记录并输出损失函数结果
        if step % 80 == 0:
            print(step, 'loss:', float(loss))
            losses.append(float(loss))
        # step为80次时,用测试集验证模型
        if step % 80 == 0:
            total, total_correct = 0., 0
            # 测试集的每一个样本
            for x, y in test_db:
                h1 = x @ w1 + b1
                h1 = tf.nn.relu(h1)
                h2 = h1 @ w2 + b2
                h2 = tf.nn.relu(h2)
                out = h2 @ w3 + b3
                pred = tf.argmax(out, axis=1)
                y = tf.argmax(y, axis=1)
                correct = tf.equal(pred, y)
                # tf变为numpy计算
                total_correct += tf.reduce_sum(tf.cast(correct, dtype=tf.int32)).numpy()
                total += x.shape[0]
            print(step, 'Evaluate Acc:', total_correct / total)
            accs.append(total_correct / total)


3. 运行结果
经过20次的epoch以后,分类正确率达到了0.779
Tensorflow2.0:加载与识别经典数据集MINIST_第1张图片

你可能感兴趣的:(Tensorflow2.0,python,tensorflow,深度学习)