Just for fun, I decided to code up the classic MNIST image recognition example using Keras. I started by doing an Internet search. I found the EXACT same code repeated over and over by multiple people. The original code comes from the Keras documentation. I was stunned that nobody made even the slightest effort to add something new.
So, I figured I’d refactor the code to use the Model() approach rather than the Sequential() approach. The Sequential() approach creates a model like this:
model = Sequential() model = model.add(Conv2D(32, input_shape=(28,28,1))) etc, etc, for 8 layers
The Model() approach look like:
X = Input(shape=(28,28,1)) layer1 = Conv2D(32)(X) layer2 = Conv@d(64)(layer1) etc, etc model = Model(X, layer8)
The exercise allowed me get insights into exactly how CNN image classification works using Keras. Like everyone I know, I learn by starting with some working code, often from documentation, but then the key is to experiment with the code.
# exp.py from __future__ import print_function import keras import numpy as np from keras.datasets import mnist from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D from keras import backend as K bat_size = 128 epochs = 3 (x_train, y_train), (x_test, y_test) = mnist.load_data() x_train = x_train.reshape(60000, 28, 28, 1) x_test = x_test.reshape(10000, 28, 28, 1) x_train = x_train.astype(np.float32) x_test = x_test.astype(np.float32) x_train /= 255 x_test /= 255 y_train = keras.utils.to_categorical(y_train, 10) y_test = keras.utils.to_categorical(y_test, 10) # model = Sequential() # model.add(Conv2D(32, kernel_size=(3, 3), # activation='relu', # input_shape=input_shape)) # model.add(Conv2D(64, (3, 3), activation='relu')) # model.add(MaxPooling2D(pool_size=(2, 2))) # model.add(Dropout(0.25)) # model.add(Flatten()) # model.add(Dense(128, activation='relu')) # model.add(Dropout(0.5)) # model.add(Dense(num_classes, activation='softmax')) X = keras.layers.Input(shape=(28,28,1)) layer1 = Conv2D(filters=32, kernel_size=(3, 3), activation='relu', padding='valid')(X) print(layer1.shape) layer2 = Conv2D(filters=64, kernel_size=(3, 3), activation='relu')(layer1) print(layer2.shape) layer3 = MaxPooling2D(pool_size=(2, 2))(layer2) print(layer3.shape) layer4 = Dropout(0.25)(layer3) print(layer4.shape) layer5 = Flatten()(layer4) print(layer5.shape) layer6 = Dense(128, activation='relu')(layer5) print(layer6.shape) layer7 = Dropout(0.5)(layer6) print(layer7.shape) layer8 = Dense(10, activation='softmax')(layer7) print(layer8.shape) model = keras.models.Model(X, layer8) model.compile(loss=keras.losses.categorical_crossentropy, optimizer=keras.optimizers.Adadelta(), metrics=['accuracy']) model.fit(x_train, y_train, batch_size=bat_size, epochs=epochs, verbose=1) score = model.evaluate(x_test, y_test, verbose=0) print('Test loss:', score) print('Test accuracy:', score)