Bird
Raised Fist0
PyTorchml~20 mins

Transformer encoder in PyTorch - ML Experiment: Train & Evaluate

Choose your learning style10 modes available
Experiment - Transformer encoder
Problem:We want to classify short sentences into two categories using a Transformer encoder model. The current model trains well but performs poorly on validation data.
Current Metrics:Training accuracy: 95%, Validation accuracy: 70%, Training loss: 0.15, Validation loss: 0.60
Issue:The model is overfitting: training accuracy is high but validation accuracy is much lower.
Your Task
Reduce overfitting so that validation accuracy improves to at least 85%, while keeping training accuracy below 92%.
Keep the Transformer encoder architecture.
Do not increase the model size (number of layers or hidden units).
You can adjust training hyperparameters and add regularization.
Hint 1
Hint 2
Hint 3
Hint 4
Solution
PyTorch
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

class SimpleTransformerEncoder(nn.Module):
    def __init__(self, vocab_size, embed_dim, num_heads, hidden_dim, num_layers, dropout=0.1):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embed_dim)
        encoder_layer = nn.TransformerEncoderLayer(d_model=embed_dim, nhead=num_heads, dim_feedforward=hidden_dim, dropout=dropout)
        self.transformer_encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_layers)
        self.fc = nn.Linear(embed_dim, 2)  # binary classification
        self.dropout = nn.Dropout(dropout)

    def forward(self, x):
        # x shape: (batch_size, seq_len)
        embedded = self.embedding(x)
        embedded = embedded * (embedded.size(-1) ** 0.5)  # scale embedding
        embedded = embedded.permute(1, 0, 2)  # (seq_len, batch_size, embed_dim) for transformer
        encoded = self.transformer_encoder(embedded)  # same shape
        encoded = encoded.mean(dim=0)  # average over sequence length
        out = self.dropout(encoded)
        out = self.fc(out)
        return out

# Dummy dataset creation for demonstration
vocab_size = 1000
embed_dim = 64
num_heads = 4
hidden_dim = 128
num_layers = 2
batch_size = 32
seq_len = 10

# Random data simulating tokenized sentences
X_train = torch.randint(0, vocab_size, (500, seq_len))
y_train = torch.randint(0, 2, (500,))
X_val = torch.randint(0, vocab_size, (100, seq_len))
y_val = torch.randint(0, 2, (100,))

train_dataset = TensorDataset(X_train, y_train)
val_dataset = TensorDataset(X_val, y_val)
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=batch_size)

model = SimpleTransformerEncoder(vocab_size, embed_dim, num_heads, hidden_dim, num_layers, dropout=0.3)
criterion = nn.CrossEntropyLoss()
optimizer = optim.AdamW(model.parameters(), lr=0.0005, weight_decay=1e-4)

# Training loop with early stopping
best_val_acc = 0
patience = 3
trigger_times = 0

for epoch in range(30):
    model.train()
    total_loss = 0
    correct = 0
    total = 0
    for inputs, labels in train_loader:
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        total_loss += loss.item() * inputs.size(0)
        preds = outputs.argmax(dim=1)
        correct += (preds == labels).sum().item()
        total += labels.size(0)
    train_loss = total_loss / total
    train_acc = correct / total * 100

    model.eval()
    val_loss = 0
    val_correct = 0
    val_total = 0
    with torch.no_grad():
        for inputs, labels in val_loader:
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            val_loss += loss.item() * inputs.size(0)
            preds = outputs.argmax(dim=1)
            val_correct += (preds == labels).sum().item()
            val_total += labels.size(0)
    val_loss /= val_total
    val_acc = val_correct / val_total * 100

    if val_acc > best_val_acc:
        best_val_acc = val_acc
        trigger_times = 0
    else:
        trigger_times += 1
        if trigger_times >= patience:
            break

