Skip to content
AILinkDeepTech
Go back
Reinforcement Learning Medium

Llama Architecture: RMSNorm, SwiGLU, RoPE, GQA, and PyTorch Implementation

Abstract

Master Llama architecture: RMSNorm pre-normalization, SwiGLU activations, RoPE relative embeddings, Grouped-Query Attention (GQA), and PyTorch pipelines.

Evolution of Open-Weight Decoder-Only Language Models

Modern autoregressive language modeling builds upon the decoder-only Transformer topology. Early foundation models (e.g., GPT-3, PaLM, Chinchilla) established key scaling laws relating parameter count and training tokens . However, initial implementations relied on post-LayerNorm, standard Multi-Head Attention (MHA), ReLU/GeLU activations, and absolute positional embeddings.

Llama (Touvron et al., Meta AI, 2023–2024) redefined open-weight architecture by introducing four synergistic hardware- and compute-efficient design choices:

  1. Pre-Normalization with RMSNorm: Replaces standard LayerNorm by eliminating mean-centering, reducing memory access overhead while maintaining training stability.
  2. SwiGLU Feed-Forward Networks: Employs gated linear activations with non-linearities, providing higher expressivity per parameter.
  3. Rotary Position Embeddings (RoPE): Replaces absolute position vectors with complex coordinate rotations, naturally encoding relative token distances and enabling zero-shot context length extrapolation.
  4. Grouped-Query Attention (GQA): Shares key-value projection heads across multiple query heads, cutting KV-cache memory consumption by during long-context autoregressive decoding.

Architectural Comparison

Architectural DimensionVanilla Transformer (Vaswani et al.)GPT-3 (Brown et al.)Llama 1 (Touvron et al.)Llama 2 (Touvron et al.)Llama 3 / 3.1 (Dubey et al.)
Normalization LayerPost-LayerNormPre-LayerNormPre-RMSNormPre-RMSNormPre-RMSNorm
FFN Activation
Positional EncodingSinusoidal 1D AbsoluteLearned 1D AbsoluteRotary ()Rotary ()Rotary ()
Attention MechanismMulti-Head (MHA)Multi-Head (MHA)Multi-Head (MHA)GQA ()Universal GQA ()
Bias TermsAll Linear LayersAll Linear LayersNo BiasNo BiasNo Bias
Context Window
Vocabulary Size
Pretraining Budget

Mathematical Foundations

flowchart TD INPUT["Token IDs x in {0, ..., V-1}^T"] --> EMBED["Token Embedding Layer E in R^(V x d)"] EMBED --> RESIDUAL_INIT["Hidden State h_0 = E[x] in R^(T x d)"] RESIDUAL_INIT --> NORM1["RMSNorm(h_l-1)"] NORM1 --> ATTN["Grouped-Query Attention (GQA)\nwith Rotary Position Embeddings (RoPE)"] ATTN --> ADD1["Residual Addition: h'_l = h_l-1 + GQA(RMSNorm(h_l-1))"] ADD1 --> NORM2["RMSNorm(h'_l)"] NORM2 --> SWIGLU["SwiGLU Feed-Forward Network\n(W_down * (SiLU(W_gate * x) . (W_up * x)))"] SWIGLU --> ADD2["Residual Addition: h_l = h'_l + FFN(RMSNorm(h'_l))"] ADD2 --> STACK["Stack of L Decoder Layers"] STACK --> FINAL_NORM["Final RMSNorm(h_L)"] FINAL_NORM --> HEAD["Language Modeling Head W_unembed in R^(d x V)"] HEAD --> LOGITS["Next-Token Logits z in R^(T x V)"]

Figure 1: Llama decoder-only Transformer block topology featuring pre-RMSNorm, RoPE-conditioned GQA, and SwiGLU FFN.

1. Root Mean Square Normalization (RMSNorm)

Standard LayerNorm centers input activations by subtracting the mean before scaling by variance :

