In [1]:
# Currently the ‘memory growth’ option should be the same for all GPUs.
# You should set the ‘memory growth’ option before initializing GPUs.

import tensorflow as tf
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
    try:
        for gpu in gpus:
            tf.config.experimental.set_memory_growth(gpu, True)
    except RuntimeError as e:
        print(e)

TiSeLaC : Time Series Land Cover Classification Challenge

This challenge originating from this website challenges anyone who is interested to deal with SITS (Satellite Imagery Time Series).

The challenge involves a multi-class single label classification problem where the examples to classify are pixels described by the time series of satellite images and the prediction is related to the land cover of associated to each pixel:

time_series_classification
Fig.1 - The Reunion Island site (a) and the corresponding classification according to the considered Land Cover Classes (b)

Before going in the EDA phase, we will first detail what our dataset is made of:
tiselac_pres_1
Fig.2 - A visual description of the dataset (b)

Data presentation

Training classes

The classes found in the training_class.txt file are the following:

Class ID Class Name # Instances
1 Urban Areas 16000
2 Other built-up surfaces 3236
3 Forests 16000
4 Sparse Vegetation 16000
5 Rocks and bare soil 12942
6 Grassland 5681
7 Sugarcane crops 7656
8 Other crops 1600
9 Water 2599

where the instances designates the pixels that makes up the image (total of 81714 pixels). It is important to note that not all pixel has a class, some are left blank.

Training file

