CNN Application - mood and sign classifer using the TF Keras

deep learning

In this notebook:

Packages

Code
import math
import numpy as np
import h5py
import matplotlib.pyplot as plt
from matplotlib.pyplot import imread
import scipy
from PIL import Image
import pandas as pd
import tensorflow as tf
import tensorflow.keras.layers as tfl
from tensorflow.python.framework import ops
from cnn_utils import *
from test_utils import summary, comparator

%matplotlib inline
np.random.seed(1)

Load the Data and Split the Data into Train/Test Sets

You’ll be using the Happy House dataset for this part of the assignment, which contains images of peoples’ faces. Your task will be to build a ConvNet that determines whether the people in the images are smiling or not – because they only get to enter the house if they’re smiling!

Code
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_happy_dataset()

# Normalize image vectors
X_train = X_train_orig/255.
X_test = X_test_orig/255.

# Reshape
Y_train = Y_train_orig.T
Y_test = Y_test_orig.T

print ("number of training examples = " + str(X_train.shape[0]))
print ("number of test examples = " + str(X_test.shape[0]))
print ("X_train shape: " + str(X_train.shape))
print ("Y_train shape: " + str(Y_train.shape))
print ("X_test shape: " + str(X_test.shape))
print ("Y_test shape: " + str(Y_test.shape))
number of training examples = 600
number of test examples = 150
X_train shape: (600, 64, 64, 3)
Y_train shape: (600, 1)
X_test shape: (150, 64, 64, 3)
Y_test shape: (150, 1)

You can display the images contained in the dataset. Images are 64x64 pixels in RGB format (3 channels).

Code
index = 424
plt.imshow(X_train_orig[index]) #display sample training image
plt.show()

Layers in TF Keras

In the previous notebook, you created layers manually in numpy. In TF Keras, you don’t have to write code directly to create layers. Rather, TF Keras has pre-defined layers you can use.

When you create a layer in TF Keras, you are creating a function that takes some input and transforms it into an output you can reuse later. Nice and easy!

The Sequential API

In the previous assignment, you built helper functions using numpy to understand the mechanics behind convolutional neural networks. Most practical applications of deep learning today are built using programming frameworks, which have many built-in functions you can simply call. Keras is a high-level abstraction built on top of TensorFlow, which allows for even more simplified and optimized model creation and training.

For the first part of this assignment, you’ll create a model using TF Keras’ Sequential API, which allows you to build layer by layer, and is ideal for building models where each layer has exactly one input tensor and one output tensor.

As you’ll see, using the Sequential API is simple and straightforward, but is only appropriate for simpler, more straightforward tasks. Later in this notebook you’ll spend some time building with a more flexible, powerful alternative: the Functional API.

Create the Sequential Model

As mentioned earlier, the TensorFlow Keras Sequential API can be used to build simple models with layer operations that proceed in a sequential order.

You can also add layers incrementally to a Sequential model with the .add() method, or remove them using the .pop() method, much like you would in a regular Python list.

Actually, you can think of a Sequential model as behaving like a list of layers. Like Python lists, Sequential layers are ordered, and the order in which they are specified matters. If your model is non-linear or contains layers with multiple inputs or outputs, a Sequential model wouldn’t be the right choice!

For any layer construction in Keras, you’ll need to specify the input shape in advance. This is because in Keras, the shape of the weights is based on the shape of the inputs. The weights are only created when the model first sees some input data. Sequential models can be created by passing a list of layers to the Sequential constructor, like you will do in the next assignment.

happyModel

Implement the happyModel function below to build the following model: ZEROPAD2D -> CONV2D -> BATCHNORM -> RELU -> MAXPOOL -> FLATTEN -> DENSE. Take help from tf.keras.layers

Also, plug in the following parameters for all the steps:

Hint:

Use tfl as shorthand for tensorflow.keras.layers

Code
# GRADED FUNCTION: happyModel

def happyModel():
    """
    Implements the forward propagation for the binary classification model:
    ZEROPAD2D -> CONV2D -> BATCHNORM -> RELU -> MAXPOOL -> FLATTEN -> DENSE
    Returns:
    model -- TF Keras model (object containing the information for the entire training process) 
    """
    model = tf.keras.Sequential([

        ## ZeroPadding2D with padding 3, input shape of 64 x 64 x 3
        tf.keras.layers.ZeroPadding2D(padding=(3,3),input_shape=(64, 64, 3), data_format="channels_last"),
        ## Conv2D with 32 7x7 filters and stride of 1
        tf.keras.layers.Conv2D(32, (7, 7), strides = (1, 1), name = 'conv0'),
        ## BatchNormalization for axis 3
        tf.keras.layers.BatchNormalization(axis = 3, name = 'bn0'),
        
        tf.keras.layers.ReLU(max_value=None, negative_slope=0.0, threshold=0.0),
        ## Max Pooling 2D with default parameters
        tf.keras.layers.MaxPooling2D((2, 2), name='max_pool0'),
    
        tf.keras.layers.Flatten(),
        ## Dense layer with 1 unit for output & 'sigmoid' activation
        tf.keras.layers.Dense(1, activation='sigmoid', name='fc'),

        ])
    
    return model
Code
happy_model = happyModel()
# Print a summary for each layer
for layer in summary(happy_model):
    print(layer)
    
output = [['ZeroPadding2D', (None, 70, 70, 3), 0, ((3, 3), (3, 3))],
            ['Conv2D', (None, 64, 64, 32), 4736, 'valid', 'linear', 'GlorotUniform'],
            ['BatchNormalization', (None, 64, 64, 32), 128],
            ['ReLU', (None, 64, 64, 32), 0],
            ['MaxPooling2D', (None, 32, 32, 32), 0, (2, 2), (2, 2), 'valid'],
            ['Flatten', (None, 32768), 0],
            ['Dense', (None, 1), 32769, 'sigmoid']]
    
comparator(summary(happy_model), output)
['ZeroPadding2D', (None, 70, 70, 3), 0, ((3, 3), (3, 3))]
['Conv2D', (None, 64, 64, 32), 4736, 'valid', 'linear', 'GlorotUniform']
['BatchNormalization', (None, 64, 64, 32), 128]
['ReLU', (None, 64, 64, 32), 0]
['MaxPooling2D', (None, 32, 32, 32), 0, (2, 2), (2, 2), 'valid']
['Flatten', (None, 32768), 0]
['Dense', (None, 1), 32769, 'sigmoid']
All tests passed!

