From a61c45254c939e230ec55430574b058206edde6f Mon Sep 17 00:00:00 2001 From: mishiznic <63307108+mishiznic@users.noreply.github.com> Date: Thu, 20 Oct 2022 20:05:13 +1000 Subject: [PATCH 01/10] Folder structure + model built in modules.py, need to test the model, next thing to do is develop functions to process the data to feed to the model (should have started this assignment a bit earlier hey --- .../45838464-improvedUNET-ISIC/README.MD | 0 .../45838464-improvedUNET-ISIC/dataset.py | 95 +++++++++++++ .../45838464-improvedUNET-ISIC/modules.py | 127 ++++++++++++++++++ .../45838464-improvedUNET-ISIC/predict.py | 0 .../45838464-improvedUNET-ISIC/train.py | 0 5 files changed, 222 insertions(+) create mode 100644 recognition/45838464-improvedUNET-ISIC/README.MD create mode 100644 recognition/45838464-improvedUNET-ISIC/dataset.py create mode 100644 recognition/45838464-improvedUNET-ISIC/modules.py create mode 100644 recognition/45838464-improvedUNET-ISIC/predict.py create mode 100644 recognition/45838464-improvedUNET-ISIC/train.py diff --git a/recognition/45838464-improvedUNET-ISIC/README.MD b/recognition/45838464-improvedUNET-ISIC/README.MD new file mode 100644 index 0000000000..e69de29bb2 diff --git a/recognition/45838464-improvedUNET-ISIC/dataset.py b/recognition/45838464-improvedUNET-ISIC/dataset.py new file mode 100644 index 0000000000..0e98c7500a --- /dev/null +++ b/recognition/45838464-improvedUNET-ISIC/dataset.py @@ -0,0 +1,95 @@ +import torch +from torch.utils.data import Dataset +from torchvision import datasets +from torchvision.transforms import ToTensor +from torchvision.io import read_image +from torch.utils.data import DataLoader +import matplotlib.pyplot as plt +import os +import cv2 + +class ISICDataSet(Dataset): + + + + + def __init__(self, ISIC_labels, ISIC_img_dir, transform=None, target_transform=None): + self.ISIC_labels = ISIC_labels + self.ISIC_img_dir = ISIC_img_dir + self.transform = transform + self.target_transform = target_transform + + def __len__(self): + return len(self.ISIC_labels) + + def __getitem__(self, idx): + img_path = os.path.join(self.ISIC_img_dir, self.ISIC_labels.iloc[idx, 0]) + image = read_image(img_path) + label = self.ISIC_labels.iloc[idx, 1] + if self.transform: + image = self.transform(image) + if self.target_transform: + image = self.target_transform(image) + return image, label + +class DataLoader(DataLoader): + pass + +def png2bw(png): + grayImage = cv2.cvtColor(png, cv2.COLOR_BGR2GRAY) + (thresh, bwImage) = cv2.threshold(grayImage, 127, 255, cv2.THRESH_BINARY) + + return bwImage + +def bBoxCoords(mask): + + # image size + height, width = mask.shape + # segmentation + countours, _ = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) + # bounding box in cv2 coordinates + x,y,w,h = cv2.boundingRect(countours[0]) + # yolo coordinates + x_rel = (x + round(w/2)) / width + y_rel = (y + round(h/2)) / height + w_rel = w/width + h_rel = h/height + + return (x_rel, y_rel, w_rel, h_rel) + +def generate_labels(load_path, save_path): + for mask in sorted(os.listdir(load_path)): + + # convert to binary matrix + bw = png2bw(mask) + # find bounding box + bbox = bBoxCoords(bw) + # generate + new_row = {'object-class':0, 'X': x, 'Y': y, 'width': w, 'height': h} + df = pd.DataFrame(data=new_row, index=[0]) + df.to_csv(output+'/'+filename[0:-3]+ 'txt',sep=' ',header=False, index=False) + cv2.imwrite(output+'/'+filename,draw_image) + + + + + # with_box = cv2.rectangle(mask, (int(x_rel*width), int(y_rel*height)), (int(x_rel*width + 20), int(y_rel*height + 20)), (100,0,0), 4) + # with_box = cv2.rectangle(mask, (x_center,y_center), (x_center + 20, y_center + 20), (100,0,0), 4) + # return with_box + + + + + +# Load and save data +# Data + + +# clean data, augment, preprocessing +if __name__ == "__main__": + train_images_dir = "./data/ISIC-2017_Training_Part1_GroundTruth" + train_ground_truth = "./data/ISIC-2017_Training_Data" + = cv2.imread("./data/ISIC-2017_Training_Part1_GroundTruth/ISIC_0000000_segmentation.png") + + cv2.waitKey(0) + cv2.destroyAllWindows() \ No newline at end of file diff --git a/recognition/45838464-improvedUNET-ISIC/modules.py b/recognition/45838464-improvedUNET-ISIC/modules.py new file mode 100644 index 0000000000..a98792e234 --- /dev/null +++ b/recognition/45838464-improvedUNET-ISIC/modules.py @@ -0,0 +1,127 @@ +import tensorflow as tf +from tensorflow.keras.layers import Conv2D,LeakyReLU,Dropout,UpSampling2D,Input, BatchNormalization, ReLU, concatenate, Add +from tensorflow.keras import Model +import numpy as np + +IMAGE_SIZE = 256 # latent space will have an encoding for every pixel +CHANNELS = 3 #RGB +BATCH_SIZE = 1 +KERNEL_SIZE = 3 +STRIDE = 2 +FIRST_DEPTH = 16 +DROPOUT = 0.3 + +def context_module(input, depth): + """ + From "Brain Tumor Segmentation and Radiomics +Survival Prediction: Contribution to the BRATS +2017 Challenge" -> "Each context module is in fact a pre-activation residual block [13] with two +3x3x3 convolutional layers and a dropout layer (pdrop = 0.3) in between. + """ + block = BatchNormalization()(input) + block = ReLU()(block) + block = Conv2D(depth, KERNEL_SIZE, padding="same")(block) + block = Dropout(DROPOUT)(block) + block = BatchNormalization()(block) + block = ReLU()(block) + block = Conv2D(depth, KERNEL_SIZE, padding='same') + return block + +def element_wise_sum(down_sample, context): + """ + Maybe use Add frunction from keras.layer + """ + pass + +def upsampling_module(input, depth): + """ + "... which is done by +means of a simple upscale that repeats the feature voxels twice in each spatial +dimension, followed by a 3x3x3 convolution that halves the number of feature +maps" + + """ + block = UpSampling2D(size=(2, 2))(input) + block = Conv2D(depth, KERNEL_SIZE, activation=LeakyReLU(alpha=0.01), padding = 'same')(block) + return block + +def localization_module(input, depth): + """ + A localization module +consists of a 3x3x3 convolution followed by a 1x1x1 convolution that halves the +number of feature maps + """ + block = Conv2D(depth, KERNEL_SIZE, activation=LeakyReLU(alpha=0.01), padding = 'same')(input) + block = BatchNormalization()(block) + block = Conv2D(depth, 1, activation=LeakyReLU(alpha=0.01), padding = 'same')(block) + block = BatchNormalization()(block) + return block + +def segmentation(input): + + return Conv2D(FIRST_DEPTH, (1, 1), (1, 1))(input) + + +def improved_uNET(input): + + input_layer = Input(shape=(IMAGE_SIZE, IMAGE_SIZE, CHANNELS), batch_size=BATCH_SIZE) + + ### Encoder ### + conv1 = Conv2D(FIRST_DEPTH, KERNEL_SIZE, padding = 'same')(input_layer) + context1 = context_module(conv1, FIRST_DEPTH) + sum1 = Add()(conv1, context1) + + conv2 = Conv2D(FIRST_DEPTH*2, KERNEL_SIZE, STRIDE, padding = 'same')(sum1) + context2 = context_module(conv2, FIRST_DEPTH*2) + sum2 = Add()(conv2, context2) + + conv3 = Conv2D(FIRST_DEPTH*(2**2), KERNEL_SIZE, STRIDE, padding = 'same')(sum2) + context3 = context_module(conv3, FIRST_DEPTH*(2**2)) + sum3 = Add()(conv3, context3) + + conv4 = Conv2D(FIRST_DEPTH*(2**3), KERNEL_SIZE, STRIDE, padding = 'same')(sum3) + context4 = context_module(conv4, FIRST_DEPTH*(2**3)) + sum4 = Add()(conv4, context4) + + conv5 = Conv2D(FIRST_DEPTH*(2**4), KERNEL_SIZE, STRIDE, padding = 'same')(sum4) + context5 = context_module(conv5, FIRST_DEPTH*(2**4)) + sum5 = Add()(conv5, context5) + + ### Decoder ### + upsamp1 = upsampling_module(sum5, FIRST_DEPTH*(2**3)) + conc1 = concatenate([sum4, upsamp1]) + loc1 = localization_module(conc1, FIRST_DEPTH*(2**3)) + + upsamp2 = upsampling_module(loc1, FIRST_DEPTH*(2**2)) + conc2 = concatenate([sum3, upsamp2]) + loc2 = localization_module(conc2, FIRST_DEPTH*(2**2)) + + seg1 = segmentation(loc2) + seg1 = UpSampling2D()((2,2))(seg1) + + upsamp3 = upsampling_module(loc2, FIRST_DEPTH*2) + conc3 = concatenate([sum2, upsamp3]) + loc3 = localization_module(conc3, FIRST_DEPTH*2) + + seg2 = segmentation(loc3) + seg2 = Add()(seg1, seg2) + seg2 = UpSampling2D((2,2))(seg2) + + upsamp4 = upsampling_module(loc3, FIRST_DEPTH) + conc4 = concatenate([sum1, upsamp4]) + + lastconv = Conv2D(FIRST_DEPTH*2, KERNEL_SIZE, stride = (1, 1), activation=LeakyReLU(alpha=0.01), padding = 'same')(conc4) + seg3 = segmentation(lastconv, FIRST_DEPTH) + + final_seg = Add(seg2, seg3) + + # softmax + output_layer = Conv2D(2,KERNEL_SIZE, activation='softmax', padding='same')(final_seg) + model = Model(name="Improved uNET", inputs=input_layer, outputs=output_layer) + return model + + + + + + diff --git a/recognition/45838464-improvedUNET-ISIC/predict.py b/recognition/45838464-improvedUNET-ISIC/predict.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/recognition/45838464-improvedUNET-ISIC/train.py b/recognition/45838464-improvedUNET-ISIC/train.py new file mode 100644 index 0000000000..e69de29bb2 From b15fb930b3a98039c94c10016e3568a68f4a5d18 Mon Sep 17 00:00:00 2001 From: mishiznic <63307108+mishiznic@users.noreply.github.com> Date: Thu, 20 Oct 2022 22:28:36 +1000 Subject: [PATCH 02/10] Finished off Model, did preprocessing function, nextdevelop a function for disc parameter and then start training. --- .../45838464-improvedUNET-ISIC/dataset.py | 124 ++++++------------ 1 file changed, 38 insertions(+), 86 deletions(-) diff --git a/recognition/45838464-improvedUNET-ISIC/dataset.py b/recognition/45838464-improvedUNET-ISIC/dataset.py index 0e98c7500a..1f949be611 100644 --- a/recognition/45838464-improvedUNET-ISIC/dataset.py +++ b/recognition/45838464-improvedUNET-ISIC/dataset.py @@ -1,95 +1,47 @@ -import torch -from torch.utils.data import Dataset -from torchvision import datasets -from torchvision.transforms import ToTensor -from torchvision.io import read_image -from torch.utils.data import DataLoader -import matplotlib.pyplot as plt +import tensorflow as tf +from tensorflow.keras.utils import to_categorical +import numpy as np import os -import cv2 +import glob -class ISICDataSet(Dataset): +def preprocess_data(path): + """ + Returns an array of the image data + """ + images = [] + image_locations = sorted(glob.glob(path)) - - - def __init__(self, ISIC_labels, ISIC_img_dir, transform=None, target_transform=None): - self.ISIC_labels = ISIC_labels - self.ISIC_img_dir = ISIC_img_dir - self.transform = transform - self.target_transform = target_transform - - def __len__(self): - return len(self.ISIC_labels) - - def __getitem__(self, idx): - img_path = os.path.join(self.ISIC_img_dir, self.ISIC_labels.iloc[idx, 0]) - image = read_image(img_path) - label = self.ISIC_labels.iloc[idx, 1] - if self.transform: - image = self.transform(image) - if self.target_transform: - image = self.target_transform(image) - return image, label - -class DataLoader(DataLoader): - pass - -def png2bw(png): - grayImage = cv2.cvtColor(png, cv2.COLOR_BGR2GRAY) - (thresh, bwImage) = cv2.threshold(grayImage, 127, 255, cv2.THRESH_BINARY) - - return bwImage - -def bBoxCoords(mask): - - # image size - height, width = mask.shape - # segmentation - countours, _ = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) - # bounding box in cv2 coordinates - x,y,w,h = cv2.boundingRect(countours[0]) - # yolo coordinates - x_rel = (x + round(w/2)) / width - y_rel = (y + round(h/2)) / height - w_rel = w/width - h_rel = h/height - - return (x_rel, y_rel, w_rel, h_rel) - -def generate_labels(load_path, save_path): - for mask in sorted(os.listdir(load_path)): + for file in image_locations: - # convert to binary matrix - bw = png2bw(mask) - # find bounding box - bbox = bBoxCoords(bw) - # generate - new_row = {'object-class':0, 'X': x, 'Y': y, 'width': w, 'height': h} - df = pd.DataFrame(data=new_row, index=[0]) - df.to_csv(output+'/'+filename[0:-3]+ 'txt',sep=' ',header=False, index=False) - cv2.imwrite(output+'/'+filename,draw_image) + # load image + image = tf.io.read_file(file) + image = tf.io.decode_jpeg(image, channels=3) + + # resize and normalize + image = tf.image.resize_with_pad(image, 128, 128) + image = image / 255.0 + images.append(image) + images = np.array(images) + return images +def preprocess_masks(path): + masks = [] + mask_locations = sorted(glob.glob(path)) - # with_box = cv2.rectangle(mask, (int(x_rel*width), int(y_rel*height)), (int(x_rel*width + 20), int(y_rel*height + 20)), (100,0,0), 4) - # with_box = cv2.rectangle(mask, (x_center,y_center), (x_center + 20, y_center + 20), (100,0,0), 4) - # return with_box - - - - - -# Load and save data -# Data - - -# clean data, augment, preprocessing -if __name__ == "__main__": - train_images_dir = "./data/ISIC-2017_Training_Part1_GroundTruth" - train_ground_truth = "./data/ISIC-2017_Training_Data" - = cv2.imread("./data/ISIC-2017_Training_Part1_GroundTruth/ISIC_0000000_segmentation.png") - - cv2.waitKey(0) - cv2.destroyAllWindows() \ No newline at end of file + for file in mask_locations: + + # load mask + mask = tf.io.read_file(file) + mask = tf.io.decode_png(mask, channels=1) + + # resize and normalize + mask = tf.image.resize_with_pad(mask, 128, 128) + mask = mask / 255.0 + masks.append(mask) + + masks = np.array(masks) + masks = to_categorical(masks) + return masks From 1c19304e89cb699baf5862aa7619f10dc5fba3b2 Mon Sep 17 00:00:00 2001 From: mishiznic <63307108+mishiznic@users.noreply.github.com> Date: Thu, 20 Oct 2022 22:53:49 +1000 Subject: [PATCH 03/10] Added notebook to train on google colab. laptop too slow :( --- .../45838464-improvedUNET-ISIC/notebook.ipynb | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 recognition/45838464-improvedUNET-ISIC/notebook.ipynb diff --git a/recognition/45838464-improvedUNET-ISIC/notebook.ipynb b/recognition/45838464-improvedUNET-ISIC/notebook.ipynb new file mode 100644 index 0000000000..023b87880e --- /dev/null +++ b/recognition/45838464-improvedUNET-ISIC/notebook.ipynb @@ -0,0 +1,119 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'preprocess_mask' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_8444\\3099504444.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[0mx\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpreprocess_data\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata_location\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 13\u001b[1;33m \u001b[0my\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpreprocess_mask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmask_location\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 14\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 15\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mNameError\u001b[0m: name 'preprocess_mask' is not defined" + ] + } + ], + "source": [ + "import tensorflow as tf\n", + "from tensorflow.keras.utils import to_categorical\n", + "import numpy as np\n", + "import os\n", + "import glob\n", + "from dataset import *\n", + "\n", + "data_location = \"./data/ISIC-2017_Training_Data/*.jpg\"\n", + "mask_location = \"./data/ISIC-2017_Training_Part1_GroundTruth/*.png\"\n", + "\n", + "\n", + "x = preprocess_data(data_location)\n", + "y = preprocess_masks(mask_location)\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(isic_data_train)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "list" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(isic_data_train)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "type(isic_data_train[0])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.7.12 ('tf-isic')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.13" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "63b7f0ca92ed5fdf48e8242447823e1637e55d3cf1bc39c2261b2158c4676ed4" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 1113063936440e02bb71a2eb93bc54e7e9ee09f4 Mon Sep 17 00:00:00 2001 From: mishiznic <63307108+mishiznic@users.noreply.github.com> Date: Thu, 20 Oct 2022 23:17:44 +1000 Subject: [PATCH 04/10] Dice coeff function added. Still need to train the model... --- recognition/45838464-improvedUNET-ISIC/utils.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 recognition/45838464-improvedUNET-ISIC/utils.py diff --git a/recognition/45838464-improvedUNET-ISIC/utils.py b/recognition/45838464-improvedUNET-ISIC/utils.py new file mode 100644 index 0000000000..3c4cd0a299 --- /dev/null +++ b/recognition/45838464-improvedUNET-ISIC/utils.py @@ -0,0 +1,16 @@ +from tensorflow.keras.backend import flatten, sum +def dice_coefficient(a, b): + """ + Dice Coefficient function from : https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient + Used to determine how closely two set overlap each other. In this case we use it to see how close the + predicted mask matches the ground truth mask. + """ + + + a = flatten(a) + b = flatten(b) + a_union_b = sum(a * b) + mag_a = sum(a) + mag_b = sum(b) + + return (2.0 * a_union_b) / (mag_a + mag_b) \ No newline at end of file From 0be98938a30a204f80b028dbcd8f09c4878844e5 Mon Sep 17 00:00:00 2001 From: mishiznic <63307108+mishiznic@users.noreply.github.com> Date: Fri, 21 Oct 2022 03:16:28 +1000 Subject: [PATCH 05/10] Added dice coefficient loss function and documented utils.py, fixed some bugs in modules.py, still working through errors in modules.py. --- .../45838464-improvedUNET-ISIC/modules.py | 142 ++++++++---------- .../45838464-improvedUNET-ISIC/utils.py | 8 +- 2 files changed, 71 insertions(+), 79 deletions(-) diff --git a/recognition/45838464-improvedUNET-ISIC/modules.py b/recognition/45838464-improvedUNET-ISIC/modules.py index a98792e234..4e5669809f 100644 --- a/recognition/45838464-improvedUNET-ISIC/modules.py +++ b/recognition/45838464-improvedUNET-ISIC/modules.py @@ -1,123 +1,109 @@ import tensorflow as tf -from tensorflow.keras.layers import Conv2D,LeakyReLU,Dropout,UpSampling2D,Input, BatchNormalization, ReLU, concatenate, Add +from tensorflow.keras.layers import Conv2D,LeakyReLU,Dropout,UpSampling2D,Input, concatenate, Add from tensorflow.keras import Model +import tensorflow_addons as tfa import numpy as np -IMAGE_SIZE = 256 # latent space will have an encoding for every pixel +IMAGE_SIZE = 128 # latent space will have an encoding for every pixel CHANNELS = 3 #RGB BATCH_SIZE = 1 KERNEL_SIZE = 3 STRIDE = 2 FIRST_DEPTH = 16 DROPOUT = 0.3 +activation_func = LeakyReLU(alpha=0.01) def context_module(input, depth): """ From "Brain Tumor Segmentation and Radiomics -Survival Prediction: Contribution to the BRATS -2017 Challenge" -> "Each context module is in fact a pre-activation residual block [13] with two -3x3x3 convolutional layers and a dropout layer (pdrop = 0.3) in between. + Survival Prediction: Contribution to the BRATS + 2017 Challenge" -> "Each context module is in fact a pre-activation residual block [13] with two + 3x3x3 convolutional layers and a dropout layer (pdrop = 0.3) in between. """ - block = BatchNormalization()(input) - block = ReLU()(block) - block = Conv2D(depth, KERNEL_SIZE, padding="same")(block) + block = tfa.layers.InstanceNormalization()(input) + block = Conv2D(depth, KERNEL_SIZE, padding="same", activation=activation_func)(block) block = Dropout(DROPOUT)(block) - block = BatchNormalization()(block) - block = ReLU()(block) - block = Conv2D(depth, KERNEL_SIZE, padding='same') + block = tfa.layers.InstanceNormalization()(block) + block = Conv2D(depth, KERNEL_SIZE, padding='same', activation=activation_func)(block) return block -def element_wise_sum(down_sample, context): - """ - Maybe use Add frunction from keras.layer - """ - pass - -def upsampling_module(input, depth): +def localization_module(input, depth): """ - "... which is done by -means of a simple upscale that repeats the feature voxels twice in each spatial -dimension, followed by a 3x3x3 convolution that halves the number of feature -maps" - + "A localization module + consists of a 3x3x3 convolution followed by a 1x1x1 convolution that halves the + number of feature maps." """ - block = UpSampling2D(size=(2, 2))(input) - block = Conv2D(depth, KERNEL_SIZE, activation=LeakyReLU(alpha=0.01), padding = 'same')(block) + block = Conv2D(depth, KERNEL_SIZE, padding = 'same', activation=activation_func)(input) + block = Conv2D(depth, (1, 1), padding = 'same', activation=activation_func)(block) return block -def localization_module(input, depth): +def encoding_layer(input, depth, stride): """ - A localization module -consists of a 3x3x3 convolution followed by a 1x1x1 convolution that halves the -number of feature maps + Building block for the encoder network as decribed in the paper. """ - block = Conv2D(depth, KERNEL_SIZE, activation=LeakyReLU(alpha=0.01), padding = 'same')(input) - block = BatchNormalization()(block) - block = Conv2D(depth, 1, activation=LeakyReLU(alpha=0.01), padding = 'same')(block) - block = BatchNormalization()(block) - return block + conv = Conv2D(depth, KERNEL_SIZE, padding = 'same',activation=activation_func)(input) + contxt = context_module(conv, depth) + add = Add()([conv, contxt]) -def segmentation(input): + return add + +def decoding_layer(input, add, depth): + """ + Decoding building block as described in the paper. + "... which is done by + means of a simple upscale that repeats the feature voxels twice in each spatial + dimension, followed by a 3x3x3 convolution that halves the number of feature + maps" - return Conv2D(FIRST_DEPTH, (1, 1), (1, 1))(input) + """ + block = UpSampling2D(size=(2, 2))(input) + block = Conv2D(depth, KERNEL_SIZE, activation=activation_func, padding = 'same')(block) + conc = concatenate([block, add]) + loc = localization_module(conc, depth) + return loc def improved_uNET(input): + """ + Improved UNet Architecture build from block defined above. + """ - input_layer = Input(shape=(IMAGE_SIZE, IMAGE_SIZE, CHANNELS), batch_size=BATCH_SIZE) + input_layer = Input(shape=(IMAGE_SIZE, IMAGE_SIZE, CHANNELS)) ### Encoder ### - conv1 = Conv2D(FIRST_DEPTH, KERNEL_SIZE, padding = 'same')(input_layer) - context1 = context_module(conv1, FIRST_DEPTH) - sum1 = Add()(conv1, context1) - - conv2 = Conv2D(FIRST_DEPTH*2, KERNEL_SIZE, STRIDE, padding = 'same')(sum1) - context2 = context_module(conv2, FIRST_DEPTH*2) - sum2 = Add()(conv2, context2) - - conv3 = Conv2D(FIRST_DEPTH*(2**2), KERNEL_SIZE, STRIDE, padding = 'same')(sum2) - context3 = context_module(conv3, FIRST_DEPTH*(2**2)) - sum3 = Add()(conv3, context3) - - conv4 = Conv2D(FIRST_DEPTH*(2**3), KERNEL_SIZE, STRIDE, padding = 'same')(sum3) - context4 = context_module(conv4, FIRST_DEPTH*(2**3)) - sum4 = Add()(conv4, context4) - - conv5 = Conv2D(FIRST_DEPTH*(2**4), KERNEL_SIZE, STRIDE, padding = 'same')(sum4) - context5 = context_module(conv5, FIRST_DEPTH*(2**4)) - sum5 = Add()(conv5, context5) + sum1 = encoding_layer(input_layer, FIRST_DEPTH*2, stride=(1, 1)) + sum2 = encoding_layer(sum1, FIRST_DEPTH*2, stride=(2, 2)) + sum3 = encoding_layer(sum2, FIRST_DEPTH*(2**2), stride=(2, 2)) + sum4 = encoding_layer(sum3, FIRST_DEPTH*(2**3), stride=(2, 2)) + sum5 = encoding_layer(sum4, FIRST_DEPTH*(2**4), stride=(2, 2)) ### Decoder ### - upsamp1 = upsampling_module(sum5, FIRST_DEPTH*(2**3)) - conc1 = concatenate([sum4, upsamp1]) - loc1 = localization_module(conc1, FIRST_DEPTH*(2**3)) + loc1 = decoding_layer(sum5, sum4, FIRST_DEPTH*(2**3)) - upsamp2 = upsampling_module(loc1, FIRST_DEPTH*(2**2)) - conc2 = concatenate([sum3, upsamp2]) - loc2 = localization_module(conc2, FIRST_DEPTH*(2**2)) - - seg1 = segmentation(loc2) - seg1 = UpSampling2D()((2,2))(seg1) + loc2 = decoding_layer(loc1, sum3, FIRST_DEPTH*(2**2)) + + seg1 = Conv2D(3, (1, 1), padding = 'same')(loc2) + seg1 = UpSampling2D((2, 2))(seg1) - upsamp3 = upsampling_module(loc2, FIRST_DEPTH*2) - conc3 = concatenate([sum2, upsamp3]) - loc3 = localization_module(conc3, FIRST_DEPTH*2) + loc3 = decoding_layer(loc2, sum2, FIRST_DEPTH*2) - seg2 = segmentation(loc3) - seg2 = Add()(seg1, seg2) - seg2 = UpSampling2D((2,2))(seg2) + seg2 = Conv2D(3, (1, 1), padding = 'same')(loc3) + seg2 = Add()([seg1, seg2]) + seg2 = UpSampling2D((2, 2))(seg2) - upsamp4 = upsampling_module(loc3, FIRST_DEPTH) - conc4 = concatenate([sum1, upsamp4]) + lastup = UpSampling2D((2, 2))(loc3) + lastup = Conv2D(FIRST_DEPTH, KERNEL_SIZE, padding = 'same', activation=activation_func)(lastup) + lastconc = concatenate([lastup, sum1]) - lastconv = Conv2D(FIRST_DEPTH*2, KERNEL_SIZE, stride = (1, 1), activation=LeakyReLU(alpha=0.01), padding = 'same')(conc4) - seg3 = segmentation(lastconv, FIRST_DEPTH) + lastconv = Conv2D(FIRST_DEPTH*2, KERNEL_SIZE, stride = (1, 1), padding = 'same')(lastconc) + seg3 = Conv2D(3, (1, 1), padding = 'same')(lastconv) - final_seg = Add(seg2, seg3) + final_seg = Add([seg2, seg3]) - # softmax - output_layer = Conv2D(2,KERNEL_SIZE, activation='softmax', padding='same')(final_seg) + # softmax (one hot encoded) + output_layer = Conv2D(3, (1, 1), activation='sigmoid')(final_seg) model = Model(name="Improved uNET", inputs=input_layer, outputs=output_layer) + return model diff --git a/recognition/45838464-improvedUNET-ISIC/utils.py b/recognition/45838464-improvedUNET-ISIC/utils.py index 3c4cd0a299..71cc18c9dc 100644 --- a/recognition/45838464-improvedUNET-ISIC/utils.py +++ b/recognition/45838464-improvedUNET-ISIC/utils.py @@ -13,4 +13,10 @@ def dice_coefficient(a, b): mag_a = sum(a) mag_b = sum(b) - return (2.0 * a_union_b) / (mag_a + mag_b) \ No newline at end of file + return (2.0 * a_union_b) / (mag_a + mag_b) + +def dice_coefficient_loss(truth, predition): + """ + Loss function as described in the Improved Unet paper. + """ + return 1 - dice_coefficient(truth, predition) \ No newline at end of file From 634073fc09d0a45e363454b20dc2d031e53b8c2e Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 21 Oct 2022 11:38:05 +1000 Subject: [PATCH 06/10] Finished Improved Unet model and now compiles width model.compile(...) --- .../45838464-improvedUNET-ISIC/modules.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/recognition/45838464-improvedUNET-ISIC/modules.py b/recognition/45838464-improvedUNET-ISIC/modules.py index 4e5669809f..4c9da6cd1f 100644 --- a/recognition/45838464-improvedUNET-ISIC/modules.py +++ b/recognition/45838464-improvedUNET-ISIC/modules.py @@ -41,7 +41,7 @@ def encoding_layer(input, depth, stride): """ Building block for the encoder network as decribed in the paper. """ - conv = Conv2D(depth, KERNEL_SIZE, padding = 'same',activation=activation_func)(input) + conv = Conv2D(depth, KERNEL_SIZE, padding = 'same',activation=activation_func, strides=stride)(input) contxt = context_module(conv, depth) add = Add()([conv, contxt]) @@ -58,12 +58,15 @@ def decoding_layer(input, add, depth): """ block = UpSampling2D(size=(2, 2))(input) block = Conv2D(depth, KERNEL_SIZE, activation=activation_func, padding = 'same')(block) + print(block.shape) + print(add.shape) + conc = concatenate([block, add]) loc = localization_module(conc, depth) return loc -def improved_uNET(input): +def improved_uNET(): """ Improved UNet Architecture build from block defined above. """ @@ -95,19 +98,15 @@ def improved_uNET(input): lastup = Conv2D(FIRST_DEPTH, KERNEL_SIZE, padding = 'same', activation=activation_func)(lastup) lastconc = concatenate([lastup, sum1]) - lastconv = Conv2D(FIRST_DEPTH*2, KERNEL_SIZE, stride = (1, 1), padding = 'same')(lastconc) + lastconv = Conv2D(FIRST_DEPTH*2, KERNEL_SIZE, strides = (1, 1), padding = 'same')(lastconc) seg3 = Conv2D(3, (1, 1), padding = 'same')(lastconv) - final_seg = Add([seg2, seg3]) + final_seg = Add()([seg2, seg3]) # softmax (one hot encoded) output_layer = Conv2D(3, (1, 1), activation='sigmoid')(final_seg) model = Model(name="Improved uNET", inputs=input_layer, outputs=output_layer) return model - - - - - + From bf10d55e3da455a68f4757bc8f24f1d6bb4c72ae Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 21 Oct 2022 13:56:08 +1000 Subject: [PATCH 07/10] First training run!!!, fixed errors in utils.py and module.py, now time to train and make some nice plots --- .../45838464-improvedUNET-ISIC/README.MD | 25 +++++++++++++++++++ .../45838464-improvedUNET-ISIC/modules.py | 4 +-- .../45838464-improvedUNET-ISIC/utils.py | 12 ++++----- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/recognition/45838464-improvedUNET-ISIC/README.MD b/recognition/45838464-improvedUNET-ISIC/README.MD index e69de29bb2..9acb5775de 100644 --- a/recognition/45838464-improvedUNET-ISIC/README.MD +++ b/recognition/45838464-improvedUNET-ISIC/README.MD @@ -0,0 +1,25 @@ +# Skin Mole Segmentation on the ISIC2017 data set using the improved UNet. + +## Author +Name: Michael Smith + +## Problem Description +Image segmentation is important in the current scene of medicine as it allows patients gain important information without the immediate precense of a doctor. This is especially beneficial for people who don't have reliable access to a hospital or GP. Image segmentation is the process of separating an image into its constituent classes. In this exampe the two classes are the skin and the mole. + +## Why UNet +The improved UNet model provides boosts in performance over the original UNet model developed by THESE GUYS, through small tweaks in the architecture. + + +## How it works +The UNet architecture is an AutoEncoder CNN which means that it takes data, encodes that to a low dimension latent space, then decodes the latent space to a segmentation. + + +## Examples + +## Dependecies +python 3.7.13 +tensorflow 2.9.1 +matlplotlib 3.5.2 +numpy 1.21.6 +glob2 0.7 +opencv 4.6.0 \ No newline at end of file diff --git a/recognition/45838464-improvedUNET-ISIC/modules.py b/recognition/45838464-improvedUNET-ISIC/modules.py index 4c9da6cd1f..0af4f1670d 100644 --- a/recognition/45838464-improvedUNET-ISIC/modules.py +++ b/recognition/45838464-improvedUNET-ISIC/modules.py @@ -104,8 +104,8 @@ def improved_uNET(): final_seg = Add()([seg2, seg3]) # softmax (one hot encoded) - output_layer = Conv2D(3, (1, 1), activation='sigmoid')(final_seg) - model = Model(name="Improved uNET", inputs=input_layer, outputs=output_layer) + output_layer = Conv2D(2, (1, 1), activation='softmax')(final_seg) + model = Model(name="Improved-uNET", inputs=input_layer, outputs=output_layer) return model diff --git a/recognition/45838464-improvedUNET-ISIC/utils.py b/recognition/45838464-improvedUNET-ISIC/utils.py index 71cc18c9dc..c428d0e9bd 100644 --- a/recognition/45838464-improvedUNET-ISIC/utils.py +++ b/recognition/45838464-improvedUNET-ISIC/utils.py @@ -1,4 +1,4 @@ -from tensorflow.keras.backend import flatten, sum +import tensorflow.keras.backend as K def dice_coefficient(a, b): """ Dice Coefficient function from : https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient @@ -7,11 +7,11 @@ def dice_coefficient(a, b): """ - a = flatten(a) - b = flatten(b) - a_union_b = sum(a * b) - mag_a = sum(a) - mag_b = sum(b) + a = K.flatten(a) + b = K.flatten(b) + a_union_b = K.sum(a * b) + mag_a = K.sum(a) + mag_b = K.sum(b) return (2.0 * a_union_b) / (mag_a + mag_b) From 2fd511b183ad88f310f407316fe33815848d2a9d Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 21 Oct 2022 14:56:50 +1000 Subject: [PATCH 08/10] Model has trained through once with appropiate disc scores :). Finished train.py functionality. Need to do predict.py and make plots+images --- .../45838464-improvedUNET-ISIC/train.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/recognition/45838464-improvedUNET-ISIC/train.py b/recognition/45838464-improvedUNET-ISIC/train.py index e69de29bb2..e2ecc4d0a6 100644 --- a/recognition/45838464-improvedUNET-ISIC/train.py +++ b/recognition/45838464-improvedUNET-ISIC/train.py @@ -0,0 +1,35 @@ +from dataset import preprocess_data, preprocess_masks +from modules import Improved_UNet +from tensorflow.keras.optimizers import Adam +import numpy as np + + +def training(datapaths, batch_size, epochs): + """ + Trains the Improved UNet model based on the given data. + datapaths is a list in the form: + [train_data_path/*jpg, train_truth_path/*png, val_data_path/*jpg, val_truth_path/*png] + Learning rate as per the paper. + """ + + # x_train = preprocess_data(datapaths[0]) + # y_train = preprocess_masks(datapaths[1]) + + # x_val = preprocess_data(datapaths[2]) + # y_val = preprocess_masks(datapaths[3]) + + x_train = np.load('x_train.npy') + y_train = np.load('y_train.npy') + x_val = np.load('x_val.npy') + y_val = np.load('y_val.npy') + + model = Improved_UNet() + + # fit the model with normal learning rate + model.compile(optimizer = Adam(0.0005), loss = "cro", metrics=['accuracy', modules.DSC]) + + history = model.fit(x_train, y_train, validation_data= (x_val, y_val), + batch_size=batch_size,shuffle='True',epochs=epochs) + + + return model, history \ No newline at end of file From 17a5b242a74285cbe50c5488984a9a604b7969a6 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 21 Oct 2022 15:35:22 +1000 Subject: [PATCH 09/10] train.py runs the model and saves to local directory, adding plotting functions in util.py to plot accuracy and loss. Last thing for funcionality is predict.py --- .../45838464-improvedUNET-ISIC/train.py | 14 +++++++--- .../45838464-improvedUNET-ISIC/utils.py | 28 ++++++++++++++++++- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/recognition/45838464-improvedUNET-ISIC/train.py b/recognition/45838464-improvedUNET-ISIC/train.py index e2ecc4d0a6..1559459ac1 100644 --- a/recognition/45838464-improvedUNET-ISIC/train.py +++ b/recognition/45838464-improvedUNET-ISIC/train.py @@ -1,7 +1,9 @@ from dataset import preprocess_data, preprocess_masks from modules import Improved_UNet +from utils import plot_accuracy, plot_loss from tensorflow.keras.optimizers import Adam import numpy as np +import matplotlib.pyplot as plt def training(datapaths, batch_size, epochs): @@ -12,6 +14,7 @@ def training(datapaths, batch_size, epochs): Learning rate as per the paper. """ + # process data # x_train = preprocess_data(datapaths[0]) # y_train = preprocess_masks(datapaths[1]) @@ -23,13 +26,16 @@ def training(datapaths, batch_size, epochs): x_val = np.load('x_val.npy') y_val = np.load('y_val.npy') + # build up Improved UNet model model = Improved_UNet() - - # fit the model with normal learning rate model.compile(optimizer = Adam(0.0005), loss = "cro", metrics=['accuracy', modules.DSC]) history = model.fit(x_train, y_train, validation_data= (x_val, y_val), batch_size=batch_size,shuffle='True',epochs=epochs) - - return model, history \ No newline at end of file + # save model + model.save('./trained-model', include_optimizer=True, save_format='tf') + # plot learning + plot_accuracy(history) + plot_loss(history) + plot_disc_scores() \ No newline at end of file diff --git a/recognition/45838464-improvedUNET-ISIC/utils.py b/recognition/45838464-improvedUNET-ISIC/utils.py index c428d0e9bd..87d1815dd6 100644 --- a/recognition/45838464-improvedUNET-ISIC/utils.py +++ b/recognition/45838464-improvedUNET-ISIC/utils.py @@ -1,4 +1,5 @@ import tensorflow.keras.backend as K +import matplotlib.pyplot as plt def dice_coefficient(a, b): """ Dice Coefficient function from : https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient @@ -19,4 +20,29 @@ def dice_coefficient_loss(truth, predition): """ Loss function as described in the Improved Unet paper. """ - return 1 - dice_coefficient(truth, predition) \ No newline at end of file + return 1 - dice_coefficient(truth, predition) + +def plot_accuracy(history): + """ + Plots the accuracy of the model throughout the training process. + """ + plt.plot(history.history['acc'], label='Training Accuracy') + plt.plot(history["val_acc"], label="Validation Accuracy") + plt.xlabel("Epochs") + plt.ylabel("Accuracy (%)") + plt.title("Test and Validation Accuracy") + plt.legend(loc='lower right') + plt.savefig("./images/accuracy.png") + +def plot_loss(history): + """ + Plots the loss of the model throughout a training session. + """ + plt.plot(history.history['loss'], label='Training Loss') + plt.plot(history["val_loss"], label="Validation Loss") + plt.xlabel("Epochs") + plt.ylabel("Loss") + plt.title("Test and Validation Loss") + plt.legend(loc='lower right') + plt.savefig("./images/loss.png") + From 05be93384bcd4eb7bcabd2eb9d22a9a934a4ef57 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 21 Oct 2022 17:35:22 +1000 Subject: [PATCH 10/10] Final commit, produced training graphs, finished read.me and commented all files --- .../45838464-improvedUNET-ISIC/README.MD | 38 +++++++++++++----- .../45838464-improvedUNET-ISIC/dataset.py | 2 +- .../45838464-improvedUNET-ISIC/modules.py | 7 +--- .../report-images/dice_accuracy.png | Bin 0 -> 33931 bytes .../report-images/improved-unet-diagram.PNG | Bin 0 -> 63560 bytes .../report-images/loss.png | Bin 0 -> 19572 bytes .../45838464-improvedUNET-ISIC/train.py | 16 +++++--- .../45838464-improvedUNET-ISIC/utils.py | 32 +++++++-------- 8 files changed, 56 insertions(+), 39 deletions(-) create mode 100644 recognition/45838464-improvedUNET-ISIC/report-images/dice_accuracy.png create mode 100644 recognition/45838464-improvedUNET-ISIC/report-images/improved-unet-diagram.PNG create mode 100644 recognition/45838464-improvedUNET-ISIC/report-images/loss.png diff --git a/recognition/45838464-improvedUNET-ISIC/README.MD b/recognition/45838464-improvedUNET-ISIC/README.MD index 9acb5775de..01c9f23194 100644 --- a/recognition/45838464-improvedUNET-ISIC/README.MD +++ b/recognition/45838464-improvedUNET-ISIC/README.MD @@ -2,24 +2,40 @@ ## Author Name: Michael Smith +Student Number: 45838464 ## Problem Description -Image segmentation is important in the current scene of medicine as it allows patients gain important information without the immediate precense of a doctor. This is especially beneficial for people who don't have reliable access to a hospital or GP. Image segmentation is the process of separating an image into its constituent classes. In this exampe the two classes are the skin and the mole. +Image segmentation is important in the current scene of medicine as it allows patients to gain important information without the immediate presence of a doctor. This is especially beneficial for people who don't have reliable access to a hospital or GP. Image segmentation is the process of separating an image into its constituent classes. In this example the two classes are the skin and the mole. The goal is to segment a test data set of lesions and compare it to the manually segemented images. The degree of similariy is the dice coeffiecient (described here https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient) and this model should aim to achieve a dice coefficient higher than 0.8. -## Why UNet -The improved UNet model provides boosts in performance over the original UNet model developed by THESE GUYS, through small tweaks in the architecture. +## Why Improved UNet and How it Works +The improved UNet model is an autoencoder network that provides boosts in performance over the original UNeting: "... architecture of the context pathway, normalization schemes, number of featuremaps throughout the network, nonlinearity and the structure of the upsampling +pathway". Both networks are made up of encoder and decoder submodules, the input image is encoded down to a low dimension latent space, then is decoded up to segmentation map. The detailed architecture is shown in the figure below. +![image](./report_images/improved-unet-diagram.png) -## How it works -The UNet architecture is an AutoEncoder CNN which means that it takes data, encodes that to a low dimension latent space, then decodes the latent space to a segmentation. +Each block can be built by layers provided in the tensorflow.keras.layers library. The details for the blocks (context, localisation, segmentaion etc.) are in modules.py. These submodules are then combine into the full ImprovedUNet model which is at the end of modules.py. +The An important difference between this model and the paper model is that this problem is using 2D data not 3D. The input is a 128x128x3 array (3 for r,g,b channels) and the ouput is 128x128x2 (2 for each class). -## Examples +## Data Preprocessing +The ISIC data needs to be preprocessed in order for optimal performace of the model. Firstly the "superpixel" files were removed using script commands. The image files were transformed to tensorflow arrays using the io and image libraries from tensorflow. The data preprossing function are located in dataset.py. Fortunately the ISIC 2017 data has already been seperated into training, validationa and testing splits and so they can be used directly. Training size is 2000, validation size is 150, testing size is 600. Note, once the data has been preprocessed once it helps to save these arrays using np.save(). This will prevent wasting time for preprocessing. These arrays can be loaded with np.load(). + +## Training Results +The model was trained with a batch size of 32 and run for 30 epochs. The dice similarity is shown to be sufficiently heigh. + +![image](./report_images/dice_accuracy.png) + +![image](./report_images/loss.png) ## Dependecies -python 3.7.13 +python 3.9.13 tensorflow 2.9.1 -matlplotlib 3.5.2 -numpy 1.21.6 -glob2 0.7 -opencv 4.6.0 \ No newline at end of file +matlplotlib 3.5.2 +numpy 1.23.3 + +To use GPU when training + +tensorflow-gpu 2.6.0 + +## References +Isensee, F., Kickingereder, P., Wick, W., Bendszus, M., & Maier-Hein, K. H. (2018, February 28). Brain tumor segmentation and radiomics survival prediction: Contribution to the brats 2017 challenge. arXiv.org. Retrieved October 19, 2022, from https://arxiv.org/abs/1802.10508v1 \ No newline at end of file diff --git a/recognition/45838464-improvedUNET-ISIC/dataset.py b/recognition/45838464-improvedUNET-ISIC/dataset.py index 1f949be611..3e3eec8f22 100644 --- a/recognition/45838464-improvedUNET-ISIC/dataset.py +++ b/recognition/45838464-improvedUNET-ISIC/dataset.py @@ -1,7 +1,6 @@ import tensorflow as tf from tensorflow.keras.utils import to_categorical import numpy as np -import os import glob def preprocess_data(path): @@ -42,6 +41,7 @@ def preprocess_masks(path): mask = mask / 255.0 masks.append(mask) + # convert to one-hot encoding masks = np.array(masks) masks = to_categorical(masks) return masks diff --git a/recognition/45838464-improvedUNET-ISIC/modules.py b/recognition/45838464-improvedUNET-ISIC/modules.py index 0af4f1670d..4895966bf2 100644 --- a/recognition/45838464-improvedUNET-ISIC/modules.py +++ b/recognition/45838464-improvedUNET-ISIC/modules.py @@ -4,11 +4,8 @@ import tensorflow_addons as tfa import numpy as np -IMAGE_SIZE = 128 # latent space will have an encoding for every pixel -CHANNELS = 3 #RGB -BATCH_SIZE = 1 +IMAGE_SIZE = 128 KERNEL_SIZE = 3 -STRIDE = 2 FIRST_DEPTH = 16 DROPOUT = 0.3 activation_func = LeakyReLU(alpha=0.01) @@ -66,7 +63,7 @@ def decoding_layer(input, add, depth): return loc -def improved_uNET(): +def Improved_UNet(): """ Improved UNet Architecture build from block defined above. """ diff --git a/recognition/45838464-improvedUNET-ISIC/report-images/dice_accuracy.png b/recognition/45838464-improvedUNET-ISIC/report-images/dice_accuracy.png new file mode 100644 index 0000000000000000000000000000000000000000..cfac78c04f11e8c58e52e796246cd66a7cf91492 GIT binary patch literal 33931 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

KLHyYOSaa=N_aEofRImQ%S3ij-0B8In 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�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

  • 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�SH|- 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 literal 0 HcmV?d00001 diff --git a/recognition/45838464-improvedUNET-ISIC/report-images/loss.png b/recognition/45838464-improvedUNET-ISIC/report-images/loss.png new file mode 100644 index 0000000000000000000000000000000000000000..4a9e49a9923bd40b7952b2acd2cdd8f13c9f2cb9 GIT binary patch literal 19572 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 literal 0 HcmV?d00001 diff --git a/recognition/45838464-improvedUNET-ISIC/train.py b/recognition/45838464-improvedUNET-ISIC/train.py index 1559459ac1..c15f7b7765 100644 --- a/recognition/45838464-improvedUNET-ISIC/train.py +++ b/recognition/45838464-improvedUNET-ISIC/train.py @@ -1,12 +1,12 @@ from dataset import preprocess_data, preprocess_masks from modules import Improved_UNet -from utils import plot_accuracy, plot_loss +from utils import dice_coefficient, dice_coefficient_loss, plot_metrics from tensorflow.keras.optimizers import Adam import numpy as np import matplotlib.pyplot as plt -def training(datapaths, batch_size, epochs): +def train(datapaths, batch_size, epochs): """ Trains the Improved UNet model based on the given data. datapaths is a list in the form: @@ -28,7 +28,7 @@ def training(datapaths, batch_size, epochs): # build up Improved UNet model model = Improved_UNet() - model.compile(optimizer = Adam(0.0005), loss = "cro", metrics=['accuracy', modules.DSC]) + model.compile(optimizer = Adam(0.0005), loss=dice_coefficient_loss, metrics=[dice_coefficient]) history = model.fit(x_train, y_train, validation_data= (x_val, y_val), batch_size=batch_size,shuffle='True',epochs=epochs) @@ -36,6 +36,10 @@ def training(datapaths, batch_size, epochs): # save model model.save('./trained-model', include_optimizer=True, save_format='tf') # plot learning - plot_accuracy(history) - plot_loss(history) - plot_disc_scores() \ No newline at end of file + plot_metrics(history) + +# if __name__ == "__main__": +# epochs = 30 +# batch_size = 32 + +# train() \ No newline at end of file diff --git a/recognition/45838464-improvedUNET-ISIC/utils.py b/recognition/45838464-improvedUNET-ISIC/utils.py index 87d1815dd6..271108f550 100644 --- a/recognition/45838464-improvedUNET-ISIC/utils.py +++ b/recognition/45838464-improvedUNET-ISIC/utils.py @@ -22,27 +22,27 @@ def dice_coefficient_loss(truth, predition): """ return 1 - dice_coefficient(truth, predition) -def plot_accuracy(history): +def plot_metrics(history): """ - Plots the accuracy of the model throughout the training process. + Plots the dice coefficient and the loss of the model throughout the training process. """ - plt.plot(history.history['acc'], label='Training Accuracy') - plt.plot(history["val_acc"], label="Validation Accuracy") + plt.figure(1) + plt.plot(history.history['loss'], label='Training Loss') + plt.plot(history.history['val_loss'], label="Validation Loss") plt.xlabel("Epochs") - plt.ylabel("Accuracy (%)") - plt.title("Test and Validation Accuracy") + plt.ylabel("Loss") + plt.title("Training and Validation Loss") plt.legend(loc='lower right') - plt.savefig("./images/accuracy.png") + plt.savefig("./report-images/loss.png") -def plot_loss(history): - """ - Plots the loss of the model throughout a training session. - """ - plt.plot(history.history['loss'], label='Training Loss') - plt.plot(history["val_loss"], label="Validation Loss") + plt.figure(2) + plt.plot(history.history['dice_coefficient'], label='Training Accuracy') + plt.plot(history.history['val_dice_coefficient'], label="Validation Accuracy") plt.xlabel("Epochs") - plt.ylabel("Loss") - plt.title("Test and Validation Loss") + plt.ylabel("Dice Similarity") + plt.title("Training and Validation Accuracy") plt.legend(loc='lower right') - plt.savefig("./images/loss.png") + plt.savefig("./report-images/dice_accuracy.png") + +