RMSNorm (Zhang & Sennrich, 2019) hypothesizes that the scaling invariance of LayerNorm is the primary stabilizing factor, rendering mean-centering redundant. For activation vector :

where is a learnable gain parameter and prevents division by zero. Eliminating mean calculation reduces GPU global memory synchronization steps and saves kernel latency under half-precision (bfloat16) execution.


2. SwiGLU Gated Feed-Forward Networks

Standard Transformer Multi-Layer Perceptrons compute:

Llama replaces standard activations with SwiGLU (Shazeer, 2020), utilizing three weight matrices without bias terms:

where , , and .

To maintain parameter parity with a standard FFN expansion ratio, the intermediate dimension is set to:

For Llama 3 8B (), .


3. Rotary Position Embeddings (RoPE)

RoPE (Su et al., 2021) injects positional information by rotating query and key vectors in complex 2D vector subspaces.

For a 2D vector coordinate pair at sequence position , the rotation matrix is defined as:

The full block-diagonal transformation acts on query and key :

Relative Coordinate Invariance Property:

Evaluating the attention dot-product:

The inner product is strictly a function of the relative distance , preserving orthogonal norm invariance . In Llama 3.1, was scaled from to , pushing maximum wavelength limits to support context windows without frequency collision.


4. Grouped-Query Attention (GQA) and KV Cache Scaling

In standard Multi-Head Attention (MHA), the number of query heads equals the number of key/value heads (). During autoregressive generation, storing past keys and values requires significant GPU VRAM:

Grouped-Query Attention (Ainslie et al., 2023) groups query heads into shared key-value groups ( queries per KV head).

Before computing attention, and are repeated times along the head dimension:

KV Cache Memory Reduction:

For Llama 3 8B (), memory footprint drops by . For 70B (), memory consumption drops by , enabling sequences on single-GPU instances.


Production PyTorch Implementation

Below is a complete, modular PyTorch implementation of the RMSNorm, SwiGLU FFN, RoPE Embedding Generator, GroupedQueryAttention, and complete LlamaTransformerBlock.

Step 1: Core Modular Layers

from __future__ import annotations

import math
import torch
import torch.nn as nn
import torch.nn.functional as F


class RMSNorm(nn.Module):
    """Root Mean Square Layer Normalization."""

    def __init__(self, dim: int, eps: float = 1e-5) -> None:
        super().__init__()
        self.eps = eps
        self.weight = nn.Parameter(torch.ones(dim))

    def _norm(self, x: torch.Tensor) -> torch.Tensor:
        return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self._norm(x.float()).type_as(x) * self.weight


class SwiGLUFFN(nn.Module):
    """SwiGLU Feed-Forward Network: down_proj( SiLU(gate_proj(x)) * up_proj(x) )."""

    def __init__(self, dim: int, hidden_dim: int) -> None:
        super().__init__()
        self.gate_proj = nn.Linear(dim, hidden_dim, bias=False)
        self.up_proj = nn.Linear(dim, hidden_dim, bias=False)
        self.down_proj = nn.Linear(hidden_dim, dim, bias=False)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))


def precompute_rope_freqs_cis(dim: int, end: int, theta: float = 500000.0) -> torch.Tensor:
    """Precompute complex frequencies for Rotary Position Embeddings."""
    freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
    t = torch.arange(end, device=freqs.device, dtype=torch.float32)
    freqs = torch.outer(t, freqs)
    freqs_cis = torch.polar(torch.ones_like(freqs), freqs)  # complex64 [end, dim // 2]
    return freqs_cis


def apply_rotary_emb(xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
    """Apply RoPE rotation in complex space."""
    xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2))
    xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))
    
    freqs_cis = freqs_cis[None, None, :xq.shape[2], :]
    xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3)
    xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)
    return xq_out.type_as(xq), xk_out.type_as(xk)

Step 2: Grouped-Query Attention & Transformer Block

from __future__ import annotations

import torch
import torch.nn as nn
import torch.nn.functional as F
from llama_layers import RMSNorm, SwiGLUFFN, apply_rotary_emb


class GroupedQueryAttention(nn.Module):
    """Grouped-Query Attention (GQA) module with RoPE integration."""

    def __init__(
        self,
        dim: int,
        num_heads: int = 32,
        num_kv_heads: int = 8,
        max_seq_len: int = 131072,
    ) -> None:
        super().__init__()
        self.num_heads = num_heads
        self.num_kv_heads = num_kv_heads
        self.head_dim = dim // num_heads
        self.num_queries_per_kv = num_heads // num_kv_heads

        self.q_proj = nn.Linear(dim, num_heads * self.head_dim, bias=False)
        self.k_proj = nn.Linear(dim, num_kv_heads * self.head_dim, bias=False)
        self.v_proj = nn.Linear(dim, num_kv_heads * self.head_dim, bias=False)
        self.o_proj = nn.Linear(num_heads * self.head_dim, dim, bias=False)

    def forward(
        self,
        x: torch.Tensor,
        freqs_cis: torch.Tensor,
        mask: torch.Tensor | None = None,
    ) -> torch.Tensor:
        b, seq_len, _ = x.shape

        # Linear projections
        xq = self.q_proj(x).view(b, seq_len, self.num_heads, self.head_dim).transpose(1, 2)
        xk = self.k_proj(x).view(b, seq_len, self.num_kv_heads, self.head_dim).transpose(1, 2)
        xv = self.v_proj(x).view(b, seq_len, self.num_kv_heads, self.head_dim).transpose(1, 2)

        # Apply RoPE
        xq, xk = apply_rotary_emb(xq, xk, freqs_cis=freqs_cis)

        # GQA Repeat Interleave: [B, num_kv_heads, T, d_k] -> [B, num_heads, T, d_k]
        xk = xk.repeat_interleave(self.num_queries_per_kv, dim=1)
        xv = xv.repeat_interleave(self.num_queries_per_kv, dim=1)

        # Scaled Dot-Product Flash Attention
        output = F.scaled_dot_product_attention(
            xq, xk, xv, attn_mask=mask, is_causal=(mask is None and seq_len > 1)
        )

        output = output.transpose(1, 2).contiguous().view(b, seq_len, -1)
        return self.o_proj(output)


class LlamaTransformerBlock(nn.Module):
    """Complete Pre-RMSNorm Llama Decoder Block."""

    def __init__(
        self,
        dim: int = 4096,
        hidden_dim: int = 14336,
        num_heads: int = 32,
        num_kv_heads: int = 8,
        eps: float = 1e-5,
    ) -> None:
        super().__init__()
        self.attention_norm = RMSNorm(dim, eps=eps)
        self.attention = GroupedQueryAttention(dim, num_heads=num_heads, num_kv_heads=num_kv_heads)
        self.ffn_norm = RMSNorm(dim, eps=eps)
        self.feed_forward = SwiGLUFFN(dim, hidden_dim=hidden_dim)

    def forward(
        self,
        x: torch.Tensor,
        freqs_cis: torch.Tensor,
        mask: torch.Tensor | None = None,
    ) -> torch.Tensor:
        h = x + self.attention(self.attention_norm(x), freqs_cis, mask=mask)
        out = h + self.feed_forward(self.ffn_norm(h))
        return out

Step 3: Production PEFT QLoRA Fine-Tuning Setup

from __future__ import annotations

import torch
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig


def setup_llama_qlora(model_id: str = "meta-llama/Meta-Llama-3.1-8B-Instruct") -> tuple[nn.Module, AutoTokenizer]:
    # 1. 4-bit NormalFloat Quantization Configuration
    bnb_config = BitsAndBytesConfig(
        load_in_4bit=True,
        bnb_4bit_quant_type="nf4",
        bnb_4bit_compute_dtype=torch.bfloat16,
        bnb_4bit_use_double_quant=True,
    )

    # 2. Load Model & Tokenizer
    tokenizer = AutoTokenizer.from_pretrained(model_id)
    tokenizer.pad_token = tokenizer.eos_token

    model = AutoModelForCausalLM.from_pretrained(
        model_id,
        quantization_config=bnb_config,
        device_map="auto",
        attn_implementation="flash_attention_2",
    )
    model = prepare_model_for_kbit_training(model)

    # 3. Target All Linear Projections
    peft_config = LoraConfig(
        r=16,
        lora_alpha=32,
        target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
        lora_dropout=0.05,
        bias="none",
        task_type="CAUSAL_LM",
    )

    peft_model = get_peft_model(model, peft_config)
    peft_model.print_trainable_parameters()
    return peft_model, tokenizer

Empirical Benchmark Evaluation

Quantitative evaluation comparing model parameters, pretraining token count, and performance across standard language benchmarks:

Model ArchitectureParametersTraining TokensMMLU (5-shot )GSM8K (8-shot )HumanEval (0-shot )MATH (4-shot )
Llama 1 (7B)
Llama 1 (65B)
Llama 2 (7B)
Llama 2 (70B)
Llama 3 (8B)
Llama 3 (70B)
Llama 3.1 (8B-Instruct)
Llama 3.1 (70B-Instruct)
Llama 3.1 (405B-Instruct)

Troubleshooting Common Deployment Faults

1. Numerical Overflow & NaN Gradients in FP16

  • Symptom: Training loss immediately diverges or evaluates to NaN within the first 100 steps under standard FP16.
  • Root Cause: RoPE frequency rotations and large intermediate activation scales in deep layers exceed FP16 maximum dynamic range ().
  • Remedy: Enforce strict torch.bfloat16 precision across training and inference.

2. End-of-Sequence Leaking & Run-On Generation

  • Symptom: Model ignores conversation completion and continues generating repetitive text.
  • Root Cause: Tokenizer EOS mismatch; Llama 3 defines <|eot_id|> (ID: 128009) as the conversational turn termination token, distinct from <|end_of_text|> (ID: 128001).
  • Remedy: Explicitly configure eos_token_id=[128001, 128009] during model.generate().

3. VRAM OOM During Long-Context Inference ()

  • Symptom: Out-of-memory errors occur despite static model weights fitting into GPU memory.
  • Root Cause: KV-cache allocation scales linearly with context length ; naive contiguous preallocation fragments memory.
  • Remedy: Deploy through vLLM utilizing PagedAttention, enable 8-bit KV-cache quantization (--kv-cache-dtype fp8), or set --max-model-len 32768 to constrain maximum allocated page buffers.

References

  1. Touvron, H., et al. (2023). LLaMA: Open and Efficient Foundation Language Models. arXiv:2302.13971.
  2. Touvron, H., et al. (2023). Llama 2: Open Foundation and Fine-Tuned Chat Models. arXiv:2307.09288.
  3. Dubey, A., et al. (2024). The Llama 3 Herd of Models. arXiv:2407.21783.
  4. Su, J., et al. (2021). RoFormer: Enhanced Transformer with Rotary Position Embedding. arXiv:2104.09864.
  5. Shazeer, N. (2020). GLU Variants Improve Transformer. arXiv:2002.05202.
  6. Ainslie, J., et al. (2023). GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. EMNLP 2023.


Cite this Explanation

@article{ailinkdeeptech2025llama,
  title={Llama Architecture: RMSNorm, SwiGLU, RoPE, GQA, and PyTorch Implementation},
  author={AILinkDeepTech},
  journal={AILinkDeepTech Algorithm Explanations},
  year={2025},
  url={https://ailinkdeeptech.com/research/llama}
}

Related Explanations