In the previous tutorial, everything we’ve seen is kind of standard Keras stuff. There’s nothing that we’ve really looked at that’s super wacky,or you know aside from Tensor flow Import Keras, everything else so far could have just been how to train a convolutional network using Keras. If we move on from the kind of creating model training and such, we get to some of the interesting pieces here.
In this tutorial shows how to train a Convolutional Neural Network for recognition images from CIFAR-10 data-set with the TensorFlow Estimators and Datasets API.
Create Convolutional Neural Network Using Keras
We’ll build a custom model and use Keras to do it. But then we’ll convert that Keras model to a TensorFlow Estimator and feed TFRecord using tf.data
API.
The code snippet below is our TensoFlow model using Keras API, a simple stack of 2 convolution layers with a ReLU activation and followed by max-pooling layers.
import tensorflow as tf def cnn_model(): input_layer = tf.keras.layers.Input(shape=(32, 32, 3)) use_bias = False # Layer 1 conv = tf.keras.layers.Conv2D(32, kernel_size=(3, 3), padding='same', use_bias=use_bias, activation=None)(input_layer) bn = tf.keras.layers.BatchNormalization(epsilon=1e-06, axis=-1, momentum=0.9)(conv) activation = tf.keras.layers.Activation('relu')(bn) conv = tf.keras.layers.Conv2D(32, kernel_size=(3, 3), padding='same', use_bias=use_bias, activation=None)(activation) bn = tf.keras.layers.BatchNormalization(epsilon=1e-06, axis=-1, momentum=0.9)(conv) activation = tf.keras.layers.Activation('relu')(bn) max_pool = tf.keras.layers.MaxPooling2D(pool_size=(2, 2))(activation) dropout = tf.keras.layers.Dropout(0.2)(max_pool) # Layer 2 conv = tf.keras.layers.Conv2D(64, kernel_size=(3, 3), padding='same', use_bias=use_bias, activation=None)(dropout) bn = tf.keras.layers.BatchNormalization(epsilon=1e-06, axis=-1, momentum=0.9)(conv) activation = tf.keras.layers.Activation('relu')(bn) conv = tf.keras.layers.Conv2D(64, kernel_size=(3, 3), padding='same', use_bias=use_bias, activation=None)(activation) bn = tf.keras.layers.BatchNormalization(epsilon=1e-06, axis=-1, momentum=0.9)(conv) activation = tf.keras.layers.Activation('relu')(bn) max_pool = tf.keras.layers.MaxPooling2D()(activation) dropout = tf.keras.layers.Dropout(0.3)(max_pool) # Layer 3 conv = tf.keras.layers.Conv2D(128, kernel_size=(3, 3), padding='same', use_bias=use_bias, activation=None)(dropout) bn = tf.keras.layers.BatchNormalization(epsilon=1e-06, axis=-1, momentum=0.9)(conv) activation = tf.keras.layers.Activation('relu')(bn) conv = tf.keras.layers.Conv2D(128, kernel_size=(3, 3), padding='same', use_bias=use_bias, activation=None)(activation) bn = tf.keras.layers.BatchNormalization(epsilon=1e-06, axis=-1, momentum=0.9)(conv) activation = tf.keras.layers.Activation('relu')(bn) max_pool = tf.keras.layers.MaxPooling2D()(activation) dropout = tf.keras.layers.Dropout(0.4)(max_pool) flatten = tf.keras.layers.Flatten()(dropout) # Output layers: separate outputs for the weather and the ground labels output = tf.keras.layers.Dense(10, activation='softmax', name='output')(flatten) return tf.keras.Model(inputs=input_layer, outputs=output)
Convert Keras model in TensorFlow Estimators
Why we need to do this conversion is because we need to put it on Cloud ML Engine, which, for now at least, only accepts TensorFlow SavedModel formats.
Now the typical reason you would export a Keras model, or at least convert a Keras model to an estimator is for the ability to do better-distributed training. Instead of training it using Keras, you would convert it to TensorFlow Estimator and train it as a TensorFlow Estimator. Then you get distribution and GPU
scaling for free in terms of there’s no additional work.
model = tensorflow_model.cnn_model() model.compile( optimizer=tf.keras.optimizers.Adam(), loss=tf.keras.losses.categorical_crossentropy, metrics=['accuracy'] ) cifar_est = tf.keras.estimator.model_to_estimator(keras_model=model, model_dir="kkt")
keras.estimator
, this is one of the pieces that were added to Keras in the inside of TensorFlow. Normal Keras does not have a .estimator module. You have this estimator.model to convert TensorFlow estimator. Basically, it’s a conversion function.it’s a utility function that will take your jars model. Now, I have the model as a Python pointer. I just have that in a variable.
The names of feature columns and labels of a keras estimator come from the corresponding compiled keras model.the input key names for train_input_fn
can be obtained from keras_inception_v3.input_names
Convert Images to TFRecord
In this tutorial we use CIFAR-10 png image to train our cnn model.TFRecords are the best way to handle an image dataset in a single tfrecord file. It’s a faster reading speed when the network Architecture is complex. Download CIFAR-10 png format.
import os from os import listdir from os.path import join import numpy as np import tensorflow as tf from tensorflow import keras from tensorflow.python.keras.preprocessing.image import img_to_array, load_img bas_dir = "/home/manu/PycharmProjects/DataSet/cifar" train_dir = join(bas_dir, "train") test_dir = join(bas_dir, "test") IMG_SIZE = 32 labels = {"airplane.png": 0, "automobile.png": 1, "bird.png": 2, "cat.png": 3, "deer.png": 4, "dog.png": 5, "frog.png": 6, "horse.png": 7, "ship.png": 8, "truck.png": 9} def getFileList(dir): x = [] y = [] for f in listdir(dir): path = join(dir, f) if os.path.isfile(path): y.append(labels.get(f.split("_")[1])) x.append(path) return x, y train_x, train_y = getFileList(train_dir) test_x, test_y = getFileList(test_dir) num_class = 10 train_y = keras.utils.to_categorical(train_y, num_class) test_y = keras.utils.to_categorical(test_y, num_class) print(len(train_x), len(train_y)) print(len(test_x), len(test_y)) def _bytes_feature(value): return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value])) def convert(image_paths, labels, out_path): writer = tf.python_io.TFRecordWriter(out_path) for i in range(len(labels)): print(image_paths[i]) im = np.array(img_to_array(load_img(image_paths[i], target_size=(IMG_SIZE, IMG_SIZE))) / 255.) g_labels = labels[i].astype(np.float32) example = tf.train.Example(features=tf.train.Features( feature={'image': _bytes_feature(im.tostring()), 'labels': _bytes_feature( g_labels.tostring()) })) writer.write(example.SerializeToString()) writer.close() tfrecord_path = "/home/manu/PycharmProjects/Keras_estimator/data" path_tfrecords_train = os.path.join(tfrecord_path, "train.tfrecords") path_tfrecords_test = os.path.join(tfrecord_path, "test.tfrecords") convert(train_x, train_y, path_tfrecords_train) convert(test_x, test_y, path_tfrecords_test)
Use TensorFlow Dataset API to train Keras Model
Input data is the lifeblood of machine learning, current algorithms and hardware are so thirsty for data that we need a powerful input pipeline to be able to keep up with them. You can either feed in data from python at each step, which was kind of slow or you could set up queue runners to feed your data, and these are a little challenging to use.tf.data
which is a new library that helps you get all of your data into TensorFlow.
Our model is an Estimator, we’ll train and evaluate it a bit differently than we did in Keras. Instead of passing our features and labels to the model directly when we run training, we need to pass it an input function. In TensorFlow, input functions prepare data for the model by mapping raw input data to feature columns.
def dataset_input_fn(filenames, num_epochs): dataset = tf.data.TFRecordDataset(filenames) def parser(record): featdef = { 'image': tf.FixedLenFeature(shape=[], dtype=tf.string), 'labels': tf.FixedLenFeature(shape=[], dtype=tf.string), } example = tf.parse_single_example(record, featdef) im = tf.decode_raw(example['image'], tf.float32) im = tf.reshape(im, (IMG_SIZE, IMG_SIZE, 3)) lbl = tf.decode_raw(example['labels'], tf.float32) return im, lbl dataset = dataset.map(parser) dataset = dataset.shuffle(buffer_size=10000) dataset = dataset.batch(128) dataset = dataset.repeat(num_epochs) iterator = dataset.make_one_shot_iterator() features, labels = iterator.get_next() return features, labels
Train Model
To train our model, all we need to do is call train() and pass in the input function we just defined with our training data and labels.
tfrecord_path = "/home/manu/PycharmProjects/Keras_estimator/data" train_input = lambda: data_utils.dataset_input_fn(train_data, None) cifar_est.train(input_fn=train_input, steps=7000)
Evaluating the accuracy of our Model
Now that we’ve trained our model, we can evaluate its accuracy on our training data. We’ll use the same input function as above, this time passing it our test data instead of training data.
test_data = os.path.join(tfrecord_path, "test.tfrecords") test_input = lambda: data_utils.dataset_input_fn(test_data, 1) result = cifar_est.evaluate(input_fn=test_input, steps=1) print(result)
Predictions on trained model
Next comes the most important part: using our trained model to generate a prediction on data it hasn’t seen before. We’ll use the first 44 examples from our test dataset. To make a prediction, we can simply call .predict()
def _parse_function(filename): image_string = tf.read_file(filename) image_decoded = tf.image.decode_jpeg(image_string, channels=3) image_decoded = tf.image.convert_image_dtype(image_decoded, tf.float32) image_decoded = image_decoded image_decoded.set_shape([32, 32, 3]) return {"input_1": image_decoded} def predict_input_fn(image_path): img_filenames = tf.constant(image_path) dataset = tf.data.Dataset.from_tensor_slices(img_filenames) dataset = dataset.map(_parse_function) dataset = dataset.repeat(1) dataset = dataset.batch(32) iterator = dataset.make_one_shot_iterator() image = iterator.get_next() return image predict_result = list(cifar_est.predict(input_fn=lambda: predict_input_fn(predict_image))) pos = 1 for img, lbl, predict_lbl in zip(predict_image, true_label, predict_result): output = np.argmax(predict_lbl.get('output'), axis=None) plt.subplot(4, 11, pos) img = mpimg.imread(img) plt.imshow(img) plt.axis('off') if output == lbl: plt.title(class_maping[output]) else: plt.title(class_maping[output] + "/" + class_maping[lbl], color='#ff0000') pos += 1 plt.show()
calling predict
with our input functions we’re able to generate predictions on our trained Estimator model.
Save Keras model to Tensorflow .pb
Next we’re going to take the TensorFlow estimator model, and now we need to export it as a .pb file.
Serving inputs function
Tensor flow has a number of utilities to help us create this serving input function.
model_input_name = model.input_names[0] def serving_input_receiver_fn(): input_ph = tf.placeholder(tf.string, shape=[None], name='image_binary') images = tf.map_fn(partial(tf.image.decode_image, channels=1), input_ph, dtype=tf.uint8) images = tf.cast(images, tf.float32) / 255. images.set_shape([None, 32, 32, 3]) return tf.estimator.export.ServingInputReceiver({model_input_name: images}, {'bytes': input_ph}) cifar_est.export_savedmodel('./export', serving_input_receiver_fn=serving_input_receiver_fn)
You call export save model on our estimator passes a directory.
This post is focused on converting Keras model to an Estimator — if we wanted to improve accuracy we could try tuning our model’s hyperparameters, changing our layer size, or adding dropout to our input layer.