The training file is in the form of a big text file where each row represents the value of the features of the given pixel at the 23 dates. As each pixel is described by 10 features (always in the following order: (Ultra Blue, Blue, Green, Red, NIR, SWIR1, SWIR2, NDVI, NDWI, BI), we have, for each row, 10*23 columns.

Coordinates file

This file gives the actual coordinates of pixels associated with a class to be able to draw a mask on the initial map of The Reunion Island.

Analysis of the source images

We will first explore the RGB component of the source images in the training file by redrawing its components.

In [2]:
# CONSTANTS & IMPORTS
import numpy as np
import pandas as pd
import time
import matplotlib.pyplot as plt
from tqdm import tqdm
import os
import cv2
import seaborn as sns;sns.set()

IMAGE_SIZE = (2866, 2633, 3)
NUM_OF_DAYS = 23
CLASSES = ["urban areas", "other built-up surfaces", "forests", 
           "sparse vegetation", "rocks and bare soil", "grassland", 
           "sugarcane crops", "other crops", "water"]
FEATURES = [
    "ultra blue","blue","green","red","NIR","SWIR1","SWIR2","NDVI","NDWI","BI"
]

NUM_OF_CLASSES = len(CLASSES)
NUM_OF_FEATURES = len(FEATURES)
NUM_OF_PIXELS = 81714
In [3]:
# DATA LOADING
data = pd.read_csv("data/train/training.txt", header=None)
coord = pd.read_csv("data/train/coord_training.txt", header=None)
classes_val = pd.read_csv("data/train/training_class.txt", header=None)

data_test = pd.read_csv("data/test/test.txt", header=None)
coord_test = pd.read_csv("data/test/coord_test.txt", header=None)
classes_val_test = pd.read_csv("data/test/test_class.txt", header=None)
y_test = classes_val_test.to_numpy()
In [4]:
img = [np.zeros(IMAGE_SIZE).astype(np.uint8) for _ in range(NUM_OF_DAYS)]
def row_to_img(row):
    
    idx = row.name
    
    coord_row = coord.iloc[idx, :]

    for i in range(23):
        b = row[i*10+1]
        g = row[i*10+2]
        r = row[i*10+3]
        
        #b = 255
        #g = 255
        #r = 255
        
        if (r > 255):
            r = 255
        if (b > 255):
            b = 255
        if (g > 255):
            g = 255
        
        img[i][coord_row[0], coord_row[1], :] = [r,g,b]
        
tqdm.pandas()
data.progress_apply(row_to_img, axis=1)
print("Images updated")
C:\Users\thoma\.conda\envs\tiselac\lib\site-packages\tqdm\std.py:658: FutureWarning: The Panel class is removed from pandas. Accessing it from the top-level namespace will also be removed in the next version
  from pandas import Panel
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 81714/81714 [02:08<00:00, 637.93it/s]
Images updated

Checking the classes distribution

The subsampling of the pixels done by the TiSeLaC organizers had, as a first intent, the idea of balancing the classes distribution. We are then expecting to see a somewhat balanced dataset.

In [5]:
val_count = classes_val.iloc[:,0].value_counts().sort_index()
x, y = val_count.keys(), val_count.values
plt.figure(figsize = (20,20))
ax = sns.barplot([CLASSES[i] + f" ({i+1})" for i in range(len(CLASSES))], y)
ax.set_title("Classes distribution of the training set")
ax.set_ylabel("Counts of instances per class")
ax.set_xlabel("Classes")
plt.show()
In [6]:
val_count = classes_val_test.iloc[:,0].value_counts().sort_index()
x, y = val_count.keys(), val_count.values
plt.figure(figsize = (20,20))
ax = sns.barplot([CLASSES[i] + f" ({i+1})" for i in range(len(CLASSES))], y)
ax.set_title("Classes distribution of the test set")
ax.set_ylabel("Counts of instances per class")
ax.set_xlabel("Classes")
plt.show()

Plotting the 23 days images of the 81714 pixels

As out of the 2866*2633 pixels, only 81714 were retained, we cannot have a good overview of their position and variation in the images presented there. However, a few things are important to point out:

  • We can notice clearly the shape of the Reunion island from the original image shown above
  • Some changes in noticeable clusters of pixels can be observed, especially at the bottom right of the image
In [7]:
plt.figure(figsize = (20,20))
plt.imshow(img[13], aspect='auto')
Out[7]:
<matplotlib.image.AxesImage at 0x288819af248>
In [8]:
# creating the gif
import imageio

# Write some Text

font                   = cv2.FONT_HERSHEY_SIMPLEX
bottomLeftCornerOfText = (1050,2600)
fontScale              = 5
fontColor              = (255,255,255)
lineType               = 4
thickness              = 10

scale_percent = 65 # percent of original size
width = int(img[0].shape[1] * scale_percent / 100)
height = int(img[0].shape[0] * scale_percent / 100)
dim = (width, height)
# resize image

with imageio.get_writer('day_animation.gif', mode='I') as writer:
    for i in range(0,NUM_OF_DAYS):
        for j in range(5):
            img_d = np.copy(img[i])
            cv2.putText(img_d,f'Day {i+1}', 
                bottomLeftCornerOfText, 
                font, 
                fontScale,
                fontColor,
                thickness,
                lineType)
            resized = cv2.resize(img_d, dim, interpolation = cv2.INTER_NEAREST) 
            writer.append_data(resized)
In [9]:
fig, axs=plt.subplots(6, 4, figsize=(20, 20), constrained_layout=True)

for i in range(0,NUM_OF_DAYS):
    
    x = int(i / 4)
    y = i % 4
    
    axs[x, y].imshow(img[i])
    
    axs[x,y].set_title(f'Day n°{i+1}')

fig.delaxes(axs[5,3])
#fig.tight_layout()

Giving insights on mean value of the 10 features over the 23 days, discriminated by class

In order to see if we can extract any pattern ourselves, we will plot the mean value evolution of each feature over the 23 days by calculating the mean of these values for each class, resulting in one plot per class, with 10 lines on each plots.

In [10]:
# we start by building an array of 10 matrices of size 10*23 each

list_of_per_class_features_mean = [
    np.zeros((10,23)) for _ in range(len(CLASSES))
]

list_of_per_class_features_std = [
    np.zeros((10,23)) for _ in range(len(CLASSES))
]

N = data.shape[0]

def row_to_class(row):
    
    idx = row.name
    
    class_val = int(classes_val.iloc[idx, 0])
    
    # designates the feature
    for i in range(10):
        # designates the day
        for j in range(23):
            
            list_of_per_class_features_mean[class_val-1][i,j] += row[j*10 + i] # calculating the mean value
            
            list_of_per_class_features_std[class_val-1][i,j] += row[j*10 + i]*row[j*10 + i]/N
    
data.progress_apply(row_to_class, axis=1)
print("Calculation over..")
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 81714/81714 [12:48<00:00, 106.38it/s]
Calculation over..

In [11]:
fig, axs = plt.subplots(3,3, figsize=(20,15))

for idx in range(len(list_of_per_class_features_mean)):
    
    i, j = idx % 3, int(idx / 3)
    
    values = list_of_per_class_features_mean[idx]/N
    
    standard_devs = list_of_per_class_features_std[idx] - np.square(values)
    
    for idx_f, feature in enumerate(FEATURES):
        
        x = np.arange(1,24)
        y = values[idx_f, :]
        
        e = np.sqrt(standard_devs[idx_f, :])
        
        axs[i, j].errorbar(x, y, label=feature)
        

    axs[i, j].set_title(f"Class {CLASSES[idx]}")
    axs[i, j].set_ylabel("Features values")
    axs[i, j].set_xlabel("Day number")
    axs[i, j].legend()
    
    

As we can see there, a few different classes see their features be highly disturbed through the days (e.g the water class or the rocks and bare soil are the most noticeable). Oppositely, the forests and crops classes are pretty steady in their results.

This apparent diversity in the variation of the features for each class is a good sign, it should not be too hard for an automatic classifier to be able to discriminate them from each other.

Classifiers

In [12]:
##  Keras imports
import tensorflow as tf
from tensorflow.keras.preprocessing import sequence
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Dense, Dropout, BatchNormalization, Input, Concatenate, Conv1D, MaxPooling1D
from tensorflow.keras.layers import LSTM, Flatten

from tensorflow.keras.optimizers import Adam, SGD
from tensorflow.keras.models import load_model
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping,ReduceLROnPlateau 

## Sklearn imports
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder, StandardScaler, MinMaxScaler

LR = 0.001
BATCH_SIZE = 256
EPOCHS = 50
VAL_SIZE = 0.1

1D-CNN

For this part, we will implement the Multi-Scale Convolutional Neural Networks presented in the following paper: Multi-Scale Convolutional Neural Networks for Time SeriesClassification

The architecture looks like this:

mcnn
Fig.3 - Overall architecture of MCNN

We will first setup our constants and imports

In [13]:
from tensorflow.keras.layers import Conv1D, Input, Concatenate, GlobalMaxPooling1D, MaxPooling1D
from tensorflow.keras.models import Model

LR = 0.01
BATCH_SIZE = 256
EPOCHS = 100
VAL_SIZE = 0.2
DOWN_SAMPLING_FACTOR = 2
DOWN_SAMPLING_SIZE = int(np.ceil(NUM_OF_DAYS)/DOWN_SAMPLING_FACTOR) + 1
SMOOTH_SIZE = 4

scaler = StandardScaler()
In [14]:
# Formatting the X data
data_train = data.to_numpy()
X = data_train.reshape((NUM_OF_PIXELS, 23, NUM_OF_FEATURES)).astype(np.int64)
coord_np = coord.to_numpy().astype(np.int32).reshape(-1, 2)
idx = np.arange(X.shape[0])

# Formatting the y data
classes_train = classes_val.to_numpy().astype(np.uint8)
enc = OneHotEncoder(handle_unknown='ignore', sparse=False)
y = enc.fit_transform(classes_train).astype(np.uint8)
In [15]:
# Splitting x and y into training and validation sets
X_train, X_val, y_train, y_val, idx_train, idx_val = train_test_split(X, y, idx, test_size = VAL_SIZE)

After splitting the image data, we take care of the pixel positions that we scale without data leak by fitting the transformer only to the training set.

In [16]:
coord_train = coord_np[idx_train]
coord_train = scaler.fit_transform(coord_train)

coord_val = scaler.transform(coord_np[idx_val])

Setting up the model

Here, we first create three simple models to extract features that may be specific to our three different scale of time series:

  • The original time series
  • The smoothed time series
  • The down sampled time series

They are then concatenated and a new Convolutional layer is added before jumping to 3 fully connected layers. This model, in the same way than the LSTM, is pretty light in parameters, making its training relatively harder, hense requiring more advanced finetuning.

In [17]:
def get_base_model(input_len, fsize=6):
    #this base model represents the convolution + pooling phase (there will be three of it)

    input_seq = Input(shape=(input_len, 10))

    x = Conv1D(40, fsize, padding="same", activation="relu")(input_seq)
    x = MaxPooling1D()(x)
    model = Model(inputs=input_seq, outputs=x)
    
    return model

def get_coord_model():
    input_c = Input(shape=(2,))
    model = Model(inputs=input_c, outputs=input_c)
    
    return model

#it takes the original time series and its down-sampled versions as an input, and returns the result of classification as an output
def get_1D_CNN():

    input_original = Input(shape=(23, 10))
    input_multifrequency = Input(shape=(23 , 10))
    input_down_sampling = Input(shape=(DOWN_SAMPLING_SIZE, 10))
    
    base_net_original = get_base_model(23)
    base_net_multifrequency = get_base_model(23)
    base_net_down_sampling = get_base_model(DOWN_SAMPLING_SIZE, fsize=3)
    
    embedding_original = base_net_original(input_original)
    embedding_multifrequency = base_net_multifrequency(input_multifrequency)
    embedding_down_sampling = base_net_down_sampling(input_down_sampling)
    
    merged = Concatenate(axis=1)([embedding_original, embedding_multifrequency, embedding_down_sampling])#concatenate all the outputs
    
    conv = Conv1D(40, 6, padding="same", activation="relu")(merged)
    x = GlobalMaxPooling1D()(conv)
    
    coord_model = get_coord_model()
    #concatenating the coord model and the CNN-extracted features
    x = Concatenate(axis=-1)([x, coord_model.output])
    x = Dense(256, activation="relu")(x)
    x = Dense(128, activation="relu")(x)
    x = Dropout(0.3)(x)
    x = Dense(64, activation="relu")(x)
    #x = Dropout(0.3)(x)
    x = BatchNormalization()(x)
    x = Dense(32, activation="relu")(x)
    
    out = Dense(NUM_OF_CLASSES, activation='softmax')(x)
    
    model = Model(inputs=[input_original, input_multifrequency, input_down_sampling, coord_model.input], outputs=out)
    return model

Creating the data generator

We have to take care of the different scale of data by making sure that the generator, when taking one time series as an input, outputs three of them, one of which being the original, the two others having been through their own sets of processing.

In [18]:
def smoothing(row):
    # given a row of shape (23,10), smoothes all 10 feature according to the smoothing factor (mean over a SMOOTH_SIZE window)
    
    to_smooth = np.copy(row)
    
    for i in range(row.shape[1]):
        for j in range(row.shape[0]):
            
            smoothing_indices = np.array([k % row.shape[0] for k in range(int(j - SMOOTH_SIZE / 2), int(j + SMOOTH_SIZE / 2 + 1))])
            
            acc = 0
            for idx in smoothing_indices:
                acc += row[idx,i]
                
            to_smooth[j,i] = acc / SMOOTH_SIZE
            
    return to_smooth

def down_sampling(row):
    new_row = []
    
    for j in range(0, len(row)+1, DOWN_SAMPLING_FACTOR):
        new_row.append(row[j])
    
    return np.array(new_row)
In [19]:
def data_generator(X, y, input_shape=(23,10), batch_size=64):
    """
        X is a tuple (X_train, X_coord) where X_train is the pixels data and X_coord their coordinates
    """
    X_train, X_coord = X
    
    while True:
        
        for i in range(0, len(X_train), batch_size):
            
            upper = min(i+batch_size, len(X_train)-1)
            
            batch = np.copy(X_train[i:upper])
            smoothed = np.copy(X_train[i:upper])
            down_sampled = np.zeros((len(batch),DOWN_SAMPLING_SIZE,input_shape[1]))
            coords = np.copy(X_coord[i:upper])
            
            for row_idx in range(len(batch)):
                smoothed[row_idx, :] = smoothing(X_train[row_idx, :])
                down_sampled[row_idx, :] = down_sampling(X_train[row_idx, :])
            
            
            X_batch = [
                batch,smoothed,down_sampled, coords
            ]
            
            y_batch = y[i:upper]
                
            yield X_batch, y_batch

Training our model

In [20]:
train_gen = data_generator(
    (X_train,coord_train), y_train, batch_size=BATCH_SIZE)
val_gen = data_generator(
    (X_val,coord_val), y_val, batch_size=BATCH_SIZE)
train_steps = round(len(X_train) / BATCH_SIZE) + 1
val_steps = round(len(X_val) / BATCH_SIZE) + 1
In [24]:
model = get_1D_CNN()

opt = Adam(LR)
model.compile(opt, loss="categorical_crossentropy",
    metrics=['categorical_accuracy'])
In [25]:
model_filename = "tiselac-1d-cnn-{epoch:02d}-{val_loss:.2f}.h5"

callbacks = [
    ModelCheckpoint(
        os.path.join("models/", model_filename),
        monitor='val_loss', verbose=1, save_best_only=True, save_freq='epoch'),
    EarlyStopping(monitor='val_loss', min_delta = 1e-3, patience = 5),
    ReduceLROnPlateau(monitor='val_loss', factor=0.2, verbose=1,
                              patience=3, min_lr=0.00001)

]
In [26]:
model.fit_generator(
    train_gen,
    steps_per_epoch=train_steps,
    epochs=EPOCHS,
    validation_data=val_gen,
    validation_steps=val_steps,
    callbacks=callbacks
)
Epoch 1/100
255/256 [============================>.] - ETA: 0s - loss: 0.9701 - categorical_accuracy: 0.6822
Epoch 00001: val_loss improved from inf to 0.84626, saving model to models/tiselac-1d-cnn-01-0.85.h5
256/256 [==============================] - 139s 541ms/step - loss: 0.9693 - categorical_accuracy: 0.6825 - val_loss: 0.8463 - val_categorical_accuracy: 0.7473
Epoch 2/100
255/256 [============================>.] - ETA: 0s - loss: 0.7121 - categorical_accuracy: 0.7766
Epoch 00002: val_loss improved from 0.84626 to 0.79918, saving model to models/tiselac-1d-cnn-02-0.80.h5
256/256 [==============================] - 132s 515ms/step - loss: 0.7123 - categorical_accuracy: 0.7766 - val_loss: 0.7992 - val_categorical_accuracy: 0.7636
Epoch 3/100
255/256 [============================>.] - ETA: 0s - loss: 0.6377 - categorical_accuracy: 0.8002
Epoch 00003: val_loss improved from 0.79918 to 0.65793, saving model to models/tiselac-1d-cnn-03-0.66.h5
256/256 [==============================] - 129s 502ms/step - loss: 0.6377 - categorical_accuracy: 0.8002 - val_loss: 0.6579 - val_categorical_accuracy: 0.7999
Epoch 4/100
255/256 [============================>.] - ETA: 0s - loss: 0.5908 - categorical_accuracy: 0.8155
Epoch 00004: val_loss improved from 0.65793 to 0.64650, saving model to models/tiselac-1d-cnn-04-0.65.h5
256/256 [==============================] - 130s 507ms/step - loss: 0.5909 - categorical_accuracy: 0.8155 - val_loss: 0.6465 - val_categorical_accuracy: 0.8042
Epoch 5/100
255/256 [============================>.] - ETA: 0s - loss: 0.5600 - categorical_accuracy: 0.8234
Epoch 00005: val_loss improved from 0.64650 to 0.58749, saving model to models/tiselac-1d-cnn-05-0.59.h5
256/256 [==============================] - 129s 503ms/step - loss: 0.5602 - categorical_accuracy: 0.8234 - val_loss: 0.5875 - val_categorical_accuracy: 0.8269
Epoch 6/100
255/256 [============================>.] - ETA: 0s - loss: 0.5335 - categorical_accuracy: 0.8331
Epoch 00006: val_loss did not improve from 0.58749
256/256 [==============================] - 125s 489ms/step - loss: 0.5337 - categorical_accuracy: 0.8331 - val_loss: 0.6075 - val_categorical_accuracy: 0.8112
Epoch 7/100
255/256 [============================>.] - ETA: 0s - loss: 0.5211 - categorical_accuracy: 0.8363
Epoch 00007: val_loss improved from 0.58749 to 0.53709, saving model to models/tiselac-1d-cnn-07-0.54.h5
256/256 [==============================] - 125s 489ms/step - loss: 0.5213 - categorical_accuracy: 0.8362 - val_loss: 0.5371 - val_categorical_accuracy: 0.8379
Epoch 8/100
255/256 [============================>.] - ETA: 0s - loss: 0.5025 - categorical_accuracy: 0.8419
Epoch 00008: val_loss did not improve from 0.53709
256/256 [==============================] - 126s 493ms/step - loss: 0.5028 - categorical_accuracy: 0.8418 - val_loss: 0.5688 - val_categorical_accuracy: 0.8266
Epoch 9/100
255/256 [============================>.] - ETA: 0s - loss: 0.4886 - categorical_accuracy: 0.8463
Epoch 00009: val_loss improved from 0.53709 to 0.48403, saving model to models/tiselac-1d-cnn-09-0.48.h5
256/256 [==============================] - 126s 492ms/step - loss: 0.4889 - categorical_accuracy: 0.8462 - val_loss: 0.4840 - val_categorical_accuracy: 0.8475
Epoch 10/100
255/256 [============================>.] - ETA: 0s - loss: 0.4798 - categorical_accuracy: 0.8488
Epoch 00010: val_loss improved from 0.48403 to 0.45598, saving model to models/tiselac-1d-cnn-10-0.46.h5
256/256 [==============================] - 126s 492ms/step - loss: 0.4800 - categorical_accuracy: 0.8487 - val_loss: 0.4560 - val_categorical_accuracy: 0.8543
Epoch 11/100
255/256 [============================>.] - ETA: 0s - loss: 0.4706 - categorical_accuracy: 0.8506
Epoch 00011: val_loss did not improve from 0.45598
256/256 [==============================] - 125s 487ms/step - loss: 0.4708 - categorical_accuracy: 0.8506 - val_loss: 0.4874 - val_categorical_accuracy: 0.8435
Epoch 12/100
255/256 [============================>.] - ETA: 0s - loss: 0.4601 - categorical_accuracy: 0.8552
Epoch 00012: val_loss did not improve from 0.45598
256/256 [==============================] - 125s 487ms/step - loss: 0.4603 - categorical_accuracy: 0.8552 - val_loss: 0.4915 - val_categorical_accuracy: 0.8476
Epoch 13/100
255/256 [============================>.] - ETA: 0s - loss: 0.4488 - categorical_accuracy: 0.8580
Epoch 00013: val_loss did not improve from 0.45598

Epoch 00013: ReduceLROnPlateau reducing learning rate to 0.0019999999552965165.
256/256 [==============================] - 128s 499ms/step - loss: 0.4490 - categorical_accuracy: 0.8580 - val_loss: 0.4664 - val_categorical_accuracy: 0.8526
Epoch 14/100
255/256 [============================>.] - ETA: 0s - loss: 0.3980 - categorical_accuracy: 0.8733
Epoch 00014: val_loss improved from 0.45598 to 0.42409, saving model to models/tiselac-1d-cnn-14-0.42.h5
256/256 [==============================] - 125s 487ms/step - loss: 0.3981 - categorical_accuracy: 0.8733 - val_loss: 0.4241 - val_categorical_accuracy: 0.8645
Epoch 15/100
255/256 [============================>.] - ETA: 0s - loss: 0.3856 - categorical_accuracy: 0.8773
Epoch 00015: val_loss did not improve from 0.42409
256/256 [==============================] - 126s 492ms/step - loss: 0.3857 - categorical_accuracy: 0.8772 - val_loss: 0.4287 - val_categorical_accuracy: 0.8643
Epoch 16/100
255/256 [============================>.] - ETA: 0s - loss: 0.3796 - categorical_accuracy: 0.8794
Epoch 00016: val_loss improved from 0.42409 to 0.41526, saving model to models/tiselac-1d-cnn-16-0.42.h5
256/256 [==============================] - 126s 494ms/step - loss: 0.3797 - categorical_accuracy: 0.8794 - val_loss: 0.4153 - val_categorical_accuracy: 0.8676
Epoch 17/100
255/256 [============================>.] - ETA: 0s - loss: 0.3755 - categorical_accuracy: 0.8810
Epoch 00017: val_loss did not improve from 0.41526
256/256 [==============================] - 123s 481ms/step - loss: 0.3758 - categorical_accuracy: 0.8808 - val_loss: 0.4221 - val_categorical_accuracy: 0.8661
Epoch 18/100
255/256 [============================>.] - ETA: 0s - loss: 0.3727 - categorical_accuracy: 0.8815
Epoch 00018: val_loss improved from 0.41526 to 0.41488, saving model to models/tiselac-1d-cnn-18-0.41.h5
256/256 [==============================] - 124s 486ms/step - loss: 0.3728 - categorical_accuracy: 0.8814 - val_loss: 0.4149 - val_categorical_accuracy: 0.8687
Epoch 19/100
255/256 [============================>.] - ETA: 0s - loss: 0.3682 - categorical_accuracy: 0.8829
Epoch 00019: val_loss improved from 0.41488 to 0.41438, saving model to models/tiselac-1d-cnn-19-0.41.h5
256/256 [==============================] - 125s 490ms/step - loss: 0.3684 - categorical_accuracy: 0.8829 - val_loss: 0.4144 - val_categorical_accuracy: 0.8687
Epoch 20/100
255/256 [============================>.] - ETA: 0s - loss: 0.3642 - categorical_accuracy: 0.8831
Epoch 00020: val_loss improved from 0.41438 to 0.40338, saving model to models/tiselac-1d-cnn-20-0.40.h5
256/256 [==============================] - 126s 491ms/step - loss: 0.3643 - categorical_accuracy: 0.8832 - val_loss: 0.4034 - val_categorical_accuracy: 0.8726
Epoch 21/100
255/256 [============================>.] - ETA: 0s - loss: 0.3595 - categorical_accuracy: 0.8843
Epoch 00021: val_loss did not improve from 0.40338
256/256 [==============================] - 126s 491ms/step - loss: 0.3597 - categorical_accuracy: 0.8842 - val_loss: 0.4038 - val_categorical_accuracy: 0.8737
Epoch 22/100
255/256 [============================>.] - ETA: 0s - loss: 0.3558 - categorical_accuracy: 0.8862
Epoch 00022: val_loss did not improve from 0.40338
256/256 [==============================] - 125s 488ms/step - loss: 0.3559 - categorical_accuracy: 0.8862 - val_loss: 0.4106 - val_categorical_accuracy: 0.8706
Epoch 23/100
255/256 [============================>.] - ETA: 0s - loss: 0.3522 - categorical_accuracy: 0.8873
Epoch 00023: val_loss improved from 0.40338 to 0.40018, saving model to models/tiselac-1d-cnn-23-0.40.h5
256/256 [==============================] - 124s 486ms/step - loss: 0.3524 - categorical_accuracy: 0.8872 - val_loss: 0.4002 - val_categorical_accuracy: 0.8723
Epoch 24/100
255/256 [============================>.] - ETA: 0s - loss: 0.3492 - categorical_accuracy: 0.8882
Epoch 00024: val_loss did not improve from 0.40018
256/256 [==============================] - 124s 485ms/step - loss: 0.3493 - categorical_accuracy: 0.8881 - val_loss: 0.4141 - val_categorical_accuracy: 0.8672
Epoch 25/100
255/256 [============================>.] - ETA: 0s - loss: 0.3472 - categorical_accuracy: 0.8879
Epoch 00025: val_loss improved from 0.40018 to 0.39679, saving model to models/tiselac-1d-cnn-25-0.40.h5
256/256 [==============================] - 130s 506ms/step - loss: 0.3472 - categorical_accuracy: 0.8879 - val_loss: 0.3968 - val_categorical_accuracy: 0.8763
Epoch 26/100
255/256 [============================>.] - ETA: 0s - loss: 0.3417 - categorical_accuracy: 0.8897
Epoch 00026: val_loss did not improve from 0.39679
256/256 [==============================] - 127s 495ms/step - loss: 0.3419 - categorical_accuracy: 0.8897 - val_loss: 0.4121 - val_categorical_accuracy: 0.8725
Epoch 27/100
255/256 [============================>.] - ETA: 0s - loss: 0.3400 - categorical_accuracy: 0.8903
Epoch 00027: val_loss did not improve from 0.39679
256/256 [==============================] - 127s 494ms/step - loss: 0.3401 - categorical_accuracy: 0.8903 - val_loss: 0.4029 - val_categorical_accuracy: 0.8725
Epoch 28/100
255/256 [============================>.] - ETA: 0s - loss: 0.3369 - categorical_accuracy: 0.8907
Epoch 00028: val_loss improved from 0.39679 to 0.38749, saving model to models/tiselac-1d-cnn-28-0.39.h5
256/256 [==============================] - 126s 493ms/step - loss: 0.3371 - categorical_accuracy: 0.8906 - val_loss: 0.3875 - val_categorical_accuracy: 0.8782
Epoch 29/100
255/256 [============================>.] - ETA: 0s - loss: 0.3337 - categorical_accuracy: 0.8915
Epoch 00029: val_loss did not improve from 0.38749
256/256 [==============================] - 125s 487ms/step - loss: 0.3338 - categorical_accuracy: 0.8915 - val_loss: 0.4014 - val_categorical_accuracy: 0.8716
Epoch 30/100
255/256 [============================>.] - ETA: 0s - loss: 0.3310 - categorical_accuracy: 0.8928
Epoch 00030: val_loss did not improve from 0.38749
256/256 [==============================] - 125s 487ms/step - loss: 0.3311 - categorical_accuracy: 0.8927 - val_loss: 0.3925 - val_categorical_accuracy: 0.8784
Epoch 31/100
255/256 [============================>.] - ETA: 0s - loss: 0.3273 - categorical_accuracy: 0.8937
Epoch 00031: val_loss did not improve from 0.38749

Epoch 00031: ReduceLROnPlateau reducing learning rate to 0.0003999999724328518.
256/256 [==============================] - 125s 489ms/step - loss: 0.3275 - categorical_accuracy: 0.8937 - val_loss: 0.4039 - val_categorical_accuracy: 0.8728
Epoch 32/100
255/256 [============================>.] - ETA: 0s - loss: 0.3135 - categorical_accuracy: 0.8990
Epoch 00032: val_loss did not improve from 0.38749
256/256 [==============================] - 126s 493ms/step - loss: 0.3136 - categorical_accuracy: 0.8989 - val_loss: 0.3894 - val_categorical_accuracy: 0.8801
Epoch 33/100
255/256 [============================>.] - ETA: 0s - loss: 0.3097 - categorical_accuracy: 0.8994
Epoch 00033: val_loss did not improve from 0.38749
256/256 [==============================] - 128s 499ms/step - loss: 0.3097 - categorical_accuracy: 0.8993 - val_loss: 0.3918 - val_categorical_accuracy: 0.8798
Out[26]:
<tensorflow.python.keras.callbacks.History at 0x2891d695048>

Testing the model

We will now test the model on the provided dataset and use a F1 Score metric for it (provided by Sk-Learn).

In [27]:
from sklearn.metrics import f1_score

data_test_np = data_test.to_numpy()

X_test = data_test_np.reshape((data_test_np.shape[0], 23, NUM_OF_FEATURES)).astype(np.float32)
coord_test_np = coord_test.to_numpy().astype(np.int32).reshape(-1, 2)
coord_test_np = scaler.transform(coord_test_np)

test_gen = data_generator((X_test,coord_test_np), y_test, batch_size=BATCH_SIZE)
test_steps = round(len(X_test) / BATCH_SIZE) + 1
In [28]:
y_pred = model.predict_generator(test_gen, steps=test_steps)
y_pred = np.argmax(y_pred, axis=1) +1
In [29]:
f1_score(y_test.flatten()[:17972], y_pred, average="weighted")
Out[29]:
0.8870601785364084

Advanced Classifiers

Based on this paper (Ismail Fawaz, H., Forestier, G., Weber, J. et al, 2019), I retained a number of the models compared.

1. Multi Channel Deep Convolutional Neural Network

Detailed in this paper (Zheng et al., 2014, 2016), this architecture want to exploit a presumed independence between the different features of the MTS data by applying convolution independently (in parallel) on each dimension of the input.

In [30]:
from tensorflow.keras.layers import Flatten, AveragePooling1D
In [31]:
def get_channel_model(ts_length):

    input_seq = Input(shape=(ts_length,1))

    x = Conv1D(12, 12, padding="same", activation="relu")(input_seq)
    x = MaxPooling1D()(x)
    x = Conv1D(24, 8, padding='same', activation="relu")(x)
    x = MaxPooling1D()(x)
    model = Model(inputs=input_seq, outputs=x)
    
    return model

def get_MCDCNN():
    
    input_models = [get_channel_model(23) for i in range(10)]
    
    merged = Concatenate(axis=1)([channel.input for channel in input_models])#concatenate all the outputs
    x = Flatten()(merged)
    x = Dense(732, activation="relu")(x)
    x = Dropout(0.3)(x)
    x = Dense(256, activation="relu")(x)
    x = BatchNormalization()(x)
    x = Dense(128, activation="relu")(x)
    x = Dense(NUM_OF_CLASSES, activation="softmax")(x)
    
    mcdcnn_model = Model([channel.input for channel in input_models], x)
    return mcdcnn_model
In [32]:
LR = 0.01
opt = SGD(LR, decay=0.0005)

mcdcnn_model = get_MCDCNN()
mcdcnn_model.compile(opt, loss="categorical_crossentropy",metrics=["accuracy"])
Starting training...
In [33]:
def data_generator_mcdcnn(X, y, input_shape=(10,23,1), batch_size=64):
    
    while True:
        
        for i in range(0, len(X), batch_size):
            
            upper = min(i+batch_size, len(X)-1)
            
            batch = np.copy(X[i:upper])

            batch = batch.reshape((batch.shape[0],)+input_shape)
            
            y_batch = y[i:upper]
                
            yield [batch[:,i,:,:] for i in range(10)], y_batch
            
In [34]:
model_filename = "tiselac-mcdcnn-{epoch:02d}-{val_loss:.2f}.h5"

callbacks = [
    ModelCheckpoint(
        os.path.join("models/", model_filename),
        monitor='val_loss', verbose=1, save_best_only=True, save_freq='epoch'),
    EarlyStopping(monitor='val_loss', min_delta = 1e-4, patience = 5),
    ReduceLROnPlateau(monitor='val_loss', factor=0.2, verbose=1,
                              patience=3, min_lr=0.00001)

]
In [35]:
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size = VAL_SIZE)
In [36]:
BATCH_SIZE = 256
EPOCHS = 120

