Encoder Architecture › Complete Encoder Implementation

Michael BrenndoerferUpdated June 15, 20253 min read
Language AI HandbookAll chapters
Part 16 of 67Transformer Architectures
Chapter 111Encoder Architecture › Complete Encoder Implementation
Reading section 9 of 13 · Complete Encoder Implementation · 3 minSection 9 of 13 · 3 min

Book contents

Section 9 of 13 · 3 min read

Encoder Architecture › Complete Encoder ImplementationOne section · Sections in this chapter9 / 13 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Let's bring everything together into a complete, production-style encoder implementation:

In[37]:
Code
class BertEncoder:
    """
    Complete BERT-style encoder implementation.

    Includes embeddings, stacked encoder layers, and pooling.
    """

    def __init__(
        self,
        vocab_size=30522,
        max_position=512,
        n_layers=12,
        d_model=768,
        n_heads=12,
        d_ff=3072,
    ):
        self.d_model = d_model
        self.n_layers = n_layers

        # Embeddings
        self.token_embeddings = np.random.randn(vocab_size, d_model) * 0.02
        self.position_embeddings = np.random.randn(max_position, d_model) * 0.02
        self.segment_embeddings = np.random.randn(2, d_model) * 0.02
        self.embedding_norm = LayerNorm(d_model)

        # Encoder layers
        self.layers = [
            EncoderLayer(d_model, n_heads, d_ff) for _ in range(n_layers)
        ]

        # Final normalization
        self.final_norm = LayerNorm(d_model)

        # Pooler (for [CLS] representation)
        self.pooler_dense = np.random.randn(d_model, d_model) * 0.02

    def embed(self, token_ids, segment_ids=None):
        """
        Compute input embeddings.

        Args:
            token_ids: Array of token indices, shape (seq_len,)
            segment_ids: Optional segment indices for sentence pairs

        Returns:
            Embeddings of shape (seq_len, d_model)
        """
        seq_len = len(token_ids)

        # Token embeddings
        token_embeds = self.token_embeddings[token_ids]

        # Position embeddings
        positions = np.arange(seq_len)
        position_embeds = self.position_embeddings[positions]

        # Segment embeddings (default to segment 0)
        if segment_ids is None:
            segment_ids = np.zeros(seq_len, dtype=int)
        segment_embeds = self.segment_embeddings[segment_ids]

        # Sum and normalize
        embeddings = token_embeds + position_embeds + segment_embeds
        embeddings = self.embedding_norm(embeddings)

        return embeddings

    def __call__(self, token_ids, segment_ids=None, attention_mask=None):
        """
        Full forward pass.

        Args:
            token_ids: Token indices, shape (seq_len,)
            segment_ids: Segment indices for sentence pairs
            attention_mask: Padding mask (1 for real, 0 for padding)

        Returns:
            Dictionary with sequence_output and pooled_output
        """
        # Compute embeddings
        hidden_states = self.embed(token_ids, segment_ids)

        # Convert attention mask to additive format
        if attention_mask is not None:
            # attention_mask: 1 for real tokens, 0 for padding
            # Convert to: 0 for allowed, -inf for blocked
            extended_mask = (1.0 - attention_mask) * float("-inf")
            extended_mask = extended_mask[
                np.newaxis, np.newaxis, :
            ]  # Broadcast dims
        else:
            extended_mask = None

        # Pass through encoder layers
        for layer in self.layers:
            hidden_states, _ = layer(hidden_states)

        # Final normalization
        sequence_output = self.final_norm(hidden_states)

        # Pooled output (from [CLS] token with tanh activation)
        cls_output = sequence_output[0]
        pooled_output = np.tanh(cls_output @ self.pooler_dense)

        return {
            "last_hidden_state": sequence_output,
            "pooler_output": pooled_output,
        }


# Create a small encoder for demonstration
small_encoder = BertEncoder(
    vocab_size=1000,
    max_position=128,
    n_layers=4,
    d_model=256,
    n_heads=8,
    d_ff=1024,
)

# Process a sample sequence
sample_tokens = np.array([2, 105, 234, 567, 89, 3])  # [CLS], tokens..., [SEP]
output = small_encoder(sample_tokens)
Out[38]:
Console
Complete Encoder Forward Pass
--------------------------------------------------
Input sequence length: 6

Outputs:
  last_hidden_state shape: (6, 256)
  pooler_output shape: (256,)

[CLS] representation (pooler output):
  Norm: 4.6243
  Min: -0.8008
  Max: 0.7338
  (tanh activation bounds values to [-1, 1])