NoPE GPT is a generative pretrained Transformer-style (GPT) language model with no positional embeddings (NoPE). Built using PyTorch and trained on HuggingFace's Fineweb, SmolTalk, and UltraFeedback datasets, NoPE GPT can answer questions, summarize documents, use tools, and more.
Features
No positional embeddings (NoPE): NoPE GPT aims to be a more parsimonious model by completely removing positional embeddings from the architecture allowing the context length to vary without complex model surgery. Despite having no positional embeddings, NoPE GPT performs better at context length generalization than the best relative embeddings (ALiBi, RoPE, T5) offering good performance even when operating within 2X the trained context window.
Fast and memory-efficient: NoPE GPT employs a number of training and inference-time optimizations such as Group Query Attention (GQA), Flash Attention, KV-caching, activation checkpointing, and fully-sharded data parallel (FSDP) pretraining. As such, you can train and infer on relatively modest hardware.
Fully Open-source: Unlike closed-source LLMs, NoPE GPT provides both the model weights and the source code to train, fine-tune, export, and generate text from the model using your own hardware.
The code required to run inference comes as a Python package that you can install with your favorite package manager such as pip.
pip install nope-gpt
Pretrained Examples
This first example we'll show how to load a pretrained base model from HuggingFace Hub and then use it to generate text. First, make sure the nope-gpt package is installed into your project. Once the package is installed you can load pretrained weights from HuggingFace Hub like in the example below.
Then, to generate text, provide a prompt, tokenize it, and iterate through the generate() method until the model outputs a stop token.
python
1import torch
23prompt =input("Enter a prompt: ")45prompt = tokenizer.tokenize(prompt)67prompt = torch.tensor(prompt, dtype=torch.int64)89for token, probability in model.generate(prompt):10if token.item()in tokenizer.stop_tokens:11break1213 out = tokenizer.decode_single_token(token)1415print(out, end="", flush=True)
Generating text from the base model is the simplest way to get started with model inference, however, it is not the most useful when it comes to being able to chat with and guide the model output. In this example we'll load one of the pretrained chat models from HuggingFace Hub and then chat with it. In addition, we'll make use of short-term memory so the model can remember the chat history.
First, load a pretrained chat model from HuggingFace Hub like in the example below.
Next, we'll instantiate a BufferWindowMemory object to handle the chat history and craft a system message that will guide generation. Note that messages are inputted as dicts with role and content keys. For a system message use the system role.
python
1from nope_gpt.memory import BufferWindowMemory
23memory = BufferWindowMemory(4)45system_message ={6"role":"system",7"content":"You are a friendly AI assistant.",8}
Finally, prompt the user for input, adds the system message and chat history to the context, tokenizes the messages, and then generates the assistant response.
python
1import torch
23whileTrue:4 prompt =input("Enter a prompt: ")56 user_message ={7"role":"user",8"content": prompt,9}1011 memory.add_message(user_message)1213 messages =[system_message]+ memory.get_history()1415 tokens = tokenizer.tokenize_prompt(messages)1617 prompt = torch.tensor(tokens, dtype=torch.int64, device=args.device)1819 response =""2021for token, probability in generate(prompt):22if token.item()in tokenizer.stop_tokens:23break2425 out = tokenizer.decode_single_token(token)2627print(out, end="", flush=True)2829 response += out
3031print("\n")3233 assistant_message ={34"role":"assistant",35"content": response,36}3738 memory.add_message(assistant_message)
You're done! For more advanced usages take a look at the generate.py and chat.py scripts located in the code repository.
Training and Fine-tuning
In addition to the inference code, we also provide training and fine-tuning code so you can build your own NoPE GPT models. Before getting started, take a look at the model_sizing.ipynb IPython notebook in the project repo for a guide to sizing your model based on the amount of memory and compute you have available.
Clone the project repo
We'll need the code from the project repository to train and/or fine-tune the model.
Project dependencies are specified in the requirements.txt file. You can install them with pip using the following command from the project root. We recommend using a virtual environment such as venv to keep package dependencies on your system tidy.
Pretraining focuses on building a foundation of language and general knowledge to use as a base for future supervised fine-tuning. The training objective is to predict the next token in a sample of text. It is a self-supervised form of training because the model learns from masked inputs of unsupervised data. For the pretraining corpus we use the Fineweb dataset which consists of 15T high-quality tokens gathered from the worldwide web. In addition, the dataset has been split into 3 subsets (10BT, 100BT, and 350BT versions) for training smaller models.
python pretrain.py
Note that it will take a while to download and pre-process the dataset the first time that the training script is run.
To customize the default architecture you can adjust the embedding_dimensions, attention heads, num_hidden_layers, and feed_forward_ratio arguments of the pretraining script.
If you are planning a long training run, it is recommended to set a random seed. This will ensure that any random state is preserved if the process gets interrupted.
python pretrain.py --seed=42
For distributed training, use PyTorch's torchrun extension to launch a distributed data parallel (DDP) session. The example below is for executing the training script on a single node with 8 individual GPUs.
Note that when training in data-parallel mode it's important that the gradient_accumulation_steps divides evenly into the world size for maximum performance. For example, if we have an 8 GPU cluster, we could perform 32 gradient accumulation steps in exactly 4 passes over the network.
Pretraining Arguments
Argument
Default
Type
Description
--dataset_subset
"sample-10BT"
str
The subset of the Fineweb dataset to train on. Options are sample-10BT, sample-100BT, and sample-350BT. Set to None to train on the full 15T token dataset.
--token_encoding
"r50k_base"
str
The Tiktoken encoding scheme to use when tokenizing the dataset. Options include r50k_base, p50k_base, cl100k_base, and o200k_base.
--dataset_path
"./datasets"
str
The path to the preprocessed dataset files on disk.
--batch_size
2
int
The number of samples of size tokens_per_sample to pass through the network at a time.
--gradient_accumulation_steps
128
int
The number of batches to pass through the network before updating the model weights.
--tokens_per_sample
4096
int
The number of tokens to pack into a single training sequence. This is sometimes called the block size or context length.
--max_steps
10000
int
The maximum number of steps to take for pretraining.
--learning_rate
1e-2
float
The learning rate of the Adafactor optimizer.
--anneal_learning_rate
False
bool
Should we linearly decay the learning rate to zero as the step approaches max_steps?
--low_memory_optimizer
False
bool
Should the optimizer reduce its memory consumption in exchange for a slightly slower runtime?
--max_gradient_norm
10.0
float
Clip gradients above this threshold norm before stepping.
--embedding_dimensions
1024
int
The dimensionality of the token embeddings.
--num_q_heads
16
int
The number of query heads within every attention layer.
--num_kv_heads
4
int
The number of key and value heads within every attention layer.
--num_hidden_layers
16
int
The number of attention/MLP blocks within the body of the network.
--feed_forward_ratio
4
(1, 2, 4)
The ratio of hidden neurons to embedding dimensions in the MLP layers of the network.
--dropout
0.0
float
The proportion of signals to send to zero during training as regularization.
--activation_checkpointing
False
bool
Should we use activation checkpointing? This will drastically reduce memory utilization during training at the cost of recomputing the forward pass.
--ddp_sharding_level
2
int
The level of sharding to use for DDP training. Options are 2 or 3 for partial and full sharding respectively, or 0 for no sharding.
--eval_interval
100
int
Evaluate the model after this many epochs on the testing set.
--num_eval_samples
2048
int
The number of hold-out samples to use for validation during training.
--checkpoint_interval
100
int
Save the model checkpoint to disk every this many epochs.
--checkpoint_path
"./checkpoints/checkpoint.pt"
str
The path to the base checkpoint file on disk.
--resume
False
bool
Should we resume training from the last checkpoint?
--resume_scheduler
False
bool
Should we resume the learning rate schedule from the last checkpoint?
--run_dir_path
"./runs"
str
The path to the TensorBoard run directory for this training session.
--device
"cpu"
str
The device to run the training on ex cuda, cuda:0, mps, cpu.
--seed
None
int
The seed for the random number generator.
Fine-tuning
Instruction-tuning is a supervised training technique focused on developing specialized objectives such as chatting, text summarization, chain-of-thought, and prompt rewriting. We use the SmolTalk and UltraFeedback datasets by HuggingFace as fine-tuning corpora because they include a broad range of training objectives such as conversation, instruction following, summarization, and human preference alignment.
python fine-tune.py
To pick which dataset subsets to train on you can specify them in a comma-separated list like in the example below.
To adjust the number of trainable LoRA parameters as well as the strength of the LoRA and Dropout signals you can change the --rank and --alpha arguments respectively.
python fine-tune.py --rank=4 --alpha=2.0
To quantize the base model weights during fine-tuning (QLoRA) you can specify the quantize_base_weights argument and to adjust the quant group size set the quant_group_size argument like in the example below.
In memory constrained environments, you can enable activation checkpointing to trade off compute for memory efficiency by recomputing the activations of each decoder block during backpropagation.
python fine-tune.py --activation_checkpointing
Fine-tuning Arguments
Argument
Default
Type
Description
--base_checkpoint_path
None
string
The path to the base model checkpoint on disk.
--dataset_subset
"all"
str
A comma-separated list of subsets of the dataset to train on. Options are all, apigen-80k, everyday-conversations, explore-instruct-rewriting, longalign, metamathqa-50k, numina-cot-100k, openhermes-100k, self-oss-instruct, smol-constraints, smol-magpie-ultra, smol-rewrite, smol-summarize, systemchats-30k, and ultra-feedback.
--max_tokens_per_sample
4096
int
The maximum number of tokens to pack into a single training sequence.
--filter_long_samples
False
bool
Should we filter out samples that are longer than the max_tokens_per_sample?
--num_dataset_processes
8
int
The number of processes to use for processing the dataset.
--batch_size
1
int
The number of samples to pass through the network at a time.
--gradient_accumulation_steps
128
int
The number of batches to pass through the network before updating the weights.
--num_epochs
2
int
The number of epochs to train for.
--learning_rate
1e-2
float
The learning rate of the Adafactor optimizer.
--low_memory_optimizer
False
bool
Should the optimizer reduce its memory consumption in exchange for a slightly slower runtime?
--max_gradient_norm
1.0
float
Clip gradients above this threshold norm before stepping.
--rank
8
int
The rank of the LoRA decomposition matrices.
--alpha
1.0
float
The strength of the LoRA signal.
--freeze_token_embeddings
False
bool
Should we freeze the weights of the token embeddings?
--activation_checkpointing
False
bool
Should we use activation checkpointing? This will reduce drastically memory utilization during training at the cost of needing to recompute the forward pass.
--eval_interval
1
int
Evaluate the model after this many epochs on the testing set.
--num_eval_samples
2048
int
The number of hold-out samples to use for validation during training.
--checkpoint_interval
1
int
Save the model parameters to disk every this many epochs.
--checkpoint_path
"./checkpoints/checkpoint.pt"
str
The path to the model checkpoint.
--resume
False
bool
Should we resume training from the last checkpoint?
--run_dir_path
"./runs"
str
The path to the TensorBoard run directory for this training session.
--device
"cpu"
str
The device to run the training on ex cuda, cuda:0, mps, cpu.
--seed
None
int
The seed for the random number generator.
Training Dashboard
We use TensorBoard to capture and display pretraining events such as loss and gradient norm updates. To launch the dashboard server run the following command from the terminal.
tensorboard --logdir=./runs
Then navigate to the dashboard using your favorite web browser.
References:
G. Penedo, et al. The FineWeb Datasets: Decanting the Web for the Finest Text Data at Scale, 38th Conference on Neural Information Processing Systems (NeurIPS 2024) Track on Datasets and Benchmarks.
L. B. Allal, et al. SmolLM2 - with great data, comes great performance, 2024.
A. Radford, et al. Language Models are Unsupervised Multitask Learners, OpenAI, 2019.
T. Brown, et al. Language Models are Few-Shot Learners. OpenAI, 2020.
A. Kazemnejad, et al. The Impact of Positional Encoding on Length Generalization in Transformers, 37th Conference on Neural Information Processing Systems (NeurIPS 2023).
S. Rajbhandari, et al. ZeRO: Memory Optimizations Toward Training Trillion Parameter Models, 2020.
J. R. Hermans, et al. Accumulated Gradient Normalization, JMLR: Workshop and Conference Proceedings, 2017.
T. Chen, et al. Training Deep Nets with Sublinear Memory Cost. MIT, 2019.
B. Zhang, et al. Root Mean Square Layer Normalization. 33rd Conference on Neural Information Processing Systems, NeurIPS 2019.
J. Kaplan, et al. Scaling Laws for Neural Language Models, OpenAI, 2020.
J. Hoffman, et al. Training Compute-Optimal Large Language Models, Deep Mind, 2022.
J. Ainslie, et al. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints, Google Research, 2023.
S. Bergsma, et al. Straight to Zero: Why Linearly Decaying the Learning Rate to Zero Works Best for LLMs, ICLR, 2025.
R. Zhao, et al. Deconstructing What Makes a Good Optimizer for Autoregressive Language Models, ICLR, 2025.