import matplotlib.pyplot as plt
import tensorflow as tf
import numpy as np
import os
from tensorflow.keras.preprocessing.image import load_img
base_dir = "./data/"
happy_dir = os.path.join(base_dir, "happy/")
sad_dir = os.path.join(base_dir, "sad/")
print("Sample happy image:")
plt.imshow(load_img(f"{os.path.join(happy_dir, os.listdir(happy_dir)[0])}"))
plt.show()
print("\nSample sad image:")
plt.imshow(load_img(f"{os.path.join(sad_dir, os.listdir(sad_dir)[0])}"))
plt.show()
Let's check the images shapes and pixel values:
from tensorflow.keras.preprocessing.image import img_to_array
# Load the first example of a happy face
sample_image = load_img(f"{os.path.join(happy_dir, os.listdir(happy_dir)[0])}")
# Convert the image into its numpy array representation
sample_array = img_to_array(sample_image)
print(f"Each image has shape: {sample_array.shape}")
print(f"The maximum pixel value used is: {np.max(sample_array)}")
Looks like the images have a resolution of 150x150. This is very important because this will be the input size of the first layer in our network.
The last dimension refers to each one of the 3 RGB channels that are used to represent colored images.
class myCallback(tf.keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs={}):
if logs.get('accuracy') is not None and logs.get('accuracy') > 0.999:
print("\nReached 99.9% accuracy so cancelling training!")
self.model.stop_training = True
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# Instantiate the ImageDataGenerator class.
# Remember to set the rescale argument.
train_datagen = ImageDataGenerator(rescale=1/255)
# Specify the method to load images from a directory and pass in the appropriate arguments:
# - directory: should be a relative path to the directory containing the data
# - targe_size: set this equal to the resolution of each image (excluding the color dimension)
# - batch_size: number of images the generator yields when asked for a next batch. Set this to 10.
# - class_mode: How the labels are represented. Should be one of "binary", "categorical" or "sparse".
# Pick the one that better suits here given that the labels are going to be 1D binary labels.
train_generator = train_datagen.flow_from_directory("./data/",
target_size=(150, 150),
batch_size=10,
class_mode='binary')
from tensorflow.keras import optimizers, losses
from tensorflow.keras.optimizers import RMSprop
# Instantiate the callback
callbacks = myCallback()
# Define the model
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(150, 150, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
# Compile the model
model.compile(loss='binary_crossentropy',
optimizer=RMSprop(learning_rate=0.001),
metrics=['accuracy'])
# Train the model
history = model.fit(train_generator,
epochs=20,
callbacks=[myCallback()]
)
print(f"Model reached the desired accuracy after {len(history.epoch)} epochs")