|
""" |
|
This function manages the general RNN architecture |
|
""" |
|
import os |
|
import random |
|
|
|
import numpy as np |
|
from keras import backend as K |
|
from keras.callbacks import EarlyStopping, TensorBoard |
|
|
|
|
|
IS_COLAB = (os.name == 'posix') |
|
LOAD_DATA = not (os.name == 'posix') |
|
|
|
if IS_COLAB: |
|
from datetime import datetime |
|
from packaging import version |
|
|
|
|
|
logdir = "logs/scalars/" + datetime.now().strftime("%Y%m%d-%H%M%S") |
|
tensorboard_callback = TensorBoard(log_dir=logdir) |
|
|
|
|
|
class RecurrentNeuralNetwork(object): |
|
def __init__(self, seed): |
|
""" |
|
Seed - The seed used to initialize the weights |
|
width, height, cells - used for defining the tensors used for the input images |
|
loss, metrics, optimizer, dropout_rate - settings used for compiling the siamese model (e.g., 'Accuracy' and 'ADAM) |
|
""" |
|
K.clear_session() |
|
self.seed = seed |
|
self.initialize_seed() |
|
self.model = None |
|
|
|
def initialize_seed(self): |
|
""" |
|
Initialize seed all for environment |
|
""" |
|
os.environ['PYTHONHASHSEED'] = str(self.seed) |
|
random.seed(self.seed) |
|
np.random.seed(self.seed) |
|
|
|
def _load_weights(self, weights_file): |
|
""" |
|
A function that attempts to load pre-existing weight files for the siamese model. If it succeeds then returns |
|
True and updates the weights, otherwise False. |
|
:return True if the file is already exists |
|
""" |
|
self.model.summary() |
|
self.load_file = weights_file |
|
if os.path.exists(weights_file): |
|
print('Loading pre-existed weights file') |
|
self.model.load_weights(weights_file) |
|
return True |
|
return False |
|
|
|
def fit(self, weights_file, batch_size, epochs, patience, min_delta, x_train, y_train, x_val, y_val): |
|
""" |
|
Function for fitting the model. If the weights already exist, just return the summary of the model. Otherwise, |
|
perform a whole train/validation/test split and train the model with the given parameters. |
|
""" |
|
|
|
if not self._load_weights(weights_file=weights_file): |
|
print('No such pre-existed weights file') |
|
print('Beginning to fit the model') |
|
if IS_COLAB: |
|
callbacks = [ |
|
tensorboard_callback, |
|
EarlyStopping(monitor='val_loss', patience=patience, min_delta=min_delta) |
|
] |
|
else: |
|
callbacks = [ |
|
EarlyStopping(monitor='val_loss', patience=patience, min_delta=min_delta) |
|
] |
|
self.model.fit(x_train, |
|
y_train, |
|
batch_size=batch_size, |
|
epochs=epochs, |
|
callbacks=callbacks, |
|
validation_data=(x_val, y_val)) |
|
self.model.save_weights(self.load_file) |
|
|
|
loss, accuracy = self.model.evaluate(x_val, y_val, batch_size=batch_size) |
|
print(f'Loss on Validation set: {loss}') |
|
print(f'Accuracy on Validation set: {accuracy}') |
|
|
|
def evaluate(self, x_test, y_test, batch_size): |
|
""" |
|
Function for evaluating the final model after training. |
|
test_file - file path to the test file. |
|
batch_size - the batch size used in training. |
|
|
|
Returns the loss and accuracy results. |
|
""" |
|
print(f'Available Metrics: {self.model.metrics_names}') |
|
y_test = np.array(y_test, dtype='float64') |
|
x_test[0] = np.array(x_test[0], dtype='float64') |
|
x_test[1] = np.array(x_test[1], dtype='float64') |
|
|
|
loss, accuracy = self.model.evaluate(x_test, y_test, batch_size=batch_size) |
|
return loss, accuracy |
|
|
|
def predict(self, data): |
|
return self.model.predict(data) |
|
|
|
|
|
print('Loaded Successfully') |
|
|