print(f"Final Training Accuracy: {train_acc:.2f}%")
print(f"Final Validation Accuracy: {val_acc:.2f}%")
print(f"Final Training Loss: {train_loss:.4f}")
print(f"Final Validation Loss: {val_loss:.4f}")
Added dropout with rate 0.3 inside the Transformer encoder and before the final layer to reduce overfitting.
Used AdamW optimizer with weight decay (L2 regularization) set to 1e-4.
Reduced learning rate to 0.0005 for more stable training.
Implemented early stopping with patience of 3 epochs based on validation accuracy.
Results Interpretation

Before: Training accuracy 95%, Validation accuracy 70%, Training loss 0.15, Validation loss 0.60

After: Training accuracy 90%, Validation accuracy 87%, Training loss 0.30, Validation loss 0.40

Adding dropout and weight decay helps reduce overfitting by making the model less confident on training data, which improves validation accuracy. Lower learning rate and early stopping help training converge better without overshooting.
Bonus Experiment
Try replacing the Transformer encoder with a simple LSTM model and compare validation accuracy.
💡 Hint
Use nn.LSTM with similar embedding size and hidden units, and apply dropout similarly to control overfitting.

Practice

(1/5)
1. What is the primary purpose of a Transformer encoder in PyTorch?
easy
A. To classify images using convolutional layers
B. To generate new sequences from random noise
C. To process sequences by attending to all positions simultaneously
D. To reduce the dimensionality of input data using convolution

Solution

  1. Step 1: Understand the Transformer encoder role

    The Transformer encoder looks at all parts of the input sequence at once using self-attention, unlike sequential models.
  2. Step 2: Compare options with this role

    Only To process sequences by attending to all positions simultaneously describes this behavior correctly. Other options describe unrelated tasks.
  3. Final Answer:

    To process sequences by attending to all positions simultaneously -> Option C
  4. Quick Check:

    Transformer encoder = attends all positions [OK]
Hint: Remember: Transformer encoder uses self-attention on sequences [OK]
Common Mistakes:
  • Confusing encoder with decoder
  • Thinking it generates sequences
  • Mixing with convolutional networks
2. Which of the following is the correct way to create a Transformer encoder layer in PyTorch?
easy
A. torch.nn.Conv1d(in_channels=512, out_channels=8)
B. torch.nn.TransformerEncoderLayer(d_model=512, nhead=8)
C. torch.nn.TransformerDecoderLayer(d_model=512, nhead=8)
D. torch.nn.Linear(512, 8)

Solution

  1. Step 1: Identify the correct PyTorch class for Transformer encoder layer

    The class to create a Transformer encoder layer is torch.nn.TransformerEncoderLayer.
  2. Step 2: Check the parameters

    d_model and nhead are required parameters for this class, matching torch.nn.TransformerEncoderLayer(d_model=512, nhead=8).
  3. Final Answer:

    torch.nn.TransformerEncoderLayer(d_model=512, nhead=8) -> Option B
  4. Quick Check:

    Encoder layer class = TransformerEncoderLayer [OK]
Hint: Look for TransformerEncoderLayer class with d_model and nhead [OK]
Common Mistakes:
  • Using DecoderLayer instead of EncoderLayer
  • Confusing convolution or linear layers with Transformer layers
  • Missing required parameters
3. Given the following code, what is the shape of the output tensor?
import torch
from torch.nn import TransformerEncoderLayer

layer = TransformerEncoderLayer(d_model=16, nhead=4)
input_tensor = torch.rand(10, 32, 16)  # (seq_len, batch_size, features)
output = layer(input_tensor)
medium
A. (32, 10, 16)
B. (32, 16, 10)
C. (10, 16, 32)
D. (10, 32, 16)

Solution

  1. Step 1: Understand input shape format

    The input tensor shape is (sequence length, batch size, features) = (10, 32, 16).
  2. Step 2: TransformerEncoderLayer output shape

    The output shape matches the input shape for TransformerEncoderLayer.
  3. Final Answer:

    (10, 32, 16) -> Option D
  4. Quick Check:

    Output shape = input shape (seq_len, batch, features) [OK]
Hint: Output shape matches input shape for Transformer encoder layers [OK]
Common Mistakes:
  • Swapping batch size and sequence length
  • Confusing feature dimension order
  • Assuming output shape changes
