Loading existing models with TensorFlow.js

A useful feature of TensorFlow.js is the ability to convert and load pre-existing models developed in python with Keras or TensorFlow for browser use. This gives us potential improvements in performance for end-users by making use of their device GPU to conduct the inference without network bottlenecks.

To demonstrate, I’m using a convolutional neural network classifier created in python using Keras and TensorFlow. The classifier was trained on 8000 labelled images of cats and dogs which were pre-processed with data augmentation.

The model was then exported to HDF5 (.h5) format and converted to TensorFlow.js Layers format using the tensorflowjs_converter cli tool. I’ve included the model source code at the end of this post.

Loading the model into TensorFlow.js is straightforward:

const model = await tf.loadModel('/path/to/model.json')

To run a prediction on new image data, we make use of the tf.fromPixels() method. Using this we can draw image data from sources such as file uploads, streaming video from webcams / device cameras and HTML canvas elements. In this demo, you can add use and example image or upload you own.

const predict = async (imageSource) => {
  const img = document.createElement('img')
  img.src = imageSource

  img.onload = async () => {
    const example = tf.fromPixels(img)
    const newImage = tf.cast(
      tf.image.resizeBilinear(example, [128, 128]),
      'float32'
    )
    const norm = tf.fill([128, 128, 3], 255)
    const normalisedImage = tf.div(newImage, norm)
    const predictme = tf.cast(tf.expandDims(normalisedImage), 'float32')
    const prediction = model.predict(predictme)
    const timeStart = new Date()
    const classificationData = await prediction.data()
    const timeEnd = new Date()
    const duration = timeEnd - timeStart
    const classificationName = classificationData[0] > 0.5 ? 'Dog' : 'Cat'
    const confidence =
      Math.round(Math.abs(classificationData[0] - 0.5) * 2 * 100) + '%'

    return { classificationName, classificationData, confidence, duration }
  }
}

The pre-trained model source (Python)


# Convolutional Neural Network

from keras.models import Sequential
from keras.layers import Convolution2D, MaxPooling2D, Flatten, Dense
classifier = Sequential()

# Convolution

convolution_layer = Convolution2D(
  filters=32,
  kernel_size=(3, 3),
  input_shape=(128, 128, 3),
  activation='relu'
)
classifier.add(convolution_layer)

# Max Pooling

pooling_layer = MaxPooling2D(pool_size=(2, 2))
classifier.add(pooling_layer)

# Add a second convolution layer

convolution_layer_2 = Convolution2D(
  filters=32,
  kernel_size=(3, 3),
  activation='relu'
)
classifier.add(convolution_layer_2)
pooling_layer_2 = MaxPooling2D(pool_size=(2, 2))
classifier.add(pooling_layer_2)

# Flattening

flattening_layer = Flatten()
classifier.add(flattening_layer)

# Full Connection

hidden_layer = Dense(units=256, activation='relu')
classifier.add(hidden_layer)
output_layer = Dense(units=1, activation='sigmoid')
classifier.add(output_layer)

# Compile

classifier.compile(
  optimizer='adam',
  loss='binary_crossentropy',
  metrics=['accuracy']
)

# Data pre-processing

from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(
  rescale=1./255,
  shear_range=0.2,
  zoom_range=0.2,
  horizontal_flip=True)

test_datagen = ImageDataGenerator(rescale=1./255)

training_set = train_datagen.flow_from_directory(
  'dataset/training_set',
  target_size=(128, 128),
  batch_size=32,
  class_mode='binary
)

test_set = test_datagen.flow_from_directory(
  'dataset/test_set',
  target_size=(128, 128),
  batch_size=32,
  class_mode='binary'
)

classifier.fit_generator(
  training_set,
  epochs=25,
  validation_data=test_set
)

# Export model

from datetime import datetime
i = datetime.now()
filename = f'cnn*model*{i.strftime("%Y-%m-%d-%H-%M-%S")}.h5'
classifier.save(filename)
print(f'Saved file: {filename}')

See the TensorFlow.js docs for more info. Example photos by Mia Phoy and Freddie Marriage.