MNIST训练的全连接神经网络测试自制手写数字样本效果差问题求助
MNIST全连接网络自制样本识别错误问题排查
问题描述
使用MNIST数据集训练了一个全连接神经网络,用于分类28*28像素的数字图像,自制样本测试时效果极差:在画图工具中绘制的数字“7”图像转换为数组后,识别结果完全不符合预期。
相关代码
模型训练代码(由François Chollet编写)
from tensorflow.keras.datasets import mnist (train_images, train_labels), (test_images, test_labels) = mnist.load_data() from tensorflow.keras import models from tensorflow.keras import layers network = models.Sequential() network.add(layers.Dense(512, activation='relu', input_shape=(28*28,))) network.add(layers.Dense(10, activation='softmax')) network.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy']) train_images = train_images.reshape((60000,28*28)) train_images = train_images.astype('float32') / 255 test_images = test_images.reshape((10000, 28*28)) test_images = test_images.astype('float32') / 255 from tensorflow.keras.utils import to_categorical train_labels = to_categorical(train_labels) test_labels = to_categorical(test_labels) network.fit(train_images,train_labels,epochs=20,batch_size=512,validation_split=0.2) print(network.evaluate(test_images,test_labels))
自制样本测试代码
from PIL import Image import PIL.ImageOps import os direccio = 'C:/Users/marcc/OneDrive/Escritorio' os.chdir(direccio) myImage = Image.open("Image.PNG").convert('L') myImage = PIL.ImageOps.invert(myImage) myImage = myImage.resize((28,28)) myImage.show() #transforming my image into an array (THE PROBLEM MUST BE HERE) import numpy as np myImage_array = np.array(myImage) myImage_array = myImage_array.reshape((28*28)) myImage_array = myImage_array.astype('float32') / 255 myImage_array=myImage_array.reshape(1,784) print(myImage_array.shape) print(network.predict(myImage_array))
测试输出
[[6.9165975e-03 3.0256975e-03 4.9591944e-01 4.8350231e-03 5.6093242e-03 8.6059235e-03 4.5295963e-01 8.3720963e-04 2.1008164e-02 2.8301307e-04]]
预测结果中,对应数字7的索引位置(第7位,索引从0开始计数)概率仅为8.3720963e-04,概率最高的两个类别分别为2和6,完全不符合预期。
可视化参考
- MNIST数据集数字9样例:

- 预处理后自制数字7样例:

问题原因
- 预处理不匹配:MNIST数据集的图像为黑底白字,数字居中、笔画粗细均匀,背景像素值接近0,笔画像素值集中在0.5~1区间。若自制原始PNG带有透明通道,
convert('L')操作会将透明区域填充为白色,反转后透明区域变为黑色,若绘制的数字本身为黑色,反转后会和背景色一致,导致输入特征完全错误。 - 全连接网络特性限制:全连接网络对像素的位置、大小、倾斜度非常敏感,仅能学习到训练集分布内的固定像素特征,只要自制数字的位置、粗细和训练集有明显差异,就会出现识别错误。
解决方案
- 修正预处理逻辑,和MNIST数据集分布对齐:
首先处理图像透明通道,避免透明区域像素值异常:
反转后添加二值化操作,消除灰度渐变干扰:myImage = Image.open("Image.PNG") # 处理透明通道,填充白色背景 if myImage.mode == 'RGBA': white_bg = Image.new('L', myImage.size, 255) white_bg.paste(myImage, mask=myImage.split()[3]) myImage = white_bg else: myImage = myImage.convert('L')
调整数字位置和大小:计算前景数字的 bounding box,将数字裁剪后 resize 到20*20,周围填充4像素黑边,完全匹配MNIST的预处理逻辑。myImage = PIL.ImageOps.invert(myImage) # 二值化处理,和MNIST风格对齐 threshold = 127 myImage = myImage.point(lambda p: 255 if p > threshold else 0) - 若修正预处理后识别效果仍然不佳,可将模型替换为简单的CNN结构,CNN对位置、大小、倾斜变化的鲁棒性远高于全连接网络,更适合手写数字识别场景。
内容的提问来源于stack exchange,提问作者Noether
相关产品推荐
相关产品推荐

