Train sea lion classifier with hog + svm


In [1]:
INPUT_DIR = '../../input/kaggle-sea-lion/02/'
INPUT_DIR2 = '../../input/kaggle-sea-lion/Train/'
OUTPUT_DIR = '../../output/kaggle-sea-lion/04/'
# IMAGE_DIMS = (42,42,3)
#IMAGE_DIMS = (84,84,3)
#IMAGE_DIMS = (32,32,3)
IMAGE_DIMS = (50,50,3)

INPUT_DATASET_NAME = 'lion-patches-0px'

RECREATE_OUTPUT_DIR = False

OUTPUT_WEIGHT = (1,1,1,1,1,5)
INPUT_RANGE = 1

BATCH_SIZE=64

In [2]:
%matplotlib inline
import numpy as np
import pandas as pd
import h5py
import matplotlib.pyplot as plt
import sklearn
import os
import glob
import cv2
from sklearn import svm
from sklearn import datasets
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import LinearSVC
from sklearn.svm import SVC
import sklearn.metrics as metrics
import sklearn.cluster as cluster
import skimage
import random
import itertools
from modules.chog import CircularHOGExtractor

import keras
from keras.preprocessing.image import ImageDataGenerator
from keras import models

from modules.logging import logger
import modules.utils as utils
from modules.utils import Timer
import modules.logging
import modules.lions as lions
import modules.objectdetect as objectdetect


Using TensorFlow backend.

Prepare

Prepare output dir


In [3]:
utils.mkdirs(OUTPUT_DIR, dirs=['weights'], recreate=RECREATE_OUTPUT_DIR)
modules.logging.setup_file_logger(OUTPUT_DIR + 'out.log')
WEIGHTS_DIR = OUTPUT_DIR + 'weights/'
input_dataset_path = INPUT_DIR + utils.dataset_name(INPUT_DATASET_NAME, IMAGE_DIMS)

logger.info('Output dirs created')


2017-05-22 00:05:06,478 INFO Output dirs created

Prepare train, validate and test data flows


In [4]:
logger.info('Using dataset ' + input_dataset_path + ' as input')
h5file = h5py.File(input_dataset_path, 'r')

logger.info('Using dataset ' + input_dataset_path + ' as input')
h5file = h5py.File(input_dataset_path, 'r')

#used for image augmentation (creating new images for balancing)
image_augmentation_generator = ImageDataGenerator(
        featurewise_center=False,
        samplewise_center=False,
        featurewise_std_normalization=False,
        samplewise_std_normalization=False,
        zca_whitening=False,
        rotation_range=359,
        width_shift_range=0.1,
        height_shift_range=0.1,
        shear_range=0,
        horizontal_flip=True,
        vertical_flip=True)

image_randomize_generator = image_augmentation_generator

logger.info('preparing train data')
train_batch_generator = utils.BatchGeneratorXYH5(h5file, start_ratio=0, end_ratio=INPUT_RANGE)
train_balance_generator = utils.ClassBalancerGeneratorXY(train_batch_generator,
                                                         image_augmentation=image_augmentation_generator,
                                                         output_weight=OUTPUT_WEIGHT,
                                                         max_augmentation_ratio=5,
                                                         max_undersampling_ratio=1,
                                                         enforce_max_ratios=False,
                                                         batch_size=BATCH_SIZE,
                                                         start_ratio=0, end_ratio=0.7)
train_generator = utils.image_augmentation_xy(train_balance_generator.flow(), image_randomize_generator)
logger.info('train size=' + str(train_balance_generator.size) + ' batches=' + str(train_balance_generator.nr_batches))


logger.info('preparing valid data')
valid_batch_generator = utils.BatchGeneratorXYH5(h5file, start_ratio=0, end_ratio=INPUT_RANGE)
valid_balance_generator = utils.ClassBalancerGeneratorXY(valid_batch_generator,
                                                         image_augmentation=image_augmentation_generator,
                                                         output_weight=OUTPUT_WEIGHT,
                                                         max_augmentation_ratio=5,
                                                         max_undersampling_ratio=1,
                                                         enforce_max_ratios=False,
                                                         batch_size=BATCH_SIZE,
                                                         start_ratio=0.7, end_ratio=0.85)
logger.info('valid size=' + str(valid_balance_generator.size) + ' batches=' + str(valid_balance_generator.nr_batches))



logger.info('preparing test data')
test_batch_generator = utils.BatchGeneratorXYH5(h5file, start_ratio=0, end_ratio=INPUT_RANGE)
test_balance_generator = utils.ClassBalancerGeneratorXY(test_batch_generator,
                                                         image_augmentation=image_augmentation_generator,
                                                         output_weight=OUTPUT_WEIGHT,
                                                         max_augmentation_ratio=5,
                                                         max_undersampling_ratio=1,
                                                         enforce_max_ratios=False,
                                                         batch_size=BATCH_SIZE,
                                                         start_ratio=0.85, end_ratio=1)
logger.info('test size=' + str(test_balance_generator.size) + ' batches=' + str(test_balance_generator.nr_batches))


2017-05-22 00:05:06,504 INFO Using dataset ../../input/kaggle-sea-lion/02/lion-patches-0px-84-84.h5 as input
2017-05-22 00:05:06,512 INFO Using dataset ../../input/kaggle-sea-lion/02/lion-patches-0px-84-84.h5 as input
2017-05-22 00:05:06,516 INFO preparing train data
2017-05-22 00:05:06,519 INFO loading input data for class distribution analysis...
2017-05-22 00:05:06,521 INFO loading Y from raw dataset
2017-05-22 00:05:06,522 INFO > [started] generator dump...
2263/2263
2017-05-22 00:05:07,036 INFO > [done]    generator dump (513.388 ms)
2017-05-22 00:05:07,039 INFO raw sample class distribution
2017-05-22 00:05:07,041 INFO 0: 78
2017-05-22 00:05:07,043 INFO 1: 45
2017-05-22 00:05:07,045 INFO 2: 675
2017-05-22 00:05:07,047 INFO 3: 150
2017-05-22 00:05:07,049 INFO 4: 281
2017-05-22 00:05:07,051 INFO 5: 1034
2017-05-22 00:05:07,052 INFO overall output samples per class: 270
2017-05-22 00:05:07,054 INFO augmentation/undersampling ratio per class
2017-05-22 00:05:07,056 INFO SETUP FLOW 0 0.7
2017-05-22 00:05:07,058 INFO calculating source range according to start/end range of the desired output..
2017-05-22 00:05:07,059 INFO output distribution for this flow
2017-05-22 00:05:07,061 INFO 0: 189 (3.46)
2017-05-22 00:05:07,062 INFO 1: 189 (6.00)
2017-05-22 00:05:07,064 INFO 2: 189 (0.40)
2017-05-22 00:05:07,065 INFO 3: 189 (1.80)
2017-05-22 00:05:07,067 INFO 4: 189 (0.96)
2017-05-22 00:05:07,069 INFO 5: 944 (1.31)
2017-05-22 00:05:07,072 INFO source range: 0-1694 (1694)
2017-05-22 00:05:07,073 INFO output range: 0-1889 (1889)
2017-05-22 00:05:07,075 INFO train size=1889 batches=30
2017-05-22 00:05:07,076 INFO preparing valid data
2017-05-22 00:05:07,078 INFO loading input data for class distribution analysis...
2017-05-22 00:05:07,079 INFO loading Y from raw dataset
2017-05-22 00:05:07,080 INFO > [started] generator dump...
2263/2263
2017-05-22 00:05:07,471 INFO > [done]    generator dump (390.268 ms)
2017-05-22 00:05:07,473 INFO raw sample class distribution
2017-05-22 00:05:07,475 INFO 0: 78
2017-05-22 00:05:07,476 INFO 1: 45
2017-05-22 00:05:07,478 INFO 2: 675
2017-05-22 00:05:07,479 INFO 3: 150
2017-05-22 00:05:07,481 INFO 4: 281
2017-05-22 00:05:07,483 INFO 5: 1034
2017-05-22 00:05:07,484 INFO overall output samples per class: 270
2017-05-22 00:05:07,486 INFO augmentation/undersampling ratio per class
2017-05-22 00:05:07,488 INFO SETUP FLOW 0.7 0.85
2017-05-22 00:05:07,489 INFO calculating source range according to start/end range of the desired output..
2017-05-22 00:05:07,490 INFO output distribution for this flow
2017-05-22 00:05:07,492 INFO 0: 40 (3.46)
2017-05-22 00:05:07,494 INFO 1: 40 (6.00)
2017-05-22 00:05:07,495 INFO 2: 40 (0.40)
2017-05-22 00:05:07,497 INFO 3: 40 (1.80)
2017-05-22 00:05:07,499 INFO 4: 40 (0.96)
2017-05-22 00:05:07,501 INFO 5: 202 (1.31)
2017-05-22 00:05:07,505 INFO source range: 1721-1983 (262)
2017-05-22 00:05:07,506 INFO output range: 1890-2295 (405)
2017-05-22 00:05:07,508 INFO valid size=405 batches=7
2017-05-22 00:05:07,510 INFO preparing test data
2017-05-22 00:05:07,511 INFO loading input data for class distribution analysis...
2017-05-22 00:05:07,513 INFO loading Y from raw dataset
2017-05-22 00:05:07,514 INFO > [started] generator dump...
2263/2263
2017-05-22 00:05:07,902 INFO > [done]    generator dump (387.659 ms)
2017-05-22 00:05:07,904 INFO raw sample class distribution
2017-05-22 00:05:07,906 INFO 0: 78
2017-05-22 00:05:07,907 INFO 1: 45
2017-05-22 00:05:07,908 INFO 2: 675
2017-05-22 00:05:07,910 INFO 3: 150
2017-05-22 00:05:07,911 INFO 4: 281
2017-05-22 00:05:07,912 INFO 5: 1034
2017-05-22 00:05:07,914 INFO overall output samples per class: 270
2017-05-22 00:05:07,915 INFO augmentation/undersampling ratio per class
2017-05-22 00:05:07,917 INFO SETUP FLOW 0.85 1
2017-05-22 00:05:07,918 INFO calculating source range according to start/end range of the desired output..
2017-05-22 00:05:07,919 INFO output distribution for this flow
2017-05-22 00:05:07,921 INFO 0: 40 (3.46)
2017-05-22 00:05:07,922 INFO 1: 40 (6.00)
2017-05-22 00:05:07,924 INFO 2: 40 (0.40)
2017-05-22 00:05:07,925 INFO 3: 40 (1.80)
2017-05-22 00:05:07,926 INFO 4: 40 (0.96)
2017-05-22 00:05:07,927 INFO 5: 202 (1.31)
2017-05-22 00:05:07,930 INFO source range: 1971-2262 (291)
2017-05-22 00:05:07,932 INFO output range: 2295-2700 (405)
2017-05-22 00:05:07,933 INFO test size=405 batches=7