Now that your model is created, you can compile it for training with an optimizer and loss of your choice. When the string accuracy is specified as a metric, the type of accuracy used will be automatically converted based on the loss function used. This is one of the many optimizations built into TensorFlow that make your life easier! If you’d like to read more on how the compiler operates, check the docs here.

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

It’s time to check your model’s parameters with the .summary() method. This will display the types of layers you have, the shape of the outputs, and how many parameters are in each layer.

Code
happy_model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
zero_padding2d (ZeroPadding2 (None, 70, 70, 3)         0         
_________________________________________________________________
conv0 (Conv2D)               (None, 64, 64, 32)        4736      
_________________________________________________________________
bn0 (BatchNormalization)     (None, 64, 64, 32)        128       
_________________________________________________________________
re_lu (ReLU)                 (None, 64, 64, 32)        0         
_________________________________________________________________
max_pool0 (MaxPooling2D)     (None, 32, 32, 32)        0         
_________________________________________________________________
flatten (Flatten)            (None, 32768)             0         
_________________________________________________________________
fc (Dense)                   (None, 1)                 32769     
=================================================================
Total params: 37,633
Trainable params: 37,569
Non-trainable params: 64
_________________________________________________________________

Train and Evaluate the Model

After creating the model, compiling it with your choice of optimizer and loss function, and doing a sanity check on its contents, you are now ready to build!

Simply call .fit() to train. That’s it! No need for mini-batching, saving, or complex backpropagation computations. That’s all been done for you, as you’re using a TensorFlow dataset with the batches specified already. You do have the option to specify epoch number or minibatch size if you like (for example, in the case of an un-batched dataset).

Code
happy_model.fit(X_train, Y_train, epochs=10, batch_size=16)
Epoch 1/10
38/38 [==============================] - 4s 103ms/step - loss: 1.1249 - accuracy: 0.6967
Epoch 2/10
38/38 [==============================] - 4s 98ms/step - loss: 0.3563 - accuracy: 0.8650
Epoch 3/10
38/38 [==============================] - 4s 97ms/step - loss: 0.1483 - accuracy: 0.9417
Epoch 4/10
38/38 [==============================] - 4s 97ms/step - loss: 0.1049 - accuracy: 0.9683
Epoch 5/10
38/38 [==============================] - 4s 97ms/step - loss: 0.1136 - accuracy: 0.9650
Epoch 6/10
38/38 [==============================] - 4s 100ms/step - loss: 0.1159 - accuracy: 0.9583
Epoch 7/10
38/38 [==============================] - 4s 100ms/step - loss: 0.2163 - accuracy: 0.9383
Epoch 8/10
38/38 [==============================] - 4s 97ms/step - loss: 0.0828 - accuracy: 0.9750
Epoch 9/10
38/38 [==============================] - 4s 98ms/step - loss: 0.0572 - accuracy: 0.9850
Epoch 10/10
38/38 [==============================] - 4s 98ms/step - loss: 0.0688 - accuracy: 0.9700
<tensorflow.python.keras.callbacks.History at 0x7f119319a150>

After that completes, just use .evaluate() to evaluate against your test set. This function will print the value of the loss function and the performance metrics specified during the compilation of the model. In this case, the binary_crossentropy and the accuracy respectively.

Code
happy_model.evaluate(X_test, Y_test)
5/5 [==============================] - 0s 36ms/step - loss: 0.2318 - accuracy: 0.9000
[0.23178650438785553, 0.8999999761581421]

But what if you need to build a model with shared layers, branches, or multiple inputs and outputs? This is where Sequential, with its beautifully simple yet limited functionality, won’t be able to help you.

The Functional API

Here you’ll use Keras’ flexible Functional API to build a ConvNet that can differentiate between 6 sign language digits.

The Functional API can handle models with non-linear topology, shared layers, as well as layers with multiple inputs or outputs. Imagine that, where the Sequential API requires the model to move in a linear fashion through its layers, the Functional API allows much more flexibility. Where Sequential is a straight line, a Functional model is a graph, where the nodes of the layers can connect in many more ways than one.

In the visual example below, the one possible direction of the movement Sequential model is shown in contrast to a skip connection, which is just one of the many ways a Functional model can be constructed. A skip connection, as you might have guessed, skips some layer in the network and feeds the output to a later layer in the network. Don’t worry, you’ll be spending more time with skip connections very soon!

Load the SIGNS Dataset

As a reminder, the SIGNS dataset is a collection of 6 signs representing numbers from 0 to 5.

Code
# Loading the data (signs)
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_signs_dataset()
Code
# Example of an image from the dataset
index = 9
plt.imshow(X_train_orig[index])
print ("y = " + str(np.squeeze(Y_train_orig[:, index])))
y = 4

Split the Data into Train/Test Sets

In Course 2, you built a fully-connected network for this dataset. But since this is an image dataset, it is more natural to apply a ConvNet to it.

To get started, let’s examine the shapes of your data.

Code
X_train = X_train_orig/255.
X_test = X_test_orig/255.
Y_train = convert_to_one_hot(Y_train_orig, 6).T
Y_test = convert_to_one_hot(Y_test_orig, 6).T
print ("number of training examples = " + str(X_train.shape[0]))
print ("number of test examples = " + str(X_test.shape[0]))
print ("X_train shape: " + str(X_train.shape))
print ("Y_train shape: " + str(Y_train.shape))
print ("X_test shape: " + str(X_test.shape))
print ("Y_test shape: " + str(Y_test.shape))
number of training examples = 1080
number of test examples = 120
X_train shape: (1080, 64, 64, 3)
Y_train shape: (1080, 6)
X_test shape: (120, 64, 64, 3)
Y_test shape: (120, 6)

Forward Propagation

In TensorFlow, there are built-in functions that implement the convolution steps for you. By now, you should be familiar with how TensorFlow builds computational graphs. In the Functional API, you create a graph of layers. This is what allows such great flexibility.

However, the following model could also be defined using the Sequential API since the information flow is on a single line. But don’t deviate. What we want you to learn is to use the functional API.

Begin building your graph of layers by creating an input node that functions as a callable object:

  • input_img = tf.keras.Input(shape=input_shape):

Then, create a new node in the graph of layers by calling a layer on the input_img object:

  • tf.keras.layers.Conv2D(filters= … , kernel_size= … , padding=‘same’)(input_img): Read the full documentation on Conv2D.

  • tf.keras.layers.MaxPool2D(pool_size=(f, f), strides=(s, s), padding=‘same’): MaxPool2D() downsamples your input using a window of size (f, f) and strides of size (s, s) to carry out max pooling over each window. For max pooling, you usually operate on a single example at a time and a single channel at a time. Read the full documentation on MaxPool2D.

  • tf.keras.layers.ReLU(): computes the elementwise ReLU of Z (which can be any shape). You can read the full documentation on ReLU.

  • tf.keras.layers.Flatten(): given a tensor “P”, this function takes each training (or test) example in the batch and flattens it into a 1D vector.

    • If a tensor P has the shape (batch_size,h,w,c), it returns a flattened tensor with shape (batch_size, k), where \(k=h \times w \times c\). “k” equals the product of all the dimension sizes other than the first dimension.

    • For example, given a tensor with dimensions [100, 2, 3, 4], it flattens the tensor to be of shape [100, 24], where 24 = 2 * 3 * 4. You can read the full documentation on Flatten.

  • tf.keras.layers.Dense(units= … , activation=‘softmax’)(F): given the flattened input F, it returns the output computed using a fully connected layer. You can read the full documentation on Dense.

In the last function above (tf.keras.layers.Dense()), the fully connected layer automatically initializes weights in the graph and keeps on training them as you train the model. Hence, you did not need to initialize those weights when initializing the parameters.

Lastly, before creating the model, you’ll need to define the output using the last of the function’s compositions (in this example, a Dense layer):

  • outputs = tf.keras.layers.Dense(units=6, activation=‘softmax’)(F)

Window, kernel, filter, pool

The words “kernel” and “filter” are used to refer to the same thing. The word “filter” accounts for the amount of “kernels” that will be used in a single convolution layer. “Pool” is the name of the operation that takes the max or average value of the kernels.

This is why the parameter pool_size refers to kernel_size, and you use (f,f) to refer to the filter size.

Pool size and kernel size refer to the same thing in different objects - They refer to the shape of the window where the operation takes place.

convolutional_model

Implement the convolutional_model function below to build the following model: CONV2D -> RELU -> MAXPOOL -> CONV2D -> RELU -> MAXPOOL -> FLATTEN -> DENSE. Use the functions above!

Also, plug in the following parameters for all the steps:

  • Conv2D: Use 8 4 by 4 filters, stride 1, padding is “SAME”
  • ReLU
  • MaxPool2D: Use an 8 by 8 filter size and an 8 by 8 stride, padding is “SAME”
  • Conv2D: Use 16 2 by 2 filters, stride 1, padding is “SAME”
  • ReLU
  • MaxPool2D: Use a 4 by 4 filter size and a 4 by 4 stride, padding is “SAME”
  • Flatten the previous output.
  • Fully-connected (Dense) layer: Apply a fully connected layer with 6 neurons and a softmax activation.
Code
def convolutional_model(input_shape):
    """
    Implements the forward propagation for the model:
    CONV2D -> RELU -> MAXPOOL -> CONV2D -> RELU -> MAXPOOL -> FLATTEN -> DENSE
    
    Arguments:
    input_img -- input dataset, of shape (input_shape)

    Returns:
    model -- TF Keras model (object containing the information for the entire training process) 
    """

    input_img = tf.keras.Input(shape=input_shape)
    ## CONV2D: 8 filters 4x4, stride of 1, padding 'SAME'
    Z1 = tf.keras.layers.Conv2D(filters = 8 , kernel_size= (4,4), strides = (1,1), padding='same')(input_img)
    ## RELU
    A1 = tf.keras.layers.ReLU()(Z1)
    ## MAXPOOL: window 8x8, stride 8, padding 'SAME'
    P1 = tf.keras.layers.MaxPool2D(pool_size=(8,8), strides=(8, 8), padding='same')(A1)
    ## CONV2D: 16 filters 2x2, stride 1, padding 'SAME'
    Z2 = tf.keras.layers.Conv2D(filters = 16 , kernel_size= (2,2), strides = (1,1), padding='same')(P1)
    ## RELU
    A2 = tf.keras.layers.ReLU()(Z2)
    ## MAXPOOL: window 4x4, stride 4, padding 'SAME'
    P2 = tf.keras.layers.MaxPool2D(pool_size=(4,4), strides=(4, 4), padding='same')(A2)
    ## FLATTEN
    F = tf.keras.layers.Flatten()(P2)
    ## Dense layer
    ## 6 neurons in output layer. Hint: one of the arguments should be "activation='softmax'" 
    outputs = tf.keras.layers.Dense(units=6, activation='softmax')(F)

    model = tf.keras.Model(inputs=input_img, outputs=outputs)
    return model
Code
conv_model = convolutional_model((64, 64, 3))
conv_model.compile(optimizer='adam',
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
conv_model.summary()
    
output = [['InputLayer', [(None, 64, 64, 3)], 0],
        ['Conv2D', (None, 64, 64, 8), 392, 'same', 'linear', 'GlorotUniform'],
        ['ReLU', (None, 64, 64, 8), 0],
        ['MaxPooling2D', (None, 8, 8, 8), 0, (8, 8), (8, 8), 'same'],
        ['Conv2D', (None, 8, 8, 16), 528, 'same', 'linear', 'GlorotUniform'],
        ['ReLU', (None, 8, 8, 16), 0],
        ['MaxPooling2D', (None, 2, 2, 16), 0, (4, 4), (4, 4), 'same'],
        ['Flatten', (None, 64), 0],
        ['Dense', (None, 6), 390, 'softmax']]
    
comparator(summary(conv_model), output)
Model: "functional_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 64, 64, 3)]       0         
_________________________________________________________________
conv2d (Conv2D)              (None, 64, 64, 8)         392       
_________________________________________________________________
re_lu_1 (ReLU)               (None, 64, 64, 8)         0         
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 8, 8, 8)           0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 8, 8, 16)          528       
_________________________________________________________________
re_lu_2 (ReLU)               (None, 8, 8, 16)          0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 2, 2, 16)          0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 64)                0         
_________________________________________________________________
dense (Dense)                (None, 6)                 390       
=================================================================
Total params: 1,310
Trainable params: 1,310
Non-trainable params: 0
_________________________________________________________________
All tests passed!

