ML/AI Wildfire Prediction

wildfireforest firebushfirewildland fire or rural fire is an unplanned, uncontrolled and unpredictable fire in an area of combustible vegetation starting in rural and urban areas.

Wildland fire is a widespread and critical element of the Earth’s system. Presently, global annual area burned is estimated to be approximately 420 Mha (Giglio et al. 2018), which is greater in area than the country of India. Wildland fires can result in significant impacts to humans, either directly through loss of life and destruction to communities or indirectly through smoke exposure. Moreover, as the climate warms, we are seeing increasing impacts from wildland fire (Coogan et al. 2019).

Consequently, billions of dollars are spent every year on fire management activities aimed at mitigating or preventing wildfires’ negative effects. Understanding and better predicting wildfires is therefore crucial in several important areas of wildfire management, including emergency response, ecosystem management, land-use planning, and climate adaptation to name a few.

Wildfire - protect the nature!
Image source canva
Image source Canva

Wildfires, whether natural or caused by humans, are considered among the most dangerous and devastating disasters around the world. Their complexity comes from the fact that they are hard to predict, hard to extinguish and cause enormous financial losses. To address this issue, many research efforts have been conducted in order to monitor, predict and prevent wildfires using several Artificial Intelligence techniques and strategies such as Big Data, Machine Learning (ML), and Remote Sensing.

Artificial intelligence (AI) has been applied in wildfire science and management since the 1990s, with early applications including neural networks and expert systems. Since then, the field has rapidly progressed congruently with the wide adoption of machine learning (ML) methods in the environmental sciences. The diagram below presents a scoping review of ML applications in wildfire science and management. 

A diagram showing the ML types, types of data, and modeling tasks in relation to potential applications in wildfire science and management. Note that the algorithms shown in bold type are core ML methods.

In this project, we deploy ML applications in wildfire science and management. The objective is to improve awareness of ML methods among fire researchers and managers and illustrate the diverse and challenging problems in wildfire open to data scientists. Specifically, we develop an early warning detection system of forest fires. We revise the Deep Learning (DL) framework that focuses on understanding the effects of the physical and environmental conditions such as temperature, wind, humidity and relative humidity on predicting the occurrence of fire in a given area. 

The dataset used in this project was downloaded from the UCI Machine Learning Repository. This is a public dataset that was used to predict the burned area of forest fires, in the NE region of Portugal (the Montesinho park), by using meteorological and other data.

Following the earlier study, the entire end-to-end ETL ML pipeline is implemented in Python/Jupyter as the following sequence of steps:

  • Import/install key libraries
  • Download the input dataset
  • Data Preparation/Manipulations
  • Exploratory Data Analysis (EDA)
  • Model Training, Testing and Validation
  • Hyperparameter Tuning/Optimization
  • Model Performance Evaluation
  • Export/Visualization of Prediction Results

Import Libraries

Let’s set the working directory YOURPATH

import os

os.chdir(‘YOURPATH’)

os. getcwd()

Let’s import key libraries

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use(‘seaborn’)
import seaborn as sns
from sklearn.preprocessing import LabelEncoder, StandardScaler, MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score
import tensorflow as tensorflow
from keras.models import Sequential
from keras.layers import Dense, Dropout
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.utils import to_categorical
from keras.callbacks import EarlyStopping
from keras.callbacks import ModelCheckpoint
from keras.utils.vis_utils import plot_model
%matplotlib inline

Read Input Data

Let’s read the csv file

df = pd.read_csv(‘forestfires.csv’)
df.head(10)

Input data table

We can see the following attributes in the above table:

  • X and Y are the spatial coordinate numbers (1-9)
  • month of the year (1-12)
  • day of the week (1-7)
  • FFMC (Fine Fuel Moisture Code) index from the FWI system (18.7-96.20)
  • DMC (Duff Moisture Code) index from the FWI system (1.1-291.3)
  • DC (Drought Code) index from the FWI system (7.9-860.6)
  • ISI (Initial Spread Index) index from the FWI system (0.0-56.10)
  • temperature in Celsius degrees (2.2-33.30)
  • RH = relative humidity in % (15.0-100)
  • wind speed in km/h (0.40 to 9.40)
  • rain in mm/m2 (0.0-6.4)
  • area = the burned area of the forest in ha (0.00-1090.84).

