In [1]:
%matplotlib inline

import tensorflow as tf
from keras.backend.tensorflow_backend import set_session, get_session
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.9
config.gpu_options.allow_growth = True
set_session(tf.Session(config=config))

import sys
sys.path.append('/mnt/raid/cheetahs/modules/')

from inception.inception_resnet_v2 import InceptionResNetV2, preprocess_input
from keras.preprocessing.image import ImageDataGenerator
from keras.layers import Dense, Dropout, Input, concatenate
from keras.models import Model
from keras.optimizers import Nadam
from scipy.ndimage.interpolation import rotate
from sklearn.metrics import precision_recall_curve, classification_report, accuracy_score, confusion_matrix
import pandas as pd
import numpy as np
import itertools
import matplotlib.pyplot as plt
Using TensorFlow backend.
In [2]:
# Monkey-patch keras DirectoryIterator to also return filename

import keras
from keras_util.util import DirectoryIteratorWithFname
keras.preprocessing.image.DirectoryIterator = DirectoryIteratorWithFname
In [3]:
# Config

data_path = '/mnt/raid/cheetahs/data/train/'
val_data_path = '/mnt/raid/cheetahs/data/val/'
batch_size = 32

Data loading

In [4]:
# Load and parse ImageNet class labels

classes = open('/mnt/raid/cheetahs/modules/imagenet_classes', 'r').readlines()

def strip(c):
    key, value = c.split(':')
    key = key.strip()
    key = key.split('{')[-1]
    value = value.split("'")[1].strip()
    return int(key), value

classes = dict([strip(c) for c in classes])
In [5]:
izw_classes = ('unknown', 'cheetah', 'leopard')
In [6]:
metadata = pd.read_hdf('/mnt/raid/cheetahs/modules/metadata.hdf5')
In [7]:
metadata.head()
Out[7]:
ambient_temp brightness contrast datetime event1 event2 filename hour label path ... sequence_max serial_no set sharpness event_key_simple sortkey timeoffset event_key duplicate new_path
13657 14 0 160 1494269790000000000 0 587 Leopard_000051.jpeg 18 leopard /mnt/raid/cheetahs/data/train/leopard/Leopard_... ... 3 H600HG01173547 train 32 H600HG01173547_2017_128_587 H600HG01173547_2017_128_5871494269790000000000 -9223372036854775808 H600HG01173547_2017_128_587 False /mnt/raid/cheetahs/data2/train/leopard/0_H600H...
14356 14 0 160 1494269791000000000 0 587 Leopard_000052.jpeg 18 leopard /mnt/raid/cheetahs/data/train/leopard/Leopard_... ... 3 H600HG01173547 train 32 H600HG01173547_2017_128_587 H600HG01173547_2017_128_5871494269791000000000 1000000000 H600HG01173547_2017_128_587 False /mnt/raid/cheetahs/data2/train/leopard/1_H600H...
14364 14 0 160 1494269792000000000 0 587 Leopard_000053.jpeg 18 leopard /mnt/raid/cheetahs/data/train/leopard/Leopard_... ... 3 H600HG01173547 train 32 H600HG01173547_2017_128_587 H600HG01173547_2017_128_5871494269792000000000 1000000000 H600HG01173547_2017_128_587 False /mnt/raid/cheetahs/data2/train/leopard/2_H600H...
14975 14 0 160 1494269794000000000 0 588 Leopard_000054.jpeg 18 leopard /mnt/raid/cheetahs/data/train/leopard/Leopard_... ... 3 H600HG01173547 train 32 H600HG01173547_2017_128_588 H600HG01173547_2017_128_5881494269794000000000 2000000000 H600HG01173547_2017_128_587 False /mnt/raid/cheetahs/data2/train/leopard/3_H600H...
13928 14 0 160 1494269795000000000 0 588 Leopard_000055.jpeg 18 leopard /mnt/raid/cheetahs/data/train/leopard/Leopard_... ... 3 H600HG01173547 train 32 H600HG01173547_2017_128_588 H600HG01173547_2017_128_5881494269795000000000 1000000000 H600HG01173547_2017_128_587 False /mnt/raid/cheetahs/data2/train/leopard/4_H600H...

5 rows × 22 columns

In [8]:
# Crop camera metainformation from images

def preprocess(data, rotate_range=None):
    for x, y, fns in data:
        batch_metadata = []
        for fname in fns:
            fname_splitted = fname.split('_')
            index = fname_splitted[0]
            rest = '_'.join(fname_splitted[1:]).split('.jpeg')[0]
            f_metadata = metadata.iloc[int(index)]
            batch_metadata.append((
                f_metadata.ambient_temp,
                f_metadata.hour))
            # optionally use metadata
        temperatures = np.array(batch_metadata).astype(np.float32)
        x = x[:, 10:-10, 10:-10, :]
        if rotate_range is not None:
            for idx in range(batch_size):
                x[idx] = rotate(x[idx], np.random.random() * rotate_range * 2 - rotate_range, 
                                mode='reflect', reshape=False).astype(np.int64)
        yield [preprocess_input(x), temperatures], y
In [9]:
# Augment train data with horizontal flips, scale to ImageNet input size

generator = ImageDataGenerator(horizontal_flip=True)
val_generator = ImageDataGenerator(horizontal_flip=False)

train_gen = preprocess(generator.flow_from_directory(
    data_path, 
    target_size=(299+20, 299+20),
    classes=izw_classes,
    batch_size=batch_size), rotate_range=10)

val_gen = preprocess(val_generator.flow_from_directory(
    val_data_path, 
    target_size=(299+20, 299+20),
    classes=izw_classes,
    batch_size=batch_size))
Found 17857 images belonging to 3 classes.
Found 1915 images belonging to 3 classes.
In [10]:
# Test data loader

plt.figure(figsize=(7, 7))
plt.imshow(1 - ((next(train_gen)[0][0][0] / 2) + .5) * 255, vmin=0, vmax=255)
Out[10]:
<matplotlib.image.AxesImage at 0x7f497c42bf98>

Test pretrained model

In [11]:
# Load pretrained model
#
# http://arxiv.org/abs/1602.07261
#
# Inception-v4, Inception-ResNet and the Impact of Residual Connections
# on Learning
#
# Christian Szegedy, Sergey Ioffe, Vincent Vanhoucke, Alex Alemi

model = InceptionResNetV2()
In [12]:
# Test pretrained model on IZW data

batch, true_labels = next(val_gen)
fig, axes = plt.subplots(16, 2, figsize=(14, (14 / 2) * 16))
for idx, (image, label, true_label) in enumerate(zip(batch[0], model.predict(batch[0]), true_labels)):
    r, c = divmod(idx, 2)
    axes[r, c].imshow(1 - ((image / 2) + .5) * 255, vmin=0, vmax=255)
    axes[r, c].set_title('P: {} ({:.1f}%) - L: {}'.format(
        classes[label.argmax()],
        label[label.argmax()] * 100,
        izw_classes[true_label.argmax()]))
    axes[r, c].grid('off')
    axes[r, c].set_axis_off()