Skip to content

← Tokenization & Embeddings step 6 of 15

Medium Primitives

Tied Input/Output Embeddings

A token embedding table gives each vocabulary item a vector. A language model can reuse that same table to turn its final hidden states into a score for each vocabulary item. This sharing is called weight tying.

The score for a token is the dot product of its embedding vector and the hidden state. A larger score means a larger probability if softmax is applied later. This exercise returns the scores, called logits, without softmax.

Your task

Implement tied_lm_head(hidden, embedding_matrix):

  • hidden is a floating-point tensor with shape (..., d_model). It can be a single vector, a batch of vectors, or a batch of token sequences.
  • embedding_matrix is the shared table with shape (vocab_size, d_model).
  • Return hidden @ embedding_matrix.T, with shape (..., vocab_size).

Both inputs have the same floating-point dtype. Preserve all leading dimensions of hidden; only its last dimension changes. The table is shared across every batch and sequence position.

logits[..., v] = sum(hidden[..., d] * embedding_matrix[v, d] over d)

Do not add a bias, normalize the vectors, scale the dot products or apply softmax. The supplied values are ready to use. Logits may be negative and do not have to sum to one.

For example, with hidden=[2, -1] and table rows [1, 0], [0, 1] and [1, 1], return [2, -1, 1]. These are three scores for one hidden vector, so the output shape is (3,), not (1, 3).

What is shared?

An untied model has separate parameters for its input table and output weights. Tying them removes one independently stored matrix of vocab_size * d_model parameters. During training, both uses contribute gradients to the same table. This function implements the output projection only; model construction is responsible for passing the shared parameter rather than a separate copy. Weight tying is an architectural choice, not a requirement for language models.