End to End Dog Vision - TensorFlow¶
END TO END MULTI-BREED DOG CLASSIFICATION¶
This notebook builds an end-to-end multi-class image classifier using Tensorflow 2.0 and Tensorflow Hub
1. Problem¶
Identifying the dog breed.
2. Data¶
Using data from Kaggle dog breed identification competition
3. Evaluation¶
Evaluation is a file with prediction probabilities for each dog breed of each test image.
4. Features¶
Info about the data:
- We're dealing with unstructured data
- Use deep learning / transfer learning
- 120 different dog breeds
- 10,000 plus images in training set (with labels)
- 10,00 plus in test set (no labels)
# UNZIP IN DRIVE FOLDER
#!unzip "drive/MyDrive/Dog-Vision/dog-breed-identification.zip" -d "drive/MyDrive/Dog-Vision/"
-- WORKSPACE SETUP --¶
- Import Tensorflow 2.x
- Import Tensorflow Hub
- Make sure we're using GPU
# IMPORT TENSORFLOW INTO COLAB
import tensorflow as tf
import tensorflow_hub as hub
print("TF Version: ", tf.__version__)
print("TF Hub Version", hub.__version__)
# CHECK FOR GPU AVAILABILITY
print("GPU", "YES!" if tf.config.list_physical_devices("GPU") else "NOT AVAILABLE")
TF Version: 2.15.0 TF Hub Version 0.16.1 GPU NOT AVAILABLE
-- GETTING DATA READY - TURNING INTO TENSORS --¶
- DATA HAS TO BE IN NUMERICAL FORMAT
# IMPORT PANADAS FOR CSV
import pandas as pd
labels_csv = pd.read_csv("/content/drive/MyDrive/Dog-Vision/labels.csv")
print(labels_csv.describe())
print(labels_csv.head())
id breed count 10222 10222 unique 10222 120 top 000bec180eb18c7604dcecc8fe0dba07 scottish_deerhound freq 1 126 id breed 0 000bec180eb18c7604dcecc8fe0dba07 boston_bull 1 001513dfcb2ffafc82cccf4d8bbaba97 dingo 2 001cdf01b096e06d78e9e5112d419397 pekinese 3 00214f311d5d2247d5dfe4fe24b2303d bluetick 4 0021f9ceb3235effd7fcde7f7538ed62 golden_retriever
labels_csv.tail()
id | breed | |
---|---|---|
10217 | ffd25009d635cfd16e793503ac5edef0 | borzoi |
10218 | ffd3f636f7f379c51ba3648a9ff8254f | dandie_dinmont |
10219 | ffe2ca6c940cddfee68fa3cc6c63213f | airedale |
10220 | ffe5f6d8e2bff356e9482a80a6e29aac | miniature_pinscher |
10221 | fff43b07992508bc822f33d8ffd902ae | chesapeake_bay_retriever |
# HOW MANY IMAGES OF EACH DOG?
labels_csv["breed"].value_counts().plot.bar(figsize=(20, 10))
<Axes: >
# FIND MEDIAN DOG IMAGES
labels_csv["breed"].value_counts().median()
82.0
# VIEW A SAMPLE IMAGE
from IPython.display import Image
Image("/content/drive/MyDrive/Dog-Vision/train/001513dfcb2ffafc82cccf4d8bbaba97.jpg")
GETTING IMAGE AND LABELS¶
- Get image file pathnames
# CREATE PATHNAMES FROM IMAGE IDS
filenames = [fname for fname in labels_csv['id']]
# GET FIRST 10
filenames[:10]
['000bec180eb18c7604dcecc8fe0dba07', '001513dfcb2ffafc82cccf4d8bbaba97', '001cdf01b096e06d78e9e5112d419397', '00214f311d5d2247d5dfe4fe24b2303d', '0021f9ceb3235effd7fcde7f7538ed62', '002211c81b498ef88e1b40b9abf84e1d', '00290d3e1fdd27226ba27a8ce248ce85', '002a283a315af96eaea0e28e7163b21b', '003df8b8a8b05244b1d920bb6cf451f9', '0042188c895a2f14ef64a918ed9c7b64']
# NEXT ITERATION OF CODE
filenames = ["/content/drive/MyDrive/Dog-Vision/train/" + fname + '.jpg' for fname in labels_csv['id']]
filenames[:10]
['/content/drive/MyDrive/Dog-Vision/train/000bec180eb18c7604dcecc8fe0dba07.jpg', '/content/drive/MyDrive/Dog-Vision/train/001513dfcb2ffafc82cccf4d8bbaba97.jpg', '/content/drive/MyDrive/Dog-Vision/train/001cdf01b096e06d78e9e5112d419397.jpg', '/content/drive/MyDrive/Dog-Vision/train/00214f311d5d2247d5dfe4fe24b2303d.jpg', '/content/drive/MyDrive/Dog-Vision/train/0021f9ceb3235effd7fcde7f7538ed62.jpg', '/content/drive/MyDrive/Dog-Vision/train/002211c81b498ef88e1b40b9abf84e1d.jpg', '/content/drive/MyDrive/Dog-Vision/train/00290d3e1fdd27226ba27a8ce248ce85.jpg', '/content/drive/MyDrive/Dog-Vision/train/002a283a315af96eaea0e28e7163b21b.jpg', '/content/drive/MyDrive/Dog-Vision/train/003df8b8a8b05244b1d920bb6cf451f9.jpg', '/content/drive/MyDrive/Dog-Vision/train/0042188c895a2f14ef64a918ed9c7b64.jpg']
# CHECK NUMBER OF FILE NAMES MATCH NUMBER OF IMAGES
import os
if len(os.listdir('/content/drive/MyDrive/Dog-Vision/train/')) == len(filenames):
print("Yes, they match")
else:
print("No, do not match.")
Yes, they match
# ONE MORE CHECK
Image(filenames[9000])
# WHAT KIND OF DOG IS IT?
labels_csv["breed"][9000]
'tibetan_mastiff'
TRAINING IMAGE FILEPATH COMPLETE - PREPARE LABELS¶
labels = labels_csv['breed']
labels
0 boston_bull 1 dingo 2 pekinese 3 bluetick 4 golden_retriever ... 10217 borzoi 10218 dandie_dinmont 10219 airedale 10220 miniature_pinscher 10221 chesapeake_bay_retriever Name: breed, Length: 10222, dtype: object
import numpy as np
labels = labels_csv['breed']
labels = np.array(labels)
# ITS AN ARRAY OF STRINGS - NEED TO CONVERT
labels
array(['boston_bull', 'dingo', 'pekinese', ..., 'airedale', 'miniature_pinscher', 'chesapeake_bay_retriever'], dtype=object)
len(labels)
10222
# CHECK FOR MISSING DATA - NUMBER OF LABELS EQUALS FILENAMES
if len(labels) == len(filenames):
print('Yes, they match')
else:
print('No, they do not match.')
Yes, they match
# FIND UNIQUE VALUES IN GIVEN ARRAY
unique_breeds = np.unique(labels)
len(unique_breeds)
120
# TURN SINGLE LABEL INTO ARRAY OF BOOLEANS - TEST
print(labels[0])
labels[0] == unique_breeds
boston_bull
array([False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False])
# TURN EVERY LABEL INTO A BOOLEAN ARRAY
boolean_labels = [label == unique_breeds for label in labels]
boolean_labels[:2]
[array([False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]), array([False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False])]
len(boolean_labels)
10222
# EXAMPLE - TURNING BOOLEAN ARRAY INTO INTEGERS
print(labels[0]) # ORIGINAL LABEL
print(np.where(unique_breeds == labels[0])) # INDEX WHERE LABEL OCCURS
print(boolean_labels[0].argmax()) # INDEX WHERE LABEL OCCURS IN BOOLEAN ARRAY
print(boolean_labels[0].astype(int)) # THERE WILL BE ONE WHERE THE SAMPLE LABEL OCCURS
boston_bull (array([19]),) 19 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
print(labels[2]) # ORIGINAL LABEL
print(boolean_labels[0].astype(int)) # THERE WILL BE ONE WHERE THE SAMPLE LABEL OCCURS
pekinese [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
CREATING OUR OWN DATA SET¶
- KAGGLE DIDN'T PROVIDE
# SET UP X AND Y VARIABLES
x = filenames
y = boolean_labels
len(filenames)
10222
Start off with experimentingwith ~1000 images and increase as needed.¶
# SET NUMBER OF IMAGES TO USE FOR EXPERIMENTING
NUM_IMAGES = 1000 #@param {type:"slider", min:1000, max:10000, step:1000}
# SPLIT DATA INTO TRAIN AND VALIDATION SETS
from sklearn.model_selection import train_test_split
# SPLIT THEM INTO TRAINING AND VALIDATION OF TOTAL SIZE NUM_IMAGES
x_train, x_val, y_train, y_val = train_test_split(x[:NUM_IMAGES],
y[:NUM_IMAGES],
test_size = 0.2, # 20% test size
random_state = 42)
len(x_train), len(y_train), len(x_val), len(y_val)
(800, 800, 200, 200)
# LOOK AT TRAINING DATA
print('IMAGE URLS: ', x_train[:2])
print('BOOLEAN LABLES', y_train[:2])
IMAGE URLS: ['/content/drive/MyDrive/Dog-Vision/train/00bee065dcec471f26394855c5c2f3de.jpg', '/content/drive/MyDrive/Dog-Vision/train/0d2f9e12a2611d911d91a339074c8154.jpg'] BOOLEAN LABLES [array([False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]), array([False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False])]
PREPROCESSING IMAGES - TURING IMAGES INTO TENSORS¶
Tensors are numerical representations, like a matrix
TO PREPROCESS IMAGES INTO TENSORS WE WRITE FUNCTION THAT DOES A FEW THINGS:
- Take an image filepath as input
- Use Tensorflow to read the file and save it to a variable,
image
- Turn our
image
(jpg) into Tensors - NORMALIZE image - convert 0-255 to 0-1 float
- Resize the
image
to be a shape of (224, 244) - Return the modified
image
# CONVERT IMAGE TO NUMPY ARRAY
from matplotlib.pyplot import imread
image = imread(filenames[42])
image.shape
# HEIGHT, WIDTH, RGB COLOR
(257, 350, 3)
# RGB color range
image.max(), image.min()
(255, 0)
# RUNS ON CPU - NOT A TENSOR
image[:2]
array([[[ 89, 137, 89], [ 76, 124, 76], [ 63, 111, 61], ..., [ 77, 133, 86], [ 76, 134, 86], [ 76, 134, 86]], [[ 72, 119, 75], [ 67, 114, 68], [ 63, 110, 64], ..., [ 75, 131, 84], [ 74, 132, 84], [ 74, 132, 84]]], dtype=uint8)
# THIS IS A TENSOR AND CAN RUN ON GPU
tf.constant(image)[:2]
<tf.Tensor: shape=(2, 350, 3), dtype=uint8, numpy= array([[[ 89, 137, 89], [ 76, 124, 76], [ 63, 111, 61], ..., [ 77, 133, 86], [ 76, 134, 86], [ 76, 134, 86]], [[ 72, 119, 75], [ 67, 114, 68], [ 63, 110, 64], ..., [ 75, 131, 84], [ 74, 132, 84], [ 74, 132, 84]]], dtype=uint8)>
# DEFINE IMAGE SIZE
IMG_SIZE = 224
# CREATE FUNCTION FOR PREPROCESSING IMAGES
def process_image(image_path, img_size = IMG_SIZE):
"""
TAKES AN IMAGE FILE PATH AND TURNS THE IMAGE INTO A TENSOR
"""
# READ IN AN IMAGE FILE
image = tf.io.read_file(image_path)
# TURN JPG IMAGE INTO NUMERICAL TENSOR WITH 3 COLOR CHANNELS - RGB
image = tf.image.decode_jpeg(image, channels=3)
# CONVERT THE COLOR CHANNEL VALUES FROM 0 - 255 TO 0-1 FLOAT VALUES - NORMALIZATION
image = tf.image.convert_image_dtype(image, tf.float32)
# RESIZE IMAGE TO DESIRED VALUE (224, 224)
image = tf.image.resize(image, size=[IMG_SIZE, IMG_SIZE])
return image
TURNING DATA INTO BATCHES (32 IS STANDARD BATCH SIZE)¶
- Take a small portion to get quick feedback (time & memory)
To use Tensorflow effectively, we need to get our datain the form of Tensors tuples which look like this:
(image, label)
# CREATE SIMPLE FUNCTION TO RETURN A TUPLE (IMAGE, LABEL)
def get_image_label(image_path, label):
"""
Takes an image file path name and the associated label,
processes the image and returns a tuple of (image, label).
"""
image = process_image(image_path)
return image, label
# DEMO OF THE ABOVE FUNCTION
(process_image(x[42], tf.constant(y[42])))
<tf.Tensor: shape=(224, 224, 3), dtype=float32, numpy= array([[[0.3264178 , 0.5222886 , 0.3232816 ], [0.2537167 , 0.44366494, 0.24117759], [0.25699762, 0.4467087 , 0.23893751], ..., [0.29325107, 0.5189916 , 0.3215547 ], [0.29721776, 0.52466875, 0.33030328], [0.2948505 , 0.5223015 , 0.33406618]], [[0.25903144, 0.4537807 , 0.27294815], [0.24375686, 0.4407019 , 0.2554778 ], [0.2838985 , 0.47213382, 0.28298813], ..., [0.2785345 , 0.5027992 , 0.31004712], [0.28428748, 0.5108719 , 0.32523635], [0.28821915, 0.5148036 , 0.32916805]], [[0.20941195, 0.40692952, 0.25792548], [0.24045378, 0.43900946, 0.2868911 ], [0.29001117, 0.47937486, 0.32247734], ..., [0.26074055, 0.48414773, 0.30125174], [0.27101526, 0.49454468, 0.32096273], [0.27939945, 0.5029289 , 0.32934693]], ..., [[0.00634795, 0.03442048, 0.0258106 ], [0.01408936, 0.04459917, 0.0301715 ], [0.01385712, 0.04856448, 0.02839671], ..., [0.4220516 , 0.39761978, 0.21622123], [0.47932503, 0.45370543, 0.2696505 ], [0.48181024, 0.45828083, 0.27004552]], [[0.00222061, 0.02262166, 0.03176915], [0.01008397, 0.03669046, 0.02473482], [0.00608852, 0.03890046, 0.01207283], ..., [0.36070833, 0.33803678, 0.16216144], [0.42499566, 0.3976801 , 0.21701711], [0.4405433 , 0.4139589 , 0.23183356]], [[0.05608118, 0.06760313, 0.10401551], [0.05441153, 0.07435327, 0.05428322], [0.04734357, 0.07581862, 0.02060969], ..., [0.3397557 , 0.3126567 , 0.14725593], [0.3877246 , 0.3602736 , 0.187147 ], [0.43942 , 0.41196904, 0.23884243]]], dtype=float32)>
TURN DATA INTO TUPLES OF TENSORS IN THE FORM: (image, label)
. TURN DATA (X,Y)
INTO BATCHES¶
# DEFINE BATCH SIZE, 32 IS A GOOD START
BATCH_SIZE = 32
# CREATE FUNCTION TO TURN DATA INTO BATCHES
def create_data_batches(x, y=None, batch_size=BATCH_SIZE, valid_data=False, test_data=False):
"""
Create batches of data out of image (x) and label (y) pairs.
Shuffle the data if it's training data, but doesn't shuffle if its validation data.
Also accepts test data as input (no labels).
"""
# IF DATA IS TEST DATASET NO LABELS
if test_data:
print("Creating test batches ...")
data = tf.data.Dataset.from_tensor_slices((tf.constant(x))) #only filepaths no labels
data_batch = data.map(process_image).batch(BATCH_SIZE)
return data_batch
# IF DATA IS VALID DATASET WE DON'T NEED TO SHUFFLE IT
elif valid_data:
print("Creating validation data batches...")
data = tf.data.Dataset.from_tensor_slices((tf.constant(x), # filepaths
tf.constant(y))) # labels
data_batch = data.map(get_image_label).batch(BATCH_SIZE)
return data_batch
else:
print("Creating training data batches ...")
#TURN FILEPATHS AND LABELS INTO TENSORS
data = tf.data.Dataset.from_tensor_slices((tf.constant(x),
tf.constant(y)))
# SHUFFLING PATHNAMES AND LABELS BEFORE MAPPING IMAGE
data = data.shuffle(buffer_size=len(x))
# CREATE IMAGE LABEL TUPLESE - ALSO TURNS IMAGE PATH INTO PREPROCESSED IMAGE
data = data.map(get_image_label)
# TURN THE TRAINING DATA INTO BATCHES
data_batch = data.batch(BATCH_SIZE)
return data_batch
# CREATING TRAINING AND VALIDATION DATA BATCHES
train_data = create_data_batches(x_train, y_train)
val_data = create_data_batches(x_val, y_val, valid_data=True)
Creating training data batches ... Creating validation data batches...
# LOOK AT DIFFERENT ATTRIBUTES OF OUR DATA BATCHES
train_data.element_spec, val_data.element_spec
((TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name=None), TensorSpec(shape=(None, 120), dtype=tf.bool, name=None)), (TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name=None), TensorSpec(shape=(None, 120), dtype=tf.bool, name=None)))
VISUALIZING DATA BATCHES¶
our data is now in batches, but hard to understand / comprehend
import matplotlib.pyplot as plt
# CREATE A FUNCTION FOR VIEWING IMAGE IN A DATA BATCH
def show_25_images(images, labels):
"""
DISPLAY A PLOT OF 25 IMAGE AND THEIR LABELS FROM A DATA BATCH
"""
# SET UP THE FIGURE
plt.figure(figsize=(10, 10))
# LOOP THROUGH 25 (FOR DISPLAYING 25 IMAGES)
for i in range(25):
# CREATE SUBPLOTS (5 ROWS, 5 COLUMNS)
ax = plt.subplot(5, 5, i+1)
# DISPLAY AN IMAGE
plt.imshow(images[i])
# ADD IMAGE LABEL AS TITLE
plt.title(unique_breeds[labels[i].argmax()])
# TURN THE GRID OFF
plt.axis("off")
train_data
<_BatchDataset element_spec=(TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name=None), TensorSpec(shape=(None, 120), dtype=tf.bool, name=None))>
# VISUALIZE DATA IN TRAINING BATCH - THESE SHUFFLE
train_images, train_labels = next(train_data.as_numpy_iterator())
show_25_images(train_images, train_labels)
# VISUALIZE VALIDATION SET - THESE DON'T SHUFFLE
val_images, val_labels = next(val_data.as_numpy_iterator())
show_25_images(val_images, val_labels)
BUILDING A MODEL¶
Before we build a model, there are a few things we need to define
- The input shape (our images shape, in the for of Tensors) to our model
- The output shape (image labels, in the form of Tensors) of our model
- The URL of the model we want to use.
IMG_SIZE
224
# SETUP INPUT SHAPE OF THE MODEL
INPUT_SHAPE = [None, IMG_SIZE, IMG_SIZE, 3] # BATCH, HEIGHT, WIDTH, RGB CHANNELS
# SETUP OUTPUT SHAPE OF OUR MODEL
OUTPUT_SHAPE = len(unique_breeds)
# SETUP MODEL URL FROM TENSORFLOW HUB
MODEL_URL = "https://kaggle.com/models/google/mobilenet-v2/frameworks/TensorFlow2/variations/130-224-classification/versions/1"
Inputs, Outputs and Model ready. Put them together into a KERAS deep learning model.¶
Create a function that:
- Takes the input shape, output shape and the model we've chosen as parameters.
- Defines the layers in a KERAS model in sequential fashion
- Compiles the model (should be evaluated and improved)
- Builds the model (tell the model the input shape it'll be getting)
- Returns the model.
# Create a function that builds KERAS model
def create_model(input_shape = INPUT_SHAPE, output_shape = OUTPUT_SHAPE, model_url = MODEL_URL):
print("Building model with: ", MODEL_URL)
# Set up the moel layers
model = tf.keras.Sequential([
hub.KerasLayer(MODEL_URL), # LAYER 1 INPUT LAYER
tf.keras.layers.Dense(units=OUTPUT_SHAPE,
activation = "softmax") # LAYER 2 - OUTPUT LAYER
])
# Compile the model
model.compile(
loss=tf.keras.losses.CategoricalCrossentropy(), # how good the model is guessing
optimizer=tf.keras.optimizers.Adam(), # how to improve it's guessing
metrics=["accuracy"] # evaluating those guesses after it's learnt
)
# Build the model
model.build(INPUT_SHAPE)
return model
model = create_model()
model.summary()
Building model with: https://kaggle.com/models/google/mobilenet-v2/frameworks/TensorFlow2/variations/130-224-classification/versions/1 Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= keras_layer (KerasLayer) (None, 1001) 5432713 dense (Dense) (None, 120) 120240 ================================================================= Total params: 5552953 (21.18 MB) Trainable params: 120240 (469.69 KB) Non-trainable params: 5432713 (20.72 MB) _________________________________________________________________
COMPREHENSIZE GUIDE TO CONVOLUTIONAL NEURAL NETWORKS¶
CREATING CALLBACKS¶
Callbacks are helper functions a model can use during training to do such things as save its progress, check its progress or stop training early if a model stops improving.
Create two callbacks:
- TensorBoard which helps track our models progress
- Early stop - prevent overfit
TensorBoard Callback¶
Setup three things:
- Load TensorBoard callback extension
- Create TensorBoard callback to save logs to a directory and pass to models
fit()
function. - Visualize models training logs with the
%tensorboard
magic function (after training)
# LOAD TENSORBOARD NOTEBOOK EXTENSION
%load_ext tensorboard
import datetime
# Create a function to build a TensorBoard callback
def create_tensorboard_callback():
# Create a log directory for storing TensorBoard logs
logdir = os.path.join("drive/MyDrive/Dog-Vision/logs",
# MAKE IT SO THE LOGS GET TRACKED WHENEVER WE RUN AN EXPERIMENT
datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
return tf.keras.callbacks.TensorBoard(logdir)
EARLY STOPPING CALLBACK¶
Early stopping helps stop model from overfitting by stopping training if certain evaluation metric stops
https://www.tensorflow.org/api_docs/python/tf/keras/callbacks/EarlyStopping
# Create early stopping callback
early_stopping = tf.keras.callbacks.EarlyStopping(monitor = "val_accuracy",
patience = 3)
Training a model (on a subset of data)¶
First model trained on 1000 image to make sure it works.
NUM_EPOCHS = 100 #@param {type:"slider", min:10, max:100, step:10}
# CHECK TO MAKE SURE WE'RE STILL RUNNING ON A GPU
print("GPU", "Yes(yes)" if tf.config.list_physical_devices("GPU") else "nope.")
GPU nope.
CREATE FUNCTION WHICH TRAINS A MODEL¶
- Create model using
create_model()
- Setup a TensorBoard callback using
create_tensorboard_callback()
- Call the
fit()
function on our model passing the training data, validation data, number of epochs to train the callbacks we'd like to use - Return the model
# Build a function to train and return a trained model
def train_model():
"""
Trains a given model and returns the trained version
"""
# Create a model
model= create_model()
#Create new TensorBoard session everytime we train a model
tensorboard = create_tensorboard_callback()
# Fit the model to the data passing it the callbacks we created
model.fit(x=train_data,
epochs=NUM_EPOCHS,
validation_data=val_data,
validation_freq=1,
callbacks=[tensorboard, early_stopping])
# Return the fitted model
return model
# Fit the model to the data
model = train_model()
Building model with: https://kaggle.com/models/google/mobilenet-v2/frameworks/TensorFlow2/variations/130-224-classification/versions/1 Epoch 1/100 25/25 [==============================] - 363s 15s/step - loss: 4.6385 - accuracy: 0.0812 - val_loss: 3.3365 - val_accuracy: 0.2450 Epoch 2/100 25/25 [==============================] - 54s 2s/step - loss: 1.6720 - accuracy: 0.6787 - val_loss: 2.1504 - val_accuracy: 0.5000 Epoch 3/100 25/25 [==============================] - 64s 3s/step - loss: 0.5896 - accuracy: 0.9237 - val_loss: 1.6586 - val_accuracy: 0.5450 Epoch 4/100 25/25 [==============================] - 66s 3s/step - loss: 0.2649 - accuracy: 0.9850 - val_loss: 1.5010 - val_accuracy: 0.6050 Epoch 5/100 25/25 [==============================] - 57s 2s/step - loss: 0.1510 - accuracy: 0.9975 - val_loss: 1.4099 - val_accuracy: 0.6450 Epoch 6/100 25/25 [==============================] - 54s 2s/step - loss: 0.1025 - accuracy: 1.0000 - val_loss: 1.3680 - val_accuracy: 0.6300 Epoch 7/100 25/25 [==============================] - 65s 3s/step - loss: 0.0772 - accuracy: 1.0000 - val_loss: 1.3428 - val_accuracy: 0.6450 Epoch 8/100 25/25 [==============================] - 54s 2s/step - loss: 0.0611 - accuracy: 1.0000 - val_loss: 1.3113 - val_accuracy: 0.6500 Epoch 9/100 25/25 [==============================] - 66s 3s/step - loss: 0.0501 - accuracy: 1.0000 - val_loss: 1.2990 - val_accuracy: 0.6500 Epoch 10/100 25/25 [==============================] - 67s 3s/step - loss: 0.0420 - accuracy: 1.0000 - val_loss: 1.2839 - val_accuracy: 0.6550 Epoch 11/100 25/25 [==============================] - 54s 2s/step - loss: 0.0362 - accuracy: 1.0000 - val_loss: 1.2716 - val_accuracy: 0.6750 Epoch 12/100 25/25 [==============================] - 55s 2s/step - loss: 0.0316 - accuracy: 1.0000 - val_loss: 1.2674 - val_accuracy: 0.6650 Epoch 13/100 25/25 [==============================] - 53s 2s/step - loss: 0.0279 - accuracy: 1.0000 - val_loss: 1.2574 - val_accuracy: 0.6650 Epoch 14/100 25/25 [==============================] - 65s 3s/step - loss: 0.0247 - accuracy: 1.0000 - val_loss: 1.2493 - val_accuracy: 0.6650
CHECKING TENSORBOARD LOGS¶
The TensorBoard magic function (%tensorboard)
will access the logs directory we created earlier and visualize its contents
%tensorboard --logdir drive/MyDrive/Dog-Vision/logs
Making and evaluating predictions using a trained model¶
# Make predictions on the validation data (not used to train on)
predictions = model.predict(val_data, verbose=1)
predictions
7/7 [==============================] - 22s 2s/step
array([[2.60485709e-03, 7.11015717e-04, 6.50771311e-04, ..., 8.82690481e-04, 3.14395329e-05, 4.18143114e-03], [3.82819236e-03, 1.92687195e-03, 2.15765312e-02, ..., 2.28854988e-04, 7.42668810e-04, 5.73002944e-05], [2.73520909e-05, 1.38894917e-04, 8.35675837e-06, ..., 1.86521246e-03, 5.88638522e-06, 1.14366633e-03], ..., [3.24849657e-06, 7.88489797e-06, 8.02099839e-06, ..., 1.07813348e-05, 4.16016592e-05, 1.29839216e-04], [7.13020563e-03, 4.53320885e-04, 2.08631551e-04, ..., 1.01280843e-04, 1.02604674e-04, 1.17479693e-02], [3.62392224e-04, 1.17725604e-05, 4.43559606e-04, ..., 8.22547637e-03, 1.33430047e-04, 5.50936202e-05]], dtype=float32)
np.sum(predictions[0])
# First Prediction
index = 42
print(predictions[index])
print(f"Max value (probability of prediction): {np.max(predictions[index])}")
print(f"Sum: {np.sum(predictions[index])}")
print(f"Max index: {np.argmax(predictions[index])}")
print(f"Predicted label: {unique_breeds[np.argmax(predictions[index])]}")
unique_breeds[113]
'walker_hound'
# Turn prediction probabilities into their respective label
def get_pred_label(prediction_probabilities):
"""
Turns array of prediction probabilities into a label
"""
return unique_breeds[np.argmax(prediction_probabilities)]
# Get a predicted label based on an array of prediction probabilities
pred_label = get_pred_label(predictions[81])
pred_label
'dingo'
val_data
<_BatchDataset element_spec=(TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name=None), TensorSpec(shape=(None, 120), dtype=tf.bool, name=None))>
Validation data is still in a batch dataset, we have to unbatchify to make predictions on the validation images and compare those predictions to the validation labels (true labels)
images_ = []
labels_ = []
# Loop through unbatched data
for image, label in val_data.unbatch().as_numpy_iterator():
images_.append(image)
labels_.append(label)
images_[0], labels_[0]
(array([[[0.29599646, 0.43284872, 0.3056691 ], [0.26635826, 0.32996926, 0.22846507], [0.31428418, 0.27701408, 0.22934894], ..., [0.77614343, 0.82320225, 0.8101595 ], [0.81291157, 0.8285351 , 0.8406944 ], [0.8209297 , 0.8263737 , 0.8423668 ]], [[0.2344871 , 0.31603682, 0.19543913], [0.3414841 , 0.36560842, 0.27241898], [0.45016077, 0.40117094, 0.33964607], ..., [0.7663987 , 0.8134138 , 0.81350833], [0.7304248 , 0.75012016, 0.76590735], [0.74518913, 0.76002574, 0.7830809 ]], [[0.30157745, 0.3082587 , 0.21018331], [0.2905954 , 0.27066195, 0.18401104], [0.4138316 , 0.36170745, 0.2964005 ], ..., [0.79871625, 0.8418535 , 0.8606443 ], [0.7957738 , 0.82859945, 0.8605655 ], [0.75181633, 0.77904975, 0.8155256 ]], ..., [[0.9746779 , 0.9878955 , 0.9342279 ], [0.99153054, 0.99772066, 0.9427856 ], [0.98925114, 0.9792082 , 0.9137934 ], ..., [0.0987601 , 0.0987601 , 0.0987601 ], [0.05703771, 0.05703771, 0.05703771], [0.03600177, 0.03600177, 0.03600177]], [[0.98197854, 0.9820659 , 0.9379411 ], [0.9811992 , 0.97015417, 0.9125648 ], [0.9722316 , 0.93666023, 0.8697186 ], ..., [0.09682598, 0.09682598, 0.09682598], [0.07196062, 0.07196062, 0.07196062], [0.0361607 , 0.0361607 , 0.0361607 ]], [[0.97279435, 0.9545954 , 0.92389745], [0.963602 , 0.93199134, 0.88407487], [0.9627158 , 0.91253304, 0.8460338 ], ..., [0.08394483, 0.08394483, 0.08394483], [0.0886985 , 0.0886985 , 0.0886985 ], [0.04514172, 0.04514172, 0.04514172]]], dtype=float32), array([False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]))
get_pred_label(labels_[0])
'cairn'
# Create a fuction to unbatch a batch dataset
def unbatchify(data):
"""
Takes a batched dataset of (image, label) Tensors and returns separate arrays of images and labels.
"""
images = []
labels = []
# Loop through unbatched data
for image, label in data.unbatch().as_numpy_iterator():
images.append(image)
labels.append(unique_breeds[np.argmax(label)])
return images, labels
# Unbatchify the validation data
val_images, val_labels = unbatchify(val_data)
val_images[0], val_labels[0]
(array([[[0.29599646, 0.43284872, 0.3056691 ], [0.26635826, 0.32996926, 0.22846507], [0.31428418, 0.27701408, 0.22934894], ..., [0.77614343, 0.82320225, 0.8101595 ], [0.81291157, 0.8285351 , 0.8406944 ], [0.8209297 , 0.8263737 , 0.8423668 ]], [[0.2344871 , 0.31603682, 0.19543913], [0.3414841 , 0.36560842, 0.27241898], [0.45016077, 0.40117094, 0.33964607], ..., [0.7663987 , 0.8134138 , 0.81350833], [0.7304248 , 0.75012016, 0.76590735], [0.74518913, 0.76002574, 0.7830809 ]], [[0.30157745, 0.3082587 , 0.21018331], [0.2905954 , 0.27066195, 0.18401104], [0.4138316 , 0.36170745, 0.2964005 ], ..., [0.79871625, 0.8418535 , 0.8606443 ], [0.7957738 , 0.82859945, 0.8605655 ], [0.75181633, 0.77904975, 0.8155256 ]], ..., [[0.9746779 , 0.9878955 , 0.9342279 ], [0.99153054, 0.99772066, 0.9427856 ], [0.98925114, 0.9792082 , 0.9137934 ], ..., [0.0987601 , 0.0987601 , 0.0987601 ], [0.05703771, 0.05703771, 0.05703771], [0.03600177, 0.03600177, 0.03600177]], [[0.98197854, 0.9820659 , 0.9379411 ], [0.9811992 , 0.97015417, 0.9125648 ], [0.9722316 , 0.93666023, 0.8697186 ], ..., [0.09682598, 0.09682598, 0.09682598], [0.07196062, 0.07196062, 0.07196062], [0.0361607 , 0.0361607 , 0.0361607 ]], [[0.97279435, 0.9545954 , 0.92389745], [0.963602 , 0.93199134, 0.88407487], [0.9627158 , 0.91253304, 0.8460338 ], ..., [0.08394483, 0.08394483, 0.08394483], [0.0886985 , 0.0886985 , 0.0886985 ], [0.04514172, 0.04514172, 0.04514172]]], dtype=float32), 'cairn')
Ways to create:
- Prediction Labels
- Validation labels (truth labels)
- Validation images
Create a function to visualize:
- Takes an array of prediction probabilities, an array of truth labels and an array of images and integer
- Convert the prediction probabilities to a predicted label
- Plot the predicted label, its predicted probability, the truth label and the target image on a single plot
def plot_pred(prediction_probabilities, labels, images, n=1):
"""
View the prediction, ground truth and image sample n
"""
pred_prob, true_label, image = prediction_probabilities[n], labels[n], images[n]
# Get the pred label
pred_label = get_pred_label(pred_prob)
# Plot image & remove ticks
plt.imshow(image)
plt.xticks([])
plt.yticks([])
# Change the color of the title depending of the prediction is correct or not
if pred_label == true_label:
color = "green"
else:
color = "red"
# Change plot title to be predicted, probability of prediction and truth
plt.title("{}{:2.0f}%{}".format(pred_label,
np.max(pred_prob)*100,
true_label),
color=color)
plot_pred(prediction_probabilities=predictions,
labels=val_labels,
images=val_images,
n=77)
Create a function to view model
- Take input of prediction probabilities array and a ground truth array and an integer
- Find the prediction using
get_pred_label()
- Find the top 10
- Prediction probabilities indexes
- Prediction probabilities values
- Predictions labels
- Plot the top 10 prediction probability values and labels, coloring the true label green
def plot_pred_conf(prediction_probabilities, labels, n=1):
"""
Plus the top 10 highet prediction confidences along with the truth label for sample n
"""
pred_prob, true_label = prediction_probabilities[n], labels[n]
# Get predicted label
pred_label = get_pred_label(pred_prob)
# Find the top 10 prediction confidence indexes
top_10_pred_indexes = pred_prob.argsort()[-10:][::-1]
# Find the top 10 prediction confidence values
top_10_pred_values = pred_prob[top_10_pred_indexes]
# FIND TOP 10 PREDICTION LABELS
top_10_pred_labels = unique_breeds[top_10_pred_indexes]
# Setup plot
top_plot = plt.bar(np.arange(len(top_10_pred_labels,)),
top_10_pred_values,
color="grey")
plt.xticks(np.arange(len(top_10_pred_labels)),
labels=top_10_pred_labels,
rotation="vertical")
# CHANGE COLOR OF TRUE LABEL
if np.isin(true_label, top_10_pred_labels):
top_plot[np.argmax(top_10_pred_labels == true_label)].set_color("green")
else:
pass
plot_pred_conf(prediction_probabilities=predictions,
labels=val_labels,
n=9)
# Check out a few predictions and their different values
i_multiplier = 10
num_rows = 3
num_cols = 2
num_images = num_rows*num_cols
plt.figure(figsize=(10*num_cols, 5*num_rows))
for i in range(num_images):
plt.subplot(num_rows, 2*num_cols, 2*i+1)
plot_pred(prediction_probabilities=predictions,
labels=val_labels,
images=val_images,
n=i+i_multiplier)
plt.subplot(num_rows, 2*num_cols, 2*i+2)
plot_pred_conf(prediction_probabilities=predictions,
labels=val_labels,
n=i+i_multiplier)
plt.tight_layout(h_pad=1.0)
plt.show()
SAVING AND RELOADING MODEL¶
# CREATE FUNCTION TO SAVE MODEL
def save_model(model, suffix=None):
# Create a model directory pathname with current time
modeldir = os.path.join("drive/MyDrive/Dog-Vision/models",
datetime.datetime.now().strftime("%Y%m%d-%H%M%s"))
model_path = modeldir + "-" + suffix + ".h5" # save format of model
print(f"Saving model to: {model_path} ...")
model.save(model_path)
return model_path
# CREATE FUNCTION TO LOAD TRAINED MODEL
def load_model(model_path):
"""
LOADS A SAVED MODEL FROM SPECIFIED PATH.
"""
print(f"Loading saved model from: {model_path}")
model = tf.keras.models.load_model(model_path,
custom_objects={"KerasLayer":hub.KerasLayer})
return model
# SAVE MODEL TRAINED ON 1000 IMAGES
save_model(model, suffix="1000-images-mobilenetv2-Adam")
Saving model to: drive/MyDrive/Dog-Vision/models/20240229-20531709240012-1000-images-mobilenetv2-Adam.h5 ...
/usr/local/lib/python3.10/dist-packages/keras/src/engine/training.py:3103: UserWarning: You are saving your model as an HDF5 file via `model.save()`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')`. saving_api.save_model(
'drive/MyDrive/Dog-Vision/models/20240229-20531709240012-1000-images-mobilenetv2-Adam.h5'
# LOAD TRAINED MODEL
loaded_1000_image_model = load_model("drive/MyDrive/Dog-Vision/models/20240229-19581709236706-1000-images-mobilenetv2-Adam.h5")
Loading saved model from: drive/MyDrive/Dog-Vision/models/20240229-19581709236706-1000-images-mobilenetv2-Adam.h5
# EVALUATE PRE-SAVED MODEL
model.evaluate(val_data)
7/7 [==============================] - 12s 1s/step - loss: 1.2493 - accuracy: 0.6650
[1.249266266822815, 0.6650000214576721]
# EVALUATE LOADED MODEL
loaded_1000_image_model.evaluate(val_data)
TRAINING A BIG DOG MODEL ON FULL DATA¶
# CREATE A DATA BATCH WITH FULL DATASET
full_data = create_data_batches(x,y)
full_data
# Create model for a full model
full_model = create_model()
Creating training data batches ... Building model with: https://kaggle.com/models/google/mobilenet-v2/frameworks/TensorFlow2/variations/130-224-classification/versions/1
# Create full model callbacks
full_model_tensorboard = create_tensorboard_callback()
# NO VALIDATION SET WHEN TRAINING ON ALL THE DATA - SO CAN'T MONITOR VALIDATION ACCURACY
full_model_early_stopping = tf.keras.callbacks.EarlyStopping(monitor="accuracy",
patience=3)
NOTE: RUNNING THE CELL BELOW MAY TAKE A LONG WHILE¶
# FIT THE FULL MODEL TO THE FULL DATA
full_model.fit(x=full_data,
epochs=NUM_EPOCHS,
callbacks=[full_model_tensorboard, full_model_early_stopping])
Epoch 1/100 320/320 [==============================] - 569s 2s/step - loss: 0.2187 - accuracy: 0.9408 Epoch 2/100 320/320 [==============================] - 559s 2s/step - loss: 0.1403 - accuracy: 0.9688 Epoch 3/100 320/320 [==============================] - 564s 2s/step - loss: 0.0977 - accuracy: 0.9803 Epoch 4/100 320/320 [==============================] - 585s 2s/step - loss: 0.0707 - accuracy: 0.9892 Epoch 5/100 320/320 [==============================] - 580s 2s/step - loss: 0.0553 - accuracy: 0.9924 Epoch 6/100 320/320 [==============================] - 581s 2s/step - loss: 0.0449 - accuracy: 0.9931 Epoch 7/100 320/320 [==============================] - 570s 2s/step - loss: 0.0361 - accuracy: 0.9961 Epoch 8/100 320/320 [==============================] - 568s 2s/step - loss: 0.0291 - accuracy: 0.9967 Epoch 9/100 320/320 [==============================] - 570s 2s/step - loss: 0.0249 - accuracy: 0.9980 Epoch 10/100 320/320 [==============================] - 569s 2s/step - loss: 0.0201 - accuracy: 0.9986 Epoch 11/100 320/320 [==============================] - 564s 2s/step - loss: 0.0195 - accuracy: 0.9982 Epoch 12/100 320/320 [==============================] - 567s 2s/step - loss: 0.0181 - accuracy: 0.9982 Epoch 13/100 320/320 [==============================] - 568s 2s/step - loss: 0.0167 - accuracy: 0.9987 Epoch 14/100 320/320 [==============================] - 561s 2s/step - loss: 0.0137 - accuracy: 0.9988 Epoch 15/100 320/320 [==============================] - 552s 2s/step - loss: 0.0117 - accuracy: 0.9990 Epoch 16/100 320/320 [==============================] - 565s 2s/step - loss: 0.0117 - accuracy: 0.9990 Epoch 17/100 320/320 [==============================] - 559s 2s/step - loss: 0.0105 - accuracy: 0.9990 Epoch 18/100 320/320 [==============================] - 563s 2s/step - loss: 0.0111 - accuracy: 0.9988
<keras.src.callbacks.History at 0x7e65829f7d30>
# SAVE MODEL TRAINED ON ALL IMAGES
save_model(model, suffix="full-image-set-mobilenetv2-Adam")
Saving model to: drive/MyDrive/Dog-Vision/models/20240301-01071709255254-full-image-set-mobilenetv2-Adam.h5 ...
/usr/local/lib/python3.10/dist-packages/keras/src/engine/training.py:3103: UserWarning: You are saving your model as an HDF5 file via `model.save()`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')`. saving_api.save_model(
'drive/MyDrive/Dog-Vision/models/20240301-01071709255254-full-image-set-mobilenetv2-Adam.h5'
# Load full model
loaded_full_model = load_model("drive/MyDrive/Dog-Vision/models/20240301-01071709255254-full-image-set-mobilenetv2-Adam.h5")
Loading saved model from: drive/MyDrive/Dog-Vision/models/20240301-01071709255254-full-image-set-mobilenetv2-Adam.h5
MAKING PREDICTION ON THE TEST DATASET¶
Model has been trained on images in the form of Tensor batches, to make prediction on the test data, need to get it in the same format (numerical)
We created create_data_batches()
earlier which can take a list of filenames as input and convert them Tensor batches
To make predictions on test data:
- Get the test image filenames
- Convert the filenames into test data batches using
create_data_batches()
and setting thetest_data
parameter toTrue
(since the test data doesn't have labels). - Make a predictions array by passing the test batches to the
predict()
method called on our model.
# LOAD TEST IMAGE FILENAMES
test_path = "drive/MyDrive/Dog-Vision/test"
test_filenames = [test_path + fname for fname in os.listdir(test_path)]
test_filenames[:10]
['drive/MyDrive/Dog-Vision/teste004d9f3a6236e2de6dd0f386b685059.jpg', 'drive/MyDrive/Dog-Vision/teste78b50f1d12148deef4c564ea4c88050.jpg', 'drive/MyDrive/Dog-Vision/teste7dc8cc599049ea9fa2a172c88646c57.jpg', 'drive/MyDrive/Dog-Vision/teste7feb64da6aae1ef8e62453f6660d0c5.jpg', 'drive/MyDrive/Dog-Vision/testde084b830010b6107215fef5d4a75b94.jpg', 'drive/MyDrive/Dog-Vision/teste425ab04e3a0d4464cda46a076964770.jpg', 'drive/MyDrive/Dog-Vision/teste4ec1e1a3e21d31f6e058c04655cb38b.jpg', 'drive/MyDrive/Dog-Vision/teste440ec011c3c7ea94838ab5fc466159c.jpg', 'drive/MyDrive/Dog-Vision/teste1e79b3edfb3579e46ad914bf755dbbc.jpg', 'drive/MyDrive/Dog-Vision/teste2915c191c0bc761b795b78f66845fe0.jpg']
# Create test data batch
test_data = create_data_batches(test_filenames, test_data=True)
Creating test batches ...
len(test_filenames)
10357
test_data
<_BatchDataset element_spec=TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name=None)>
NOTE: THIS WILL TAKE A LONG TIME TO RUN¶
# Make predictions on test data batch using the loaded full model
test_predictions = loaded_full_model.predict(test_data, verbose=1)
--------------------------------------------------------------------------- NotFoundError Traceback (most recent call last) <ipython-input-130-b28ca8b6cc83> in <cell line: 2>() 1 # Make predictions on test data batch using the loaded full model ----> 2 test_predictions = loaded_full_model.predict(test_data, verbose=1) /usr/local/lib/python3.10/dist-packages/keras/src/utils/traceback_utils.py in error_handler(*args, **kwargs) 68 # To get the full stack trace, call: 69 # `tf.debugging.disable_traceback_filtering()` ---> 70 raise e.with_traceback(filtered_tb) from None 71 finally: 72 del filtered_tb /usr/local/lib/python3.10/dist-packages/tensorflow/python/eager/execute.py in quick_execute(op_name, num_outputs, inputs, attrs, ctx, name) 51 try: 52 ctx.ensure_initialized() ---> 53 tensors = pywrap_tfe.TFE_Py_Execute(ctx._handle, device_name, op_name, 54 inputs, attrs, num_outputs) 55 except core._NotOkStatusException as e: NotFoundError: Graph execution error: Detected at node ReadFile defined at (most recent call last): <stack traces unavailable> drive/MyDrive/Dog-Vision/teste004d9f3a6236e2de6dd0f386b685059.jpg; No such file or directory [[{{node ReadFile}}]] [[IteratorGetNext]] [Op:__inference_predict_function_113320]
# SAVE PREDICTION (Numpy array) to csv file (for access later)
np.savetxt("drive/MyDrive/Dog-Vision/preds_array.csv", test_predictions, delimiter=",")
# Load predictions (NumPy array from csv file)
test_predictions = np.loadtxt("drive/MyDrive/Dog-Vision/preds_array.csv", delimiter=",")
SKIPPED AHEAD IN VIDEO - TEST PREDICTIONS CSV WAS PROVIDED TO MOVE FOWARD WITH SESSION¶
test_predictions[:10]
array([[1.61196489e-09, 3.44086413e-12, 2.32834394e-11, ..., 1.06917716e-13, 1.58530451e-08, 1.52161670e-06], [3.17894322e-10, 3.20088262e-14, 1.85374840e-10, ..., 7.00588814e-08, 1.88822238e-08, 2.56980937e-10], [4.27301083e-09, 1.84139528e-13, 1.11784948e-09, ..., 2.71949238e-12, 2.23927123e-06, 7.41860809e-11], ..., [4.47232779e-10, 4.28004029e-07, 4.11986996e-08, ..., 4.65437893e-07, 8.21722967e-10, 8.86002116e-09], [3.50528079e-11, 1.94377336e-03, 1.44941642e-10, ..., 1.56135718e-06, 6.13228721e-08, 7.32120961e-12], [1.23221771e-08, 3.08354520e-09, 1.87174110e-10, ..., 8.16165635e-10, 9.98905063e-01, 6.73740752e-09]])
PREPARING TEST DATASET PREDICTIONS READY FOR KAGGLE¶
Kaggle wants our models prediction probability outputs in a dataframe wht id and column for different dog breed
to get this format:
- Create Pandas DataFrame with ID column as well as a column for each dog breed.
- Add data to the ID Column by extracting the test image ID's from their filepaths.
- Add data (the prediction probabilities) to each of the dog breed columns.
- Export the DataFrame as a CSV to submit to Kaggle
# Create a panda DataFrame with empty columns
preds_df = pd.DataFrame(columns=["id"] + list(unique_breeds))
preds_df.head()
id | affenpinscher | afghan_hound | african_hunting_dog | airedale | american_staffordshire_terrier | appenzeller | australian_terrier | basenji | basset | ... | toy_poodle | toy_terrier | vizsla | walker_hound | weimaraner | welsh_springer_spaniel | west_highland_white_terrier | whippet | wire-haired_fox_terrier | yorkshire_terrier |
---|
0 rows × 121 columns
# Append test image IDs to predictions DataFrame
test_ids = [os.path.splitext(path[0]) for path in os.listdir(test_path)]
preds_df["id"] = test_ids
preds_df.head()
id | affenpinscher | afghan_hound | african_hunting_dog | airedale | american_staffordshire_terrier | appenzeller | australian_terrier | basenji | basset | ... | toy_poodle | toy_terrier | vizsla | walker_hound | weimaraner | welsh_springer_spaniel | west_highland_white_terrier | whippet | wire-haired_fox_terrier | yorkshire_terrier | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | (e, ) | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
1 | (e, ) | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2 | (e, ) | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
3 | (e, ) | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
4 | (d, ) | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
5 rows × 121 columns
# Add the prediction probabilities to each dog breed column
preds_df[list(unique_breeds)] = test_predictions
preds_df.head()
id | affenpinscher | afghan_hound | african_hunting_dog | airedale | american_staffordshire_terrier | appenzeller | australian_terrier | basenji | basset | ... | toy_poodle | toy_terrier | vizsla | walker_hound | weimaraner | welsh_springer_spaniel | west_highland_white_terrier | whippet | wire-haired_fox_terrier | yorkshire_terrier | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | (e, ) | 1.611965e-09 | 3.440864e-12 | 2.328344e-11 | 1.407994e-12 | 5.980330e-09 | 2.145339e-11 | 5.328517e-10 | 1.764934e-10 | 4.491057e-11 | ... | 8.200658e-09 | 4.056766e-08 | 2.202154e-11 | 3.074556e-12 | 7.080598e-12 | 3.024534e-09 | 2.991727e-07 | 1.069177e-13 | 1.585305e-08 | 1.521617e-06 |
1 | (e, ) | 3.178943e-10 | 3.200883e-14 | 1.853748e-10 | 1.954662e-13 | 8.682216e-07 | 3.362278e-07 | 2.264711e-06 | 9.995926e-01 | 1.876677e-10 | ... | 3.441671e-07 | 1.129437e-04 | 6.675200e-09 | 1.690707e-06 | 6.804413e-10 | 5.923428e-09 | 5.574148e-09 | 7.005888e-08 | 1.888222e-08 | 2.569809e-10 |
2 | (e, ) | 4.273011e-09 | 1.841395e-13 | 1.117849e-09 | 1.106639e-10 | 7.225005e-11 | 1.169239e-05 | 7.223256e-07 | 5.553372e-04 | 9.785655e-11 | ... | 3.530463e-09 | 4.605002e-05 | 9.586189e-12 | 2.740325e-08 | 8.798643e-12 | 2.793681e-08 | 1.502214e-07 | 2.719492e-12 | 2.239271e-06 | 7.418608e-11 |
3 | (e, ) | 5.227723e-14 | 3.371553e-14 | 1.638175e-11 | 5.283554e-12 | 7.160043e-08 | 1.832600e-13 | 6.625124e-13 | 1.087913e-13 | 8.482403e-11 | ... | 5.968796e-12 | 1.492889e-13 | 2.230498e-06 | 4.158368e-10 | 9.999646e-01 | 3.224581e-13 | 1.426521e-11 | 2.974644e-12 | 8.130380e-13 | 6.134530e-11 |
4 | (d, ) | 9.613753e-11 | 1.304277e-08 | 1.246931e-08 | 1.478856e-07 | 6.658420e-09 | 6.374474e-12 | 2.422878e-05 | 4.128350e-09 | 1.767556e-04 | ... | 1.207746e-06 | 2.052871e-08 | 6.508744e-13 | 2.080402e-10 | 1.428936e-09 | 5.703394e-08 | 1.541623e-06 | 2.052792e-05 | 3.110282e-04 | 1.318874e-06 |
5 rows × 121 columns
# Export predictions dataframe to CSV
preds_df.to_csv("drive/MyDrive/Dog-Vision/full_model_predictions_submission_1_mobilenetV2.csv",
index = False)
MAKING PREDICTIONS ON CUSTOM IMAGES¶
To make predictions on custom images:
- Get the filepaths of our own images
- Turn the filepath into data batches using
create_data_batches()
. And since our custom images don't have labels, we set tehtest_data
parameter toTrue
. - Pass the custom image data batch to our model's
predict()
method. - Convert the prediction output probabilities to prediction labels.
- Compare the predicted labels to custom images.
# Get custom image filepaths
custom_path = "drive/MyDrive/Dog-Vision/MyPhotos/"
custom_image_paths = [custom_path + fname for fname in os.listdir(custom_path)]
custom_image_paths
['drive/MyDrive/Dog-Vision/MyPhotos/doggo_01.jpg', 'drive/MyDrive/Dog-Vision/MyPhotos/doggo_03.webp', 'drive/MyDrive/Dog-Vision/MyPhotos/doggo_04.jpg', 'drive/MyDrive/Dog-Vision/MyPhotos/doggo_02.jpg']
# Turn custom images into batch datasets
custom_data = create_data_batches(custom_image_paths, test_data=True)
custom_data
Creating test batches ...
<_BatchDataset element_spec=TensorSpec(shape=(None, 224, 224, 3), dtype=tf.float32, name=None)>
# Make predictions on the custom data
custom_preds = loaded_full_model.predict(custom_data)
--------------------------------------------------------------------------- InvalidArgumentError Traceback (most recent call last) <ipython-input-125-02c9d19ab00f> in <cell line: 2>() 1 # Make predictions on the custom data ----> 2 custom_preds = loaded_full_model.predict(custom_data) /usr/local/lib/python3.10/dist-packages/keras/src/utils/traceback_utils.py in error_handler(*args, **kwargs) 68 # To get the full stack trace, call: 69 # `tf.debugging.disable_traceback_filtering()` ---> 70 raise e.with_traceback(filtered_tb) from None 71 finally: 72 del filtered_tb /usr/local/lib/python3.10/dist-packages/tensorflow/python/eager/execute.py in quick_execute(op_name, num_outputs, inputs, attrs, ctx, name) 51 try: 52 ctx.ensure_initialized() ---> 53 tensors = pywrap_tfe.TFE_Py_Execute(ctx._handle, device_name, op_name, 54 inputs, attrs, num_outputs) 55 except core._NotOkStatusException as e: InvalidArgumentError: Graph execution error: Detected at node DecodeJpeg defined at (most recent call last): <stack traces unavailable> Unknown image file format. One of JPEG, PNG, GIF, BMP required. [[{{node DecodeJpeg}}]] [[IteratorGetNext]] [Op:__inference_predict_function_113320]
custom_preds.shape
# Get custom image prediction labels
custom_pred_labels = [get_pred_label(custom_preds[i]) for i in range(len(custom_preds))]
custom_pred_labels
# Get custom images (Our unbatchify() function won't work since there aren't labels)
custom_images = []
# Loop through unbatched data
for image in custom_data.unbatch().as_numpy_iterator():
custom_images.append(image)
# Check custom image predictions
plt.figure(figsize=(10, 10))
for i, image in enumerate(custom_images):
plt.subplot(1, 3, i+1)
plt.xticks([])
plt.yticks([])
plt.title(custom_pred_labels[i])
plt.imshow(image)