PythiloLesson 27 of 30 · progress kept in this browser

A transformer encoder

PyTorch ships the whole transformer block. nn.TransformerEncoderLayer is multi-head attention and a small MLP, each with a residual connection and layer norm; nn.TransformerEncoder stacks copies of it.

Attention itself has no idea of order. Shuffle the positions of the input and the output is shuffled the same way, nothing else changes:

import torch
from torch import nn

torch.manual_seed(0)
layer = nn.TransformerEncoderLayer(
    d_model=8, nhead=2, dim_feedforward=16,
    dropout=0.0, batch_first=True)
x = torch.randn(1, 4, 8)
perm = torch.tensor([2, 0, 3, 1])
a = layer(x)[:, perm]
b = layer(x[:, perm])
print(torch.allclose(a, b, atol=1e-5))

So "the cat chased the dog" and "the dog chased the cat" look alike. Order enters only through position embeddings: a learned vector per position, added to each token's embedding before the first layer.

Set dropout=0.0 for small experiments; the default of 0.1 adds noise that only pays off on large data.

Your task

Using the given order_data and train, write OrderClassifier(vocab, d, context): self.tokens = nn.Embedding(vocab, d), self.positions = nn.Embedding(context, d), self.encoder, an nn.TransformerEncoder of one nn.TransformerEncoderLayer(d, 2, 2 * d, dropout=0.0, batch_first=True), and self.head = nn.Linear(d, 2). forward(ids) embeds tokens plus positions, encodes, averages over positions and returns the head's two scores per sequence.

This lesson uses torch, which Python in this browser does not include. Read it here, and run and check it in the Pythilo app on iPhone or iPad.