train_gen = data_generator_mcdcnn(X_train, y_train, batch_size=BATCH_SIZE)
val_gen = data_generator_mcdcnn(X_val, y_val, batch_size=BATCH_SIZE)
train_steps = round(len(X_train) / BATCH_SIZE) + 1
val_steps = round(len(X_val) / BATCH_SIZE) + 1

mcdcnn_model.fit_generator(
    train_gen,
    steps_per_epoch=train_steps,
    epochs=EPOCHS,
    validation_data=val_gen,
    validation_steps=val_steps,
    callbacks=callbacks
)
Epoch 1/120
253/256 [============================>.] - ETA: 0s - loss: 1.0860 - accuracy: 0.6550
Epoch 00001: val_loss improved from inf to 0.80646, saving model to models/tiselac-mcdcnn-01-0.81.h5
256/256 [==============================] - 7s 28ms/step - loss: 1.0834 - accuracy: 0.6557 - val_loss: 0.8065 - val_accuracy: 0.7477
Epoch 2/120
255/256 [============================>.] - ETA: 0s - loss: 0.8089 - accuracy: 0.7475
Epoch 00002: val_loss improved from 0.80646 to 0.73327, saving model to models/tiselac-mcdcnn-02-0.73.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.8084 - accuracy: 0.7476 - val_loss: 0.7333 - val_accuracy: 0.7638
Epoch 3/120
255/256 [============================>.] - ETA: 0s - loss: 0.7471 - accuracy: 0.7657
Epoch 00003: val_loss improved from 0.73327 to 0.68336, saving model to models/tiselac-mcdcnn-03-0.68.h5
256/256 [==============================] - 7s 27ms/step - loss: 0.7470 - accuracy: 0.7657 - val_loss: 0.6834 - val_accuracy: 0.7817
Epoch 4/120
255/256 [============================>.] - ETA: 0s - loss: 0.7098 - accuracy: 0.7778
Epoch 00004: val_loss improved from 0.68336 to 0.64763, saving model to models/tiselac-mcdcnn-04-0.65.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.7096 - accuracy: 0.7778 - val_loss: 0.6476 - val_accuracy: 0.7935
Epoch 5/120
253/256 [============================>.] - ETA: 0s - loss: 0.6828 - accuracy: 0.7868
Epoch 00005: val_loss improved from 0.64763 to 0.62620, saving model to models/tiselac-mcdcnn-05-0.63.h5
256/256 [==============================] - 8s 32ms/step - loss: 0.6823 - accuracy: 0.7868 - val_loss: 0.6262 - val_accuracy: 0.8005
Epoch 6/120
253/256 [============================>.] - ETA: 0s - loss: 0.6658 - accuracy: 0.7911
Epoch 00006: val_loss improved from 0.62620 to 0.61206, saving model to models/tiselac-mcdcnn-06-0.61.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.6655 - accuracy: 0.7911 - val_loss: 0.6121 - val_accuracy: 0.8029
Epoch 7/120
253/256 [============================>.] - ETA: 0s - loss: 0.6491 - accuracy: 0.7962
Epoch 00007: val_loss improved from 0.61206 to 0.60103, saving model to models/tiselac-mcdcnn-07-0.60.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.6485 - accuracy: 0.7963 - val_loss: 0.6010 - val_accuracy: 0.8056
Epoch 8/120
254/256 [============================>.] - ETA: 0s - loss: 0.6340 - accuracy: 0.8003
Epoch 00008: val_loss improved from 0.60103 to 0.58423, saving model to models/tiselac-mcdcnn-08-0.58.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.6337 - accuracy: 0.8003 - val_loss: 0.5842 - val_accuracy: 0.8108
Epoch 9/120
254/256 [============================>.] - ETA: 0s - loss: 0.6237 - accuracy: 0.8030
Epoch 00009: val_loss improved from 0.58423 to 0.57322, saving model to models/tiselac-mcdcnn-09-0.57.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.6235 - accuracy: 0.8030 - val_loss: 0.5732 - val_accuracy: 0.8138
Epoch 10/120
254/256 [============================>.] - ETA: 0s - loss: 0.6118 - accuracy: 0.8073
Epoch 00010: val_loss improved from 0.57322 to 0.56190, saving model to models/tiselac-mcdcnn-10-0.56.h5
256/256 [==============================] - 7s 29ms/step - loss: 0.6116 - accuracy: 0.8073 - val_loss: 0.5619 - val_accuracy: 0.8175
Epoch 11/120
254/256 [============================>.] - ETA: 0s - loss: 0.6036 - accuracy: 0.8093
Epoch 00011: val_loss improved from 0.56190 to 0.55338, saving model to models/tiselac-mcdcnn-11-0.55.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.6032 - accuracy: 0.8093 - val_loss: 0.5534 - val_accuracy: 0.8196
Epoch 12/120
254/256 [============================>.] - ETA: 0s - loss: 0.5953 - accuracy: 0.8131
Epoch 00012: val_loss improved from 0.55338 to 0.54821, saving model to models/tiselac-mcdcnn-12-0.55.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5951 - accuracy: 0.8132 - val_loss: 0.5482 - val_accuracy: 0.8217
Epoch 13/120
254/256 [============================>.] - ETA: 0s - loss: 0.5891 - accuracy: 0.8130
Epoch 00013: val_loss improved from 0.54821 to 0.54678, saving model to models/tiselac-mcdcnn-13-0.55.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5889 - accuracy: 0.8131 - val_loss: 0.5468 - val_accuracy: 0.8233
Epoch 14/120
254/256 [============================>.] - ETA: 0s - loss: 0.5802 - accuracy: 0.8176
Epoch 00014: val_loss improved from 0.54678 to 0.53860, saving model to models/tiselac-mcdcnn-14-0.54.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5800 - accuracy: 0.8176 - val_loss: 0.5386 - val_accuracy: 0.8261
Epoch 15/120
254/256 [============================>.] - ETA: 0s - loss: 0.5735 - accuracy: 0.8189
Epoch 00015: val_loss improved from 0.53860 to 0.53068, saving model to models/tiselac-mcdcnn-15-0.53.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5732 - accuracy: 0.8190 - val_loss: 0.5307 - val_accuracy: 0.8284
Epoch 16/120
255/256 [============================>.] - ETA: 0s - loss: 0.5704 - accuracy: 0.8198 ETA: 0s - los
Epoch 00016: val_loss improved from 0.53068 to 0.52700, saving model to models/tiselac-mcdcnn-16-0.53.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5703 - accuracy: 0.8198 - val_loss: 0.5270 - val_accuracy: 0.8304
Epoch 17/120
253/256 [============================>.] - ETA: 0s - loss: 0.5649 - accuracy: 0.8220
Epoch 00017: val_loss improved from 0.52700 to 0.51996, saving model to models/tiselac-mcdcnn-17-0.52.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5647 - accuracy: 0.8220 - val_loss: 0.5200 - val_accuracy: 0.8317
Epoch 18/120
254/256 [============================>.] - ETA: 0s - loss: 0.5583 - accuracy: 0.8222
Epoch 00018: val_loss improved from 0.51996 to 0.51478, saving model to models/tiselac-mcdcnn-18-0.51.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5578 - accuracy: 0.8223 - val_loss: 0.5148 - val_accuracy: 0.8328
Epoch 19/120
253/256 [============================>.] - ETA: 0s - loss: 0.5556 - accuracy: 0.8232
Epoch 00019: val_loss improved from 0.51478 to 0.51121, saving model to models/tiselac-mcdcnn-19-0.51.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5554 - accuracy: 0.8232 - val_loss: 0.5112 - val_accuracy: 0.8332
Epoch 20/120
254/256 [============================>.] - ETA: 0s - loss: 0.5506 - accuracy: 0.8265
Epoch 00020: val_loss improved from 0.51121 to 0.50835, saving model to models/tiselac-mcdcnn-20-0.51.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5506 - accuracy: 0.8266 - val_loss: 0.5083 - val_accuracy: 0.8345
Epoch 21/120
253/256 [============================>.] - ETA: 0s - loss: 0.5485 - accuracy: 0.8267
Epoch 00021: val_loss did not improve from 0.50835
256/256 [==============================] - 7s 28ms/step - loss: 0.5483 - accuracy: 0.8267 - val_loss: 0.5087 - val_accuracy: 0.8355
Epoch 22/120
255/256 [============================>.] - ETA: 0s - loss: 0.5438 - accuracy: 0.8286
Epoch 00022: val_loss improved from 0.50835 to 0.50419, saving model to models/tiselac-mcdcnn-22-0.50.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5439 - accuracy: 0.8285 - val_loss: 0.5042 - val_accuracy: 0.8359
Epoch 23/120
255/256 [============================>.] - ETA: 0s - loss: 0.5413 - accuracy: 0.8284
Epoch 00023: val_loss improved from 0.50419 to 0.49764, saving model to models/tiselac-mcdcnn-23-0.50.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5412 - accuracy: 0.8284 - val_loss: 0.4976 - val_accuracy: 0.8381
Epoch 24/120
255/256 [============================>.] - ETA: 0s - loss: 0.5374 - accuracy: 0.8294
Epoch 00024: val_loss improved from 0.49764 to 0.49746, saving model to models/tiselac-mcdcnn-24-0.50.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5374 - accuracy: 0.8293 - val_loss: 0.4975 - val_accuracy: 0.8370
Epoch 25/120
254/256 [============================>.] - ETA: 0s - loss: 0.5372 - accuracy: 0.8287
Epoch 00025: val_loss improved from 0.49746 to 0.49323, saving model to models/tiselac-mcdcnn-25-0.49.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5370 - accuracy: 0.8287 - val_loss: 0.4932 - val_accuracy: 0.8407
Epoch 26/120
255/256 [============================>.] - ETA: 0s - loss: 0.5307 - accuracy: 0.8318
Epoch 00026: val_loss improved from 0.49323 to 0.49259, saving model to models/tiselac-mcdcnn-26-0.49.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5305 - accuracy: 0.8318 - val_loss: 0.4926 - val_accuracy: 0.8397
Epoch 27/120
255/256 [============================>.] - ETA: 0s - loss: 0.5288 - accuracy: 0.8328
Epoch 00027: val_loss improved from 0.49259 to 0.49057, saving model to models/tiselac-mcdcnn-27-0.49.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5290 - accuracy: 0.8327 - val_loss: 0.4906 - val_accuracy: 0.8408
Epoch 28/120
254/256 [============================>.] - ETA: 0s - loss: 0.5251 - accuracy: 0.8335
Epoch 00028: val_loss improved from 0.49057 to 0.48951, saving model to models/tiselac-mcdcnn-28-0.49.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5251 - accuracy: 0.8334 - val_loss: 0.4895 - val_accuracy: 0.8403
Epoch 29/120
254/256 [============================>.] - ETA: 0s - loss: 0.5230 - accuracy: 0.8351
Epoch 00029: val_loss did not improve from 0.48951
256/256 [==============================] - 7s 28ms/step - loss: 0.5227 - accuracy: 0.8350 - val_loss: 0.4918 - val_accuracy: 0.8394
Epoch 30/120
255/256 [============================>.] - ETA: 0s - loss: 0.5205 - accuracy: 0.8354
Epoch 00030: val_loss improved from 0.48951 to 0.48408, saving model to models/tiselac-mcdcnn-30-0.48.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5206 - accuracy: 0.8353 - val_loss: 0.4841 - val_accuracy: 0.8415
Epoch 31/120
254/256 [============================>.] - ETA: 0s - loss: 0.5179 - accuracy: 0.8360
Epoch 00031: val_loss improved from 0.48408 to 0.48248, saving model to models/tiselac-mcdcnn-31-0.48.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5177 - accuracy: 0.8361 - val_loss: 0.4825 - val_accuracy: 0.8425
Epoch 32/120
253/256 [============================>.] - ETA: 0s - loss: 0.5167 - accuracy: 0.8352
Epoch 00032: val_loss improved from 0.48248 to 0.47915, saving model to models/tiselac-mcdcnn-32-0.48.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5167 - accuracy: 0.8352 - val_loss: 0.4791 - val_accuracy: 0.8440
Epoch 33/120
253/256 [============================>.] - ETA: 0s - loss: 0.5162 - accuracy: 0.8365
Epoch 00033: val_loss improved from 0.47915 to 0.47896, saving model to models/tiselac-mcdcnn-33-0.48.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5162 - accuracy: 0.8366 - val_loss: 0.4790 - val_accuracy: 0.8444
Epoch 34/120
254/256 [============================>.] - ETA: 0s - loss: 0.5114 - accuracy: 0.8379
Epoch 00034: val_loss improved from 0.47896 to 0.47471, saving model to models/tiselac-mcdcnn-34-0.47.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5111 - accuracy: 0.8380 - val_loss: 0.4747 - val_accuracy: 0.8459
Epoch 35/120
255/256 [============================>.] - ETA: 0s - loss: 0.5093 - accuracy: 0.8375
Epoch 00035: val_loss did not improve from 0.47471
256/256 [==============================] - 7s 28ms/step - loss: 0.5093 - accuracy: 0.8375 - val_loss: 0.4750 - val_accuracy: 0.8458
Epoch 36/120
254/256 [============================>.] - ETA: 0s - loss: 0.5087 - accuracy: 0.8391
Epoch 00036: val_loss improved from 0.47471 to 0.47092, saving model to models/tiselac-mcdcnn-36-0.47.h5
256/256 [==============================] - 7s 29ms/step - loss: 0.5086 - accuracy: 0.8391 - val_loss: 0.4709 - val_accuracy: 0.8456
Epoch 37/120
254/256 [============================>.] - ETA: 0s - loss: 0.5079 - accuracy: 0.8390
Epoch 00037: val_loss improved from 0.47092 to 0.46949, saving model to models/tiselac-mcdcnn-37-0.47.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5078 - accuracy: 0.8390 - val_loss: 0.4695 - val_accuracy: 0.8475
Epoch 38/120
255/256 [============================>.] - ETA: 0s - loss: 0.5052 - accuracy: 0.8394
Epoch 00038: val_loss did not improve from 0.46949
256/256 [==============================] - 7s 28ms/step - loss: 0.5053 - accuracy: 0.8393 - val_loss: 0.4700 - val_accuracy: 0.8476
Epoch 39/120
253/256 [============================>.] - ETA: 0s - loss: 0.5030 - accuracy: 0.8398
Epoch 00039: val_loss improved from 0.46949 to 0.46746, saving model to models/tiselac-mcdcnn-39-0.47.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5031 - accuracy: 0.8398 - val_loss: 0.4675 - val_accuracy: 0.8482
Epoch 40/120
255/256 [============================>.] - ETA: 0s - loss: 0.5010 - accuracy: 0.8414
Epoch 00040: val_loss improved from 0.46746 to 0.46559, saving model to models/tiselac-mcdcnn-40-0.47.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5011 - accuracy: 0.8413 - val_loss: 0.4656 - val_accuracy: 0.8494
Epoch 41/120
255/256 [============================>.] - ETA: 0s - loss: 0.5003 - accuracy: 0.8412
Epoch 00041: val_loss improved from 0.46559 to 0.46448, saving model to models/tiselac-mcdcnn-41-0.46.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.5001 - accuracy: 0.8412 - val_loss: 0.4645 - val_accuracy: 0.8495
Epoch 42/120
254/256 [============================>.] - ETA: 0s - loss: 0.4996 - accuracy: 0.8422
Epoch 00042: val_loss did not improve from 0.46448
256/256 [==============================] - 7s 28ms/step - loss: 0.4994 - accuracy: 0.8423 - val_loss: 0.4645 - val_accuracy: 0.8497
Epoch 43/120
255/256 [============================>.] - ETA: 0s - loss: 0.4972 - accuracy: 0.8427
Epoch 00043: val_loss improved from 0.46448 to 0.46127, saving model to models/tiselac-mcdcnn-43-0.46.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4972 - accuracy: 0.8427 - val_loss: 0.4613 - val_accuracy: 0.8500
Epoch 44/120
255/256 [============================>.] - ETA: 0s - loss: 0.4957 - accuracy: 0.8428
Epoch 00044: val_loss did not improve from 0.46127
256/256 [==============================] - 7s 28ms/step - loss: 0.4956 - accuracy: 0.8428 - val_loss: 0.4622 - val_accuracy: 0.8498
Epoch 45/120
255/256 [============================>.] - ETA: 0s - loss: 0.4927 - accuracy: 0.8431
Epoch 00045: val_loss improved from 0.46127 to 0.46116, saving model to models/tiselac-mcdcnn-45-0.46.h5
256/256 [==============================] - 7s 29ms/step - loss: 0.4925 - accuracy: 0.8431 - val_loss: 0.4612 - val_accuracy: 0.8511
Epoch 46/120
254/256 [============================>.] - ETA: 0s - loss: 0.4945 - accuracy: 0.8432
Epoch 00046: val_loss did not improve from 0.46116
256/256 [==============================] - 7s 28ms/step - loss: 0.4946 - accuracy: 0.8432 - val_loss: 0.4614 - val_accuracy: 0.8507
Epoch 47/120
254/256 [============================>.] - ETA: 0s - loss: 0.4896 - accuracy: 0.8435
Epoch 00047: val_loss improved from 0.46116 to 0.45873, saving model to models/tiselac-mcdcnn-47-0.46.h5
256/256 [==============================] - 7s 29ms/step - loss: 0.4895 - accuracy: 0.8435 - val_loss: 0.4587 - val_accuracy: 0.8523
Epoch 48/120
255/256 [============================>.] - ETA: 0s - loss: 0.4893 - accuracy: 0.8439
Epoch 00048: val_loss improved from 0.45873 to 0.45658, saving model to models/tiselac-mcdcnn-48-0.46.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4893 - accuracy: 0.8439 - val_loss: 0.4566 - val_accuracy: 0.8531
Epoch 49/120
254/256 [============================>.] - ETA: 0s - loss: 0.4899 - accuracy: 0.8435
Epoch 00049: val_loss improved from 0.45658 to 0.45639, saving model to models/tiselac-mcdcnn-49-0.46.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4899 - accuracy: 0.8436 - val_loss: 0.4564 - val_accuracy: 0.8524
Epoch 50/120
255/256 [============================>.] - ETA: 0s - loss: 0.4859 - accuracy: 0.8446
Epoch 00050: val_loss improved from 0.45639 to 0.45336, saving model to models/tiselac-mcdcnn-50-0.45.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4860 - accuracy: 0.8445 - val_loss: 0.4534 - val_accuracy: 0.8540
Epoch 51/120
253/256 [============================>.] - ETA: 0s - loss: 0.4858 - accuracy: 0.8453
Epoch 00051: val_loss did not improve from 0.45336
256/256 [==============================] - 7s 28ms/step - loss: 0.4856 - accuracy: 0.8453 - val_loss: 0.4535 - val_accuracy: 0.8529
Epoch 52/120
253/256 [============================>.] - ETA: 0s - loss: 0.4858 - accuracy: 0.8458
Epoch 00052: val_loss improved from 0.45336 to 0.45016, saving model to models/tiselac-mcdcnn-52-0.45.h5
256/256 [==============================] - 7s 29ms/step - loss: 0.4857 - accuracy: 0.8459 - val_loss: 0.4502 - val_accuracy: 0.8537
Epoch 53/120
255/256 [============================>.] - ETA: 0s - loss: 0.4827 - accuracy: 0.8470
Epoch 00053: val_loss did not improve from 0.45016
256/256 [==============================] - 7s 28ms/step - loss: 0.4827 - accuracy: 0.8469 - val_loss: 0.4511 - val_accuracy: 0.8548
Epoch 54/120
254/256 [============================>.] - ETA: 0s - loss: 0.4833 - accuracy: 0.8463
Epoch 00054: val_loss did not improve from 0.45016
256/256 [==============================] - 7s 28ms/step - loss: 0.4833 - accuracy: 0.8463 - val_loss: 0.4523 - val_accuracy: 0.8534
Epoch 55/120
254/256 [============================>.] - ETA: 0s - loss: 0.4814 - accuracy: 0.8465
Epoch 00055: val_loss improved from 0.45016 to 0.44948, saving model to models/tiselac-mcdcnn-55-0.45.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4813 - accuracy: 0.8466 - val_loss: 0.4495 - val_accuracy: 0.8551
Epoch 56/120
255/256 [============================>.] - ETA: 0s - loss: 0.4803 - accuracy: 0.8475
Epoch 00056: val_loss improved from 0.44948 to 0.44802, saving model to models/tiselac-mcdcnn-56-0.45.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4803 - accuracy: 0.8475 - val_loss: 0.4480 - val_accuracy: 0.8552
Epoch 57/120
254/256 [============================>.] - ETA: 0s - loss: 0.4799 - accuracy: 0.8475
Epoch 00057: val_loss did not improve from 0.44802
256/256 [==============================] - 7s 28ms/step - loss: 0.4798 - accuracy: 0.8475 - val_loss: 0.4486 - val_accuracy: 0.8547
Epoch 58/120
255/256 [============================>.] - ETA: 0s - loss: 0.4794 - accuracy: 0.8472
Epoch 00058: val_loss improved from 0.44802 to 0.44609, saving model to models/tiselac-mcdcnn-58-0.45.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4796 - accuracy: 0.8472 - val_loss: 0.4461 - val_accuracy: 0.8555
Epoch 59/120
253/256 [============================>.] - ETA: 0s - loss: 0.4787 - accuracy: 0.8481
Epoch 00059: val_loss improved from 0.44609 to 0.44532, saving model to models/tiselac-mcdcnn-59-0.45.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4788 - accuracy: 0.8480 - val_loss: 0.4453 - val_accuracy: 0.8550
Epoch 60/120
253/256 [============================>.] - ETA: 0s - loss: 0.4792 - accuracy: 0.8481
Epoch 00060: val_loss did not improve from 0.44532
256/256 [==============================] - 7s 28ms/step - loss: 0.4790 - accuracy: 0.8482 - val_loss: 0.4458 - val_accuracy: 0.8552
Epoch 61/120
254/256 [============================>.] - ETA: 0s - loss: 0.4747 - accuracy: 0.8489
Epoch 00061: val_loss did not improve from 0.44532
256/256 [==============================] - 7s 28ms/step - loss: 0.4746 - accuracy: 0.8489 - val_loss: 0.4454 - val_accuracy: 0.8555
Epoch 62/120
254/256 [============================>.] - ETA: 0s - loss: 0.4746 - accuracy: 0.8491
Epoch 00062: val_loss improved from 0.44532 to 0.44446, saving model to models/tiselac-mcdcnn-62-0.44.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4745 - accuracy: 0.8491 - val_loss: 0.4445 - val_accuracy: 0.8564
Epoch 63/120
254/256 [============================>.] - ETA: 0s - loss: 0.4736 - accuracy: 0.8493
Epoch 00063: val_loss improved from 0.44446 to 0.44325, saving model to models/tiselac-mcdcnn-63-0.44.h5
256/256 [==============================] - 7s 29ms/step - loss: 0.4733 - accuracy: 0.8494 - val_loss: 0.4432 - val_accuracy: 0.8565
Epoch 64/120
255/256 [============================>.] - ETA: 0s - loss: 0.4747 - accuracy: 0.8499
Epoch 00064: val_loss improved from 0.44325 to 0.44210, saving model to models/tiselac-mcdcnn-64-0.44.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4747 - accuracy: 0.8499 - val_loss: 0.4421 - val_accuracy: 0.8564
Epoch 65/120
254/256 [============================>.] - ETA: 0s - loss: 0.4721 - accuracy: 0.8501
Epoch 00065: val_loss improved from 0.44210 to 0.44188, saving model to models/tiselac-mcdcnn-65-0.44.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4719 - accuracy: 0.8501 - val_loss: 0.4419 - val_accuracy: 0.8556
Epoch 66/120
254/256 [============================>.] - ETA: 0s - loss: 0.4695 - accuracy: 0.8497
Epoch 00066: val_loss improved from 0.44188 to 0.44078, saving model to models/tiselac-mcdcnn-66-0.44.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4695 - accuracy: 0.8496 - val_loss: 0.4408 - val_accuracy: 0.8582
Epoch 67/120
253/256 [============================>.] - ETA: 0s - loss: 0.4703 - accuracy: 0.8498
Epoch 00067: val_loss improved from 0.44078 to 0.44019, saving model to models/tiselac-mcdcnn-67-0.44.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4699 - accuracy: 0.8499 - val_loss: 0.4402 - val_accuracy: 0.8576
Epoch 68/120
254/256 [============================>.] - ETA: 0s - loss: 0.4674 - accuracy: 0.8518
Epoch 00068: val_loss improved from 0.44019 to 0.43837, saving model to models/tiselac-mcdcnn-68-0.44.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4673 - accuracy: 0.8518 - val_loss: 0.4384 - val_accuracy: 0.8585
Epoch 69/120
255/256 [============================>.] - ETA: 0s - loss: 0.4715 - accuracy: 0.8498
Epoch 00069: val_loss did not improve from 0.43837
256/256 [==============================] - 7s 28ms/step - loss: 0.4714 - accuracy: 0.8498 - val_loss: 0.4385 - val_accuracy: 0.8584
Epoch 70/120
253/256 [============================>.] - ETA: 0s - loss: 0.4706 - accuracy: 0.8494
Epoch 00070: val_loss improved from 0.43837 to 0.43777, saving model to models/tiselac-mcdcnn-70-0.44.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4706 - accuracy: 0.8493 - val_loss: 0.4378 - val_accuracy: 0.8581
Epoch 71/120
254/256 [============================>.] - ETA: 0s - loss: 0.4672 - accuracy: 0.8515
Epoch 00071: val_loss improved from 0.43777 to 0.43619, saving model to models/tiselac-mcdcnn-71-0.44.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4671 - accuracy: 0.8514 - val_loss: 0.4362 - val_accuracy: 0.8588
Epoch 72/120
253/256 [============================>.] - ETA: 0s - loss: 0.4664 - accuracy: 0.8514
Epoch 00072: val_loss improved from 0.43619 to 0.43513, saving model to models/tiselac-mcdcnn-72-0.44.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4663 - accuracy: 0.8514 - val_loss: 0.4351 - val_accuracy: 0.8588
Epoch 73/120
253/256 [============================>.] - ETA: 0s - loss: 0.4639 - accuracy: 0.8523
Epoch 00073: val_loss improved from 0.43513 to 0.43461, saving model to models/tiselac-mcdcnn-73-0.43.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4639 - accuracy: 0.8522 - val_loss: 0.4346 - val_accuracy: 0.8599
Epoch 74/120
255/256 [============================>.] - ETA: 0s - loss: 0.4649 - accuracy: 0.8525
Epoch 00074: val_loss did not improve from 0.43461
256/256 [==============================] - 7s 28ms/step - loss: 0.4649 - accuracy: 0.8524 - val_loss: 0.4360 - val_accuracy: 0.8589
Epoch 75/120
254/256 [============================>.] - ETA: 0s - loss: 0.4632 - accuracy: 0.8521
Epoch 00075: val_loss improved from 0.43461 to 0.43368, saving model to models/tiselac-mcdcnn-75-0.43.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4633 - accuracy: 0.8521 - val_loss: 0.4337 - val_accuracy: 0.8596
Epoch 76/120
255/256 [============================>.] - ETA: 0s - loss: 0.4652 - accuracy: 0.8521
Epoch 00076: val_loss did not improve from 0.43368
256/256 [==============================] - 7s 28ms/step - loss: 0.4651 - accuracy: 0.8521 - val_loss: 0.4349 - val_accuracy: 0.8588
Epoch 77/120
254/256 [============================>.] - ETA: 0s - loss: 0.4628 - accuracy: 0.8524
Epoch 00077: val_loss did not improve from 0.43368
256/256 [==============================] - 7s 28ms/step - loss: 0.4625 - accuracy: 0.8525 - val_loss: 0.4350 - val_accuracy: 0.8596
Epoch 78/120
255/256 [============================>.] - ETA: 0s - loss: 0.4633 - accuracy: 0.8523
Epoch 00078: val_loss did not improve from 0.43368

