From 278397a6ecc70f3cb6cc1ca21b047683a2327969 Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Mon, 23 Oct 2023 03:55:13 +1000 Subject: [PATCH 01/16] VIT_init_test_1.py This is a test to ensure the repository and commits are correctly set up --- VIT_test.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 VIT_test.py diff --git a/VIT_test.py b/VIT_test.py new file mode 100644 index 000000000..8d0c938f4 --- /dev/null +++ b/VIT_test.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# coding: utf-8 + +# In[2]: + + +import torch +from torch import nn + + + +# classes + +class FeedForward(nn.Module): + def __init__(self, x, y): + super().__init__() + + def forward(self, x): + return self.net(x) + +class Attention(nn.Module): + def __init__(self, x, heads): + super().__init__() + + + +# In[ ]: + + + + From 8ba1b3e506b066cafd6b1d546dfef7f3b1e802cf Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Mon, 23 Oct 2023 22:23:20 +1000 Subject: [PATCH 02/16] upload_file.py Converting them to a format suitable for machine learning, organizing them into groups, and creating labels --- upload_file.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 upload_file.py diff --git a/upload_file.py b/upload_file.py new file mode 100644 index 000000000..a1908d0bc --- /dev/null +++ b/upload_file.py @@ -0,0 +1,80 @@ +import numpy as np +import torch +from PIL import Image +import os +import torchvision.transforms as transforms + +transform = transforms.Compose([ + transforms.PILToTensor() +]) + +xtrain = [] +xtest = [] +ytrain = [] +ytest = [] +slicemax = 20 #20 images per patient + +ntrainimgs_AD = 0 +patient = [] +slice = 0 +for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/train/AD/')): + f = os.path.join('../ADNI_AD_NC_2D/AD_NC/train/AD/', filename) + img = Image.open(f) + imgtorch = transform(img).float() + imgtorch.require_grad = True + patient.append(imgtorch/255) #go from 0,255 to 0,1 + slice = (slice+1) % slicemax + if slice == 0: + xtrain.append(torch.stack(patient)) + patient = [] + ntrainimgs_AD += 1 + pass +ntrainimgs_NC = 0 +patient = [] +slice = 0 +for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/train/NC')): + f = os.path.join('../ADNI_AD_NC_2D/AD_NC/train/NC', filename) + img = Image.open(f) + imgtorch = transform(img).float() + imgtorch.require_grad = True + patient.append(imgtorch/255) #go from 0,255 to 0,1 + slice = (slice+1) % slicemax + if slice == 0: + xtrain.append(torch.stack(patient)) + patient = [] + ntrainimgs_NC += 1 + pass +ntestimgs_AD = 0 +patient = [] +slice = 0 +for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/test/AD')): + f = os.path.join('../ADNI_AD_NC_2D/AD_NC/test/AD', filename) + img = Image.open(f) + imgtorch = transform(img).float() + imgtorch.require_grad = True + patient.append(imgtorch/255) #go from 0,255 to 0,1 + slice = (slice+1) % slicemax + if slice == 0: + xtest.append(torch.stack(patient)) + patient = [] + ntestimgs_AD += 1 + pass +ntestimgs_NC = 0 +patient = [] +slice = 0 +for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/test/NC')): + f = os.path.join('../ADNI_AD_NC_2D/AD_NC/test/NC', filename) + img = Image.open(f) + imgtorch = transform(img).float() + imgtorch.require_grad = True + patient.append(imgtorch/255) #go from 0,255 to 0,1 + slice = (slice+1) % slicemax + if slice == 0: + xtest.append(torch.stack(patient)) + patient = [] + ntestimgs_NC += 1 + pass +xtrain = torch.stack(xtrain) +xtest = torch.stack(xtest) +ytrain = torch.from_numpy(np.concatenate((np.ones(ntrainimgs_AD), np.zeros(ntrainimgs_NC)), axis=0)) +ytest = torch.from_numpy(np.concatenate((np.ones(ntestimgs_AD), np.zeros(ntestimgs_NC)), axis=0)) \ No newline at end of file From 99733ad9bc6fadf27b13e235b4264f9b7a2a6fb1 Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Tue, 24 Oct 2023 16:05:28 +1000 Subject: [PATCH 03/16] dataset.py Set-up data loading pipelines for training, validation, and testing --- dataset.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 dataset.py diff --git a/dataset.py b/dataset.py new file mode 100644 index 000000000..db5f4d7f0 --- /dev/null +++ b/dataset.py @@ -0,0 +1,13 @@ +from torchvision import datasets, transforms +from torch.utils.data import DataLoader, random_split + + +transform = transforms.Compose([transforms.Grayscale(num_output_channels=1), transforms.ToTensor()]) +dataset_train = datasets.ImageFolder('../ADNI_AD_NC_2D/AD_NC/train/', transform=transform) +dataloader_train = DataLoader(dataset_train, batch_size=32, shuffle=True) +dataset_test = datasets.ImageFolder('../ADNI_AD_NC_2D/AD_NC/test/', transform=transform) +dataset_test, dataset_val = random_split(dataset_test, [0.7, 0.3]) +dataloader_test = DataLoader(dataset_test, batch_size=32, shuffle=True) + +def returnDataloaders(): + return dataloader_train, dataloader_test, dataloader_val \ No newline at end of file From f60e732b368ef34b01d993766a8c8a0ea463a024 Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Tue, 24 Oct 2023 20:47:07 +1000 Subject: [PATCH 04/16] dataset.py Slight modification to code as error persisted --- dataset.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dataset.py b/dataset.py index db5f4d7f0..c7ceddb25 100644 --- a/dataset.py +++ b/dataset.py @@ -8,6 +8,7 @@ dataset_test = datasets.ImageFolder('../ADNI_AD_NC_2D/AD_NC/test/', transform=transform) dataset_test, dataset_val = random_split(dataset_test, [0.7, 0.3]) dataloader_test = DataLoader(dataset_test, batch_size=32, shuffle=True) +dataloader_val = DataLoader(dataset_val, batch_size=32, shuffle=True) def returnDataloaders(): return dataloader_train, dataloader_test, dataloader_val \ No newline at end of file From 56cfdd75b9a19db73aa94c6c26de5e6b8d657292 Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Wed, 25 Oct 2023 01:48:57 +1000 Subject: [PATCH 05/16] Update of dataset.py Completely changed dataset.py as previously it dealt with 2d images, now updated for 3d --- dataset.py | 95 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 10 deletions(-) diff --git a/dataset.py b/dataset.py index c7ceddb25..50087ea72 100644 --- a/dataset.py +++ b/dataset.py @@ -1,14 +1,89 @@ -from torchvision import datasets, transforms -from torch.utils.data import DataLoader, random_split +import numpy as np +import torch +from PIL import Image +import os +import torchvision.transforms as transforms +from torch.utils.data import TensorDataset, DataLoader, random_split +transform = transforms.Compose([ + transforms.PILToTensor() +]) -transform = transforms.Compose([transforms.Grayscale(num_output_channels=1), transforms.ToTensor()]) -dataset_train = datasets.ImageFolder('../ADNI_AD_NC_2D/AD_NC/train/', transform=transform) -dataloader_train = DataLoader(dataset_train, batch_size=32, shuffle=True) -dataset_test = datasets.ImageFolder('../ADNI_AD_NC_2D/AD_NC/test/', transform=transform) -dataset_test, dataset_val = random_split(dataset_test, [0.7, 0.3]) -dataloader_test = DataLoader(dataset_test, batch_size=32, shuffle=True) -dataloader_val = DataLoader(dataset_val, batch_size=32, shuffle=True) +xtrain = [] +xtest = [] +ytrain = [] +ytest = [] +slicemax = 20 #20 images per patient -def returnDataloaders(): +ntrainimgs_AD = 0 +patient = [] +slice = 0 +for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/train/AD/')): + f = os.path.join('../ADNI_AD_NC_2D/AD_NC/train/AD/', filename) + img = Image.open(f) + imgtorch = transform(img).float() + imgtorch.require_grad = True + patient.append(imgtorch/255) #go from 0,255 to 0,1 + slice = (slice+1) % slicemax + if slice == 0: + xtrain.append(torch.stack(patient)) + patient = [] + ntrainimgs_AD += 1 + pass +ntrainimgs_NC = 0 +patient = [] +slice = 0 +for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/train/NC')): + f = os.path.join('../ADNI_AD_NC_2D/AD_NC/train/NC', filename) + img = Image.open(f) + imgtorch = transform(img).float() + imgtorch.require_grad = True + patient.append(imgtorch/255) #go from 0,255 to 0,1 + slice = (slice+1) % slicemax + if slice == 0: + xtrain.append(torch.stack(patient)) + patient = [] + ntrainimgs_NC += 1 + pass +ntestimgs_AD = 0 +patient = [] +slice = 0 +for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/test/AD')): + f = os.path.join('../ADNI_AD_NC_2D/AD_NC/test/AD', filename) + img = Image.open(f) + imgtorch = transform(img).float() + imgtorch.require_grad = True + patient.append(imgtorch/255) #go from 0,255 to 0,1 + slice = (slice+1) % slicemax + if slice == 0: + xtest.append(torch.stack(patient)) + patient = [] + ntestimgs_AD += 1 + pass +ntestimgs_NC = 0 +patient = [] +slice = 0 +for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/test/NC')): + f = os.path.join('../ADNI_AD_NC_2D/AD_NC/test/NC', filename) + img = Image.open(f) + imgtorch = transform(img).float() + imgtorch.require_grad = True + patient.append(imgtorch/255) #go from 0,255 to 0,1 + slice = (slice+1) % slicemax + if slice == 0: + xtest.append(torch.stack(patient)) + patient = [] + ntestimgs_NC += 1 + pass +xtrain = torch.stack(xtrain) +xtest = torch.stack(xtest) +ytrain = torch.from_numpy(np.concatenate((np.ones(ntrainimgs_AD), np.zeros(ntrainimgs_NC)), axis=0)) +ytest = torch.from_numpy(np.concatenate((np.ones(ntestimgs_NC), np.zeros(ntestimgs_NC)), axis=0)) + +data_val, data_test = random_split(TensorDataset(xtest, ytest), [0.7,0.3]) +dataloader_train = DataLoader(TensorDataset(xtrain, ytrain), batch_size=32, shuffle=True) +dataloader_test = DataLoader(data_test, batch_size=32, shuffle=True) +dataloader_val = DataLaoder(data_val, batch_size=32, shuffle=True) + +def returnDataLoaders(): return dataloader_train, dataloader_test, dataloader_val \ No newline at end of file From 9233558e778d70e2235f7dbe5aa96bce68c89a63 Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Thu, 26 Oct 2023 03:38:47 +1000 Subject: [PATCH 06/16] source code of the components of your model define the core components of your recognition model using classes or functions. --- modules.py | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 modules.py diff --git a/modules.py b/modules.py new file mode 100644 index 000000000..508926a73 --- /dev/null +++ b/modules.py @@ -0,0 +1,73 @@ +import torch +import torch.nn as nn + +def image_patcher(image,size_patch, patch_depth): + Batch_Size, Depth, C, Height, Width = image.shape + # change the shape of the tensor + Height_final = Height // size_patch + Width_final = Width // size_patch + Depth_final = Depth // patch_depth + image = image.reshape(Batch_Size, Depth_final, patch_depth, C,Height_final,size_patch,Width_final,size_patch) + #permute the dimensions of the tensor + image = image.permute(0, 1, 4, 6, 3, 2, 5, 7) + #flatten specific dimensions of the tensor + image = image.flatten(1, 3).flatten(2, 5) + return image + +class AttentionBlock(nn.Module): + def __init__(self,input_dimen,hiddenlayer_dimen,number_heads): + super().__init__() + #layer normalization is applied to the input data + self.input_layer_norm = nn.LayerNorm(input_dimen) + #normalizes the output of the attention mechanism. + self.output_layer_norm = nn.LayerNorm(input_dimen) + # block with multiple attention heads. + self.multihead_attention = nn.MultiheadAttention(input_dimen,number_heads) + self.linear = nn.Sequential(nn.Linear(input_dimen,hiddenlayer_dimen),nn.GELU(), + nn.Linear(hiddenlayer_dimen,input_dimen), + ) + + def forward(self,image): + inp_x = self.input_layer_norm(image) + add = self.multihead_attention(inp_x, inp_x, inp_x)[0] + image = image + add + image = image + self.linear(self.output_layer_norm(image)) + return image + +class VisionTransformer(nn.Module): + def __init__( + self,input_dimen,hiddenlayer_dimen,number_heads,transform_layers,predict_num,size_patch + ): + super().__init__() + (size_patch_x, size_patch_y) = size_patch + + self.size_patch = size_patch_x * size_patch_y + #creates an instance of the nn.linear + self.input_layer = nn.Linear(5*self.size_patch, input_dimen) + #creates an instance of nn.sequential + self.final_transform = nn.Sequential(*(AttentionBlock(input_dimen, hiddenlayer_dimen, number_heads) for _ in range(transform_layers))) + + self.dense_head = nn.Sequential(nn.LayerNorm(input_dimen), nn.Linear(input_dimen, predict_num)) + final_num_patch = 1 + (240 // size_patch_x)*(256 // size_patch_y) + self.positional_emb = nn.Parameter(torch.randn(1,4*final_num_patch,input_dimen)) + self.classification_tkn = nn.Parameter(torch.randn(1,1,input_dimen)) + + + def forward(self, image): + # input being preprocessed + image = image_patcher(image, 16, 5) + Batch_Size, x, _ = image.shape + + image = self.input_layer(image) + + # Add a positional encoding and a CLS token + classification_tkn = self.classification_tkn.repeat(Batch_Size, 1, 1) + image = torch.cat([classification_tkn, image], dim=1) + image = image + self.positional_emb[:, : x + 1] + + #this adds a final_transform + image = image.transpose(0, 1) + image = self.final_transform(image) + class_ = image[0] + out = self.dense_head(class_) + return out \ No newline at end of file From e2103f7472037f0e52618340cd7ba86a03ab24f6 Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Thu, 26 Oct 2023 03:39:37 +1000 Subject: [PATCH 07/16] Tiny updates and increased epoch to 75 Increased Epoch to get high accuracy --- train.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 train.py diff --git a/train.py b/train.py new file mode 100644 index 000000000..a97432315 --- /dev/null +++ b/train.py @@ -0,0 +1,48 @@ +import torch +import torch.nn as nn +from dataset import returnDataLoaders +from modules import * +import torch.optim as optim + +dataloader_train, dataloader_test, dataloader_val = returnDataloaders() + +losses = [] +accuracies = [] + +def train(net, dataloader_train, dataloader_val, cross_entropy): + optimizer = optim.Adam(net.parameters(), lr=1e-4) + epochs = 75 + # training loop + for epoch in range(epochs): + epoch_loss = 0 + net.train() + for (x_batch, y_batch) in dataloader_train: # for each mini-batch + optimizer.zero_grad() + loss = cross_entropy(net.forward(x_batch), y_batch) + loss.backward() + optimizer.step() + epoch_loss += loss.detach().item() + epoch_loss = epoch_loss / len(dataloader_train) + losses.append(epoch_loss) + + net.eval() + acc = test(net, dataloader_val) + print("epoch:", epoch, "accuracy:", acc, flush=True) + accuracies.append(acc) + +def test(net, dataloader_val, batch_size=16): + with torch.no_grad(): + acc = 0 + for (x_batch, y_batch) in dataloader_val: + acc += torch.sum((y_batch == torch.max(net(x_batch).detach(), 1)[1]), axis=0)/len(y_batch) + acc = acc/len(dataloader_val) + return acc + +vit = VisionTransformer(input_dimen=128, + hiddenlayer_dimen=256, + number_heads=4, + transform_layers=4, + predict_num=2, + size_patch=(16,16)) +cross_entropy = nn.CrossEntropyLoss() +train(vit, dataloader_train, dataloader_val, cross_entropy) From 827e1894194198805b78c86e62c41df767f2fb91 Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Thu, 26 Oct 2023 03:41:07 +1000 Subject: [PATCH 08/16] Fixed tiny errors that came up upon testing --- dataset.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dataset.py b/dataset.py index 50087ea72..95c6a1414 100644 --- a/dataset.py +++ b/dataset.py @@ -77,13 +77,13 @@ pass xtrain = torch.stack(xtrain) xtest = torch.stack(xtest) -ytrain = torch.from_numpy(np.concatenate((np.ones(ntrainimgs_AD), np.zeros(ntrainimgs_NC)), axis=0)) -ytest = torch.from_numpy(np.concatenate((np.ones(ntestimgs_NC), np.zeros(ntestimgs_NC)), axis=0)) +ytrain = torch.from_numpy(np.concatenate((np.ones(ntrainimgs_AD), np.zeros(ntrainimgs_NC)), axis=0)).type(torch.LongTensor) +ytest = torch.from_numpy(np.concatenate((np.ones(ntestimgs_AD), np.zeros(ntestimgs_NC)), axis=0)).type(torch.LongTensor) data_val, data_test = random_split(TensorDataset(xtest, ytest), [0.7,0.3]) dataloader_train = DataLoader(TensorDataset(xtrain, ytrain), batch_size=32, shuffle=True) dataloader_test = DataLoader(data_test, batch_size=32, shuffle=True) -dataloader_val = DataLaoder(data_val, batch_size=32, shuffle=True) +dataloader_val = DataLoader(data_val, batch_size=32, shuffle=True) def returnDataLoaders(): return dataloader_train, dataloader_test, dataloader_val \ No newline at end of file From e3b92860ff9b9788d2d4e049bfd1642437211ada Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Fri, 27 Oct 2023 02:04:00 +1000 Subject: [PATCH 09/16] predict.py with 75 epoch and just accuracy plot Just copied the accuracies from the output file in rangpur and plotted it against the epoch --- predict.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 predict.py diff --git a/predict.py b/predict.py new file mode 100644 index 000000000..ed6eac938 --- /dev/null +++ b/predict.py @@ -0,0 +1,31 @@ +import torch +from train import test +#from dataset import trainloader, valloader, testloader +from dataset import returnDataLoaders + + +import matplotlib.pyplot as plt + +model = torch.jit.load('model_trained.pt') +model.eval() + +epoch = list(range(75)) +accuracies = [ + 0.4939, 0.6016, 0.5729, 0.5243, 0.5050, 0.5343, 0.5786, 0.6042, 0.5075, 0.5056, + 0.5925, 0.5694, 0.5604, 0.5567, 0.6067, 0.5681, 0.5337, 0.5422, 0.5243, 0.5431, + 0.5194, 0.5806, 0.5905, 0.5794, 0.5880, 0.6260, 0.5737, 0.5675, 0.5709, 0.5942, + 0.6061, 0.6022, 0.5829, 0.6149, 0.6022, 0.5905, 0.5786, 0.5704, 0.6399, 0.6260, + 0.5843, 0.5856, 0.5999, 0.6118, 0.5885, 0.5999, 0.6104, 0.5536, 0.6130, 0.5612, + 0.6374, 0.6106, 0.6155, 0.6388, 0.5968, 0.6167, 0.6167, 0.5587, 0.5874, 0.5601, + 0.6019, 0.5905, 0.6093, 0.6013, 0.6005, 0.5987, 0.5997, 0.5944, 0.6024, 0.6036, + 0.6079, 0.6036, 0.6013, 0.6050, 0.6013, 0.6812 +] + +plt.figure(figsize=(12, 6)) +plt.plot(epoch, accuracies, marker='o', linestyle='-', color='b', label='Accuracy') +plt.title('Accuracy vs Epoch') +plt.xlabel('Epoch') +plt.ylabel('Accuracy') +plt.legend() +plt.grid(True) +plt.show() From b0cea1782ce9060604ca4b9a68f5868a99f5e973 Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Fri, 27 Oct 2023 13:21:43 +1000 Subject: [PATCH 10/16] Update learning rate and epoch Testing to see what would give highest accuracy. This gave 0.68 --- train.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/train.py b/train.py index a97432315..fe10ee451 100644 --- a/train.py +++ b/train.py @@ -10,8 +10,8 @@ accuracies = [] def train(net, dataloader_train, dataloader_val, cross_entropy): - optimizer = optim.Adam(net.parameters(), lr=1e-4) - epochs = 75 + optimizer = optim.AdamW(net.parameters(), lr=3e-4) + epochs = 100 # training loop for epoch in range(epochs): epoch_loss = 0 @@ -24,10 +24,10 @@ def train(net, dataloader_train, dataloader_val, cross_entropy): epoch_loss += loss.detach().item() epoch_loss = epoch_loss / len(dataloader_train) losses.append(epoch_loss) - + net.eval() acc = test(net, dataloader_val) - print("epoch:", epoch, "accuracy:", acc, flush=True) + print("epoch:", epoch, "accuracy:", acc, "loss:", epoch_loss, flush=True) accuracies.append(acc) def test(net, dataloader_val, batch_size=16): From 6a70144858d213c3acfd0d6fabc732be459f48e4 Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Fri, 27 Oct 2023 15:52:23 +1000 Subject: [PATCH 11/16] Update to the README.md First proper update on readme.md. Still need to add graphs --- README.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 4a064f841..ff6b0fb70 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,60 @@ -# Pattern Analysis -Pattern Analysis of various datasets by COMP3710 students at the University of Queensland. +# Classifying Alzheimer's Disease Diagnoses Using Vision Trainsformer -We create pattern recognition and image processing library for Tensorflow (TF), PyTorch or JAX. +This project aims to categorize the ADNI brain dataset into AD (Alzheimer's Disease) and NC (Normal Cognitive) groups. It employs a Vision Transformer network (ViT) based on the principles presented in the paper. The model was trained using an Adam Optimizer and the parameters were tweaked often to find a good accuracy. Each sample has 20 slices that is 240x256 greyscale image corresponding to a patient, which is to be classified as either NC or AD -This library is created and maintained by The University of Queensland [COMP3710](https://my.uq.edu.au/programs-courses/course.html?course_code=comp3710) students. +## Dataset Splitting -The library includes the following implemented in Tensorflow: -* fractals -* recognition problems +The dataset is already split into 21,500 images for training, and 9000 images for testing. However, I needed a third split for validation in the dataset.py file. +data_val, data_test = random_split(TensorDataset(xtest, ytest), [0.7,0.3]) +I used random_split for the validation and did a 70/30 split. +I then ended up with 6300 images for validation, and 2700 for testing. -In the recognition folder, you will find many recognition problems solved including: -* OASIS brain segmentation -* Classification -etc. +## Preprocessing the data +The provided code preprocesses the image data by dividing it into patches, applying layer normalization and Multihead Attention mechanisms, and incorporating positional encoding before utilizing the Vision Transformer + +## Training the data +These were the following parameters used for training. I didnt need a parameter for number of channels as we were only dealing with black and white data. +vit = VisionTransformer(input_dimen=128, + hiddenlayer_dimen=256, + number_heads=4, + transform_layers=4, + predict_num=2, + size_patch=(16,16)) +input_dimen - Dimensionality of the input feature vectors to the Transformer +hiddenlayer_dimen - Dimensionality of the hidden layer in the feed-forward networks within the Transformer +number_heads - Number of heads to use in the Multi-Head Attention block +transform_layers - Number of layers to use in the Transformer +predict_num - Number of classes to predict +size_patch - Number of pixels that the patches have per dimension + +The time taken to finish training depended on the parameters. +Using adam optimizer and learning rate = 1e-4 and 75 epoch, I had accuracy of 0.68 ( 5.5 hours ) +With adamW optimizer and learning rate = 3e-4 and 100 epoch, I had a low accuracy of 0.53 ( 7 hours ) + +## Configuration +All main configurations would be done in the train.py file +In the train function there is this: + optimizer = optim.AdamW(net.parameters(), lr=3e-4) + epochs = 100 +You can change between optimizers, learning rate and epoch value in here +Also in the end of the train.py file, there is the VIT. + +vit = VisionTransformer(input_dimen=128, + hiddenlayer_dimen=256, + number_heads=4, + transform_layers=4, + predict_num=2, + size_patch=(16,16)) + + + + +The project consists of four essential files, namely dataset.py, modules.py, train.py, and predict.py. The primary files to be executed are train.py and predict.py. The train.py file handles the training and testing of the model, allowing the option to save the model, along with recording the loss and validation accuracy for each epoch. This data is utilized by predict.py. Predict.py evaluates the actual output data as it can generate graphs depicting the loss and accuracy curves using the matplotlib library. + + + +Key considerations: +1. Inside the dataset.py file, script loads, preprocesses, and organizes medical image data from specific directories, converting the images to tensors, dividing them into training and testing sets with corresponding labels, and creating data loaders for training, testing, and validation. +2. in train.py script imports required libraries, modules, and functions, then loads the data using returnDataLoaders from the dataset.py file. It defines an empty list for storing losses and accuracies, sets up a training function that utilizes the AdamW optimizer and CrossEntropyLoss +3. In the predict.py script, I plot two separate graphs. The first graph illustrates the accuracy vs epoch, displaying the trend of the model's accuracy over the training epochs. The second graph demonstrates the loss vs epoch, showcasing how the training loss varies throughout the training process. +4. The modules.py file contains functions and classes for implementing a Vision Transformer model, including an image patching function, an attention block class for multi-head attention, and a VisionTransformer class that applies linear transformations, positional embeddings \ No newline at end of file From d78a6ad289e201c826bbc7de0712cd8df43ec159 Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Fri, 27 Oct 2023 17:48:07 +1000 Subject: [PATCH 12/16] Delete upload_file.py --- upload_file.py | 80 -------------------------------------------------- 1 file changed, 80 deletions(-) delete mode 100644 upload_file.py diff --git a/upload_file.py b/upload_file.py deleted file mode 100644 index a1908d0bc..000000000 --- a/upload_file.py +++ /dev/null @@ -1,80 +0,0 @@ -import numpy as np -import torch -from PIL import Image -import os -import torchvision.transforms as transforms - -transform = transforms.Compose([ - transforms.PILToTensor() -]) - -xtrain = [] -xtest = [] -ytrain = [] -ytest = [] -slicemax = 20 #20 images per patient - -ntrainimgs_AD = 0 -patient = [] -slice = 0 -for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/train/AD/')): - f = os.path.join('../ADNI_AD_NC_2D/AD_NC/train/AD/', filename) - img = Image.open(f) - imgtorch = transform(img).float() - imgtorch.require_grad = True - patient.append(imgtorch/255) #go from 0,255 to 0,1 - slice = (slice+1) % slicemax - if slice == 0: - xtrain.append(torch.stack(patient)) - patient = [] - ntrainimgs_AD += 1 - pass -ntrainimgs_NC = 0 -patient = [] -slice = 0 -for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/train/NC')): - f = os.path.join('../ADNI_AD_NC_2D/AD_NC/train/NC', filename) - img = Image.open(f) - imgtorch = transform(img).float() - imgtorch.require_grad = True - patient.append(imgtorch/255) #go from 0,255 to 0,1 - slice = (slice+1) % slicemax - if slice == 0: - xtrain.append(torch.stack(patient)) - patient = [] - ntrainimgs_NC += 1 - pass -ntestimgs_AD = 0 -patient = [] -slice = 0 -for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/test/AD')): - f = os.path.join('../ADNI_AD_NC_2D/AD_NC/test/AD', filename) - img = Image.open(f) - imgtorch = transform(img).float() - imgtorch.require_grad = True - patient.append(imgtorch/255) #go from 0,255 to 0,1 - slice = (slice+1) % slicemax - if slice == 0: - xtest.append(torch.stack(patient)) - patient = [] - ntestimgs_AD += 1 - pass -ntestimgs_NC = 0 -patient = [] -slice = 0 -for filename in sorted(os.listdir('../ADNI_AD_NC_2D/AD_NC/test/NC')): - f = os.path.join('../ADNI_AD_NC_2D/AD_NC/test/NC', filename) - img = Image.open(f) - imgtorch = transform(img).float() - imgtorch.require_grad = True - patient.append(imgtorch/255) #go from 0,255 to 0,1 - slice = (slice+1) % slicemax - if slice == 0: - xtest.append(torch.stack(patient)) - patient = [] - ntestimgs_NC += 1 - pass -xtrain = torch.stack(xtrain) -xtest = torch.stack(xtest) -ytrain = torch.from_numpy(np.concatenate((np.ones(ntrainimgs_AD), np.zeros(ntrainimgs_NC)), axis=0)) -ytest = torch.from_numpy(np.concatenate((np.ones(ntestimgs_AD), np.zeros(ntestimgs_NC)), axis=0)) \ No newline at end of file From dd1e10013eb7fc2991b34687d74ac7ecdb5587e2 Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Fri, 27 Oct 2023 17:48:30 +1000 Subject: [PATCH 13/16] Delete VIT_test.py --- VIT_test.py | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 VIT_test.py diff --git a/VIT_test.py b/VIT_test.py deleted file mode 100644 index 8d0c938f4..000000000 --- a/VIT_test.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -# coding: utf-8 - -# In[2]: - - -import torch -from torch import nn - - - -# classes - -class FeedForward(nn.Module): - def __init__(self, x, y): - super().__init__() - - def forward(self, x): - return self.net(x) - -class Attention(nn.Module): - def __init__(self, x, heads): - super().__init__() - - - -# In[ ]: - - - - From 62e18da2e61ed829f1773870294e275b6000189a Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Fri, 27 Oct 2023 23:03:29 +1000 Subject: [PATCH 14/16] Update README.md --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ff6b0fb70..40219ca66 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,16 @@ vit = VisionTransformer(input_dimen=128, predict_num=2, size_patch=(16,16)) +## Results +These are the results: +loss vs epoch graph- ![image](https://github.com/HaadiQureshi/VIT-46878467/assets/141606798/64605a94-429c-4dc8-b5fd-8e4e10276942) +Accuracy vs epoch graph - image + + +## How to use The project consists of four essential files, namely dataset.py, modules.py, train.py, and predict.py. The primary files to be executed are train.py and predict.py. The train.py file handles the training and testing of the model, allowing the option to save the model, along with recording the loss and validation accuracy for each epoch. This data is utilized by predict.py. Predict.py evaluates the actual output data as it can generate graphs depicting the loss and accuracy curves using the matplotlib library. @@ -57,4 +64,4 @@ Key considerations: 1. Inside the dataset.py file, script loads, preprocesses, and organizes medical image data from specific directories, converting the images to tensors, dividing them into training and testing sets with corresponding labels, and creating data loaders for training, testing, and validation. 2. in train.py script imports required libraries, modules, and functions, then loads the data using returnDataLoaders from the dataset.py file. It defines an empty list for storing losses and accuracies, sets up a training function that utilizes the AdamW optimizer and CrossEntropyLoss 3. In the predict.py script, I plot two separate graphs. The first graph illustrates the accuracy vs epoch, displaying the trend of the model's accuracy over the training epochs. The second graph demonstrates the loss vs epoch, showcasing how the training loss varies throughout the training process. -4. The modules.py file contains functions and classes for implementing a Vision Transformer model, including an image patching function, an attention block class for multi-head attention, and a VisionTransformer class that applies linear transformations, positional embeddings \ No newline at end of file +4. The modules.py file contains functions and classes for implementing a Vision Transformer model, including an image patching function, an attention block class for multi-head attention, and a VisionTransformer class that applies linear transformations, positional embeddings From 2261826a5078ffd99c0165747b88f8a4979606dd Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Fri, 27 Oct 2023 23:05:24 +1000 Subject: [PATCH 15/16] Finalise train.py and predict.py --- predict.py | 36 +++++++++++++++++------------------- train.py | 2 +- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/predict.py b/predict.py index ed6eac938..3596a3e94 100644 --- a/predict.py +++ b/predict.py @@ -1,25 +1,13 @@ -import torch -from train import test -#from dataset import trainloader, valloader, testloader -from dataset import returnDataLoaders +import matplotlib.pyplot as plt +#This is the accuracies of the first 100 epoch +accuracies = [0.4962, 0.5274, 0.5917, 0.4944, 0.5124, 0.5476, 0.5922, 0.5431, 0.5013, 0.5294, 0.5464, 0.5487, 0.5922, 0.6340, 0.5876, 0.6005, 0.6104, 0.6167, 0.6243, 0.6215, 0.6473, 0.6436, 0.5936, 0.6391, 0.6030, 0.6030, 0.5675, 0.6116, 0.6212, 0.5968, 0.5843, 0.6056, 0.6073, 0.6175, 0.5985, 0.5948, 0.6186, 0.5752, 0.6056, 0.5769, 0.6042, 0.6212, 0.5825, 0.5931, 0.5786, 0.6002, 0.5712, 0.5624, 0.5907, 0.5848, 0.6260, 0.6030, 0.5854, 0.5819, 0.6329, 0.6042, 0.6204, 0.6106, 0.6110, 0.6112, 0.6126, 0.6126, 0.6135, 0.6098, 0.6081, 0.6087, 0.6130, 0.6167, 0.6118, 0.6130, 0.6135, 0.6124, 0.6118, 0.6135, 0.6124, 0.6106, 0.6141, 0.6147, 0.6141, 0.6112, 0.6118, 0.6130, 0.6153, 0.6135, 0.6130, 0.6101, 0.6124, 0.6135, 0.6141, 0.6095, 0.6147, 0.6112, 0.6118, 0.6093, 0.6159, 0.6098, 0.6087, 0.6093, 0.6093, 0.6093] +#This is the loss for the first 100 epoch +loss = [0.6979881910716786, 0.6844412877279169, 0.6904780426446129, 0.684895454084172, 0.6812622880234438, 0.6792347308467416, 0.6771022852729348, 0.6855413440395804, 0.6720500413109275, 0.6870778799057007, 0.6519009260570302, 0.6404731641797459, 0.6227208665188622, 0.5900690169895396, 0.5951909887440064, 0.5607741247205174, 0.5638843687141643, 0.5399825283709694, 0.5193865106386297, 0.4769795151317821, 0.46142111543346853, 0.45512034174273996, 0.4230612568995532, 0.3895933969932444, 0.39457252358689027, 0.3760155246538274, 0.37903575160924124, 0.3169827342909925, 0.3307492321028429, 0.25006428689641114, 0.2171676978468895, 0.284952069468358, 0.19351636508808417, 0.19536656217978282, 0.1634677432696609, 0.11777753673274727, 0.14037292516406844, 0.23939100105096311, 0.11117816716432571, 0.06792027106070343, 0.11127064086715965, 0.08680430388845065, 0.08349954084876705, 0.0602918595815187, 0.04537964773172622, 0.018756276154068902, 0.017304050311555758, 0.0667554905932561, 0.056819359415813404, 0.01601847937426475, 0.0256724186885335, 0.08536267633248559, 0.016678674338275894, 0.021344836472588426, 0.03200960334951935, 0.054271318350562495, 0.032041940687443406, 0.008468315467539737, 0.0025479644400012843, 0.0009727750567596077, 0.0007114587334559902, 0.0006080651262035483, 0.0005404480839120772, 0.0004825884388992563, 0.00043984228036339013, 0.0004121263824773076, 0.00037888841025586077, 0.0003548304273007328, 0.0003334864805390894, 0.0003150697696529438, 0.0002981368049992906, 0.00028354384695001715, 0.00027058320034377496, 0.0002587148782742374, 0.00024809086993199717, 0.00023693855730337366, 0.0002282507754417191, 0.00022031878153725034, 0.00021815271654358024, 0.0002045452338814571, 0.00019706551778226103, 0.00019002843627651388, 0.0001844407169675619, 0.00017817121774629305, 0.00017225533241905985, 0.00016851070519324448, 0.00016327866144231795, 0.0001579179693448275, 0.00015318737795870917, 0.00014883789652444916, 0.00014545178911409013, 0.00014506131992675364, 0.00013773206635104383, 0.00013385336698026068, 0.00013058477484532085, 0.00012730956672492218, 0.00012449162686072455, 0.00012149684548871043, 0.0001185430414539844, 0.00011599305349484305] -import matplotlib.pyplot as plt -model = torch.jit.load('model_trained.pt') -model.eval() - -epoch = list(range(75)) -accuracies = [ - 0.4939, 0.6016, 0.5729, 0.5243, 0.5050, 0.5343, 0.5786, 0.6042, 0.5075, 0.5056, - 0.5925, 0.5694, 0.5604, 0.5567, 0.6067, 0.5681, 0.5337, 0.5422, 0.5243, 0.5431, - 0.5194, 0.5806, 0.5905, 0.5794, 0.5880, 0.6260, 0.5737, 0.5675, 0.5709, 0.5942, - 0.6061, 0.6022, 0.5829, 0.6149, 0.6022, 0.5905, 0.5786, 0.5704, 0.6399, 0.6260, - 0.5843, 0.5856, 0.5999, 0.6118, 0.5885, 0.5999, 0.6104, 0.5536, 0.6130, 0.5612, - 0.6374, 0.6106, 0.6155, 0.6388, 0.5968, 0.6167, 0.6167, 0.5587, 0.5874, 0.5601, - 0.6019, 0.5905, 0.6093, 0.6013, 0.6005, 0.5987, 0.5997, 0.5944, 0.6024, 0.6036, - 0.6079, 0.6036, 0.6013, 0.6050, 0.6013, 0.6812 -] +epoch = list(range(100)) + plt.figure(figsize=(12, 6)) plt.plot(epoch, accuracies, marker='o', linestyle='-', color='b', label='Accuracy') @@ -29,3 +17,13 @@ plt.legend() plt.grid(True) plt.show() + + + +plt.plot(range(len(loss)), loss, marker='o', linestyle='-', color='b', label='Loss') +plt.title('Loss vs Epoch') +plt.xlabel('Epoch') +plt.ylabel('Loss') +plt.legend() +plt.grid() +plt.show() \ No newline at end of file diff --git a/train.py b/train.py index fe10ee451..eeaa50abb 100644 --- a/train.py +++ b/train.py @@ -10,7 +10,7 @@ accuracies = [] def train(net, dataloader_train, dataloader_val, cross_entropy): - optimizer = optim.AdamW(net.parameters(), lr=3e-4) + optimizer = optim.Adam(net.parameters(), lr=2e-4) epochs = 100 # training loop for epoch in range(epochs): From ccdc0e57ae5e9054d6246bad9788a24899fe25eb Mon Sep 17 00:00:00 2001 From: HaadiQureshi <141606798+HaadiQureshi@users.noreply.github.com> Date: Fri, 27 Oct 2023 23:08:29 +1000 Subject: [PATCH 16/16] Update README.md url --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 40219ca66..e77aaae6e 100644 --- a/README.md +++ b/README.md @@ -65,3 +65,5 @@ Key considerations: 2. in train.py script imports required libraries, modules, and functions, then loads the data using returnDataLoaders from the dataset.py file. It defines an empty list for storing losses and accuracies, sets up a training function that utilizes the AdamW optimizer and CrossEntropyLoss 3. In the predict.py script, I plot two separate graphs. The first graph illustrates the accuracy vs epoch, displaying the trend of the model's accuracy over the training epochs. The second graph demonstrates the loss vs epoch, showcasing how the training loss varies throughout the training process. 4. The modules.py file contains functions and classes for implementing a Vision Transformer model, including an image patching function, an attention block class for multi-head attention, and a VisionTransformer class that applies linear transformations, positional embeddings +# URL +https://github.com/HaadiQureshi/VIT-46878467.git