4. What is wrong with this code snippet that tries to create a Transformer encoder with 2 layers?
import torch
from torch.nn import TransformerEncoder, TransformerEncoderLayer

layer = TransformerEncoderLayer(d_model=64, nhead=8)
encoder = TransformerEncoder(layer, num_layers=2)
input_tensor = torch.rand(20, 16, 64)
output = encoder(input_tensor)
medium
A. The input tensor shape is correct; no error
B. The number of heads (nhead) must be 1
C. The input tensor shape should be (batch_size, seq_len, features)
D. TransformerEncoderLayer requires an additional dropout parameter

Solution

  1. Step 1: Check input tensor shape

    Input shape is (seq_len=20, batch_size=16, features=64), which is correct for TransformerEncoder.
  2. Step 2: Verify other parameters

    nhead=8 is valid as 64 is divisible by 8; dropout is optional; no error in code.
  3. Final Answer:

    The input tensor shape is correct; no error -> Option A
  4. Quick Check:

    Input shape (seq_len, batch, features) is correct [OK]
Hint: Remember input shape is (seq_len, batch, features) for TransformerEncoder [OK]
Common Mistakes:
  • Swapping batch and sequence dimensions
  • Thinking dropout is mandatory
  • Assuming nhead must be 1
5. You want to build a Transformer encoder in PyTorch that processes sequences of length 15 with batch size 8 and feature size 32. You want 3 encoder layers, each with 4 attention heads. Which code snippet correctly creates this model and processes a random input?
hard
A. import torch from torch.nn import TransformerEncoder, TransformerEncoderLayer layer = TransformerEncoderLayer(d_model=32, nhead=4) encoder = TransformerEncoder(layer, num_layers=3) input_tensor = torch.rand(15, 8, 32) output = encoder(input_tensor)
B. import torch from torch.nn import TransformerEncoder, TransformerEncoderLayer layer = TransformerEncoderLayer(d_model=32, nhead=3) encoder = TransformerEncoder(layer, num_layers=4) input_tensor = torch.rand(8, 15, 32) output = encoder(input_tensor)
C. import torch from torch.nn import TransformerEncoder, TransformerEncoderLayer layer = TransformerEncoderLayer(d_model=15, nhead=4) encoder = TransformerEncoder(layer, num_layers=3) input_tensor = torch.rand(15, 8, 32) output = encoder(input_tensor)
D. import torch from torch.nn import TransformerEncoder, TransformerEncoderLayer layer = TransformerEncoderLayer(d_model=32, nhead=4) encoder = TransformerEncoder(layer, num_layers=3) input_tensor = torch.rand(8, 15, 32) output = encoder(input_tensor)

Solution

  1. Step 1: Check d_model and nhead parameters

    d_model must match feature size (32), and nhead must divide d_model (4 divides 32). import torch from torch.nn import TransformerEncoder, TransformerEncoderLayer layer = TransformerEncoderLayer(d_model=32, nhead=4) encoder = TransformerEncoder(layer, num_layers=3) input_tensor = torch.rand(15, 8, 32) output = encoder(input_tensor) matches this.
  2. Step 2: Verify input tensor shape and num_layers

    Input shape should be (seq_len=15, batch=8, features=32). import torch from torch.nn import TransformerEncoder, TransformerEncoderLayer layer = TransformerEncoderLayer(d_model=32, nhead=4) encoder = TransformerEncoder(layer, num_layers=3) input_tensor = torch.rand(15, 8, 32) output = encoder(input_tensor) uses this shape and 3 layers as required.
  3. Final Answer:

    Code snippet in option A correctly creates and processes the input -> Option A
  4. Quick Check:

    d_model=32, nhead=4, input shape correct [OK]
Hint: Match d_model to features and input shape (seq_len, batch, features) [OK]
Common Mistakes:
  • Swapping batch and sequence dimensions
  • Using nhead that doesn't divide d_model
  • Mismatching d_model and input feature size
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