LLaMA Components › Stacking Blocks into a Model

Michael BrenndoerferUpdated August 2, 20253 min read
Language AI HandbookAll chapters
Part 29 of 67Modern Decoder Models
Chapter 208LLaMA Components › Stacking Blocks into a Model
Reading section 7 of 12 · Stacking Blocks into a Model · 3 minSection 7 of 12 · 3 min

Book contents

Section 7 of 12 · 3 min read

LLaMA Components › Stacking Blocks into a ModelOne section · Sections in this chapter7 / 12 ↓
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

A complete LLaMA model stacks many blocks, adds embeddings at the input, and applies a final normalization before the output projection:

In[20]:
Code
class LLaMAModel:
    """
    Simplified LLaMA model for demonstration.

    Stacks transformer blocks with token embeddings and output projection.
    """

    def __init__(
        self, vocab_size, d_model, n_heads, d_ff, n_layers, rope_base=10000
    ):
        self.d_model = d_model

        # Token embeddings (no positional embeddings - RoPE handles position)
        self.token_embed = np.random.randn(vocab_size, d_model) * 0.02

        # Stack of transformer blocks
        self.blocks = [
            LLaMABlock(d_model, n_heads, d_ff, rope_base)
            for _ in range(n_layers)
        ]

        # Final normalization
        self.final_norm = RMSNorm(d_model)

        # Output projection (weight-tied with embedding in real LLaMA)
        self.output_proj = np.random.randn(d_model, vocab_size) * 0.02

    def __call__(self, token_ids):
        """
        Forward pass.

        Args:
            token_ids: Array of token IDs, shape (seq_len,)

        Returns:
            Logits of shape (seq_len, vocab_size)
        """
        seq_len = len(token_ids)

        # Token embeddings
        x = self.token_embed[token_ids]  # (seq_len, d_model)

        # Causal mask
        mask = np.tril(np.ones((seq_len, seq_len), dtype=bool))

        # Pass through all blocks
        for block in self.blocks:
            x = block(x, mask)

        # Final normalization and projection
        x = self.final_norm(x)
        logits = x @ self.output_proj

        return logits
In[21]:
Code
# Create a small model
model = LLaMAModel(
    vocab_size=1000,
    d_model=128,
    n_heads=4,
    d_ff=341,  # ~2.67 * 128
    n_layers=4,
)

# Sample input (random token IDs)
tokens = np.array([42, 123, 7, 891, 456, 0, 333, 222])
logits = model(tokens)
Out[22]:
Console
Model Configuration:
  Vocabulary size: 1000
  Model dimension: 128
  Attention heads: 4
  FFN dimension:   341
  Layers:          4

Input: 8 tokens
Output logits shape: (8, 1000)

Top 5 predictions for next token:
  1. Token 461: logit = 0.8190
  2. Token 569: logit = 0.6806
  3. Token 957: logit = 0.6565
  4. Token 736: logit = 0.6402
  5. Token 208: logit = 0.6200

This simplified model demonstrates the complete LLaMA architecture. The output logits have shape (8, 1000), meaning for each of the 8 input tokens, we get a probability distribution over the 1000-word vocabulary. The top predictions for the next token show varying logit values, which would become probabilities after applying softmax. Since the model uses random weights, these predictions are meaningless, but the structure shows how a trained model would generate text token by token.

Note the absence of learned position embeddings at the input, since RoPE encodes position directly in the attention mechanism. This is a key architectural difference from GPT-style models, where position embeddings are added to token embeddings at the input layer.