# Architecture & System Design: Apex-64M Small Language Model (SLM) Comprehensive technical documentation of the **63.8M Parameter Apex Small Language Model**, covering model architecture, pre-training token pipelines, Supervised Fine-Tuning (SFT) alignment, multi-turn memory inference, and guardrail subsystems. --- ## Table of Contents 1. [Overview & High-Level Philosophy](#1-overview--high-level-philosophy) 2. [Model Architecture Specification](#2-model-architecture-specification) 3. [Pre-Training Pipeline (Foundation Model)](#3-pre-training-pipeline-foundation-model) 4. [Supervised Fine-Tuning (SFT) Alignment](#4-supervised-fine-tuning-sft-alignment) 5. [Inference Engine & Multi-Turn Chat Memory](#5-inference-engine--multi-turn-chat-memory) 6. [Dual-Layer Safety Guardrail Subsystem](#6-dual-layer-safety-guardrail-subsystem) 7. [Parameter Accounting & Memory Footprint](#7-parameter-accounting--memory-footprint) --- ## 1. Overview & High-Level Philosophy The objective of this project is to build an end-to-end generative AI assistant from scratch: * **Zero pre-trained weight dependencies** during pre-training (trained from random weight initialization N(0, 0.02)). * Optimized parameter scale (**63.82M parameters**) capable of training on consumer/free cloud hardware (Tesla T4 GPU) while running blazingly fast on standard laptop CPUs (<300 MB RAM). * Complete 2-stage lifecycle: **Unsupervised Pre-Training** (C4 English corpus -> Base Model) followed by **Supervised Fine-Tuning** (Databricks Dolly 15k -> Chat Assistant). ``` +-----------------------------------------------------------------------------------+ | FULL SYSTEM PIPELINE | +-----------------------------------------------------------------------------------+ | | | [C4 English Dataset] | | | | | v (tiktoken GPT-2 Tokenization & Continuous Packing) | | [Packed Memmap Cache (train.bin)] | | | | | v (Stage 1: Pre-Training ~60,000 steps, Cosine LR, FP16 AMP) | | [Apex-64M Base Foundation Model: best_model.pt (~63.8M Params)] | | | | | v (Stage 2: SFT Alignment on Dolly 15k, Prompt Masking, 1-Token Shift) | | [Apex-64M Chat Assistant: sft_model.pt] | | | | | v (Inference Layer: Top-P, Repetition Penalty, Chat Memory) | | [Safety Layer: Toxic-BERT + Keyword Filtering] | | | | | v | | [End-User Multi-Turn Chat / Gradio Web UI] | +-----------------------------------------------------------------------------------+ ``` --- ## 2. Model Architecture Specification The model is a **Decoder-Only Pre-LayerNorm Transformer** built in pure PyTorch with fused attention kernels. ``` +------------------------+ | Input Token IDs (x) | +------------------------+ | +-------------------+-------------------+ | | v v +--------------------+ +--------------------+ | Token Embed (wte) | | Pos Embed (wpe) | | [50257, 512] | | [512, 512] | +--------------------+ +--------------------+ | | +-------------------+-------------------+ | v +--------------------+ | Dropout (p=0.1) | +--------------------+ | v +============================================+ | Transformer Block (x 12 Layers) | | | | +------------------------------------+ | | | LayerNorm (ln_1) | | | +------------------------------------+ | | | | | v | | +------------------------------------+ | | | Causal Multi-Head Self-Attention | | | | (8 Heads, d_k=64, FlashAttention) | | | +------------------------------------+ | | | | | v | | [ + Residual Add ] | | | | | v | | +------------------------------------+ | | | LayerNorm (ln_2) | | | +------------------------------------+ | | | | | v | | +------------------------------------+ | | | MLP (Linear 512 -> 2048 -> 512) | | | | Activation: New-GELU Approximation| | | +------------------------------------+ | | | | | v | | [ + Residual Add ] | +============================================+ | v +--------------------+ | Final LayerNorm | | (ln_f) | +--------------------+ | v +--------------------+ | LM Output Head | | (Tied Weights wte) | +--------------------+ | v +--------------------+ | Logits [B, T, V] | +--------------------+ ``` ### Key Architectural Choices: 1. **Pre-Layer Normalization (Pre-LN):** LayerNorm is applied *before* the Multi-Head Attention and MLP sub-layers (rather than Post-LN as in original GPT). This provides stable gradient flow and eliminates warmup instability. 2. **PyTorch Fused Flash Attention (`F.scaled_dot_product_attention`):** Uses FlashAttention CUDA kernels when running on GPU, cutting memory complexity from O(N^2) to O(N) and boosting speed by 3x. 3. **Weight Tying (Weight Sharing):** The output projection matrix `lm_head.weight` is tied directly to `wte.weight` (50,257 x 512). This saves **25.73 Million parameters** (~40% of the total model parameter budget) while improving semantic convergence. 4. **New-GELU Activation:** Uses the accurate Gaussian Error Linear Unit approximation inside the feed-forward network. --- ## 3. Pre-Training Pipeline (Foundation Model) ### Tokenization & Data Packing: * **Tokenizer:** OpenAI `tiktoken` BPE tokenizer (`gpt2` / `r50k_base`) with vocabulary size 50,257. * **Continuous Token Packing:** Documents from C4 English are streamed, tokenized, and concatenated with the `<|endoftext|>` (50,256) separator into continuous `uint16` memory-mapped arrays (`train.bin`, `val.bin`). * **Zero Padding Waste:** In pre-training, sequences are sliced into exact 512-token chunks with zero padding tokens. ### Target Alignment: In `dataset.py`: $$\mathbf{x} = \text{chunk}[0 : T-1], \quad \mathbf{y} = \text{chunk}[1 : T]$$ Position $t$ predicts token $t+1$. ### Pre-Training Hyperparameters: * **Target Token Budget:** ~1.28 Billion tokens * **Effective Batch Size:** 32 (8 micro-batch size x 4 gradient accumulation steps) * **Optimizer:** AdamW (`beta1 = 0.9`, `beta2 = 0.95`, `weight_decay = 0.01`) * **Precision:** FP16 Automatic Mixed Precision (`torch.autocast`) with `GradScaler` * **Learning Rate Schedule:** Cosine decay from `6e-4` to `6e-5` across 60,000 steps. * **Final Pre-Training Loss:** **`~4.02`** (Validation Perplexity ≈ 55.7). --- ## 4. Supervised Fine-Tuning (SFT) Alignment To transform the raw completion model into an instructional chat assistant, the model is fine-tuned on **Databricks Dolly 15k** (15,011 human-written instruction pairs). ### Prompt Formatting Template: ```text ### Instruction: {instruction} ### Context: {optional context} ### Response: {assistant response}<|endoftext|> ``` ### SFT Loss Masking (Prompt Masking): Standard causal language modeling calculates loss on the entire sequence. However, calculating loss on the user prompt teaches the model to memorize user questions rather than learning how to respond. We apply **selective loss masking** with `ignore_index = -1`: $$\mathbf{y}_{\text{target}}[t] = \begin{cases} -1 & \text{if } t \text{ is in Prompt} \\ \text{token ID} & \text{if } t \text{ is in Response} \\ -1 & \text{if } t \text{ is in Padding} \end{cases}$$ $$\mathcal{L} = -\frac{1}{N_{\text{resp}}} \sum_{t \in \text{Response}} \log P(y_t \mid x_{\le t})$$ ### The 1-Token Autoregressive Shift: To maintain autoregressive causal next-token alignment: $$\mathbf{x}_{\text{input}} = \text{tokens}[0 : N-1], \quad \mathbf{y}_{\text{target}} = \text{labels}[1 : N]$$ The last prompt token (`### Response:\n`) at index $t$ directly targets the first token of the assistant's answer at index $t+1$. ### SFT Training Parameters: * **Epochs:** 3 Epochs (1,326 optimizer steps) * **Learning Rate:** `2e-5` with Cosine Annealing to `2e-6` (Conservative rate prevents catastrophic forgetting) * **Dataset Filter:** Slices exceeding 512 tokens skipped to avoid mid-sentence cutoff (14,122 clean samples preserved). * **Final SFT Loss:** **`~3.17`** --- ## 5. Inference Engine & Multi-Turn Chat Memory ### Generation Sampling Strategy: To balance creativity and coherence while avoiding repetitive loops: 1. **Temperature Scaling (T=0.7):** Softens the logit distribution: $\hat{z}_i = z_i / T$. 2. **Repetition Penalty (alpha=1.2):** Penalizes already generated tokens. 3. **Top-P (Nucleus) Filtering (P=0.90):** Retains the smallest set of top tokens whose cumulative probability $\ge 0.90$, truncating the low-probability tail. 4. **Early Termination Safeguards:** * Stops immediately on `<|endoftext|>` (50,256). * Stops if model generates follow-up prompt headers (`### Instruction:`). ### Multi-Turn Memory Management: The inference engine implements a **Sliding Window Multi-Turn Buffer**: * Maintains a structured dialogue history array `conversation_history`. * Appends previous turns into a unified context prompt. * If prompt tokens exceed 380, it dynamically trims older turns from the left, ensuring 130+ tokens remain available for response generation within the 512 context limit. --- ## 6. Dual-Layer Safety Guardrail Subsystem The inference pipeline incorporates an asynchronous dual-layer guardrail: ``` [User Input] | v [Layer 1: Input Keyword Heuristic + Toxic-BERT Classifier] | +---> If Unsafe ---> [Return Safe Rejection Message] | v (If Safe) [Apex-64M Neural Generation] | v [Layer 2: Output Toxicity Verification] | +---> If Unsafe ---> [Return Neutral Fallback Message] | v (If Safe) [Delivered Assistant Response] ``` 1. **Layer 1 (Pre-Generation Filter):** Evaluates input against high-risk categories via exact heuristics and `unitary/toxic-bert`. 2. **Layer 2 (Post-Generation Moderation):** Scans model output prior to display to ensure generated content meets safety thresholds. --- ## 7. Parameter Accounting & Memory Footprint ### Layer-by-Layer Parameter Breakdown: | Component | Dimensions / Formula | Parameters | % of Model | | :--- | :--- | :--- | :--- | | **Token Embeddings (`wte`)** | 50,257 x 512 | 25,731,584 | 40.32% | | **Positional Embeddings (`wpe`)** | 512 x 512 | 262,144 | 0.41% | | **12 Transformer Blocks:** | | | | | - *Attention QKV Projections* | 3 x (512 x 512 + 512) | 787,968 x 12 = 9,455,616 | 14.82% | | - *Attention Output Projection* | 512 x 512 + 512 | 262,656 x 12 = 3,151,872 | 4.94% | | - *LayerNorm 1 (`ln_1`)* | 2 x 512 | 1,024 x 12 = 12,288 | 0.02% | | - *MLP FC1 (Up-Projection)* | 512 x 2048 + 2048 | 1,050,624 x 12 = 12,607,488 | 19.75% | | - *MLP FC2 (Down-Projection)* | 2048 x 512 + 512 | 1,049,088 x 12 = 12,589,056 | 19.72% | | - *LayerNorm 2 (`ln_2`)* | 2 x 512 | 1,024 x 12 = 12,288 | 0.02% | | **Final LayerNorm (`ln_f`)** | 2 x 512 | 1,024 | <0.01% | | **LM Output Head (`lm_head`)** | Tied with `wte` | *0 (Reused)* | 0.00% | | **Total Parameters** | | **63,823,360** | **100.0%** | ### Memory Footprint: * **FP32 Storage:** ~255.3 MB * **FP16 Storage:** ~127.6 MB * **INT8 Quantized:** ~63.8 MB * **Runtime RAM Requirement:** <300 MB (Runs on any mobile device or CPU).