The most atomic way to train and inference a GPT in pure, dependency-free Rust.
Note: This file is the complete algorithm. Everything else is just efficiency.
This is a minimal, dependency-free implementation for understanding Generative Pre-trained Transformers (GPT).
GitHub Repository: https://github.com/aarambh-darshan/microgpt-rust
The implementation demonstrates the core concepts of modern large language models (LLMs) including:
- Token embeddings and positional encodings
- Multi-head self-attention mechanism
- Feed-forward neural networks (MLP)
- Layer normalization (RMSNorm)
- Autoregressive training with cross-entropy loss
- Adam optimizer with gradient clipping
- Zero Dependencies: Pure Rust implementation with only the standard library
- Complete Training Pipeline: From random initialization to trained model
- Text Generation: Generate new text samples after training
- Educational: Clean, readable code that demonstrates core concepts
- Fast: Optimized release builds for reasonable training times
The model follows the GPT-2 architecture with minor modifications:
- Embedding dimension: 16
- Number of attention heads: 4
- Number of layers: 1
- Context length (block size): 16
- Vocabulary size: 27 (A-Z characters + BOS token)
- Total parameters: ~4,192
Modifications from standard GPT-2:
- LayerNorm β RMSNorm
- GeLU β ReLU activation
- No bias terms in linear layers
- Rust toolchain (1.70+)
- curl (for downloading the dataset)
# Clone the repository
git clone https://github.com/aarambh-darshan/microgpt-rust.git
cd microgpt-rust
# Run in release mode for optimal performance
cargo run --releaseThe program will:
- Download the names dataset (if not present)
- Train for 1000 steps (time varies by hardware, use
--releasefor best performance) - Generate 20 new sample names
num docs: 32033
vocab size: 27
num params: 4192
step 1 / 1000 | loss 3.2889
step 2 / 1000 | loss 3.3999
step 3 / 1000 | loss 3.3450
...
step 1000 / 1000 | loss 2.6440
--- inference (new, hallucinated names) ---
sample 1: ama
sample 2: adana
sample 3: sada
sample 4: salan
sample 5: caanan
...
The implementation includes a minimal automatic differentiation engine:
// Values track their computation graph for backprop
let x = Value::new(2.0);
let y = x.mul(&x); // y = xΒ²
y.backward(); // dy/dx = 4.0fn forward(&self, token_id: usize, pos_id: usize, ...) -> Vec<Rc<Value>> {
// Token + positional embedding
let tok_emb = &self.wte[token_id];
let pos_emb = &self.wpe[pos_id];
let mut x: Vec<Rc<Value>> = tok_emb.iter()
.zip(pos_emb.iter())
.map(|(t, p)| t.add(p))
.collect();
// Multi-head attention + MLP
// ... (see src/main.rs for full implementation)
linear(&x, &self.lm_head)
}The training follows standard supervised learning:
- Sample a document from the dataset
- Tokenize and create input-target pairs
- Forward pass through the model
- Compute cross-entropy loss
- Backward pass to compute gradients
- Update parameters with Adam optimizer
The implementation uses Rc<Value> (reference counting) to manage the computation graph:
struct Value {
data: f64,
grad: RefCell<f64>,
children: Vec<Rc<Value>>, // References to parent nodes
local_grads: Vec<f64>, // Local derivatives
}To ensure stable training, gradients are clipped to a maximum norm:
let max_grad_norm = 1.0;
let grad_norm = compute_gradient_norm(&grads);
let clip_scale = if grad_norm > max_grad_norm {
max_grad_norm / grad_norm
} else { 1.0 };Layer normalization without centering:
fn rmsnorm(x: &[Rc<Value>]) -> Vec<Rc<Value>> {
let ms = mean_square(x);
let scale = (ms + 1e-5).pow(-0.5);
x.iter().map(|xi| xi.mul(&scale)).collect()
}Training performance varies by hardware. On modern CPUs with --release:
- Typical training: ~45 steps/second
- Memory usage: <50MB
Note: Always run with --release flag for optimal performance:
cargo run --releaseThis is an educational implementation, not production-ready:
- Single-threaded (no parallelization)
- No GPU support
- Fixed hyperparameters
- Character-level tokenization only
- No checkpointing/resuming
To understand the concepts behind this implementation:
-
Andrej Karpathy's Neural Networks: Zero to Hero
- YouTube playlist covering backpropagation, MLPs, RNNs, Transformers
- https://karpathy.ai/zero-to-hero.html
-
The Illustrated Transformer by Jay Alammar
- Visual explanation of attention mechanisms
- https://jalammar.github.io/illustrated-transformer/
-
Attention Is All You Need (Original Transformer Paper)
- Vaswani et al., 2017
- https://arxiv.org/abs/1706.03762
-
GPT-2 Paper
This project is released under the MIT License.
- Darshan Vichhi (@aarambh-darshan) - Implementation
- Andrej Karpathy (@karpathy) for inspiration and excellent educational content
- The Rust community for providing a zero-cost abstraction language perfect for systems programming
Darshan Vichhi - GitHub
This is primarily an educational project. Feel free to fork and experiment with:
- Different model architectures (deeper networks, different attention heads)
- Alternative optimizers (SGD with momentum, AdaGrad, etc.)
- Different datasets (text generation, code completion, etc.)
- Performance optimizations (parallelization, SIMD, etc.)
Built with β€οΈ for the love of understanding how transformers work.