Load HDF5 checkpoint models with custom metrics - tensorflow

I've created a Keras Regressor to run a RandomizedSearch CV using a ModelCheckpoint callback, but the training overran the Colab runtime 12H limit and stopped halfway through. The models are saved in hdf5 format.
I used tensorflow_addons to add the RSquare class to monitor the R2 for train and validation sets. However, when I used keras.models.load_model, I get the following error:
As you can see from the traceback, I have passed the custom_objects parameter, but still it is not recognised.
How can I solve this?
You can see the full code example below:
import os
import tensorflow as tf
import tensorflow_addons as tfa
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Dropout
from tensorflow.keras.layers import Input, InputLayer
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint
from keras.wrappers.scikit_learn import KerasRegressor
from sklearn.model_selection import RandomizedSearchCV
def build_model(n_hidden = 2, n_neurons = 64, input_shape = (X_train.shape[1],), dropout = 0):
model = Sequential()
model.add(InputLayer(input_shape = input_shape))
for i in range(n_hidden):
model.add(Dense(n_neurons, activation = 'relu'))
model.add(Dropout(dropout))
model.add(Dense(1))
model.compile(loss = 'mean_squared_error', optimizer = 'adam', metrics = [tfa.metrics.RSquare(y_shape=(1,))])
return model
keras_reg = KerasRegressor(build_model)
checkdir = os.path.join(r'/content/drive/MyDrive/COP328/Case A', 'checkpoints', datetime.datetime.now().strftime('%d-%m-%Y_%H-%M-%S'), 'imputed_log1p-{epoch:02d}-{val_r_square:.3f}.hdf5')
callbacks = [ModelCheckpoint(checkdir, save_freq='epoch', save_best_only = True, monitor = 'val_r_square', mode = 'max'),
EarlyStopping(patience = 10)]
# Here is where training got interrupted because of Colab runtime being dropped:
param_dist = {
'n_hidden' : [1,2],
'n_neurons': [8,16,32,64,128],
'dropout': [0,0.2,0.4]
}
rnd_search_cv = RandomizedSearchCV(keras_reg, param_dist, n_iter= 15, cv = 5)
rnd_search_cv.fit(X_train, y_train, epochs = 200, batch_size = 64,
validation_data = (X_valid,y_valid),
callbacks = callbacks)
# Here is where I am trying to reload one of the most promising models based on R2, and getting the error:
from keras.models import load_model
import tensorflow_addons as tfa
rnd_model = load_model(r'/content/drive/MyDrive/COP328/Case A/checkpoints/26-06-2021_17-32-29/imputed_log1p-56-1.000.hdf5', custom_objects = {'r_square': tfa.metrics.RSquare, 'val_r_square': tfa.metrics.RSquare})

This solution doesn't take into account the addons package but one possibility is to create the coefficient of determination (R^2) as a different metric without that package, and then defining it as your loss.
def coeff_determination(y_true, y_pred):
from keras import backend as K
SS_res = K.sum(K.square( y_true-y_pred ))
SS_tot = K.sum(K.square( y_true - K.mean(y_true) ) )
return ( 1 - SS_res/(SS_tot + K.epsilon()) )
Recall that minimizing MSE will maximize R^2.

Related

Keras predicting different output for same input image

