A complete PyTorch implementation of the RNJ-1 (pronounced "range-1") architecture, following the design principles of the model developed by Essential AI, led by Ashish Vaswani (co-author of "Attention Is All You Need").
Overview
This is a configurable implementation of the RNJ-1 architecture that allows you to build models of various sizes. The original RNJ-1 is an 8.3B parameter model optimized for code generation, agentic tasks, and STEM problem solving, but this implementation lets you adjust the model size based on your needs and available resources.
The actual parameter count is calculated at runtime and depends on your configuration in RNJ1_CONFIG. The default configuration targets the full RNJ-1 architecture (~8.3B), but you can easily modify it to create smaller models for testing or limited GPU memory.
Key Facts
Parameters: Fully configurable - actual count calculated at runtime (see RNJ1_CONFIG in rnj1.py)
Default Config: Targets ~8.3B parameters (can be modified for smaller models)
Context Length: Configurable (default 32K tokens)
License: Apache 2.0
Architecture: Based on Gemma 3, with key simplifications
Original Model: Essential AI (led by Transformer co-inventor Ashish Vaswani)
Architecture
Model Specifications
The model configuration is defined in RNJ1_CONFIG in rnj1.py. You can modify these values to create models of any size:
Hyperparameter
Default Value
Config Key
Notes
Number of Layers
32
n_layers
Main size factor
Model Dimension
4096
emb_dim
Affects all layers
MLP Dimension
16384
hidden_dim
Typically 4x emb_dim
Number of Attention Heads
32
n_heads
Should divide emb_dim
Number of Key-Value Heads
8
n_kv_groups
GQA ratio
Attention Head Dimension
128
head_dim
Typically emb_dim/n_heads
Vocabulary Size
From tokenizer
vocab_size
Affects embedding size
Tokenizer
SentencePiece BPE
Auto-detected
With fallback options
Context Length
32768
context_length
Can be reduced
Activation Function
GeGLU
Fixed
In FeedForward class
Tied Embeddings
Yes
Fixed
Embedding and output head share weights
Important:
Total Parameters: Calculated automatically from the config above using count_parameters() function and printed when you run the script
The actual parameter count is printed when you run the script - look for: Total trainable parameters: X,XXX,XXX (~X.XXB)
To create a smaller model, modify RNJ1_CONFIG in rnj1.py before running
The embedding layer size = vocab_size × emb_dim, which can be significant
Example: Reducing emb_dim from 4096 to 1024 and n_layers from 32 to 12 creates a much smaller model
Key Architectural Features
Global Attention Only: Unlike Gemma 3's hybrid sliding window + global attention, RNJ-1 uses only global attention throughout all layers. This provides full context awareness at every layer, which is beneficial for code and agentic tasks.
Standard RoPE: Uses single RoPE (Rotary Position Embeddings) with theta_base = 10,000. Context extension from 8K to 32K is handled via YaRN (Yet another RoPE extensioN) during mid-training.
GeGLU Activation: Uses GeGLU (Gated GeLU) activation function in the feedforward network, which provides better expressiveness compared to standard GeLU.
Grouped Query Attention (GQA): 32 query heads with 8 KV heads (4:1 ratio), providing memory efficiency while maintaining performance.
QK Normalization: Uses query-key normalization for training stability.
4 RMSNorm Layers: Pre-norm architecture with 4 normalization layers per transformer block:
The model size is determined by RNJ1_CONFIG in the script. The actual parameter count is calculated at runtime and printed during initialization. To create a smaller model, modify the configuration:
python
1# Example: Smaller model for testing2RNJ1_CONFIG ={3"vocab_size": vocab_size,# From tokenizer4"emb_dim":1024,# Reduced from 40965"n_heads":16,# Reduced from 326"head_dim":64,# Reduced from 1287"n_kv_groups":4,# Reduced from 88"n_layers":12,# Reduced from 329"hidden_dim":4096,# Reduced from 1638410"context_length":2048,# Reduced from 32K11"rope_base":10_000.0,12"qk_norm":True,13"dtype": torch.bfloat16,14}
Running Training
python rnj1.py
What the script does:
Loads tokenizer (with fallback options if RNJ-1 tokenizer unavailable)
Downloads and tokenizes TinyStories dataset (if train.bin doesn't exist)
Initializes model with RNJ1_CONFIG settings
Prints actual parameter count (this is the real model size!)
Trains with mixed precision (bfloat16)
Saves best model based on validation loss (rnj1_model.pt)
Generates sample text after training
To see your actual model size, look for this output when running:
Total trainable parameters: X,XXX,XXX (~X.XXB)
Model Components
The implementation includes:
RoPE (Rotary Position Embeddings): Standard implementation with configurable base frequency
RMSNorm: Zero-centered weights with (1 + weight) scaling
GroupedQueryAttention: GQA with QK normalization
FeedForward: GeGLU-based feedforward network
TransformerBlock: Complete transformer block with 4 normalization layers
Rnj1Model: Full model with token embeddings, transformer blocks, and output head
Performance
Benchmarks
Code Generation:
HumanEval+: Strong performance
MBPP+: Strong performance
BigCodeBench: Strong performance
SWE-bench: 20.8% (exceptional for 8B model)
Mathematical Reasoning:
GSM8K: Strong performance
Minerva-MATH: On par with best models
AIME: Outperforms or matches best models
STEM:
GPQA-Diamond: Close to best similarly sized models
SuperGPQA: Strong long-context reasoning
Implementation Details
Tokenizer
Type: SentencePiece BPE
Vocabulary Size: 128,000 tokens
Loading: Uses EssentialAI/rnj-1 tokenizer with fallback options
Data Type Handling
Training: bfloat16 (preferred) or float16
Token IDs: uint32 (required for vocab_size > 65536)
Mixed Precision: Automatic via torch.amp.autocast
Memory Optimization
Gradient Accumulation: Simulates larger batch size without more memory
Mixed Precision: Reduces memory usage
Gradient Checkpointing: Can be added for further memory savings
Key Features
Complete Implementation: All components from scratch in PyTorch
Training Ready: Full training loop with best practices
Modular Design: Easy to modify and extend
Well Documented: Inline comments explaining each component
Production Ready: Includes evaluation, checkpointing, and text generation
Limitations & Notes
Model Size: The actual parameter count is calculated and printed at runtime. The default RNJ1_CONFIG targets ~8.3B parameters, but:
The actual size depends on vocab_size (from tokenizer) and all config values
You can modify RNJ1_CONFIG to create much smaller models
For testing, many users reduce emb_dim, n_layers, and hidden_dim significantly
The embedding layer (vocab_size × emb_dim) is often the largest component
Optimizer: This implementation uses AdamW, but the original RNJ-1 uses Muon optimizer (custom optimizer by Essential AI). Muon provides superior token efficiency but is not publicly available.
Training Scale: The provided script uses TinyStories dataset for demonstration. Full RNJ-1 training requires:
8.4T tokens for pre-training (8K context)
380B tokens for context extension (8K → 32K)
150B tokens for supervised fine-tuning
Memory Requirements: Memory usage depends on model size. For the full 8.3B model, you need significant GPU memory. For smaller models, adjust batch_size and block_size based on available hardware. You can also reduce model dimensions in RNJ1_CONFIG.
Tokenizer Fallback: If RNJ-1 tokenizer is unavailable, the script falls back to Llama 3.1 tokenizer (also 128K vocab, SentencePiece BPE). The actual vocab_size affects the embedding layer size significantly.
File Structure
rnj-1/
├── README.md # This file
├── rnj1.py # Complete training script
├── RNJ1_QUICK_REFERENCE.md # Quick reference guide
├── RNJ1_REVIEW.md # Detailed model review
├── RNJ1_TOKENIZER_INFO.md # Tokenizer details
├── RNJ1_VS_GEMMA3_COMPARISON.md # Architecture comparison
└── linkedin_post_rnj1.md # Social media post about implementation