Bird
Raised Fist0
PyTorchml~20 mins

Train/val/test split in PyTorch - ML Experiment: Train & Evaluate

Choose your learning style10 modes available
Experiment - Train/val/test split
Problem:You have a dataset but currently you train your model on all data without splitting. This causes unreliable evaluation because the model is tested on data it has already seen.
Current Metrics:Training accuracy: 95%, Validation accuracy: N/A, Test accuracy: N/A
Issue:No validation or test split means no way to check if the model generalizes well to new data.
Your Task
Split the dataset into training, validation, and test sets with 70%, 15%, and 15% of the data respectively. Train the model on the training set, validate during training on the validation set, and finally evaluate on the test set. Report accuracy for all three sets.
Use PyTorch and its DataLoader and Dataset utilities.
Do not change the model architecture.
Use random splitting but ensure reproducibility with a fixed seed.
Hint 1
Hint 2
Hint 3
Hint 4
Solution
PyTorch
import torch
from torch import nn, optim
from torch.utils.data import DataLoader, random_split
from torchvision import datasets, transforms

# Fix random seed for reproducibility
torch.manual_seed(42)

# Define transform to normalize data
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])

# Load dataset (e.g., MNIST)
dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)

# Calculate lengths for splits
train_len = int(0.7 * len(dataset))
val_len = int(0.15 * len(dataset))
test_len = len(dataset) - train_len - val_len

# Split dataset
train_set, val_set, test_set = random_split(dataset, [train_len, val_len, test_len])

# Create DataLoaders
train_loader = DataLoader(train_set, batch_size=64, shuffle=True)
val_loader = DataLoader(val_set, batch_size=64, shuffle=False)
test_loader = DataLoader(test_set, batch_size=64, shuffle=False)

# Define simple model
class SimpleNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.linear = nn.Linear(28*28, 10)
    def forward(self, x):
        x = self.flatten(x)
        return self.linear(x)

model = SimpleNN()

# Loss and optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)

# Training function
def train_epoch(loader):
    model.train()
    total, correct = 0, 0
    for images, labels in loader:
        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
    return correct / total

# Validation function
def eval_model(loader):
    model.eval()
    total, correct = 0, 0
    with torch.no_grad():
        for images, labels in loader:
            outputs = model(images)
            _, predicted = torch.max(outputs, 1)
            total += labels.size(0)
            correct += (predicted == labels).sum().item()
    return correct / total

# Train for 5 epochs
for epoch in range(5):
    train_acc = train_epoch(train_loader)
    val_acc = eval_model(val_loader)
    print(f'Epoch {epoch+1}: Train Acc: {train_acc:.4f}, Val Acc: {val_acc:.4f}')

# Final test accuracy
test_acc = eval_model(test_loader)
print(f'Test Accuracy: {test_acc:.4f}')
Split the dataset into train (70%), validation (15%), and test (15%) sets using random_split.
Created separate DataLoaders for each split.
Added validation evaluation after each training epoch.
Evaluated the model on the test set after training.
Results Interpretation

Before splitting:
Training accuracy: 95%
Validation accuracy: N/A
Test accuracy: N/A

After splitting and training:
Training accuracy: ~85%
Validation accuracy: ~83%
Test accuracy: ~82%

Splitting data into train, validation, and test sets helps measure how well the model generalizes to new data. Validation accuracy guides training decisions, and test accuracy gives an unbiased final evaluation.
Bonus Experiment
Try using stratified splitting to keep class proportions balanced in train, val, and test sets.
💡 Hint
Use sklearn.model_selection.StratifiedShuffleSplit to create indices for splits, then create subsets accordingly.

Practice

(1/5)
1. What is the main purpose of splitting data into train, validation, and test sets in PyTorch?
easy
A. To train the model, tune hyperparameters, and evaluate performance separately
B. To increase the size of the dataset artificially
C. To reduce the number of features in the dataset
D. To convert data into tensors automatically

Solution

  1. Step 1: Understand the role of each data split

    The training set is used to teach the model, the validation set helps tune settings, and the test set checks how well the model works on new data.
  2. Step 2: Match purpose to options

    Only To train the model, tune hyperparameters, and evaluate performance separately correctly describes these roles. Other options describe unrelated tasks.
  3. Final Answer:

    To train the model, tune hyperparameters, and evaluate performance separately -> Option A
  4. Quick Check:

    Train/val/test split = separate training, tuning, testing [OK]
Hint: Remember: train teaches, val tunes, test checks [OK]
Common Mistakes:
  • Thinking splitting increases dataset size
  • Confusing splitting with feature selection
  • Assuming splitting converts data types
