---
license: apache-2.0
language:
- en
library_name: transformers
pipeline_tag: text-generation
tags:
- causal-lm
- pretraining
- continued-pretraining
- long-context
- math
- code
- from-scratch
- fineweb-edu
- dclm-edu
- single-gpu
- l20
datasets:
- HuggingFaceFW/fineweb-edu
- HuggingFaceTB/smollm-corpus
- HuggingFaceTB/finemath
- HuggingFaceTB/stack-edu
- HuggingFaceTB/dclm-edu
---

# l20-edu-135m

`l20-edu-135m` is a 134.5M-parameter Llama-style causal language model
pretrained from scratch on 10B FineWeb-Edu tokens using a single NVIDIA L20 GPU.

This is a **base model**, not an instruction-tuned chat model. It is released as
a small-model pretraining artifact for research, evaluation, reproducibility,
continued pretraining, and downstream supervised fine-tuning.

## Latest Results

The latest completed checkpoint is the Stage 2 continued-pretraining checkpoint:

`step-001850-stage2-math-code`

Stage 2 starts from the 8K long-context checkpoint and continues training on a
1B-token replay mixture with high-quality educational web data, FineMath,
Stack-Edu code, Cosmopedia-style textbook data, and replay from the earlier
educational corpus. The checkpoint and full eval artifacts are included in this
repository under:

- `step-001850-stage2-math-code/`
- `eval_results/step-001850_sota/`
- `eval_results/current_vs_smollm_summary.md`
- `training_artifacts/`

### Stage 2 Six-Task Benchmark

Zero-shot `lm-eval` results for the Stage 2 checkpoint:

| Task | Metric | Score |
| --- | --- | ---: |
| ARC-Challenge | acc_norm | 0.2765 |
| ARC-Easy | acc_norm | 0.5059 |
| HellaSwag | acc_norm | 0.3272 |
| LAMBADA OpenAI | acc | 0.2540 |
| PIQA | acc_norm | 0.6224 |
| WinoGrande | acc | 0.5099 |

### Current SmolLM Target Comparison

The table below uses the same target tasks as the current SmolLM comparison
script in `training_artifacts/scripts/eval_smollm_benchmark.sh`.

| Task | Metric | ours-stage2 | SmolLM-135M | SmolLM2-135M |
| --- | --- | ---: | ---: | ---: |
| ARC-Challenge | acc_norm | 0.2807 | 0.2875 | 0.2969 |
| ARC-Easy | acc_norm | 0.5059 | 0.5610 | 0.5854 |
| HellaSwag | acc_norm | 0.3242 | 0.4265 | 0.4301 |
| LAMBADA OpenAI | acc | pending rerun | 0.3757 | 0.4289 |
| PIQA | acc_norm | 0.6137 | 0.6823 | 0.6839 |
| WinoGrande | acc | pending rerun | 0.5272 | 0.5249 |

Mean over available matched metrics:

| Model | Mean |
| --- | ---: |
| ours-stage2 | 0.4311 |
| SmolLM-135M | 0.4767 |
| SmolLM2-135M | 0.4917 |

The largest remaining gaps are HellaSwag, PIQA, and ARC-Easy. The next planned
Stage 3 recipe therefore shifts the data mix toward DCLM-Edu and high-quality
general educational web data instead of only increasing math/code data.

## Model Details

| Field | Value |
| --- | --- |
| Model type | Decoder-only causal LM |
| Architecture | Llama-style Transformer |
| Parameters | 134,515,008 |
| Layers | 30 |
| Hidden size | 576 |
| FFN size | 1536 |
| Attention | 9 query heads, 3 key/value heads |
| Context length | 2048 |
| Tokenizer | `HuggingFaceTB/SmolLM2-135M` tokenizer |
| Training data | `HuggingFaceFW/fineweb-edu`, `sample-10BT` |
| Training budget | 10,001,252,352 planned tokens |
| Tokens / parameter | 74.35 |
| Final checkpoint | step 18,928 |
| Hardware | single NVIDIA L20 GPU |

## Training Recipe

| Field | Value |
| --- | --- |
| Sequence length | 2048 tokens |
| Micro batch size | 6 sequences |
| Gradient accumulation | 43 steps |
| Global batch size | 258 sequences |
| Tokens / optimizer step | 528,384 |
| Max steps | 18,928 |
| Optimizer | AdamW |
| Peak learning rate | `4e-4` |
| LR schedule | linear warmup + cosine decay to `0.1 * peak_lr` |
| Warmup | 1,000 steps |
| Weight decay | 0.1 |
| Adam beta1 / beta2 | 0.9 / 0.95 |
| Gradient clipping | 1.0 |
| Precision | bfloat16 |
| Gradient checkpointing | enabled |
| Torch compile | enabled |
| Eval interval | 500 steps |
| Checkpoint interval | 1,000 steps, keeping the last 2 regular checkpoints |

The training config is included in the repository as
`configs/l20_135m_deepthin.yaml`. A fuller recipe is available in
`docs/training_recipe.md`.

## Runtime And Cost Notes

| Field | Value |
| --- | --- |
| GPU | NVIDIA L20 |
| Reported GPU memory | 46,068 MiB total |
| Mean logged throughput | 38,541 tokens/s |
| Mean logged throughput after step 1,000 | 38,587 tokens/s |
| Estimated training time | about 72 GPU-hours |
| Final checkpoint mtime | 2026-05-19 05:04:22 +0800 |

Exact peak VRAM and billing cost were not logged. A reproducible cost estimate
is `72 GPU-hours * L20_hourly_rate`, excluding storage, network egress, idle
time, and engineering time.

Known run issues:

- Transient dataset mirror read timeouts occurred near the end of training and
  recovered through retry.
- The final perplexity command printed `loss=2.8731 perplexity=17.69`, then hit
  a Python finalization crash. The metric is reported because it was printed
  before process teardown.
- The training process printed `terminate called without an active exception`
  after the final checkpoint had been written. The final checkpoint was
  load-tested with `AutoModelForCausalLM`.

## Usage

```python
from transformers import AutoModelForCausalLM, AutoTokenizer

repo = "AliceYin/l20-edu-135m"
tokenizer = AutoTokenizer.from_pretrained(repo)
model = AutoModelForCausalLM.from_pretrained(repo)

prompt = "The capital of France is"
inputs = tokenizer(prompt, return_tensors="pt")
outputs = model.generate(
    **inputs,
    max_new_tokens=40,
    do_sample=True,
    temperature=0.8,
    top_p=0.95,
)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
```

Because this is a base model, completion-style prompts work better than
instruction/chat prompts.

## Evaluation

Final validation:

- Loss: `2.8731`
- Perplexity: `17.69`

Training artifacts:

- `training/training_metrics.csv`
- `training/training_summary.json`
- `training/loss_curve_zoom.png`
- `training/training_curves.png`

![Loss curve after warmup](training/loss_curve_zoom.png)

![Training curves](training/training_curves.png)

Zero-shot `lm-eval` results for the final checkpoint:

| Task | Metric | Score |
| --- | --- | ---: |
| ARC-Challenge | acc_norm | 0.2765 |
| ARC-Easy | acc_norm | 0.5059 |
| HellaSwag | acc_norm | 0.3272 |
| LAMBADA OpenAI | acc | 0.2540 |
| PIQA | acc_norm | 0.6224 |
| WinoGrande | acc | 0.5099 |

### Benchmark Protocol

Candidate and public baseline numbers were run with the same evaluation setup:

| Field | Setting |
| --- | --- |
| Harness | EleutherAI `lm-evaluation-harness` |
| Harness version | `0.4.12` |
| Backend | `--model hf` |
| Device | `cuda:0` |
| Dtype | `bfloat16` |
| Batch size | `auto`, resolved to 64 |
| Few-shot setting | zero-shot |
| Dataset limit | none; full task datasets |
| Samples | `--log_samples` enabled |
| Seeds | harness defaults: Python 0, NumPy 1234, Torch 1234, few-shot 1234 |
| Candidate numbers | self-run on the final checkpoint |
| Baseline numbers | self-run through `scripts/eval_public_baselines.sh`, not copied from leaderboards |

The public baselines were evaluated with the same harness version, task list,
zero-shot setting, dtype, device class, batch policy, and comparison parser. They
were **not** evaluated with the same tokenizer or model context length; each
public model used its own released tokenizer and Hugging Face model config. This
is therefore a public-model benchmark comparison, not a controlled
same-tokenizer architecture comparison.

Public baseline win rates on the same task set:

| Baseline | Wins / Tasks | Win Rate |
| --- | ---: | ---: |
| GPT-2 small | 5 / 6 | 0.833 |
| OPT-125M | 4 / 6 | 0.667 |
| GPT-Neo-125M | 4 / 6 | 0.667 |
| Cerebras-GPT-111M | 6 / 6 | 1.000 |
| Pythia-160M | 6 / 6 | 1.000 |
| SmolLM-135M | 0 / 6 | 0.000 |
| SmolLM2-135M | 0 / 6 | 0.000 |

The full comparison artifacts are included in this repository under:

- `eval/comparison.md`
- `eval/comparison.json`
- `docs/evaluation_report.md`

### Contamination Status

No full benchmark contamination pass is claimed for this release. The project
repository includes `scripts/check_contamination.py` and
`scripts/sample_training_text.py`, but a separate audit against ARC, HellaSwag,
PIQA, LAMBADA, and WinoGrande samples was not completed before release. Because
the model was trained on a public web-scale FineWeb-Edu slice, benchmark overlap
cannot be ruled out without that audit.

## Interpretation

This model is competitive with several older 100M-160M public base models on a
matched `lm-eval` task suite while using only 10B pretraining tokens on one L20.
It is not SOTA and does not beat modern heavily overtrained compact models such
as SmolLM-135M or SmolLM2-135M, which use substantially larger token budgets.

## Intended Use

This checkpoint is suitable for:

- base model evaluation
- continued pretraining experiments
- supervised fine-tuning experiments
- small-model training pipeline demonstrations
- studying single-GPU pretraining tradeoffs

It is not suitable as a production assistant without post-training, safety
evaluation, and domain-specific validation.

## Limitations

- This is a small base model trained on 10B tokens.
- It is not instruction-tuned and may not follow user requests reliably.
- It can produce incorrect facts, repetition, or incomplete generations.
- It has not been safety aligned.
- Benchmark results should not be interpreted as general assistant quality.
- Results should not be described as SOTA without controlled matched-budget
  baselines and contamination checks.

## Training-Budget Context

For fair interpretation, training data size matters:

| Model | Reported Training Budget |
| --- | --- |
| `l20-edu-135m` | 10B FineWeb-Edu tokens |
| GPT-2 small | WebText, about 40GB text; no clean official token count |
| OPT-125M | 180B tokens |
| GPT-Neo-125M | The Pile, commonly reported as 300B tokens |
| Cerebras-GPT-111M | about 2.2B tokens |
| Pythia-160M | about 300B tokens |
| SmolLM-135M | 600B tokens |
| SmolLM2-135M | 2T tokens |

## Citation

If you use this checkpoint, please cite or link to this repository and include
the training-token budget when comparing against other compact language models.
