fernandoperlar/preprocessing_image
0
1from logging import Filter2import matplotlib.pyplot as plt3import matplotlib.cm as cm4import numpy as np5import cv2 as cv6import tensorflow as tf7from keras import callbacks, models, layers, utils, losses, preprocessing, backend8from sklearn import metrics9from tensorflow.keras import optimizers10from .Misc import *11 12class Model:13 def __init__(self, name, filter, new=True, summary=True, plot=True):14 self.name = name15 self.filter = filter16 self.model = self.__create_model()17 self.weights_path = f"./output/{self.name}/weights_" + "{epoch:03d}" + ".hdf5"18 self.best_epoch = 019 20 computer.create_output_folder(self.name, new)21 22 utils.vis_utils.plot_model(self.model, to_file=f"./output/{self.name}/model.png", show_shapes=True, show_layer_names=True)23 24 if summary:25 self.model.summary()26 27 if plot:28 plt.imshow(plt.imread(f"./output/{self.name}/model.png"))29 plt.axis("off")30 31 plt.show()32 33 def __create_model(self):34 class FilterLayer(layers.Layer):35 def __init__(self, filter, **kwargs):36 self.filter = filter37 38 super(FilterLayer, self).__init__(name="filter_layer", **kwargs)39 40 def call(self, image):41 shape = image.shape42 [image, ] = tf.py_function(self.filter, [image], [tf.float32])43 image = backend.stop_gradient(image)44 image.set_shape(shape)45 46 return image47 48 def get_config(self):49 return super().get_config()50 51 model = models.Sequential()52 53 model.add(layers.Input(shape=(215, 538, 3)))54 model.add(FilterLayer(filter=self.filter))55 56 model.add(layers.Conv2D(32, (3, 3), activation="relu"))57 model.add(layers.MaxPooling2D(pool_size=(2, 2)))58 59 model.add(layers.Conv2D(32, (3, 3), activation="relu"))60 model.add(layers.GlobalAveragePooling2D())61 62 model.add(layers.Dropout(rate=0.4))63 model.add(layers.Dense(32, activation="relu"))64 model.add(layers.Dropout(rate=0.4))65 model.add(layers.Dense(2, activation="softmax"))66 67 return model68 69 def compile(self): 70 self.model.compile(loss=losses.binary_crossentropy, optimizer=optimizers.Adam(learning_rate=5*10e-4), metrics=["accuracy"])71 72 with open(f"./output/{self.name}/model.json", "w") as json_file:73 json_file.write(self.model.to_json())74 75 def fit(self, train_generator, validation_generator, epochs, verbose=True, plot=True):76 class GetProgress(callbacks.Callback):77 def __init__(self, name, weights_path):78 self.name = name79 self.weights_path = weights_path80 self.best_accuracy = 081 self.best_epoch = 082 83 def on_epoch_end(self, epoch, logs=None):84 if logs["val_accuracy"] > self.best_accuracy:85 self.best_accuracy = logs["val_accuracy"]86 self.best_epoch = epoch87 88 print(89 f"\rModel {self.name} -> " +90 f"Epoch {epoch + 1}/{epochs} -> " +91 f"Accuracy (Validation): {round(logs['val_accuracy'], 2)} -> " +92 f"{self.weights_path.format(epoch=self.best_epoch + 1)}"93 , end="")94 95 if epoch + 1 >= epochs:96 print("\n", end="")97 98 checkpoint = callbacks.ModelCheckpoint(99 self.weights_path,100 monitor="val_accuracy",101 verbose=1 if verbose else 0,102 save_best_only=True,103 mode="max"104 )105 106 get_progress = GetProgress(self.name, self.weights_path)107 108 history = self.model.fit(109 train_generator,110 epochs=epochs,111 verbose=1 if verbose else 0,112 validation_data=validation_generator,113 callbacks=[114 checkpoint,115 get_progress116 ]117 )118 119 self.best_epoch = get_progress.best_epoch120 121 if plot:122 plt.style.use("ggplot")123 124 plt.figure()125 126 plt.plot(history.history["loss"], label="Training loss")127 plt.plot(history.history["val_loss"], label="Validation loss")128 plt.plot(history.history["accuracy"], label="Training accuracy")129 plt.plot(history.history["val_accuracy"], label="Validation accuracy")130 131 plt.title("Training Loss and Accuracy")132 plt.xlabel("Epoch #")133 plt.ylabel("Loss/Accuracy")134 plt.legend(loc="lower left")135 136 plt.show()137 138 def load_model(self, path=None):139 self.model = models.load_model(self.weights_path.format(epoch=self.best_epoch + 1) if path is None else path)140 141 def evaluate(self, predict, path=None):142 if path is not None:143 self.load_model(path)144 145 predictions = np.argmax(self.model.predict(predict), axis=-1)146 cm = metrics.confusion_matrix(predict.classes, predictions)147 148 metrics.ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=np.unique(predict.labels)).plot(cmap=plt.cm.Blues, xticks_rotation=0)149 plt.show()150 151 print(metrics.classification_report(predict.classes, predictions))152 153 TP = cm[1][1]154 TN = cm[0][0]155 FP = cm[0][1]156 FN = cm[1][0]157 158 accuracy = (float(TP + TN) / float(TP + TN + FP + FN))159 print("Accuracy:", round(accuracy, 4))160 161 specificity = (TN / float(TN + FP))162 print("Specificity:", round(specificity, 4))163 164 sensitivity = (TP / float(TP + FN))165 print("Sensitivity:", round(sensitivity, 4))166 167 precision = (TP / float(TP + FP))168 print("Precision:", round(precision, 4))169 170 def visualize_heatmap(self, image):171 img = cv.cvtColor(cv.imread(image.image), cv.COLOR_BGR2RGB).astype("float32") * 1./255172 img = np.expand_dims(img, axis=0)173 174 heatmap = self.__compute_heatmap(img)175 jet_heatmap, superimposed_img = self.__get_heatmap(image.image, heatmap)176 177 fig, ax = plt.subplots(1, 3, figsize=(20, 8))178 179 ax[0].imshow(img[0])180 ax[0].set_title(os.path.basename(image.image))181 ax[1].imshow(preprocessing.image.array_to_img(jet_heatmap))182 ax[1].set_title(f"Real class: {image.category}")183 ax[2].imshow(superimposed_img)184 ax[2].set_title(f"Predicted class: {np.argmax(self.model.predict(img)[0])}")185 186 plt.show()187 188 def compute_heatmap(self, image):189 last_layer = self.model.get_layer(index=2)190 191 grad_model = models.Model(inputs=[self.model.input], outputs=[last_layer.output, self.model.output])192 193 with tf.GradientTape() as tape:194 model_output, last_layer = grad_model(image)195 196 grads = tape.gradient(last_layer[:, 1], model_output)197 pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))198 199 heatmap = model_output[0] @ pooled_grads[..., tf.newaxis]200 heatmap = tf.squeeze(heatmap)201 heatmap = tf.maximum(heatmap, 0)/tf.math.reduce_max(heatmap)202 203 return heatmap.numpy()204 205 def get_heatmap(self, path, heatmap):206 img = preprocessing.image.load_img(path, color_mode="grayscale")207 img = preprocessing.image.img_to_array(img)208 209 jet = cm.get_cmap("jet")210 jet_colors = jet(np.arange(256))[:, :3]211 212 jet_heatmap = jet_colors[np.uint8(255 * heatmap)]213 jet_heatmap = preprocessing.image.array_to_img(jet_heatmap)214 jet_heatmap = jet_heatmap.resize((img.shape[1], img.shape[0]))215 jet_heatmap = preprocessing.image.img_to_array(jet_heatmap)216 217 superimposed_img = jet_heatmap * 0.4 + img218 superimposed_img = preprocessing.image.array_to_img(superimposed_img)219 220 return jet_heatmap, superimposed_img221 