2. Which of the following is the correct way to split a PyTorch dataset into train and test sets using random_split?
easy
A. train_set, test_set = random_split(dataset, [80%, 20%])
B. train_set, test_set = random_split(dataset, [80, 20])
C. train_set, test_set = random_split(dataset, [0.8, 0.2])
D. train_set, test_set = random_split(dataset, [80])

Solution

  1. Step 1: Check the expected input for random_split

    random_split expects the dataset and a list of lengths (integers) for each split, not fractions or percentages.
  2. Step 2: Evaluate each option

    train_set, test_set = random_split(dataset, [80, 20]) uses integer lengths [80, 20], which is correct. train_set, test_set = random_split(dataset, [0.8, 0.2]) uses floats, train_set, test_set = random_split(dataset, [80%, 20%]) uses invalid syntax with %, and train_set, test_set = random_split(dataset, [80]) provides only one length.
  3. Final Answer:

    train_set, test_set = random_split(dataset, [80, 20]) -> Option B
  4. Quick Check:

    random_split needs integer lengths [OK]
Hint: Use integer lengths, not fractions, in random_split [OK]
Common Mistakes:
  • Passing fractions or percentages instead of integers
  • Providing only one length instead of two
  • Using invalid syntax like % in list
3. Given the code below, what will be the length of val_set?
from torch.utils.data import random_split

full_dataset = list(range(100))
train_size = 70
val_size = 20
test_size = 10
train_set, val_set, test_set = random_split(full_dataset, [train_size, val_size, test_size])
print(len(val_set))
medium
A. 10
B. 70
C. 20
D. 100

Solution

  1. Step 1: Understand random_split lengths

    The list [70, 20, 10] tells random_split to split the dataset into parts of those exact lengths.
  2. Step 2: Identify val_set length

    val_set corresponds to the second split with length 20, so len(val_set) will be 20.
  3. Final Answer:

    20 -> Option C
  4. Quick Check:

    val_size = 20 means val_set length = 20 [OK]
Hint: Lengths in random_split match output sizes exactly [OK]
Common Mistakes:
  • Confusing sizes with percentages
  • Assuming val_set length is sum of others
  • Forgetting order of splits in output
4. You wrote this code to split your dataset but get a ValueError: Sum of input lengths does not equal the length of the input dataset!. What is the error?
from torch.utils.data import random_split

dataset = list(range(50))
train_set, test_set = random_split(dataset, [30, 25])
medium
A. The sum of lengths 30 + 25 is greater than dataset length 50
B. random_split requires fractions, not lengths
C. dataset must be a PyTorch tensor, not a list
D. random_split cannot split into two parts

Solution

  1. Step 1: Check dataset length and split lengths

    Dataset length is 50. The sum of split lengths is 30 + 25 = 55, which is more than 50.
  2. Step 2: Understand random_split requirements

    random_split requires the sum of split lengths to exactly match dataset length.
  3. Final Answer:

    The sum of lengths 30 + 25 is greater than dataset length 50 -> Option A
  4. Quick Check:

    Sum of split lengths must equal dataset length [OK]
Hint: Sum of split lengths must equal dataset size exactly [OK]
Common Mistakes:
  • Passing split lengths that don't sum to dataset size
  • Thinking random_split accepts fractions
  • Assuming dataset must be tensor, not list
5. You want to split a PyTorch dataset of 1000 samples into 70% train, 15% validation, and 15% test sets. Which code correctly performs this split using random_split?
hard
A. train_set, val_set, test_set = random_split(dataset, [0.7, 0.15, 0.15])
B. train_set, val_set, test_set = random_split(dataset, [700, 150, 100])
C. train_set, val_set, test_set = random_split(dataset, [700, 150])
D. train_set, val_set, test_set = random_split(dataset, [700, 150, 150])

Solution

  1. Step 1: Calculate integer split sizes

    70% of 1000 is 700, 15% is 150, so splits are [700, 150, 150].
  2. Step 2: Check options for correctness

    train_set, val_set, test_set = random_split(dataset, [700, 150, 150]) uses correct integer lengths summing to 1000. train_set, val_set, test_set = random_split(dataset, [0.7, 0.15, 0.15]) uses floats (invalid), train_set, val_set, test_set = random_split(dataset, [700, 150]) misses one split, train_set, val_set, test_set = random_split(dataset, [700, 150, 100]) sums to 950 (incorrect).
  3. Final Answer:

    train_set, val_set, test_set = random_split(dataset, [700, 150, 150]) -> Option D
  4. Quick Check:

    Use integer lengths summing to dataset size [OK]
Hint: Convert percentages to integers summing to dataset size [OK]
Common Mistakes:
  • Passing fractions instead of integers
  • Not summing split sizes to dataset length
  • Missing one of the splits
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard