InceptionV3 — Transfer Learning / Conceito básico na prática

Francke Peixoto
6 min readJul 19, 2020

--

Transfer Learning (TL)

È transferir o conhecimento de um modelo para resolver outros problemas, ou seja, usamos modelos pré-treinados como ponto de partida na resolução de novos problemas.

“Transfer learning (TL) is a research problem in machine learning (ML) that focuses on storing knowledge gained while solving one problem and applying it to a different but related problem.[1]
For example, knowledge gained while learning to recognize cars could apply when trying to recognize trucks.
This area of research bears some relation to the long history of psychological literature on transfer of learning, although formal ties between the two fields are limited.”
wikipedia

Inception v3 Model

È um modelo convolucional com 48 camadas de profundidade. Esse modelo é um dos mais famosos para o uso de transferencia de aprendizado.

“Inceptionv3[1] is a convolutional neural network for assisting in image analysis and object detection, and got its start as a module for Googlenet. It is the third edition of Google’s Inception Convolutional Neural Network, originally introduced during the ImageNet Recognition Challenge. Just as ImageNet can be thought of as a database of classified visual objects, Inception helps classification of objects[2] in the world of computer vision.” — wikipedia

Setup

In [1]:

!unzip -q   /kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip -d .
!unzip -q /kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip -d .

In [2]:

