Object detection on Satellite Imagery using RetinaNet (Part 1) — Training

Source: Deep Learning on Medium

2. Loading and preparing training data

As already mentioned, using a Google Colab Jupyter Notebook which has everything pre-installed means you can pretty much start working straight away. Just make sure you are using Keras version 2.3.1 for this tutorial.

To start off, I clone the Github repository of Fizyr’s popular implementation of RetinatNet.

import osrepo_url = 'https://github.com/fizyr/keras-retinanet'
repo_dir_path = os.path.abspath(os.path.join('.', os.path.basename(repo_url)))
# clone git repository
!git clone {repo_url}

The dataset is downloaded from Kaggle using the Kaggle API (use after you’ve installed it) — pretty straight forward (remember to insert your personal kaggle username and kaggle key):

# import osos.environ['KAGGLE_USERNAME'] = "YOUR_USERNAME"
os.environ['KAGGLE_KEY'] = "YOUR_KAGGLE_KEY"
!kaggle datasets download kbhartiya83/swimming-pool-and-car-detection -p /content/data --unzip

Next, I prepare the data such that it can be fed directly into the training step. For this exercise, I first select a random sample of 800 images to quickly get an idea of how well I can expect the algorithm to do on this task. Feel free to use the full dataset, but bear in mind computational and time implications.

# select subsample of N for initial training
# import os
import random
from shutil import copyfile
# determine number for the sample
NUM = 800
# create directory for the sample
base_dir = os.getcwd()
sub_dir = base_dir + '/images_subset/'
!mkdir {sub_dir}
image_dir = base_dir + '/data/training_data/training_data/images/'
image_paths = os.listdir(image_dir)
# randomly select subsample
random_NUM = random.sample(image_paths, NUM)
# copy subsample into subsample directory
for i in random_NUM:
copyfile(image_dir + i, sub_dir + i )

I then proceed to splitting the dataset into train and test sets and generate the train.csv, test.csv and classes.csv files required for model training. I start by constructing an argument parser and creating variables from the arguments.

Argument parser

The next bit of code defines our train and test sets by creating two respective lists of image paths:

Train and test split

Now I can create the actual train and test sets by extracting annotation data, i.e. the object’s class and its bounding box coordinates, from the XML annotation files according to the training and test image path lists. There is one XML file per image, meaning each file can contain several object tags (one for each annotation).

Generate train, test and classes files for training

After combining the three preceding code snippets into a build_dataset.py file, it can be easily run as follows:

!python /content/ije_retinanet/build_dataset.py \
-l /content/data/training_data/training_data/labels/ \
-i /content/images_subset/ \
-r /content/images_subset/train.csv \
-e /content/images_subset/test.csv \
-c /content/images_subset/classes.csv

With 800 images and a 80–20 split, the output should look something like this:

[INFO] creating 'train' set ... 
[INFO] 640 total images in 'train'
[INFO] writing train annotations ...
[INFO] total 2827 annotations
[INFO] train.csv completed
[INFO] creating 'test' set ...
[INFO] 160 total images in 'test'
[INFO] writing test annotations ...
[INFO] total 604 annotations
[INFO] test.csv completed
[INFO] writing classes ...
[INFO] classes.csv completed
[FINAL] Task completed!

Lastly, I download a pre-trained model for transfer learning. I use ResNet50, one of the classical pre-trained models trained on the ImageNet dataset.

import urllib.request# path where pre-trained weights should be saved
PRETRAINED_MODEL = '/content/keras-retinanet/snapshots/resnet50_coco_best_v2.1.0.h5'
# model url
URL_MODEL = 'https://github.com/fizyr/keras-retinanet/releases/download/0.5.1/resnet50_coco_best_v2.1.0.h5'
# retrieve model from model url and save
urllib.request.urlretrieve(URL_MODEL, PRETRAINED_MODEL)