Epoch 00078: ReduceLROnPlateau reducing learning rate to 0.0019999999552965165.
256/256 [==============================] - 7s 28ms/step - loss: 0.4632 - accuracy: 0.8523 - val_loss: 0.4349 - val_accuracy: 0.8599
Epoch 79/120
255/256 [============================>.] - ETA: 0s - loss: 0.4599 - accuracy: 0.8525
Epoch 00079: val_loss improved from 0.43368 to 0.43293, saving model to models/tiselac-mcdcnn-79-0.43.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4598 - accuracy: 0.8525 - val_loss: 0.4329 - val_accuracy: 0.8601
Epoch 80/120
253/256 [============================>.] - ETA: 0s - loss: 0.4607 - accuracy: 0.8528
Epoch 00080: val_loss improved from 0.43293 to 0.43159, saving model to models/tiselac-mcdcnn-80-0.43.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4605 - accuracy: 0.8527 - val_loss: 0.4316 - val_accuracy: 0.8606
Epoch 81/120
254/256 [============================>.] - ETA: 0s - loss: 0.4577 - accuracy: 0.8533
Epoch 00081: val_loss improved from 0.43159 to 0.43039, saving model to models/tiselac-mcdcnn-81-0.43.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4575 - accuracy: 0.8533 - val_loss: 0.4304 - val_accuracy: 0.8605
Epoch 82/120
254/256 [============================>.] - ETA: 0s - loss: 0.4595 - accuracy: 0.8525
Epoch 00082: val_loss improved from 0.43039 to 0.42988, saving model to models/tiselac-mcdcnn-82-0.43.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4595 - accuracy: 0.8525 - val_loss: 0.4299 - val_accuracy: 0.8609
Epoch 83/120
254/256 [============================>.] - ETA: 0s - loss: 0.4598 - accuracy: 0.8536
Epoch 00083: val_loss did not improve from 0.42988
256/256 [==============================] - 7s 28ms/step - loss: 0.4598 - accuracy: 0.8536 - val_loss: 0.4303 - val_accuracy: 0.8605
Epoch 84/120
255/256 [============================>.] - ETA: 0s - loss: 0.4598 - accuracy: 0.8532
Epoch 00084: val_loss improved from 0.42988 to 0.42911, saving model to models/tiselac-mcdcnn-84-0.43.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4598 - accuracy: 0.8532 - val_loss: 0.4291 - val_accuracy: 0.8619
Epoch 85/120
254/256 [============================>.] - ETA: 0s - loss: 0.4569 - accuracy: 0.8545
Epoch 00085: val_loss did not improve from 0.42911
256/256 [==============================] - 7s 28ms/step - loss: 0.4564 - accuracy: 0.8546 - val_loss: 0.4296 - val_accuracy: 0.8616
Epoch 86/120
255/256 [============================>.] - ETA: 0s - loss: 0.4567 - accuracy: 0.8551
Epoch 00086: val_loss did not improve from 0.42911
256/256 [==============================] - 7s 28ms/step - loss: 0.4566 - accuracy: 0.8551 - val_loss: 0.4307 - val_accuracy: 0.8608
Epoch 87/120
254/256 [============================>.] - ETA: 0s - loss: 0.4598 - accuracy: 0.8526
Epoch 00087: val_loss improved from 0.42911 to 0.42882, saving model to models/tiselac-mcdcnn-87-0.43.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4597 - accuracy: 0.8527 - val_loss: 0.4288 - val_accuracy: 0.8617
Epoch 88/120
255/256 [============================>.] - ETA: 0s - loss: 0.4583 - accuracy: 0.8530
Epoch 00088: val_loss improved from 0.42882 to 0.42844, saving model to models/tiselac-mcdcnn-88-0.43.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4582 - accuracy: 0.8529 - val_loss: 0.4284 - val_accuracy: 0.8615
Epoch 89/120
254/256 [============================>.] - ETA: 0s - loss: 0.4591 - accuracy: 0.8530
Epoch 00089: val_loss did not improve from 0.42844
256/256 [==============================] - 7s 28ms/step - loss: 0.4591 - accuracy: 0.8530 - val_loss: 0.4288 - val_accuracy: 0.8612
Epoch 90/120
255/256 [============================>.] - ETA: 0s - loss: 0.4589 - accuracy: 0.8538
Epoch 00090: val_loss did not improve from 0.42844
256/256 [==============================] - 7s 28ms/step - loss: 0.4588 - accuracy: 0.8538 - val_loss: 0.4293 - val_accuracy: 0.8611
Epoch 91/120
253/256 [============================>.] - ETA: 0s - loss: 0.4568 - accuracy: 0.8547
Epoch 00091: val_loss improved from 0.42844 to 0.42826, saving model to models/tiselac-mcdcnn-91-0.43.h5
256/256 [==============================] - 7s 28ms/step - loss: 0.4569 - accuracy: 0.8546 - val_loss: 0.4283 - val_accuracy: 0.8614
Epoch 92/120
255/256 [============================>.] - ETA: 0s - loss: 0.4590 - accuracy: 0.8538
Epoch 00092: val_loss did not improve from 0.42826
256/256 [==============================] - 7s 28ms/step - loss: 0.4589 - accuracy: 0.8538 - val_loss: 0.4301 - val_accuracy: 0.8609
Epoch 93/120
254/256 [============================>.] - ETA: 0s - loss: 0.4566 - accuracy: 0.8530
Epoch 00093: val_loss did not improve from 0.42826
256/256 [==============================] - 7s 29ms/step - loss: 0.4565 - accuracy: 0.8529 - val_loss: 0.4300 - val_accuracy: 0.8612
Epoch 94/120
255/256 [============================>.] - ETA: 0s - loss: 0.4558 - accuracy: 0.8551
Epoch 00094: val_loss did not improve from 0.42826