Both the Sequential and Functional APIs return a TF Keras model object. The only difference is how inputs are handled inside the object model!

Train the Model

Code
train_dataset = tf.data.Dataset.from_tensor_slices((X_train, Y_train)).batch(64)
test_dataset = tf.data.Dataset.from_tensor_slices((X_test, Y_test)).batch(64)
history = conv_model.fit(train_dataset, epochs=100, validation_data=test_dataset)
Epoch 1/100
17/17 [==============================] - 2s 113ms/step - loss: 1.8195 - accuracy: 0.1639 - val_loss: 1.7877 - val_accuracy: 0.1917
Epoch 2/100
17/17 [==============================] - 2s 106ms/step - loss: 1.7867 - accuracy: 0.2213 - val_loss: 1.7784 - val_accuracy: 0.3667
Epoch 3/100
17/17 [==============================] - 2s 107ms/step - loss: 1.7793 - accuracy: 0.2370 - val_loss: 1.7724 - val_accuracy: 0.2833
Epoch 4/100
17/17 [==============================] - 2s 106ms/step - loss: 1.7728 - accuracy: 0.2880 - val_loss: 1.7663 - val_accuracy: 0.3833
Epoch 5/100
17/17 [==============================] - 2s 106ms/step - loss: 1.7623 - accuracy: 0.3204 - val_loss: 1.7573 - val_accuracy: 0.3750
Epoch 6/100
17/17 [==============================] - 2s 111ms/step - loss: 1.7466 - accuracy: 0.3537 - val_loss: 1.7438 - val_accuracy: 0.4333
Epoch 7/100
17/17 [==============================] - 2s 106ms/step - loss: 1.7275 - accuracy: 0.3833 - val_loss: 1.7289 - val_accuracy: 0.4333
Epoch 8/100
17/17 [==============================] - 2s 106ms/step - loss: 1.7048 - accuracy: 0.3944 - val_loss: 1.7071 - val_accuracy: 0.4167
Epoch 9/100
17/17 [==============================] - 2s 106ms/step - loss: 1.6774 - accuracy: 0.4222 - val_loss: 1.6835 - val_accuracy: 0.4000
Epoch 10/100
17/17 [==============================] - 2s 112ms/step - loss: 1.6464 - accuracy: 0.4324 - val_loss: 1.6555 - val_accuracy: 0.4333
Epoch 11/100
17/17 [==============================] - 2s 107ms/step - loss: 1.6108 - accuracy: 0.4407 - val_loss: 1.6239 - val_accuracy: 0.4333
Epoch 12/100
17/17 [==============================] - 2s 106ms/step - loss: 1.5714 - accuracy: 0.4509 - val_loss: 1.5902 - val_accuracy: 0.4750
Epoch 13/100
17/17 [==============================] - 2s 111ms/step - loss: 1.5295 - accuracy: 0.4648 - val_loss: 1.5501 - val_accuracy: 0.4833
Epoch 14/100
17/17 [==============================] - 2s 106ms/step - loss: 1.4866 - accuracy: 0.4694 - val_loss: 1.5125 - val_accuracy: 0.4917
Epoch 15/100
17/17 [==============================] - 2s 106ms/step - loss: 1.4456 - accuracy: 0.4852 - val_loss: 1.4733 - val_accuracy: 0.4917
Epoch 16/100
17/17 [==============================] - 2s 107ms/step - loss: 1.4041 - accuracy: 0.4972 - val_loss: 1.4349 - val_accuracy: 0.5000
Epoch 17/100
17/17 [==============================] - 2s 106ms/step - loss: 1.3648 - accuracy: 0.5083 - val_loss: 1.3962 - val_accuracy: 0.5250
Epoch 18/100
17/17 [==============================] - 2s 106ms/step - loss: 1.3268 - accuracy: 0.5083 - val_loss: 1.3610 - val_accuracy: 0.5167
Epoch 19/100
17/17 [==============================] - 2s 108ms/step - loss: 1.2904 - accuracy: 0.5343 - val_loss: 1.3229 - val_accuracy: 0.5333
Epoch 20/100
17/17 [==============================] - 2s 106ms/step - loss: 1.2535 - accuracy: 0.5444 - val_loss: 1.2856 - val_accuracy: 0.5500
Epoch 21/100
17/17 [==============================] - 2s 111ms/step - loss: 1.2190 - accuracy: 0.5583 - val_loss: 1.2514 - val_accuracy: 0.5833
Epoch 22/100
17/17 [==============================] - 2s 111ms/step - loss: 1.1846 - accuracy: 0.5778 - val_loss: 1.2160 - val_accuracy: 0.5917
Epoch 23/100
17/17 [==============================] - 2s 111ms/step - loss: 1.1511 - accuracy: 0.5935 - val_loss: 1.1822 - val_accuracy: 0.5917
Epoch 24/100
17/17 [==============================] - 2s 112ms/step - loss: 1.1213 - accuracy: 0.6000 - val_loss: 1.1535 - val_accuracy: 0.5917
Epoch 25/100
17/17 [==============================] - 2s 107ms/step - loss: 1.0896 - accuracy: 0.6167 - val_loss: 1.1224 - val_accuracy: 0.6333
Epoch 26/100
17/17 [==============================] - 2s 111ms/step - loss: 1.0642 - accuracy: 0.6222 - val_loss: 1.0956 - val_accuracy: 0.6333
Epoch 27/100
17/17 [==============================] - 2s 112ms/step - loss: 1.0363 - accuracy: 0.6333 - val_loss: 1.0712 - val_accuracy: 0.6333
Epoch 28/100
17/17 [==============================] - 2s 106ms/step - loss: 1.0076 - accuracy: 0.6481 - val_loss: 1.0452 - val_accuracy: 0.6417
Epoch 29/100
17/17 [==============================] - 2s 112ms/step - loss: 0.9843 - accuracy: 0.6556 - val_loss: 1.0237 - val_accuracy: 0.6333
Epoch 30/100
17/17 [==============================] - 2s 111ms/step - loss: 0.9607 - accuracy: 0.6583 - val_loss: 1.0019 - val_accuracy: 0.6167
Epoch 31/100
17/17 [==============================] - 2s 111ms/step - loss: 0.9377 - accuracy: 0.6657 - val_loss: 0.9810 - val_accuracy: 0.6333
Epoch 32/100
17/17 [==============================] - 2s 111ms/step - loss: 0.9184 - accuracy: 0.6722 - val_loss: 0.9642 - val_accuracy: 0.6333
Epoch 33/100
17/17 [==============================] - 2s 112ms/step - loss: 0.8970 - accuracy: 0.6852 - val_loss: 0.9462 - val_accuracy: 0.6417
Epoch 34/100
17/17 [==============================] - 2s 111ms/step - loss: 0.8786 - accuracy: 0.6907 - val_loss: 0.9271 - val_accuracy: 0.6417
Epoch 35/100
17/17 [==============================] - 2s 107ms/step - loss: 0.8623 - accuracy: 0.7074 - val_loss: 0.9133 - val_accuracy: 0.6500
Epoch 36/100
17/17 [==============================] - 2s 106ms/step - loss: 0.8430 - accuracy: 0.7028 - val_loss: 0.8989 - val_accuracy: 0.6500
Epoch 37/100
17/17 [==============================] - 2s 106ms/step - loss: 0.8316 - accuracy: 0.7139 - val_loss: 0.8840 - val_accuracy: 0.6667
Epoch 38/100
17/17 [==============================] - 2s 111ms/step - loss: 0.8145 - accuracy: 0.7176 - val_loss: 0.8727 - val_accuracy: 0.6667
Epoch 39/100
17/17 [==============================] - 2s 107ms/step - loss: 0.7944 - accuracy: 0.7259 - val_loss: 0.8592 - val_accuracy: 0.6667
Epoch 40/100
17/17 [==============================] - 2s 112ms/step - loss: 0.7805 - accuracy: 0.7380 - val_loss: 0.8458 - val_accuracy: 0.6750
Epoch 41/100
17/17 [==============================] - 2s 111ms/step - loss: 0.7674 - accuracy: 0.7407 - val_loss: 0.8338 - val_accuracy: 0.6667
Epoch 42/100
17/17 [==============================] - 2s 112ms/step - loss: 0.7519 - accuracy: 0.7528 - val_loss: 0.8249 - val_accuracy: 0.6750
Epoch 43/100
17/17 [==============================] - 2s 106ms/step - loss: 0.7394 - accuracy: 0.7537 - val_loss: 0.8134 - val_accuracy: 0.6750
Epoch 44/100
17/17 [==============================] - 2s 107ms/step - loss: 0.7258 - accuracy: 0.7593 - val_loss: 0.8037 - val_accuracy: 0.6750
Epoch 45/100
17/17 [==============================] - 2s 106ms/step - loss: 0.7135 - accuracy: 0.7639 - val_loss: 0.7920 - val_accuracy: 0.6750
Epoch 46/100
17/17 [==============================] - 2s 111ms/step - loss: 0.7014 - accuracy: 0.7704 - val_loss: 0.7827 - val_accuracy: 0.6833
Epoch 47/100
17/17 [==============================] - 2s 112ms/step - loss: 0.6893 - accuracy: 0.7759 - val_loss: 0.7718 - val_accuracy: 0.7000
Epoch 48/100
17/17 [==============================] - ETA: 0s - loss: 0.6787 - accuracy: 0.78 - 2s 112ms/step - loss: 0.6787 - accuracy: 0.7806 - val_loss: 0.7633 - val_accuracy: 0.7000
Epoch 49/100
17/17 [==============================] - 2s 112ms/step - loss: 0.6677 - accuracy: 0.7843 - val_loss: 0.7540 - val_accuracy: 0.7000
Epoch 50/100
17/17 [==============================] - 2s 107ms/step - loss: 0.6561 - accuracy: 0.7917 - val_loss: 0.7441 - val_accuracy: 0.7000
Epoch 51/100
17/17 [==============================] - 2s 107ms/step - loss: 0.6460 - accuracy: 0.7981 - val_loss: 0.7364 - val_accuracy: 0.7000
Epoch 52/100
17/17 [==============================] - 2s 106ms/step - loss: 0.6357 - accuracy: 0.8028 - val_loss: 0.7274 - val_accuracy: 0.7083
Epoch 53/100
17/17 [==============================] - 2s 107ms/step - loss: 0.6256 - accuracy: 0.8083 - val_loss: 0.7200 - val_accuracy: 0.7083
Epoch 54/100
17/17 [==============================] - 2s 111ms/step - loss: 0.6160 - accuracy: 0.8139 - val_loss: 0.7106 - val_accuracy: 0.7083
Epoch 55/100
17/17 [==============================] - 2s 112ms/step - loss: 0.6065 - accuracy: 0.8213 - val_loss: 0.7032 - val_accuracy: 0.7167
Epoch 56/100
17/17 [==============================] - 2s 107ms/step - loss: 0.5972 - accuracy: 0.8231 - val_loss: 0.6956 - val_accuracy: 0.7167
Epoch 57/100
17/17 [==============================] - 2s 112ms/step - loss: 0.5874 - accuracy: 0.8269 - val_loss: 0.6872 - val_accuracy: 0.7167
Epoch 58/100
17/17 [==============================] - 2s 112ms/step - loss: 0.5791 - accuracy: 0.8343 - val_loss: 0.6802 - val_accuracy: 0.7083
Epoch 59/100
17/17 [==============================] - 2s 112ms/step - loss: 0.5704 - accuracy: 0.8380 - val_loss: 0.6729 - val_accuracy: 0.7250
Epoch 60/100
17/17 [==============================] - 2s 112ms/step - loss: 0.5619 - accuracy: 0.8361 - val_loss: 0.6667 - val_accuracy: 0.7250
Epoch 61/100
17/17 [==============================] - 2s 111ms/step - loss: 0.5537 - accuracy: 0.8417 - val_loss: 0.6595 - val_accuracy: 0.7250
Epoch 62/100
17/17 [==============================] - 2s 112ms/step - loss: 0.5459 - accuracy: 0.8444 - val_loss: 0.6529 - val_accuracy: 0.7500
Epoch 63/100
17/17 [==============================] - 2s 112ms/step - loss: 0.5380 - accuracy: 0.8463 - val_loss: 0.6459 - val_accuracy: 0.7500
Epoch 64/100
17/17 [==============================] - 2s 111ms/step - loss: 0.5302 - accuracy: 0.8481 - val_loss: 0.6393 - val_accuracy: 0.7500
Epoch 65/100
17/17 [==============================] - 2s 111ms/step - loss: 0.5226 - accuracy: 0.8500 - val_loss: 0.6344 - val_accuracy: 0.7500
Epoch 66/100
17/17 [==============================] - 2s 112ms/step - loss: 0.5152 - accuracy: 0.8500 - val_loss: 0.6272 - val_accuracy: 0.7583
Epoch 67/100
17/17 [==============================] - 2s 107ms/step - loss: 0.5078 - accuracy: 0.8519 - val_loss: 0.6224 - val_accuracy: 0.7583
Epoch 68/100
17/17 [==============================] - 2s 112ms/step - loss: 0.5007 - accuracy: 0.8537 - val_loss: 0.6152 - val_accuracy: 0.7583
Epoch 69/100
17/17 [==============================] - 2s 112ms/step - loss: 0.4937 - accuracy: 0.8574 - val_loss: 0.6105 - val_accuracy: 0.7583
Epoch 70/100
17/17 [==============================] - 2s 106ms/step - loss: 0.4867 - accuracy: 0.8602 - val_loss: 0.6043 - val_accuracy: 0.7583
Epoch 71/100
17/17 [==============================] - 2s 106ms/step - loss: 0.4800 - accuracy: 0.8639 - val_loss: 0.5983 - val_accuracy: 0.7583
Epoch 72/100
17/17 [==============================] - 2s 106ms/step - loss: 0.4734 - accuracy: 0.8657 - val_loss: 0.5925 - val_accuracy: 0.7583
Epoch 73/100
17/17 [==============================] - 2s 112ms/step - loss: 0.4670 - accuracy: 0.8694 - val_loss: 0.5869 - val_accuracy: 0.7583
Epoch 74/100
17/17 [==============================] - 2s 106ms/step - loss: 0.4607 - accuracy: 0.8713 - val_loss: 0.5813 - val_accuracy: 0.7583
Epoch 75/100
17/17 [==============================] - 2s 106ms/step - loss: 0.4546 - accuracy: 0.8741 - val_loss: 0.5759 - val_accuracy: 0.7667
Epoch 76/100
17/17 [==============================] - 2s 106ms/step - loss: 0.4485 - accuracy: 0.8750 - val_loss: 0.5717 - val_accuracy: 0.7750
Epoch 77/100
17/17 [==============================] - 2s 106ms/step - loss: 0.4427 - accuracy: 0.8806 - val_loss: 0.5659 - val_accuracy: 0.7750
Epoch 78/100
17/17 [==============================] - 2s 112ms/step - loss: 0.4369 - accuracy: 0.8806 - val_loss: 0.5620 - val_accuracy: 0.7750
Epoch 79/100
17/17 [==============================] - 2s 112ms/step - loss: 0.4313 - accuracy: 0.8833 - val_loss: 0.5559 - val_accuracy: 0.7750
Epoch 80/100
17/17 [==============================] - 2s 107ms/step - loss: 0.4256 - accuracy: 0.8852 - val_loss: 0.5526 - val_accuracy: 0.7750
Epoch 81/100
17/17 [==============================] - 2s 106ms/step - loss: 0.4203 - accuracy: 0.8880 - val_loss: 0.5476 - val_accuracy: 0.7750
Epoch 82/100
17/17 [==============================] - 2s 112ms/step - loss: 0.4149 - accuracy: 0.8898 - val_loss: 0.5429 - val_accuracy: 0.7750
Epoch 83/100
17/17 [==============================] - 2s 112ms/step - loss: 0.4096 - accuracy: 0.8935 - val_loss: 0.5385 - val_accuracy: 0.7917
Epoch 84/100
17/17 [==============================] - 2s 111ms/step - loss: 0.4045 - accuracy: 0.8926 - val_loss: 0.5340 - val_accuracy: 0.8000
Epoch 85/100
17/17 [==============================] - 2s 111ms/step - loss: 0.3997 - accuracy: 0.8944 - val_loss: 0.5301 - val_accuracy: 0.8000
Epoch 86/100
17/17 [==============================] - 2s 111ms/step - loss: 0.3947 - accuracy: 0.8944 - val_loss: 0.5252 - val_accuracy: 0.8000
Epoch 87/100
17/17 [==============================] - 2s 112ms/step - loss: 0.3903 - accuracy: 0.8935 - val_loss: 0.5213 - val_accuracy: 0.8083
Epoch 88/100
17/17 [==============================] - 2s 107ms/step - loss: 0.3855 - accuracy: 0.8963 - val_loss: 0.5168 - val_accuracy: 0.8000
Epoch 89/100
17/17 [==============================] - 2s 111ms/step - loss: 0.3811 - accuracy: 0.8981 - val_loss: 0.5134 - val_accuracy: 0.8000
Epoch 90/100
17/17 [==============================] - 2s 112ms/step - loss: 0.3766 - accuracy: 0.8991 - val_loss: 0.5101 - val_accuracy: 0.8083
Epoch 91/100
17/17 [==============================] - 2s 112ms/step - loss: 0.3724 - accuracy: 0.8991 - val_loss: 0.5062 - val_accuracy: 0.8083
Epoch 92/100
17/17 [==============================] - 2s 107ms/step - loss: 0.3683 - accuracy: 0.9000 - val_loss: 0.5022 - val_accuracy: 0.8083
Epoch 93/100
17/17 [==============================] - 2s 112ms/step - loss: 0.3641 - accuracy: 0.8981 - val_loss: 0.4997 - val_accuracy: 0.8083
Epoch 94/100
17/17 [==============================] - 2s 111ms/step - loss: 0.3600 - accuracy: 0.9009 - val_loss: 0.4960 - val_accuracy: 0.8083
Epoch 95/100
17/17 [==============================] - 2s 112ms/step - loss: 0.3561 - accuracy: 0.9009 - val_loss: 0.4928 - val_accuracy: 0.8083
Epoch 96/100
17/17 [==============================] - 2s 106ms/step - loss: 0.3520 - accuracy: 0.9019 - val_loss: 0.4902 - val_accuracy: 0.8083
Epoch 97/100
17/17 [==============================] - 2s 107ms/step - loss: 0.3483 - accuracy: 0.9028 - val_loss: 0.4867 - val_accuracy: 0.8083
Epoch 98/100
17/17 [==============================] - 2s 112ms/step - loss: 0.3444 - accuracy: 0.9028 - val_loss: 0.4830 - val_accuracy: 0.8083
Epoch 99/100
17/17 [==============================] - 2s 112ms/step - loss: 0.3409 - accuracy: 0.9046 - val_loss: 0.4791 - val_accuracy: 0.8083
Epoch 100/100
17/17 [==============================] - 2s 112ms/step - loss: 0.3372 - accuracy: 0.9056 - val_loss: 0.4769 - val_accuracy: 0.8083

