一、数据集说明通过网盘分享的文件mnist keras链接: https://pan.baidu.com/s/1WeSY8nCavUug8wtIHYlbEA 提取码: eze3文件夹中有4个.npy文件那什么是 .npy呢 .npy是NumPy 专用二进制文件专门存储单个 numpy 多维数组ndarray。核心优点自带元信息保存数组形状 shape、维度、数据类型 dtype加载后直接还原数组不用手动定义尺寸无损存储二进制存储浮点数无精度丢失读写极快远快于 csv、txt 文本文件深度学习数据集图片像素、标签大量使用跨平台Windows / Linux / Mac 互通这里文件中储存的是我们需要的手写数字图片test.npytest_labels.npytrain.npytrain_labels.npy二、数据预处理导入我们需要的包没有的可以通过 pip install 命令下载注意下载的包版本需要与本机使用的 python 版本兼容import numpy as np import tensorflow as tf import matplotlib.pyplot as plt定义数据所在的目录注意文件目录记得根据自己本机具体情况修改DATA_DIR G:/xiaoE1/和Data/手写数字识别/mnist kerasimport os #导入os工具 print(os.listdir(G:/xiaoE1/和Data/手写数字识别/mnist keras))再将四个文件分别赋值X_train np.load(os.path.join(DATA_DIR, train.npy)) #训练图像 y_train np.load(os.path.join(DATA_DIR, train_labels.npy)) #训练标签 X_test np.load(os.path.join(DATA_DIR, test.npy)) #测试图像 y_test np.load(os.path.join(DATA_DIR, test_labels.npy)) #测试标签查看数据集集体情况# 打印原始形状 print(原始训练图像形状: , X_train.shape, 数据类型: , X_train.dtype) print(原始训练标签形状: , y_train.shape, 数据类型: , y_train.dtype)print(原始测试图像形状: , X_test.shape, 数据类型: , X_test.dtype) print(原始测试标签形状: , y_test.shape, 数据类型: , y_test.dtype)其中 .T转置功能交换数组两个维度把格式从(像素数, 样本数)转为(样本数, 像素数)是机器学习标准第 0 维永远代表样本数量。X_train X_train.T # (784, 60000) → (60000, 784) X_test X_test.T # (784, 10000) → (10000, 784)原本图形形状为78460000需要还原成(样本数, 28, 28)三维图片数组满足后续 CNN 卷积神经网络、绘图代码的输入要求。X_train X_train.reshape(-1, 28, 28) X_test X_test.reshape(-1, 28, 28)小贴士两种MINIST数据格式对比存储格式形状适用场景是否需要转置 reshape展平旧格式(784, 样本数)传统全连接网络需要执行.Treshape图像标准格式(样本数,28,28,1)CNN、matplotlib 绘图无需转换直接使用转换后的数据情况为该为测试集且为全项目最终版数据情况像素值归一化处理0~255 → 0~1因为神经网络运算需要浮点数值因此转换数据类型为 32 位浮点数。X_train X_train.astype(float32) / 255. X_test X_test.astype(float32) / 255.归一化的核心作用加速神经网络梯度下降收敛大幅提升训练速度统一数值尺度避免大像素值主导权重更新提升模型精度几乎所有图像分类任务的标准预处理步骤。清洗维度、转为整数标签y_train y_train.astype(int32).squeeze() #去掉多余维度 y_test y_test.astype(int32).squeeze()转换为 One-Hot 编码num_classes 10 y_train tf.keras.utils.to_categorical(y_train, num_classes) y_test tf.keras.utils.to_categorical(y_test, num_classes)再次打印, 确认形状已变成正常格式print(\n处理后训练图像形状: , X_train.shape, 最小像素值: ,X_train.min(), 最大像素值: , X_train.max()) print(处理后训练标签形状: ,y_train.shape) print(\n处理后测试图像形状: , X_test.shape) print(处理后测试标签形状: , y_test.shape)三、数据可视化import matplotlib.pyplot as plt # 设置支持中文的字体 plt.rcParams[font.family] [SimHei, WenQuanYi Micro Hei, Heiti TC] # 解决负号显示异常问题 plt.rcParams[axes.unicode_minus] False先可视化一张图片plt.imshow(X_train[10000], cmapgray) plt.title(标签 one-hot 编码: str(y_train[10000])) plt.axis(off) plt.show()把数据格式转换成 TensorFlow/Keras 卷积神经网络CNN强制要求的标准格式。#给训练/测试图像增加通道维(灰度图1) X_train X_train.reshape(60000, 28, 28, 1) X_test X_test.reshape(10000, 28, 28, 1)Keras 的卷积层Conv2D强制要求输入数据是4 维数组缺少通道维会直接报错。四、训练模型导入依赖库tensorflow深度学习框架搭建、训练神经网络models.Sequential序贯模型一层一层线性堆叠网络层适合简单 CNN层功能说明Conv2D二维卷积层提取图片纹理、轮廓等视觉特征MaxPooling2D最大池化层压缩特征图尺寸、降低计算量、保留核心特征Dropout随机失活层抑制过拟合Flatten展平层把二维特征图转为一维向量对接全连接层Dense全连接层用于最终分类import tensorflow as tf from tensorflow.keras import models #模型容器 from tensorflow.keras.layers import (Conv2D, MaxPooling2D, Dropout, Flatten, Dense)初始化序贯模型创建一个空的线性模型容器后续通过model.add()依次添加网络层。#序贯式模型骨架 model models.Sequential()卷积 池化特征提取模块2 组 ConvPool第一组卷积池化Conv2D(32, (3,3), activationrelu)32输出 32 张特征图32 个卷积核(3,3)3×3 大小卷积窗口图像领域标准尺寸relu激活函数引入非线性让网络能学习复杂特征input_shape(28,28,1)仅第一层需要规定输入图片尺寸28 高 ×28 宽、单通道灰度图和你预处理后的X_train/X_test维度匹配MaxPooling2D(pool_size(2,2))2×2 窗口做最大池化特征图宽高各缩小一半减少计算量同时防止过拟合。model.add(Conv2D(32, (3, 3), activationrelu, input_shape (28, 28, 1))) #首层需指定输入形状 model.add(MaxPooling2D(pool_size (2, 2)))第二组卷积池化64使用 64 个卷积核深层网络提取更复杂的组合特征笔画、数字整体轮廓无需再写input_shape网络自动承接上一层输出维度同样搭配 2×2 最大池化压缩特征model.add(Conv2D(64, (3, 3), activation relu)) model.add(MaxPooling2D(pool_size (2, 2)))正则化 展平过渡层Dropout(0.5)训练时随机将 50% 神经元输出置 0强制网络不依赖局部少数神经元缓解过拟合Flatten()将经过卷积池化后的二维特征矩阵拉直成一维数组作为全连接层的输入。#正则化 展平 model.add(Dropout(0.5)) model.add(Flatten()) #把二维特征图拉成一维向量全连接分类头部Dense(128, activationrelu)128 个神经元的隐藏全连接层融合卷积提取到的所有特征第二层Dropout(0.5)再次随机失活进一步抑制过拟合Dense(10, activationsoftmax)输出层10 个神经元对应手写数字 0~9 共 10 个分类softmax激活函数输出 10 个 0~1 之间的概率值总和为 1概率最大的索引就是预测数字完美适配 one-hot 标签。#全连接分类头 model.add(Dense(128, activation relu)) model.add(Dropout(0.5)) model.add(Dense(10, activation softmax)) #10 类softmax输出编译模型配置训练参数optimizeradamAdam 自适应优化器自动调节学习率收敛速度快、效果稳定图像分类任务常用losscategorical_crossentropy分类交叉熵损失函数专门搭配 one-hot 编码标签计算预测概率与真实标签的误差指导网络权重更新metrics[accuracy]训练时监控准确率指标每轮输出训练 / 验证集识别正确率#编译模型 (指定优化器、损失函数、评估指标) model.compile(optimizer adam, loss categorical_crossentropy, metrics [accuracy])打印网络结构model.summary()模型训练#开始训练 (沿用前面处理好的 X_train, y_train) model.fit(X_train, y_train, validation_split0.3, epochs10, batch_size64)部分显示五、评估模型测试及预测准确率#在测试集上评估模型 score model.evaluate(X_test, y_test, verbose 0) #verbose0 关闭进度条 print(测试及预测准确率, score[1]) #score[0]是lossscore[1]是accuracy展示模型从测试集取出一张图片送入训练好的 CNN 模型完成数字预测单张手写数字图片模型预测#取测试集第13张图索引 12并保留通道维 img X_test[12] #形状已经是28281 pred model.predict(img[np.newaxis, ...]) #升维成128281 print(网络输出 one-hot, pred[0]) print(转换后数字, pred.argmax())pred形状为(1, 10)第 0 维1 个样本第 1 维10 个数字0~9的 softmax 概率总和 1也就是 one-hot 概率数组。pred[0]取出第一张样本的 10 个预测概率.argmax()找到概率数组里最大值的索引索引就是模型识别出的手写数字。 例如果pred[0] [0.001,0.98,0.002,...]argmax()返回 1代表模型判定图片数字是 1。可视化显示#绘图时把通道维去掉变成28×28 plt.imshow(img.squeeze(), cmap Greys) plt.axis(off) plt.title(f预测结果{pred.argmax()}) plt.show()