Epoch 00094: ReduceLROnPlateau reducing learning rate to 0.0003999999724328518.
256/256 [==============================] - 7s 28ms/step - loss: 0.4559 - accuracy: 0.8550 - val_loss: 0.4298 - val_accuracy: 0.8613
Epoch 95/120
253/256 [============================>.] - ETA: 0s - loss: 0.4557 - accuracy: 0.8547
Epoch 00095: val_loss did not improve from 0.42826
256/256 [==============================] - 7s 28ms/step - loss: 0.4559 - accuracy: 0.8546 - val_loss: 0.4302 - val_accuracy: 0.8609
Epoch 96/120
253/256 [============================>.] - ETA: 0s - loss: 0.4568 - accuracy: 0.8541
Epoch 00096: val_loss did not improve from 0.42826
256/256 [==============================] - 7s 28ms/step - loss: 0.4566 - accuracy: 0.8541 - val_loss: 0.4296 - val_accuracy: 0.8609
Out[36]:
<tensorflow.python.keras.callbacks.History at 0x28941ccffc8>
Testing the model

We will now test the model on the provided dataset and use a F1 Score metric for it (provided by Sk-Learn).

In [37]:
from sklearn.metrics import f1_score

data_test_np = data_test.to_numpy()

X_test = data_test_np.reshape((data_test_np.shape[0], 23, NUM_OF_FEATURES)).astype(np.float32)

