FAU Monkey Face ID v1.00

In [1]:
%reload_ext autoreload
%autoreload 2
%matplotlib inline
In [2]:
from fastai.vision import *
from fastai.metrics import error_rate
from pathlib import Path
from fastai.widgets import *
In [3]:
bs = 64

Looking at the data

In [4]:
path = Path('/home/jupyter/monkey/monkey224');
In [5]:
path.ls()
Out[5]:
[PosixPath('/home/jupyter/monkey/monkey224/Fiona'),
 PosixPath('/home/jupyter/monkey/monkey224/King'),
 PosixPath('/home/jupyter/monkey/monkey224/Dove'),
 PosixPath('/home/jupyter/monkey/monkey224/Flower'),
 PosixPath('/home/jupyter/monkey/monkey224/Liza'),
 PosixPath('/home/jupyter/monkey/monkey224/Jinja'),
 PosixPath('/home/jupyter/monkey/monkey224/India')...]
In [6]:
path_img = path

Create an ImageDataBunch using the folder structure above.

Reserve 20% of the images randomly for validation.

In [7]:
data = ImageDataBunch.from_folder(path, valid_pct=0.2, ds_tfms=get_transforms(), size=224)
In [8]:
data.show_batch(rows=6, figsize=(24,24))
In [9]:
print(data.classes)
len(data.classes),data.c
['Addison', 'Banana', 'Bea', 'Best', 'Bora', 'Carson', 'Donda', 'Dove', 'Elsa', 'Figiri', 'Fiona', 'Flower', 'Gold', 'Happy', 'Hope', 'Ibuka', 'Ice', 'India', 'Ire', 'Jenny', 'Jib', 'Jinja', 'Joly', 'Juice', 'June', 'Kadi', 'Kau', 'Kenya', 'King', 'Krys', 'Likizo', 'Limao', 'Liza', 'Lucky', 'Mapera', 'Mercy', 'Msada', 'Okwi', 'Orange', 'Pices', 'Ramani', 'Rocket', 'Ruby', 'Savannah', 'Scarface', 'Supu', 'Tabu', 'Tamu', 'Tatu', 'Tisa', 'Twin', 'Uma', 'Venus', 'Vibe', 'Viola', 'Vumi', 'Wali', 'Zalia', 'Ziwa', 'Zoo', 'Zuri']
Out[9]:
(61, 61)

Training: resnet50

Train the model using resNet50 (more layers)

In [10]:
learn = cnn_learner(data, models.resnet50, metrics=error_rate)

Find and plot the learning rate.

In [18]:
learn.lr_find()
learn.recorder.plot()
LR Finder is complete, type {learner_name}.recorder.plot() to see the graph.

Observe the loss rate vs. Learning rate. This will be used when we unfreeze the model. Run it for 4 cycles.

In [19]:
learn.fit_one_cycle(4)
epoch train_loss valid_loss error_rate time
0 1.438101 0.708872 0.180749 02:13
1 0.507030 0.268920 0.072733 02:08
2 0.268352 0.155644 0.042402 02:08
3 0.169836 0.130789 0.034974 02:08

96.5% Accurate! Impressive, but we can do better.

In [4]:
# save or load the model
#learn.load('mf-stage-1-50')
#learn.save('mf-stage-1-50')

Unfreeze the model and then train it again, using a max learning rate determine when we plotted the data above.

In [14]:
learn.unfreeze()
learn.fit_one_cycle(3, max_lr=slice(1e-4,1e-2))
epoch train_loss valid_loss error_rate time
0 0.751920 0.884791 0.218199 02:59
1 0.200353 0.108024 0.036212 02:48
2 0.031403 0.021279 0.005571 02:48

After 3 more epochs, we are at an impressive 99.44% accuracy rate.

In [16]:
# Save stage 2
# learn.save('mf-stage-2-50');

Let's dive deeper into the Classifier to see what little it's confused about.

In [17]:
interp = ClassificationInterpretation.from_learner(learn)
In [18]:
interp.most_confused(min_val=2)
Out[18]:
[('Carson', 'Zalia', 2), ('Dove', 'Carson', 2), ('Jenny', 'Tisa', 2)]
In [19]:
losses,idxs = interp.top_losses()

len(data.valid_ds)==len(losses)==len(idxs)
Out[19]:
True
In [20]:
interp.plot_top_losses(9, figsize=(15,11))
In [21]:
interp.plot_confusion_matrix(figsize=(12,12), dpi=120)
In [22]:
# export the learning model for use on another computer. 
#learn.export();
In [14]:
# export the data model for use on another computer. 
#data.export()