import datetime
import os
import yaml
import kerastuner as kt
import tensorflow as tf
[docs]class build_param():
def __init__(self, config_path):
with open(config_path + 'tuner_config.yaml', 'r') as file:
self.hparam = yaml.load(file, Loader=yaml.FullLoader)
global tuner_parameters
tuner_parameters = self.hparam
[docs]def build_tuner_model(hp):
'''
Functions that builds a convolutional keras model with
tunable hyperparameters
Parameters
----------
hp: keras tuner class
A class that is used to define the parameter search space
Returns
-------
model: Keras sequential model
The trained convolutional neural network
'''
###################################
# loading the configuration file for tuner
param = tuner_parameters
####################################
# Defining input size
# need to put input shape in the config file
input = (param['input_shape'][0], param['input_shape'][0],
param['input_shape'][1])
inputs = tf.keras.Input(shape=input)
x = inputs
####################################
# extracting parameters from the parameters file
# and feeding in the tuner
kernel = getattr(
hp, param['kernel_size'][0])(
'kernel_size', values=param['kernel_size'][1]['values']),
kernel_size = (kernel[0], kernel[0])
filter = getattr(
hp, param['filters'][0])(
'filters', min(param['filters'][1]['values']),
max(param['filters'][1]['values']), step=4, default=8)
for i in range(hp.Int('conv_layers', 1, max(param['layers']),
default=3)):
x = tf.keras.layers.Conv2D(
filters=filter*(i+1),
kernel_size=kernel_size,
activation=getattr(hp, param['activation'][0])
('activation_' + str(i+1), values=param['activation'][1]['values']
), padding='same')(x)
if getattr(hp,
param['pooling'][0])('pooling',
values=param['pooling'][1]['values'])\
== 'max':
x = tf.keras.layers.GlobalMaxPooling2D()(x)
else:
x = tf.keras.layers.GlobalAveragePooling2D()(x)
outputs = tf.keras.layers.Dense(
param['num_classes'][0], activation='softmax')(x)
model = tf.keras.Model(inputs, outputs)
# adding in the optimizer
optimizer = getattr(hp, param['optimizer'][0])('optimizer',
values=param['optimizer']
[1]['values'])
# compiling neural network model
model.compile(optimizer, loss='categorical_crossentropy',
metrics=['accuracy'])
return model
[docs]def best_model(tuner, training_set, validation_set, test_set):
'''
Function that takes the tuner and builds up the model on the basis on best
hyperparameters in the tuner
Parameters
----------
tuner: keras tuner
tuner generated by specifications from tuner_build_model function
training_set: keras pointer
training set data generated through flow from directory
validation_set: keras pointer
validation set data generated through flow from directory
test_set: keras point
test_set data generated through flow from directory. Used for
cross validation of model
epochs: int
the number of times model is executed to be trained over
training set & validation set
Returns
-------
model: keras model
model built up using the best hyperparameters in the tuner
history: dict
dictionary containing result from fitting model oveer training
and validation set
metrics: np.float64
np array containing loss and accuracy for cross-validation of data
'''
param = tuner_parameters
best_hp = tuner.get_best_hyperparameters()[0]
early_stopping = tf.keras.callbacks.EarlyStopping(monitor='loss',
patience=param['patience'
][0])
# best_hp_values = best_hp.values
model = tuner.hypermodel.build(best_hp)
history = model.fit(training_set, epochs=param['epochs'][0], verbose=0,
validation_data=validation_set,
callbacks=[early_stopping])
metrics = model.evaluate(test_set, verbose=0)
return model, history, metrics
[docs]def run_tuner(training_set, validation_set, project_name='untransformed'):
'''
Function that runs the tuner using training set, validation set and
hyperparameters defined in the config file
Parameters
----------
training_set: keras pointer
training set data generated through keras flow from
directory function
validation_set: keras pointer
validation set data generated through keras flow from
directory function
project_name: str
name to use for the log files of the tuner run
Returns
-------
tuner: keras tuner
'''
param = tuner_parameters
early_stopping = tf.keras.callbacks.EarlyStopping(monitor='loss',
patience=param['patience'
][0])
if param['search_function'][0] == 'BayesianOptimization':
tuner = getattr(kt.tuners, param['search_function'][0]
)(build_tuner_model, objective='val_accuracy',
max_trials=param['max_trials'][0],
# alpha=param['alpha'][0],
# beta=param['beta'][0],
executions_per_trial=param['exec_per_trial'][0],
project_name=project_name)
else:
tuner = getattr(kt.tuners, param['search_function'][0]
)(build_tuner_model, objective='val_accuracy',
max_trials=param['max_trials'][0],
executions_per_trial=param['exec_per_trial'][0],
project_name=project_name)
tuner.search(training_set, epochs=param['epochs'][0],
validation_data=validation_set,
verbose=2, callbacks=[early_stopping])
return tuner
[docs]def report_generation(model, history, metrics, log_dir,
tuner=None, save_model=True, config_path=None,
k_fold=False, k=None):
'''
Function that generates the report based on tuner search
and hyperparameters
Parameters
----------
tuner: keras tuner
tuner generated by the run_tuner function
model: keras model
model built up using the best hyperparameters in the tuner
generated by the tuner 'best_model' function
history: history: dict
dictionary containing result from fitting model over training
and validation set generated by best_model function
metrics: np.float64
np array containing loss and accuracy for cross-validation of
data generated by best_model function
log_dir: str
string representing the location where the report needs to be
stored
save_model: bool
If true saves the model with best hyperparameters in the
defined location
config_path: str
location of configuration file for the convolutional neural
network
Returns
-------
.yaml file containing the hyperparameters, performance and history
of the trained CNN
'''
if tuner is not None:
best_hp = tuner.get_best_hyperparameters()[0].values
else:
assert (config_path), "Please,Provide the config path"
with open(config_path + 'cnn_config.yaml', 'r') as file:
best_hp = yaml.load(file, Loader=yaml.FullLoader)
if save_model:
if not os.path.exists(log_dir):
os.makedirs(log_dir)
model_location = log_dir+'best_model'
model.save(model_location+'.h5')
model_location_dict = {'model_location': model_location}
else:
model_location = 'None'
model_location_dict = {'model_location': model_location}
metrics_accuracy = history.__dict__['history']
metrics_accuracy_feed = {}
for key, value in metrics_accuracy.items():
metrics_accuracy_feed.update({key: [float(item) for item in value]})
validation_metrics_dict = {'test_loss': float(metrics[0]),
'test_accuracy': float(metrics[1])}
report_location = log_dir+'/report/'
if not os.path.exists(report_location):
os.makedirs(report_location)
with open(report_location+datetime.datetime.now().strftime(
"%y%m%d_%H%M") + ".yaml", 'w') as yaml_file:
yaml.dump(best_hp, yaml_file)
yaml.dump(metrics_accuracy_feed, yaml_file)
yaml.dump(validation_metrics_dict, yaml_file)
yaml.dump(model_location_dict, yaml_file)
if k_fold:
k_val = {'k_folds': k}
yaml.dump(k_val, yaml_file)
yaml_file.close()
return