Hello,

I just wanted to mention that there are definitely instances when one would want to transform both feature and target variables.

To make this work you have to pass different transforms that is a transform for feature and transform for target. In this way each transform will store particular mean and std and don’t mess up with each other while calling transform function.
The code looks like this (This will give more clarity of what I am saying)
class CSVDataset(Dataset):
    # Load the dataset.
    def __init__(self, file_path, train, X_transform=None, y_transform=None):
        # Read the data into a dataframe.
        df = pd.read_csv(file_path)
        # Store the input & output variables.
        self.train_X = df.iloc[:, 1:-1].values.astype('float32')
        self.train_Y = df.iloc[:, -1].values.astype('float32')
        self.test_X = df.iloc[:, 1:-1].values.astype('float32')
        self.test_Y = np.empty(len(self.test_X))
        self.X_transform = X_transform
        self.y_transform = y_transform
        
        # fit on the training data
        self.X_transform.fit(train_X)
        self.y_transform.fit(train_Y)

        self.train = train

    def __getitem__(self, index):
        if self.train is True:
            X_data = self.train_X[index]
            Y_data = self.train_Y[index]
            if self.X_transform is not None:
                X_data = self.X_transform(X_data)
            if self.Y_transform is not None:
                Y_data = self.y_transform(Y_data)
            return X_data, Y_data
        else:
            X_data = self.test_X[index]
            if self.X_transform is not None:
                X_data = self.X_transform(X_data)
            return X_data

    def __len__(self):
        if self.train is True:
            return len(self.train_Y)
        else:
            return len(self.test_Y)

def train_val_dataset(dataset, val_split=0.2):
    train_idx, val_idx = train_test_split(list(range(len(dataset))), \
        test_size=val_split, shuffle=False, random_state=42)
    train_val_splits = {}
    train_val_splits['train'] = Subset(dataset, train_idx)
    train_val_splits['val'] = Subset(dataset, val_idx)
    return train_val_splits

def test_dataset(dataset):
    test_idx = list(range(len(dataset)))
    test_split = {}
    test_split['test'] = Subset(dataset, test_idx)
    return test_split


################################################################################################
class StandardScaler():
    """Standardize data by removing the mean and scaling to unit variance.
       This object can be used as a transform in PyTorch data loaders.

    Args:
        mean (FloatTensor): The mean value for each feature in the data.
        scale (FloatTensor): Per-feature relative scaling.
    """

    def __init__(self, mean=None, scale=None):
        if mean is not None:
            #mean = torch.FloatTensor(mean)
            mean = mean
        if scale is not None:
            scale = scale
            #scale = torch.FloatTensor(scale)
        self.mean_ = mean
        self.scale_ = scale

    def fit(self, sample):
        """Set the mean and scale values based on the sample data.
        """
        self.mean_ = sample.mean(axis=0, keepdims=True)
        self.scale_ = sample.std(axis=0, ddof=1, keepdims=True)
        return self

    def __call__(self, sample):
        return (sample - self.mean_)/self.scale_

    def inverse_transform(self, sample):
        """Scale the data back to the original sample space.
        """
        return sample * self.scale_ + self.mean_
################################################################################################

# Create transform function to pass into CSVDataset class.
X_transform = StandardScaler()
y_transform = StandardScaler()


# Test CSVDataset class definition & print train/test dataset sizes.
dataset = CSVDataset(file_path, train=True, X_transform=X_transform, y_transform=y_transform)
print(dataset.train_X)
print()

print(dataset.train_Y)
print()

print(dataset.test_X)
print()

# Print the length of the entire passed dataset.
print("Dataset Length:", len(dataset))
print()

# Split into train/validation sets & print respective lengths.
train_val_splits = train_val_dataset(dataset)
print("Train Set Length:", len(train_val_splits['train']))
print("Val Set Length:", len(train_val_splits['val']))
print()

# Pass train/validation splits into PyTorch DataLoader functions.
def cycle(iterable):
    while True:
        for x in iterable:
            yield x

train_loader = DataLoader(train_val_splits['train'], batch_size=8, shuffle=False, num_workers=0, pin_memory=True)
train_iter = iter(cycle(train_loader))

val_loader = DataLoader(train_val_splits['val'], batch_size=8, shuffle=False, num_workers=0, pin_memory=True)
val_iter = iter(cycle(val_loader))

# Acquire & print test batch of training/validation data.
dataiter = iter(train_loader)
train_batch = dataiter.next()
print(train_batch)
print()

dataiter2 = iter(val_loader)
val_batch = dataiter2.next()
print(val_batch)
print()