Let's train this model on TPU. It's worth it.

Imports


In [1]:
import os, sys, math
import numpy as np
from matplotlib import pyplot as plt
if 'google.colab' in sys.modules: # Colab-only Tensorflow version selector
  %tensorflow_version 2.x
import tensorflow as tf
print("Tensorflow version " + tf.__version__)
AUTO = tf.data.experimental.AUTOTUNE


TensorFlow 2.x selected.
Tensorflow version 2.1.0-rc1

TPU detection


In [2]:
# Detect hardware
try:
  tpu = tf.distribute.cluster_resolver.TPUClusterResolver() # TPU detection
except ValueError:
  tpu = None
  gpus = tf.config.experimental.list_logical_devices("GPU")
    
# Select appropriate distribution strategy for hardware
if tpu:
  tf.config.experimental_connect_to_cluster(tpu)
  tf.tpu.experimental.initialize_tpu_system(tpu)
  strategy = tf.distribute.experimental.TPUStrategy(tpu)
  print('Running on TPU ', tpu.master())  
elif len(gpus) > 0:
  strategy = tf.distribute.MirroredStrategy(gpus) # this works for 1 to multiple GPUs
  print('Running on ', len(gpus), ' GPU(s) ')
else:
  strategy = tf.distribute.get_strategy() # default strategy that works on CPU and single GPU
  print('Running on CPU')

# How many accelerators do we have ?
print("Number of accelerators: ", strategy.num_replicas_in_sync)


INFO:tensorflow:Initializing the TPU system: 10.55.216.162:8470
INFO:tensorflow:Initializing the TPU system: 10.55.216.162:8470
INFO:tensorflow:Clearing out eager caches
INFO:tensorflow:Clearing out eager caches
INFO:tensorflow:Finished initializing TPU system.
INFO:tensorflow:Finished initializing TPU system.
INFO:tensorflow:Found TPU system:
INFO:tensorflow:Found TPU system:
INFO:tensorflow:*** Num TPU Cores: 8
INFO:tensorflow:*** Num TPU Cores: 8
INFO:tensorflow:*** Num TPU Workers: 1
INFO:tensorflow:*** Num TPU Workers: 1
INFO:tensorflow:*** Num TPU Cores Per Worker: 8
INFO:tensorflow:*** Num TPU Cores Per Worker: 8
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:localhost/replica:0/task:0/device:CPU:0, CPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:localhost/replica:0/task:0/device:CPU:0, CPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:localhost/replica:0/task:0/device:XLA_CPU:0, XLA_CPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:localhost/replica:0/task:0/device:XLA_CPU:0, XLA_CPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:CPU:0, CPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:CPU:0, CPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:0, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:0, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:1, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:1, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:2, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:2, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:3, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:3, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:4, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:4, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:5, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:5, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:6, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:6, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:7, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU:7, TPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU_SYSTEM:0, TPU_SYSTEM, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:TPU_SYSTEM:0, TPU_SYSTEM, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:XLA_CPU:0, XLA_CPU, 0, 0)
INFO:tensorflow:*** Available Device: _DeviceAttributes(/job:worker/replica:0/task:0/device:XLA_CPU:0, XLA_CPU, 0, 0)
Running on TPU  grpc://10.55.216.162:8470
Number of accelerators:  8

Configuration


In [3]:
GCS_PATTERN = 'gs://flowers-public/tfrecords-jpeg-192x192-2/*.tfrec'
IMAGE_SIZE = [192, 192]

if tpu:
  BATCH_SIZE = 16*strategy.num_replicas_in_sync  # A TPU has 8 cores so this will be 128
else:
  BATCH_SIZE = 32  # On Colab/GPU, a higher batch size does not help and sometimes does not fit on the GPU (OOM)

VALIDATION_SPLIT = 0.19
CLASSES = ['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips'] # do not change, maps to the labels in the data (folder names)

# splitting data files between training and validation
filenames = tf.io.gfile.glob(GCS_PATTERN)
split = int(len(filenames) * VALIDATION_SPLIT)
training_filenames = filenames[split:]
validation_filenames = filenames[:split]
print("Pattern matches {} data files. Splitting dataset into {} training files and {} validation files".format(len(filenames), len(training_filenames), len(validation_filenames)))
validation_steps = int(3670 // len(filenames) * len(validation_filenames)) // BATCH_SIZE
steps_per_epoch = int(3670 // len(filenames) * len(training_filenames)) // BATCH_SIZE
print("With a batch size of {}, there will be {} batches per training epoch and {} batch(es) per validation run.".format(BATCH_SIZE, steps_per_epoch, validation_steps))


Pattern matches 16 data files. Splitting dataset into 13 training files and 3 validation files
With a batch size of 128, there will be 23 batches per training epoch and 5 batch(es) per validation run.

In [0]:
#@title display utilities [RUN ME]

def dataset_to_numpy_util(dataset, N):
  dataset = dataset.batch(N)
  
  # In eager mode, iterate in the Datset directly.
  for images, labels in dataset:
    numpy_images = images.numpy()
    numpy_labels = labels.numpy()
    break;

  return numpy_images, numpy_labels

def title_from_label_and_target(label, correct_label):
  label = np.argmax(label, axis=-1)  # one-hot to class number
  correct_label = np.argmax(correct_label, axis=-1) # one-hot to class number
  correct = (label == correct_label)
  return "{} [{}{}{}]".format(CLASSES[label], str(correct), ', shoud be ' if not correct else '',
                              CLASSES[correct_label] if not correct else ''), correct

def display_one_flower(image, title, subplot, red=False):
    plt.subplot(subplot)
    plt.axis('off')
    plt.imshow(image)
    plt.title(title, fontsize=16, color='red' if red else 'black')
    return subplot+1
  
def display_9_images_from_dataset(dataset):
  subplot=331
  plt.figure(figsize=(13,13))
  images, labels = dataset_to_numpy_util(dataset, 9)
  for i, image in enumerate(images):
    title = CLASSES[np.argmax(labels[i], axis=-1)]
    subplot = display_one_flower(image, title, subplot)
    if i >= 8:
      break;
              
  plt.tight_layout()
  plt.subplots_adjust(wspace=0.1, hspace=0.1)
  plt.show()
  
def display_9_images_with_predictions(images, predictions, labels):
  subplot=331
  plt.figure(figsize=(13,13))
  for i, image in enumerate(images):
    title, correct = title_from_label_and_target(predictions[i], labels[i])
    subplot = display_one_flower(image, title, subplot, not correct)
    if i >= 8:
      break;
              
  plt.tight_layout()
  plt.subplots_adjust(wspace=0.1, hspace=0.1)
  plt.show()
  
def display_training_curves(training, validation, title, subplot):
  if subplot%10==1: # set up the subplots on the first call
    plt.subplots(figsize=(10,10), facecolor='#F0F0F0')
    plt.tight_layout()
  ax = plt.subplot(subplot)
  ax.set_facecolor('#F8F8F8')
  ax.plot(training)
  ax.plot(validation)
  ax.set_title('model '+ title)
  ax.set_ylabel(title)
  ax.set_xlabel('epoch')
  ax.legend(['train', 'valid.'])

Read images and labels from TFRecords


In [0]:
def read_tfrecord(example):
    features = {
        "image": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring
        "class": tf.io.FixedLenFeature([], tf.int64),  # shape [] means scalar
        "one_hot_class": tf.io.VarLenFeature(tf.float32),
    }
    example = tf.io.parse_single_example(example, features)
    image = tf.image.decode_jpeg(example['image'], channels=3)
    image = tf.cast(image, tf.float32) / 255.0  # convert image to floats in [0, 1] range
    image = tf.reshape(image, [*IMAGE_SIZE, 3]) # explicit size will be needed for TPU
    one_hot_class = tf.sparse.to_dense(example['one_hot_class'])
    one_hot_class = tf.reshape(one_hot_class, [5])
    return image, one_hot_class

def load_dataset(filenames):
  # read from TFRecords. For optimal performance, read from multiple
  # TFRecord files at once and set the option experimental_deterministic = False
  # to allow order-altering optimizations.

  option_no_order = tf.data.Options()
  option_no_order.experimental_deterministic = False

  dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO)
  dataset = dataset.with_options(option_no_order)
  dataset = dataset.map(read_tfrecord, num_parallel_calls=AUTO)
  return dataset

In [6]:
display_9_images_from_dataset(load_dataset(training_filenames))


training and validation datasets


In [0]:
def data_augment(image, one_hot_class):
    image = tf.image.random_flip_left_right(image)
    image = tf.image.random_saturation(image, 0, 2)
    return image, one_hot_class

def get_batched_dataset(filenames, train=False):
  dataset = load_dataset(filenames)
  dataset = dataset.cache() # This dataset fits in RAM
  if train:
    # Best practices for Keras:
    # Training dataset: repeat then batch
    # Evaluation dataset: do not repeat
    dataset = dataset.repeat()
    dataset = dataset.map(data_augment, num_parallel_calls=AUTO)
    dataset = dataset.shuffle(2000)
  dataset = dataset.batch(BATCH_SIZE)
  dataset = dataset.prefetch(AUTO) # prefetch next batch while training (autotune prefetch buffer size)
  # should shuffle too but this dataset was well shuffled on disk already
  return dataset
  # source: Dataset performance guide: https://www.tensorflow.org/guide/performance/datasets

# instantiate the datasets
training_dataset = get_batched_dataset(training_filenames, train=True)
validation_dataset = get_batched_dataset(validation_filenames, train=False)

some_flowers, some_labels = dataset_to_numpy_util(load_dataset(validation_filenames), 160)

Model


In [21]:
with strategy.scope(): # this line is all that is needed to run on TPU (or multi-GPU, ...)

  bnmomemtum=0.9
  def fire(x, squeeze, expand):
    y  = tf.keras.layers.Conv2D(filters=squeeze, kernel_size=1, activation='relu', padding='same')(x)
    y = tf.keras.layers.BatchNormalization(momentum=bnmomemtum)(y)
    y1 = tf.keras.layers.Conv2D(filters=expand//2, kernel_size=1, activation='relu', padding='same')(y)
    y1 = tf.keras.layers.BatchNormalization(momentum=bnmomemtum)(y1)
    y3 = tf.keras.layers.Conv2D(filters=expand//2, kernel_size=3, activation='relu', padding='same')(y)
    y3 = tf.keras.layers.BatchNormalization(momentum=bnmomemtum)(y3)
    return tf.keras.layers.concatenate([y1, y3])

  def fire_module(squeeze, expand):
    return lambda x: fire(x, squeeze, expand)

  x = tf.keras.layers.Input(shape=[*IMAGE_SIZE, 3]) # input is 192x192 pixels RGB

  y = tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', use_bias=True, activation='relu')(x)
  y = tf.keras.layers.BatchNormalization(momentum=bnmomemtum)(y)
  y = fire_module(24, 48)(y)
  y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
  y = fire_module(48, 96)(y)
  y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
  y = fire_module(64, 128)(y)
  y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
  y = fire_module(48, 96)(y)
  y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
  y = fire_module(24, 48)(y)
  y = tf.keras.layers.GlobalAveragePooling2D()(y)
  y = tf.keras.layers.Dense(5, activation='softmax')(y)

  model = tf.keras.Model(x, y)

  model.compile(
    optimizer='adam',
    loss= 'categorical_crossentropy',
    metrics=['accuracy'])

  model.summary()


Model: "model_4"
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to                     
==================================================================================================
input_5 (InputLayer)            [(None, 192, 192, 3) 0                                            
__________________________________________________________________________________________________
conv2d_64 (Conv2D)              (None, 192, 192, 32) 896         input_5[0][0]                    
__________________________________________________________________________________________________
batch_normalization_64 (BatchNo (None, 192, 192, 32) 128         conv2d_64[0][0]                  
__________________________________________________________________________________________________
conv2d_65 (Conv2D)              (None, 192, 192, 24) 792         batch_normalization_64[0][0]     
__________________________________________________________________________________________________
batch_normalization_65 (BatchNo (None, 192, 192, 24) 96          conv2d_65[0][0]                  
__________________________________________________________________________________________________
conv2d_66 (Conv2D)              (None, 192, 192, 24) 600         batch_normalization_65[0][0]     
__________________________________________________________________________________________________
conv2d_67 (Conv2D)              (None, 192, 192, 24) 5208        batch_normalization_65[0][0]     
__________________________________________________________________________________________________
batch_normalization_66 (BatchNo (None, 192, 192, 24) 96          conv2d_66[0][0]                  
__________________________________________________________________________________________________
batch_normalization_67 (BatchNo (None, 192, 192, 24) 96          conv2d_67[0][0]                  
__________________________________________________________________________________________________
concatenate_20 (Concatenate)    (None, 192, 192, 48) 0           batch_normalization_66[0][0]     
                                                                 batch_normalization_67[0][0]     
__________________________________________________________________________________________________
max_pooling2d_16 (MaxPooling2D) (None, 96, 96, 48)   0           concatenate_20[0][0]             
__________________________________________________________________________________________________
conv2d_68 (Conv2D)              (None, 96, 96, 48)   2352        max_pooling2d_16[0][0]           
__________________________________________________________________________________________________
batch_normalization_68 (BatchNo (None, 96, 96, 48)   192         conv2d_68[0][0]                  
__________________________________________________________________________________________________
conv2d_69 (Conv2D)              (None, 96, 96, 48)   2352        batch_normalization_68[0][0]     
__________________________________________________________________________________________________
conv2d_70 (Conv2D)              (None, 96, 96, 48)   20784       batch_normalization_68[0][0]     
__________________________________________________________________________________________________
batch_normalization_69 (BatchNo (None, 96, 96, 48)   192         conv2d_69[0][0]                  
__________________________________________________________________________________________________
batch_normalization_70 (BatchNo (None, 96, 96, 48)   192         conv2d_70[0][0]                  
__________________________________________________________________________________________________
concatenate_21 (Concatenate)    (None, 96, 96, 96)   0           batch_normalization_69[0][0]     
                                                                 batch_normalization_70[0][0]     
__________________________________________________________________________________________________
max_pooling2d_17 (MaxPooling2D) (None, 48, 48, 96)   0           concatenate_21[0][0]             
__________________________________________________________________________________________________
conv2d_71 (Conv2D)              (None, 48, 48, 64)   6208        max_pooling2d_17[0][0]           
__________________________________________________________________________________________________
batch_normalization_71 (BatchNo (None, 48, 48, 64)   256         conv2d_71[0][0]                  
__________________________________________________________________________________________________
conv2d_72 (Conv2D)              (None, 48, 48, 64)   4160        batch_normalization_71[0][0]     
__________________________________________________________________________________________________
conv2d_73 (Conv2D)              (None, 48, 48, 64)   36928       batch_normalization_71[0][0]     
__________________________________________________________________________________________________
batch_normalization_72 (BatchNo (None, 48, 48, 64)   256         conv2d_72[0][0]                  
__________________________________________________________________________________________________
batch_normalization_73 (BatchNo (None, 48, 48, 64)   256         conv2d_73[0][0]                  
__________________________________________________________________________________________________
concatenate_22 (Concatenate)    (None, 48, 48, 128)  0           batch_normalization_72[0][0]     
                                                                 batch_normalization_73[0][0]     
__________________________________________________________________________________________________
max_pooling2d_18 (MaxPooling2D) (None, 24, 24, 128)  0           concatenate_22[0][0]             
__________________________________________________________________________________________________
conv2d_74 (Conv2D)              (None, 24, 24, 48)   6192        max_pooling2d_18[0][0]           
__________________________________________________________________________________________________
batch_normalization_74 (BatchNo (None, 24, 24, 48)   192         conv2d_74[0][0]                  
__________________________________________________________________________________________________
conv2d_75 (Conv2D)              (None, 24, 24, 48)   2352        batch_normalization_74[0][0]     
__________________________________________________________________________________________________
conv2d_76 (Conv2D)              (None, 24, 24, 48)   20784       batch_normalization_74[0][0]     
__________________________________________________________________________________________________
batch_normalization_75 (BatchNo (None, 24, 24, 48)   192         conv2d_75[0][0]                  
__________________________________________________________________________________________________
batch_normalization_76 (BatchNo (None, 24, 24, 48)   192         conv2d_76[0][0]                  
__________________________________________________________________________________________________
concatenate_23 (Concatenate)    (None, 24, 24, 96)   0           batch_normalization_75[0][0]     
                                                                 batch_normalization_76[0][0]     
__________________________________________________________________________________________________
max_pooling2d_19 (MaxPooling2D) (None, 12, 12, 96)   0           concatenate_23[0][0]             
__________________________________________________________________________________________________
conv2d_77 (Conv2D)              (None, 12, 12, 24)   2328        max_pooling2d_19[0][0]           
__________________________________________________________________________________________________
batch_normalization_77 (BatchNo (None, 12, 12, 24)   96          conv2d_77[0][0]                  
__________________________________________________________________________________________________
conv2d_78 (Conv2D)              (None, 12, 12, 24)   600         batch_normalization_77[0][0]     
__________________________________________________________________________________________________
conv2d_79 (Conv2D)              (None, 12, 12, 24)   5208        batch_normalization_77[0][0]     
__________________________________________________________________________________________________
batch_normalization_78 (BatchNo (None, 12, 12, 24)   96          conv2d_78[0][0]                  
__________________________________________________________________________________________________
batch_normalization_79 (BatchNo (None, 12, 12, 24)   96          conv2d_79[0][0]                  
__________________________________________________________________________________________________
concatenate_24 (Concatenate)    (None, 12, 12, 48)   0           batch_normalization_78[0][0]     
                                                                 batch_normalization_79[0][0]     
__________________________________________________________________________________________________
global_average_pooling2d_4 (Glo (None, 48)           0           concatenate_24[0][0]             
__________________________________________________________________________________________________
dense_4 (Dense)                 (None, 5)            245         global_average_pooling2d_4[0][0] 
==================================================================================================
Total params: 120,613
Trainable params: 119,301
Non-trainable params: 1,312
__________________________________________________________________________________________________

Training


In [22]:
EPOCHS = 35

history = model.fit(training_dataset, steps_per_epoch=steps_per_epoch, epochs=EPOCHS,
                    validation_data=validation_dataset)


Train for 23 steps
Epoch 1/35
23/23 [==============================] - 35s 2s/step - loss: 1.3346 - accuracy: 0.4361 - val_loss: 1.9849 - val_accuracy: 0.2420
Epoch 2/35
23/23 [==============================] - 3s 131ms/step - loss: 1.1345 - accuracy: 0.5594 - val_loss: 1.4754 - val_accuracy: 0.4145
Epoch 3/35
23/23 [==============================] - 3s 130ms/step - loss: 1.0336 - accuracy: 0.6124 - val_loss: 0.9516 - val_accuracy: 0.6217
Epoch 4/35
23/23 [==============================] - 3s 134ms/step - loss: 0.9750 - accuracy: 0.6172 - val_loss: 0.9085 - val_accuracy: 0.6638
Epoch 5/35
23/23 [==============================] - 3s 130ms/step - loss: 0.9412 - accuracy: 0.6535 - val_loss: 0.8398 - val_accuracy: 0.6826
Epoch 6/35
23/23 [==============================] - 3s 128ms/step - loss: 0.9029 - accuracy: 0.6593 - val_loss: 0.8212 - val_accuracy: 0.6812
Epoch 7/35
23/23 [==============================] - 3s 129ms/step - loss: 0.8858 - accuracy: 0.6593 - val_loss: 0.7716 - val_accuracy: 0.7072
Epoch 8/35
23/23 [==============================] - 3s 130ms/step - loss: 0.8394 - accuracy: 0.6861 - val_loss: 0.7525 - val_accuracy: 0.7232
Epoch 9/35
23/23 [==============================] - 3s 128ms/step - loss: 0.8323 - accuracy: 0.6899 - val_loss: 0.7927 - val_accuracy: 0.6971
Epoch 10/35
23/23 [==============================] - 3s 128ms/step - loss: 0.8001 - accuracy: 0.7055 - val_loss: 1.0298 - val_accuracy: 0.6304
Epoch 11/35
23/23 [==============================] - 3s 129ms/step - loss: 0.8104 - accuracy: 0.7041 - val_loss: 0.8145 - val_accuracy: 0.7101
Epoch 12/35
23/23 [==============================] - 3s 128ms/step - loss: 0.7535 - accuracy: 0.7235 - val_loss: 0.6810 - val_accuracy: 0.7406
Epoch 13/35
23/23 [==============================] - 3s 129ms/step - loss: 0.7210 - accuracy: 0.7374 - val_loss: 0.6915 - val_accuracy: 0.7275
Epoch 14/35
23/23 [==============================] - 3s 130ms/step - loss: 0.7413 - accuracy: 0.7300 - val_loss: 1.0259 - val_accuracy: 0.6319
Epoch 15/35
23/23 [==============================] - 3s 130ms/step - loss: 0.7089 - accuracy: 0.7296 - val_loss: 0.6727 - val_accuracy: 0.7551
Epoch 16/35
23/23 [==============================] - 3s 128ms/step - loss: 0.6738 - accuracy: 0.7483 - val_loss: 0.7487 - val_accuracy: 0.7159
Epoch 17/35
23/23 [==============================] - 3s 128ms/step - loss: 0.6625 - accuracy: 0.7531 - val_loss: 0.6422 - val_accuracy: 0.7420
Epoch 18/35
23/23 [==============================] - 3s 128ms/step - loss: 0.6197 - accuracy: 0.7785 - val_loss: 0.7248 - val_accuracy: 0.7493
Epoch 19/35
23/23 [==============================] - 3s 128ms/step - loss: 0.6497 - accuracy: 0.7666 - val_loss: 0.6348 - val_accuracy: 0.7536
Epoch 20/35
23/23 [==============================] - 3s 130ms/step - loss: 0.6122 - accuracy: 0.7700 - val_loss: 0.5869 - val_accuracy: 0.7928
Epoch 21/35
23/23 [==============================] - 3s 127ms/step - loss: 0.5849 - accuracy: 0.7850 - val_loss: 0.5993 - val_accuracy: 0.7884
Epoch 22/35
23/23 [==============================] - 3s 129ms/step - loss: 0.5847 - accuracy: 0.7942 - val_loss: 0.6432 - val_accuracy: 0.7652
Epoch 23/35
23/23 [==============================] - 3s 129ms/step - loss: 0.5819 - accuracy: 0.7901 - val_loss: 0.5595 - val_accuracy: 0.8058
Epoch 24/35
23/23 [==============================] - 3s 130ms/step - loss: 0.5542 - accuracy: 0.8030 - val_loss: 0.7815 - val_accuracy: 0.7406
Epoch 25/35
23/23 [==============================] - 3s 134ms/step - loss: 0.5087 - accuracy: 0.8132 - val_loss: 0.6459 - val_accuracy: 0.7478
Epoch 26/35
23/23 [==============================] - 3s 129ms/step - loss: 0.5101 - accuracy: 0.8207 - val_loss: 0.6724 - val_accuracy: 0.7594
Epoch 27/35
23/23 [==============================] - 3s 129ms/step - loss: 0.4877 - accuracy: 0.8251 - val_loss: 0.5945 - val_accuracy: 0.7783
Epoch 28/35
23/23 [==============================] - 3s 129ms/step - loss: 0.5001 - accuracy: 0.8196 - val_loss: 0.6236 - val_accuracy: 0.7681
Epoch 29/35
23/23 [==============================] - 3s 130ms/step - loss: 0.4749 - accuracy: 0.8319 - val_loss: 0.5598 - val_accuracy: 0.7957
Epoch 30/35
23/23 [==============================] - 3s 127ms/step - loss: 0.4834 - accuracy: 0.8261 - val_loss: 0.8824 - val_accuracy: 0.7058
Epoch 31/35
23/23 [==============================] - 3s 128ms/step - loss: 0.4530 - accuracy: 0.8329 - val_loss: 0.6356 - val_accuracy: 0.7623
Epoch 32/35
23/23 [==============================] - 3s 128ms/step - loss: 0.4508 - accuracy: 0.8346 - val_loss: 0.6290 - val_accuracy: 0.7609
Epoch 33/35
23/23 [==============================] - 3s 128ms/step - loss: 0.4452 - accuracy: 0.8448 - val_loss: 0.5604 - val_accuracy: 0.7826
Epoch 34/35
23/23 [==============================] - 3s 127ms/step - loss: 0.4517 - accuracy: 0.8353 - val_loss: 0.5687 - val_accuracy: 0.8014
Epoch 35/35
23/23 [==============================] - 3s 131ms/step - loss: 0.3968 - accuracy: 0.8679 - val_loss: 0.5266 - val_accuracy: 0.8000

In [23]:
print(history.history.keys())
display_training_curves(history.history['accuracy'], history.history['val_accuracy'], 'accuracy', 211)
display_training_curves(history.history['loss'], history.history['val_loss'], 'loss', 212)


dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])

Predictions


In [24]:
# randomize the input so that you can execute multiple times to change results
permutation = np.random.permutation(160)
some_flowers, some_labels = (some_flowers[permutation], some_labels[permutation])

predictions = model.predict(some_flowers, batch_size=16)
evaluations = model.evaluate(some_flowers, some_labels, batch_size=16)
  
print(np.array(CLASSES)[np.argmax(predictions, axis=-1)].tolist())
print('[val_loss, val_acc]', evaluations)


160/160 [==============================] - 3s 19ms/sample - loss: 0.6513 - accuracy: 0.7812
['tulips', 'roses', 'tulips', 'dandelion', 'sunflowers', 'tulips', 'sunflowers', 'sunflowers', 'tulips', 'tulips', 'roses', 'roses', 'dandelion', 'sunflowers', 'dandelion', 'dandelion', 'tulips', 'sunflowers', 'dandelion', 'tulips', 'sunflowers', 'sunflowers', 'daisy', 'dandelion', 'sunflowers', 'daisy', 'tulips', 'tulips', 'dandelion', 'dandelion', 'tulips', 'tulips', 'dandelion', 'dandelion', 'dandelion', 'roses', 'tulips', 'dandelion', 'tulips', 'sunflowers', 'sunflowers', 'tulips', 'dandelion', 'sunflowers', 'dandelion', 'daisy', 'daisy', 'tulips', 'tulips', 'sunflowers', 'tulips', 'dandelion', 'sunflowers', 'tulips', 'roses', 'roses', 'dandelion', 'roses', 'roses', 'sunflowers', 'dandelion', 'tulips', 'roses', 'tulips', 'tulips', 'tulips', 'tulips', 'dandelion', 'daisy', 'roses', 'sunflowers', 'dandelion', 'dandelion', 'roses', 'tulips', 'sunflowers', 'sunflowers', 'sunflowers', 'sunflowers', 'tulips', 'tulips', 'dandelion', 'dandelion', 'tulips', 'tulips', 'roses', 'roses', 'daisy', 'roses', 'dandelion', 'tulips', 'tulips', 'roses', 'sunflowers', 'dandelion', 'tulips', 'sunflowers', 'tulips', 'daisy', 'roses', 'daisy', 'roses', 'roses', 'dandelion', 'tulips', 'dandelion', 'tulips', 'sunflowers', 'tulips', 'roses', 'dandelion', 'sunflowers', 'sunflowers', 'sunflowers', 'tulips', 'dandelion', 'sunflowers', 'sunflowers', 'roses', 'tulips', 'roses', 'dandelion', 'tulips', 'dandelion', 'dandelion', 'dandelion', 'roses', 'sunflowers', 'dandelion', 'sunflowers', 'dandelion', 'sunflowers', 'roses', 'daisy', 'roses', 'tulips', 'tulips', 'daisy', 'sunflowers', 'dandelion', 'daisy', 'roses', 'roses', 'sunflowers', 'roses', 'dandelion', 'dandelion', 'tulips', 'tulips', 'sunflowers', 'tulips', 'sunflowers', 'tulips', 'sunflowers', 'dandelion', 'dandelion', 'sunflowers', 'roses', 'tulips', 'daisy']
[val_loss, val_acc] [0.6512959212064743, 0.78125]

In [25]:
display_9_images_with_predictions(some_flowers, predictions, some_labels)


License


author: Martin Gorner
twitter: @martin_gorner


Copyright 2020 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.


This is not an official Google product but sample code provided for an educational purpose