LeNet-5实战

Tip

我不能创造的事物,我就还没有完全理解它。−理查德·費曼

LeNet-5模型介绍

LeNet-5Yann LeCun在1998年设计的用于手写数字识别的卷积神经网络,当年美国大多数银行就是用它来识别支票上面的手写数字的,它是早期卷积神经网络中最有代表性的实验系统之一。

实战代码

前置引入

import os
import tensorflow as tf
from tensorflow import keras
os.environ["TF_CPP_MIN_LOG_LEVEL"] = '2'

创建LeNet-5网络模型

model = tf.keras.Sequential([
    # 第1层-卷积层 滤波器尺寸5*5,6个
    keras.layers.Conv2D(6, 3),
    # 第2层-池化层,滤波器尺寸为2×2,步长为2
    keras.layers.MaxPooling2D(pool_size=2, strides=2),
    keras.layers.ReLU(),
    # 第3层-卷积层 滤波器尺寸5*5,16个
    keras.layers.Conv2D(16, 3),
    # 第4层-池化层,滤波器尺寸为2×2,步长为2
    keras.layers.MaxPooling2D(pool_size=2, strides=2),
    keras.layers.ReLU(),
    keras.layers.Flatten(),  # 拉平之后方便做全连接
    # 第5层-全连接层
    keras.layers.Dense(120, activation='relu'),
    # 第6层-全连接层
    keras.layers.Dense(84, activation='relu'),
    # 第7层-全连接层
    keras.layers.Dense(10, activation='softmax')  # 最后输出10类,0-9的数字
])

model.build(input_shape=(4, 28, 28, 1))  # 28*28*1 1个通道

# 打印出网络结构
model.summary()

# 编译
model.compile(
    optimizer=keras.optimizers.Adam(),
    loss=keras.losses.CategoricalCrossentropy(),
    metrics=['accuracy']
)

数据预处理与加载

# 数据预处理
def preprocess(x, y):
    x = tf.cast(x, dtype=tf.float32) / 255
    x = tf.reshape(x, [-1, 28, 28, 1])
    y = tf.one_hot(y, depth=10)
    return x, y


# 加载数据集
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
# 查看类型
print('x_train=', type(x_train))
print('y_train=', type(y_train))

train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train))
print('train_db=', type(train_db))
train_db = train_db.shuffle(10000)  # 打乱数据
train_db = train_db.batch(128)
train_db = train_db.map(preprocess)

test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test))
print('test_db=', type(test_db))
test_db = test_db.shuffle(10000)
test_db = test_db.batch(128)
test_db = test_db.map(preprocess)

模型训练

# 开始训练
model.fit(train_db, epochs=10)

# 在测试集上验证
model.evaluate(test_db)

详细部分

点击查看代码
import os

os.environ["TF_CPP_MIN_LOG_LEVEL"] = '2'
import tensorflow as tf
from tensorflow.keras import Sequential, layers

network = Sequential([  # 网络容器
    layers.Conv2D(6, kernel_size=3, strides=1),  # 第一个卷积层, 6 个 3x3 卷积核
    layers.MaxPooling2D(pool_size=2, strides=2),  # 高宽各减半的池化层
    layers.ReLU(),  # 激活函数
    layers.Conv2D(16, kernel_size=3, strides=1),  # 第二个卷积层, 16 个 3x3 卷积核
    layers.MaxPooling2D(pool_size=2, strides=2),  # 高宽各减半的池化层
    layers.ReLU(),  # 激活函数
    layers.Flatten(),  # 打平层,方便全连接层处理
    layers.Dense(120, activation='relu'),  # 全连接层,120 个节点
    layers.Dense(84, activation='relu'),  # 全连接层,84 节点
    layers.Dense(10)  # 全连接层,10 个节点
])

# build 一次网络模型,给输入 X 的形状,其中 4 为随意给的 batchsz
network.build(input_shape=(4, 28, 28, 1))
# 统计网络信息
network.summary()

# 导入误差计算,优化器模块
from tensorflow.keras import losses, optimizers

# 创建损失函数的类,在实际计算时直接调用类实例即可
criteon = losses.CategoricalCrossentropy(from_logits=True)
# 优化器,加快训练速度
optimizer = optimizers.Adam(lr=1e-3)


# 数据预处理
def preprocess(x, y):
    x = tf.cast(x, dtype=tf.float32) / 255
    return x, y


# 加载数据集
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
# 查看类型
print('x_train=', type(x_train))
print('y_train=', type(y_train))

train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train))
print('train_db=', type(train_db))
train_db = train_db.shuffle(10000)  # 打乱数据
train_db = train_db.batch(128)
train_db = train_db.map(preprocess)

test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test))
print('test_db=', type(test_db))
test_db = test_db.shuffle(10000)
test_db = test_db.batch(128)
test_db = test_db.map(preprocess)

# 生成train数据的迭代器
db_iter = iter(train_db)
sample = next(db_iter)
print(f'batch: {sample[0].shape, sample[1].shape}')


def main():
    for epoch in range(10):
        for step, (x, y) in enumerate(train_db):
            # 构建梯度记录环境
            with tf.GradientTape() as tape:
                # 插入通道维度,=>[b,28,28,1]
                x = tf.expand_dims(x, axis=3)  # 前向计算,获得 10 类别的概率分布,[b, 784] => [b, 10]
                out = network(x)
                # 真实标签 one-hot 编码,[b] => [b, 10]
                y_onehot = tf.one_hot(y, depth=10)  # 计算交叉熵损失函数,标量
                loss = criteon(y_onehot, out)

            # 自动计算梯度
            grads = tape.gradient(loss, network.trainable_variables)
            # 自动更新参数
            optimizer.apply_gradients(zip(grads, network.trainable_variables))

            if step % 100 == 0:
                print(epoch, step, f'loss: {float(loss)}')

        # 记录预测正确的数量,总样本数量
        correct, total = 0, 0
        for x, y in test_db:  # 遍历所有训练集样本
            # 插入通道维度,=>[b,28,28,1]
            x = tf.expand_dims(x, axis=3)  # 前向计算,获得 10 类别的预测分布,[b, 784] => [b, 10]
            out = network(x)
            # 真实的流程时先经过 softmax,再 argmax
            # 但是由于 softmax 不改变元素的大小相对关系,故省去
            pred = tf.argmax(out, axis=-1)
            y = tf.cast(y, tf.int64)
            # 统计预测正确数量
            correct += float(tf.reduce_sum(tf.cast(tf.equal(pred, y), tf.float32)))
            # 统计预测样本总数
            total += x.shape[0]  # 计算准确率
        print('test acc:', correct / total)


if __name__ == '__main__':
    main()

posted @   lanercifang  阅读(52)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示