I remember how hard it was when I started out in ML/PyTorch/Keras so here is some starter code. That being said, there is a wealth of information, both on this forum and online - I suggest you break up your questions into smaller parts to solve first by yourself, and then post your errors on the forum. It is generally not good practice to post your entire problem for the community to solve without efforts on your part (unless its an open research question).
Any pytorch dataset can be custom made following this boiler plate code below. You need to create:

An __init__ method that will house all the variables you need to call in future methods (like maybe a list of patients as below).
A __len__ method that will output the total size of your dataset, in this case its the number of patients you have in the folder
And finally, the heart of the dataset, the __getitem__ method which the dataloader will call on everytime with an index which is a number from 0 to size_of_dataset (ie len(self.patients)).


This method takes the idx-th index from the list of self.patients


path_to_pat is a direct path to the patient you want to load in this iteration
Using nib, you can load the patient’s full volume into the mri variable.
At this point, everything is numpy and you can do normalization as you please and at the end, return the mri volume as one datasample.
Now, if your batch size is greater than 1, you have to make sure all your patient volumes are the same size in all dimensions otherwise you will not be able to batch them. (You can do this by chunking or resampling, your design choice)

import os
import nibabel as nib
from torch.utils.data import Dataset, DataLoader

class ADNI(Dataset):

    def __init__(self, path_to_adni_files):      
        self.data_path = path_to_adni_files
        self.patients = os.listdir(self.data_path)
            
    def __len__(self):
        return len(self.patients)
            
    def __getitem__(self, idx):
        path_to_pat = os.path.join(self.data_path, self.patients[idx])
        mri = nib.load(path_to_pat).get_data()
        mri = (mri - mri.min())/(mri.max() - mri.min())
        mri = mri - mri.mean()       
        return mri

# example use
path_to_adni_files = "define_this_path"
dataset = ADNI(path_to_adni_files)
dataloader =  DataLoader(dataset, batch_size=1, shuffle=True)
one_batch_of_pats = next(iter(dataloader))
print(one_batch_of_pats.shape)