As of 2019, fast.ai supports 4 types of DL applications
- computer vision
- natural language text
- tabular data
- collaborative filtering
Fast.ai uses type hinting introduced in Python 3.5 quite heavily. Thus if you type
help(fastai.untar_data), you notice type hints.
- The image dimensions used here is 224. This is a convention.
- normalizing images means turning them to (mean 0, 1 SD). This is done prior to training
data.c-> gives number of classes.
data.classes-> gives the names of the classes.
- we use transfer learning. We pick a model that already knows something about images and tune it to our case study.
- download data into local directory
- import data files into a
data_bunch. This process automatically creates a validation set.
show_batchto see the classes and labels
- print the number of classes
- create a
ConvLearnerobject by passing the data bunch, specifying the model architecture and metrics to use to evaluate training stats
- Fit the model. You can use
fit_one_cyclemethods, but recommended is to use latter. Pass the epoch number (also called
- look at the results and if good, save by calling
- Validation - create an
ClassificationInterpretation.from_learner(learn). The learn object so far knows the data and the model used to train. Now its time to validate
- Find the biggest losses using
interp.plot_top_losses(9, figsize=(15,11)). You can also plot
interp.plot_confusion_matrix()to view the CF matrix. Fastai also has
interp.most_confused(min_val=2)which will return the top losses.
- Generally, when you call
fit_one_cycleit only trains the last or last few layers. To improve this better, you need to call
learn.unfreeze()to unfreeze the model.
Next, you repeat the
learn.fit_one_cycle(numepochs). Sometimes, the error goes up when doing this. This happens because you have a reckless learning rate which makes the model lose it original learning. We need to be more nuanced here.
Find the optimal learning rate: Now load the original model using
learn.load('stage-1'), then run
learn.lr_find()and find the highest learning rate that has the lowest loss.
With this new information retrain the model.
learn.unfreeze(); learn.fit_one_cycle(epochs=2, max_lr=slice(1e-6, 1e-4)). What the slice suggests is, train the initial layers at start value specified and last layer at the end value specified and interpolate for the rest of the layers. It is tradecraft to make the end learning rate about 10 times smaller than rate at which errors start to increase.
from fastai.vision import * from fastai.metrics import error_rate
Inside colab, importing fastai, automatically imports the
Help on function untar_data in module fastai.datasets: untar_data(url:str, fname:Union[pathlib.Path, str]=None, dest:Union[pathlib.Path, str]=None, data=True) -> pathlib.Path Download `url` to `fname` if it doesn't exist, and un-tgz to folder `dest`.
data = ImageDataBunch.from_name_re(path_img, fnames, pat, ds_tfms=get_transforms(), size=224, bs=bs ).normalize(imagenet_stats)
Which gives you an Image data bunch object.
Just calling out the object will reveal the number of training, test datasets
>>>data ImageDataBunch; Train: LabelList (5912 items) x: ImageList Image (3, 224, 224),Image (3, 224, 224),Image (3, 224, 224),Image (3, 224, 224),Image (3, 224, 224) y: CategoryList samoyed,newfoundland,american_bulldog,american_pit_bull_terrier,saint_bernard Path: /content/data/oxford-iiit-pet/images; Valid: LabelList (1478 items) x: ImageList Image (3, 224, 224),Image (3, 224, 224),Image (3, 224, 224),Image (3, 224, 224),Image (3, 224, 224) y: CategoryList basset_hound,Persian,wheaten_terrier,shiba_inu,keeshond Path: /content/data/oxford-iiit-pet/images; Test: None
You can query just the validation data set as below:
>>> data.valid_ds.x ImageList (1478 items) Image (3, 333, 500),Image (3, 333, 500),Image (3, 500, 333),Image (3, 500, 375),Image (3, 375, 500) Path: /content/data/oxford-iiit-pet/images
To visually see a sample of the training data, use
To get the list of data classes present in the training data, use
>>> print(data.classes) len(data.classes),data.c ['Abyssinian', 'Bengal', 'Birman', 'Bombay', 'British_Shorthair', 'Egyptian_Mau', 'Maine_Coon', 'Persian', 'Ragdoll', 'Russian_Blue', 'Siamese', 'Sphynx', 'american_bulldog', 'american_pit_bull_terrier', 'basset_hound', 'beagle', 'boxer', 'chihuahua', 'english_cocker_spaniel', 'english_setter', 'german_shorthaired', 'great_pyrenees', 'havanese', 'japanese_chin', 'keeshond', 'leonberger', 'miniature_pinscher', 'newfoundland', 'pomeranian', 'pug', 'saint_bernard', 'samoyed', 'scottish_terrier', 'shiba_inu', 'staffordshire_bull_terrier', 'wheaten_terrier', 'yorkshire_terrier'] (37, 37)
There are 2 concepts at a high level:
DataBunch: A general fastai concept for your data, and from there, there are subclasses for particular applications like
- Learner: A general concept for things that can learn to fit a model. From that, there are various subclasses to make things easier in particular, there is a convnet learner (something that will create a convolutional neural network for you).
The general syntax to instantiate a learner in fast ai is as below:
learn = cnn_learner(<DataBunch obj>, <models.model>, metrics=error_rate)
>>> learn = cnn_learner(data, models.resnet34, metrics=error_rate) >>> type(learn) fastai.basic_train.Learner
fast.ai comes with several models. If you do a
['BasicBlock', 'Darknet', 'DynamicUnet', 'ResLayer', 'ResNet', 'SqueezeNet', 'UnetBlock', 'WideResNet', 'XResNet', 'alexnet', 'darknet', 'densenet121', 'densenet161', 'densenet169', 'densenet201', 'resnet101', 'resnet152', 'resnet18', 'resnet34', 'resnet50', 'squeezenet1_0', 'squeezenet1_1', 'unet', 'vgg16_bn', 'vgg19_bn', 'wrn', 'wrn_22', 'xception', 'xresnet', 'xresnet101', 'xresnet152', 'xresnet18', 'xresnet34', 'xresnet50']
learner object created already is validated against a validation set. The
ImageDataBunch object already knows which is training and which is validation. Thus the
error_rate parameter seeks to minimize test error and thereby avoid overfitting.
To start with, use
resnet34 which is pretty capable for most problems.
Resnet34 is a CNN that is trained on over a million images of various categories. This already knows to differentiatie between a large number of classes seen in everyday life. Thus, resnet34 is a generalist.
Transfer learning is the process of taking a generalist neural net and training it to become a specialist. We train the restnet34 in lesson 1 to classify between
37 classes of cats and dogs.
Transfer learning allows you to train nets with
1/100th less time using
1/100 less data.
When it comes to training, it is always recommended to use
fit_one_cycle() rather than
fit() method. This is to avoid overfitting. Fit one cycle is based on a 2018 paper which changed the approach to image DL. The images are shown only once and the learner is expected to figure out the pattern. Thus:
which will run 4 times on the images. Each time it runs, it gets a bit better
Total time: 07:24 epoch train_loss valid_loss error_rate time 0 1.387328 0.305607 0.084574 01:50 1 0.550968 0.220240 0.080514 01:50 2 0.353485 0.186418 0.066306 01:52 3 0.258271 0.169682 0.060217 01:51 CPU times: user 1min 25s, sys: 41.1 s, total: 2min 6s Wall time: 7min 24s
4th time, we get an error rate of
94% accuracy. This is phenomenal accuracy in DL speak compared to the most sophisticated approch of 2012 which got around
Then we save the model using
This stores the model along with the training data used to create it. Note: This fast.ai model is based on the
restnet34 model which is about
84mb in size. The fast.ai model is
87mb in size, the thin layer of specialization is about
3mb in size now.
Since this is a classification problem, we use confusion matrix for accuracy assessment. We create a
ClassificationInterpretation object using the
Learner object created earlier
>>> interp = ClassificationInterpretation.from_learner(learn) >>> type(interp) fastai.train.ClassificationInterpretation
We can plot the top losses using the
plot_top_losses() method off the
Learner object. This plots the top ‘n’ classes where the classifier has least
interp.plot_top_losses(9, figsize=(15,11), heatmap=False)