History Object

The history object is an output of the .fit() operation, and provides a record of all the loss and metric values in memory. It’s stored as a dictionary that you can retrieve at history.history:

Code
history.history
{'loss': [1.81948983669281,
  1.7866532802581787,
  1.7793265581130981,
  1.77281653881073,
  1.7623060941696167,
  1.7465872764587402,
  1.727473497390747,
  1.7047957181930542,
  1.6774042844772339,
  1.6463961601257324,
  1.6108105182647705,
  1.5713599920272827,
  1.5294722318649292,
  1.4865756034851074,
  1.4456082582473755,
  1.404129147529602,
  1.3647756576538086,
  1.326806664466858,
  1.2904385328292847,
  1.253509283065796,
  1.218967318534851,
  1.1845623254776,
  1.1511088609695435,
  1.121297001838684,
  1.0895981788635254,
  1.0641520023345947,
  1.0362637042999268,
  1.007636308670044,
  0.984308660030365,
  0.9606931209564209,
  0.9377419948577881,
  0.9183765053749084,
  0.8969680070877075,
  0.8786231875419617,
  0.8622653484344482,
  0.8430467844009399,
  0.8316110372543335,
  0.8145042657852173,
  0.7943885326385498,
  0.7805250883102417,
  0.7673527598381042,
  0.7519320845603943,
  0.7394407987594604,
  0.7258064150810242,
  0.7135477662086487,
  0.7014078497886658,
  0.68934565782547,
  0.6786521673202515,
  0.6677185893058777,
  0.6560553312301636,
  0.6460168361663818,
  0.6356738209724426,
  0.6255865693092346,
  0.6160153150558472,
  0.6064593195915222,
  0.5971838235855103,
  0.5874453186988831,
  0.5790672302246094,
  0.5704237222671509,
  0.5618683695793152,
  0.5537489652633667,
  0.5459328889846802,
  0.5380069017410278,
  0.5302292704582214,
  0.5225710868835449,
  0.5152164697647095,
  0.5078424215316772,
  0.5006593465805054,
  0.4936710000038147,
  0.48668015003204346,
  0.48004111647605896,
  0.47341179847717285,
  0.46695125102996826,
  0.4606838524341583,
  0.45455649495124817,
  0.4484941065311432,
  0.4427187442779541,
  0.43690988421440125,
  0.43131959438323975,
  0.4256468117237091,
  0.4202720522880554,
  0.4148544669151306,
  0.40955156087875366,
  0.40451714396476746,
  0.399653822183609,
  0.3946843445301056,
  0.3902546465396881,
  0.3855292499065399,
  0.38111716508865356,
  0.3765600025653839,
  0.37237632274627686,
  0.36830776929855347,
  0.36407360434532166,
  0.35997268557548523,
  0.3561058044433594,
  0.3520120680332184,
  0.34831100702285767,
  0.34443145990371704,
  0.34088581800460815,
  0.3372299075126648],
 'accuracy': [0.16388888657093048,
  0.2212962955236435,
  0.2370370328426361,
  0.28796297311782837,
  0.3203703761100769,
  0.35370370745658875,
  0.38333332538604736,
  0.39444443583488464,
  0.42222222685813904,
  0.432407408952713,
  0.4407407343387604,
  0.45092591643333435,
  0.46481481194496155,
  0.4694444537162781,
  0.4851851761341095,
  0.4972222149372101,
  0.5083333253860474,
  0.5083333253860474,
  0.5342592597007751,
  0.5444444417953491,
  0.5583333373069763,
  0.5777778029441833,
  0.5935184955596924,
  0.6000000238418579,
  0.6166666746139526,
  0.6222222447395325,
  0.6333333253860474,
  0.6481481194496155,
  0.6555555462837219,
  0.6583333611488342,
  0.6657407283782959,
  0.6722221970558167,
  0.6851851940155029,
  0.6907407641410828,
  0.7074074149131775,
  0.7027778029441833,
  0.7138888835906982,
  0.7175925970077515,
  0.7259259223937988,
  0.7379629611968994,
  0.7407407164573669,
  0.7527777552604675,
  0.7537037134170532,
  0.7592592835426331,
  0.7638888955116272,
  0.770370364189148,
  0.7759259343147278,
  0.7805555462837219,
  0.7842592597007751,
  0.7916666865348816,
  0.7981481552124023,
  0.8027777671813965,
  0.8083333373069763,
  0.8138889074325562,
  0.8212962746620178,
  0.8231481313705444,
  0.8268518447875977,
  0.8342592716217041,
  0.8379629850387573,
  0.8361111283302307,
  0.8416666388511658,
  0.8444444537162781,
  0.8462963104248047,
  0.8481481671333313,
  0.8500000238418579,
  0.8500000238418579,
  0.8518518805503845,
  0.8537036776542664,
  0.8574073910713196,
  0.8601852059364319,
  0.8638888597488403,
  0.8657407164573669,
  0.8694444298744202,
  0.8712962865829468,
  0.8740741014480591,
  0.875,
  0.8805555701255798,
  0.8805555701255798,
  0.8833333253860474,
  0.885185182094574,
  0.8879629373550415,
  0.8898147940635681,
  0.8935185074806213,
  0.8925926089286804,
  0.894444465637207,
  0.894444465637207,
  0.8935185074806213,
  0.8962963223457336,
  0.8981481194496155,
  0.8990740776062012,
  0.8990740776062012,
  0.8999999761581421,
  0.8981481194496155,
  0.9009259343147278,
  0.9009259343147278,
  0.9018518328666687,
  0.9027777910232544,
  0.9027777910232544,
  0.904629647731781,
  0.9055555462837219],
 'val_loss': [1.7876800298690796,
  1.7783701419830322,
  1.7724140882492065,
  1.7663179636001587,
  1.7573018074035645,
  1.7437589168548584,
  1.7289468050003052,
  1.7070850133895874,
  1.6835014820098877,
  1.65554940700531,
  1.623866319656372,
  1.5901832580566406,
  1.5500829219818115,
  1.5125292539596558,
  1.4733363389968872,
  1.43490731716156,
  1.3961615562438965,
  1.3610016107559204,
  1.322857141494751,
  1.285576581954956,
  1.2514076232910156,
  1.2160006761550903,
  1.1821620464324951,
  1.1535362005233765,
  1.1223864555358887,
  1.0956348180770874,
  1.0711747407913208,
  1.0452433824539185,
  1.0237010717391968,
  1.0019229650497437,
  0.9809500575065613,
  0.9642131924629211,
  0.9462014436721802,
  0.9270848631858826,
  0.9132782220840454,
  0.8989419341087341,
  0.8840094208717346,
  0.8726851344108582,
  0.859239935874939,
  0.8458324670791626,
  0.8338425755500793,
  0.8249179124832153,
  0.8133607506752014,
  0.8037306666374207,
  0.7920339107513428,
  0.7827457189559937,
  0.771838366985321,
  0.7632779479026794,
  0.7540360689163208,
  0.7441073060035706,
  0.7364082932472229,
  0.7273833155632019,
  0.720013439655304,
  0.7106152772903442,
  0.7032146453857422,
  0.6956319212913513,
  0.6872405409812927,
  0.6802046895027161,
  0.6728969812393188,
  0.6666851043701172,
  0.6595165133476257,
  0.6528659462928772,
  0.6459203362464905,
  0.6392733454704285,
  0.63435959815979,
  0.6271969079971313,
  0.6224012970924377,
  0.6151788234710693,
  0.6105490326881409,
  0.6042757630348206,
  0.5982545018196106,
  0.5924508571624756,
  0.5869402289390564,
  0.5812922120094299,
  0.5758609771728516,
  0.5716504454612732,
  0.5659103393554688,
  0.5619857907295227,
  0.5559280514717102,
  0.552624523639679,
  0.5476232171058655,
  0.5429303646087646,
  0.5385484099388123,
  0.5340473055839539,
  0.5300840139389038,
  0.5251633524894714,
  0.5212688446044922,
  0.516834020614624,
  0.5134209990501404,
  0.510094404220581,
  0.506202757358551,
  0.5022371411323547,
  0.4997330904006958,
  0.495976060628891,
  0.4928143322467804,
  0.4902016520500183,
  0.486672580242157,
  0.4830384850502014,
  0.47912654280662537,
  0.4768778681755066],
 'val_accuracy': [0.19166666269302368,
  0.36666667461395264,
  0.28333333134651184,
  0.38333332538604736,
  0.375,
  0.4333333373069763,
  0.4333333373069763,
  0.4166666567325592,
  0.4000000059604645,
  0.4333333373069763,
  0.4333333373069763,
  0.4749999940395355,
  0.4833333194255829,
  0.49166667461395264,
  0.49166667461395264,
  0.5,
  0.5249999761581421,
  0.5166666507720947,
  0.5333333611488342,
  0.550000011920929,
  0.5833333134651184,
  0.5916666388511658,
  0.5916666388511658,
  0.5916666388511658,
  0.6333333253860474,
  0.6333333253860474,
  0.6333333253860474,
  0.6416666507720947,
  0.6333333253860474,
  0.6166666746139526,
  0.6333333253860474,
  0.6333333253860474,
  0.6416666507720947,
  0.6416666507720947,
  0.6499999761581421,
  0.6499999761581421,
  0.6666666865348816,
  0.6666666865348816,
  0.6666666865348816,
  0.675000011920929,
  0.6666666865348816,
  0.675000011920929,
  0.675000011920929,
  0.675000011920929,
  0.675000011920929,
  0.6833333373069763,
  0.699999988079071,
  0.699999988079071,
  0.699999988079071,
  0.699999988079071,
  0.699999988079071,
  0.7083333134651184,
  0.7083333134651184,
  0.7083333134651184,
  0.7166666388511658,
  0.7166666388511658,
  0.7166666388511658,
  0.7083333134651184,
  0.7250000238418579,
  0.7250000238418579,
  0.7250000238418579,
  0.75,
  0.75,
  0.75,
  0.75,
  0.7583333253860474,
  0.7583333253860474,
  0.7583333253860474,
  0.7583333253860474,
  0.7583333253860474,
  0.7583333253860474,
  0.7583333253860474,
  0.7583333253860474,
  0.7583333253860474,
  0.7666666507720947,
  0.7749999761581421,
  0.7749999761581421,
  0.7749999761581421,
  0.7749999761581421,
  0.7749999761581421,
  0.7749999761581421,
  0.7749999761581421,
  0.7916666865348816,
  0.800000011920929,
  0.800000011920929,
  0.800000011920929,
  0.8083333373069763,
  0.800000011920929,
  0.800000011920929,
  0.8083333373069763,
  0.8083333373069763,
  0.8083333373069763,
  0.8083333373069763,
  0.8083333373069763,
  0.8083333373069763,
  0.8083333373069763,
  0.8083333373069763,
  0.8083333373069763,
  0.8083333373069763,
  0.8083333373069763]}

Now visualize the loss over time using history.history:

Code
# The history.history["loss"] entry is a dictionary with as many values as epochs that the
# model was trained on. 
df_loss_acc = pd.DataFrame(history.history)
df_loss= df_loss_acc[['loss','val_loss']]
df_loss.rename(columns={'loss':'train','val_loss':'validation'},inplace=True)
df_acc= df_loss_acc[['accuracy','val_accuracy']]
df_acc.rename(columns={'accuracy':'train','val_accuracy':'validation'},inplace=True)
df_loss.plot(title='Model loss',figsize=(12,8)).set(xlabel='Epoch',ylabel='Loss')
df_acc.plot(title='Model Accuracy',figsize=(12,8)).set(xlabel='Epoch',ylabel='Accuracy')

References

https://www.tensorflow.org/guide/keras/sequential_model

https://www.tensorflow.org/guide/keras/functional

https://www.coursera.org/learn/convolutional-neural-networks/programming/7Bfm2/convolution-model-application/lab?path=%2Fnotebooks%2Frelease%2FW1A2%2FConvolution_model_Application.ipynb