In order to have flexibility to play with the noise, I wouldn’t save a noise-added dataset.
As for your case where you want to add more perturbations, that transform approach also works here. You can have several conditional transforms if needed, ie to add or not add noise, followed by other perturbations as needed. Here’s one example from one of my projects:
train_transform = transforms.Compose([
            ImageThinning(p = cf.thinning_threshold) if cf.thinning_threshold < 1 else NoneTransform(),            
            OverlayImage(cf) if cf.overlay_image else NoneTransform(), # Add random image background here, to mimic painting            
            PadImage((cf.MAX_IMAGE_WIDTH, cf.MAX_IMAGE_HEIGHT)) if cf.pad_images else NoneTransform(),            
            transforms.Resize(cf.input_size) if cf.resize_images else NoneTransform(),            
            transforms.ToTensor(),            
            transforms.Lambda(lambda x: x.repeat(3, 1, 1))  if not(RGB_img)  else NoneTransform(), # in case the image has a single channel 
            transforms.Normalize( mu, std ) if cf.normalize_images else NoneTransform(),                                   
            ])    

ImageThinning, OverlayImage, and, PadImage are custom transforms.
You still need to code your customized transforms (if you can’t find one from PyTorch that works for you)… Here’s an example for the (custom) ImageThinning transform shown above.
class ImageThinning(object):
    """  Image input as PIL and output as PIL
        To be used as part of  torchvision.transforms
       Args: p, a threshold value to control image thinning        
    """
    def __init__(self, p = 0.2):
        self.p = p                  
        
    def __call__(self, image):
        image = image_thinning(image, self.p)         
        return image


The other approach (as Wesley mentioned) is to define a custom dataset 7 class and have train_data = datasets.MNIST... as the object of that class, and then, play with the noise or any other perturbations at the __getitem__  level.
Either ways, you’d have to get your hands dirty with coding. Good luck!