test_gen = data_generator_mcdcnn(X_test, y_test, batch_size=BATCH_SIZE)
test_steps = round(len(X_test) / BATCH_SIZE) + 1
In [38]:
y_pred = mcdcnn_model.predict_generator(test_gen, steps=test_steps)
y_pred = np.argmax(y_pred, axis=1) +1
In [39]:
test_gen = data_generator_mcdcnn(X_test, y_test, batch_size=BATCH_SIZE)
In [40]:
f1_score(y_test.flatten()[:-1], y_pred[:17972], average="weighted")
Out[40]:
0.8687671316110633

2. Time-CNN

Seen as an improvement of the MCDCNN method, by training multivariate time series jointly for better feature extraction, this architecture has been developed in this paper (Zhao B, Lu H, Chen S, Liu J, Wu D , 2017).

Multiple unique characteristics are notable:

  • A MSE loss used with a sigmoid output layer
  • Use of Average pooling instead of Max Pooling
  • No Pooling layer after the last convolution layer before the feature extracted classification
In [41]:
def get_time_cnn(input_shape=(23,10)):
    
    input_l = Input(input_shape)
    x = Conv1D(24, 8, activation="relu")(input_l)
    x = AveragePooling1D(pool_size=3)(x)
    x = Conv1D(24, 4, activation="relu")(x)
    x = Flatten()(x)
    x = Dense(128, activation="relu")(x)
    x = Dropout(0.3)(x)
    x = Dense(64, activation="relu")(x)
    x = BatchNormalization()(x)
    x = Dense(32, activation="relu")(x)
    x = Dense(NUM_OF_CLASSES, activation='sigmoid')(x)
    
    model = Model(input_l, x)
    return model
In [42]:
LR = 0.001
opt = Adam(LR, decay=0)

time_cnn = get_time_cnn()
time_cnn.compile(opt, loss="mse")
In [43]:
model_filename = "tiselac-time-cnn-{epoch:02d}-{val_loss:.2f}.h5"

callbacks = [
    ModelCheckpoint(
        os.path.join("models/", model_filename),
        monitor='val_loss', verbose=1, save_best_only=True, save_freq='epoch'),
    EarlyStopping(monitor='val_loss', min_delta = 1e-4, patience = 5),
    ReduceLROnPlateau(monitor='val_loss', factor=0.2, verbose=1,
                              patience=3, min_lr=0.00001)

]
In [44]:
BATCH_SIZE = 128
EPOCHS = 2000

time_cnn.fit(
    X_train, y_train,
    epochs=EPOCHS,
    batch_size=BATCH_SIZE,
    validation_data=(X_val, y_val),
    callbacks=callbacks
)
Train on 65371 samples, validate on 16343 samples
Epoch 1/2000
64512/65371 [============================>.] - ETA: 0s - loss: 0.0570
Epoch 00001: val_loss improved from inf to 0.03589, saving model to models/tiselac-time-cnn-01-0.04.h5
65371/65371 [==============================] - 4s 54us/sample - loss: 0.0567 - val_loss: 0.0359
Epoch 2/2000
65024/65371 [============================>.] - ETA: 0s - loss: 0.0359
Epoch 00002: val_loss improved from 0.03589 to 0.03257, saving model to models/tiselac-time-cnn-02-0.03.h5
65371/65371 [==============================] - 2s 32us/sample - loss: 0.0359 - val_loss: 0.0326
Epoch 3/2000
65024/65371 [============================>.] - ETA: 0s - loss: 0.0327
Epoch 00003: val_loss improved from 0.03257 to 0.03102, saving model to models/tiselac-time-cnn-03-0.03.h5
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0327 - val_loss: 0.0310
Epoch 4/2000
64256/65371 [============================>.] - ETA: 0s - loss: 0.0309
Epoch 00004: val_loss improved from 0.03102 to 0.02984, saving model to models/tiselac-time-cnn-04-0.03.h5
65371/65371 [==============================] - 2s 32us/sample - loss: 0.0309 - val_loss: 0.0298
Epoch 5/2000
63616/65371 [============================>.] - ETA: 0s - loss: 0.0295
Epoch 00005: val_loss improved from 0.02984 to 0.02868, saving model to models/tiselac-time-cnn-05-0.03.h5
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0295 - val_loss: 0.0287
Epoch 6/2000
63744/65371 [============================>.] - ETA: 0s - loss: 0.0287
Epoch 00006: val_loss did not improve from 0.02868
65371/65371 [==============================] - 2s 32us/sample - loss: 0.0287 - val_loss: 0.0305
Epoch 7/2000
64384/65371 [============================>.] - ETA: 0s - loss: 0.0278
Epoch 00007: val_loss improved from 0.02868 to 0.02738, saving model to models/tiselac-time-cnn-07-0.03.h5
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0278 - val_loss: 0.0274
Epoch 8/2000
63872/65371 [============================>.] - ETA: 0s - loss: 0.0272
Epoch 00008: val_loss did not improve from 0.02738
65371/65371 [==============================] - 2s 32us/sample - loss: 0.0272 - val_loss: 0.0286
Epoch 9/2000
64640/65371 [============================>.] - ETA: 0s - loss: 0.0265
Epoch 00009: val_loss did not improve from 0.02738
65371/65371 [==============================] - 2s 32us/sample - loss: 0.0265 - val_loss: 0.0300
Epoch 10/2000
64640/65371 [============================>.] - ETA: 0s - loss: 0.0262
Epoch 00010: val_loss did not improve from 0.02738

Epoch 00010: ReduceLROnPlateau reducing learning rate to 0.00020000000949949026.
65371/65371 [==============================] - 2s 32us/sample - loss: 0.0262 - val_loss: 0.0274
Epoch 11/2000
64512/65371 [============================>.] - ETA: 0s - loss: 0.0243
Epoch 00011: val_loss improved from 0.02738 to 0.02412, saving model to models/tiselac-time-cnn-11-0.02.h5
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0242 - val_loss: 0.0241
Epoch 12/2000
64384/65371 [============================>.] - ETA: 0s - loss: 0.0239
Epoch 00012: val_loss improved from 0.02412 to 0.02396, saving model to models/tiselac-time-cnn-12-0.02.h5
65371/65371 [==============================] - 2s 34us/sample - loss: 0.0239 - val_loss: 0.0240
Epoch 13/2000
64128/65371 [============================>.] - ETA: 0s - loss: 0.0237
Epoch 00013: val_loss improved from 0.02396 to 0.02348, saving model to models/tiselac-time-cnn-13-0.02.h5
65371/65371 [==============================] - 2s 34us/sample - loss: 0.0236 - val_loss: 0.0235
Epoch 14/2000
64768/65371 [============================>.] - ETA: 0s - loss: 0.0234
Epoch 00014: val_loss did not improve from 0.02348
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0234 - val_loss: 0.0245
Epoch 15/2000
65152/65371 [============================>.] - ETA: 0s - loss: 0.0233
Epoch 00015: val_loss did not improve from 0.02348
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0233 - val_loss: 0.0243
Epoch 16/2000
63616/65371 [============================>.] - ETA: 0s - loss: 0.0233
Epoch 00016: val_loss improved from 0.02348 to 0.02328, saving model to models/tiselac-time-cnn-16-0.02.h5
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0233 - val_loss: 0.0233
Epoch 17/2000
65280/65371 [============================>.] - ETA: 0s - loss: 0.0231
Epoch 00017: val_loss improved from 0.02328 to 0.02321, saving model to models/tiselac-time-cnn-17-0.02.h5
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0231 - val_loss: 0.0232
Epoch 18/2000
64128/65371 [============================>.] - ETA: 0s - loss: 0.0230
Epoch 00018: val_loss did not improve from 0.02321
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0230 - val_loss: 0.0232
Epoch 19/2000
64128/65371 [============================>.] - ETA: 0s - loss: 0.0229
Epoch 00019: val_loss did not improve from 0.02321

Epoch 00019: ReduceLROnPlateau reducing learning rate to 4.0000001899898055e-05.
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0229 - val_loss: 0.0233
Epoch 20/2000
64384/65371 [============================>.] - ETA: 0s - loss: 0.0223
Epoch 00020: val_loss improved from 0.02321 to 0.02256, saving model to models/tiselac-time-cnn-20-0.02.h5
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0223 - val_loss: 0.0226
Epoch 21/2000
64512/65371 [============================>.] - ETA: 0s - loss: 0.0222
Epoch 00021: val_loss improved from 0.02256 to 0.02247, saving model to models/tiselac-time-cnn-21-0.02.h5
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0223 - val_loss: 0.0225
Epoch 22/2000
64640/65371 [============================>.] - ETA: 0s - loss: 0.0222
Epoch 00022: val_loss improved from 0.02247 to 0.02242, saving model to models/tiselac-time-cnn-22-0.02.h5
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0223 - val_loss: 0.0224
Epoch 23/2000
64768/65371 [============================>.] - ETA: 0s - loss: 0.0222
Epoch 00023: val_loss improved from 0.02242 to 0.02240, saving model to models/tiselac-time-cnn-23-0.02.h5
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0222 - val_loss: 0.0224
Epoch 24/2000
64256/65371 [============================>.] - ETA: 0s - loss: 0.0223
Epoch 00024: val_loss did not improve from 0.02240
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0223 - val_loss: 0.0224
Epoch 25/2000
63872/65371 [============================>.] - ETA: 0s - loss: 0.0221
Epoch 00025: val_loss improved from 0.02240 to 0.02237, saving model to models/tiselac-time-cnn-25-0.02.h5

Epoch 00025: ReduceLROnPlateau reducing learning rate to 1e-05.
65371/65371 [==============================] - 3s 52us/sample - loss: 0.0221 - val_loss: 0.0224
Epoch 26/2000
63616/65371 [============================>.] - ETA: 0s - loss: 0.0220
Epoch 00026: val_loss improved from 0.02237 to 0.02231, saving model to models/tiselac-time-cnn-26-0.02.h5
65371/65371 [==============================] - 2s 34us/sample - loss: 0.0220 - val_loss: 0.0223
Epoch 27/2000
65024/65371 [============================>.] - ETA: 0s - loss: 0.0220
Epoch 00027: val_loss improved from 0.02231 to 0.02230, saving model to models/tiselac-time-cnn-27-0.02.h5
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0220 - val_loss: 0.0223
Epoch 28/2000
64256/65371 [============================>.] - ETA: 0s - loss: 0.0221
Epoch 00028: val_loss did not improve from 0.02230
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0220 - val_loss: 0.0223
Epoch 29/2000
64512/65371 [============================>.] - ETA: 0s - loss: 0.0220
Epoch 00029: val_loss did not improve from 0.02230
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0220 - val_loss: 0.0223
Epoch 30/2000
65280/65371 [============================>.] - ETA: 0s - loss: 0.0219
Epoch 00030: val_loss did not improve from 0.02230
65371/65371 [==============================] - 2s 33us/sample - loss: 0.0219 - val_loss: 0.0223
Epoch 31/2000
65152/65371 [============================>.] - ETA: 0s - loss: 0.0220
Epoch 00031: val_loss improved from 0.02230 to 0.02227, saving model to models/tiselac-time-cnn-31-0.02.h5
65371/65371 [==============================] - 2s 35us/sample - loss: 0.0220 - val_loss: 0.0223
Out[44]:
<tensorflow.python.keras.callbacks.History at 0x28978652b88>
Testing the model

