Pytorch Image Segmentation Tutorial For Beginners — I

Making masks for Brain Tumor MRI Images in Pytorch

5 min readAug 4, 2020

--

AI in Healthcare

Artificial intelligence (AI) is used in healthcare for prognosis, diagnosis, and treatment. AI reduces the healthcare cost and performance time, makes revenue cycle faster and more accurate, enhances the quality of healthcare processes.

AI to Enhance Radiology

Machine Learning and Artificial Intelligence are tremendous developments, especially with the new capabilities for image analysis that is making a real difference in speed, cost, and accuracy. It is going to power a lot of really exciting applications and solutions for radiologists to really help them do their job better, more easily, more reliably, and more usefully for their patients.

Image segmentation

In image segmentation the basic idea is we want to separate objects, we want to call different objects with different names depending on some properties of objects.

Making pixelwise binary classification of images is called “Semantic Segmentation”.

If we are trying to recognize many objects in an image we are performing “Instance Segmentation”. Instance Segmentation is a multiclass segmentation. For example, in self-driving cars, objects are classified as car, road, tree, house, sky, pedestrian, etc.

In this tutorial, we are doing semantic segmentation of Brain Tumor MRI images by making masks to them.

About The Project

We are making masks for brain tumor MRI images.

Brain tumor segmentation is an important task in healthcare AI. Early diagnosis of brain tumors has an important role in improving treatment possibilities and increases the survival rate of the patients. Manual segmentation of the brain tumors for cancer diagnosis, from large amount of MRI images generated in clinical routine, is a difficult and time consuming task. There is a need for automatic tumor image segmentation.

Brain Tumor MRI Images And Ground Truth Masks

Pytorch

In this tutorial, I explained how to make an image segmentation mask in Pytorch. I gave all the steps to make it easier for beginners.

Models Genesis

In this project, I used Models Genesis. The difference of Models Genesis is to train a U-Net model using health data. I downloaded the U-Net model class and weights from the Github page of Models Genesis.

Dataset

We can download the dataset from figshare.

This brain tumor dataset containing 3064 T1 MRIs from 233 patients with three kinds of brain tumor: Meningioma (708 slices), Glioma (1426 slices), Pituitary tumor (930 slices).

This data is organized in matlab data format (.mat file). Each file stores a struct containing the following fields for an image:

cjdata.label: 1 for meningioma, 2 for glioma, 3 for pituitary tumor

cjdata.PID: patient ID

cjdata.image: image data

cjdata.tumorBorder: a vector storing the coordinates of discrete points on tumor border. We can use it to generate a binary image of the tumor mask.

cjdata.tumorMask: a binary image with 1s indicating tumor region

I used only the cjdata.label and the cjdata.image.

Load The Images

We need to load 3064 images into the notebook. Images are in .mat format and names of the files are numbers. (i.e. 1.mat, 2.mat…)

Initialize two lists to store the images and masks.

image_data = []mask_data = []

Define the filenames.

filenames = range(1,3065)

Load all the images in a for loop

for name in filenames:file = h5py.File(‘/content/drive/My Drive/Brain-Tumor-Segmentation-Project/brainTumorData/’+str(name)+’.mat’, ‘r’).get(‘cjdata’)

Get the files

input = file.get(‘image’)[()]mask = file.get(‘tumorMask’)[()]

Change dimensions

Reshape, expand dimensions and append the images and masks to the lists.

input= np.reshape(input,(64,64,64))input = np.expand_dims(input,axis=0)image_data.append(input)mask = np.reshape(mask,(64,64,64))mask = np.expand_dims(mask,axis=0)mask_data.append(mask)

Note: There are 15 images whose sizes are not suitable for the model. We omit these images.

Split The Data

In deep learning, we need to make 3 splits: Train, test, and validation. So we use train_test_split two times. We can change the split ratio by changing the test size parameter. In this split ratio, we have train size = 2439, test size = 305, validation size= 305

from sklearn.model_selection import train_test_splitimage_train_data, image_test_data, mask_train_data, mask_test_data = train_test_split(image_data, mask_data, test_size = 0.1, random_state=123)image_train_data, image_val_data, mask_train_data, mask_val_data = train_test_split(image_train_data,mask_train_data, test_size = 0.111, random_state=123)

Data Loaders

Transform To Torch Tensor

We need to transform train, test, and validation data to tensors.

image_train_data = torch.Tensor(image_train_data) 
mask_train_data = torch.Tensor(mask_train_data)

Create Dataset Object

We create dataset objects for train, test, and validation sets.

train_dataset = TensorDataset(image_train_data, mask_train_data)

Create Data Loader Object

We create data loader objects for train, test and validation dataset objects.

We should set shuffle = True for the loader to mix the dataset and give all classes to the training model.

train_dataloader = DataLoader(train_dataset, batch_size = 4,    num_workers = 2, shuffle = True)

Transfer Learning Model Structure

Imagenet is state of art in transfer learning. However, we use the structure of a U-net model that is trained in health data. We download the U-net class from Models Genesis Github page.

We initialize our model with the U-net class.

model = UNet3D()

Pre-trained Weights

We download the weights of the model we use for transfer learning. You can download the weights from this request page.

Path

After getting the weights we define the path to the Genesis_Chest_CT.pt file.

weight_dir = ‘/content/drive/My Drive/Brain-Tumor-Segmentation-Project/Genesis_Chest_CT.pt’

Weights

Load the weights of Model Genesis from Genesis_Chest_CT.pt file to the notebook.

checkpoint = torch.load(weight_dir,map_location=torch.device(‘cpu’))state_dict = checkpoint[‘state_dict’]

Initialize a dictionary in the notebook to store the weights.

unParalled_state_dict = {}

Store weights in unparalleled_state_dict.

for key in state_dict.keys():unParalled_state_dict[key.replace(“module.”, “”)] = state_dict[key]

Load the new dictionary to the model.

model.load_state_dict(unParalled_state_dict)

Parameters

We define the training parameters of the network before we start training.

Criterion

We define a loss function for the model. We can use Binary Cross-Entropy(BCE) loss but we use a combination of BCE and DICE losses. For detailed information about image segmentation metrics, read this post. You can reach the code for bce_dice_loss from that post.

criterion = bce_dice_loss

Optimizer

We define an optimizer for the model. In this project, we use AdamW optimizer to prevent overfitting. AdamW implements Adam algorithm with weight decay fix.

from torch.optim import AdamWoptimizer = AdamW(model.parameters(), 0.1)

Learning Rate Scheduler

When we use a learning rate scheduler, we change the learning rate while training. We can achieve increased performance and faster training by adapting the learning rate for our stochastic gradient descent optimization procedure.

from torch.optim import lr_scheduler 
scheduler = lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.5)

Conclusion

Now we are ready to start training our model. In the next tutorial, we are going to train our model and interpret the results.

--

--