Image Classifications: Flowers Recognition using TensorFlow

Alex G.
6 min readJun 30, 2020

--

(Photo,GIF by Author) https://github.com/oleksandr-g-rock/flower_classification/blob/main/23432432.png

Short summary:

In this article, I will explain how to create a solution for image classification for the 5 classes with the best result : loss: 0.1172 — accuracy: 0.9570 — val_loss: 0.2223 — val_accuracy: 0.9125. Code for this article available here

So Let’s start :)

The steps:

###Data preparation###

###Transfer learning###

### Fine tuning###

###Show Result###

If you want just to look at the notebook or just run code please click here

First, I want to run this code (like below) in google colab, but you can run this code anywhere and it should work.

1 Go to the colab

2 Download this dataset to your PC (like on screenshot)

(Photo,GIF by Author) https://github.com/oleksandr-g-rock/flower_classification/blob/main/1__ebmPe3qRfrk2th1h540Ug.png

3 Upload file which you download (above) to colab (like on screenshot)

(Photo,GIF by Author) https://github.com/oleksandr-g-rock/flower_classification/blob/main/1_s89DSv7KtvaccMu0C7iFgA%20(1).png

4 Unzip this file (just add code like on screenshot)

(Photo,GIF by Author) https://github.com/oleksandr-g-rock/flower_classification/blob/main/1_XQw7KwQWJhh9eq8vRGYzTg.png
!jar xvf /content/flowers-recognition.zip

5 Sort this dataset (prepare data)
Why we need it, if dataset is already prepared?
This dataset does not have the same number of pictures for each class.
This will cause problems during training of the model.
Therefore, it is necessary to make the same number of pictures for the train dataset and for the test dataset.
The train folder will have 80 percent of the total number of pictures. The test folder will have 20 percent of the total number of pictures.

So, you can run these commands to sort this dataset.

!git clone https://raw.githubusercontent.com/oleksandr-g-rock/flower_classification/main/flowers_sort.sh
!chmod 777 flowers_sort.sh
!cat flowers_sort.sh
!bash flowers_sort.sh

6 Ok. When our data is prepared, we can run modules.

from tensorflow.keras.applications.inception_v3 import InceptionV3
from tensorflow.keras.preprocessing import image
from tensorflow.keras.models import Model, load_model
from tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D, Dropout
from tensorflow.keras.layers import BatchNormalization, Activation
from tensorflow.python.keras.optimizers import Adam, RMSprop
from tensorflow.python.keras.preprocessing.image import ImageDataGenerator
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from numpy import loadtxt
import tensorflow.keras
from PIL import Image, ImageOps
%matplotlib inline

7 Set image size & batch size

image_size = 256
batch_size = 32

8 Create image generator
Why we need this image generator?
Because we don’t have many images. This generator will create new images from one image like this:

(Photo,GIF by Author) https://github.com/oleksandr-g-rock/flower_classification/blob/main/1_DO4Ssn5DQkRltCippat1Og.png

# folders with train dir & val dir
train_dir = '/content/flowers/train/'
test_dir = '/content/flowers/val/'
input_shape = (image_size, image_size, 3)
train_datagen = ImageDataGenerator(rescale=1. / 255,
samplewise_center=True,
samplewise_std_normalization=True,
horizontal_flip = True,
vertical_flip = True,
height_shift_range= 0.05,
width_shift_range=0.2,
rotation_range=5,
shear_range = 0.1,
fill_mode = 'reflect',
zoom_range=0.2)

9 Check our generator for one image

img_path = '/content/flowers/train/daisy/174131220_c853df1287.jpg'
img = image.load_img(img_path, target_size=(image_size, image_size))
x = image.img_to_array(img)
x = x.reshape((1,) + x.shape)
i = 0
for batch in train_datagen.flow(x, batch_size=1):
plt.figure(i)
imgplot = plt.imshow(image.array_to_img(batch[0]))
i += 1
if i % 6 == 0:
break
plt.show()

10 Set settings for train and test generator. It’s mean that we will use dataset with images from “image generator” to train our model, but for test we will use images from dataset without “image generator”.

#Setting train generator
train_generator = train_datagen.flow_from_directory(
train_dir,
target_size=(image_size, image_size),
batch_size=batch_size,
class_mode='categorical')
#Setting test generator without data augmentation
test_datagen = ImageDataGenerator(rescale=1. / 255)
test_generator = test_datagen.flow_from_directory(
test_dir,
target_size=(image_size, image_size),
batch_size=batch_size,
class_mode='categorical')
#Print count classes
train_generator.class_indices

11 Data Visualization

(Photo,GIF by Author) https://github.com/oleksandr-g-rock/flower_classification/blob/main/1_lqQXRXTASIBXBN7HDDpbTg.png

source for graph in “train” folder:

from sklearn.utils.class_weight import compute_class_weight
cls_train = train_generator.classes
from collections import OrderedDict
classes = list(train_generator.class_indices.keys())
num_values = []
unique, counts = np.unique(cls_train, return_counts=True)
valdict=OrderedDict(zip(unique, counts))
for i in range(5):
num_values.append(valdict[i])
plt.figure(figsize=(30,10))
x = np.arange(len(num_values))
xlabel = classes
plt.bar(x, num_values)
plt.xticks(x, xlabel)
plt.show()

source for graph in “test” folder:

from sklearn.utils.class_weight import compute_class_weight
cls_test = test_generator.classes
from collections import OrderedDict
classes = list(test_generator.class_indices.keys())
num_values = []
unique, counts = np.unique(cls_test, return_counts=True)
valdict=OrderedDict(zip(unique, counts))
for i in range(5):
num_values.append(valdict[i])
plt.figure(figsize=(30,10))
x = np.arange(len(num_values))
xlabel = classes
plt.bar(x, num_values)
plt.xticks(x, xlabel)
plt.show()

source for display of a round graph in “train” folder:

import matplotlib.pyplot as plt
goal_types = list(train_generator.class_indices.keys())
unique, counts = np.unique(cls_train, return_counts=True)
goals = [(counts)]
colors = ['y','r','b','g','b']
plt.pie(goals, labels = goal_types, colors=colors ,shadow = True, explode = (0.05, 0.05, 0.05, 0.05, 0.05), autopct = '%1.1f%%')
plt.axis('equal')
plt.show()

source for display of a round graph in “test” folder:

import matplotlib.pyplot as plt
goal_types = list(test_generator.class_indices.keys())
unique, counts = np.unique(cls_test, return_counts=True)
goals = [(counts)]
colors = ['y','r','b','g','b']
plt.pie(goals, labels = goal_types, colors=colors ,shadow = True, explode = (0.05, 0.05, 0.05, 0.05, 0.05), autopct = '%1.1f%%')
plt.axis('equal')
plt.show()

###Transfer learning###
We will use pretrained model Inception V3, because this model is well suited for this task.

12 Download pretrained model Inception V3

pretrained_model = InceptionV3(weights='imagenet', include_top=False)pretrained_model.summary()

13 “Froze” all weights of pretrained models. We do this to add new layers to our model.

pretrained_model.trainable = Falsepretrained_model.summary()

14 Create main layers in the end of inceptionV3 model.

x = pretrained_model.outputx = GlobalAveragePooling2D()(x)x = Dense(1024)(x)x = BatchNormalization()(x)x = Activation('relu')(x)x = Dropout(0.5)(x)x = Dense(512)(x)x = Activation('relu')(x)predictions = Dense(5, activation='softmax')(x) # because we have 5 classes imagesmodel = Model(inputs=pretrained_model.input, outputs=predictions)

15 View all model before training

model.summary()

16 Train a composite neural network based on InceptionV3. We will train our model for 240 epochs and save only the best epoch to file “inceptionv3_best.h5”.
Also, we will use “learning_rate_reduction” and optimizer=’adam’ and metrics=[‘accuracy’].

model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
filepath="inceptionv3_best.h5"
checkpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1,
save_best_only=True, mode='min')
learning_rate_reduction = ReduceLROnPlateau(monitor='val_accuracy',
patience=10,
verbose=1,
factor=0.5,
min_lr=0.00001)
callbacks_list = [checkpoint, learning_rate_reduction]
steps_per_epoch = 40
history = model.fit_generator(
train_generator,
steps_per_epoch=steps_per_epoch,
validation_data=test_generator,
validation_steps=5,
callbacks=callbacks_list,
epochs=240,
verbose=2)

