Reputation: 883
I have a colab with which I am working. It is about using keras to build CNN. My code so far which works is as follows (epochs set to 5 due to time reasons):
import os as os
import numpy as np
import glob as gl
import matplotlib.pyplot as plt
import shutil
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
URL = 'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz'
zip_dir = tf.keras.utils.get_file('flower_photos.tgz', URL, extract=True)
base_dir = os.path.join(os.path.dirname(zip_dir), 'flower_photos')
labels = ['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips']
for label in labels:
imagepath = os.path.join(base_dir, label)
images = gl.glob(imagepath + '/*.jpg')
print("{}: {} Images".format(label, len(images)))
train, val = images[:round(len(images)*0.8)], images[round(len(images)*0.8):]
for t in train:
if not os.path.exists(os.path.join(base_dir, 'train', label)):
os.makedirs(os.path.join(base_dir, 'train', label))
shutil.move(t, os.path.join(base_dir, 'train', label))
for v in val:
if not os.path.exists(os.path.join(base_dir, 'val', label)):
os.makedirs(os.path.join(base_dir, 'val', label))
shutil.move(v, os.path.join(base_dir, 'val', label))
traindir = os.path.join(base_dir, 'train')
val_dir = os.path.join(base_dir, 'val')
batch_size = 100
img_size = 150
image_gen_train = ImageDataGenerator(rescale = 1./255,
rotation_range=45,
width_shift_range=0.15,
zoom_range=0.5,
height_shift_range=0.15,
horizontal_flip=True)
image_gen_val = ImageDataGenerator(rescale = 1./255)
train_data_gen = image_gen_train.flow_from_directory(batch_size=batch_size,
directory=traindir,
shuffle=True,
target_size=(img_size,img_size),
class_mode='sparse')
val_data_gen = image_gen_val.flow_from_directory(batch_size=batch_size,
directory=val_dir,
target_size=(img_size,img_size),
class_mode='sparse')
def plotImages(images_arr):
fig, axes = plt.subplots(1, 5, figsize=(20,20))
axes = axes.flatten()
for img, ax in zip( images_arr, axes):
ax.imshow(img)
plt.tight_layout()
plt.show()
augmented_images = [train_data_gen[0][0][0] for i in range(5)]
plotImages(augmented_images)
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, (3,3), padding='same', activation='relu', input_shape=(img_size, img_size, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3,3), padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Conv2D(64, (3,3), padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dense(5, activation='softmax')
])
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.summary()
epochs = 5
history = model.fit(
train_data_gen,
epochs=epochs,
validation_data=val_data_gen
)
Now I have two questions (the second one being more important):
I use a kernel of 3,3 ( tf.keras.layers.Conv2D(16, (3,3)
). In the solution however, they just use:
model.add(Conv2D(16, 3, padding='same', activation='relu', input_shape=(IMG_SHAPE,IMG_SHAPE, 3)))
So just the integer 3. Why this? The task clearly states "All convolutional filters should be 3 x 3".
My second question: I would like to have not only a train and validation set, but also a test set. At the end I want to check my performance on the test dataset. So I do use the training and validation dataset in the model training, but furthermore at the end I want to compare it with the following statment:
# Evaluate against the test set.
print("\n Evaluate the new model against the test set:")
my_model.evaluate(x=x_test_normalized, y=y_test, batch_size=batch_size)
How does the code needs to be modified in order to get a training, validation and test set?
I tried to use the validation split and hoped I could use the up to know called validation set as a test set:
history = model.fit(
train_data_gen,
epochs=epochs,
validation_split= 0.2
)
my_model.evaluate(x=val_data_gen, y=train_data_gen, batch_size=batch_size)
However, this does not work as my input in the model fit does not support validation split, the error message tells me.
Upvotes: 2
Views: 198
Reputation: 608
Your first question: So just the integer 3. Why this? The task clearly states "All convolutional filters should be 3 x 3"
Answer: Refering to the documentation https://www.tensorflow.org/api_docs/python/tf/keras/layers/Conv2D, kernel_size can be integer or tuple/list of 2 integers, specifying the height and width of the 2D convolution window. Can be a single integer to specify the same value for all spatial dimensions. So the kernel is taking shape of 3 x 3 by providing single integer 3.
Your second question: How does the code needs to be modified in order to get a training, validation and test set?
Answer: You can refer this link How to split data into 3 sets (train, validation and test)?
Edit: Second answer complete exmaple for what you have asked
import os
import glob
import matplotlib.pyplot as plt
import shutil
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
URL = 'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz'
zip_dir = tf.keras.utils.get_file('flower_photos.tgz', URL, extract=True)
base_dir = os.path.join(os.path.dirname(zip_dir), 'flower_photos')
labels = ['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips']
for label in labels:
imagepath = os.path.join(base_dir, label)
images = glob.glob(imagepath + '/*.jpg')
print("{}: {} Images".format(label, len(images)))
# here you have split dataset into 80:20 ratio for train and validation
train, val = images[:round(len(images) * 0.8)], images[round(len(images) * 0.8):]
# here we will split train into 75:25 ratio for train and test
train, test = train[:round(len(train) * 0.75)], train[round(len(train) * 0.75):]
# Note: Second one is 75:25 because overall dataset of one label will be split into 60:20:20
for t in train:
if not os.path.exists(os.path.join(base_dir, 'train', label)):
os.makedirs(os.path.join(base_dir, 'train', label))
shutil.move(t, os.path.join(base_dir, 'train', label))
for v in val:
if not os.path.exists(os.path.join(base_dir, 'val', label)):
os.makedirs(os.path.join(base_dir, 'val', label))
shutil.move(v, os.path.join(base_dir, 'val', label))
# we will create same thing for test dataset like we did for train and val above
for t in test:
if not os.path.exists(os.path.join(base_dir, 'test', label)):
os.makedirs(os.path.join(base_dir, 'test', label))
shutil.move(t, os.path.join(base_dir, 'test', label))
train_dir = os.path.join(base_dir, 'train')
val_dir = os.path.join(base_dir, 'val')
test_dir = os.path.join(base_dir, 'test')
batch_size = 100
img_size = 150
image_gen_train = ImageDataGenerator(rescale=1. / 255,
rotation_range=45,
width_shift_range=0.15,
zoom_range=0.5,
height_shift_range=0.15,
horizontal_flip=True)
image_gen_val = ImageDataGenerator(rescale=1. / 255)
image_gen_test = ImageDataGenerator(rescale=1. / 255)
train_data_gen = image_gen_train.flow_from_directory(batch_size=batch_size,
directory=train_dir,
shuffle=True,
target_size=(img_size, img_size),
class_mode='sparse')
val_data_gen = image_gen_val.flow_from_directory(batch_size=batch_size,
directory=val_dir,
target_size=(img_size, img_size),
class_mode='sparse')
# we will create a test data generator here
test_data_gen = image_gen_test.flow_from_directory(batch_size=batch_size,
directory=test_dir,
target_size=(img_size, img_size),
class_mode='sparse')
def plotImages(images_arr):
fig, axes = plt.subplots(1, 5, figsize=(20, 20))
axes = axes.flatten()
for img, ax in zip(images_arr, axes):
ax.imshow(img)
plt.tight_layout()
plt.show()
augmented_images = [train_data_gen[0][0][0] for i in range(5)]
plotImages(augmented_images)
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, (3, 3), padding='same', activation='relu',
input_shape=(img_size, img_size, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3, 3), padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3, 3), padding='same', activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dense(5, activation='softmax')
])
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.summary()
epochs = 5
history = model.fit(
train_data_gen,
epochs=epochs,
validation_data=val_data_gen
)
# evaluate model using test data generator
model.evaluate(test_data_gen, batch_size=batch_size)
# to know what above scalar values represent
print(model.metrics_names)
Upvotes: 2