am working on a classification problem for binary classes, I have finished the training and testing the model in single images now using the below code
import warnings
import time
from urllib.request import urlopen
import os
import urllib.request
start_time = time.time()
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=FutureWarning)
import numpy as np
from keras.preprocessing.image import img_to_array, load_img
from keras.models import Sequential
from keras.layers import Dropout, Flatten, Dense, GlobalAveragePooling2D
from keras.applications.vgg16 import VGG16
import tensorflow as tf
import logging
logging.getLogger('tensorflow').disabled = True
img_size = 224
class PersonPrediction:
def __init__(self):
self.class_dictionary = np.load(
'class_indices_vgg.npy',
allow_pickle=True).item()
self.top_model_weights_path = 'v2/weights/bottleneck_fc_model_2020-10-10-05.h5'
self.num_classes = len(self.class_dictionary)
self.model = self.create_model(self.num_classes)
self.graph = tf.compat.v1.get_default_graph()
def create_model(self, num_of_cls):
model = Sequential()
vgg_model = VGG16(include_top=False, weights='imagenet', input_shape=(img_size, img_size, 3))
for layer in vgg_model.layers[:-4]:
layer.trainable = False
model.add(vgg_model)
model.add(GlobalAveragePooling2D())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1, activation='sigmoid'))
return model
def predict(self, path=None, file_name=None):
if path:
image_path = path
path = self.url_to_image(image_path)
else:
path = os.path.join('imgs', file_name)
print("[INFO] loading and preprocessing image...")
image = load_img(path, target_size=(224, 224))
image = img_to_array(image)
# important! otherwise the predictions will be '0'
image = image / 255
image = np.expand_dims(image, axis=0)
label_idx = self.model.predict_classes(image)[0][0]
probability = self.model.predict(image)[0]
inv_map = {v: k for k, v in self.class_dictionary.items()}
label = inv_map[label_idx]
return label, probability[0]
path = 'temp.jpg'
tax_model = PersonPrediction()
label, proba = tax_model.predict(
file_name='frame303.jpg')
print(label, proba)
Problem is I keep getting chaning predictions of both label and accuracy every time I rerun the code, am not sure what is causing that
There are a number of sources that create randomness in the results when training a model. First the weights are randomly initialized so your model is starting from a different point in N space (N is the number of trainable parameters). Second layers like dropout have randomness in terms of which nodes will be nodes will be selected. Some GPU processes particularly with multi-processing can also have some degree of randomness. I have seen a number of posts on getting repeatable results in tensorflow but I have not found one that seems to really work. In general though the results should be reasonably close if your model is working correctly and you run enough epochs. Now once the model is trained and you use it for predictions as long as you use the same trained model you should get identical prediction results.

Reproduce same results on each run - Keras, Google Colab

I run the following code in Google Colab(with GPU):
import random
random.seed(1)
import numpy as np
from numpy.random import seed
seed(1)
from tensorflow import set_random_seed
set_random_seed(2)
import pandas as pd
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.layers import Flatten, Dense, Lambda, SimpleRNN
from keras.optimizers import *
from keras.utils import np_utils
from keras.initializers import *
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, roc_auc_score, auc, precision_recall_curve
from sklearn.metrics import confusion_matrix
from keras.callbacks import EarlyStopping
from keras import backend as K
session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)
##Loading dataset train and validation files, the files are same for every run
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=5)
print("***********************************************************************************************")
def make_model():
model = Sequential()
model.add(Conv2D(10,(5,5), kernel_initializer=glorot_uniform(seed=1), input_shape = (22,10,1), use_bias = True, activation = "relu", strides = 1, padding = "valid"))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(20, kernel_initializer=glorot_uniform(seed=1), activation = "relu"))
model.add(Lambda(lambda x: tf.expand_dims(x, axis=1)))
model.add(SimpleRNN(20, kernel_initializer=glorot_uniform(seed=1), activation="relu",return_sequences=False))
model.add(Dense(1, kernel_initializer=glorot_uniform(seed=1), activation="sigmoid"))
opti = SGD(lr = 0.01)
model.compile(loss = "binary_crossentropy", optimizer = opti, metrics = ["accuracy"])
return model
model = make_model()
model.fit(x_train, y_train, validation_data = (x_validation,y_validation), epochs = 50, batch_size = 20, verbose = 2, callbacks=[es])
Despite setting all seed values, my prediction results of the model are different on subsequent runs. The training and testing of the model happens in the same Colab cell.
You are dealing with floating point numbers that are multiplied and added on different threads and can therefore happen in different order. Floating point additions and multiplications are not commutative. See What Every Computer Scientist Should Know About Floating-Point Arithmetic.

How to add a constant tensor to Input tensor in Keras/tensorflow