Dump train, validation and test data


In [5]:
logger.info('Loading train/valid data...')

def validate_sample(x,y):
    #remove images with too much zeroed pixels
    hist = cv2.calcHist([cv2.cvtColor(x,cv2.COLOR_BGR2GRAY).astype('u1')],[0],None,[256],[0,256])
    return (hist[0][0]<200)

X_train, Y_train = utils.dump_xy_to_array(train_generator, train_balance_generator.size, x=True, y=True, filter_function=validate_sample)
X_valid, Y_valid = utils.dump_xy_to_array(valid_balance_generator.flow(), valid_balance_generator.size, x=True, y=True, filter_function=validate_sample)
X_test, Y_test = utils.dump_xy_to_array(test_balance_generator.flow(), test_balance_generator.size, x=True, y=True, filter_function=validate_sample)

Y_train = utils.onehot_to_label(Y_train)
Y_valid = utils.onehot_to_label(Y_valid)
Y_test = utils.onehot_to_label(Y_test)

print(X_train.shape)
print(Y_train.shape)

test_img = cv2.cvtColor(X_train[0],cv2.COLOR_BGR2GRAY).astype('u1')
test_img2 = cv2.cvtColor(X_train[1],cv2.COLOR_BGR2GRAY).astype('u1')


2017-05-22 00:05:07,948 INFO Loading train/valid data...
2017-05-22 00:05:07,950 INFO > [started] generator dump...
2017-05-22 00:05:07,952 INFO starting new flow...
1920/1889
2017-05-22 00:05:12,389 INFO > [done]    generator dump (4439.195 ms)
2017-05-22 00:05:12,390 INFO > [started] generator dump...
2017-05-22 00:05:12,393 INFO starting new flow...
448/405
2017-05-22 00:05:12,717 INFO > [done]    generator dump (326.721 ms)
2017-05-22 00:05:12,719 INFO > [started] generator dump...
2017-05-22 00:05:12,720 INFO starting new flow...
448/405
2017-05-22 00:05:13,033 INFO > [done]    generator dump (314.000 ms)
(1889, 84, 84, 3)
(1889,)

