Sequential模型预测结果恒为5的问题排查求助
Hey there, let's figure out why your Flask setup is stuck predicting 5 every time, even though your model works perfectly in the notebook. This is almost always a preprocessing mismatch between your training data and the images your server receives, but let's walk through all possible culprits step by step.
1. The #1 Culprit: Image Preprocessing Doesn't Match Training
Your model was trained on MNIST data, which has very specific characteristics:
- Digits are white (high pixel values) on a black background (low pixel values)
- Pixel values are typically normalized to the range
[0, 1](divided by 255)
Looking at your server code, you're missing two critical steps that your notebook's training pipeline probably included:
Fixes to Add:
# After converting to grayscale array: grayscaleArray = np.array(grayscaleImage) # 1. Reverse pixel values (if your drawing app uses black digits on white background) # MNIST uses white digits on black, so flip the contrast: grayscaleArray = 255 - grayscaleArray # 2. Normalize pixel values to [0, 1] (match what you did during training) grayscaleArray = grayscaleArray.astype('float32') / 255.0 # 3. Ensure the shape matches your model's input expectation # If your model was trained on (28,28) inputs, reshape to (1,28,28) grayscaleArray = grayscaleArray.reshape(1, 28, 28) # If your model expects a channel dimension (common for CNNs), use (1,28,28,1) instead # grayscaleArray = grayscaleArray.reshape(1, 28, 28, 1)
2. Image Resizing/ Cropping Issues
Your code uses ImageOps.fit(originalImage, dim, Image.ANTIALIAS) which crops the image to fit the 28x28 size, rather than scaling it. If your drawing canvas isn't square, this could cut off parts of the digit, making it unrecognizable to the model.
Better Resizing Approach (Preserve Entire Digit):
Instead of cropping, first pad the image to a square, then resize:
def pad_to_square(image, background_color=(255,255,255)): width, height = image.size max_side = max(width, height) square_img = Image.new(image.mode, (max_side, max_side), background_color) # Center the original image on the square canvas square_img.paste(image, ((max_side - width)//2, (max_side - height)//2)) return square_img originalImage = Image.open("theImage.png") square_image = pad_to_square(originalImage) resizedImage = square_image.resize(dim, Image.Resampling.LANCZOS) # Use LANCZOS instead of ANTIALIAS (deprecated in newer PIL)
3. Verify Model Loading is Correct
It's possible your Flask server is loading an old, broken version of the model instead of the one you trained in the notebook. To confirm:
- Double-check that
MyModel.h5is in Flask's working directory (printos.getcwd()to verify) - Add a quick test prediction at server startup using a known MNIST sample:
import numpy as np from tensorflow.keras.datasets import mnist # Load a sample from MNIST test set (_, _), (X_test, y_test) = mnist.load_data() test_sample = X_test[0].reshape(1,28,28) / 255.0 # Match preprocessing print("Test prediction for known digit:", y_test[0]) print("Model output:", model.predict(test_sample)) print("Predicted digit:", np.argmax(model.predict(test_sample)))
If this test gives the wrong result, you know the model file itself is the issue (re-save the model from your notebook).
4. Data Type Mismatch
PIL's grayscale arrays are uint8 (0-255), but your model was trained on float32 data. Adding .astype('float32') (as in the first fix) ensures the data type matches what the model expects.
Start with the preprocessing fixes first—this is by far the most common cause of this exact issue. Once you implement those, your predictions should start matching the notebook results.
内容的提问来源于stack exchange,提问作者Neil

