上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
返回列表 发新帖

MNIST手写数字学习

[复制链接]
  • TA的每日心情

    2025-8-16 01:57
  • 签到天数: 196 天

    [LV.7]常住居民III

    760

    主题

    6734

    回帖

    7382

    积分

    管理员

    非物质文化遗产社会摇传承人

    积分
    7382

    荣誉开发者油中2周年生态建设者

    发表于 4 小时前 | 显示全部楼层 | 阅读模式

    首先导入依赖库

    # 导入必要的库和模块
    import numpy as np  # 用于数值计算和数组操作
    import pandas as pd  # 用于数据处理和分析
    from keras.datasets import mnist  # 加载MNIST手写数字数据集
    from tensorflow.keras.utils import to_categorical  # 将标签转换为分类格式
    from keras import models  # 神经网络模型类
    from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D  # 神经网络层类型
    from PIL import Image

    然后导入mnist数据集,并对格式进行转换

    (X_train_image, y_train_lable), (X_test_image, y_test_lable) = mnist.load_data()
    
    # 数据预处理
    # 将图像数据重塑为4D张量: (样本数, 高度, 宽度, 通道数)
    # 添加通道维度1,表示灰度图像(如果是RGB图像则为3)
    X_train = X_train_image.reshape(60000, 28, 28, 1)
    X_test = X_test_image.reshape(10000, 28, 28, 1)
    
    # 将标签转换为one-hot编码格式
    # 例如: 数字3 -> [0,0,0,1,0,0,0,0,0,0]
    # 数字7 -> [0,0,0,0,0,0,0,1,0,0]
    y_train = to_categorical(y_train_lable, 10)
    y_test = to_categorical(y_test_lable, 10)

    reshape其中60000是文件样本数,28和28是像素,1是通道数,拓展1是为了更加方便理解
    to_categorical是转换为独热编码,方便机器学习跟分类对应理解
    然后创建一个模型

    # 创建Sequential顺序模型
    model = models.Sequential()

    然后开始叠神经元
    我理解第一个是通过3*3进行扫描,生成32个通道,其中relu是因为如果不用激活函数,会导致一直都是一维线性,会导致叠加深度无效,input_shape是输入参数
    然后添加池化,为了减少数据量,提取特征
    接下来再进行一次扫描,这次会让感受野增加,识别的特征更多
    池化
    然后随机丢弃25%神经元防止过拟合
    将数据平铺后丢入全连接层
    丢弃50%神经元
    然后softmax进行分类

    # 添加第一个卷积层
    # 32个3x3的卷积核,使用ReLU激活函数
    # input_shape指定输入数据的维度: 28x28像素,1个通道(灰度)
    model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
    
    # 添加最大池化层
    # 使用2x2池化窗口,将特征图尺寸减半(28x28 -> 14x14)
    # 减少参数数量,增强特征不变性
    model.add(MaxPooling2D(pool_size=(2, 2)))
    
    # 添加第二个卷积层
    # 64个3x3的卷积核,提取更复杂的特征
    model.add(Conv2D(64, (3, 3), activation='relu'))
    
    # 添加第二个最大池化层
    # 进一步减少特征图尺寸(14x14 -> 7x7)
    model.add(MaxPooling2D(pool_size=(2, 2)))
    
    # 添加Dropout层防止过拟合
    # 在训练过程中随机丢弃25%的神经元连接
    # 强制网络学习更鲁棒的特征表示
    model.add(Dropout(0.25))
    
    # 将多维特征图展平为一维向量
    # 为全连接层准备输入数据
    model.add(Flatten())
    
    # 添加全连接层(密集层)
    # 128个神经元,使用ReLU激活函数
    # 进行高级特征组合和分类决策
    model.add(Dense(128, activation='relu'))
    
    # 添加第二个Dropout层
    # 丢弃50%的神经元连接,进一步防止过拟合
    # 同时可以加速训练过程
    model.add(Dropout(0.5))
    
    # 添加输出层
    # 10个神经元对应10个数字类别(0-9)
    # 使用softmax激活函数输出概率分布
    model.add(Dense(10, activation='softmax'))

    编译模型,配置训练过程
    optimizer: 使用rmsprop优化算法更新权重
    loss: 使用分类交叉熵损失函数,适用于多分类问题
    metrics: 监控准确率指标

    开始训练模型
    X_train, y_train: 训练数据和标签
    validation_split=0.3: 使用30%的训练数据作为验证集
    epochs=5: 整个训练集迭代5次
    batch_size=128: 每次使用128个样本更新权重

    model.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    model.fit(X_train, y_train,
              validation_split=0.3,
              epochs=5,
              batch_size=128)
     print('测试集预测准确率:', score[1])

    输出内容
    测试集预测准确率: 0.9782999753952026

    写一张图片进行测试
    图片.png

    # 读取本地图片 pic.PNG,转换为 (1, 28, 28, 1) 格式并用训练好的 model 预测
    try:
        # 尝试打开同一目录下的 pic.PNG
        img = Image.open('pic.PNG').convert('L')  # 转为灰度
        # Pillow 新旧版本兼容的重采样选项
        # Image.Resampling (Pillow>=9.1.0) 使用枚举,例如 Image.Resampling.LANCZOS
        # 在旧版本中可能存在 Image.LANCZOS 或 Image.ANTIALIAS;确保向后兼容
        if hasattr(Image, 'Resampling'):
            resample = Image.Resampling.LANCZOS
        elif hasattr(Image, 'LANCZOS'):
            resample = Image.LANCZOS
        elif hasattr(Image, 'ANTIALIAS'):
            resample = Image.ANTIALIAS
        else:
            # 兜底使用 BICUBIC,任何 Pillow 版本都应支持
            resample = Image.BICUBIC
        img = img.resize((28, 28), resample)
        img_arr = np.array(img)
    
        # 如果图片背景/前景颜色与你的训练数据(MNIST:白字黑底)不同,可能需要反转。
        img_arr = 255 - img_arr  # 反转颜色(如果需要)
    
        # 形状调整为 (1,28,28,1)
        img_arr = img_arr.reshape(1, 28, 28, 1)
    
        # 保持与训练数据相近的数据类型(训练时使用的是从 mnist.load_data 返回的 uint8)
        img_arr = img_arr.astype(np.float32)
    
        # 如果在训练时进行了归一化(例如除以255),这里也要相同处理。
        # 原训练脚本没有除以255,因此我们不做归一化;如果你修改过训练预处理,请在此处做相同处理。
        prediction = model.predict(img_arr)
        predicted_label = np.argmax(prediction, axis=1)[0]
        print('\nPrediction probabilities for pic.PNG:\n', prediction)
        print('Predicted label for pic.PNG:', int(predicted_label))
    except FileNotFoundError:
        print('\npic.PNG 未找到,已跳过图像预测。请把 pic.PNG 放到脚本同一目录下后重试。')
    except Exception as e:
        print('\n处理 pic.PNG 时出错:', e)

    输出:
    Predicted label for pic.PNG: 6

    完整代码

    # 导入必要的库和模块
    import numpy as np  # 用于数值计算和数组操作
    import pandas as pd  # 用于数据处理和分析
    from keras.datasets import mnist  # 加载MNIST手写数字数据集
    from tensorflow.keras.utils import to_categorical  # 将标签转换为分类格式
    from keras import models  # 神经网络模型类
    from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D  # 神经网络层类型
    from PIL import Image
    
    # 加载MNIST数据集,包含训练集和测试集
    # X_train_image: 60000张28x28的训练图像
    # y_train_lable: 60000个对应的训练标签(0-9)
    # X_test_image: 10000张28x28的测试图像  
    # y_test_lable: 10000个对应的测试标签
    (X_train_image, y_train_lable), (X_test_image, y_test_lable) = mnist.load_data()
    
    # 数据预处理
    # 将图像数据重塑为4D张量: (样本数, 高度, 宽度, 通道数)
    # 添加通道维度1,表示灰度图像(如果是RGB图像则为3)
    X_train = X_train_image.reshape(60000, 28, 28, 1)
    X_test = X_test_image.reshape(10000, 28, 28, 1)
    
    # 将标签转换为one-hot编码格式
    # 例如: 数字3 -> [0,0,0,1,0,0,0,0,0,0]
    # 数字7 -> [0,0,0,0,0,0,0,1,0,0]
    y_train = to_categorical(y_train_lable, 10)
    y_test = to_categorical(y_test_lable, 10)
    
    # 创建Sequential顺序模型
    model = models.Sequential()
    
    # 添加第一个卷积层
    # 32个3x3的卷积核,使用ReLU激活函数
    # input_shape指定输入数据的维度: 28x28像素,1个通道(灰度)
    model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
    
    # 添加最大池化层
    # 使用2x2池化窗口,将特征图尺寸减半(28x28 -> 14x14)
    # 减少参数数量,增强特征不变性
    model.add(MaxPooling2D(pool_size=(2, 2)))
    
    # 添加第二个卷积层
    # 64个3x3的卷积核,提取更复杂的特征
    model.add(Conv2D(64, (3, 3), activation='relu'))
    
    # 添加第二个最大池化层
    # 进一步减少特征图尺寸(14x14 -> 7x7)
    model.add(MaxPooling2D(pool_size=(2, 2)))
    
    # 添加Dropout层防止过拟合
    # 在训练过程中随机丢弃25%的神经元连接
    # 强制网络学习更鲁棒的特征表示
    model.add(Dropout(0.25))
    
    # 将多维特征图展平为一维向量
    # 为全连接层准备输入数据
    model.add(Flatten())
    
    # 添加全连接层(密集层)
    # 128个神经元,使用ReLU激活函数
    # 进行高级特征组合和分类决策
    model.add(Dense(128, activation='relu'))
    
    # 添加第二个Dropout层
    # 丢弃50%的神经元连接,进一步防止过拟合
    # 同时可以加速训练过程
    model.add(Dropout(0.5))
    
    # 添加输出层
    # 10个神经元对应10个数字类别(0-9)
    # 使用softmax激活函数输出概率分布
    model.add(Dense(10, activation='softmax'))
    
    # 编译模型,配置训练过程
    # optimizer: 使用rmsprop优化算法更新权重
    # loss: 使用分类交叉熵损失函数,适用于多分类问题
    # metrics: 监控准确率指标
    model.compile(optimizer='rmsprop',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    
    # 开始训练模型
    # X_train, y_train: 训练数据和标签
    # validation_split=0.3: 使用30%的训练数据作为验证集
    # epochs=5: 整个训练集迭代5次
    # batch_size=128: 每次使用128个样本更新权重
    model.fit(X_train, y_train,
              validation_split=0.3,
              epochs=5,
              batch_size=128)
    
    # 在测试集上评估模型性能
    # 返回损失值和准确率
    score = model.evaluate(X_test, y_test)
    
    # 打印测试集准确率
    # score[0]是损失值,score[1]是准确率
    print('测试集预测准确率:', score[1])
    
    # 读取本地图片 pic.PNG,转换为 (1, 28, 28, 1) 格式并用训练好的 model 预测
    try:
        # 尝试打开同一目录下的 pic.PNG
        img = Image.open('pic.PNG').convert('L')  # 转为灰度
        # Pillow 新旧版本兼容的重采样选项
        # Image.Resampling (Pillow>=9.1.0) 使用枚举,例如 Image.Resampling.LANCZOS
        # 在旧版本中可能存在 Image.LANCZOS 或 Image.ANTIALIAS;确保向后兼容
        if hasattr(Image, 'Resampling'):
            resample = Image.Resampling.LANCZOS
        elif hasattr(Image, 'LANCZOS'):
            resample = Image.LANCZOS
        elif hasattr(Image, 'ANTIALIAS'):
            resample = Image.ANTIALIAS
        else:
            # 兜底使用 BICUBIC,任何 Pillow 版本都应支持
            resample = Image.BICUBIC
        img = img.resize((28, 28), resample)
        img_arr = np.array(img)
    
        # 如果图片背景/前景颜色与你的训练数据(MNIST:白字黑底)不同,可能需要反转。
        img_arr = 255 - img_arr  # 反转颜色(如果需要)
    
        # 形状调整为 (1,28,28,1)
        img_arr = img_arr.reshape(1, 28, 28, 1)
    
        # 保持与训练数据相近的数据类型(训练时使用的是从 mnist.load_data 返回的 uint8)
        img_arr = img_arr.astype(np.float32)
    
        # 如果在训练时进行了归一化(例如除以255),这里也要相同处理。
        # 原训练脚本没有除以255,因此我们不做归一化;如果你修改过训练预处理,请在此处做相同处理。
        prediction = model.predict(img_arr)
        predicted_label = np.argmax(prediction, axis=1)[0]
        print('\nPrediction probabilities for pic.PNG:\n', prediction)
        print('Predicted label for pic.PNG:', int(predicted_label))
    except FileNotFoundError:
        print('\npic.PNG 未找到,已跳过图像预测。请把 pic.PNG 放到脚本同一目录下后重试。')
    except Exception as e:
        print('\n处理 pic.PNG 时出错:', e)
    混的人。
    ------------------------------------------
    進撃!永遠の帝国の破壊虎---李恒道

    入驻了爱发电https://afdian.com/a/lihengdao666

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表