Circular HOG approach

Extract Circular HOG Features


In [6]:
logger.info('Extracting chog for train...')
ch = CircularHOGExtractor()
X_chog_train = np.array([ch.extract(cv2.cvtColor(im,cv2.COLOR_BGR2GRAY).astype('u1')) for im in X_train])
logger.info('Extracting chog for validation...')
X_chog_valid = np.array([ch.extract(cv2.cvtColor(im,cv2.COLOR_BGR2GRAY).astype('u1')) for im in X_valid])
logger.info('Extracting chog for test...')
X_chog_test = np.array([ch.extract(cv2.cvtColor(im,cv2.COLOR_BGR2GRAY).astype('u1')) for im in X_test])
logger.info('done')


2017-05-22 00:05:13,042 INFO Extracting chog for train...
2017-05-22 00:05:26,673 INFO Extracting chog for validation...
2017-05-22 00:05:29,469 INFO Extracting chog for test...
2017-05-22 00:05:32,266 INFO done

Train SVM over Circular HOG Features


In [7]:
#BATCH_SIZE = 10
#for batch in range(round(train_balance_generator.size/BATCH_SIZE)):
#    logger.info('Batch ' + str(batch) + '...')
#    X_train, Y_train = utils.dump_xy_to_array(train_generator, BATCH_SIZE, x=True, y=True)

#X = utils.extract_hogs(X_train)
#Y_true = utils.onehot_to_label(Y_train)
#Y_true = np.array([l if l==5 else 0 for l in Y_true])

logger.info('Training SVM...')
#ovr = OneVsRestClassifier(LinearSVC(random_state=0))
ovr = OneVsRestClassifier(SVC(probability=True))

#train just on two classes: 1-lion or 0-non-lion
Y_train_2 = np.array([0 if x==5 else 1 for x in Y_train])
Y_valid_2 = np.array([0 if x==5 else 1 for x in Y_valid])
Y_test_2 = np.array([0 if x==5 else 1 for x in Y_test])

svm_model = ovr.fit(X_chog_train, Y_train_2)

Y_train_pred = svm_model.predict(X_chog_train)
acc = metrics.accuracy_score(Y_train_2, Y_train_pred)
logger.info('Train accuracy: ' + str(acc))

Y_valid_pred = svm_model.predict(X_chog_valid)
acc = metrics.accuracy_score(Y_valid_2, Y_valid_pred)
logger.info('Validation accuracy: ' + str(acc))

Y_test_pred = svm_model.predict(X_chog_test)
Y_test_prob = svm_model.predict_proba(X_chog_test)
acc = metrics.accuracy_score(Y_test_2, Y_test_pred)
logger.info('Test accuracy: ' + str(acc))

logger.debug("Done")

utils.evaluate_predictions(Y_valid_2, Y_valid_pred)


2017-05-22 00:05:32,287 INFO Training SVM...
2017-05-22 00:05:35,431 INFO Train accuracy: 0.877183695077
2017-05-22 00:05:35,535 INFO Validation accuracy: 0.723456790123
2017-05-22 00:05:35,731 INFO Test accuracy: 0.674074074074
2017-05-22 00:05:35,733 INFO Accuracy: 0.723456790123
2017-05-22 00:05:35,736 INFO Number of test samples: 405
2017-05-22 00:05:35,738 INFO Kappa score: 0.395973154362 (-1 bad; 0 just luck; 1 great)
2017-05-22 00:05:35,740 INFO 
             precision    recall  f1-score   support

          0       0.94      0.39      0.55       176
          1       0.68      0.98      0.80       229

avg / total       0.79      0.72      0.69       405

2017-05-22 00:05:35,742 INFO Accuracy per class:
2017-05-22 00:05:35,743 INFO 0: 94.4%
2017-05-22 00:05:35,745 INFO 1: 67.6%
2017-05-22 00:05:35,746 INFO Confusion matrix:
2017-05-22 00:05:35,748 INFO 
[[ 68 108]
 [  4 225]]

