forked from AhmedAhres/Satellite-Image-Classification
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcnn_model.py
More file actions
135 lines (102 loc) · 5.17 KB
/
cnn_model.py
File metadata and controls
135 lines (102 loc) · 5.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#Import TensorFlow and Keras
import tensorflow as tf
from tensorflow import keras
#Import all the necessary for our model
from keras.optimizers import Adam
from keras.utils import to_categorical
from keras.callbacks import ReduceLROnPlateau, EarlyStopping, TensorBoard
from keras.regularizers import l2
from keras.models import Sequential, load_model
from keras.layers import Activation, Dropout, Flatten, Dense, Conv2D, MaxPooling2D, LeakyReLU
#Import helper libraries
import numpy as np
import scipy as scipy
from helpers import *
class cnn_model:
# Initialize the class
def __init__(self, shape):
self.shape = shape
self.model = self.initialize_cnn_model(shape)
def initialize_cnn_model(self, shape):
# INPUT
# shape - Size of the input images
# OUTPUT
# model - Compiled CNN
# Define hyperparamters
KERNEL3 = (3, 3)
KERNEL5 = (5, 5)
# Define a model
model = Sequential()
# Add the layers
# Selection of the model is described in the report
# We use padding = 'same' to avoid issues with the matrix sizes
model.add(Conv2D(64, KERNEL5, input_shape = shape, padding='same'))
model.add(LeakyReLU(alpha=0.1))
model.add(MaxPooling2D(pool_size=(2, 2), padding='same'))
model.add(Dropout(0.25))
model.add(Conv2D(128, KERNEL3, padding='same'))
model.add(LeakyReLU(alpha=0.1))
model.add(MaxPooling2D(pool_size=(2, 2), padding='same'))
model.add(Dropout(0.25))
model.add(Conv2D(256, KERNEL3, padding='same'))
model.add(LeakyReLU(alpha=0.1))
model.add(MaxPooling2D(pool_size=(2, 2), padding='same'))
model.add(Dropout(0.25))
model.add(Conv2D(256, KERNEL3, padding='same'))
model.add(LeakyReLU(alpha=0.1))
model.add(MaxPooling2D(pool_size=(2, 2), padding='same'))
model.add(Dropout(0.25))
model.add(Conv2D(256, KERNEL3, padding='same'))
model.add(LeakyReLU(alpha=0.1))
model.add(MaxPooling2D(pool_size=(2, 2), padding='same'))
model.add(Dropout(0.25))
model.add(Conv2D(256, KERNEL3, padding='same'))
model.add(LeakyReLU(alpha=0.1))
model.add(MaxPooling2D(pool_size=(2, 2), padding='same'))
model.add(Dropout(0.25))
# Flatten it and use regularizers to avoid overfitting
# The parameters have been chosen empirically
model.add(Flatten())
model.add(Dense(128, kernel_regularizer=l2(0.000001), activity_regularizer=l2(0.000001)))
model.add(LeakyReLU(alpha=0.1))
model.add(Dropout(0.5))
# Add output layer
model.add(Dense(2, kernel_regularizer=l2(0.000001), activity_regularizer=l2(0.000001)))
model.add(Activation('sigmoid'))
# Compile the model using the binary crossentropy loss and the Adam optimizer for it
# We used the accuracy as a metric, but F1 score is also a plausible choice
model.compile(loss='binary_crossentropy',
optimizer=Adam(lr=0.001),
metrics=['accuracy'])
# Print a summary of the model to see what has been generated
model.summary()
return model
def train(self):
# We define the number of epochs and steps per epochs
EPOCHS = 150
STEPS_PER_EPOCH = 1500
# Early stopping callback after 10 steps
early_stopping = EarlyStopping(monitor='loss', min_delta=0, patience=10, verbose=1, mode='auto')
# Reduce learning rate on plateau after 4 steps
lr_callback = ReduceLROnPlateau(monitor='loss', factor=0.5, patience=4, verbose=1, mode='auto')
# Tensorboard to visualize the training
tensorboard = keras.callbacks.TensorBoard(log_dir='./log_last_test', histogram_freq=0, batch_size=125, write_graph=True, write_grads=False, write_images=False, embeddings_freq=0, embeddings_layer_names=None, embeddings_metadata=None, embeddings_data=None)
# Place the callbacks in a list to be used when training
callbacks = [early_stopping, lr_callback, tensorboard]
# Train the model using the previously defined functions and callbacks
self.model.fit_generator(create_minibatch(), steps_per_epoch=STEPS_PER_EPOCH, epochs=EPOCHS,\
use_multiprocessing=False, workers=1, callbacks=callbacks, verbose=1)
def classify(self, X):
# Subdivide the images into blocks with a stride and patch_size of 16
img_patches = create_patches(X, 16, 16, padding=28)
# Predict
predictions = self.model.predict(img_patches)
predictions = (predictions[:,0] < predictions[:,1]) * 1
# Regroup patches into images
return group_patches(predictions, X.shape[0])
def load(self, filename):
# Load the model (used for submission)
self.model = load_model(filename)
def save(self, filename):
# Save the model (used to then load to submit)
self.model.save(filename)