Font style recognition using fast.ai

Jupyter notebook for this exercise can be downloaded here:

Data bundle containing the font catalog used in this exercise is available for download here. The font catalog was generated using the code here.

We pick 6 font styles and try train the machine to differentiate between them: Lato-Hairline, Lato-HairlineItalic, Purisa, Purisa-Bold, Purisa-BoldOblique and Purisa-Oblique.

%matplotlib inline
from fastai import *
from fastai.vision import *
np.random.seed(77)
import glob
mypath = '/home/jupyter/tutorials/data/fontcatalog2'
fnames = glob.glob(f'{mypath}/Lato-Hairline') fnames.extend(glob.glob(f'{mypath}/Purisa'))
pat = r'([^\/]+)_\w.png'
sz = 175
tfms = get_transforms(do_flip=False)
data = ImageDataBunch.from_name_re(Path(mypath), fnames, pat, valid_pct=.2,
ds_tfms=tfms, size=sz).normalize(imagenet_stats)
data.show_batch(rows=3, figsize=(7,6))
print(data.classes)

We get:

['Lato-Hairline', 'Lato-HairlineItalic', 'Purisa', 'Purisa-Bold', 'Purisa-BoldOblique', 'Purisa-Oblique']
train, valid = [], []
count_train, count_valid, count_grand = 0, 0, 0
for i in range(len(data.train_ds)):
train.append(f'{data.train_ds.y[i]}'.split()[0])
for i in range(len(data.valid_ds)):
valid.append(f'{data.valid_ds.y[i]}'.split()[0])
train = np.asarray(train)
valid = np.asarray(valid)
print('{:>20s}{:>10s}{:>10s}{:>15s}'.format('category', 'train', 'valid', 'train+valid'))
for i in range(data.c):
count_train = len(np.where(train==data.classes[i])[0])
count_valid = len(np.where(valid==data.classes[i])[0])
print('{:>20s}{:>10d}{:>10d}{:>15d}'.format(data.classes[i], count_train, count_valid, count_train+count_valid))

We get:

            category     train     valid    train+valid
Lato-Hairline 49 12 61
Lato-HairlineItalic 52 9 61
Purisa 57 4 61
Purisa-Bold 42 19 61
Purisa-BoldOblique 49 12 61
Purisa-Oblique 44 17 61

learn = create_cnn(data, models.resnet50, metrics=error_rate)
learn.fit_one_cycle(1)

learn.unfreeze()
learn.lr_find()
learn.recorder.plot()

learn.fit_one_cycle(9, max_lr=slice(2e-4,3e-4))
interp = ClassificationInterpretation.from_learner(learn)
interp.plot_confusion_matrix(figsize=(5,5))
wrongs = 0
for t in interp.most_confused():
wrongs += t[2]
print(wrongs, 'wrong')

We get:

22 wrong
learn.fit_one_cycle(10, max_lr=slice(2e-4,3e-4))
interp = ClassificationInterpretation.from_learner(learn)
interp.plot_confusion_matrix(figsize=(5,5))
wrongs = 0
for t in interp.most_confused():
wrongs += t[2]
print(wrongs, 'wrong')

We get:

12 wrong
interp.plot_top_losses(9, figsize=(15,11))

Leave a Reply

Your email address will not be published. Required fields are marked *