17 Visualize the history of network learning: accuracy

plt.plot(history.history['accuracy'], label='The score of correct answers on the training set')
plt.plot(history.history['val_accuracy'], label='The score of correct answers on the val set')
plt.xlabel('Epoch')
plt.ylabel('Score correct answers')
plt.legend()
plt.show()
(Photo,GIF by Author) https://github.com/oleksandr-g-rock/flower_classification/blob/main/1_S1QPCbUn4-u4WM_MgHzZ8g.png

18 Visualize the history of network learning: loss

(Photo,GIF by Author) https://github.com/oleksandr-g-rock/flower_classification/blob/main/1_ijiB_P_e2sX_LB19huik4w.png
plt.plot(history.history['loss'], label='The score of loss on the training set')
plt.plot(history.history['val_loss'], label='The score of val_loss on the val set')
plt.xlabel('Epoch')
plt.ylabel('Score loss')
plt.legend()
plt.show()

###Fine tuning convolutional layers Inception V3###
19 Download the best weights and Defrost the last 2 blocks of Inception V3

model.load_weights("inceptionv3_best.h5")pretrained_model.trainable = False
for layer in model.layers[:290]:
layer.trainable = False
for layer in model.layers[290:]:
layer.trainable = True

20 Compile a network with defrosted layers. Then, start learning

model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
filepath="inceptionv3_fine_tuned.h5"
checkpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1, save_best_only=True, mode='min')
callbacks_list = [checkpoint, learning_rate_reduction]
steps_per_epoch = 32
history = model.fit_generator(
train_generator,
steps_per_epoch=steps_per_epoch,
validation_data=test_generator,
validation_steps=5,
callbacks=callbacks_list,
epochs=200,
verbose=2)

21 Again Visualize the history of network learning: accuracy and loss

plt.plot(history.history['accuracy'], label='The score of correct answers on the training set')
plt.plot(history.history['val_accuracy'], label='The score of correct answers on the val set')
plt.xlabel('Epoch')
plt.ylabel('Score correct answers')
plt.legend()
plt.show()
plt.plot(history.history['loss'], label='The score of loss on the training set')
plt.plot(history.history['val_loss'], label='The score of val_loss on the val set')
plt.xlabel('Epoch')
plt.ylabel('Score loss')
plt.legend()
plt.show()

###Testing of the model and download of the best weights###
Congratulations!
You have just created your first model. Now we will evaluate the quality of its work.

22 Load the best model

model = tensorflow.keras.models.load_model(‘/content/inceptionv3_fine_tuned.h5’)

23 Upload a random photo from the internet with flowers and prepare it for our model

!wget https://upload.wikimedia.org/wikipedia/commons/thumb/a/a3/Iglesia_de_Nuestra_Se%C3%B1ora_de_La_Blanca%2C_Cardej%C3%B3n%2C_Espa%C3%B1a%2C_2012-09-01%2C_DD_02_cropped.JPG/2880px-Iglesia_de_Nuestra_Se%C3%B1ora_de_La_Blanca%2C_Cardej%C3%B3n%2C_Espa%C3%B1a%2C_2012-09-01%2C_DD_02_cropped.JPGimg_path = '/content/2880px-Iglesia_de_Nuestra_Señora_de_La_Blanca,_Cardejón,_España,_2012-09-01,_DD_02_cropped.JPG'img = image.load_img(img_path, target_size=(image_size, image_size))
plt.imshow(img)
plt.show()
x = image.img_to_array(img)
x /= 255
x = np.expand_dims(x, axis=0)

24 Prediction

prediction = model.predict(x)predictionclasses = np.argmax(prediction, axis = 1)print(classes)

25 Show Result
‘sunflower’: 3

Result:

We created image classification for 5 classes with the best result.

--

--

Alex G.

ML DevOps engineer. 🙂 I am always open to new opportunities and offers. 🖖 I trying to help the world 🌏 with machine learning.