I have a simple CNN with inputs of shape (5,5,3). As a first step I want to add a constant tensor to the input.
With the code below, I get
AttributeError: 'NoneType' object has no attribute '_inbound_nodes'
I have tried a few things like
const_change = Input(tensor=tf.constant([ ...
or
const_change = Input(tensor=K.variable([ ...
but nothing seems to work. Any help is highly appreciated.
from __future__ import print_function
import tensorflow as tf
import numpy as np
import keras
from keras import backend as K
from keras.models import Model
from keras.layers import Input
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
# Python 2.7.10
# keras version 2.2.0
# tf.VERSION '1.8.0'
raw_input = Input(shape=(5, 5, 3))
const_change = tf.constant([
[[5.0,0.0,0.0],[0.0,0.0,-3.0],[-10.0,0.0,0.0],[0.0,0.0,4.0],[-20.0,0.0,0.0]],
[[-15.0,0.0,12.0],[0.0,4.0,0.0],[-3.0,0.0,10.0],[-18.0,0.0,0.0],[20.0,0.0,-6.0]],
[[0.0,0.0,6.0],[0.0,-2.0,-6.0],[0.0,0.0,2.0],[0.0,0.0,-9.0],[7.0,-6.0,0.0]],
[[-3.0,4.0,0.0],[11.0,-12.0,0.0],[0.0,0.0,0.0],[0.0,0.0,7.0],[0.0,0.0,2.0]],
[[0.0,0.0,0.0],[0.0,1.0,-2.0],[4.0,0.0,3.0],[0.0,0.0,0.0],[0.0,0.0,0.0]]])
cnn_layer1 = Conv2D(32, (4, 4), activation='relu')
cnn_layer2 = MaxPooling2D(pool_size=(2, 2))
cnn_layer3 = Dense(128, activation='relu')
cnn_layer4 = Dropout(0.1)
cnn_output = Dense(4, activation='softmax')
proc_input = keras.layers.Add()([raw_input, const_change])
# proc_input = keras.layers.add([raw_input, const_change]) -> leads to the same error (see below)
lay1 = cnn_layer1(proc_input)
lay2 = cnn_layer2(lay1)
lay3 = Flatten()(lay2)
lay4 = cnn_layer3(lay3)
lay5 = cnn_layer4(lay4)
lay_out = cnn_output(lay5)
model = Model(inputs=raw_input, outputs=lay_out)
# -> AttributeError: 'NoneType' object has no attribute '_inbound_nodes'
The const_change should be also Input just like raw_input. You can create another input layer named const_input, and feed raw_input and const_input together into model.
...
const_input = Input(tensor=const_change)
...
proc_input = keras.layers.Add()[raw_input, const_input]
...
model = Model(inputs=[raw_input, const_input], outputs=lay_out)

Sequential' object has no attribute '_ckpt_saved_epoch' error when trying to save my model using callback on Keras

I got this error when i tried to save my MobileNet model.
Traceback (most recent call last): File "../src/script.py", line 150, in <module> callbacks=[cb_checkpointer, cb_early_stopper] File "/opt/conda/lib/python3.6/site-packages/keras/legacy/interfaces.py", line 91, in wrapper
return func(*args, **kwargs) File "/opt/conda/lib/python3.6/site-packages/keras/engine/training.py", line 1418, in fit_generator
initial_epoch=initial_epoch) File "/opt/conda/lib/python3.6/site-packages/keras/engine/training_generator.py", line 264, in fit_generator
callbacks.on_train_end() File "/opt/conda/lib/python3.6/site-packages/keras/callbacks.py", line 142, in on_train_end callback.on_train_end(logs) File "/opt/conda/lib/python3.6/site-packages/tensorflow/python/keras/callbacks.py", line 940, in on_train_end
if self.model._ckpt_saved_epoch is not None: AttributeError: 'Sequential' object has no attribute '_ckpt_saved_epoch'
I am using callbacks for saving:
filepath="weights-improvement-{epoch:02d}-{val_acc:.2f}.hdf5"
cb_early_stopper = EarlyStopping(monitor = 'val_loss', mode='min', verbose=1, patience = EARLY_STOP_PATIENCE)
cb_checkpointer = ModelCheckpoint(filepath = filepath, monitor = 'val_loss', save_best_only = True, mode = 'auto')
My model code:
import numpy as np
import cv2
import os
#from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense
from tensorflow.python.keras import optimizers
from keras import regularizers
from keras.regularizers import l2
from keras.layers import Dropout
from keras.applications.mobilenet import MobileNet
from keras.layers import GlobalAveragePooling2D, Dense, Dropout, Flatten, BatchNormalization
from keras.models import Sequential
from keras.applications.resnet50 import preprocess_input
from keras.preprocessing.image import ImageDataGenerator
from tensorflow.python.keras.callbacks import EarlyStopping, ModelCheckpoint
#print(os.listdir("testset/"))
# Fixed for our classes
NUM_CLASSES = 3
# Fixed for color images
CHANNELS = 3
IMAGE_RESIZE = 224
RESNET50_POOLING_AVERAGE = 'avg'
DENSE_LAYER_ACTIVATION = 'softmax'
OBJECTIVE_FUNCTION = 'categorical_crossentropy'
# Common accuracy metric for all outputs, but can use different metrics for different output
LOSS_METRICS = ['accuracy']
# EARLY_STOP_PATIENCE must be < NUM_EPOCHS
NUM_EPOCHS = 100
EARLY_STOP_PATIENCE = 50
# These steps value should be proper FACTOR of no.-of-images in train & valid folders respectively
# Training images processed in each step would be no.-of-train-images / STEPS_PER_EPOCH_TRAINING
STEPS_PER_EPOCH_TRAINING = 27
STEPS_PER_EPOCH_VALIDATION = 11
# These steps value should be proper FACTOR of no.-of-images in train & valid folders respectively
# NOTE that these BATCH* are for Keras ImageDataGenerator batching to fill epoch step input
BATCH_SIZE_TRAINING = 8
BATCH_SIZE_VALIDATION = 8
base_mobilenet_model = MobileNet(include_top = False, weights = None)
model = Sequential()
model.add(BatchNormalization(input_shape = [224,224,3]))
model.add(base_mobilenet_model)
model.add(BatchNormalization())
model.add(GlobalAveragePooling2D())
model.add(Dropout(0.5))
# 2nd layer as Dense for 3-class classification,
model.add(Dense(NUM_CLASSES, activation = DENSE_LAYER_ACTIVATION,activity_regularizer=regularizers.l2(0.01)))
model.summary()
model.compile(optimizer = 'adam', loss = OBJECTIVE_FUNCTION, metrics = LOSS_METRICS)
image_size = IMAGE_RESIZE
shift = 0.2
# preprocessing_function is applied on each image but only after re-sizing & augmentation (resize => augment => pre-process)
# Each of the keras.application.resnet* preprocess_input MOSTLY mean BATCH NORMALIZATION (applied on each batch) stabilize the inputs to nonlinear activation functions
# Batch Normalization helps in faster convergence
# featurewise_center=True, featurewise_std_normalization=True,
data_generator = ImageDataGenerator(preprocessing_function=preprocess_input,
width_shift_range=shift,
height_shift_range=shift,
horizontal_flip=True,
vertical_flip=True,
rotation_range=45,
brightness_range=[0.2,1.0],
zoom_range=[0.5,1.0]
)
# flow_From_directory generates batches of augmented data (where augmentation can be color conversion, etc)
# Both train & valid folders must have NUM_CLASSES sub-folders
train_generator = data_generator.flow_from_directory(
'/kaggle/input/grade-dataset/trainset/',
target_size=(image_size, image_size),
batch_size=BATCH_SIZE_TRAINING,
class_mode='categorical')
validation_generator = data_generator.flow_from_directory(
'/kaggle/input/grade-dataset/testset/',
target_size=(image_size, image_size),
batch_size=BATCH_SIZE_VALIDATION,
class_mode='categorical')
# Max number of steps that these generator will have opportunity to process their source content
# len(train_generator) should be 'no. of available train images / BATCH_SIZE_TRAINING'
# len(valid_generator) should be 'no. of available train images / BATCH_SIZE_VALIDATION'
(BATCH_SIZE_TRAINING, len(train_generator), BATCH_SIZE_VALIDATION, len(validation_generator))
# Early stopping & checkpointing the best model in ../working dir & restoring that as our model for prediction
filepath="weights-improvement-{epoch:02d}-{val_acc:.2f}.hdf5"
cb_early_stopper = EarlyStopping(monitor = 'val_loss', mode='min', verbose=1, patience = EARLY_STOP_PATIENCE)
cb_checkpointer = ModelCheckpoint(filepath = filepath, monitor = 'val_loss', save_best_only = True, mode = 'auto')
fit_history = model.fit_generator(
train_generator,
steps_per_epoch=STEPS_PER_EPOCH_TRAINING,
epochs = NUM_EPOCHS,
validation_data=validation_generator,
validation_steps=STEPS_PER_EPOCH_VALIDATION,
callbacks=[cb_checkpointer, cb_early_stopper]
)
I solved the problem by replacing the code:
from tensorflow.python.keras.callbacks import EarlyStopping, ModelCheckpoint
with the code:
from keras.callbacks import EarlyStopping, ModelCheckpoint
Mentioning the Solution here, for the benefit of the Community.
Replacing the code,
from tensorflow.python.keras.callbacks import EarlyStopping, ModelCheckpoint
with the code,
from keras.callbacks import EarlyStopping, ModelCheckpoint
has resolved the error.

Best method for defining layers using tf keras api?

tensorflow.keras api not working on while creating the layers reference, any other methods of creating layers reference?
code :
layer=keras.layers
Error message : NameError: name 'leyer' is not defined
Full code is pasted here...
import tensorflow as tf
from tensorflow import keras
import pandas as pd
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
from sklearn.preprocessing import LabelEncoder
import numpy as np
#makin seed values
seed=7
np.random.seed(seed)
#setting up the dataset for training
dataframe=pd.read_csv("../datasets/iris.csv",header=None)
data=dataframe.values
input_x = data[:,0:4]
true_y = data[:,4]
#Encoding the true_y data to one hot encoding
le=LabelEncoder()
le.fit(true_y)
y_encoded = le.transform(true_y)
y_encoded = keras.utils.to_categorical(y_encoded,num_classes=3)
# creating the model
def base_fun():
layer=keras.layers
model = keras.models.Sequential()
model.add(layer.Dense(4,input_dim=4,kernel_initializer='normal',activation='relu'))
model.add(leyer.Dense(3, kernel_initializer='normal', activation='relu'))
estimator=keras.wrappers.scikit_learn.KerasClassifier(build_fn=base_fun,epochs=20,batch_size=10)
kfold = KFold(n_splits=10, shuffle=True, random_state=seed)
result = cross_val_score(estimator, input_x, y_encoded,cv=kfold)
print("Accuracy : %.2%% (%.2%%)" %(result.mean()*100, result.std()*100))
Well, this line:
model.add(leyer.Dnese(3, kernel_initializer='normal', activation='relu'))
has two typos, namely leyer should be layer and Dnese should be Dense like
model.add(layer.Dense(3, kernel_initializer='normal', activation='relu'))
Based on your comment, this line also causes an error:
estimator = keras.wrappers.scikit_learn.KerasClassifier( build_fn = base_fun, epochs = 20, batch_size = 10 )
From the Keras Scikit documentation:
build_fn should construct, compile and return a Keras model, which will then be used to fit/predict.
But you function base_fun() does not return anything. Append this line at the end of base_fun():
return model
As per your comment, the last print line could be changed to this (I don't know the % formatting, I generally use the syntax below):
print( "Accuracy : {:.2%} ({:.2%})".format( result.mean(), result.std() ) )