import tensorflow as tf
from tensorflow import keras
from keras.preprocessing.image import load_img,img_to_array
import numpy as np
import os
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
import time
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
import shutil
from keras.preprocessing.image import ImageDataGenerator
for dirname, _, filenames in os.walk('/kaggle/input'):
for filename in filenames:
print(os.path.join(dirname, filename))
print("GPU is {}".format(tf.config.list_physical_devices('GPU')))
print("tensorflow version {}".format(tf.__version__))
print(os.listdir("./"))!nvidia-smikeras.backend.clear_session()Using TensorFlow backend./kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip
/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip
/kaggle/input/dogs-vs-cats-redux-kernels-edition/sample_submission.csv
GPU is [PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
tensorflow version 2.1.0
['__notebook__.ipynb', 'test', 'train']
Fri Jun 5 11:14:24 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.67 Driver Version: 418.67 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla P100-PCIE... Off | 00000000:00:04.0 Off | 0 |
| N/A 40C P0 32W / 250W | 10MiB / 16280MiB | 0% Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+

Data Pre-processing and Visualization

In [3]:

def show_cats_and_dogs(show="",width=150,height=150, images_path ='./train/'):
cols = 25
limit = 100
index = 0
images = list()
vertical_images=[]

for path in os.listdir(images_path):
if show != "" and (show in path)==False:
continue
index=index+1
if index%limit==0:
break
#keras.preprocessing.image
image = load_img(images_path+path, target_size=(width,height))
image= img_to_array(image) #to numpy
image_height, image_width, image_channel = image.shape
horizontal_side = np.ones((image_height, 5, image_channel), dtype=np.float32)*255

images.append(image)
images.append(horizontal_side)
if index%cols==0:
horizontal_image = np.hstack((images))
image_height, image_width, image_channel = horizontal_image.shape
vertical_side = np.ones((5, image_width, image_channel), dtype=np.float32)*255
vertical_images.append(horizontal_image)
vertical_images.append(vertical_side)
images=list()
gallery=np.vstack((vertical_images))
plt.figure(figsize=(12,12))
plt.xticks([])
plt.yticks([])
title={"":"cães & gatos",
"cat": "gatos",
"dog": "cães"}
plt.title("{} imagens de {} [ path {} ] .".format(limit, title[show],images_path))
plt.imshow(gallery.astype(np.uint8))

In [4]:

# raw Dataset
print("O dataset possui {} imagens de gatos e cães para classificação.".format(len(os.listdir("./train"))))
print("O dataset de teste possui {}.".format(len(os.listdir("./test"))))
O dataset possui 25000 imagens de gatos e cães para classificação.
O dataset de teste possui 12500.

Gatos

In [5]:

show_cats_and_dogs(show='cat')

Cães

In [6]:

show_cats_and_dogs(show='dog')

Ambos

In [7]:

show_cats_and_dogs(show='')

Test

In [8]:

show_cats_and_dogs(images_path='./test/')

Pre-processing

In [9]:

image_width,image_height = 150,150#299,299
labels =['dog','cat']
for d in labels:
dir_path = './train/' + d
if not os.path.exists(dir_path):
print('{} criado.'.format(dir_path))
os.mkdir(dir_path)
else:
print('{} já existe.'.format(dir_path))
train_path ="./train/"
for file in os.listdir(train_path):
category = file.split(".")[0]
if '.jpg' in file:
if 'dog'in category:
shutil.copyfile(train_path+file,'./train/dog/'+ file)
elif 'cat'in category:
shutil.copyfile(train_path+file,'./train/cat/'+ file)
./train/dog criado.
./train/cat criado.

In [10]:

print("Total de cães:\t{}".format(sum([len(files) for r, d, files in os.walk('./train/dog/')])))
print("Total de gatos:\t{}".format(sum([len(files) for r, d, files in os.walk('./train/cat/')])))
Total de cães: 12500
Total de gatos: 12500

In [11]:

keras.backend.clear_session()
batch_size=64
validation_split=0.3
val_size = 7500
dataset_size = 17500
train_data_generator = ImageDataGenerator(rescale=1./255, horizontal_flip=True, validation_split=validation_split)
train_datagenerator = train_data_generator.flow_from_directory(train_path,
target_size=(image_width,image_height ),
class_mode="categorical",
batch_size=batch_size,
shuffle=True,
subset='training')
val_datagenerator = train_data_generator.flow_from_directory(train_path,
target_size=(image_width,image_height),
class_mode="categorical",
shuffle=True,
batch_size=batch_size,
subset='validation')
Found 17500 images belonging to 2 classes.
Found 7500 images belonging to 2 classes.

InceptionV3 — Using

Com seu peso pré-treinado.

In [12]:

inception_v3_model = keras.applications.InceptionV3(include_top=False, weights='imagenet',input_shape=(image_width,image_height,3))Downloading data from https://github.com/fchollet/deep-learning-models/releases/download/v0.5/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5
87916544/87910968 [==============================] - 2s 0us/step

In [13]:

keras.backend.clear_session()
x = inception_v3_model.output
avg_pool2d = keras.layers.GlobalAveragePooling2D()(x)
dense = keras.layers.Dense(512, activation= keras.activations.relu)(avg_pool2d)
output = keras.layers.Dense(2,activation=keras.activations.softmax)(dense)
model = keras.Model(inputs=inception_v3_model.input, outputs=output,name = "transfer_inception_v3")

Fine tune

In [14]:

freeze= np.round((len(model.layers)-len(model.layers)*0.3),0).astype('int') 
for layer in model.layers[:freeze]:
layer.trainable =False
for layer in model.layers[freeze:]:
layer.trainable=True
model.summary()
Model: "transfer_inception_v3"
______________________________
========
Total params: 22,852,898
Trainable params: 13,862,786
Non-trainable params: 8,990,112
_______________________________
plateau_callback = keras.callbacks.ReduceLROnPlateau(monitor='val_accuracy', patience=3, verbose=2, factor=.5, min_lr=.00001)

start = time.time()

model.compile(loss=keras.losses.BinaryCrossentropy(from_logits=True),
optimizer=keras.optimizers.RMSprop(lr=0.0005, decay = 1e-6, momentum = 0.9),
metrics=['accuracy'])

history = model.fit(train_datagenerator,
steps_per_epoch=(dataset_size//batch_size),
epochs= 5,
verbose=1,
validation_data=val_datagenerator,
validation_steps=(val_size//batch_size),
callbacks=[plateau_callback]
)


print("training: ",time.time()-start)
Train for 273 steps, validate for 117 steps
Epoch 1/5
273/273 [==============================] - 175s 642ms/step - loss: 0.5677 - accuracy: 0.8697 - val_loss: 0.5634 - val_accuracy: 0.8791
Epoch 2/5
273/273 [==============================] - 164s 601ms/step - loss: 0.5504 - accuracy: 0.9050 - val_loss: 0.5578 - val_accuracy: 0.8896
Epoch 3/5
273/273 [==============================] - 168s 614ms/step - loss: 0.5480 - accuracy: 0.9101 - val_loss: 0.5335 - val_accuracy: 0.9391
Epoch 4/5
273/273 [==============================] - 169s 618ms/step - loss: 0.5484 - accuracy: 0.9097 - val_loss: 0.5285 - val_accuracy: 0.9494
Epoch 5/5
273/273 [==============================] - 169s 620ms/step - loss: 0.5422 - accuracy: 0.9219 - val_loss: 0.5309 - val_accuracy: 0.9443
training: 846.1809797286987

In [17]:

print("Train Accuracy:{:.3f}".format(history.history['accuracy'][-1]))
print("Val Accuracy:{:.3f}".format(history.history['val_accuracy'][-1]))
print('')
print("Train Loss:{:.3f}".format(history.history['loss'][-1]))
print("Val Loss:{:.3f}".format(history.history['val_loss'][-1]))
Train Accuracy:0.922
Val Accuracy:0.944

Train Loss:0.542
Val Loss:0.531

In [18]:

score = model.evaluate_generator(val_datagenerator,verbose=1)
print('Val loss: ', score[0])
print('Val accuracy', score[1])
118/118 [==============================] - 51s 428ms/step - loss: 0.5315 - accuracy: 0.9427
Val loss: 0.5314714459039397
Val accuracy 0.94266665

Accuracy

In [19]:

epochs = list(range(1,len(history.history['accuracy'])+1))
epochs
plt.plot(epochs, history.history['accuracy'],epochs,history.history['val_accuracy'])
plt.legend(('Training','Validation'))
plt.show()

Loss

In [20]:

epochs = list(range(1,len(history.history['loss'])+1))
epochs
plt.plot(epochs, history.history['loss'],epochs,history.history['val_loss'])
plt.legend(('Training','Validation'))
plt.show()

In [21]:

test_path ="./test/"
if not os.path.exists("./test"):
os.mkdir("./test")
print('./test criado.')

dir_path = "./test/data"
if not os.path.exists(dir_path):
print('{} criado.'.format(dir_path))
os.mkdir(dir_path)
else:
print('{} já existe.'.format(dir_path))
for file in os.listdir(test_path):
if '.jpg' in file:
shutil.copyfile(test_path+file,dir_path+'/'+file)

print("Total de gatos:\t{}".format(sum([len(files) for r, d, files in os.walk(dir_path+'/')])))

test_path = dir_path+'/'
test_data_generator = ImageDataGenerator(rescale=1./255)

test_generator = test_data_generator.flow_from_directory(directory ='./test',
target_size=(image_width,image_height),
batch_size=batch_size,
class_mode=None,shuffle=False)
./test/data criado.
Total de gatos: 12500
Found 12500 images belonging to 1 classes.

In [22]:

predict = model.predict(test_generator,verbose=1)196/196 [==============================] - 86s 439ms/step

In [23]:

index = 56
path= test_generator.filenames[index]
plt.figure(figsize=(4, 4))
img=load_img('./test/'+path, target_size=(image_width,image_height))
plt.imshow(img)
if (predict[index,1]) >= 1.:
label='Dog'
else:
label='Cat'
plt.title("Class: {}".format(label))
plt.show()

Notebook

Referencies

--

--

Francke Peixoto
Francke Peixoto

Written by Francke Peixoto

Software Engineer | Data Engineer | Data & Analytics Enthusiastic | Machine Learning | Azure | Fullstack Developer | Systems Analist | .Net — Acta, non verba