Show prediction images


In [8]:
Y_test_pred
Y_test_true0 = utils.onehot_to_label(Y_test_2)
il = []
for i,yp in enumerate(Y_test_pred):
    il.append(str(yp) + '/' + str(Y_test_true0[i]))

utils.show_images(X_test[0:10], image_labels=il, cols=10, size=2)


2017-05-22 00:05:36,080 INFO showing 10 images
2017-05-22 00:05:36,083 INFO > [started] generating image patches. rows=2; cols=10...
2017-05-22 00:05:36,956 INFO > [done]    generating image patches. rows=2; cols=10 (873.840 ms)

Find lions on image


In [9]:
import numpy as np
import skimage.feature as feature
import skimage.transform as transform
from sklearn.feature_extraction import image
from itertools import permutations

img_path = INPUT_DIR2 + '47.jpg'
img = cv2.imread(img_path)
#img = img[1800:4000,2000:3300]
#img = img[3000:4000,2500:3500]
#img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY).astype('u1')

def eval_region(region_img):
    try:
        region_chog = [ch.extract(cv2.cvtColor(region_img,cv2.COLOR_BGR2GRAY).astype('u1'))]
        score = svm_model.predict_proba(region_chog)
    except:
        return 0
    return score[0][1] * 255

img2 = img.copy()

print('preparing blur')
img2 = cv2.GaussianBlur(img2,(5,5),3)

region_generator = objectdetect.sliding_window_generator(img2, step=(30,30), window=IMAGE_DIMS, pyramid_max_layers=1)
good_regions, imgs = objectdetect.evaluate_regions(region_generator, eval_region, score_threshold=180, apply_non_max_suppression=True, supression_overlap_threshold=0.3, threads=None)

print('regions found:')
print(len(good_regions))

patches = []
for i, region in enumerate(good_regions):
    score = int(good_regions[i][4])
    p = img[region[0]:region[0]+region[2],region[1]:region[1]+region[3]]
    patches.append(p)
    cv2.rectangle(img2, (region[1],region[0]), (region[3]+region[1],region[2]+region[0]), color=(score,score,score), thickness=2)    

utils.show_image(img2, size=40, is_bgr=True)
utils.show_images(patches[100:160], size=2, cols=10)


preparing blur
2017-05-22 00:05:37,585 INFO > [started] sliding_window...
3720/3744 [=========================>] 99% 54s remaining=0s sliding windoww
2017-05-22 00:06:32,224 INFO > [done]    sliding_window (54639.470 ms)
2017-05-22 00:06:32,226 INFO > [started] non_max_suppression. boxes=10198...
2017-05-22 00:06:52,780 INFO > [done]    non_max_suppression. boxes=10198 (20554.249 ms)
regions found:
3079
2017-05-22 00:06:56,798 INFO showing 60 images
2017-05-22 00:06:56,803 INFO > [started] generating image patches. rows=7; cols=10...
2017-05-22 00:07:01,896 INFO > [done]    generating image patches. rows=7; cols=10 (5093.138 ms)

Test model


In [10]:
logger.info('Evaluating svm model performance samples)...')
Y_test_pred = svm_model.predict(X_chog_test)
utils.evaluate_predictions(Y_test_2, Y_test_pred)


2017-05-22 00:07:01,909 INFO Evaluating svm model performance samples)...
2017-05-22 00:07:02,013 INFO Accuracy: 0.674074074074
2017-05-22 00:07:02,015 INFO Number of test samples: 405
2017-05-22 00:07:02,017 INFO Kappa score: 0.3671875 (-1 bad; 0 just luck; 1 great)
2017-05-22 00:07:02,019 INFO 
             precision    recall  f1-score   support

          0       0.98      0.39      0.56       213
          1       0.59      0.99      0.74       192

avg / total       0.80      0.67      0.64       405

2017-05-22 00:07:02,020 INFO Accuracy per class:
2017-05-22 00:07:02,022 INFO 0: 97.6%
2017-05-22 00:07:02,024 INFO 1: 59.4%
2017-05-22 00:07:02,025 INFO Confusion matrix:
2017-05-22 00:07:02,026 INFO 
[[ 83 130]
 [  2 190]]

In [ ]:


In [ ]:


In [ ]: