Text Generation
Transformers
Safetensors
MLX
qwen3
oeis
integer-sequences
causal-lm
text-generation-inference
Instructions to use N8Programs/NextTerm-2-440M with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use N8Programs/NextTerm-2-440M with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="N8Programs/NextTerm-2-440M")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("N8Programs/NextTerm-2-440M") model = AutoModelForCausalLM.from_pretrained("N8Programs/NextTerm-2-440M", device_map="auto") - MLX
How to use N8Programs/NextTerm-2-440M with MLX:
# Make sure mlx-lm is installed # pip install --upgrade mlx-lm # if on a CUDA device, also pip install mlx[cuda] # Generate text with mlx-lm from mlx_lm import load, generate model, tokenizer = load("N8Programs/NextTerm-2-440M") prompt = "Once upon a time in" text = generate(model, tokenizer, prompt=prompt, verbose=True) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- vLLM
How to use N8Programs/NextTerm-2-440M with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "N8Programs/NextTerm-2-440M" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "N8Programs/NextTerm-2-440M", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/N8Programs/NextTerm-2-440M
- SGLang
How to use N8Programs/NextTerm-2-440M with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "N8Programs/NextTerm-2-440M" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "N8Programs/NextTerm-2-440M", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "N8Programs/NextTerm-2-440M" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "N8Programs/NextTerm-2-440M", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - MLX LM
How to use N8Programs/NextTerm-2-440M with MLX LM:
Generate or start a chat session
# Install MLX LM uv tool install mlx-lm # Generate some text mlx_lm.generate --model "N8Programs/NextTerm-2-440M" --prompt "Once upon a time"
- Docker Model Runner
How to use N8Programs/NextTerm-2-440M with Docker Model Runner:
docker model run hf.co/N8Programs/NextTerm-2-440M
- Atomic Chat
NextTerm-2-440M: bf16 weights, model card, eval scripts and data
Browse files- .gitattributes +1 -0
- README.md +192 -0
- config.json +26 -0
- eval_m1.py +251 -0
- eval_neo.py +165 -0
- eval_results.txt +38 -0
- eval_ryskina.py +102 -0
- gen_poly_evals.py +52 -0
- generation_config.json +6 -0
- m1_competition_111.jsonl +0 -0
- model.safetensors +3 -0
- oeis_val_neo.jsonl +0 -0
- radar_chart.png +3 -0
- ryskina_knight_57.jsonl +57 -0
- tokenizer.json +1 -0
- tokenizer_config.json +8 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
radar_chart.png filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: cc-by-sa-4.0
|
| 3 |
+
library_name: transformers
|
| 4 |
+
pipeline_tag: text-generation
|
| 5 |
+
tags:
|
| 6 |
+
- oeis
|
| 7 |
+
- integer-sequences
|
| 8 |
+
- qwen3
|
| 9 |
+
- causal-lm
|
| 10 |
+
- mlx
|
| 11 |
+
datasets:
|
| 12 |
+
- N8Programs/oeis-ladder-10b
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
# NextTerm-2-440M
|
| 16 |
+
|
| 17 |
+
(Model Card Co-Written w/ Opus 5.5)
|
| 18 |
+
|
| 19 |
+
[](radar_chart.png)
|
| 20 |
+
|
| 21 |
+
## Model Summary
|
| 22 |
+
|
| 23 |
+
NextTerm-2-440M is a 441M parameter causal transformer trained to continue integer
|
| 24 |
+
sequences. It is the largest model in the NextTerm-2 series (5M, 50M and 440M), three
|
| 25 |
+
models trained on the same 10B tokens with identical hyperparameters for controlled comparison. It uses the Qwen3 architecture with a byte-level
|
| 26 |
+
vocabulary: the 256 byte values plus BOS, EOS and PAD.
|
| 27 |
+
|
| 28 |
+
The training corpus, [N8Programs/oeis-ladder-10b](https://huggingface.co/datasets/N8Programs/oeis-ladder-10b),
|
| 29 |
+
contains every training-split OEIS sequence once (terms from its b-file, up to 4,096
|
| 30 |
+
bytes) plus 9.2B tokens of distinct, synthetically transformed copies of OEIS sequences.
|
| 31 |
+
|
| 32 |
+
Compared with NextTerm-440M, NextTerm-2-440M is better on every benchmark below while
|
| 33 |
+
training on about 30% fewer tokens (10B vs 14B). The largest gains are on Ryskina & Knight
|
| 34 |
+
(+14 points) and on polynomial continuation from short prompts, where it needs far fewer
|
| 35 |
+
terms to identify a cubic or quartic.
|
| 36 |
+
|
| 37 |
+
The model reads integer sequences formatted as comma-separated values, with a trailing
|
| 38 |
+
comma, for example:
|
| 39 |
+
|
| 40 |
+
```text
|
| 41 |
+
1,-2,3,-4,
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
Training data contained only digits, commas and `-`, with no spaces and no leading
|
| 45 |
+
zeros. Other characters are accepted by the byte-level tokenizer but are out of
|
| 46 |
+
distribution, so format prompts exactly as above.
|
| 47 |
+
|
| 48 |
+
## Training Details
|
| 49 |
+
|
| 50 |
+
| Field | Value |
|
| 51 |
+
| --- | --- |
|
| 52 |
+
| Parameters | 440,997,888 |
|
| 53 |
+
| Architecture | Qwen3-style causal LM |
|
| 54 |
+
| Layers | 28 |
|
| 55 |
+
| Hidden size | 1024 |
|
| 56 |
+
| FFN size | 3072 |
|
| 57 |
+
| Attention heads | 16 (head dim 128) |
|
| 58 |
+
| KV heads | 8 |
|
| 59 |
+
| Vocabulary size | 259 (256 bytes + BOS/EOS/PAD) |
|
| 60 |
+
| Training tokens | 9,999,999,999 (one epoch) |
|
| 61 |
+
| Sequence length cap | 4,096 bytes per sequence |
|
| 62 |
+
| Batch mode | Whole-document packing, 98,304 token positions per step (97% filled), no cross-document attention |
|
| 63 |
+
| Steps | 105,029 |
|
| 64 |
+
| Optimizer | Muon/AdamW hybrid with μP width scaling |
|
| 65 |
+
| LR schedule | Linear warmup over 2% of steps to `2e-3` for Muon, `5e-4` for AdamW, cosine decay to 0.1x |
|
| 66 |
+
| AdamW | β = (0.9, 0.99), weight decay 0.01 |
|
| 67 |
+
| Training hardware | 2× NVIDIA DGX Spark (GB10), data parallel, bf16 |
|
| 68 |
+
| Training time | 4 days 8 hours |
|
| 69 |
+
| Export dtype | bfloat16 |
|
| 70 |
+
|
| 71 |
+
Muon was used for 2D weight matrices and AdamW for embeddings, norm gains and the output
|
| 72 |
+
head. All three NextTerm-2 models share these settings.
|
| 73 |
+
|
| 74 |
+
## Evaluation Results
|
| 75 |
+
|
| 76 |
+
### Main Benchmarks
|
| 77 |
+
|
| 78 |
+
| Model | OEIS-Eval-Neo | Ryskina & Knight | M1 Competition 111 MAPE |
|
| 79 |
+
| --- | ---: | ---: | ---: |
|
| 80 |
+
| **NextTerm-2-440M** | **36.25%** | 66.67% | **17.1105** |
|
| 81 |
+
| NextTerm-2-50M | 31.56% | 66.67% | 18.3615 |
|
| 82 |
+
| NextTerm-2-5M | 23.38% | 42.11% | 20.8527 |
|
| 83 |
+
| NextTerm-440M | 34.43% | 52.63% | 17.6239 |
|
| 84 |
+
| NextTerm-47M | 29.49% | **70.18%** | 18.7621 |
|
| 85 |
+
| Qwen3-0.6B | 18.44% | 33.33% | 22.7984 |
|
| 86 |
+
| Qwen3-1.7B | 20.77% | 49.12% | 22.2411 |
|
| 87 |
+
| Qwen3-4B | 23.74% | 63.16% | 19.1731 |
|
| 88 |
+
| Qwen3-8B | 24.62% | 57.89% | 18.4027 |
|
| 89 |
+
| Qwen3-14B | 26.00% | 59.65% | 17.9837 |
|
| 90 |
+
|
| 91 |
+
OEIS-Eval-Neo is a held-out OEIS next-term evaluation (19,034 sequences). M1 Competition
|
| 92 |
+
111 reports macro MAPE, where lower is better; the Naive2 forecasting baseline scores
|
| 93 |
+
17.7987. Ryskina & Knight (2021) is a 57-sequence next-term benchmark based on
|
| 94 |
+
psychometrics and puzzles. NextTerm-47M remains ahead there, consistent with its strength
|
| 95 |
+
on very short prompts.
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
### Polynomial Continuation
|
| 99 |
+
|
| 100 |
+
The polynomial continuation evaluation samples integer sequences from
|
| 101 |
+
polynomials of degree 1 through 4 and asks for the next term. Accuracy is exact
|
| 102 |
+
match across 200 samples for each prompt length `k`.
|
| 103 |
+
|
| 104 |
+
| Model | Arithmetic | Quadratic | Cubic | Quartic |
|
| 105 |
+
| --- | ---: | ---: | ---: | ---: |
|
| 106 |
+
| **NextTerm-2-440M** | 96.15% | **94.39%** | **88.70%** | **83.74%** |
|
| 107 |
+
| NextTerm-2-50M | **96.31%** | 84.11% | 63.95% | 47.86% |
|
| 108 |
+
| NextTerm-2-5M | 78.21% | 23.87% | 1.89% | 0.50% |
|
| 109 |
+
| NextTerm-440M | 94.38% | 86.39% | 75.20% | 67.83% |
|
| 110 |
+
| NextTerm-47M | 94.15% | 81.07% | 37.43% | 15.17% |
|
| 111 |
+
| Qwen3-0.6B | 90.31% | 8.72% | 0.30% | 0.02% |
|
| 112 |
+
| Qwen3-1.7B | 93.10% | 41.57% | 5.36% | 0.71% |
|
| 113 |
+
| Qwen3-4B | 93.90% | 77.26% | 28.18% | 5.98% |
|
| 114 |
+
| Qwen3-8B | 96.10% | 80.59% | 32.93% | 7.95% |
|
| 115 |
+
| Qwen3-14B | 95.60% | 84.61% | 49.16% | 14.98% |
|
| 116 |
+
|
| 117 |
+
## Usage
|
| 118 |
+
|
| 119 |
+
### MLX
|
| 120 |
+
|
| 121 |
+
```bash
|
| 122 |
+
mlx_lm.generate --model N8Programs/NextTerm-2-440M --prompt "1,2,3,"
|
| 123 |
+
```
|
| 124 |
+
|
| 125 |
+
### Hugging Face Transformers
|
| 126 |
+
|
| 127 |
+
```python
|
| 128 |
+
import torch
|
| 129 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 130 |
+
|
| 131 |
+
model_name = "N8Programs/NextTerm-2-440M"
|
| 132 |
+
tokenizer = AutoTokenizer.from_pretrained(model_name)
|
| 133 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 134 |
+
model_name,
|
| 135 |
+
dtype=torch.bfloat16,
|
| 136 |
+
device_map="auto",
|
| 137 |
+
)
|
| 138 |
+
|
| 139 |
+
prompt = "1,2,3,4,5,"
|
| 140 |
+
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
|
| 141 |
+
|
| 142 |
+
outputs = model.generate(
|
| 143 |
+
**inputs,
|
| 144 |
+
max_new_tokens=64,
|
| 145 |
+
do_sample=False,
|
| 146 |
+
eos_token_id=[tokenizer.convert_tokens_to_ids(","), tokenizer.eos_token_id],
|
| 147 |
+
pad_token_id=tokenizer.pad_token_id,
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
|
| 151 |
+
```
|
| 152 |
+
|
| 153 |
+
For strict next-term evaluation, stop generation on *comma or EOS* and parse the
|
| 154 |
+
text before the first comma as the predicted integer. The tokenizer adds BOS
|
| 155 |
+
automatically.
|
| 156 |
+
|
| 157 |
+
## Reproducibility
|
| 158 |
+
|
| 159 |
+
This repository contains the evaluation scripts and data used for the results above:
|
| 160 |
+
|
| 161 |
+
- `eval_neo.py` for OEIS-Eval-Neo (and the polynomial sets).
|
| 162 |
+
- `gen_poly_evals.py` to regenerate the arithmetic/quadratic/cubic/quartic sets.
|
| 163 |
+
- `eval_m1.py` for M1 Competition 111 MAPE.
|
| 164 |
+
- `eval_ryskina.py` for Ryskina & Knight.
|
| 165 |
+
- `oeis_val_neo.jsonl`, `m1_competition_111.jsonl` and `ryskina_knight_57.jsonl`.
|
| 166 |
+
- `eval_results.txt` for the compact result table.
|
| 167 |
+
|
| 168 |
+
The model was trained with [spark-gpt](https://github.com/N8python/spark-gpt) on the
|
| 169 |
+
[N8Programs/oeis-ladder-10b](https://huggingface.co/datasets/N8Programs/oeis-ladder-10b)
|
| 170 |
+
dataset, whose card documents the data recipe in full.
|
| 171 |
+
|
| 172 |
+
## Citation
|
| 173 |
+
|
| 174 |
+
```bibtex
|
| 175 |
+
@misc{nextterm2_2026,
|
| 176 |
+
author = {Nathan Breslow and Opus 5.5},
|
| 177 |
+
title = {NextTerm-2: A Scaling Ladder of Pretrained Transformers for Integer Sequence Prediction},
|
| 178 |
+
year = {2026},
|
| 179 |
+
publisher = {Hugging Face},
|
| 180 |
+
howpublished = {\url{https://huggingface.co/N8Programs/NextTerm-2-440M}},
|
| 181 |
+
note = {441M parameter model trained on 10B tokens of augmented OEIS data}
|
| 182 |
+
}
|
| 183 |
+
```
|
| 184 |
+
|
| 185 |
+
## Attribution
|
| 186 |
+
|
| 187 |
+
This model was trained on data from the
|
| 188 |
+
**On-Line Encyclopedia of Integer Sequences (OEIS)**.
|
| 189 |
+
|
| 190 |
+
- Source: https://oeis.org/
|
| 191 |
+
- License: Creative Commons Attribution-ShareAlike 4.0 (CC BY-SA 4.0)
|
| 192 |
+
- OEIS End-User License Agreement: https://oeis.org/wiki/The_OEIS_End-User_License_Agreement
|
config.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"Qwen3ForCausalLM"
|
| 4 |
+
],
|
| 5 |
+
"model_type": "qwen3",
|
| 6 |
+
"vocab_size": 259,
|
| 7 |
+
"hidden_size": 1024,
|
| 8 |
+
"num_hidden_layers": 28,
|
| 9 |
+
"intermediate_size": 3072,
|
| 10 |
+
"num_attention_heads": 16,
|
| 11 |
+
"num_key_value_heads": 8,
|
| 12 |
+
"head_dim": 128,
|
| 13 |
+
"hidden_act": "silu",
|
| 14 |
+
"rms_norm_eps": 1e-06,
|
| 15 |
+
"max_position_embeddings": 4096,
|
| 16 |
+
"rope_theta": 1000000.0,
|
| 17 |
+
"rope_scaling": null,
|
| 18 |
+
"attention_bias": false,
|
| 19 |
+
"attention_dropout": 0.0,
|
| 20 |
+
"tie_word_embeddings": false,
|
| 21 |
+
"use_cache": true,
|
| 22 |
+
"bos_token_id": 256,
|
| 23 |
+
"eos_token_id": 257,
|
| 24 |
+
"pad_token_id": 258,
|
| 25 |
+
"torch_dtype": "bfloat16"
|
| 26 |
+
}
|
eval_m1.py
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""M1 Competition 111 forecasting eval (macro MAPE) for byte-level spark-gpt OEIS checkpoints.
|
| 2 |
+
|
| 3 |
+
A PyTorch port of eval_m1_competition_mape_mlx.py from the NextTerm-440M repository (the protocol
|
| 4 |
+
behind the NextTerm model cards: Naive2 17.7987, NextTerm-440M 17.6239, NextTerm-47M 18.7621),
|
| 5 |
+
unchanged in substance:
|
| 6 |
+
* each series' context is scaled to integers by the largest number of decimal places visible
|
| 7 |
+
in the context, joined by commas, with a trailing comma
|
| 8 |
+
* greedy decoding with EOS and PAD suppressed, stopping once `horizon` commas are generated
|
| 9 |
+
(or after --max-new-tokens); series are decoded together in left-padded batches with
|
| 10 |
+
per-row stopping (same greedy result as one at a time, up to batching numerics)
|
| 11 |
+
* the first `horizon` generated integers, divided back by the scale, are the forecast;
|
| 12 |
+
missing terms are scored as 0 (missing_policy "zero")
|
| 13 |
+
* series MAPE = mean APE over the horizon (zero actuals skipped); macro MAPE = mean over series
|
| 14 |
+
(the number on the model cards); median MAPE = median over series is also reported, since
|
| 15 |
+
one runaway forecast (e.g. a parabola on a flat series, APE ~700) can swing the macro mean
|
| 16 |
+
by several points
|
| 17 |
+
* prompts of --max-context-tokens or more tokens (BOS included) are skipped
|
| 18 |
+
|
| 19 |
+
Usage: python eval_m1.py <hf_dir> <m1_competition_111.jsonl> <out_prefix>
|
| 20 |
+
Writes <out_prefix>.series.jsonl and <out_prefix>.summary.json.
|
| 21 |
+
"""
|
| 22 |
+
import argparse
|
| 23 |
+
import json
|
| 24 |
+
import math
|
| 25 |
+
from decimal import Decimal, InvalidOperation, localcontext
|
| 26 |
+
from statistics import mean, median
|
| 27 |
+
|
| 28 |
+
import torch
|
| 29 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def parse_decimal(raw):
|
| 33 |
+
try:
|
| 34 |
+
value = Decimal(str(raw).strip())
|
| 35 |
+
except InvalidOperation as exc:
|
| 36 |
+
raise ValueError(f"Could not parse decimal value {raw!r}") from exc
|
| 37 |
+
if not value.is_finite():
|
| 38 |
+
raise ValueError(f"Non-finite decimal value {raw!r}")
|
| 39 |
+
return value
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def context_scale(raw_context):
|
| 43 |
+
places = 0
|
| 44 |
+
for raw in raw_context:
|
| 45 |
+
exponent = parse_decimal(raw).as_tuple().exponent
|
| 46 |
+
if exponent < 0:
|
| 47 |
+
places = max(places, -exponent)
|
| 48 |
+
return 10 ** places
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def scale_decimal_to_int(value, scale):
|
| 52 |
+
scaled = value * Decimal(scale)
|
| 53 |
+
with localcontext() as ctx:
|
| 54 |
+
ctx.prec = max(50, len(scaled.as_tuple().digits) + 10)
|
| 55 |
+
rounded = scaled.to_integral_value()
|
| 56 |
+
if rounded != scaled:
|
| 57 |
+
raise ValueError(f"Context scale {scale} does not make {value} integral")
|
| 58 |
+
return int(rounded)
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def parse_generated_terms(text, limit):
|
| 62 |
+
terms, current, malformed = [], [], False
|
| 63 |
+
|
| 64 |
+
def flush():
|
| 65 |
+
nonlocal malformed
|
| 66 |
+
if not current:
|
| 67 |
+
return
|
| 68 |
+
token = "".join(current)
|
| 69 |
+
current.clear()
|
| 70 |
+
if token == "-":
|
| 71 |
+
malformed = True
|
| 72 |
+
return
|
| 73 |
+
try:
|
| 74 |
+
terms.append(int(token))
|
| 75 |
+
except ValueError:
|
| 76 |
+
malformed = True
|
| 77 |
+
|
| 78 |
+
for ch in text:
|
| 79 |
+
if len(terms) >= limit:
|
| 80 |
+
break
|
| 81 |
+
if ch.isdigit() or (ch == "-" and not current):
|
| 82 |
+
current.append(ch)
|
| 83 |
+
elif ch == ",":
|
| 84 |
+
flush()
|
| 85 |
+
elif ch.isspace():
|
| 86 |
+
continue
|
| 87 |
+
else:
|
| 88 |
+
malformed = True
|
| 89 |
+
flush()
|
| 90 |
+
break
|
| 91 |
+
if len(terms) < limit:
|
| 92 |
+
flush()
|
| 93 |
+
return terms[:limit], malformed
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def ape(actual, prediction):
|
| 97 |
+
if actual == 0:
|
| 98 |
+
return None
|
| 99 |
+
return float(abs(actual - prediction) / abs(actual) * Decimal(100))
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def mape_for_predictions(actuals, predictions, missing_policy, fallback):
|
| 103 |
+
apes, missing = [], 0
|
| 104 |
+
for actual, pred in zip(actuals, predictions):
|
| 105 |
+
if pred is None:
|
| 106 |
+
missing += 1
|
| 107 |
+
if missing_policy == "skip":
|
| 108 |
+
apes.append(None)
|
| 109 |
+
continue
|
| 110 |
+
pred = Decimal(0) if missing_policy == "zero" else fallback
|
| 111 |
+
apes.append(ape(actual, pred))
|
| 112 |
+
valid = [x for x in apes if x is not None and math.isfinite(x)]
|
| 113 |
+
return (mean(valid) if valid else None), apes, missing
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def main():
|
| 117 |
+
p = argparse.ArgumentParser()
|
| 118 |
+
p.add_argument("hf_dir")
|
| 119 |
+
p.add_argument("data")
|
| 120 |
+
p.add_argument("out_prefix")
|
| 121 |
+
p.add_argument("--max-new-tokens", type=int, default=1024)
|
| 122 |
+
p.add_argument("--max-context-tokens", type=int, default=2048)
|
| 123 |
+
p.add_argument("--missing-policy", choices=["zero", "last_context", "skip"], default="zero")
|
| 124 |
+
p.add_argument("--batch-size", type=int, default=128,
|
| 125 |
+
help="series decoded together (greedy, left-padded, per-row stopping)")
|
| 126 |
+
args = p.parse_args()
|
| 127 |
+
|
| 128 |
+
tok = AutoTokenizer.from_pretrained(args.hf_dir)
|
| 129 |
+
model = AutoModelForCausalLM.from_pretrained(args.hf_dir, dtype=torch.float32).cuda().eval()
|
| 130 |
+
bos, eos, pad = tok.bos_token_id, tok.eos_token_id, tok.pad_token_id
|
| 131 |
+
comma = ord(",")
|
| 132 |
+
suppress = torch.tensor([t for t in (eos, pad) if t is not None], device="cuda")
|
| 133 |
+
|
| 134 |
+
rows = [json.loads(line) for line in open(args.data) if line.strip()]
|
| 135 |
+
series = []
|
| 136 |
+
skipped_long = 0
|
| 137 |
+
for row in rows:
|
| 138 |
+
raw_context = [str(x) for x in row["context"]]
|
| 139 |
+
context = [parse_decimal(x) for x in raw_context]
|
| 140 |
+
scale = context_scale(raw_context)
|
| 141 |
+
prompt_text = ",".join(str(scale_decimal_to_int(v, scale)) for v in context) + ","
|
| 142 |
+
prompt = [bos] + list(prompt_text.encode("utf-8"))
|
| 143 |
+
assert tok(prompt_text).input_ids == prompt, "tokenizer disagrees with BOS + bytes"
|
| 144 |
+
if args.max_context_tokens > 0 and len(prompt) >= args.max_context_tokens:
|
| 145 |
+
skipped_long += 1
|
| 146 |
+
continue
|
| 147 |
+
series.append((row, raw_context, context, scale, prompt, int(row["horizon"])))
|
| 148 |
+
|
| 149 |
+
@torch.no_grad()
|
| 150 |
+
def greedy_batch(batch):
|
| 151 |
+
"""Greedy decode a left-padded batch with a KV cache, EOS/PAD suppressed; each row
|
| 152 |
+
stops once it has generated `horizon` commas (or after --max-new-tokens)."""
|
| 153 |
+
width = max(len(s[4]) for s in batch)
|
| 154 |
+
ids = torch.full((len(batch), width), pad, dtype=torch.long, device="cuda")
|
| 155 |
+
mask = torch.zeros((len(batch), width), dtype=torch.long, device="cuda")
|
| 156 |
+
for r, s in enumerate(batch):
|
| 157 |
+
ids[r, width - len(s[4]):] = torch.tensor(s[4], device="cuda")
|
| 158 |
+
mask[r, width - len(s[4]):] = 1
|
| 159 |
+
pos = (mask.cumsum(-1) - 1).clamp(min=0)
|
| 160 |
+
out = model(ids, attention_mask=mask, position_ids=pos, use_cache=True)
|
| 161 |
+
past, logits = out.past_key_values, out.logits[:, -1]
|
| 162 |
+
horizon = torch.tensor([s[5] for s in batch], device="cuda")
|
| 163 |
+
commas = torch.zeros(len(batch), dtype=torch.long, device="cuda")
|
| 164 |
+
done = torch.zeros(len(batch), dtype=torch.bool, device="cuda")
|
| 165 |
+
last_pos = pos[:, -1]
|
| 166 |
+
generated = []
|
| 167 |
+
for _ in range(args.max_new_tokens):
|
| 168 |
+
logits = logits.float()
|
| 169 |
+
logits[:, suppress] = float("-inf")
|
| 170 |
+
nxt = logits.argmax(-1)
|
| 171 |
+
generated.append(torch.where(done, torch.full_like(nxt, pad), nxt))
|
| 172 |
+
commas += (nxt == comma) & ~done
|
| 173 |
+
done |= commas >= horizon
|
| 174 |
+
if bool(done.all()):
|
| 175 |
+
break
|
| 176 |
+
mask = torch.cat([mask, torch.ones_like(mask[:, :1])], dim=1)
|
| 177 |
+
last_pos = last_pos + 1
|
| 178 |
+
out = model(nxt[:, None], attention_mask=mask, position_ids=last_pos[:, None],
|
| 179 |
+
past_key_values=past, use_cache=True)
|
| 180 |
+
past, logits = out.past_key_values, out.logits[:, -1]
|
| 181 |
+
gen = torch.stack(generated, dim=1).tolist()
|
| 182 |
+
return [bytes(t for t in g if t < 256).decode("utf-8", "replace") for g in gen]
|
| 183 |
+
|
| 184 |
+
texts = []
|
| 185 |
+
for b in range(0, len(series), args.batch_size):
|
| 186 |
+
texts.extend(greedy_batch(series[b:b + args.batch_size]))
|
| 187 |
+
|
| 188 |
+
records = []
|
| 189 |
+
for (row, raw_context, context, scale, prompt, horizon), text in zip(series, texts):
|
| 190 |
+
target = [parse_decimal(str(x)) for x in row["target"]]
|
| 191 |
+
naive2 = [parse_decimal(str(x)) for x in row["naive2_forecast"]]
|
| 192 |
+
terms, malformed = parse_generated_terms(text, horizon)
|
| 193 |
+
predictions = [Decimal(t) / Decimal(scale) for t in terms] + [None] * (horizon - len(terms))
|
| 194 |
+
fallback = context[-1] if context else Decimal(0)
|
| 195 |
+
mape, apes, missing = mape_for_predictions(target, predictions, args.missing_policy, fallback)
|
| 196 |
+
naive2_mape, naive2_apes, _ = mape_for_predictions(target, naive2, "skip", fallback)
|
| 197 |
+
records.append({
|
| 198 |
+
"row_index": row["row_index"], "series_name": row["series_name"], "period": row["period"],
|
| 199 |
+
"horizon": horizon, "scale": scale, "prompt_tokens": len(prompt),
|
| 200 |
+
"target": [str(x) for x in target],
|
| 201 |
+
"prediction": [str(x) if x is not None else None for x in predictions],
|
| 202 |
+
"parsed_terms": len(terms), "missing_terms": missing, "malformed": malformed,
|
| 203 |
+
"mape": mape, "apes": apes, "naive2_mape": naive2_mape, "naive2_apes": naive2_apes,
|
| 204 |
+
"generated_text": text,
|
| 205 |
+
})
|
| 206 |
+
|
| 207 |
+
def finite(rs, key):
|
| 208 |
+
return [float(r[key]) for r in rs if r[key] is not None and math.isfinite(float(r[key]))]
|
| 209 |
+
|
| 210 |
+
def macro(rs, key):
|
| 211 |
+
vals = finite(rs, key)
|
| 212 |
+
return mean(vals) if vals else None
|
| 213 |
+
|
| 214 |
+
def med(rs, key):
|
| 215 |
+
vals = finite(rs, key)
|
| 216 |
+
return median(vals) if vals else None
|
| 217 |
+
|
| 218 |
+
by_period = {}
|
| 219 |
+
for period in sorted({r["period"] for r in records}):
|
| 220 |
+
rs = [r for r in records if r["period"] == period]
|
| 221 |
+
by_period[period] = {"series": len(rs),
|
| 222 |
+
"model_median_series_mape": med(rs, "mape"),
|
| 223 |
+
"model_macro_mape": macro(rs, "mape"),
|
| 224 |
+
"naive2_median_series_mape": med(rs, "naive2_mape"),
|
| 225 |
+
"naive2_macro_mape": macro(rs, "naive2_mape")}
|
| 226 |
+
summary = {
|
| 227 |
+
"checkpoint": args.hf_dir,
|
| 228 |
+
"series_evaluated": len(records),
|
| 229 |
+
"skipped_long": skipped_long,
|
| 230 |
+
"model_median_series_mape": med(records, "mape"),
|
| 231 |
+
"model_macro_mape": macro(records, "mape"),
|
| 232 |
+
"naive2_median_series_mape": med(records, "naive2_mape"),
|
| 233 |
+
"naive2_macro_mape": macro(records, "naive2_mape"),
|
| 234 |
+
"parsed_full_series": sum(1 for r in records if r["parsed_terms"] >= r["horizon"]),
|
| 235 |
+
"total_missing_terms": sum(r["missing_terms"] for r in records),
|
| 236 |
+
"malformed_series": sum(1 for r in records if r["malformed"]),
|
| 237 |
+
"by_period": by_period,
|
| 238 |
+
}
|
| 239 |
+
with open(args.out_prefix + ".series.jsonl", "w") as f:
|
| 240 |
+
for r in records:
|
| 241 |
+
f.write(json.dumps(r) + "\n")
|
| 242 |
+
with open(args.out_prefix + ".summary.json", "w") as f:
|
| 243 |
+
json.dump(summary, f, indent=2)
|
| 244 |
+
print(json.dumps({k: summary[k] for k in ["series_evaluated", "skipped_long",
|
| 245 |
+
"model_median_series_mape", "naive2_median_series_mape",
|
| 246 |
+
"model_macro_mape", "naive2_macro_mape", "parsed_full_series",
|
| 247 |
+
"total_missing_terms", "malformed_series"]}))
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
if __name__ == "__main__":
|
| 251 |
+
main()
|
eval_neo.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""OEIS-Eval-Neo: last-term exact-match accuracy on the decontaminated held-out OEIS set.
|
| 2 |
+
|
| 3 |
+
A batched PyTorch/transformers port of oeis_eval_mlx_neo.py from the NextTerm-440M repository
|
| 4 |
+
(the protocol behind that card's 34.43%), unchanged in substance:
|
| 5 |
+
* rows with fewer than 2 terms are skipped; prompt = every term but the last, comma-joined, with
|
| 6 |
+
a trailing comma; answer = the last term (compared as an exact integer)
|
| 7 |
+
* prompts of --max-context-tokens or more tokens (BOS included) are skipped
|
| 8 |
+
* greedy decoding, stopping at the comma token or EOS, up to --max-new-tokens (196)
|
| 9 |
+
* prediction = the generated text before the first comma, parsed as an integer
|
| 10 |
+
(unparseable, e.g. an immediate EOS, counts as wrong)
|
| 11 |
+
Works with any tokenizer that has a single comma token (the byte-level spark-gpt checkpoints, or
|
| 12 |
+
the NextTerm digit tokenizer).
|
| 13 |
+
|
| 14 |
+
Two modes, same accuracy: --mode teacher (default) checks greedy correctness in one forward pass
|
| 15 |
+
over prompt + answer + "," (correct iff the argmax reproduces every answer token and is then a
|
| 16 |
+
comma or EOS, which is exactly when greedy decoding would produce the answer); --mode generate
|
| 17 |
+
decodes greedily.
|
| 18 |
+
|
| 19 |
+
Usage: python eval_neo.py <hf_dir> <oeis_val_neo.jsonl> <out_prefix> [--batch-size 128]
|
| 20 |
+
Writes <out_prefix>.rows.jsonl and <out_prefix>.summary.json.
|
| 21 |
+
"""
|
| 22 |
+
import argparse
|
| 23 |
+
import json
|
| 24 |
+
import time
|
| 25 |
+
|
| 26 |
+
import torch
|
| 27 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def parse_generated(text):
|
| 31 |
+
text = text.split(",")[0]
|
| 32 |
+
try:
|
| 33 |
+
return int(text)
|
| 34 |
+
except ValueError:
|
| 35 |
+
return None
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def main():
|
| 39 |
+
p = argparse.ArgumentParser()
|
| 40 |
+
p.add_argument("hf_dir")
|
| 41 |
+
p.add_argument("data")
|
| 42 |
+
p.add_argument("out_prefix")
|
| 43 |
+
p.add_argument("--batch-size", type=int, default=128)
|
| 44 |
+
p.add_argument("--max-new-tokens", type=int, default=196)
|
| 45 |
+
p.add_argument("--first-pass-tokens", type=int, default=24,
|
| 46 |
+
help="decode budget for the first pass; unfinished rows are redone at --max-new-tokens")
|
| 47 |
+
p.add_argument("--max-context-tokens", type=int, default=4096)
|
| 48 |
+
p.add_argument("--max-examples", type=int, default=0)
|
| 49 |
+
p.add_argument("--dtype", choices=["float32", "bfloat16"], default="bfloat16")
|
| 50 |
+
p.add_argument("--mode", choices=["teacher", "generate"], default="teacher",
|
| 51 |
+
help="teacher: one forward pass per row (exact for greedy); generate: decode")
|
| 52 |
+
args = p.parse_args()
|
| 53 |
+
|
| 54 |
+
started = time.perf_counter()
|
| 55 |
+
tok = AutoTokenizer.from_pretrained(args.hf_dir)
|
| 56 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 57 |
+
args.hf_dir, dtype=getattr(torch, args.dtype)).cuda().eval()
|
| 58 |
+
comma = tok.encode(",", add_special_tokens=False)
|
| 59 |
+
if not comma: # the NextTerm tokenizer strips a leading comma
|
| 60 |
+
comma = tok.encode("1,", add_special_tokens=False)[-1:]
|
| 61 |
+
assert len(comma) == 1, f"comma is not a single token: {comma}"
|
| 62 |
+
comma = comma[0]
|
| 63 |
+
stops = [comma] + ([tok.eos_token_id] if tok.eos_token_id is not None else [])
|
| 64 |
+
pad = tok.pad_token_id if tok.pad_token_id is not None else tok.eos_token_id
|
| 65 |
+
|
| 66 |
+
prompts, answers, rows = [], [], []
|
| 67 |
+
for i, line in enumerate(open(args.data)):
|
| 68 |
+
seq = json.loads(line, parse_int=str).get("seq", [])
|
| 69 |
+
if len(seq) < 2:
|
| 70 |
+
continue
|
| 71 |
+
prompts.append(tok(",".join(str(x) for x in seq[:-1]) + ",").input_ids)
|
| 72 |
+
answers.append(int(seq[-1]))
|
| 73 |
+
rows.append(i)
|
| 74 |
+
if args.max_examples > 0:
|
| 75 |
+
prompts, answers, rows = prompts[:args.max_examples], answers[:args.max_examples], rows[:args.max_examples]
|
| 76 |
+
keep = [k for k, pr in enumerate(prompts)
|
| 77 |
+
if args.max_context_tokens <= 0 or len(pr) < args.max_context_tokens]
|
| 78 |
+
skipped_long = len(prompts) - len(keep)
|
| 79 |
+
keep.sort(key=lambda k: len(prompts[k]))
|
| 80 |
+
|
| 81 |
+
def greedy(idx, max_new):
|
| 82 |
+
"""Greedy-decode prompts idx (left-padded batches); return {k: tokens before the stop}
|
| 83 |
+
and the set of k that hit a stop token."""
|
| 84 |
+
gens, stopped = {}, set()
|
| 85 |
+
for b in range(0, len(idx), args.batch_size):
|
| 86 |
+
batch = idx[b:b + args.batch_size]
|
| 87 |
+
width = max(len(prompts[k]) for k in batch)
|
| 88 |
+
ids = torch.full((len(batch), width), pad, dtype=torch.long)
|
| 89 |
+
mask = torch.zeros((len(batch), width), dtype=torch.long)
|
| 90 |
+
for r, k in enumerate(batch):
|
| 91 |
+
ids[r, width - len(prompts[k]):] = torch.tensor(prompts[k])
|
| 92 |
+
mask[r, width - len(prompts[k]):] = 1
|
| 93 |
+
out = model.generate(ids.cuda(), attention_mask=mask.cuda(), do_sample=False,
|
| 94 |
+
max_new_tokens=max_new, eos_token_id=stops, pad_token_id=pad)
|
| 95 |
+
for r, k in enumerate(batch):
|
| 96 |
+
gen = out[r, width:].tolist()
|
| 97 |
+
cut = next((j for j, t in enumerate(gen) if t in stops), None)
|
| 98 |
+
if cut is not None:
|
| 99 |
+
stopped.add(k)
|
| 100 |
+
gens[k] = gen[:cut] if cut is not None else gen[:max_new]
|
| 101 |
+
return gens, stopped
|
| 102 |
+
|
| 103 |
+
results = []
|
| 104 |
+
if args.mode == "generate":
|
| 105 |
+
with torch.no_grad():
|
| 106 |
+
# Most answers are short. Decode everything briefly, then redo only rows that have
|
| 107 |
+
# not reached a stop token with the full budget (equivalent under greedy decoding).
|
| 108 |
+
gens, stopped = greedy(keep, min(args.first_pass_tokens, args.max_new_tokens))
|
| 109 |
+
long_rows = [k for k in keep if k not in stopped]
|
| 110 |
+
if long_rows and args.first_pass_tokens < args.max_new_tokens:
|
| 111 |
+
more, _ = greedy(long_rows, args.max_new_tokens)
|
| 112 |
+
gens.update(more)
|
| 113 |
+
for k in keep:
|
| 114 |
+
text = tok.decode(gens[k], skip_special_tokens=True)
|
| 115 |
+
pred = parse_generated(text)
|
| 116 |
+
results.append({"row_index": rows[k], "answer": str(answers[k]),
|
| 117 |
+
"prediction": None if pred is None else str(pred),
|
| 118 |
+
"correct": pred == answers[k], "parsed": pred is not None,
|
| 119 |
+
"generated_text": text})
|
| 120 |
+
else:
|
| 121 |
+
# Teacher-forced check, one forward pass per row: greedy decoding emits exactly the
|
| 122 |
+
# answer iff the argmax at every answer position is the answer's next token and the
|
| 123 |
+
# argmax after the last digit is a stop token. (Only differs from `generate` mode if a
|
| 124 |
+
# model emits leading zeros, which int() parsing would forgive.)
|
| 125 |
+
ans_ids = {k: tok.encode(str(answers[k]), add_special_tokens=False) for k in keep}
|
| 126 |
+
stop_t = torch.tensor(stops, device="cuda")
|
| 127 |
+
with torch.no_grad():
|
| 128 |
+
for b in range(0, len(keep), args.batch_size):
|
| 129 |
+
batch = keep[b:b + args.batch_size]
|
| 130 |
+
seqs = [prompts[k] + ans_ids[k] for k in batch]
|
| 131 |
+
width = max(map(len, seqs))
|
| 132 |
+
ids = torch.full((len(batch), width), pad, dtype=torch.long)
|
| 133 |
+
mask = torch.zeros((len(batch), width), dtype=torch.long)
|
| 134 |
+
for r, s in enumerate(seqs): # right padding is fine for teacher forcing
|
| 135 |
+
ids[r, :len(s)] = torch.tensor(s)
|
| 136 |
+
mask[r, :len(s)] = 1
|
| 137 |
+
top = model(ids.cuda(), attention_mask=mask.cuda()).logits.argmax(-1)
|
| 138 |
+
for r, k in enumerate(batch):
|
| 139 |
+
n_p, ans = len(prompts[k]), ans_ids[k]
|
| 140 |
+
pred = top[r, n_p - 1:n_p + len(ans)]
|
| 141 |
+
ok = (len(ans) < args.max_new_tokens
|
| 142 |
+
and bool((pred[:-1] == torch.tensor(ans, device="cuda")).all())
|
| 143 |
+
and bool(torch.isin(pred[-1], stop_t)))
|
| 144 |
+
results.append({"row_index": rows[k], "answer": str(answers[k]),
|
| 145 |
+
"correct": ok, "parsed": True})
|
| 146 |
+
|
| 147 |
+
correct = sum(r["correct"] for r in results)
|
| 148 |
+
summary = {
|
| 149 |
+
"checkpoint": args.hf_dir, "data": args.data, "documents": len(prompts),
|
| 150 |
+
"evaluated": len(results), "skipped_long": skipped_long,
|
| 151 |
+
"parsed": sum(r["parsed"] for r in results), "correct": correct,
|
| 152 |
+
"accuracy": correct / len(results) if results else 0.0,
|
| 153 |
+
"max_new_tokens": args.max_new_tokens, "dtype": args.dtype, "mode": args.mode,
|
| 154 |
+
"seconds": round(time.perf_counter() - started, 1),
|
| 155 |
+
}
|
| 156 |
+
with open(args.out_prefix + ".rows.jsonl", "w") as f:
|
| 157 |
+
for r in sorted(results, key=lambda r: r["row_index"]):
|
| 158 |
+
f.write(json.dumps(r) + "\n")
|
| 159 |
+
with open(args.out_prefix + ".summary.json", "w") as f:
|
| 160 |
+
json.dump(summary, f, indent=2)
|
| 161 |
+
print(json.dumps(summary))
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
if __name__ == "__main__":
|
| 165 |
+
main()
|
eval_results.txt
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
NextTerm-2 evaluation results (released bf16 weights; greedy decoding).
|
| 2 |
+
NextTerm-440M / NextTerm-47M / Naive2 rows are from the NextTerm-440M model card.
|
| 3 |
+
|
| 4 |
+
OEIS-Eval-Neo:
|
| 5 |
+
NextTerm-2-440M - 36.25%
|
| 6 |
+
NextTerm-2-50M - 31.56%
|
| 7 |
+
NextTerm-2-5M - 23.38%
|
| 8 |
+
NextTerm-440M - 34.43%
|
| 9 |
+
NextTerm-47M - 29.49%
|
| 10 |
+
|
| 11 |
+
Ryskina & Knight (2021):
|
| 12 |
+
NextTerm-2-440M - 66.67%
|
| 13 |
+
NextTerm-2-50M - 66.67%
|
| 14 |
+
NextTerm-2-5M - 42.11%
|
| 15 |
+
NextTerm-440M - 52.63%
|
| 16 |
+
NextTerm-47M - 70.18%
|
| 17 |
+
|
| 18 |
+
M1 Competition 111 MAPE (macro; canonical greedy; lower is better):
|
| 19 |
+
Naive2 - 17.7987
|
| 20 |
+
NextTerm-2-440M - 17.1105
|
| 21 |
+
NextTerm-2-50M - 18.3615
|
| 22 |
+
NextTerm-2-5M - 20.8527
|
| 23 |
+
NextTerm-440M - 17.6239
|
| 24 |
+
NextTerm-47M - 18.7621
|
| 25 |
+
|
| 26 |
+
M1 Competition 111 by frequency (macro MAPE):
|
| 27 |
+
Naive2 - monthly 17.3871 / quarterly 19.5958 / yearly 17.1314
|
| 28 |
+
NextTerm-2-440M - monthly 18.5442 / quarterly 16.6647 / yearly 12.7485
|
| 29 |
+
NextTerm-2-50M - monthly 20.7720 / quarterly 16.6578 / yearly 12.1251
|
| 30 |
+
NextTerm-2-5M - monthly 22.3369 / quarterly 23.4687 / yearly 12.7977
|
| 31 |
+
NextTerm-440M - monthly 18.3407 / quarterly 19.0475 / yearly 13.5498
|
| 32 |
+
NextTerm-47M - monthly 21.2719 / quarterly 16.0270 / yearly 13.3741
|
| 33 |
+
|
| 34 |
+
Polynomial continuation evals (accuracy; 200 samples per k):
|
| 35 |
+
Arithmetic (k=2-25): NextTerm-2-440M - 96.15%; NextTerm-2-50M - 96.31%; NextTerm-2-5M - 78.21%; NextTerm-440M - 94.38%; NextTerm-47M - 94.15%
|
| 36 |
+
Quadratic (k=3-25): NextTerm-2-440M - 94.39%; NextTerm-2-50M - 84.11%; NextTerm-2-5M - 23.87%; NextTerm-440M - 86.39%; NextTerm-47M - 81.07%
|
| 37 |
+
Cubic (k=4-25): NextTerm-2-440M - 88.70%; NextTerm-2-50M - 63.95%; NextTerm-2-5M - 1.89%; NextTerm-440M - 75.20%; NextTerm-47M - 37.43%
|
| 38 |
+
Quartic (k=5-25): NextTerm-2-440M - 83.74%; NextTerm-2-50M - 47.86%; NextTerm-2-5M - 0.50%; NextTerm-440M - 67.83%; NextTerm-47M - 15.17%
|
eval_ryskina.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Ryskina & Knight (2021) next-term eval for byte-level spark-gpt OEIS checkpoints.
|
| 2 |
+
|
| 3 |
+
Each item is a short sequence. The prompt is every term but the last, written
|
| 4 |
+
"t1,t2,...,tk," with a trailing comma. The answer is the last term.
|
| 5 |
+
|
| 6 |
+
Two scores per item:
|
| 7 |
+
exact greedy decode until the next comma or EOS; correct iff the text equals
|
| 8 |
+
str(answer). This matches the NextTerm model-card protocol.
|
| 9 |
+
logprob log P(answer is the next term) in nats: the sum of the log-probs of the
|
| 10 |
+
answer's bytes, plus log(P(",") + P(EOS)) at the position after it. A
|
| 11 |
+
continuous score, much less noisy than 57 binary outcomes.
|
| 12 |
+
|
| 13 |
+
Encoding is BOS + UTF-8 bytes, exactly as spark-gpt trains. The script checks
|
| 14 |
+
that the exported HF tokenizer agrees.
|
| 15 |
+
|
| 16 |
+
Usage: python eval_ryskina.py <hf_dir> <ryskina.jsonl> <out_prefix>
|
| 17 |
+
Writes <out_prefix>.items.jsonl and <out_prefix>.summary.json.
|
| 18 |
+
"""
|
| 19 |
+
import json
|
| 20 |
+
import math
|
| 21 |
+
import statistics
|
| 22 |
+
import sys
|
| 23 |
+
|
| 24 |
+
import torch
|
| 25 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 26 |
+
|
| 27 |
+
MAX_NEW_TOKENS = 40 # longest answer is far shorter; a runaway decode just scores wrong
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def main():
|
| 31 |
+
hf_dir, data_path, out_prefix = sys.argv[1:4]
|
| 32 |
+
tok = AutoTokenizer.from_pretrained(hf_dir)
|
| 33 |
+
model = AutoModelForCausalLM.from_pretrained(hf_dir, dtype=torch.float32).cuda().eval()
|
| 34 |
+
bos, eos = tok.bos_token_id, tok.eos_token_id
|
| 35 |
+
comma = ord(",")
|
| 36 |
+
|
| 37 |
+
def encode(text):
|
| 38 |
+
ids = [bos] + list(text.encode("utf-8"))
|
| 39 |
+
assert tok(text).input_ids == ids, f"tokenizer disagrees on {text!r}"
|
| 40 |
+
return ids
|
| 41 |
+
|
| 42 |
+
items = [json.loads(line)["seq"] for line in open(data_path)]
|
| 43 |
+
results = []
|
| 44 |
+
with torch.no_grad():
|
| 45 |
+
for idx, seq in enumerate(items):
|
| 46 |
+
prompt_text = ",".join(str(x) for x in seq[:-1]) + ","
|
| 47 |
+
answer = str(seq[-1])
|
| 48 |
+
prompt = encode(prompt_text)
|
| 49 |
+
|
| 50 |
+
# exact match: greedy until comma / EOS
|
| 51 |
+
ids = torch.tensor([prompt], device="cuda")
|
| 52 |
+
generated = []
|
| 53 |
+
for _ in range(MAX_NEW_TOKENS):
|
| 54 |
+
nxt = int(model(ids).logits[0, -1].argmax())
|
| 55 |
+
if nxt in (comma, eos):
|
| 56 |
+
break
|
| 57 |
+
generated.append(nxt)
|
| 58 |
+
ids = torch.cat([ids, torch.tensor([[nxt]], device="cuda")], dim=1)
|
| 59 |
+
prediction = bytes(b for b in generated if b < 256).decode("utf-8", "replace")
|
| 60 |
+
|
| 61 |
+
# log P(answer is the next term)
|
| 62 |
+
ans_ids = list(answer.encode("utf-8"))
|
| 63 |
+
full = torch.tensor([prompt + ans_ids], device="cuda")
|
| 64 |
+
logp = torch.log_softmax(model(full).logits[0].float(), dim=-1)
|
| 65 |
+
start = len(prompt) - 1 # logits at position i predict token i + 1
|
| 66 |
+
lp_answer = sum(float(logp[start + j, t]) for j, t in enumerate(ans_ids))
|
| 67 |
+
end = logp[start + len(ans_ids)]
|
| 68 |
+
lp_stop = float(torch.logaddexp(end[comma], end[eos]))
|
| 69 |
+
lp = lp_answer + lp_stop
|
| 70 |
+
|
| 71 |
+
results.append({
|
| 72 |
+
"idx": idx,
|
| 73 |
+
"prompt": prompt_text,
|
| 74 |
+
"answer": answer,
|
| 75 |
+
"prediction": prediction,
|
| 76 |
+
"correct": prediction == answer,
|
| 77 |
+
"logprob": lp,
|
| 78 |
+
"logprob_answer_bytes": lp_answer,
|
| 79 |
+
"logprob_stop": lp_stop,
|
| 80 |
+
})
|
| 81 |
+
|
| 82 |
+
lps = [r["logprob"] for r in results]
|
| 83 |
+
n_correct = sum(r["correct"] for r in results)
|
| 84 |
+
summary = {
|
| 85 |
+
"checkpoint": hf_dir,
|
| 86 |
+
"items": len(results),
|
| 87 |
+
"exact_correct": n_correct,
|
| 88 |
+
"exact_acc": n_correct / len(results),
|
| 89 |
+
"mean_logprob": statistics.fmean(lps),
|
| 90 |
+
"median_logprob": statistics.median(lps),
|
| 91 |
+
"mean_answer_prob": statistics.fmean(math.exp(x) for x in lps),
|
| 92 |
+
}
|
| 93 |
+
with open(out_prefix + ".items.jsonl", "w") as f:
|
| 94 |
+
for r in results:
|
| 95 |
+
f.write(json.dumps(r) + "\n")
|
| 96 |
+
with open(out_prefix + ".summary.json", "w") as f:
|
| 97 |
+
json.dump(summary, f, indent=2)
|
| 98 |
+
print(json.dumps(summary, indent=2))
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
if __name__ == "__main__":
|
| 102 |
+
main()
|
gen_poly_evals.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Write the NextTerm-440M card's polynomial-continuation eval sets as jsonl.
|
| 2 |
+
|
| 3 |
+
Reproduces arithmetic_eval.py's sampling exactly (same tasks, coefficient ranges, per-task
|
| 4 |
+
RNG random.Random(seed + degree), same draw order): for each prior-term count k from the
|
| 5 |
+
task's minimum up to --max-terms, --samples-per-k sequences f(0), ..., f(k) of a random
|
| 6 |
+
non-negative-integer polynomial; the prompt is the first k terms and the answer is f(k).
|
| 7 |
+
Each row is {"id", "seq", "k"} with seq = prompt + [answer], so scripts/eval_neo.py
|
| 8 |
+
(last-term exact match; teacher-forced greedy) scores it directly.
|
| 9 |
+
|
| 10 |
+
Degrees 5 and 6 (quintic, sextic; --extended) are an optional extension, not part of the
|
| 11 |
+
published polynomial evals: the x^5 and
|
| 12 |
+
x^6 coefficients are drawn from [0, 9] like x^4's, before the card's draws (highest degree
|
| 13 |
+
first, as the card orders them), so degrees 1-4 stay byte-identical.
|
| 14 |
+
|
| 15 |
+
Usage: python gen_poly_evals.py <out_dir> [--extended] [--seed 0 --max-terms 25 --samples-per-k 200]
|
| 16 |
+
"""
|
| 17 |
+
import argparse
|
| 18 |
+
import json
|
| 19 |
+
import random
|
| 20 |
+
from pathlib import Path
|
| 21 |
+
|
| 22 |
+
COEFF_MAX = {"g": 9, "f": 9, "a": 9, "b": 99, "c": 999, "d": 9999, "e": 99999} # g: x^6, f: x^5
|
| 23 |
+
CARD_TASKS = (("arithmetic", 1, 2), ("quadratic", 2, 3), ("cubic", 3, 4), ("quartic", 4, 5))
|
| 24 |
+
EXTENDED_TASKS = (("quintic", 5, 6), ("sextic", 6, 7))
|
| 25 |
+
|
| 26 |
+
p = argparse.ArgumentParser()
|
| 27 |
+
p.add_argument("out_dir")
|
| 28 |
+
p.add_argument("--seed", type=int, default=0)
|
| 29 |
+
p.add_argument("--max-terms", type=int, default=25)
|
| 30 |
+
p.add_argument("--samples-per-k", type=int, default=200)
|
| 31 |
+
p.add_argument("--extended", action="store_true", help="write quintic and sextic instead")
|
| 32 |
+
args = p.parse_args()
|
| 33 |
+
out = Path(args.out_dir)
|
| 34 |
+
out.mkdir(parents=True, exist_ok=True)
|
| 35 |
+
|
| 36 |
+
for name, degree, min_terms in (EXTENDED_TASKS if args.extended else CARD_TASKS):
|
| 37 |
+
rng = random.Random(args.seed + degree)
|
| 38 |
+
with open(out / f"poly_{name}.jsonl", "w") as f:
|
| 39 |
+
for k in range(min_terms, args.max_terms + 1):
|
| 40 |
+
for i in range(args.samples_per_k):
|
| 41 |
+
g = rng.randint(0, COEFF_MAX["g"]) if degree >= 6 else 0
|
| 42 |
+
f5 = rng.randint(0, COEFF_MAX["f"]) if degree >= 5 else 0
|
| 43 |
+
# identical draw order to arithmetic_eval.sample_coefficients
|
| 44 |
+
a = rng.randint(0, COEFF_MAX["a"]) if degree >= 4 else 0
|
| 45 |
+
b = rng.randint(0, COEFF_MAX["b"]) if degree >= 3 else 0
|
| 46 |
+
c = rng.randint(0, COEFF_MAX["c"]) if degree >= 2 else 0
|
| 47 |
+
d = rng.randint(0, COEFF_MAX["d"]) if degree >= 1 else 0
|
| 48 |
+
e = rng.randint(0, COEFF_MAX["e"])
|
| 49 |
+
seq = [g * x**6 + f5 * x**5 + a * x**4 + b * x**3 + c * x**2 + d * x + e
|
| 50 |
+
for x in range(k + 1)]
|
| 51 |
+
f.write(json.dumps({"id": f"{name}_k{k}_{i}", "seq": seq, "k": k}) + "\n")
|
| 52 |
+
print(name, (args.max_terms - min_terms + 1) * args.samples_per_k, "rows")
|
generation_config.json
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"bos_token_id": 256,
|
| 3 |
+
"eos_token_id": 257,
|
| 4 |
+
"pad_token_id": 258,
|
| 5 |
+
"transformers_version": "5.11.0"
|
| 6 |
+
}
|
m1_competition_111.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9f360e1ef6d63e659abd54e959de5935b7d07b58dfc3aaaf9570c44a38d12fda
|
| 3 |
+
size 882030896
|
oeis_val_neo.jsonl
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
radar_chart.png
ADDED
|
Git LFS Details
|
ryskina_knight_57.jsonl
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"seq": [1, 2, 3, 4, 5], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 2 |
+
{"seq": [0, 2, 4, 6, 8], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 3 |
+
{"seq": [12, 19, 26, 33, 40], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 4 |
+
{"seq": [0, 1, 1, 2, 3, 5, 8], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 5 |
+
{"seq": [13, 15, 20, 22, 27, 29], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 6 |
+
{"seq": [32, 35, 39, 44, 50], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 7 |
+
{"seq": [1, 1, 8, 5, 15, 9, 22], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 8 |
+
{"seq": [89, 76, 65, 52, 41], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 9 |
+
{"seq": [17, -24, 41, -65, 106, -171], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 10 |
+
{"seq": [95, 89, 77, 59, 35], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 11 |
+
{"seq": [1, 3, 6, 10, 15, 21], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 12 |
+
{"seq": [1, 4, 10, 20, 35, 56], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 13 |
+
{"seq": [11, 23, 38, 11, 23, 38], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 14 |
+
{"seq": [6, 28, 12, 14, 24, 7, 48], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 15 |
+
{"seq": [7, 19, 43, 91, 187], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 16 |
+
{"seq": [17, 32, 61, 118, 231], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 17 |
+
{"seq": [23, 25, 28, 32, 34, 37, 41], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 18 |
+
{"seq": [1, 4, 9, 16, 25, 36], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 19 |
+
{"seq": [32, 16, 20, 10, 14, 7, 11], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 20 |
+
{"seq": [1, 1, 2, 6, 24, 120], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 21 |
+
{"seq": [65536, 256, 16, 4], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 22 |
+
{"seq": [32, 112, 392, 1372, 4802, 16807], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 23 |
+
{"seq": [12, 19, 38, 45, 90, 97], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 24 |
+
{"seq": [3, 8, 7, 15, 15, 29, 31, 57], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 25 |
+
{"seq": [1, 3, 19, 49, 93, 151], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 26 |
+
{"seq": [2, 6, 12, 20, 30, 42, 56], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 27 |
+
{"seq": [7, 14, 19, 29, 40, 44, 52], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 28 |
+
{"seq": [819, 648, 497, 366, 255], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 29 |
+
{"seq": [87, 165, 726, 1353, 4884], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 30 |
+
{"seq": [15, 47, 31, 54, 73, 15], "source": "https://www.nibcode.com/en/psychometric-training/test-of-numerical-sequence"}
|
| 31 |
+
{"seq": [4, 8, 16, 32, 64, 128], "source": "https://www.syvum.com/cgi/online/serve.cgi/iq/ar_series3.html?question_hide"}
|
| 32 |
+
{"seq": [2, 3, 5, 7, 11, 13, 17, 19, 23], "source": "https://www.syvum.com/cgi/online/serve.cgi/iq/ar_series3.html?question_hide"}
|
| 33 |
+
{"seq": [500, 475, 425, 350, 250, 125], "source": "https://www.syvum.com/cgi/online/serve.cgi/iq/ar_series3.html?question_hide"}
|
| 34 |
+
{"seq": [200, 196, 180, 116, -140], "source": "https://www.syvum.com/cgi/online/serve.cgi/iq/ar_series3.html?question_hide"}
|
| 35 |
+
{"seq": [2, 3, 4, 12, 6, 23, 8, 36, 10, 51], "source": "https://www.12minprep.com/knowledge-hub/number-series-practice/#sample-questions-horizontal"}
|
| 36 |
+
{"seq": [16, 18, 29, 49, 78], "source": "https://www.12minprep.com/knowledge-hub/number-series-practice/#sample-questions-horizontal"}
|
| 37 |
+
{"seq": [4, 11, 25, 53, 109], "source": "https://www.12minprep.com/knowledge-hub/number-series-practice/#sample-questions-horizontal"}
|
| 38 |
+
{"seq": [29, 41, 53, 65, 77, 89], "source": "https://www.12minprep.com/knowledge-hub/number-series-practice/#sample-questions-horizontal"}
|
| 39 |
+
{"seq": [2, 4, 8, 10, 20, 22], "source": "https://www.12minprep.com/knowledge-hub/number-series-practice/#sample-questions-horizontal"}
|
| 40 |
+
{"seq": [2, 3, 1, 4, 0, 5, -1], "source": "https://www.12minprep.com/knowledge-hub/number-series-practice/#sample-questions-horizontal"}
|
| 41 |
+
{"seq": [6, 18, 0, 24, -6, 30, -12], "source": "https://www.12minprep.com/knowledge-hub/number-series-practice/#sample-questions-horizontal"}
|
| 42 |
+
{"seq": [6, 3, 12, 6, 24, 12, 48], "source": "https://www.12minprep.com/knowledge-hub/number-series-practice/#sample-questions-horizontal"}
|
| 43 |
+
{"seq": [11, 21, 31, 41, 51], "source": "https://iqtestprep.com/number-sequence-test/"}
|
| 44 |
+
{"seq": [48, 42, 36, 30, 24], "source": "https://iqtestprep.com/number-sequence-test/"}
|
| 45 |
+
{"seq": [3, 9, 27, 81, 243], "source": "https://iqtestprep.com/number-sequence-test/"}
|
| 46 |
+
{"seq": [2, 8, 4, 16, 8, 32], "source": "https://iqtestprep.com/number-sequence-test/"}
|
| 47 |
+
{"seq": [249, 254, 127, 132, 66], "source": "https://iqtestprep.com/number-sequence-test/"}
|
| 48 |
+
{"seq": [8, 15, 12, 15, 16, 15, 20], "source": "https://iqtestprep.com/number-sequence-test/"}
|
| 49 |
+
{"seq": [22, 2, 22, 4, 22, 8, 22, 16], "source": "https://iqtestprep.com/number-sequence-test/"}
|
| 50 |
+
{"seq": [324, 361, 400, 441, 484], "source": "https://www.hitbullseye.com/Number-Series-Tricks.php"}
|
| 51 |
+
{"seq": [512, 729, 1000, 1331], "source": "https://www.hitbullseye.com/Number-Series-Tricks.php"}
|
| 52 |
+
{"seq": [4, 36, 324, 2916, 26244], "source": "https://www.hitbullseye.com/Number-Series-Tricks.php"}
|
| 53 |
+
{"seq": [4, 9, 14, 19, 24, 29, 34], "source": "https://www.hitbullseye.com/Number-Series-Tricks.php"}
|
| 54 |
+
{"seq": [1, 3, 6, 10, 15, 21], "source": "https://www.hitbullseye.com/Number-Series-Tricks.php"}
|
| 55 |
+
{"seq": [10, 22, 46, 94, 190, 382], "source": "https://www.hitbullseye.com/Number-Series-Tricks.php"}
|
| 56 |
+
{"seq": [1, 4, 8, 11, 22, 25, 50], "source": "https://www.hitbullseye.com/Number-Series-Tricks.php"}
|
| 57 |
+
{"seq": [1, 2, 6, 36, 44, 440, 452], "source": "https://www.hitbullseye.com/Number-Series-Tricks.php"}
|
tokenizer.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"version": "1.0", "truncation": null, "padding": null, "added_tokens": [{"id": 256, "content": "<bos>", "single_word": false, "lstrip": false, "rstrip": false, "normalized": false, "special": true}, {"id": 257, "content": "<eos>", "single_word": false, "lstrip": false, "rstrip": false, "normalized": false, "special": true}, {"id": 258, "content": "<pad>", "single_word": false, "lstrip": false, "rstrip": false, "normalized": false, "special": true}], "normalizer": null, "pre_tokenizer": {"type": "ByteLevel", "add_prefix_space": false, "trim_offsets": true, "use_regex": true}, "post_processor": {"type": "TemplateProcessing", "single": [{"SpecialToken": {"id": "<bos>", "type_id": 0}}, {"Sequence": {"id": "A", "type_id": 0}}], "pair": [{"SpecialToken": {"id": "<bos>", "type_id": 0}}, {"Sequence": {"id": "A", "type_id": 0}}, {"SpecialToken": {"id": "<bos>", "type_id": 1}}, {"Sequence": {"id": "B", "type_id": 1}}], "special_tokens": {"<bos>": {"id": "<bos>", "ids": [256], "tokens": ["<bos>"]}}}, "decoder": {"type": "ByteLevel", "add_prefix_space": false, "trim_offsets": true, "use_regex": true}, "model": {"type": "BPE", "dropout": null, "unk_token": null, "continuing_subword_prefix": null, "end_of_word_suffix": null, "fuse_unk": false, "byte_fallback": false, "ignore_merges": false, "vocab": {"Ā": 0, "ā": 1, "Ă": 2, "ă": 3, "Ą": 4, "ą": 5, "Ć": 6, "ć": 7, "Ĉ": 8, "ĉ": 9, "Ċ": 10, "ċ": 11, "Č": 12, "č": 13, "Ď": 14, "ď": 15, "Đ": 16, "đ": 17, "Ē": 18, "ē": 19, "Ĕ": 20, "ĕ": 21, "Ė": 22, "ė": 23, "Ę": 24, "ę": 25, "Ě": 26, "ě": 27, "Ĝ": 28, "ĝ": 29, "Ğ": 30, "ğ": 31, "Ġ": 32, "!": 33, "\"": 34, "#": 35, "$": 36, "%": 37, "&": 38, "'": 39, "(": 40, ")": 41, "*": 42, "+": 43, ",": 44, "-": 45, ".": 46, "/": 47, "0": 48, "1": 49, "2": 50, "3": 51, "4": 52, "5": 53, "6": 54, "7": 55, "8": 56, "9": 57, ":": 58, ";": 59, "<": 60, "=": 61, ">": 62, "?": 63, "@": 64, "A": 65, "B": 66, "C": 67, "D": 68, "E": 69, "F": 70, "G": 71, "H": 72, "I": 73, "J": 74, "K": 75, "L": 76, "M": 77, "N": 78, "O": 79, "P": 80, "Q": 81, "R": 82, "S": 83, "T": 84, "U": 85, "V": 86, "W": 87, "X": 88, "Y": 89, "Z": 90, "[": 91, "\\": 92, "]": 93, "^": 94, "_": 95, "`": 96, "a": 97, "b": 98, "c": 99, "d": 100, "e": 101, "f": 102, "g": 103, "h": 104, "i": 105, "j": 106, "k": 107, "l": 108, "m": 109, "n": 110, "o": 111, "p": 112, "q": 113, "r": 114, "s": 115, "t": 116, "u": 117, "v": 118, "w": 119, "x": 120, "y": 121, "z": 122, "{": 123, "|": 124, "}": 125, "~": 126, "ġ": 127, "Ģ": 128, "ģ": 129, "Ĥ": 130, "ĥ": 131, "Ħ": 132, "ħ": 133, "Ĩ": 134, "ĩ": 135, "Ī": 136, "ī": 137, "Ĭ": 138, "ĭ": 139, "Į": 140, "į": 141, "İ": 142, "ı": 143, "IJ": 144, "ij": 145, "Ĵ": 146, "ĵ": 147, "Ķ": 148, "ķ": 149, "ĸ": 150, "Ĺ": 151, "ĺ": 152, "Ļ": 153, "ļ": 154, "Ľ": 155, "ľ": 156, "Ŀ": 157, "ŀ": 158, "Ł": 159, "ł": 160, "¡": 161, "¢": 162, "£": 163, "¤": 164, "¥": 165, "¦": 166, "§": 167, "¨": 168, "©": 169, "ª": 170, "«": 171, "¬": 172, "Ń": 173, "®": 174, "¯": 175, "°": 176, "±": 177, "²": 178, "³": 179, "´": 180, "µ": 181, "¶": 182, "·": 183, "¸": 184, "¹": 185, "º": 186, "»": 187, "¼": 188, "½": 189, "¾": 190, "¿": 191, "À": 192, "Á": 193, "Â": 194, "Ã": 195, "Ä": 196, "Å": 197, "Æ": 198, "Ç": 199, "È": 200, "É": 201, "Ê": 202, "Ë": 203, "Ì": 204, "Í": 205, "Î": 206, "Ï": 207, "Ð": 208, "Ñ": 209, "Ò": 210, "Ó": 211, "Ô": 212, "Õ": 213, "Ö": 214, "×": 215, "Ø": 216, "Ù": 217, "Ú": 218, "Û": 219, "Ü": 220, "Ý": 221, "Þ": 222, "ß": 223, "à": 224, "á": 225, "â": 226, "ã": 227, "ä": 228, "å": 229, "æ": 230, "ç": 231, "è": 232, "é": 233, "ê": 234, "ë": 235, "ì": 236, "í": 237, "î": 238, "ï": 239, "ð": 240, "ñ": 241, "ò": 242, "ó": 243, "ô": 244, "õ": 245, "ö": 246, "÷": 247, "ø": 248, "ù": 249, "ú": 250, "û": 251, "ü": 252, "ý": 253, "þ": 254, "ÿ": 255, "<bos>": 256, "<eos>": 257, "<pad>": 258}, "merges": []}}
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"tokenizer_class": "PreTrainedTokenizerFast",
|
| 3 |
+
"bos_token": "<bos>",
|
| 4 |
+
"eos_token": "<eos>",
|
| 5 |
+
"pad_token": "<pad>",
|
| 6 |
+
"model_max_length": 4096,
|
| 7 |
+
"clean_up_tokenization_spaces": false
|
| 8 |
+
}
|