You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MNIST模型准确率高但自制手写数字图片预测错误求助

问题:MNIST模型在官方数据集准确率95%,但自制手写图片预测全错

我正在学习神经网络,首个练习是MNIST手写数字分类。模型在官方数据集上训练测试准确率约95%,但用画图工具自制的4张手写数字图片测试时,预测结果完全错误。我有C#、Java后端开发经验,但对Python和神经网络不熟悉。

我的代码

import tensorflow as tf
from keras.datasets import mnist
import keras
import numpy as np
import matplotlib.pyplot as plt
import csv
from PIL import Image
import glob

epochs = 10
learning_rate = 0.001
batch_size=16

def CreateAndTrainModel(epochs, learning_rate, batch_size):
    (x_train, y_train), (x_test, y_test) = mnist.load_data()

    x_train, x_test = tf.cast(x_train/255.0, tf.float32), tf.cast(x_test/255.0, tf.float32)
    x_train = np.array(x_train).reshape(-1,784)
    x_test = np.array(x_test).reshape(-1,784)

    model = tf.keras.models.Sequential()

    model.add(tf.keras.layers.Dense(784,input_dim=784))
    model.add(tf.keras.layers.Dense(256, activation="relu"))
    model.add(tf.keras.layers.Dense(128, activation="relu"))
    model.add(tf.keras.layers.Dense(128, activation="relu"))
    model.add(tf.keras.layers.Dense(10, activation="softmax"))

    optimizer = keras.optimizers.SGD(learning_rate)
    model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
    model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs)
    model.evaluate(x_test, y_test)
    mse, bias, var = bias_variance_decomp(model, x_train, y_train, x_test, y_test, loss='mse', num_rounds=200,
                                      random_seed=1)

    return model

def GetData():
    file = open("CSV\data.csv", "r")
    data = list(csv.reader(file, delimiter=","))
    file.close()
    return data

def getImageList():
    image_list = []
    for filename in glob.glob('Images/*.png'):
        im = Image.open(filename)
        image_list.append(im)
    return image_list

def GetFileNameOnly(path):
    return path.filename.split('\\')[1].split('.')[0]

def GetCorrectAnswerByFilePath(path):
    key = GetFileNameOnly(path)
    answer = -1

    for dataValues in data:
        if (dataValues[0] == key):
            answer = dataValues[1]
    return answer

def ShowAllImages(image_list_length):
    for i in range(image_list_length):
        print(GetFileNameOnly(image_list[i]), GetCorrectAnswerByFilePath(image_list[i]))
        plt.imshow(image_list[i])
        plt.show()

def PredictImage(image):
    image = tf.image.rgb_to_grayscale(image)
    image = np.array(image).reshape(-1, 784)

    predicted_answer = np.argmax(model.predict(image.reshape(-1, 784)), 1)

    return predicted_answer

#Main
data = GetData()
model = CreateAndTrainModel(epochs, learning_rate, batch_size)

print(data)
image_list = getImageList()
image_list_length = (len(image_list))

for image in image_list:
    correct_answer = GetCorrectAnswerByFilePath(image)
    fileName = GetFileNameOnly(image)
    predicted_answer = PredictImage(image)
    print("File Name: ", fileName, "Predicted Answer", predicted_answer, "Actual answer", correct_answer)

训练与测试结果

官方数据集训练测试结果:

Epoch 10/10
3750/3750 [] - 9s 2ms/step - loss: 0.1733 - accuracy: 0.9500
313/313 [
] - 1s 2ms/step - loss: 0.1688 - accuracy: 0.9506

自制图片预测结果:

File Name: a Predicted Answer [3] Actual answer 4
File Name: b Predicted Answer [2] Actual answer 8
File Name: c Predicted Answer [3] Actual answer 1
File Name: d Predicted Answer [3] Actual answer 2

我尝试调整batch size、epochs、网络层数和神经元数量等参数,但大多情况预测结果仍不正确。怀疑可能的原因:1. 是否存在过拟合?2. 代码是否存在问题?3. MNIST模型是否不适用于此类自制图片?希望得到排查建议。


排查建议

1. 优先修正自制图片与MNIST的格式差异

MNIST数据集的图片有固定标准:28x28像素、白底黑字(背景白,数字黑,0为黑、255为白)、数字居中且占满大部分画布,你的自制图片大概率不符合这些要求:

  • 检查尺寸:必须缩放到28x28,缩放时要保持比例,避免拉伸变形(比如先把数字缩到20x20,再填充到28x28)
  • 检查颜色反转:如果你的图片是黑底白字,必须反转像素值(255 - image),模型是在白底黑字的数据上训练的
  • 检查通道:MNIST是单通道灰度图,PNG可能带透明通道,需转为纯灰度图
  • 检查数字位置:确保数字居中,避免偏边或过小

2. 修复预测前的预处理逻辑错误

你的PredictImage函数有核心问题:

  • 未对自制图片做归一化(除以255),训练时输入是x_train/255.0,但预测时像素值还是0-255,输入分布完全不一致
  • 直接用tf.image.rgb_to_grayscale处理PIL图片可能导致维度混乱
  • 修正后的示例代码:
def PredictImage(image):
    # 转为灰度图
    image = image.convert('L')
    # 缩放到28x28
    image = image.resize((28, 28))
    # 转为numpy数组
    image_np = np.array(image)
    # 若为黑底白字则反转颜色
    # image_np = 255 - image_np
    # 归一化到0-1区间,和训练数据对齐
    image_np = image_np / 255.0
    # 调整形状为(1,784),匹配模型输入
    image_np = image_np.reshape(-1, 784)
    # 预测(关闭冗余打印)
    predicted_answer = np.argmax(model.predict(image_np, verbose=0), 1)
    return predicted_answer

3. 排除过拟合可能

从训练和测试准确率来看,两者均为95%左右,没有出现训练准确率远高于测试的情况,因此过拟合不是当前问题的原因。

4. 优化模型细节

  • 输入层Dense(784, input_dim=784)无激活函数,可添加relu或直接删除该层
  • SGD优化器在0.001的学习率下收敛较慢,建议换成Adam优化器:
optimizer = keras.optimizers.Adam(learning_rate=learning_rate)

5. 验证预处理效果

在预测前显示预处理后的图片,确认它和MNIST的图片视觉一致:

def PredictImage(image):
    # ... 预处理步骤 ...
    plt.imshow(image_np.reshape(28,28), cmap='gray')
    plt.show()
    # ... 预测 ...

如果预处理后的图片和MNIST数字风格一致,预测结果大概率会正确。


内容的提问来源于stack exchange,提问作者EvgenieT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 19:24:57