-
Notifications
You must be signed in to change notification settings - Fork 0
/
Fine-tuned Google MobileNet V2 model for Mask or No Mask Prediction - (V1 224 x 224).py
355 lines (199 loc) · 11.3 KB
/
Fine-tuned Google MobileNet V2 model for Mask or No Mask Prediction - (V1 224 x 224).py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
#!/usr/bin/env python
# coding: utf-8
# # Importing the libraries
# In[1]:
import matplotlib.pyplot as plt
import numpy as np
import os
import tensorflow as tf
from tensorflow.keras.preprocessing import image_dataset_from_directory
# In[2]:
tf.__version__
# In[3]:
import os
print (os.getcwd())
print ('')
#Include the working directory path of the dataset folder
os.chdir('C:\\Users\\Ibrahim Hameem\\Desktop\\Machine Learning\\7. Neural Nets\\Convolutional Neural Network\\Project Face Mask\\Mask_dataset')
print (os.getcwd())
# # Image Preprocessing
# ## Uploading the Training Set
# In[4]:
Batch_size = 32
Img_size = (224,224)
train_dataset = image_dataset_from_directory('Training_dataset',
batch_size = Batch_size,
image_size = Img_size,
shuffle = True)
# ### Visualizing the some uploaded images
# In[5]:
class_names = train_dataset.class_names
plt.figure(figsize = (10,10))
for image, labels in train_dataset.take(1):
for i in range (0,16):
plt.subplot(4,4,i+1)
plt.imshow(image[i].numpy().astype('uint8'))
plt.title(class_names[labels[i]])
plt.axis("off")
# ## Uploading the Validation Set
# In[6]:
validation_dataset = image_dataset_from_directory('Testing_dataset',
batch_size = Batch_size,
image_size = Img_size,
shuffle = True)
# ### Creating a Test Set using the Validation set
# In[7]:
val_batches = tf.data.experimental.cardinality(validation_dataset)
test_dataset = validation_dataset.take(val_batches // 5)
validation_dataset = validation_dataset.skip(val_batches // 5)
print ('Number of Vaidation batches:%d' % tf.data.experimental.cardinality(validation_dataset))
print ('')
print ('Number of Test batches:%d' % tf.data.experimental.cardinality(test_dataset))
# ### Configure the data to improve performance
# In[8]:
AUTOTUNE = tf.data.experimental.AUTOTUNE
train_dataset = train_dataset.prefetch(buffer_size = AUTOTUNE)
validation_dataset = validation_dataset.prefetch(buffer_size = AUTOTUNE)
test_dataset = test_dataset.prefetch(buffer_size = AUTOTUNE)
# ### Creating the data augmentation instance
# In[9]:
data_augmentation = tf.keras.Sequential([tf.keras.layers.experimental.preprocessing.RandomFlip('horizontal_and_vertical'),
tf.keras.layers.experimental.preprocessing.RandomRotation(0.4),
tf.keras.layers.experimental.preprocessing.RandomZoom(0.1),
tf.keras.layers.experimental.preprocessing.RandomZoom(-0.7),
tf.keras.layers.experimental.preprocessing.RandomTranslation(0.1,0.1)])
# #### Visualizing an image subject to the above data augmentation procedures
# In[10]:
plt.figure(figsize=(10, 10))
for image,_ in train_dataset.take(1):#The "_" syntax represents the "i" syntax
first_image = image[0]
for i in range(9):
ax = plt.subplot(3, 3, i + 1)
augmented_image = data_augmentation(tf.expand_dims(first_image, 0))#We add a dummy dimension to account for batches
plt.imshow(augmented_image[0]/255)
plt.axis('off')
#By writing for image,_ in train_dataset.take(1), we are taking the ith instance from within train_dataset.take(1) and then
#taking image from within that instance
# ### Creating the Rescaling instance
# In a moment, you will download tf.keras.applications.MobileNetV2 for use as your base model. This model expects pixel vaues in [-1,1], but at this point, the pixel values in your images are in [0-255]. To rescale them, use the preprocessing method included with the model.
# In[11]:
rescale = tf.keras.layers.experimental.preprocessing.Rescaling(1./127.5, offset= -1)
# # Creating the base model from pre-trained Convnets
# MobileNet V2 model was developed at Google. This is pre-trained on the ImageNet dataset, a large dataset consisting of 1.4M images and 1000 classes. ImageNet is a research training dataset with a wide variety of categories like jackfruit and syringe. This base of knowledge will help us classify cats and dogs from our specific dataset.
# First, instantiate a MobileNet V2 model pre-loaded with weights trained on ImageNet. By specifying the include_top=False argument, you load a network that doesn't include the classification layers at the top, which is ideal for feature extraction
# In[12]:
# Create the base model from the pre-trained model MobileNet V2 (Google)
IMG_SHAPE = Img_size + (3,)
base_model = tf.keras.applications.MobileNetV2 (input_shape = IMG_SHAPE,
include_top = False,
weights = 'imagenet')
# Basically we have taken the Convolutional layers and its pre-trained weight leading upto the flattened later prior to the fully connected layers
# This feature extractor converts each 224x224x3 image into a 7x7x1280 block of features. Let's see what it does to an example batch of images:
# In[13]:
image_batch, label_batch = next(iter(train_dataset))
feature_batch = base_model(image_batch)
print(feature_batch.shape)
# ### Feature Extraction
# In this step, you will freeze most of the convolutional base created from the previous step. This is becuase the base model has been trained on the images on ImageNet, which does not include the images of humans with or without a mask. However all is not lost and we can still use the pre-trained MobileNet V2 to a large extent. This is becuase in most convolutional networks, the higher up a layer is, the more specialized it is. The first few layers learn very simple and generic features that generalize to almost all types of images. As you go higher up, the features are increasingly more specific to the dataset on which the model was trained. The goal of fine-tuning is to adapt these specialized features to work with the new dataset, rather than overwrite the generic learning
# Hence we will freeze the first 80 inital layers of the MobileNet V2 architecture and train the remanining layers, inluding the new layers added by us on top of the base_model
# In[14]:
base_model.trainable = True
# In[15]:
print("Number of layers in the base model: ", len(base_model.layers))
print ('')
fine_tune_at = 75
for layer in base_model.layers[:fine_tune_at]:
layer.trainable = False
# Many models contain tf.keras.layers.BatchNormalization layers. This layer is a special case and precautions should be taken in the context of fine-tuning, as shown later in this tutorial.
#
# When you set layer.trainable = False, the BatchNormalization layer will run in inference mode, and will not update its mean and variance statistics.
#
# When you unfreeze a model that contains BatchNormalization layers in order to do fine-tuning, you should keep the BatchNormalization layers in inference mode by passing training = False when calling the base model. Otherwise, the updates applied to the non-trainable weights will destroy what the model has learned.
# In[16]:
# Let's take a look at the base model architecture
base_model.summary()
# In order to generate predictions from the block of features, average over the spatial 5x5 spatial locations, using a tf.keras.layers.GlobalAveragePooling2D layer to convert the features to a single 1280-element vector per image - This is a feature of the MobileNet V2 architecture
# In[17]:
global_average_layer = tf.keras.layers.GlobalAveragePooling2D()
#Testing the above line of code on the feature batch created
feature_batch_average = global_average_layer(feature_batch)
print(feature_batch_average.shape)
# Apply a tf.keras.layers.Dense layer to convert these features into a single prediction per image. You don't need an activation function here because this prediction will be treated as a logit, or a raw prediction value. Positive numbers predict class 1, negative numbers predict class 0.
# In[18]:
#Flatten layer
Flatten_layer = tf.keras.layers.Flatten(name = 'flatten')
# The Dropout layer randomly sets input units to 0 with a frequency of rate at each step during training time, which helps prevent overfitting
# In[19]:
#Bulding a shell model that will be fitted on the dataset
inputs = tf.keras.Input(shape=(224, 224, 3))
x = data_augmentation(inputs)
x = rescale(x)
x = base_model(x, training=False)
x = global_average_layer(x)
x = Flatten_layer(x)
x = tf.keras.layers.Dense(units = 128, activation = 'relu')(x)
x = tf.keras.layers.Dropout(0.2)(x)
outputs = tf.keras.layers.Dense(1, activation = 'sigmoid')(x)
model = tf.keras.Model(inputs, outputs)
# ### Compile the model
# Compile the model before training it. Since there are two classes, use a binary cross-entropy loss with from_logits=True since the model provides a linear output.
# In[20]:
base_learning_rate = 0.0001/10
model.compile(optimizer = tf.keras.optimizers.Adam(lr = base_learning_rate),
loss = 'binary_crossentropy',
metrics = ['accuracy'])
# In[21]:
model.summary()
# We can see that the 2,040,065 parameters of the base model is trainable.
# # Train the model
# In[22]:
#Evaluating the half-baked model on the validation set prior to training it
loss0, accuracy0 = model.evaluate(validation_dataset)
# In[23]:
history = model.fit(x = train_dataset, validation_data = validation_dataset, epochs = 17)
#
#
# # Learning curves
# In[24]:
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
plt.figure(figsize=(8, 8))
plt.subplot(2, 1, 1)
plt.plot(acc, label='Training Accuracy', linewidth = 3, marker = 'o', ms = 5, color = 'navy')
plt.plot(val_acc, label='Validation Accuracy',linewidth = 3, marker = 'o', ms = 5, color = 'greenyellow')
plt.legend(loc='lower right')
plt.ylabel('Accuracy')
plt.ylim([min(plt.ylim()),1])
plt.title('Training and Validation Accuracy')
plt.subplot(2, 1, 2)
plt.plot(loss, label='Training Loss',linewidth = 3, marker = 'D', ms = 5, color = 'deepskyblue')
plt.plot(val_loss, label='Validation Loss',linewidth = 3, marker = 'D', ms = 5, color = 'hotpink')
plt.legend(loc='upper right')
plt.ylabel('Cross Entropy')
plt.ylim([0,1.0])
plt.title('Training and Validation Loss')
plt.xlabel('epoch')
plt.show()
# # Using the trained model to predict if an image is wearing a mask or not
# In[25]:
#Retrieve a batch of images from the test set
image_batch, label_batch = test_dataset.as_numpy_iterator().next()
#Make predictions on the batch of images
predictions = model.predict_on_batch(image_batch).flatten()
# Apply a sigmoid since our model returns logits
predictions = tf.where(predictions < 0.5, 0, 1)
print('Predictions:\n', predictions.numpy())
print('Labels:\n', label_batch)
print ('')
plt.figure(figsize=(20, 20))
for i in range(32):
ax = plt.subplot(8, 4, i + 1)
plt.imshow(image_batch[i].astype("uint8"))
plt.title(class_names[predictions[i]])
plt.axis("off")
# In[26]:
#Include the path to the folder where the trained model needs to be saved (This could be anywhere in your computer)
os.chdir('C:\\Users\\Ibrahim Hameem\\Desktop\\Machine Learning\\7. Neural Nets\\Convolutional Neural Network\\Project Face Mask')
model.save('mask_model_pre-trained_1.h5')