We will now test the model on the provided dataset and use a F1 Score metric for it (provided by Sk-Learn).

In [45]:
from sklearn.metrics import f1_score

data_test_np = data_test.to_numpy()

X_test = data_test_np.reshape((data_test_np.shape[0], 23, NUM_OF_FEATURES)).astype(np.float32)
In [46]:
y_pred = time_cnn.predict(X_test)
y_pred = np.argmax(y_pred, axis=1) +1
In [47]:
f1_score(y_test.flatten(), y_pred, average="weighted")
Out[47]:
0.8731067419980513

Merge of Multimodal/Unimodal architecture

We will first work with Deep Learning oriented solution and try implementing an LSTM on this data. Let's setup our working environment with the adequate hyperparameters.

In [48]:
LR = 0.001
BATCH_SIZE = 256
EPOCHS = 50
VAL_SIZE = 0.1

Setting up the data (splitting into training and validation sets)

In [49]:
scaler_coord = StandardScaler()

# Formatting the X data
data_train = data.to_numpy()
#data_train = minmax_scaler.fit_transform(data_train)

data_coord = coord.to_numpy().astype(np.int32).reshape(-1, 2)
data_coord = scaler_coord.fit_transform(data_coord)


X = data_train.reshape((NUM_OF_PIXELS, 23, NUM_OF_FEATURES)).astype(np.int32)


# Formatting the y data
classes_train = classes_val.to_numpy().astype(np.uint8)
enc = OneHotEncoder(handle_unknown='ignore', sparse=False)
y = enc.fit_transform(classes_train).astype(np.uint8)
In [50]:
# Splitting x and y into training and validation sets
indices = np.arange(X.shape[0])
X_train, X_val, y_train, y_val, idx_train, idx_val = train_test_split(X, y, indices, test_size = VAL_SIZE)
In [51]:
X_train_formatted = [
    X_train, 
    #X_train
    data_coord[idx_train]
]
X_train_formatted.extend([np.expand_dims(X_train[:,:,i], axis=2) for i in range(10)])

X_val_formatted = [
    X_val, 
    #X_val
    data_coord[idx_val]
]
X_val_formatted.extend([np.expand_dims(X_val[:,:,i], axis=2) for i in range(10)])

Setting up the model

In [52]:
model_filename = "tiselac-time-cnn-{epoch:02d}-{val_loss:.2f}.h5"

callbacks = [
    ModelCheckpoint(
        os.path.join("models/", model_filename),
        monitor='val_loss', verbose=1, save_best_only=True, save_freq='epoch'),
    #EarlyStopping(monitor='val_loss', min_delta = 1e-3, patience = 6),
    ReduceLROnPlateau(monitor='val_loss', factor=0.2, verbose=1,
                              patience=3, min_lr=0.00001)


]

In [53]:
def get_multivariate_model():
    """
        Treats the data of each band as a multimodal time serie
    """
    input_lstm = Input((23, 10))
    #lstm = LSTM(512, input_shape=(23, 10))(input_lstm)
    
    conv = Conv1D(32, 3, padding="same", activation="relu")(input_lstm)
    conv = Conv1D(32, 3, padding="same", activation="relu")(conv)
    conv = Conv1D(32, 3, padding="same", activation="relu")(conv)
    flat = Flatten()(conv)
    
    return Model(inputs=input_lstm,outputs=flat)

def get_coordinates_model():
    """
        Treats the pixel coordinates on the image
    """
    input_seq = Input(shape=(2,))

    #x = Conv1D(32, 3, padding="same", activation="relu")(input_seq)
    #x = MaxPooling1D()(x)
    #x = Conv1D(32, 3, padding="same", activation="relu")(x)
    
    return Model(inputs=input_seq, outputs=input_seq)

def get_univariate_models():
    """
        Treats each band independently then concatenate models in one single
    """
    # Models built for each band
    inputs = [Input((23,1)) for _ in range(10)]
    convs1 = [Conv1D(8,3,padding="same",activation="relu")(inputs[i]) for i in range(10)]    
    pools = [MaxPooling1D()(convs1[i]) for i in range(10)]
    convs2 = [Conv1D(4,3,padding="same",activation="relu")(pools[i]) for i in range(10)]
    pools = [MaxPooling1D()(convs2[i]) for i in range(10)]
    flatt = [Flatten()(pools[i]) for i in range(10)]
    
    
    # First concatenate: each band at the first convolutional level
    conca1 = Concatenate()(convs1)
    conv1 = Conv1D(8,10,padding="same",activation="relu")(conca1)
    flatt1 = Flatten()(conv1)
    flatt.append(flatt1)
    
    # Second concatenate: each band at the second convolutional level
    conca2 = Concatenate()(convs2)
    conv2 = Conv1D(4,10,padding="same",activation="relu")(conca2)
    flatt2 = Flatten()(conv2)
    flatt.append(flatt2)
    
    # Third and last concatenate after every flatten, adding the process of the first and second concats
    conca3 = Concatenate()(flatt)
    
    return Model(inputs=inputs, outputs=conca3)
    
# Merging inputs from the time series and the pixel position
mult_model = get_multivariate_model()
coord_model = get_coordinates_model()
univ_models = get_univariate_models()


merged = Concatenate(axis=-1)([
    mult_model.output, 
    coord_model.output, 
    univ_models.output])

x = Dense(256, activation="relu")(merged)
x = Dense(128, activation="relu")(x)
x = Dropout(0.3)(x)
x = Dense(64, activation="relu")(x)
x = Dropout(0.3)(x)
x = Dense(32, activation="relu")(x)
out = Dense(NUM_OF_CLASSES, activation='softmax')(x)

model = Model(inputs=[
    mult_model.input, 
    coord_model.input, 
    univ_models.input], outputs=[out])

opt = Adam(LR)

model.compile(opt, loss="categorical_crossentropy",
    metrics=['categorical_accuracy'])
In [54]:
model.fit(
    X_train_formatted, y_train, batch_size=BATCH_SIZE, epochs=EPOCHS, verbose=1, 
    callbacks=callbacks, 
    validation_data=(X_val_formatted, y_val))
Train on 73542 samples, validate on 8172 samples
Epoch 1/50
73216/73542 [============================>.] - ETA: 0s - loss: 1.9781 - categorical_accuracy: 0.5942
Epoch 00001: val_loss improved from inf to 0.79496, saving model to models/tiselac-time-cnn-01-0.79.h5
73542/73542 [==============================] - 8s 106us/sample - loss: 1.9741 - categorical_accuracy: 0.5946 - val_loss: 0.7950 - val_categorical_accuracy: 0.7521
Epoch 2/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.8818 - categorical_accuracy: 0.7344
Epoch 00002: val_loss improved from 0.79496 to 0.69212, saving model to models/tiselac-time-cnn-02-0.69.h5
73542/73542 [==============================] - 3s 41us/sample - loss: 0.8808 - categorical_accuracy: 0.7348 - val_loss: 0.6921 - val_categorical_accuracy: 0.7912
Epoch 3/50
73216/73542 [============================>.] - ETA: 0s - loss: 0.7433 - categorical_accuracy: 0.7783
Epoch 00003: val_loss improved from 0.69212 to 0.58370, saving model to models/tiselac-time-cnn-03-0.58.h5
73542/73542 [==============================] - 3s 43us/sample - loss: 0.7430 - categorical_accuracy: 0.7785 - val_loss: 0.5837 - val_categorical_accuracy: 0.8235
Epoch 4/50
72192/73542 [============================>.] - ETA: 0s - loss: 0.6631 - categorical_accuracy: 0.8026
Epoch 00004: val_loss improved from 0.58370 to 0.55157, saving model to models/tiselac-time-cnn-04-0.55.h5
73542/73542 [==============================] - 3s 42us/sample - loss: 0.6631 - categorical_accuracy: 0.8026 - val_loss: 0.5516 - val_categorical_accuracy: 0.8310
Epoch 5/50
72448/73542 [============================>.] - ETA: 0s - loss: 0.6023 - categorical_accuracy: 0.8209
Epoch 00005: val_loss improved from 0.55157 to 0.54354, saving model to models/tiselac-time-cnn-05-0.54.h5
73542/73542 [==============================] - 3s 43us/sample - loss: 0.6019 - categorical_accuracy: 0.8209 - val_loss: 0.5435 - val_categorical_accuracy: 0.8325
Epoch 6/50
72192/73542 [============================>.] - ETA: 0s - loss: 0.5447 - categorical_accuracy: 0.8385
Epoch 00006: val_loss improved from 0.54354 to 0.52418, saving model to models/tiselac-time-cnn-06-0.52.h5
73542/73542 [==============================] - 3s 42us/sample - loss: 0.5455 - categorical_accuracy: 0.8382 - val_loss: 0.5242 - val_categorical_accuracy: 0.8500
Epoch 7/50
73472/73542 [============================>.] - ETA: 0s - loss: 0.5109 - categorical_accuracy: 0.8463
Epoch 00007: val_loss improved from 0.52418 to 0.46064, saving model to models/tiselac-time-cnn-07-0.46.h5
73542/73542 [==============================] - 3s 43us/sample - loss: 0.5108 - categorical_accuracy: 0.8464 - val_loss: 0.4606 - val_categorical_accuracy: 0.8655
Epoch 8/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.4770 - categorical_accuracy: 0.8581 ETA: 0s - loss: 0.4788 - cate
Epoch 00008: val_loss did not improve from 0.46064
73542/73542 [==============================] - 3s 41us/sample - loss: 0.4770 - categorical_accuracy: 0.8582 - val_loss: 0.4785 - val_categorical_accuracy: 0.8486
Epoch 9/50
72704/73542 [============================>.] - ETA: 0s - loss: 0.4532 - categorical_accuracy: 0.8632
Epoch 00009: val_loss improved from 0.46064 to 0.43217, saving model to models/tiselac-time-cnn-09-0.43.h5
73542/73542 [==============================] - 4s 52us/sample - loss: 0.4530 - categorical_accuracy: 0.8633 - val_loss: 0.4322 - val_categorical_accuracy: 0.8642
Epoch 10/50
72704/73542 [============================>.] - ETA: 0s - loss: 0.4306 - categorical_accuracy: 0.8693
Epoch 00010: val_loss improved from 0.43217 to 0.40136, saving model to models/tiselac-time-cnn-10-0.40.h5
73542/73542 [==============================] - 4s 54us/sample - loss: 0.4303 - categorical_accuracy: 0.8694 - val_loss: 0.4014 - val_categorical_accuracy: 0.8697
Epoch 11/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.4062 - categorical_accuracy: 0.8763
Epoch 00011: val_loss improved from 0.40136 to 0.39100, saving model to models/tiselac-time-cnn-11-0.39.h5
73542/73542 [==============================] - 4s 50us/sample - loss: 0.4058 - categorical_accuracy: 0.8765 - val_loss: 0.3910 - val_categorical_accuracy: 0.8747
Epoch 12/50
73472/73542 [============================>.] - ETA: 0s - loss: 0.3885 - categorical_accuracy: 0.8813
Epoch 00012: val_loss improved from 0.39100 to 0.37096, saving model to models/tiselac-time-cnn-12-0.37.h5
73542/73542 [==============================] - 3s 44us/sample - loss: 0.3886 - categorical_accuracy: 0.8812 - val_loss: 0.3710 - val_categorical_accuracy: 0.8841
Epoch 13/50
73472/73542 [============================>.] - ETA: 0s - loss: 0.3713 - categorical_accuracy: 0.8866 ETA: 0s - loss: 0.370
Epoch 00013: val_loss improved from 0.37096 to 0.36854, saving model to models/tiselac-time-cnn-13-0.37.h5
73542/73542 [==============================] - 3s 43us/sample - loss: 0.3712 - categorical_accuracy: 0.8867 - val_loss: 0.3685 - val_categorical_accuracy: 0.8835
Epoch 14/50
72704/73542 [============================>.] - ETA: 0s - loss: 0.3493 - categorical_accuracy: 0.8932
Epoch 00014: val_loss improved from 0.36854 to 0.35564, saving model to models/tiselac-time-cnn-14-0.36.h5
73542/73542 [==============================] - 3s 43us/sample - loss: 0.3492 - categorical_accuracy: 0.8932 - val_loss: 0.3556 - val_categorical_accuracy: 0.8842
Epoch 15/50
72704/73542 [============================>.] - ETA: 0s - loss: 0.3346 - categorical_accuracy: 0.8972
Epoch 00015: val_loss improved from 0.35564 to 0.34797, saving model to models/tiselac-time-cnn-15-0.35.h5
73542/73542 [==============================] - 3s 44us/sample - loss: 0.3342 - categorical_accuracy: 0.8973 - val_loss: 0.3480 - val_categorical_accuracy: 0.8891
Epoch 16/50
72448/73542 [============================>.] - ETA: 0s - loss: 0.3189 - categorical_accuracy: 0.9017
Epoch 00016: val_loss improved from 0.34797 to 0.34168, saving model to models/tiselac-time-cnn-16-0.34.h5
73542/73542 [==============================] - 3s 46us/sample - loss: 0.3188 - categorical_accuracy: 0.9017 - val_loss: 0.3417 - val_categorical_accuracy: 0.8897
Epoch 17/50
72704/73542 [============================>.] - ETA: 0s - loss: 0.3097 - categorical_accuracy: 0.9036
Epoch 00017: val_loss improved from 0.34168 to 0.32338, saving model to models/tiselac-time-cnn-17-0.32.h5
73542/73542 [==============================] - 3s 45us/sample - loss: 0.3092 - categorical_accuracy: 0.9038 - val_loss: 0.3234 - val_categorical_accuracy: 0.8992
Epoch 18/50
73216/73542 [============================>.] - ETA: 0s - loss: 0.2874 - categorical_accuracy: 0.9099
Epoch 00018: val_loss improved from 0.32338 to 0.32321, saving model to models/tiselac-time-cnn-18-0.32.h5
73542/73542 [==============================] - 3s 44us/sample - loss: 0.2872 - categorical_accuracy: 0.9099 - val_loss: 0.3232 - val_categorical_accuracy: 0.8964
Epoch 19/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.2837 - categorical_accuracy: 0.9117
Epoch 00019: val_loss improved from 0.32321 to 0.31063, saving model to models/tiselac-time-cnn-19-0.31.h5
73542/73542 [==============================] - 3s 44us/sample - loss: 0.2835 - categorical_accuracy: 0.9117 - val_loss: 0.3106 - val_categorical_accuracy: 0.9021
Epoch 20/50
72448/73542 [============================>.] - ETA: 0s - loss: 0.2675 - categorical_accuracy: 0.9166
Epoch 00020: val_loss did not improve from 0.31063
73542/73542 [==============================] - 3s 42us/sample - loss: 0.2670 - categorical_accuracy: 0.9167 - val_loss: 0.3279 - val_categorical_accuracy: 0.9010
Epoch 21/50
73216/73542 [============================>.] - ETA: 0s - loss: 0.2632 - categorical_accuracy: 0.9187
Epoch 00021: val_loss improved from 0.31063 to 0.30411, saving model to models/tiselac-time-cnn-21-0.30.h5
73542/73542 [==============================] - 3s 44us/sample - loss: 0.2629 - categorical_accuracy: 0.9188 - val_loss: 0.3041 - val_categorical_accuracy: 0.9049
Epoch 22/50
73472/73542 [============================>.] - ETA: 0s - loss: 0.2439 - categorical_accuracy: 0.9239
Epoch 00022: val_loss did not improve from 0.30411
73542/73542 [==============================] - 3s 42us/sample - loss: 0.2438 - categorical_accuracy: 0.9239 - val_loss: 0.3054 - val_categorical_accuracy: 0.9071
Epoch 23/50
73216/73542 [============================>.] - ETA: 0s - loss: 0.2336 - categorical_accuracy: 0.9269
Epoch 00023: val_loss improved from 0.30411 to 0.30352, saving model to models/tiselac-time-cnn-23-0.30.h5
73542/73542 [==============================] - 3s 45us/sample - loss: 0.2337 - categorical_accuracy: 0.9269 - val_loss: 0.3035 - val_categorical_accuracy: 0.9092
Epoch 24/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.2303 - categorical_accuracy: 0.9279
Epoch 00024: val_loss did not improve from 0.30352
73542/73542 [==============================] - 3s 42us/sample - loss: 0.2302 - categorical_accuracy: 0.9280 - val_loss: 0.3063 - val_categorical_accuracy: 0.9039
Epoch 25/50
73216/73542 [============================>.] - ETA: 0s - loss: 0.2156 - categorical_accuracy: 0.9316
Epoch 00025: val_loss improved from 0.30352 to 0.28555, saving model to models/tiselac-time-cnn-25-0.29.h5
73542/73542 [==============================] - 3s 45us/sample - loss: 0.2157 - categorical_accuracy: 0.9316 - val_loss: 0.2856 - val_categorical_accuracy: 0.9123
Epoch 26/50
72448/73542 [============================>.] - ETA: 0s - loss: 0.2075 - categorical_accuracy: 0.9352
Epoch 00026: val_loss did not improve from 0.28555
73542/73542 [==============================] - 3s 43us/sample - loss: 0.2080 - categorical_accuracy: 0.9351 - val_loss: 0.2901 - val_categorical_accuracy: 0.9158
Epoch 27/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.2013 - categorical_accuracy: 0.9367
Epoch 00027: val_loss did not improve from 0.28555
73542/73542 [==============================] - 3s 43us/sample - loss: 0.2012 - categorical_accuracy: 0.9366 - val_loss: 0.2883 - val_categorical_accuracy: 0.9150
Epoch 28/50
72704/73542 [============================>.] - ETA: 0s - loss: 0.1926 - categorical_accuracy: 0.9397
Epoch 00028: val_loss did not improve from 0.28555

