Tensorflow - Testing a mnist neural net with my own images
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.
Introduction
Training a neural network on MNIST is often the first milestone in a deep learning journey, but the real satisfaction comes from testing it with your own handwritten digits. The process is straightforward in principle — load an image, preprocess it, and feed it to the model — but the preprocessing details trip up almost everyone the first time. Understanding why each step matters will save you from staring at confidently wrong predictions.
Why Preprocessing Matters
MNIST images have very specific characteristics. Every digit is 28x28 pixels, grayscale, drawn in white on a black background, centered in the frame, and normalized to values between 0 and 1. Your phone camera or scanner produces images that violate most of these constraints. If you skip any preprocessing step, the model receives input that looks nothing like its training data, and it will produce nonsensical predictions regardless of how accurate it was on the test set.
Loading and Converting Your Image
Start by loading the image using PIL (Pillow) or OpenCV, then convert it to grayscale and resize it to 28x28 pixels.
Using PIL:
Using OpenCV:
Inverting Colors: White-on-Black
MNIST digits are white strokes on a black background. Most people naturally write dark digits on white paper, which is the opposite. You must invert the image so the pixel values match what the model expects.
You can verify by plotting the image:
The digit should appear as bright pixels on a dark background. If it does not, the model will see your background as the digit and perform poorly.
Normalizing and Reshaping for Model Input
MNIST pixel values are scaled to the range [0, 1]. Your image has values in [0, 255], so divide by 255. Then reshape the array to match the model's expected input shape.
Running the Prediction
With the image properly preprocessed, pass it to the model:
If you want to see the probability distribution across all 10 digits:
Complete End-to-End Example
Here is a full pipeline that loads, preprocesses, and predicts a custom digit image:
The automatic inversion check (np.mean > 127) works for most clean images. If your image has a noisy or gray background, you may need to apply thresholding first.
Why Predictions Go Wrong
Even with correct preprocessing, custom images sometimes produce wrong predictions. The most common reasons are:
Poor centering: MNIST digits are centered in the 28x28 frame by center of mass. If your digit is shifted to one corner, the model sees a pattern it was never trained on. You can center it by computing the center of mass and shifting the digit accordingly.
Stroke thickness mismatch: MNIST digits have a specific stroke thickness relative to the frame size. A very thin pen or a very thick marker produces digits that look foreign to the model. Resize your source image so the digit occupies roughly the same proportion of the frame as MNIST digits do.
Background noise: Shadows, paper texture, or uneven lighting create non-zero pixel values in the background. Apply a threshold to force background pixels to zero:
Common Pitfalls
- Forgetting to invert colors: This is the single most common mistake. The model sees a mostly-white image and has no idea what digit it represents.
- Using the wrong reshape dimensions: A dense (fully connected) model expects
(1, 784)or(1, 28, 28), while a CNN expects(1, 28, 28, 1). A shape mismatch either raises an error or silently misinterprets the data. - Skipping normalization: If pixel values remain in the 0-255 range instead of 0-1, every activation in the network is wildly different from training, producing garbage outputs.
- Resizing with the wrong interpolation: Some interpolation methods introduce gray anti-aliasing artifacts. Use
Image.LANCZOS(PIL) orcv2.INTER_AREA(OpenCV) when downscaling for the cleanest results. - Testing with stylized or unusual digit forms: MNIST was written by US Census Bureau employees and high school students. Unusual digit styles (European crossed 7s, looped 2s) may not match any training example closely enough for correct prediction.
Summary
- MNIST models expect 28x28 grayscale images with white digits on a black background, normalized to values between 0 and 1.
- Always invert colors if your original image has dark digits on a light background.
- Reshape the input to match your model's architecture:
(1, 28, 28)for dense networks,(1, 28, 28, 1)for CNNs. - Poor centering, wrong stroke thickness, and background noise are the leading causes of incorrect predictions on custom images.
- Visualize your preprocessed image before feeding it to the model to verify it resembles actual MNIST samples.
Related reading
- TensorFlow - tf.data.Dataset reading large HDF5 files
- TensorFlow - tf.layers vs tf.contrib.layers
- Tensorflow - Using tf.summary with 1.2 Estimator API
- Tensorflow - ValueError Failed to convert a NumPy array to a Tensor Unsupported object type float
- Tensorflow - ValueError Failed to convert a NumPy array to a Tensor Unsupported object type float
- Tensorflow - ValueError Parent directory of trained_variables.ckpt doesn''t exist, can''t save
- Tensorflow Is it possible to use different train input size and test input size?
- Tensorflow REstart queue runners different train and test queue
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.