<jupyter_start><jupyter_text>Introduction to the datasetThe Oxford-IIIT Pet Dataset is a 37 category pet dataset with roughly 200 images for each class created by the Visual Geometry Group at Oxford. The images have a large variations in scale, pose and lighting. All images have an associated ground truth annotation of breed, head ROI, and pixel level trimap segmentation. Here we will use the fastai library to train a model for multi-class classification of cat and dog breeds. Future kernels will look at bounding-box detection and image segmentation with the fastai library.This kernel was inspired by [lesson 1](https://github.com/fastai/course-v3/blob/master/nbs/dl1/lesson1-pets.ipynb) of the [2019 version of fast.ai Part 1](https://course.fast.ai)<jupyter_code>%reload_ext autoreload
%autoreload 2
%matplotlib inline<jupyter_output><empty_output><jupyter_text>Let's import all the necessary libraries. This is very easy with fastai, as the computer vision functionality is part of the `fastai.vision` module:<jupyter_code>from fastai.vision import *<jupyter_output><empty_output><jupyter_text>Looking at the data<jupyter_code>import os
cwd = os.getcwd()
print(cwd)
path_img = Path('../input/images/images')
fnames = get_image_files(path_img)
fnames[:5]<jupyter_output><empty_output><jupyter_text>We will use a regex expression to extract the labels of the images and load into the `ImageDataBunch` class, which is the class for inputting image data into the neural network for the fastai library.<jupyter_code>np.random.seed(2) #random seed for reproducibility
pat = r'/([^/]+)_\d+.jpg$' #regex expression
sz = 128
bs = 64
data = ImageDataBunch.from_name_re('.', fnames, pat, ds_tfms=get_transforms(), size=sz, bs=bs
                                  ).normalize(imagenet_stats)<jupyter_output><empty_output><jupyter_text>Note that we will resize the images to `sz=128` and load our data into the neural network with a batch size of `bs=64`. We use default transformations for image augmentation to improve training and generalization. Let's look at some sample data:<jupyter_code>data.show_batch(rows=3, figsize=(7,6))
print(data.classes)
len(data.classes),data.c<jupyter_output><empty_output><jupyter_text>We have 37 classes as we expected.  Training: Resnet50We will now start training a new model. We will take a convolutional neural network architecture (ResNet50) pretrained on the [ImageNet](http://www.image-net.org/) dataset, an add a new layer to output the predictions for our given dataset. We will then train this last layer. The idea behind this is that the ResNet50 trained on the ImageNet dataset already has learnt to identify important features and does not need to be retrained from scratch. So we only train the last layer for our particular task.<jupyter_code>from fastai.metrics import accuracy
learn = create_cnn(data, models.resnet50, metrics=accuracy)<jupyter_output><empty_output><jupyter_text>We will utilize the learning rate finder to find the optimal learning rate for training. The idea behind this is that we will train the network while increasing the learning rate, and observe how the loss decreases. We choose the learning rate for when the loss decreases the fastest.<jupyter_code>learn.lr_find()
learn.recorder.plot()<jupyter_output><empty_output><jupyter_text>We see that the optimal learning rate seems to be around `lr=1e-2` so that is what we will train the model with:<jupyter_code>learn.fit_one_cycle(4,max_lr=1e-2)
learn.save('stage-1')<jupyter_output><empty_output><jupyter_text>Fine-tuning We will now unfreeze the rest of the model and train the rest of the layers as well. We will use lower learning rate for the earlier layers of the model, since these layers are probably detecting simple features like lines or circles, and don't need to be adjusted much. However, the later layers are adjusted more, with higher learning rates. This technique is known as discriminative learning rates.We will first determine the optimal learning rate again.<jupyter_code>learn.unfreeze()
learn.lr_find()
learn.recorder.plot()
learn.fit_one_cycle(4, max_lr=slice(1e-6,1e-4))
learn.save('stage-2')<jupyter_output><empty_output><jupyter_text>This is a very accurate model!  Results/InterpretationFastai provides some nice tools for checking our results:<jupyter_code>interp = ClassificationInterpretation.from_learner(learn)
losses,idxs = interp.top_losses()
len(data.valid_ds)==len(losses)==len(idxs)<jupyter_output><empty_output><jupyter_text>We can plot and see which images the neural network was most confused by:<jupyter_code>interp.plot_top_losses(9, figsize=(15,11))<jupyter_output><empty_output><jupyter_text>We can also create a confusion matrix:<jupyter_code>interp.plot_confusion_matrix(figsize=(12,12), dpi=60)<jupyter_output><empty_output><jupyter_text>When having so many classes, it can be hard to interpret the confusion matrix. Fastai has the `interp.most_confused()` function to print out which classes the network was most confused by.<jupyter_code>interp.most_confused(min_val=2)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.07901477832512316, 'fraction_numerical': 0.012610837438423646, 'mean_word_length': 6.189801699716714, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 53, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '13', 'dir': 'jupyter-structured-clean-dedup', 'id': '586914', 'license': 'MIT', 'n_tokens_mistral': 1551, 'n_tokens_neox': 1480, 'n_words': 559, 'path': 'reference_kernels/Oxford-IIIT Pet Dataset Classification with Fastai.ipynb', 'repo_name': 'bmj-hackathon/ocean_cats_dogs_oxford', 'size': '5075'}