Epoch 00028: ReduceLROnPlateau reducing learning rate to 0.00020000000949949026.
73542/73542 [==============================] - 3s 43us/sample - loss: 0.1927 - categorical_accuracy: 0.9397 - val_loss: 0.3009 - val_categorical_accuracy: 0.9158
Epoch 29/50
72448/73542 [============================>.] - ETA: 0s - loss: 0.1386 - categorical_accuracy: 0.9561
Epoch 00029: val_loss improved from 0.28555 to 0.26413, saving model to models/tiselac-time-cnn-29-0.26.h5
73542/73542 [==============================] - 3s 44us/sample - loss: 0.1384 - categorical_accuracy: 0.9561 - val_loss: 0.2641 - val_categorical_accuracy: 0.9300
Epoch 30/50
73216/73542 [============================>.] - ETA: 0s - loss: 0.1210 - categorical_accuracy: 0.9615
Epoch 00030: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.1210 - categorical_accuracy: 0.9615 - val_loss: 0.2706 - val_categorical_accuracy: 0.9294
Epoch 31/50
72704/73542 [============================>.] - ETA: 0s - loss: 0.1126 - categorical_accuracy: 0.9645
Epoch 00031: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.1127 - categorical_accuracy: 0.9645 - val_loss: 0.2761 - val_categorical_accuracy: 0.9288
Epoch 32/50
72448/73542 [============================>.] - ETA: 0s - loss: 0.1083 - categorical_accuracy: 0.9657
Epoch 00032: val_loss did not improve from 0.26413

Epoch 00032: ReduceLROnPlateau reducing learning rate to 4.0000001899898055e-05.
73542/73542 [==============================] - 3s 43us/sample - loss: 0.1084 - categorical_accuracy: 0.9657 - val_loss: 0.2826 - val_categorical_accuracy: 0.9288
Epoch 33/50
72704/73542 [============================>.] - ETA: 0s - loss: 0.0948 - categorical_accuracy: 0.9699
Epoch 00033: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 42us/sample - loss: 0.0950 - categorical_accuracy: 0.9699 - val_loss: 0.2846 - val_categorical_accuracy: 0.9307
Epoch 34/50
73472/73542 [============================>.] - ETA: 0s - loss: 0.0904 - categorical_accuracy: 0.9715
Epoch 00034: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0904 - categorical_accuracy: 0.9715 - val_loss: 0.2887 - val_categorical_accuracy: 0.9318
Epoch 35/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.0897 - categorical_accuracy: 0.9715
Epoch 00035: val_loss did not improve from 0.26413

Epoch 00035: ReduceLROnPlateau reducing learning rate to 1e-05.
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0896 - categorical_accuracy: 0.9715 - val_loss: 0.2891 - val_categorical_accuracy: 0.9322
Epoch 36/50
73216/73542 [============================>.] - ETA: 0s - loss: 0.0869 - categorical_accuracy: 0.9728
Epoch 00036: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0869 - categorical_accuracy: 0.9728 - val_loss: 0.2897 - val_categorical_accuracy: 0.9317
Epoch 37/50
72448/73542 [============================>.] - ETA: 0s - loss: 0.0852 - categorical_accuracy: 0.9730
Epoch 00037: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0849 - categorical_accuracy: 0.9731 - val_loss: 0.2899 - val_categorical_accuracy: 0.9337
Epoch 38/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.0850 - categorical_accuracy: 0.9729
Epoch 00038: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0849 - categorical_accuracy: 0.9728 - val_loss: 0.2921 - val_categorical_accuracy: 0.9333
Epoch 39/50
73216/73542 [============================>.] - ETA: 0s - loss: 0.0846 - categorical_accuracy: 0.9735
Epoch 00039: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0845 - categorical_accuracy: 0.9735 - val_loss: 0.2950 - val_categorical_accuracy: 0.9328
Epoch 40/50
72704/73542 [============================>.] - ETA: 0s - loss: 0.0837 - categorical_accuracy: 0.9735
Epoch 00040: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0837 - categorical_accuracy: 0.9734 - val_loss: 0.2955 - val_categorical_accuracy: 0.9333
Epoch 41/50
73472/73542 [============================>.] - ETA: 0s - loss: 0.0834 - categorical_accuracy: 0.9740
Epoch 00041: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0834 - categorical_accuracy: 0.9740 - val_loss: 0.2953 - val_categorical_accuracy: 0.9328
Epoch 42/50
72448/73542 [============================>.] - ETA: 0s - loss: 0.0836 - categorical_accuracy: 0.9736
Epoch 00042: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0835 - categorical_accuracy: 0.9736 - val_loss: 0.2972 - val_categorical_accuracy: 0.9327
Epoch 43/50
72704/73542 [============================>.] - ETA: 0s - loss: 0.0831 - categorical_accuracy: 0.9736
Epoch 00043: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0831 - categorical_accuracy: 0.9735 - val_loss: 0.2984 - val_categorical_accuracy: 0.9326
Epoch 44/50
72192/73542 [============================>.] - ETA: 0s - loss: 0.0831 - categorical_accuracy: 0.9734
Epoch 00044: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0827 - categorical_accuracy: 0.9736 - val_loss: 0.2989 - val_categorical_accuracy: 0.9318
Epoch 45/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.0813 - categorical_accuracy: 0.9745
Epoch 00045: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0812 - categorical_accuracy: 0.9745 - val_loss: 0.2996 - val_categorical_accuracy: 0.9329
Epoch 46/50
72192/73542 [============================>.] - ETA: 0s - loss: 0.0809 - categorical_accuracy: 0.9746
Epoch 00046: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0809 - categorical_accuracy: 0.9746 - val_loss: 0.3011 - val_categorical_accuracy: 0.9334
Epoch 47/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.0802 - categorical_accuracy: 0.9749
Epoch 00047: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0802 - categorical_accuracy: 0.9749 - val_loss: 0.3013 - val_categorical_accuracy: 0.9322
Epoch 48/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.0797 - categorical_accuracy: 0.9746
Epoch 00048: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0797 - categorical_accuracy: 0.9746 - val_loss: 0.3024 - val_categorical_accuracy: 0.9326
Epoch 49/50
72960/73542 [============================>.] - ETA: 0s - loss: 0.0797 - categorical_accuracy: 0.9754
Epoch 00049: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 44us/sample - loss: 0.0799 - categorical_accuracy: 0.9754 - val_loss: 0.3034 - val_categorical_accuracy: 0.9328
Epoch 50/50
73216/73542 [============================>.] - ETA: 0s - loss: 0.0799 - categorical_accuracy: 0.9749
Epoch 00050: val_loss did not improve from 0.26413
73542/73542 [==============================] - 3s 43us/sample - loss: 0.0800 - categorical_accuracy: 0.9748 - val_loss: 0.3041 - val_categorical_accuracy: 0.9321
Out[54]:
<tensorflow.python.keras.callbacks.History at 0x288f272ec88>

Testing the model

We will now test the model on the provided dataset and use a F1 Score metric for it (provided by Sk-Learn).

In [55]:
from sklearn.metrics import f1_score, confusion_matrix

data_test_np = data_test.to_numpy()
#data_test_np = data_test_np.transform(minmax_scaler)

X_test = data_test_np.reshape((data_test_np.shape[0], 23, NUM_OF_FEATURES)).astype(np.float32)
coord_test_np = coord_test.to_numpy().astype(np.int32).reshape(-1, 2)
coord_test_np = scaler_coord.transform(coord_test_np)

univariate_bands = [np.expand_dims(X_test[:,:,i], axis=2) for i in range(10)]

X_test = [
    X_test, 
    #X_test
    coord_test_np
]
X_test.extend(univariate_bands)

y_pred = model.predict(X_test)
y_pred = np.argmax(y_pred, axis=1) +1

We evaluate the F1 score to compare with other teams result in the context of the TiSeLaC challenge.

In [56]:
f1_score(y_test.flatten(), y_pred, average="weighted")
Out[56]:
0.9338552920515625

To have better insights on which classes are often misclassified, we will plot a confusion matrix using seaborn and sklearn.

In [57]:
m = confusion_matrix(y_test.flatten(), y_pred)
m_pd = pd.DataFrame(m)
classes_as_dict = {i: CLASSES[i] for i in range(9)}
m_pd = m_pd.rename(columns=classes_as_dict, index=classes_as_dict)
In [58]:
figs, axs = plt.subplots(figsize=(20,20))
sns.heatmap(m_pd, ax=axs, annot=True)
Out[58]:
<matplotlib.axes._subplots.AxesSubplot at 0x289d6e27c08>