By following the fast.ai course - Lesson 1, I could have the chance to run a fast.ai deep learning classification model classifying birds and forests from 00-is-it-a-bird-creating-a-model-from-your-own-data.ipynb. The steps to implement this model were provided to us for research and learning as follows:

  1. Use DuckDuckGo to search for images of “bird photos”
  2. Use DuckDuckGo to search for images of “forest photos”
  3. Fine-tune a pretrained neural network to recognise these two groups
  4. Try running this model on a picture of a bird and see if it works.

I would like to comment on some of the key point I discovered at here.


To implement Step 1 and Step 2, it was expected to use DuckDuckGo’s API to search the URL. Thus, I could find that the author has written a search_images() function to search the special URL for each image searched. This function used the library from duckduckgo_search to import the ddg_images module, but I needed to install the duckduckgo_search library since I never use it before.

# Skip this cell if you already have duckduckgo_search installed
!pip install -Uqq duckduckgo_search

from duckduckgo_search import ddg_images
from fastcore.all import *

def search_images(term, max_images=200): return L(ddg_images(term, max_results=max_images)).itemgot('image')

After the image’s URL was searched by this function, ran another cell in the notebook to download the image. I tried the single demo of this download cell to download a bird’s photo or image from the URL. And it could download the image I wanted. So I would like to mark down the cell that was used to download at least 200 examples of each of the “bird” and “forest” photos. Also, each group of photos was saved to a different folder. Thus, Step 1 and Step 2 could be done very easily.

searches = 'forest','bird'
path = Path('bird_or_not')
from time import sleep

for o in searches:
    dest = (path/o)
    dest.mkdir(exist_ok=True, parents=True)
    download_images(dest, urls=search_images(f'{o} photo'))
    sleep(10)  # Pause between searches to avoid over-loading server
    download_images(dest, urls=search_images(f'{o} sun photo'))
    sleep(10)
    download_images(dest, urls=search_images(f'{o} shade photo'))
    sleep(10)
    resize_images(path/o, max_size=400, dest=path/o)

The author described an object called DataLoaders. This object could set up a training and a validation set for subsequent model training and testing. And then, I could apply the images downloaded before to fast.ai’s DataBlock function to split and summarise the data before training.

dls = DataBlock(
    blocks=(ImageBlock, CategoryBlock), 
    get_items=get_image_files, 
    splitter=RandomSplitter(valid_pct=0.2, seed=42),
    get_y=parent_label,
    item_tfms=[Resize(192, method='squish')]
).dataloaders(path)

dls.show_batch(max_n=6)

The model was trained by applying vision_learner() function. After that, the author used a function called fine_tune to adopt the best practices for fine-tuning a pre-trained model automatically. In this case, the author didn’t apply any loss function to train the model, but I discover that there were a few build-in loss functions I could use from fast.ai loss function library.

learn = vision_learner(dls, resnet18, metrics=error_rate)
learn.fine_tune(3)

In the end, I ran the last cell that was about to check the performance of this classification model on the validation set. The author mentioned that the accuracy was 100% in this case.