It’s a major challenge to keep up with the continuous changes to the Keras/TensorFlow neural code library (and the PyTorch library too). I recently upgraded my Keras installation to version 2.6 and so I’m going through all my standard examples to bring them up to date with the inevitable changes.
I was using a new desktop machine and so I had to install TensorFlow 2.6 (which contains Keras 2.6). I ran into unexpected problems when the “wrapt” sub-library refused to build correctly (the installation process builds a .whl file for wrapt instead of using a pre-built .whl file). I found a hack online that suggested issuing the command SET WRAPT_INSTALL_EXTENSIONS=false, before the command pip install tensorflow, and that magically worked. Somehow.
One of the standard examples is the MNIST image dataset. There are 70,000 simple images (60,000 training images and 10,000 test images). Each image has 28×28 pixels and is a handwritten digit from ‘0’ to ‘9’. Each pixel value is between 0 and 255.
I used the built-in MNIST dataset from Keras but I could have loaded the raw MNIST data using np.loadtxt() or a similar function.
I used the Model() approach by defining separate layers and then passing the first and last layer to the Model() constructor. An alternative design is to use the Sequential() approach. I have no strong preference between Model() and Sequential() — it’s just syntax.
To save time, I only used 2 training epochs with a batch size of 100. In a non-demo scenario I’d use more epochs, but then have to watch for over-fitting.
After the model was trained, I set up a fake 28×28 image with one vertical bar, one horizontal bar, and one diagonal bar. The trained model predicted the fake image is a ‘5’ with pseudo-probability = 1.0000. Many machine learning systems aren’t very good at distinguishing between authentic and fake items. This has generated interest in ML systems that output a prediction plus a confidence score of some type.
Good fun!

Left: A clever pseudo Chanel bag made from a paper grocery bag and a chain from a hardware store. Center: A whimsical pseudo Louis Vuitton bag, complete with misspelling. Right: A serious attempt at a Coach bag, but I don’t think it will fool many people.
Code below.
# mnist_tfk.py
# MNIST using CNN
# Keras 2.6.0 in TensorFlow 2.6.0 ("_tfk")
# Anaconda3-2020.02 Python 3.7.6 Windows 10
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2' # suppress warn
import numpy as np
import tensorflow as tf
from tensorflow import keras as K
import matplotlib.pyplot as plt
def main():
# 0. get started
print("\nBegin MNIST using Keras %s " % K.__version__)
np.random.seed(1)
tf.random.set_seed(1)
# 1. load data
print("\nLoading train and test data ")
(train_x, train_y), \
(test_x, test_y) = K.datasets.mnist.load_data()
train_x = train_x.reshape(60_000, 28, 28, 1)
test_x = test_x.reshape(10_000, 28, 28, 1)
train_x = train_x.astype(np.float32)
test_x = test_x.astype(np.float32)
train_x /= 255
test_x /= 255
train_y = K.utils.to_categorical(train_y, 10)
test_y = K.utils.to_categorical(test_y, 10)
# 2. define model
print("\nCreating network with two Convolution, \
two Dropout, two Dense layers ")
g_init = K.initializers.glorot_uniform(seed=1)
opt = K.optimizers.Adam(learning_rate=0.01)
x = K.layers.Input(shape=(28,28,1))
con1 = K.layers.Conv2D(filters=32,
kernel_size=(3,3), kernel_initializer=g_init,
activation='relu', padding='valid')(x)
con2 = K.layers.Conv2D(filters=64,
kernel_size=(3,3), kernel_initializer=g_init,
activation='relu', padding='valid')(con1)
mp1 = K.layers.MaxPooling2D(pool_size=(2,2))(con2)
do1 = K.layers.Dropout(0.25)(mp1)
z = K.layers.Flatten()(do1)
fc1 = K.layers.Dense(units=128,
kernel_initializer=g_init, activation='relu')(z)
do2 = K.layers.Dropout(0.5)(fc1)
fc2 = K.layers.Dense(units=10,
kernel_initializer=g_init, activation='softmax')(do2)
model = K.models.Model(x, fc2)
model.compile(loss='categorical_crossentropy',
optimizer=opt, metrics=['accuracy'])
# 3. train model
bat_size= 100
max_epochs = 2
print("\nStarting training with batch size = %d " % bat_size)
model.fit(train_x, train_y, batch_size=bat_size,
epochs=max_epochs, verbose=1)
print("Training finished ")
# 4. evaluate model
eval = model.evaluate(test_x, test_y, verbose=0)
loss = eval[0]
acc = eval[1] * 100
print("\nTest data: loss = %0.4f \
accuracy = %0.2f%%" % (loss, acc))
# 5. save model
print("\nSaving MNIST model to disk ")
# mp = ".\\Models\\mnist_model.h5"
# model.save(mp)
# 6. use model
print("\nMaking prediction for fake image: ")
# np.set_printoptions(precision=4, suppress=True)
np.set_printoptions(formatter={'float': '{: 0.4f}'.format})
x = np.zeros(shape=(28,28), dtype=np.float32)
for row in range(5,23):
x[row][9] = 180 # vertical line
for rc in range(9,19):
x[rc][rc] = 250 # diagonal
for col in range(5,15):
x[14][col] = 200 # horizontal
plt.imshow(x, cmap=plt.get_cmap('gray_r'))
plt.show()
x = x.reshape(1, 28, 28, 1)
pred_probs = model.predict(x)
print("\nPrediction probabilities: ")
print(pred_probs)
pred_digit = np.argmax(pred_probs)
print("\nPredicted digit: ")
print(pred_digit)
print("\nEnd MNIST demo ")
if __name__ == "__main__":
main()

.NET Test Automation Recipes
Software Testing
SciPy Programming Succinctly
Keras Succinctly
R Programming
2026 Visual Studio Live
2025 Summer MLADS Conference
2026 DevIntersection Conference
2025 Machine Learning Week
2025 Ai4 Conference
2026 G2E Conference
2026 iSC West Conference
In the end of the article you made a great footnote :
About that neural nets, are not good in telling the certainty of their results.
Maybe you could make it into an article, also how about GAN’s in this respect.
Not saying they can do this, but they generate their own ‘wrong’ data.
Then there is something that should be measurable ?,