In [ ]:
#!/usr/bin/python
#
# Copyright 2018 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import absolute_import
import tensorflow as tf
import numpy as np
tf.keras.backend.clear_session()
# Load data
(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()
TRAINING_SIZE = len(train_images)
TEST_SIZE = len(test_images)
# Reshape from (N, 28, 28) to (N, 784)
train_images = np.reshape(train_images, (TRAINING_SIZE, 784))
test_images = np.reshape(test_images, (TEST_SIZE, 784))
# Convert the array to float32 as opposed to uint8
train_images = train_images.astype(np.float32)
test_images = test_images.astype(np.float32)
# Convert the pixel values from integers between 0 and 255 to floats between 0 and 1
train_images /= 255
test_images /= 255
NUM_DIGITS = 10
print("Before", train_labels[0]) # The format of the labels before conversion
train_labels = tf.keras.utils.to_categorical(train_labels, NUM_DIGITS)
print("After", train_labels[0]) # The format of the labels after conversion
test_labels = tf.keras.utils.to_categorical(test_labels, NUM_DIGITS)
# Cast the labels to floats, needed later
train_labels = train_labels.astype(np.float32)
test_labels = test_labels.astype(np.float32)
# The model we implement is similar to famous LeNet5 "Gradient-Based Learning Applied to Document Recognition"
# with some simplifications:
# (1) The first Conv2D uses default initialization.
# (2) Use max pooling for subsampling and remove upsampling.
# (3) Use ReLU as activation functions.
model = tf.keras.Sequential()
model.add(tf.keras.layers.Reshape((28, 28, 1), input_shape=(784,), name='reshape_1')) # <- [None, 28, 28, 1]
model.add(tf.keras.layers.Conv2D(filters=6, kernel_size=(5, 5), padding='same', activation=tf.nn.relu, name='conv_1')) # <- [None, 28, 28, 6]
model.add(tf.keras.layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2), padding='valid', name='maxpool_1')) # <- [None, 14, 14, 6]
model.add(tf.keras.layers.Conv2D(filters=16, kernel_size=(5, 5), strides=(1, 1), padding='valid', activation=tf.nn.relu, name='conv_2')) # <- [None, 10, 10, 16]
model.add(tf.keras.layers.MaxPool2D(pool_size=(2, 2), strides=(2, 2), padding='valid', name='maxpool_2')) # <- [None, 5, 5, 16]
model.add(tf.keras.layers.Flatten(name='flatten')) # <- [None, 400]
model.add(tf.keras.layers.Dense(120, activation=tf.nn.relu, name='dense_1')) # <- [None, 120]
model.add(tf.keras.layers.Dense(84, activation=tf.nn.relu, name='dense_2')) # <- [None, 84]
model.add(tf.keras.layers.Dense(10, activation=tf.nn.softmax, name='dense_3')) # <- [None, 10]
# Notes: Make sure each layer above has explicit names to support tfjs.
optimizer = tf.train.RMSPropOptimizer(learning_rate=0.001)
model.compile(loss='categorical_crossentropy',
optimizer=optimizer,
metrics=['accuracy'])
model.summary()
BATCH_SIZE=128
EPOCHS=5
model.fit(train_images, train_labels, epochs=EPOCHS, batch_size=BATCH_SIZE)
print("Starting evaluation")
loss, accuracy = model.evaluate(test_images, test_labels)
print('Test accuracy: %.2f' % (accuracy))
model.save('model.h5')
In [ ]: