Architecture

System Overview

flaxchat is a complete LLM training pipeline that runs on TPU pods and GPUs with automatic data parallelism.

graph TD
    subgraph "User Interface"
        CLI[CLI Scripts]
        WEB[Web Chat UI]
        REMOTE[Remote Runners]
    end

    subgraph "Core Library"
        GPT[gpt.py<br/>GPT Model]
        OPT[optim.py<br/>Muon + AdamW]
        DL[dataloader.py<br/>BOS Best-Fit Packing]
        TOK[tokenizer.py<br/>BPE rustbpe+tiktoken]
        ENG[engine.py<br/>KV-Cache Inference]
        EVAL[eval.py<br/>CORE + BPB]
        CKPT[checkpoint.py<br/>Orbax]
        CFG[config.py<br/>Depth Auto-Config]
        COMMON[common.py<br/>Mesh + Distributed]
        REPORT[report.py<br/>Training Reports]
    end

    subgraph "Training Scripts"
        PT[pretrain.py]
        SFT[sft.py]
        RL[rl.py]
        EV[eval script]
    end

    subgraph "Infrastructure"
        TPU[cloud/launcher.py<br/>GCP TPU Pods]
        KAGGLE[remote/kaggle_runner.py<br/>Kaggle GPUs]
    end

    CLI --> PT & SFT & RL & EV
    WEB --> ENG
    REMOTE --> TPU & KAGGLE

    PT --> GPT & OPT & DL & COMMON & CKPT
    SFT --> GPT & OPT & COMMON & CKPT
    RL --> GPT & ENG & COMMON

    GPT --> CFG
    OPT --> CFG
    DL --> TOK
    ENG --> GPT
    EV --> ENG & EVAL

    COMMON --> |"Mesh + Sharding"| GPT & DL & PT & SFT

Module Dependency Graph

flaxchat/__init__.py
    ├── config.py          (no internal deps)
    ├── common.py          (no internal deps)
    ├── gpt.py             ← config.py, common.py
    ├── optim.py           ← config.py (via setup_optimizer)
    ├── tokenizer.py       (no internal deps)
    ├── dataloader.py      ← dataset.py, common.py
    ├── dataset.py         ← common.py
    ├── engine.py          ← gpt.py, common.py
    ├── eval.py            ← common.py
    ├── checkpoint.py      (no internal deps, uses orbax)
    ├── report.py          ← common.py
    ├── remote/
    │   ├── base.py        (no deps — abstract interface)
    │   └── kaggle_runner.py ← base.py
    └── cloud/
        ├── tpu_vm.py      (no internal deps — uses gcloud CLI)
        └── launcher.py    ← tpu_vm.py, remote/base.py

No circular dependencies. config.py and common.py are leaf modules.

GPT Model Architecture

graph TD
    INPUT[Input Tokens<br/>B x T] --> WTE[Token Embedding<br/>wte]
    WTE --> NORM1[RMS Norm]
    NORM1 --> SMEAR[Smear<br/>bigram mixing]

    SMEAR --> BLOCK1[Block 0]
    BLOCK1 --> BLOCK2[Block 1]
    BLOCK2 --> BLOCKN[Block N-1]

    subgraph "Transformer Block"
        direction TB
        RL[resid_lambda * x<br/>+ x0_lambda * x0]
        RL --> ATTN_NORM[RMS Norm]
        ATTN_NORM --> ATTN[Causal Self-Attention<br/>RoPE + QK Norm + GQA]
        VE[Value Embedding] -.-> ATTN
        ATTN --> ADD1[Residual Add]
        ADD1 --> MLP_NORM[RMS Norm]
        MLP_NORM --> MLP[MLP<br/>ReLU^2]
        MLP --> ADD2[Residual Add]
    end

    BLOCKN --> BACKOUT[Backout<br/>subtract mid-layer]
    BACKOUT --> NORM2[RMS Norm]
    NORM2 --> LM_HEAD[LM Head<br/>untied weights]
    LM_HEAD --> SOFTCAP[Logit Softcap<br/>15 * tanh x/15]
    SOFTCAP --> OUTPUT[Logits<br/>B x T x V]

Attention Detail

graph LR
    X[Input x] --> Q[Linear → Q]
    X --> K[Linear → K]
    X --> V[Linear → V]

    Q --> ROPE_Q[RoPE]
    K --> ROPE_K[RoPE]

    ROPE_Q --> QKN_Q[QK Norm * 1.2]
    ROPE_K --> QKN_K[QK Norm * 1.2]

    QKN_Q --> DOT[dot_product_attention<br/>+ causal mask<br/>+ sliding window]
    QKN_K --> DOT
    V --> DOT

    VE[Value Embedding] -.-> |"gate * ve"| V

    DOT --> PROJ[Linear → output]

Training Pipeline

graph LR
    subgraph "Stage 1: Data"
        RAW[Raw Text<br/>ClimbMix-400B] --> TOK_TRAIN[Train BPE<br/>vocab=32K]
        TOK_TRAIN --> TOKENIZE[Tokenize<br/>→ parquet shards]
    end

    subgraph "Stage 2: Pretrain"
        TOKENIZE --> DL[BOS Best-Fit<br/>Dataloader]
        DL --> TRAIN[Pretrain GPT<br/>Muon + AdamW]
        TRAIN --> |"Chinchilla<br/>scaling laws"| TRAIN
        TRAIN --> BASE[Base Model<br/>checkpoint]
    end

    subgraph "Stage 3: SFT"
        BASE --> SFT_TRAIN[SFT on<br/>SmolTalk]
        SFT_TRAIN --> SFT_MODEL[SFT Model]
    end

    subgraph "Stage 4: RL"
        SFT_MODEL --> RL_TRAIN[GRPO on<br/>GSM8K]
        RL_TRAIN --> RL_MODEL[RL Model]
    end

    subgraph "Stage 5: Eval"
        RL_MODEL --> EVAL[MMLU, ARC<br/>GSM8K, HumanEval<br/>SpellingBee]
        EVAL --> REPORT[Training<br/>Report]
    end

    subgraph "Stage 6: Serve"
        RL_MODEL --> CHAT[Web Chat UI<br/>FastAPI + WS]
    end

Data Parallelism

graph TD
    subgraph "Host 0"
        D0[Local Data Shard 0]
        GPU0[GPU/TPU 0]
        GPU1[GPU/TPU 1]
    end

    subgraph "Host 1 (multi-host)"
        D1[Local Data Shard 1]
        GPU2[GPU/TPU 2]
        GPU3[GPU/TPU 3]
    end

    MESH[JAX Mesh<br/>axis='data'] --> GPU0 & GPU1 & GPU2 & GPU3

    D0 --> |"P('data')"| GPU0 & GPU1
    D1 --> |"P('data')"| GPU2 & GPU3

    GPU0 & GPU1 & GPU2 & GPU3 --> |"Auto all-reduce<br/>(XLA SPMD)"| GRADS[Synchronized Gradients]
    GRADS --> UPDATE[Optimizer Update<br/>Replicated Params]

Sharding Strategy

Component Sharding Mesh Axis
Input data (batch dim) P('data') Split across devices
Model params P() Replicated on all devices
Gradients Auto all-reduce XLA handles it
Optimizer state P() or P('fsdp') Replicated or sharded

For models too large for one device, use shard_model_fsdp() which shards the first dimension of 2D+ params across the fsdp mesh axis.