Let’s check the data structure
df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 517 entries, 0 to 516
Data columns (total 13 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   X       517 non-null    int64  
 1   Y       517 non-null    int64  
 2   month   517 non-null    object 
 3   day     517 non-null    object 
 4   FFMC    517 non-null    float64
 5   DMC     517 non-null    float64
 6   DC      517 non-null    float64
 7   ISI     517 non-null    float64
 8   temp    517 non-null    float64
 9   RH      517 non-null    int64  
 10  wind    517 non-null    float64
 11  rain    517 non-null    float64
 12  area    517 non-null    float64
dtypes: float64(8), int64(3), object(2)
memory usage: 52.6+ KB

Count null features in the dataset
df.isnull().sum()

X        0
Y        0
month    0
day      0
FFMC     0
DMC      0
DC       0
ISI      0
temp     0
RH       0
wind     0
rain     0
area     0
dtype: int64

Check the number of columns and rows in the dataset
print(df.shape)

(517, 13)

Check statistical information about numerical fields

df.describe()

Statistical information about numerical fields

It appears that

  • the structured dataset consists of 13 columns (attributes) and 517 rows (measurements)
  • columns X and Y are int indices that do not represent actual coordinates
  • the dataset does not contain NaN values.

Exploratory Data Analysis (EDA)

Let’s plot the pie-chart comparing 12 months

plt.figure(figsize= (12,8))
explode_gender=(0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.2,0.25,0.35,0.55)
colors = [‘#ff9999′,’#66b3ff’,’#99ff99′,’#ffcc99′,’#c2c2f0′,’#ffb3e6′,’#ffebcd’,’#ffefdb’,’#66cdaa’,’#e3cf57′,’#0000ff’,’#ff4040′]
fig = df[“month”].value_counts(normalize = True).plot.pie(autopct=’%1.2f%%’,colors=colors,explode=explode_gender,wedgeprops={‘linewidth’: 3.0, ‘edgecolor’: ‘white’},
textprops={‘size’: ‘x-large’},
startangle=90,labeldistance = 1.1)

fig.legend(title=”month”,
loc=”center left”,
bbox_to_anchor=(1.15, 0, 0.5, 1))
plt.savefig(‘piechartmonth.png’)
plt.show()

pie-chart showing month

According to this chart, August and September are the most wildfire-prone months in the study area.

Let’s plot the pie-chart comparing 7 days of the week

plt.figure(figsize= (10,6))
import plotly.express as px
from matplotlib import cm
import random
import matplotlib.colors as mcolors
number_of_colors=7
#colors = random.choices(list(mcolors.CSS4_COLORS.values()),k = number_of_colors)

colors = [‘#ff9999′,’#66b3ff’,’#99ff99′,’#ffcc99′,’#c2c2f0′,’#ffb3e6′,’#ffebcd’]

fig = df[“day”].value_counts(normalize = True).plot.pie(autopct=’%1.2f%%’,colors=colors,textprops={‘size’: ‘x-large’})
plt.title(“Pie-chart showing Day”, fontdict={‘fontsize’: 20, ‘fontweight’ : 5, ‘color’ : ‘Blue’})
fig.legend(title=”day”,
loc=”center left”,
bbox_to_anchor=(1.1, 0, 0.5, 1))
plt.savefig(‘piechartday.png’)
plt.show()

pie-chart comparing days of the week

The distribution of wildfires looks pretty uniform throughout the week, with the slight increase during weekends due to a relatively slow response of firefighters.

Let’s plot the attribute list

df.columns

Index(['X', 'Y', 'month', 'day', 'FFMC', 'DMC', 'DC', 'ISI', 'temp', 'RH',
       'wind', 'rain', 'area'],
      dtype='object')

df.dtypes

X          int64
Y          int64
month     object
day       object
FFMC     float64
DMC      float64
DC       float64
ISI      float64
temp     float64
RH         int64
wind     float64
rain     float64
area     float64
dtype: object

Let’s create the list

X = df[[‘FFMC’, ‘DMC’ , ‘DC’, ‘ISI’, ‘RH’,’wind’,’temp’]]

and plot the cross-pairs

sns_plot=sns.pairplot(X)
plt.savefig(‘snspairplot.png’)
plt.show()

sns pair plot of the list
X = df[['FFMC', 'DMC' , 'DC', 'ISI', 'RH','wind','temp']]

We can see a significant correlation trends in the following X-plots: (temp-RH), (temp-ISI), and (temp-FFMC). At the same time, wind does not appear to exhibit strong correlations with other attributes.

Let’s plot the correlation coefficient heatmap

sns.heatmap(X.corr(), annot=True)
plt.savefig(‘snscorrheatmap.png’)
plt.show()

X.corr() sns heatmap
where 
X = df[['FFMC', 'DMC' , 'DC', 'ISI', 'RH','wind','temp']]
X.corr() sns heatmap

We can see that the pair DC-DMC has the maximum correlation of 0.68, while the pair wind-RH has the minimum negative correlation of -0.53.

Let’s create the following scatter plot

import matplotlib.pyplot as plt
plt.figure(figsize=(8, 8), dpi=80)

SMALL_SIZE = 14
MEDIUM_SIZE = 14
BIGGER_SIZE = 14

plt.rc(‘font’, size=SMALL_SIZE) # controls default text sizes
plt.rc(‘axes’, titlesize=SMALL_SIZE) # fontsize of the axes title
plt.rc(‘axes’, labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
plt.rc(‘xtick’, labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc(‘ytick’, labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc(‘legend’, fontsize=SMALL_SIZE) # legend fontsize
plt.rc(‘figure’, titlesize=BIGGER_SIZE) # fontsize of the figure title
plt.scatter(df[‘DMC’],df[‘FFMC’],s=df[‘RH’]*2,c=df[‘temp’],cmap=’magma’) plt.colorbar() plt.xlabel(“DMC”) plt.ylabel(“FFMC”) plt.text( 3.2, 35, “Size of marker = RH*2\n” “Color of marker = temp”,
)
plt.savefig(‘pltscatterdmcffmc_rhtemp.png’)
plt.show()

Scatter plot FFMC-DMC 
Size of marker = RH*2
Color of marker = temp

This plot shows a strong correlation between DMC and FFMC, except outliers in the range of lower temp<15 and higher RH.

Let’s create the 2nd scatter plot

plt.figure(figsize=(8, 8), dpi=80)

SMALL_SIZE = 14
MEDIUM_SIZE = 14
BIGGER_SIZE = 14

plt.rc(‘font’, size=SMALL_SIZE) # controls default text sizes
plt.rc(‘axes’, titlesize=SMALL_SIZE) # fontsize of the axes title
plt.rc(‘axes’, labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
plt.rc(‘xtick’, labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc(‘ytick’, labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc(‘legend’, fontsize=SMALL_SIZE) # legend fontsize
plt.rc(‘figure’, titlesize=BIGGER_SIZE) # fontsize of the figure title
plt.scatter(df[‘DC’],df[‘ISI’],s=df[‘RH’]*2,c=df[‘temp’],cmap=’magma’) plt.colorbar() plt.xlabel(“DC”) plt.ylabel(“ISI”) plt.text( 3.2, 35, “Size of marker = RH*2\n” “Color of marker = temp”,
)
plt.savefig(‘pltscatterdcisi_rhtemp.png’)
plt.show()

Let’s create the 3rd scatter plot

Scatter plot ISI-DC 
Size of marker = RH*2
Color of marker = temp

We can observe a weak correlation between ISI and DC, with a single outlier ISI>55 at DC~200.

plt.figure(figsize=(8, 8), dpi=80)

SMALL_SIZE = 14
MEDIUM_SIZE = 14
BIGGER_SIZE = 14

plt.rc(‘font’, size=SMALL_SIZE) # controls default text sizes
plt.rc(‘axes’, titlesize=SMALL_SIZE) # fontsize of the axes title
plt.rc(‘axes’, labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
plt.rc(‘xtick’, labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc(‘ytick’, labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc(‘legend’, fontsize=SMALL_SIZE) # legend fontsize
plt.rc(‘figure’, titlesize=BIGGER_SIZE) # fontsize of the figure title
plt.scatter(df[‘RH’],df[‘FFMC’],s=df[‘ISI’]10,c=df[‘temp’],cmap=’magma’) plt.colorbar() plt.xlabel(“RH”) plt.ylabel(“FFMC”) plt.text( 19.8, 32.5, “Size of marker = ISI10\n” “Color of marker = temp”
)
plt.savefig(‘pltscatterrhffmc_isitemp.png’)
plt.show()

Scatter plot FFMC-RH
Size of marker = ISI*10
Color of marker = temp

This plot shows a strong correlation between FFMC and RH, excluding outliers at very low values of ISI as FFMC<80.

Let’s look at the monthly FFMC box-plots

fig = px.box(df, x=’month’, y=’FFMC’, points=”all”)
fig.update_layout(
title_text=”Monthly FFMC Spread”)

Box plot FFMC Spread monthly

and the corresponding monthly/weekly violin-plots

fig = px.violin(df, y=”FFMC”, x=”month”, color=”day”, box=True, points=”all”, hover_data=df.columns)
fig.update_layout(title_text=”Monthly/Weekly FFMC”)
fig.show()

Violin-plots monthly/weekly

We can see that the maximum spread takes place in jan and jun/sat. Most outliers are recorded on weekends when FFMC<80.

Let’s look at the DMC monthly spread

fig = px.box(df, x=’month’, y=’DMC’, points=”all”)
fig.update_layout(
title_text=”Monthly DMC Spread”)

Box-plot DMC monthly spread

and the corresponding violin plot showing monthly/weekly DMC spread

fig = px.violin(df, y=”DMC”, x=”month”, color=”day”, box=True, points=”all”, hover_data=df.columns)
fig.update_layout(title_text=”Monthly/Weekly DMC”)

Violin-plot DMC spread monthly/weekly

These plots show that jun, jul, aug and sep have seen the highest DMC spreads for both weekdays and weekends.

Let’s look at the DC monthly spread

fig = px.box(df, x=’month’, y=’DC’, points=”all”)
fig.update_layout(
title_text=”Monthly DC Spread”)

Box-plot DC spread monthly

and the corresponding violin plot showing monthly/weekly DC spread

fig = px.violin(df, y=”DC”, x=”month”, color=”day”, box=True, points=”all”, hover_data=df.columns)
fig.update_layout(title_text=”Monthly/Weekly DC”)

Violin-plot DC spread monthly/weekly

We can see a few DC outliers in aug feb and jul violin-plots. The data recorded in nov, dec, jan, apr, and may may not be reliable.

Let’s look at the ISI monthly spread

fig = px.box(df, x=’month’, y=’ISI’, points=”all”)
fig.update_layout(
title_text=”Monthly ISI Spread”)

Box-plot ISI monthly spread

and the corresponding monthly/weekly ISI violin-plot

fig = px.violin(df, y=”ISI”, x=”month”, color=”day”, box=True, points=”all”, hover_data=df.columns)
fig.update_layout(title_text=”Monthly/Weekly ISI”)

Violin-plot ISI monthly/weekly spread

We can see 1 ISI outlier on sun jun and insufficient monthly data samples in dec, may, nov, and jan.

Let’s look at the RH monthly spread

fig = px.box(df, x=’month’, y=’RH’, points=”all”)
fig.update_layout(
title_text=”Monthly RH Spread”)

Box-plot RH monthly spread

and the corresponding monthly/weekly RH violin-plot

fig = px.violin(df, y=”RH”, x=”month”, color=”day”, box=True, points=”all”, hover_data=df.columns)
fig.update_layout(title_text=”Monthly/Weekly RH”)

Violin-plot RH monthly/weekly spread

We can see that the monthly RH data in apr, dec, may, nov, and jan are not suffifient. Also, notice RH outliers when RH>100 and RH<10.

Let’s look at the temp monthly spread

fig = px.box(df, x=’month’, y=’temp’, points=”all”)
fig.update_layout(
title_text=”Monthly temp Spread”)

Box-plot temp monthly spread

and the corresponding monthly/weekly temp violin-plot

fig = px.violin(df, y=”temp”, x=”month”, color=”day”, box=True, points=”all”, hover_data=df.columns)
fig.update_layout(title_text=”Monthly/Weekly temp”)

Violin-plot temp monthly/weekly spread

We can see 1 temp outlier on sat jun, other outliers as temp<5.0 and sparse temp data sampling in dec, may, nov, and jan.

Let’s look at the wind monthly spread

fig = px.box(df, x=’month’, y=’wind’, points=”all”)
fig.update_layout(
title_text=”Monthly wind Spread”)

Box-plot wind monthly spread

and the corresponding monthly/weekly wind violin-plot

fig = px.violin(df, y=”wind”, x=”month”, color=”day”, box=True, points=”all”, hover_data=df.columns)
fig.update_layout(title_text=”Monthly/Weekly wind”)

Violin-plot wind monthly/weekly spread

We can see several wind outliers as wind>10.0 and wind <2.0. Observe sparse monthly wind data in apr, dec, may, nov, and jan.

Let’s look at the rain monthly spread

fig = px.box(df, x=’month’, y=’rain’, points=”all”)
fig.update_layout(
title_text=”Monthly rain Spread”)

Box-plot rain monthly spread

and the corresponding monthly/weekly rain violin-plot

fig = px.violin(df, y=”rain”, x=”month”, color=”day”, box=True, points=”all”, hover_data=df.columns)
fig.update_layout(title_text=”Monthly/Weekly rain”)

Violin-plot rain monthly weekly spread

We can see that rain ~0.0 except a few outliers rain >1.0 in aug.

Let’s look at the area (target variable) monthly spread

fig = px.box(df, x=’month’, y=’area’, points=”all”)
fig.update_layout(
title_text=”Monthly area Spread”)

Box-plot area monthly spread

and the corresponding monthly/weekly area violin-plot

fig = px.violin(df, y=”area”, x=”month”, color=”day”, box=True, points=”all”, hover_data=df.columns)
fig.update_layout(title_text=”Monthly/Weekly area”)

Violin-plot area monthly/weekly spread

We can see a few area outliers in jul, aug and sep as area>200. Notice sparse area data in dec, may, nov, and jan.

Let’s look at the following density plots:

sns.distplot(df.FFMC)
plt.savefig(‘distplot_ffmc.png’)
plt.show()

FFMC density plot
Left-skewed single-mode leptokurtic distribution

sns.distplot(df.DMC)
plt.savefig(‘distplot_dmc.png’)
plt.show()

DMC density plot
Right-skewed bimodal mesokurtic distribution

sns.distplot(df.DC)
plt.savefig(‘distplot_dc.png’)
plt.show()

DC density plot
Left-skewed bimodal mesokurtic distribution

sns.distplot(df.ISI)
plt.savefig(‘distplot_isi.png’)
plt.show()

Right-skewed single-mode leptokurtic distribution

sns.distplot(df.RH)
plt.savefig(‘distplot_rh.png’)
plt.show()

RH density plot
Right-skewed single-mode platykurtic distribution

sns.distplot(df.temp)
plt.savefig(‘distplot_temp.png’)
plt.show()

temp density plot
Left-skewed single-mode mesokurtic distribution

sns.distplot(df.wind)
plt.savefig(‘distplot_wind.png’)
plt.show()

wind density plot
Right-skewed single-mode platykurtic distribution

sns.distplot(df.rain)
plt.savefig(‘distplot_rain.png’)
plt.show()

Rain density plot
Right-skewed single-mode leptokurtic distribution

sns.distplot(df.area)
plt.savefig(‘distplot_area.png’)
plt.show()

Area density plot
Right-skewed single-mode leptokurtic distribution

Let’s look at the pivot tables of interest:

pivot8 = pd.pivot_table(data = df, index = “DMC”, columns = “DC”, values = “temp”)
plt.figure(figsize= (10,6))
sns.heatmap(pivot8, cmap = “Greens”, annot = False,fmt=’.2f’)
plt.show()

pivot table DMC-DC-temp
Pivot table DMC-DC-temp

pivot8 = pd.pivot_table(data = df, index = “wind”, columns = “temp”, values = “ISI”)
plt.figure(figsize= (10,6))
sns.heatmap(pivot8, cmap = “Greens”, annot = False,fmt=’.2f’)
plt.show()

pivot table wind-temp-ISI
Pivot table wind-temp-ISI

pivot8 = pd.pivot_table(data = df, index = “ISI”, columns = “month”, values = “temp”)
sns.set(rc = {‘figure.figsize’:(15,8)})
sns.heatmap(pivot8, cmap = “Greens”, annot = False)
plt.show()

Pivot table ISI-month-temp
Pivot table ISI-month-temp

pivot8 = pd.pivot_table(data = df, index = “FFMC”, columns = “month”, values = “temp”)
sns.set(rc = {‘figure.figsize’:(15,8)})
sns.heatmap(pivot8, cmap = “Greens”, annot = False)
plt.show()

pivot table FFMC-month-temp
Pivot table FFMC-month-temp

pivot8 = pd.pivot_table(data = df, index = “RH”, columns = “month”, values = “temp”)
sns.set(rc = {‘figure.figsize’:(15,8)})
sns.heatmap(pivot8, cmap = “Greens”, annot = False)
plt.show()

pivot table RH-month-temp
Pivot table RH-month-temp

pivot8 = pd.pivot_table(data = df, index = “DMC”, columns = “month”, values = “temp”)
sns.set(rc = {‘figure.figsize’:(15,8)})
sns.heatmap(pivot8, cmap = “Greens”, annot = False)
plt.show()

pivot table DMC-month-temp
Pivot table DMC-month-temp

pivot8 = pd.pivot_table(data = df, index = “DC”, columns = “month”, values = “temp”)
sns.set(rc = {‘figure.figsize’:(15,8)})
sns.heatmap(pivot8, cmap = “Greens”, annot = False)
plt.show()

pivot table DC-month-temp
Pivot table DC-month-temp

pivot8 = pd.pivot_table(data = df, index = “area”, columns = “month”, values = “temp”)
sns.set(rc = {‘figure.figsize’:(15,8)})
sns.heatmap(pivot8, cmap = “Greens”, annot = False)
plt.show()

pivot table area-month-temp
Pivot table area-month-temp

pivot8 = pd.pivot_table(data = df, index = “rain”, columns = “month”, values = “temp”)
sns.set(rc = {‘figure.figsize’:(15,8)})
sns.heatmap(pivot8, cmap = “Greens”, annot = False)
plt.show()

pivot table rain-month-temp
Pivot table rain-month-temp

pivot8 = pd.pivot_table(data = df, index = “wind”, columns = “month”, values = “temp”)
sns.set(rc = {‘figure.figsize’:(15,8)})
sns.heatmap(pivot8, cmap = “Greens”, annot = False)
plt.show()

pivot table wind-month-temp
Pivot table wind-month-temp

These pivot table show that the best data quality is observed in jul, aug, and sep.

ML Data Preparation

Let’s transform/rename our weekly data

df[‘day’] = ((df[‘day’] == ‘sun’) | (df[‘day’] == ‘sat’))

df = df.rename(columns = {‘day’ : ‘is_weekend’})

and plot the day count

sns.countplot(df[‘is_weekend’])
plt.title(‘Count plot of weekend vs weekday’)

Weekend vs weekday count histogram

Let’s scale the rain and area data representing skewed distributions with outliers, as shown above:

df.loc[:, [‘rain’, ‘area’]] = df.loc[:, [‘rain’, ‘area’]].apply(lambda x: np.log(x + 1), axis = 1)

Let’s consider the best quality monthly data, as discussed above:

df[‘month’] = ((df[‘month’] == ‘aug’) | (df[‘month’] == ‘sep’)| (df[‘month’] == ‘jul’))

Let’s split train/test data as 80:20

features = df.drop([‘size_category’], axis = 1)
labels = df[‘size_category’].values.reshape(-1, 1)
X_train, X_test, y_train, y_test = train_test_split(features,labels, test_size = 0.2, random_state = 42)

and apply StandardScaler()

sc_features = StandardScaler()

X_test = sc_features.fit_transform(X_test)

X_train = sc_features.transform(X_train)

Features:
X_test = pd.DataFrame(X_test, columns = features.columns)
X_train = pd.DataFrame(X_train, columns = features.columns)

Labels:
y_test = pd.DataFrame(y_test, columns = [‘size_category’])
y_train = pd.DataFrame(y_train, columns = [‘size_category’])

ANN Model Training

Let’s define our ANN model as follows

model = Sequential()

Input layer + 1st hidden layer:

model.add(Dense(6, input_dim=13, activation=’relu’))

2nd hidden layer:

model.add(Dense(6, activation=’relu’))

Output layer:

model.add(Dense(6, activation=’sigmoid’))
model.add(Dropout(0.2))
model.add(Dense(1, activation = ‘relu’))
model.summary()

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense (Dense)               (None, 6)                 84        
                                                                 
 dense_1 (Dense)             (None, 6)                 42        
                                                                 
 dense_2 (Dense)             (None, 6)                 42        
                                                                 
 dropout (Dropout)           (None, 6)                 0         
                                                                 
 dense_3 (Dense)             (None, 1)                 7         
                                                                 
=================================================================
Total params: 175
Trainable params: 175
Non-trainable params: 0

Let’s compile the model
model.compile(optimizer = ‘adam’, metrics=[‘accuracy’], loss =’binary_crossentropy’)

and train it
history = model.fit(X_train, y_train, validation_data = (X_test, y_test), batch_size = 10, epochs = 100)

Epoch 1/100
42/42 [==============================] - 0s 3ms/step - loss: 3.9964 - accuracy: 0.7312 - val_loss: 4.1529 - val_accuracy: 0.7308
Epoch 2/100
42/42 [==============================] - 0s 1ms/step - loss: 3.9510 - accuracy: 0.7312 - val_loss: 4.1529 - val_accuracy: 0.7308
Epoch 3/100
42/42 [==============================] - 0s 1ms/step - loss: 3.9330 - accuracy: 0.7312 - val_loss: 4.1529 - val_accuracy: 0.7308
Epoch 4/100
42/42 [==============================] - 0s 1ms/step - loss: 3.8950 - accuracy: 0.7312 - val_loss: 4.1529 - val_accuracy: 0.7308
Epoch 5/100
42/42 [==============================] - 0s 1ms/step - loss: 3.7621 - accuracy: 0.7312 - val_loss: 4.1529 - val_accuracy: 0.7308
Epoch 6/100
42/42 [==============================] - 0s 1ms/step - loss: 3.7872 - accuracy: 0.7312 - val_loss: 4.1529 - val_accuracy: 0.7308
Epoch 7/100
42/42 [==============================] - 0s 1ms/step - loss: 3.5116 - accuracy: 0.7312 - val_loss: 4.1529 - val_accuracy: 0.7308
Epoch 8/100
42/42 [==============================] - 0s 1ms/step - loss: 3.6054 - accuracy: 0.7337 - val_loss: 3.9324 - val_accuracy: 0.7308
Epoch 9/100
42/42 [==============================] - 0s 1ms/step - loss: 3.4001 - accuracy: 0.7215 - val_loss: 3.4334 - val_accuracy: 0.7308
Epoch 10/100
42/42 [==============================] - 0s 1ms/step - loss: 2.8922 - accuracy: 0.7288 - val_loss: 2.8330 - val_accuracy: 0.7308
Epoch 11/100
42/42 [==============================] - 0s 1ms/step - loss: 2.4768 - accuracy: 0.7433 - val_loss: 1.2727 - val_accuracy: 0.7308
Epoch 12/100
42/42 [==============================] - 0s 1ms/step - loss: 1.6051 - accuracy: 0.7240 - val_loss: 0.6996 - val_accuracy: 0.7404
Epoch 13/100
42/42 [==============================] - 0s 1ms/step - loss: 1.3042 - accuracy: 0.7409 - val_loss: 0.6729 - val_accuracy: 0.7500
Epoch 14/100
42/42 [==============================] - 0s 1ms/step - loss: 1.2543 - accuracy: 0.7361 - val_loss: 0.6578 - val_accuracy: 0.7500
Epoch 15/100
42/42 [==============================] - 0s 1ms/step - loss: 1.2196 - accuracy: 0.7094 - val_loss: 0.5239 - val_accuracy: 0.7788
Epoch 16/100
42/42 [==============================] - 0s 1ms/step - loss: 0.9230 - accuracy: 0.7458 - val_loss: 0.5067 - val_accuracy: 0.7885
Epoch 17/100
42/42 [==============================] - 0s 1ms/step - loss: 0.9433 - accuracy: 0.7627 - val_loss: 0.4927 - val_accuracy: 0.8269
Epoch 18/100
42/42 [==============================] - 0s 1ms/step - loss: 0.8862 - accuracy: 0.7240 - val_loss: 0.3726 - val_accuracy: 0.8462
Epoch 19/100
42/42 [==============================] - 0s 1ms/step - loss: 0.7844 - accuracy: 0.7554 - val_loss: 0.3550 - val_accuracy: 0.8462
Epoch 20/100
42/42 [==============================] - 0s 1ms/step - loss: 0.8198 - accuracy: 0.7240 - val_loss: 0.3450 - val_accuracy: 0.8558
Epoch 21/100
42/42 [==============================] - 0s 1ms/step - loss: 0.5507 - accuracy: 0.7506 - val_loss: 0.3382 - val_accuracy: 0.8558
Epoch 22/100
42/42 [==============================] - 0s 1ms/step - loss: 0.8161 - accuracy: 0.7458 - val_loss: 0.3326 - val_accuracy: 0.8462
Epoch 23/100
42/42 [==============================] - 0s 1ms/step - loss: 0.7026 - accuracy: 0.7603 - val_loss: 0.3232 - val_accuracy: 0.8654
Epoch 24/100
42/42 [==============================] - 0s 1ms/step - loss: 0.5395 - accuracy: 0.7651 - val_loss: 0.3169 - val_accuracy: 0.8654
Epoch 25/100
42/42 [==============================] - 0s 1ms/step - loss: 0.5820 - accuracy: 0.7942 - val_loss: 0.3098 - val_accuracy: 0.8558
Epoch 26/100
42/42 [==============================] - 0s 1ms/step - loss: 0.5944 - accuracy: 0.7651 - val_loss: 0.3020 - val_accuracy: 0.8654
Epoch 27/100
42/42 [==============================] - 0s 1ms/step - loss: 0.6394 - accuracy: 0.7651 - val_loss: 0.2969 - val_accuracy: 0.8654
Epoch 28/100
42/42 [==============================] - 0s 1ms/step - loss: 0.5938 - accuracy: 0.7651 - val_loss: 0.2896 - val_accuracy: 0.8750
Epoch 29/100
42/42 [==============================] - 0s 1ms/step - loss: 0.5811 - accuracy: 0.7797 - val_loss: 0.2835 - val_accuracy: 0.8750
Epoch 30/100
42/42 [==============================] - 0s 1ms/step - loss: 0.3789 - accuracy: 0.8329 - val_loss: 0.2797 - val_accuracy: 0.8846
Epoch 31/100
42/42 [==============================] - 0s 1ms/step - loss: 0.5529 - accuracy: 0.8063 - val_loss: 0.2734 - val_accuracy: 0.8846
Epoch 32/100
42/42 [==============================] - 0s 1ms/step - loss: 0.5569 - accuracy: 0.8039 - val_loss: 0.2654 - val_accuracy: 0.8846
Epoch 33/100
42/42 [==============================] - 0s 1ms/step - loss: 0.5183 - accuracy: 0.8039 - val_loss: 0.2590 - val_accuracy: 0.8942
Epoch 34/100
42/42 [==============================] - 0s 1ms/step - loss: 0.5420 - accuracy: 0.7845 - val_loss: 0.2572 - val_accuracy: 0.9038
Epoch 35/100
42/42 [==============================] - 0s 1ms/step - loss: 0.4040 - accuracy: 0.8015 - val_loss: 0.2511 - val_accuracy: 0.9135
Epoch 36/100
42/42 [==============================] - 0s 1ms/step - loss: 0.3933 - accuracy: 0.8257 - val_loss: 0.2446 - val_accuracy: 0.9038
Epoch 37/100
42/42 [==============================] - 0s 1ms/step - loss: 0.4350 - accuracy: 0.8208 - val_loss: 0.2378 - val_accuracy: 0.9135
Epoch 38/100
42/42 [==============================] - 0s 1ms/step - loss: 0.3923 - accuracy: 0.7748 - val_loss: 0.2341 - val_accuracy: 0.9135
Epoch 39/100
42/42 [==============================] - 0s 1ms/step - loss: 0.3426 - accuracy: 0.8354 - val_loss: 0.2309 - val_accuracy: 0.9135
Epoch 40/100
42/42 [==============================] - 0s 1ms/step - loss: 0.3220 - accuracy: 0.8354 - val_loss: 0.2272 - val_accuracy: 0.9135
Epoch 41/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2793 - accuracy: 0.8426 - val_loss: 0.2248 - val_accuracy: 0.9231
Epoch 42/100
42/42 [==============================] - 0s 1ms/step - loss: 0.3744 - accuracy: 0.8208 - val_loss: 0.2247 - val_accuracy: 0.9135
Epoch 43/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2990 - accuracy: 0.8281 - val_loss: 0.2243 - val_accuracy: 0.9135
Epoch 44/100
42/42 [==============================] - 0s 1ms/step - loss: 0.3358 - accuracy: 0.8136 - val_loss: 0.2193 - val_accuracy: 0.9231
Epoch 45/100
42/42 [==============================] - 0s 1ms/step - loss: 0.3040 - accuracy: 0.8378 - val_loss: 0.2149 - val_accuracy: 0.9231
Epoch 46/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2857 - accuracy: 0.8426 - val_loss: 0.2123 - val_accuracy: 0.9231
Epoch 47/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2844 - accuracy: 0.8475 - val_loss: 0.2135 - val_accuracy: 0.9135
Epoch 48/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2593 - accuracy: 0.8668 - val_loss: 0.2134 - val_accuracy: 0.9135
Epoch 49/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2941 - accuracy: 0.8668 - val_loss: 0.2089 - val_accuracy: 0.9135
Epoch 50/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2833 - accuracy: 0.8426 - val_loss: 0.2054 - val_accuracy: 0.9231
Epoch 51/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2422 - accuracy: 0.8547 - val_loss: 0.2017 - val_accuracy: 0.9231
Epoch 52/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2671 - accuracy: 0.8862 - val_loss: 0.1998 - val_accuracy: 0.9231
Epoch 53/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2401 - accuracy: 0.8765 - val_loss: 0.2019 - val_accuracy: 0.9231
Epoch 54/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2222 - accuracy: 0.8959 - val_loss: 0.1992 - val_accuracy: 0.9231
Epoch 55/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2345 - accuracy: 0.8717 - val_loss: 0.1948 - val_accuracy: 0.9231
Epoch 56/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2173 - accuracy: 0.8983 - val_loss: 0.1922 - val_accuracy: 0.9038
Epoch 57/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2781 - accuracy: 0.8765 - val_loss: 0.1908 - val_accuracy: 0.9135
Epoch 58/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2143 - accuracy: 0.9031 - val_loss: 0.1867 - val_accuracy: 0.9135
Epoch 59/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2553 - accuracy: 0.8959 - val_loss: 0.1814 - val_accuracy: 0.9135
Epoch 60/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1861 - accuracy: 0.9104 - val_loss: 0.1793 - val_accuracy: 0.9135
Epoch 61/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1968 - accuracy: 0.9128 - val_loss: 0.1737 - val_accuracy: 0.9135
Epoch 62/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1867 - accuracy: 0.9177 - val_loss: 0.1697 - val_accuracy: 0.9135
Epoch 63/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2166 - accuracy: 0.9056 - val_loss: 0.1616 - val_accuracy: 0.9135
Epoch 64/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2100 - accuracy: 0.8910 - val_loss: 0.1572 - val_accuracy: 0.9231
Epoch 65/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2105 - accuracy: 0.9249 - val_loss: 0.1564 - val_accuracy: 0.9135
Epoch 66/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2176 - accuracy: 0.9201 - val_loss: 0.1505 - val_accuracy: 0.9327
Epoch 67/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1684 - accuracy: 0.9177 - val_loss: 0.1471 - val_accuracy: 0.9327
Epoch 68/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1757 - accuracy: 0.9177 - val_loss: 0.1545 - val_accuracy: 0.9135
Epoch 69/100
42/42 [==============================] - 0s 1ms/step - loss: 0.2016 - accuracy: 0.9177 - val_loss: 0.1478 - val_accuracy: 0.9135
Epoch 70/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1990 - accuracy: 0.9322 - val_loss: 0.1423 - val_accuracy: 0.9327
Epoch 71/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1628 - accuracy: 0.9370 - val_loss: 0.1374 - val_accuracy: 0.9423
Epoch 72/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1443 - accuracy: 0.9370 - val_loss: 0.1339 - val_accuracy: 0.9423
Epoch 73/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1568 - accuracy: 0.9298 - val_loss: 0.1317 - val_accuracy: 0.9423
Epoch 74/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1604 - accuracy: 0.9274 - val_loss: 0.1323 - val_accuracy: 0.9423
Epoch 75/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1412 - accuracy: 0.9492 - val_loss: 0.1252 - val_accuracy: 0.9423
Epoch 76/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1372 - accuracy: 0.9370 - val_loss: 0.1184 - val_accuracy: 0.9519
Epoch 77/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1375 - accuracy: 0.9370 - val_loss: 0.1173 - val_accuracy: 0.9519
Epoch 78/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1366 - accuracy: 0.9225 - val_loss: 0.1097 - val_accuracy: 0.9519
Epoch 79/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1279 - accuracy: 0.9395 - val_loss: 0.1112 - val_accuracy: 0.9519
Epoch 80/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1340 - accuracy: 0.9322 - val_loss: 0.1087 - val_accuracy: 0.9519
Epoch 81/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1659 - accuracy: 0.9419 - val_loss: 0.1091 - val_accuracy: 0.9615
Epoch 82/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1200 - accuracy: 0.9322 - val_loss: 0.1007 - val_accuracy: 0.9615
Epoch 83/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1404 - accuracy: 0.9443 - val_loss: 0.0999 - val_accuracy: 0.9615
Epoch 84/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1102 - accuracy: 0.9540 - val_loss: 0.0964 - val_accuracy: 0.9615
Epoch 85/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1389 - accuracy: 0.9564 - val_loss: 0.1013 - val_accuracy: 0.9615
Epoch 86/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1249 - accuracy: 0.9685 - val_loss: 0.1036 - val_accuracy: 0.9615
Epoch 87/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1446 - accuracy: 0.9467 - val_loss: 0.0920 - val_accuracy: 0.9615
Epoch 88/100
42/42 [==============================] - 0s 1ms/step - loss: 0.0985 - accuracy: 0.9588 - val_loss: 0.0894 - val_accuracy: 0.9615
Epoch 89/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1088 - accuracy: 0.9443 - val_loss: 0.1060 - val_accuracy: 0.9615
Epoch 90/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1456 - accuracy: 0.9443 - val_loss: 0.0969 - val_accuracy: 0.9615
Epoch 91/100
42/42 [==============================] - 0s 1ms/step - loss: 0.0906 - accuracy: 0.9661 - val_loss: 0.0977 - val_accuracy: 0.9615
Epoch 92/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1322 - accuracy: 0.9564 - val_loss: 0.2185 - val_accuracy: 0.9615
Epoch 93/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1119 - accuracy: 0.9395 - val_loss: 0.2174 - val_accuracy: 0.9615
Epoch 94/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1040 - accuracy: 0.9443 - val_loss: 0.1006 - val_accuracy: 0.9615
Epoch 95/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1316 - accuracy: 0.9613 - val_loss: 0.2223 - val_accuracy: 0.9615
Epoch 96/100
42/42 [==============================] - 0s 1ms/step - loss: 0.0881 - accuracy: 0.9637 - val_loss: 0.2296 - val_accuracy: 0.9712
Epoch 97/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1257 - accuracy: 0.9467 - val_loss: 0.1126 - val_accuracy: 0.9712
Epoch 98/100
42/42 [==============================] - 0s 1ms/step - loss: 0.1157 - accuracy: 0.9685 - val_loss: 0.3307 - val_accuracy: 0.9712
Epoch 99/100
42/42 [==============================] - 0s 1ms/step - loss: 0.0810 - accuracy: 0.9613 - val_loss: 0.3307 - val_accuracy: 0.9712
Epoch 100/100
42/42 [==============================] - 0s 1ms/step - loss: 0.0871 - accuracy: 0.9588 - val_loss: 0.3281 - val_accuracy: 0.9712

Let’s check the accuracy

_, train_acc = model.evaluate(X_train, y_train, verbose=0)

_, valid_acc = model.evaluate(X_test, y_test, verbose=0)
print(‘Train: %.3f, Valid: %.3f’ % (train_acc, valid_acc))

Train: 0.976, Valid: 0.971

Let’s plot the corresponding taining/validation accuracy curves

plt.figure(figsize=[8,5])
plt.plot(history.history[‘accuracy’], label=’Train’)
plt.plot(history.history[‘val_accuracy’], label=’Valid’)
plt.legend()
plt.xlabel(‘Epochs’, fontsize=16)
plt.ylabel(‘Accuracy’, fontsize=16)
plt.title(‘Accuracy Curves Epoch 100, Batch Size 10’, fontsize=16)
plt.savefig(‘accuracycurveepoch100.png’)
plt.show()

ML ANN model training/validation accuracy plots 
epoch=100, batch size = 10

Hyper-Parameter Optimization (HPO)

Let’s define the following function

Fit a model and plot learning curve
def fit_model(X_train, y_train, X_test, y_test, n_batch):

Define Model
model = Sequential()
model.add(Dense(6, input_dim=13, activation='relu'))
model.add(Dense(6, activation='relu'))
model.add(Dense(6, activation='sigmoid'))
model.add(Dropout(0.2))
model.add(Dense(1, activation = 'relu'))
Compile Model
model.compile(optimizer = 'adam',
metrics=['accuracy'],
loss = 'binary_crossentropy')
Fit Model
history = model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=100, verbose=0, batch_size=n_batch)
Plot Learning Curves
plt.plot(history.history['accuracy'], label='train')
plt.plot(history.history['val_accuracy'], label='test')
plt.title('batch='+str(n_batch))
plt.legend()
Let’s create learning curves for different batch sizes

batch_sizes = [4, 6, 10, 16, 32, 64, 128, 260]
plt.figure(figsize=(10,15))
for i in range(len(batch_sizes)):

Determine the Plot Number
    plot_no = 420 + (i+1)
    plt.subplot(plot_no)
Fit model and plot learning curves for a batch size
    fit_model(X_train, y_train, X_test, y_test, batch_sizes[i])
Show learning curves

plt.savefig(‘accuracycurvebatchvar.png’)
plt.show()

Learning curves different batch size

This accuracy graph shows that the value batch = 10 results in the optimal model performance.

Let’s define a function that fits a model and plot learning curve for different epoch given batch size of 10


def fit_model(trainX, trainy, validX, validy, n_epoch):

Define model
model = Sequential()
model.add(Dense(10, input_dim=13, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(10, activation='sigmoid'))
model.add(Dropout(0.2))
model.add(Dense(1, activation = 'relu'))
Compile model
model.compile(optimizer ='adam', metrics=['accuracy'], loss = 'binary_crossentropy')
Fit model
history = model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=n_epoch, verbose=0, batch_size=10)
# plot learning curves
plt.plot(history.history['accuracy'], label='train')
plt.plot(history.history['val_accuracy'], label='test')
plt.title('epoch='+str(n_epoch))
plt.legend()

Let’s create learning curves for different
epochs = [20, 50, 100, 120, 150, 200, 300, 400]
plt.figure(figsize=(10,15))
for i in range(len(batch_sizes)):

Determine the Plot Number
plot_no = 420 + (i+1)
plt.subplot(plot_no)
Fit model and plot learning curves for a specific value of epoch
fit_model(X_train, y_train, X_test, y_test, epochs[i])
Show learning curves

plt.savefig(‘accuracycurveepochvar.png’)
plt.show()

Learning curves variable epochs and batch size = 10

This accuracy graph shows that the values epoch>100 result in the optimal model performance.

Let’s define the final model

def init_model():

Define model
model = Sequential()
model.add(Dense(10, input_dim=13, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(10, activation='sigmoid'))
model.add(Dropout(0.2))
model.add(Dense(1, activation = 'relu'))
model.compile(optimizer ='adam',
metrics=['accuracy'],
loss = 'binary_crossentropy')
return model

Let’s apply our function init_model
model = init_model()

Simple early stopping

es = EarlyStopping(monitor=’val_loss’, mode=’min’, verbose=1, patience=150)

Model checkpoint

mc = ModelCheckpoint(‘best_model.h5′, monitor=’val_accuracy’, mode=’max’, verbose=1, save_best_only=True)

Fitting model

history = model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=250, verbose=0, batch_size=10, callbacks=[es, mc])

Epoch 1: val_accuracy improved from -inf to 0.73077, saving model to best_model.h5

Epoch 2: val_accuracy did not improve from 0.73077

Epoch 3: val_accuracy did not improve from 0.73077

Epoch 4: val_accuracy did not improve from 0.73077

Epoch 5: val_accuracy did not improve from 0.73077

Epoch 6: val_accuracy did not improve from 0.73077

Epoch 7: val_accuracy did not improve from 0.73077

Epoch 8: val_accuracy did not improve from 0.73077

Epoch 9: val_accuracy did not improve from 0.73077

Epoch 10: val_accuracy did not improve from 0.73077

Epoch 11: val_accuracy did not improve from 0.73077

Epoch 12: val_accuracy did not improve from 0.73077

Epoch 13: val_accuracy did not improve from 0.73077

Epoch 14: val_accuracy did not improve from 0.73077

Epoch 15: val_accuracy did not improve from 0.73077

Epoch 16: val_accuracy did not improve from 0.73077

Epoch 17: val_accuracy did not improve from 0.73077

Epoch 18: val_accuracy did not improve from 0.73077

Epoch 19: val_accuracy did not improve from 0.73077

Epoch 20: val_accuracy did not improve from 0.73077

Epoch 21: val_accuracy did not improve from 0.73077

Epoch 22: val_accuracy did not improve from 0.73077

Epoch 23: val_accuracy did not improve from 0.73077

Epoch 24: val_accuracy did not improve from 0.73077

Epoch 25: val_accuracy did not improve from 0.73077

Epoch 26: val_accuracy did not improve from 0.73077

Epoch 27: val_accuracy did not improve from 0.73077

Epoch 28: val_accuracy did not improve from 0.73077

Epoch 29: val_accuracy did not improve from 0.73077

Epoch 30: val_accuracy did not improve from 0.73077

Epoch 31: val_accuracy did not improve from 0.73077

Epoch 32: val_accuracy did not improve from 0.73077

Epoch 33: val_accuracy did not improve from 0.73077

Epoch 34: val_accuracy did not improve from 0.73077

Epoch 35: val_accuracy did not improve from 0.73077

Epoch 36: val_accuracy did not improve from 0.73077

Epoch 37: val_accuracy did not improve from 0.73077

Epoch 38: val_accuracy did not improve from 0.73077

Epoch 39: val_accuracy did not improve from 0.73077

Epoch 40: val_accuracy did not improve from 0.73077

Epoch 41: val_accuracy did not improve from 0.73077

Epoch 42: val_accuracy did not improve from 0.73077

Epoch 43: val_accuracy did not improve from 0.73077

Epoch 44: val_accuracy did not improve from 0.73077

Epoch 45: val_accuracy did not improve from 0.73077

Epoch 46: val_accuracy did not improve from 0.73077

Epoch 47: val_accuracy did not improve from 0.73077

Epoch 48: val_accuracy did not improve from 0.73077

Epoch 49: val_accuracy did not improve from 0.73077

Epoch 50: val_accuracy did not improve from 0.73077

Epoch 51: val_accuracy did not improve from 0.73077

Epoch 52: val_accuracy did not improve from 0.73077

Epoch 53: val_accuracy did not improve from 0.73077

Epoch 54: val_accuracy did not improve from 0.73077

Epoch 55: val_accuracy did not improve from 0.73077

Epoch 56: val_accuracy did not improve from 0.73077

Epoch 57: val_accuracy did not improve from 0.73077

Epoch 58: val_accuracy did not improve from 0.73077

Epoch 59: val_accuracy did not improve from 0.73077

Epoch 60: val_accuracy did not improve from 0.73077

Epoch 61: val_accuracy did not improve from 0.73077

Epoch 62: val_accuracy did not improve from 0.73077

Epoch 63: val_accuracy did not improve from 0.73077

Epoch 64: val_accuracy did not improve from 0.73077

Epoch 65: val_accuracy improved from 0.73077 to 0.74038, saving model to best_model.h5

Epoch 66: val_accuracy improved from 0.74038 to 0.77885, saving model to best_model.h5

Epoch 67: val_accuracy did not improve from 0.77885

Epoch 68: val_accuracy did not improve from 0.77885

Epoch 69: val_accuracy did not improve from 0.77885

Epoch 70: val_accuracy did not improve from 0.77885

Epoch 71: val_accuracy improved from 0.77885 to 0.79808, saving model to best_model.h5

Epoch 72: val_accuracy did not improve from 0.79808

Epoch 73: val_accuracy did not improve from 0.79808

Epoch 74: val_accuracy improved from 0.79808 to 0.80769, saving model to best_model.h5

Epoch 75: val_accuracy did not improve from 0.80769

Epoch 76: val_accuracy did not improve from 0.80769

Epoch 77: val_accuracy improved from 0.80769 to 0.81731, saving model to best_model.h5

Epoch 78: val_accuracy did not improve from 0.81731

Epoch 79: val_accuracy improved from 0.81731 to 0.83654, saving model to best_model.h5

Epoch 80: val_accuracy did not improve from 0.83654

Epoch 81: val_accuracy did not improve from 0.83654

Epoch 82: val_accuracy did not improve from 0.83654

Epoch 83: val_accuracy did not improve from 0.83654

Epoch 84: val_accuracy improved from 0.83654 to 0.84615, saving model to best_model.h5

Epoch 85: val_accuracy did not improve from 0.84615

Epoch 86: val_accuracy did not improve from 0.84615

Epoch 87: val_accuracy did not improve from 0.84615

Epoch 88: val_accuracy did not improve from 0.84615

Epoch 89: val_accuracy improved from 0.84615 to 0.85577, saving model to best_model.h5

Epoch 90: val_accuracy did not improve from 0.85577

Epoch 91: val_accuracy did not improve from 0.85577

Epoch 92: val_accuracy did not improve from 0.85577

Epoch 93: val_accuracy did not improve from 0.85577

Epoch 94: val_accuracy did not improve from 0.85577

Epoch 95: val_accuracy did not improve from 0.85577

Epoch 96: val_accuracy did not improve from 0.85577

Epoch 97: val_accuracy improved from 0.85577 to 0.86538, saving model to best_model.h5

Epoch 98: val_accuracy did not improve from 0.86538

Epoch 99: val_accuracy did not improve from 0.86538

Epoch 100: val_accuracy did not improve from 0.86538

Epoch 101: val_accuracy did not improve from 0.86538

Epoch 102: val_accuracy did not improve from 0.86538

Epoch 103: val_accuracy did not improve from 0.86538

Epoch 104: val_accuracy did not improve from 0.86538

Epoch 105: val_accuracy did not improve from 0.86538

Epoch 106: val_accuracy did not improve from 0.86538

Epoch 107: val_accuracy did not improve from 0.86538

Epoch 108: val_accuracy did not improve from 0.86538

Epoch 109: val_accuracy did not improve from 0.86538

Epoch 110: val_accuracy did not improve from 0.86538

Epoch 111: val_accuracy did not improve from 0.86538

Epoch 112: val_accuracy improved from 0.86538 to 0.87500, saving model to best_model.h5

Epoch 113: val_accuracy improved from 0.87500 to 0.88462, saving model to best_model.h5

Epoch 114: val_accuracy did not improve from 0.88462

Epoch 115: val_accuracy did not improve from 0.88462

Epoch 116: val_accuracy did not improve from 0.88462

Epoch 117: val_accuracy did not improve from 0.88462

Epoch 118: val_accuracy did not improve from 0.88462

Epoch 119: val_accuracy did not improve from 0.88462

Epoch 120: val_accuracy did not improve from 0.88462

Epoch 121: val_accuracy did not improve from 0.88462

Epoch 122: val_accuracy did not improve from 0.88462

Epoch 123: val_accuracy did not improve from 0.88462

Epoch 124: val_accuracy did not improve from 0.88462

Epoch 125: val_accuracy did not improve from 0.88462

Epoch 126: val_accuracy did not improve from 0.88462

Epoch 127: val_accuracy did not improve from 0.88462

Epoch 128: val_accuracy did not improve from 0.88462

Epoch 129: val_accuracy did not improve from 0.88462

Epoch 130: val_accuracy did not improve from 0.88462

Epoch 131: val_accuracy did not improve from 0.88462

Epoch 132: val_accuracy did not improve from 0.88462

Epoch 133: val_accuracy did not improve from 0.88462

Epoch 134: val_accuracy did not improve from 0.88462

Epoch 135: val_accuracy did not improve from 0.88462

Epoch 136: val_accuracy did not improve from 0.88462

Epoch 137: val_accuracy did not improve from 0.88462

Epoch 138: val_accuracy did not improve from 0.88462

Epoch 139: val_accuracy did not improve from 0.88462

Epoch 140: val_accuracy did not improve from 0.88462

Epoch 141: val_accuracy did not improve from 0.88462

Epoch 142: val_accuracy did not improve from 0.88462

Epoch 143: val_accuracy did not improve from 0.88462

Epoch 144: val_accuracy did not improve from 0.88462

Epoch 145: val_accuracy did not improve from 0.88462

Epoch 146: val_accuracy did not improve from 0.88462
Epoch 147: val_accuracy did not improve from 0.88462

Epoch 148: val_accuracy did not improve from 0.88462

Epoch 149: val_accuracy did not improve from 0.88462

Epoch 150: val_accuracy did not improve from 0.88462

Epoch 151: val_accuracy did not improve from 0.88462

Epoch 152: val_accuracy did not improve from 0.88462

Epoch 153: val_accuracy did not improve from 0.88462

Epoch 154: val_accuracy did not improve from 0.88462

Epoch 155: val_accuracy did not improve from 0.88462

Epoch 156: val_accuracy did not improve from 0.88462

Epoch 157: val_accuracy did not improve from 0.88462

Epoch 158: val_accuracy did not improve from 0.88462

Epoch 159: val_accuracy did not improve from 0.88462

Epoch 160: val_accuracy did not improve from 0.88462

Epoch 161: val_accuracy did not improve from 0.88462

Epoch 162: val_accuracy did not improve from 0.88462

Epoch 163: val_accuracy improved from 0.88462 to 0.89423, saving model to best_model.h5

Epoch 164: val_accuracy did not improve from 0.89423

Epoch 165: val_accuracy did not improve from 0.89423

Epoch 166: val_accuracy did not improve from 0.89423

Epoch 167: val_accuracy did not improve from 0.89423

Epoch 168: val_accuracy did not improve from 0.89423

Epoch 169: val_accuracy did not improve from 0.89423

Epoch 170: val_accuracy did not improve from 0.89423

Epoch 171: val_accuracy did not improve from 0.89423

Epoch 172: val_accuracy did not improve from 0.89423

Epoch 173: val_accuracy did not improve from 0.89423

Epoch 174: val_accuracy did not improve from 0.89423

Epoch 175: val_accuracy did not improve from 0.89423

Epoch 176: val_accuracy did not improve from 0.89423

Epoch 177: val_accuracy did not improve from 0.89423

Epoch 178: val_accuracy did not improve from 0.89423

Epoch 179: val_accuracy did not improve from 0.89423

Epoch 180: val_accuracy did not improve from 0.89423

Epoch 181: val_accuracy did not improve from 0.89423

Epoch 182: val_accuracy improved from 0.89423 to 0.91346, saving model to best_model.h5

Epoch 183: val_accuracy did not improve from 0.91346

Epoch 184: val_accuracy did not improve from 0.91346

Epoch 185: val_accuracy did not improve from 0.91346

Epoch 186: val_accuracy did not improve from 0.91346

Epoch 187: val_accuracy did not improve from 0.91346

Epoch 188: val_accuracy did not improve from 0.91346

Epoch 189: val_accuracy did not improve from 0.91346

Epoch 190: val_accuracy did not improve from 0.91346

Epoch 191: val_accuracy did not improve from 0.91346

Epoch 192: val_accuracy did not improve from 0.91346

Epoch 193: val_accuracy did not improve from 0.91346

Epoch 194: val_accuracy did not improve from 0.91346

Epoch 195: val_accuracy did not improve from 0.91346

Epoch 196: val_accuracy did not improve from 0.91346

Epoch 197: val_accuracy did not improve from 0.91346

Epoch 198: val_accuracy improved from 0.91346 to 0.92308, saving model to best_model.h5

Epoch 199: val_accuracy did not improve from 0.92308

Epoch 200: val_accuracy did not improve from 0.92308

Epoch 201: val_accuracy did not improve from 0.92308

Epoch 202: val_accuracy did not improve from 0.92308

Epoch 203: val_accuracy improved from 0.92308 to 0.93269, saving model to best_model.h5

Epoch 204: val_accuracy improved from 0.93269 to 0.94231, saving model to best_model.h5

Epoch 205: val_accuracy improved from 0.94231 to 0.95192, saving model to best_model.h5

Epoch 206: val_accuracy did not improve from 0.95192

Epoch 207: val_accuracy did not improve from 0.95192

Epoch 208: val_accuracy did not improve from 0.95192

Epoch 209: val_accuracy did not improve from 0.95192

Epoch 210: val_accuracy did not improve from 0.95192

Epoch 211: val_accuracy improved from 0.95192 to 0.96154, saving model to best_model.h5

Epoch 212: val_accuracy improved from 0.96154 to 0.97115, saving model to best_model.h5

Epoch 213: val_accuracy did not improve from 0.97115

Epoch 214: val_accuracy did not improve from 0.97115

Epoch 215: val_accuracy did not improve from 0.97115

Epoch 216: val_accuracy did not improve from 0.97115

Epoch 217: val_accuracy did not improve from 0.97115

Epoch 218: val_accuracy did not improve from 0.97115

Epoch 219: val_accuracy did not improve from 0.97115

Epoch 220: val_accuracy did not improve from 0.97115

Epoch 221: val_accuracy did not improve from 0.97115

Epoch 222: val_accuracy did not improve from 0.97115

Epoch 223: val_accuracy did not improve from 0.97115

Epoch 224: val_accuracy did not improve from 0.97115

Epoch 225: val_accuracy did not improve from 0.97115

Epoch 226: val_accuracy did not improve from 0.97115

Epoch 227: val_accuracy did not improve from 0.97115

Epoch 228: val_accuracy did not improve from 0.97115

Epoch 229: val_accuracy did not improve from 0.97115

Epoch 230: val_accuracy did not improve from 0.97115

Epoch 231: val_accuracy did not improve from 0.97115

Epoch 232: val_accuracy did not improve from 0.97115

Epoch 233: val_accuracy did not improve from 0.97115

Epoch 234: val_accuracy did not improve from 0.97115

Epoch 235: val_accuracy did not improve from 0.97115

Epoch 236: val_accuracy did not improve from 0.97115

Epoch 237: val_accuracy did not improve from 0.97115

Epoch 238: val_accuracy did not improve from 0.97115

Epoch 239: val_accuracy did not improve from 0.97115

Epoch 240: val_accuracy did not improve from 0.97115

Epoch 241: val_accuracy did not improve from 0.97115

Epoch 242: val_accuracy did not improve from 0.97115

Epoch 243: val_accuracy did not improve from 0.97115

Epoch 244: val_accuracy did not improve from 0.97115

Epoch 245: val_accuracy did not improve from 0.97115

Epoch 246: val_accuracy did not improve from 0.97115

Epoch 247: val_accuracy did not improve from 0.97115

Epoch 248: val_accuracy did not improve from 0.97115

Epoch 249: val_accuracy did not improve from 0.97115

Epoch 250: val_accuracy did not improve from 0.97115

Let’s plot training history
plt.plot(history.history[‘loss’], label=’train’)
plt.plot(history.history[‘val_loss’], label=’valid’)
plt.legend()
plt.xlabel(‘Epochs’, fontsize=14)
plt.ylabel(‘Loss’, fontsize=14)
plt.title(‘Loss Curves’, fontsize=16)
plt.savefig(‘losscurvesfinal.png’)
plt.show()

Final loss curves training/validation data

Let’s plot final accuracy plot

plt.figure(figsize=[8,5])
plt.plot(history.history[‘accuracy’], label=’Train’)
plt.plot(history.history[‘val_accuracy’], label=’Valid’)
plt.legend()
plt.xlabel(‘Epochs’, fontsize=16)
plt.ylabel(‘Accuracy’, fontsize=16)
plt.title(‘Accuracy Curves’, fontsize=16)
plt.savefig(‘accuracycurvesfinal.png’)
plt.show()

Final accuracy curves training/validation data

The final accuracy values are as follows

_, train_acc = model.evaluate(X_train, y_train, verbose=0)

_, valid_acc = model.evaluate(X_test, y_test, verbose=0)

print(‘Train: %.3f, Valid: %.3f’ % (train_acc, valid_acc))

Train: 0.985, Valid: 0.962

The final model is optimal in that it resolves a trade-off between training/test/validation data leakage/overfitting and overall precision. Thus, the ANN-based optimized early stopping with patience and model checkpoint method avoids data overfitting and yields the accuracy scores of the training and validation data of 98.5% and 96.2%, respectively.

Conclusions

The key success for controlling wildfires is the early detection and accurate prediction of these catastrophic phenomena. The present use-case study offers opportunities for the wildfire community to apply ANN-based deep learning techniques in early wildfire warning systems, hazard assessment and related risk management. This includes the EDA sequence that focuses on understanding the effects of the physical and environmental conditions such as temperature, wind, humidity and relative humidity on predicting the occurrence of fire in a given area. It was found that the final three-fold EDA+ANN+HPO workflow with an accuracy of prediction of 98% performed the best. The data for this project is taken from the NE Portugal Fire Dataset (courtsey of University of Minho, Portugal). 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: