mini-tron-50 / README.md
Imperius's picture
Update README.md
4f99444 verified
---
language:
- ru
license: apache-2.0
library_name: pytorch
tags:
- text-generation
- russian
- chat
- chatbot
- nanogpt
- small-llm
- sft
- educational
- research
datasets:
ZeroAgency/ru-big-russian-dataset
pipeline_tag: text-generation
inference: false
---
## mini-tron-50 (SFT) (Russian and English)
## English
> **Translator's note:** This is a translation from Russian. Model outputs in the examples below are rendered in English, but originally generated in Russian.
---
A 50M-parameter GPT-2-style language model trained from scratch on a Russian SFT corpus as a chatbot. Illustrates **what can be squeezed out of a model this size** without pretraining on raw text.
Git-source - https://codeberg.org/imperius/mini-tron-50
## TL;DR
- **Architecture**: 10 layer × 8 head × 512 emb (GPT-2 style), 47.85M params
- **Trained from scratch**: SFT on ~1 GB of chat data (1.7M dialogs), 1 epoch
- **Hardware**: 1× RTX 3050 Laptop (4 GB VRAM), 13 hours
- **Tokenizer**: SentencePiece BPE, 32k vocab, custom-trained on the corpus
- **Format**: ChatML with special tokens `<|system|>`, `<|user|>`, `<|assistant|>`, `<|endoftext|>`
- **Loss masking**: only on assistant tokens (standard SFT trick)
- **Status**: SFT phase successful; KTO phase attempted and failed (see below)
The model **has not reached its ceiling** — this is one of its key features. It was trained for exactly one epoch over the corpus (Chinchilla-optimal for 50M), and the loss curves show that validation loss had not yet plateaued. Further training or continued training on new data will likely yield noticeable improvement.
## Architecture
```text
GPTConfig(
n_layer = 10,
n_head = 8,
n_embd = 512,
block_size = 1024,
vocab_size = 32000,
bias = False,
dropout = 0.1,
)
```
Standard GPT-2 without bias. Tied embeddings (`transformer.wte` shared with `lm_head`). Attention uses `F.scaled_dot_product_attention` (flash-attn under the hood on Ampere+).
## Capabilities
| Capability | Quality |
| --- | --- |
| Russian grammar | ✅ flawless (cases, agreement, syntax) |
| Chat format (responds as assistant) | ✅ stable |
| Markdown structure (lists, **bold**, headers) | ✅ imitates GPT-4 style |
| Self-identification ("I am an AI assistant") | ✅ says the right words |
| EOS completion | ✅ usually stops on its own |
| Local coherence (1–2 sentences) | ⚠️ somewhat meaningful in places |
| Response strictly on prompt topic | ⚠️ hears trigger words, not substance |
| Facts and precise knowledge | ❌ hallucinations |
| Arithmetic | ❌ imitates calculation without performing it |
| Multi-step reasoning | ❌ |
| Code (syntax + semantics) | ❌ form is correct, does not work |
## Known failure modes
1. **Canned responses** to simple questions:
```
you> Do you like cats or dogs?
bot> Hello! I'm glad I could help you today. If you have any questions,
feel free to contact us. Good luck!
```
A memorized template tail of ChatGPT-style responses.
2. **Tutorial walls** on any open-ended prompt:
```
you> Tell me about yourself
bot> ### Step 1: Define the task
### Step 2: ...
### Conclusion
```
3. **Token loops** on out-of-distribution prompts:
```
you> Which is greater: 17 or 71?
bot> To calculate... + 112 - 112 + 112 + 112 - 112 + 112 ... [50+ repeats]
```
4. **Semantic mush** in a fully literate wrapper:
```
you> What is 7 times 8?
bot> 5! = (5 × 8) / 8 = 120. Now divide 120 by 8...
So, there are 140 ways to choose 7 times 8 in total.
```
The model imitates the genre of school arithmetic without performing the operation itself.
These failure modes are not cured by SFT, but by preference learning + increasing model size.
## Training data
**Source**: `big-russian-dataset` (HuggingFace) — Russian SFT corpus.
| Split | Dialogs | After filtering |
| --- | --- | --- |
| train | 1.71M | 1,709,621 (99.9%) |
| val | 18.5k | 10,396 (56%) |
**Filter**: `overall_score ≥ 6 AND safety ≥ 8 AND pii_leak = 0`.
In train, the dataset authors had already cleaned out the garbage — there are no records with score < 6, so the filter passes almost everything. In val, the score spread of 1–10 was left intentionally for evaluation on hard examples.
**Volume in tokens**: ~1.04 GB of tokens in train.bin, of which ~603M tokens are under loss (assistant + EOT, 57.7%).
## Training parameters
```python
# AdamW
learning_rate = 3e-4 # cosine decay → min_lr=3e-5
weight_decay = 0.1
beta1, beta2 = 0.9, 0.95
grad_clip = 1.0
# Schedule
warmup_iters = 200
max_iters = 16000 # ~1 epoch
lr_decay_iters = 16000
# Batch
batch_size = 2
gradient_accumulation_steps = 32 # effective batch = 64 sequences
block_size = 1024
# tokens per iter = 65,536
# System
dtype = 'bfloat16'
compile = False
```
## Learning curve
```text
iter 0 loss 10.49 (≈ ln(32000), random initialization)
iter 500 loss ~5 (warmup complete, LR at peak)
iter 5500 loss ~2.4 (first saved checkpoint)
iter 11500 loss ~1.7 (third)
iter 14500 loss ~1.5 (best val_loss ~ 1.8)
iter 16000 loss ~1.45 (max_iters reached)
```
Train-val gap at the end ~1.7 nats — a healthy value for SFT on a small model.
## How to use
The model is distributed in nanoGPT (Karpathy) format. **Not directly compatible with `transformers.AutoModelForCausalLM`** without conversion (weight names differ from GPT-2 standard, specifically no bias).
### Option 1 — via nanoGPT repository (Python)
```bash
git clone https://github.com/karpathy/nanoGPT.git
cd nanoGPT
# copy ckpt.pt, tokenizer.model, meta.pkl here
python chat.py --out_dir=<path-to-checkpoint-dir>
```
The `chat.py` from this release provides an interactive REPL with commands to change temperature, top_p, top_k, and repetition_penalty on the fly.
### Option 2 — via pre-built Go single-binary
This release includes a pre-built `nanogpt-chat.exe` (~97 MB) — a single binary with embedded weights, tokenizer, and config. Runs without Python and without GPU. Performance: ~36 tok/sec on a 4-core CPU.
```bash
./nanogpt-chat.exe
```
REPL commands:
```text
/help help
/show current parameters
/reset reset dialog history
/system <text> change system prompt
/temp <float> temperature (>0)
/top_p <float> nucleus sampling
/top_k <int> top-k
/rep <float> repetition penalty
/preset <name> creative | balanced | precise
/quit exit
```
All commands have single-letter aliases (/h, /s, /r, /q, /t, /p, /k, ...).
### Option 3 — conversion to HuggingFace transformers
Not provided in this release. Requires renaming weights to GPT-2 conventions, adding null biases, and building `GPT2LMHeadModel` with a custom tokenizer (SentencePiece, not GPT-2 BPE). If someone writes a converter — PRs welcome.
## Examples
```text
you> Hello
bot> Hello! I'm ready to help you achieve your goals. Have a great day!
you> Explain in simple words what a black hole is.
bot> First, let's break this down step by step.
### Step 1: Studying a black hole
- This means that a black hole is part of a black hole.
- It can have different sizes...
[grammatically correct, but content is nonsense — this is the 50M ceiling on facts]
you> Write bubble sort in Python.
bot> Here is an example of bubble sort in Python:
```python
def merge_sort(arr):
"""Performs bubble sort in sorted order."""
sorted_array = {}
for i in range(len(arr)):
if arr[i] < sorted_array[i - 1]:
return merge_sort(arr[i], reverse=True)
return sorted_array
```
[function name merge_sort instead of bubble_sort, dictionary instead of two loops —
form is correct, implementation is meaningless]
```
Good prompts for this model are short, conversational, and do not require precise facts:
```text
you> Hi, how are you?
you> My name is Alex. What's yours?
you> Name three fruits.
you> Tell me a short fairy tale.
```
## Limitations
- **Knowledge**: the model does **not** contain reliable facts. Do not ask about dates, names, numbers, geography, biology, or medicine. Any response is an imitation of the reference genre, not real information.
- **Reasoning**: multi-step logic is unavailable. Arithmetic is imitated without execution. Code is syntactically plausible but does not work.
- **Length**: the model was trained with `block_size=1024`. Long dialogs (>800 tokens in history) are truncated from the beginning — the model "forgets" earlier utterances.
- **Languages**: Russian only. On English prompts it will attempt to respond, but quality is worse.
- **Safety**: the model was trained only on the filtered part of the dataset (`safety ≥ 8`), but has no special alignment — behavior on overtly harmful prompts is not guaranteed.
## What didn't work
After SFT, an attempt was made at preference learning via **KTO** to suppress known failure modes. Both attempts (β=0.1 and β=0.03) produced a completely destroyed model — coherent responses turned into semantic garbage. Detailed root-cause analysis is in `04_kto_attempts.md` of the accompanying report.
In short: a combination of (a) a bug in the loss implementation (missing `clamp(z_ref, 0)`) and (b) asymmetric difficulty between chosen data and self-generated rejected. After fixing the bug, degradation still remained, just slower.
A curious side-effect: after KTO, the model drifted not just into noise, but into an "aphoristic-philosophical" register — a recognizable stylistic tail of the distribution that KTO did not suppress.
Only the **SFT checkpoint** is published in this release; KTO weights are not included.
## Fine-tuning opportunities
The model is **not at its ceiling**. Several directions for continuation:
1. **Continued SFT** on an expanded corpus. Especially — add a corpus with factual knowledge (e.g., excerpts from Wikipedia) and code. Every ~30% of new data is worth giving ~1–2 epochs.
2. **Pre-training on raw text** (if you want to push below the 50M quality floor). 1–5 GB of Russian OSCAR/CulturaX before SFT may give a significant boost.
3. **Distillation from an external large model**. The current dataset is already a distill, but generating new responses from Claude / GPT-4o-mini / Yandex YandexGPT on the same prompts will give style diversity.
4. **Preference learning** (DPO/KTO) with **external** rejected (not self-generated). For example, low-score responses from the val split of the same dataset.
5. **Scale up** to 100–200M params with the same hyperparameters and the same corpus. Strongly non-linear quality boost.
## Release files
| File | Size | Description |
| --- | --- | --- |
| `ckpt.pt` | 553 MB | nanoGPT checkpoint (model + optimizer state + config) |
| `tokenizer.model` | 930 KB | SentencePiece tokenizer (BPE 32k) |
| `meta.pkl` | <1 KB | special token IDs + vocab_size |
| `nanogpt-chat.exe` (opt.) | 97 MB | Go single-binary with embedded model |
| `model_card.md` | this file | |
If you only want inference — `tokenizer.model` + `ckpt.pt` is sufficient.
## Citation / acknowledgments
```bibtex
@misc{mini-tron-50,
title = {mini-tron-50: 50M Russian chat model trained from scratch},
author = {Impi},
year = {2026},
note = {Educational baseline; nanoGPT architecture}
}
```
Resources used:
- [nanoGPT](https://github.com/karpathy/nanoGPT) by Andrej Karpathy — foundation of architecture and training loop
- `big-russian-dataset` — training corpus
## License
Apache 2.0 — for code and weights of this model.
## Russian
50M-параметровая GPT-2-style языковая модель, обученная с нуля на русском
SFT-корпусе как чат-бот. Иллюстрирует **что можно
выжать из модели такого размера** без претрейна на сыром тексте.
Git-source - https://codeberg.org/imperius/mini-tron-50
## TL;DR
- **Architecture**: 10 layer × 8 head × 512 emb (GPT-2 style), 47.85M params
- **Trained from scratch**: SFT на ~1 ГБ chat-данных (1.7M диалогов), 1 эпоха
- **Hardware**: 1× RTX 3050 Laptop (4 ГБ VRAM), 13 часов
- **Tokenizer**: SentencePiece BPE, 32k vocab, custom-trained на корпусе
- **Format**: ChatML с спецтокенами `<|system|>`, `<|user|>`, `<|assistant|>`,
`<|endoftext|>`
- **Loss masking**: только на assistant-токенах (стандартный SFT-trick)
- **Status**: SFT-фаза успешна; KTO-фаза проведена и провалилась (см. ниже)
Модель **не достигла своего потолка** — это одна из её особенностей. Она
тренировалась ровно одну эпоху по корпусу (Chinchilla-оптимум для 50M), и
контурные кривые показывают что улучшения val_loss ещё не выходили на плато.
Дальнейшая тренировка или продолжение на новых данных вероятно даст ощутимое
улучшение.
## Архитектура
```text
GPTConfig(
n_layer = 10,
n_head = 8,
n_embd = 512,
block_size = 1024,
vocab_size = 32000,
bias = False,
dropout = 0.1,
)
```
Стандартный GPT-2 без bias. Tied embeddings (`transformer.wte` shared с `lm_head`).
Attention использует `F.scaled_dot_product_attention` (flash-attn под капотом
на Ampere+).
## Что модель умеет
| Способность | Качество |
| --- | --- |
| Грамматика русского | ✅ безупречно (падежи, согласования, синтаксис) |
| Chat-формат (отвечает в роли ассистента) | ✅ устойчиво |
| Markdown-структура (списки, **bold**, заголовки) | ✅ имитирует GPT-4-стиль |
| Самоидентификация ("я ИИ-ассистент") | ✅ говорит правильные слова |
| Завершение по EOS | ✅ обычно сама останавливается |
| Локальная связность 1-2 предложения | ⚠️ местами осмысленно |
| Ответ строго по теме промпта | ⚠️ слышит триггерные слова, не суть |
| Факты и точные знания | ❌ галлюцинации |
| Арифметика | ❌ имитирует подсчёт без него |
| Многошаговый reasoning | ❌ |
| Code (синтаксис + семантика) | ❌ форма правильная, не работает |
## Известные failure modes
1. **Canned-ответы** на простые вопросы:
```
you> Любишь котов или собак?
bot> Привет! Я рад, что смог помочь вам сегодня. Если у вас есть вопросы,
не стесняйтесь обращаться к нам. Удачи!
```
Заученный шаблонный хвост ChatGPT-style ответов.
2. **Tutorial-простыни** на любой открытый промпт:
```
you> Расскажи о себе
bot> ### Шаг 1: Определение задачи
### Шаг 2: ...
### Заключение
```
3. **Token-loops** на промптах вне распределения:
```
you> Что больше: 17 или 71?
bot> Чтобы посчитать... + 112 - 112 + 112 + 112 - 112 + 112 ... [50+ повторов]
```
4. **Семантическая каша** в полностью грамотной обёртке:
```
you> Сколько будет 7 умножить на 8?
bot> 5! = (5 × 8) / 8 = 120. Теперь разделим 120 на 8...
Итак, всего будет 140 способов выбрать 7 умножить на 8.
```
Модель имитирует жанр школьной арифметики, не выполняя саму операцию.
Эти failure modes лечатся не SFT, а preference learning'ом + увеличением
размера модели.
## Тренировочные данные
**Источник**: `big-russian-dataset` (HuggingFace) — русскоязычный SFT-корпус.
| Сплит | Диалогов | После фильтра |
| --- | --- | --- |
| train | 1.71M | 1,709,621 (99.9%) |
| val | 18.5k | 10,396 (56%) |
**Фильтр**: `overall_score ≥ 6 AND safety ≥ 8 AND pii_leak = 0`.
В train авторы датасета сами уже почистили мусор — там нет записей со
score < 6, поэтому фильтр пропускает почти всё. В val разброс score 1-10
оставлен специально для оценки на трудных примерах.
**Объём в токенах**: ~1.04 ГБ токенов в train.bin, из них ~603M токенов под
loss (assistant + EOT, 57.7%).
## Тренировочные параметры
```python
# AdamW
learning_rate = 3e-4 # cosine decay → min_lr=3e-5
weight_decay = 0.1
beta1, beta2 = 0.9, 0.95
grad_clip = 1.0
# Schedule
warmup_iters = 200
max_iters = 16000 # ~1 эпоха
lr_decay_iters = 16000
# Batch
batch_size = 2
gradient_accumulation_steps = 32 # effective batch = 64 sequences
block_size = 1024
# tokens per iter = 65,536
# System
dtype = 'bfloat16'
compile = False
```
## Кривая обучения
```text
iter 0 loss 10.49 (≈ ln(32000), стартовая случайная инициализация)
iter 500 loss ~5 (warmup закончен, LR на peak)
iter 5500 loss ~2.4 (первый saved checkpoint)
iter 11500 loss ~1.7 (третий)
iter 14500 loss ~1.5 (best val_loss ~ 1.8)
iter 16000 loss ~1.45 (max_iters достигнут)
```
train-val gap к концу ~1.7 nats — здоровое значение для SFT на small model.
## Как использовать
Модель распространяется в формате nanoGPT (Karpathy). **Не совместима напрямую
с `transformers.AutoModelForCausalLM`** без конвертации (имена весов отличаются от
GPT-2-стандарта, в частности нет bias).
### Вариант 1 — через nanoGPT-репозиторий (Python)
```bash
git clone https://github.com/karpathy/nanoGPT.git
cd nanoGPT
# скопировать ckpt.pt, tokenizer.model, meta.pkl сюда
python chat.py --out_dir=<path-to-checkpoint-dir>
```
`chat.py` из этого релиза предоставляет интерактивный REPL с командами для
изменения temperature, top_p, top_k, repetition_penalty на лету.
### Вариант 2 — через готовый Go single-binary
В этом релизе есть pre-built `nanogpt-chat.exe` (~97 МБ) — single-binary с
встроенными весами, токенайзером, конфигом. Запускается без Python и без
GPU. Performance: ~36 ток/сек на 4-ядерном CPU.
```bash
./nanogpt-chat.exe
```
Команды REPL:
```text
/help справка
/show текущие параметры
/reset сбросить историю диалога
/system <текст> сменить system-prompt
/temp <float> temperature (>0)
/top_p <float> nucleus sampling
/top_k <int> top-k
/rep <float> repetition_penalty
/preset <name> creative | balanced | precise
/quit выход
```
Все команды имеют однобуквенные алиасы (/h, /s, /r, /q, /t, /p, /k, ...).
### Вариант 3 — конвертация в HuggingFace transformers
Не предусмотрена в релизе. Требует переименования весов под GPT-2 conventions,
добавления nullевых bias, и сборки `GPT2LMHeadModel` с custom tokenizer
(SentencePiece, не GPT-2 BPE). Если кто-то напишет конвертер — буду рад PR.
## Примеры
```text
you> Привет
bot> Привет! Я готов помочь вам в достижении ваших целей. Хорошего дня!
you> Объясни простыми словами, что такое черная дыра.
bot> Для начала, давайте разберемся с этим вопросом шаг за шагом.
### Шаг 1: Изучение черной дыры
- Это означает, что черная дыра является частью черной дыры.
- Она может иметь разные размеры...
[грамотно, но содержательно бредово -- это потолок 50M на фактах]
you> Напиши сортировку пузырьком на Python.
bot> Вот пример сортировки пузырьком на Python:
```python
def merge_sort(arr):
"""Выполняет сортировку пузырьком в отсортированном порядке."""
sorted_array = {}
for i in range(len(arr)):
if arr[i] < sorted_array[i - 1]:
return merge_sort(arr[i], reverse=True)
return sorted_array
```
[имя функции merge_sort вместо bubble_sort, словарь вместо двух циклов --
форма правильная, реализация бессмысленная]
```
Хорошие промпты для этой модели — короткие, диалоговые, не требующие точных
фактов:
```text
you> Привет, как дела?
you> Меня зовут Лёша. А тебя?
you> Назови три фрукта.
you> Расскажи короткую сказку.
```
## Ограничения
- **Знания**: модель **не** содержит достоверных фактов. Не стоит спрашивать о
датах, именах, числах, географии, биологии, медицине. Любой ответ —
имитация жанра справки, а не реальная информация.
- **Reasoning**: многошаговая логика недоступна. Арифметика — имитируется
без выполнения. Code — синтаксически правдоподобен, но не работает.
- **Длина**: модель тренировалась с `block_size=1024`. Длинные диалоги
(>800 токенов в истории) обрезаются с начала — модель «забывает» ранние
реплики.
- **Языки**: только русский. На английских промптах попытается отвечать,
но качество хуже.
- **Безопасность**: модель тренировалась только на отфильтрованной части
датасета (`safety ≥ 8`), но не имеет специального alignment — на
откровенно вредных промптах поведение не гарантировано.
## Что не получилось
После SFT была попытка preference-learning'а через **KTO** для подавления
известных failure modes. Обе попытки (β=0.1 и β=0.03) дали полностью
разрушенную модель — связные ответы превратились в семантический мусор.
Подробный root-cause анализ — в `04_kto_attempts.md` сопровождающего отчёта.
Кратко: комбинация (a) бага в реализации loss (отсутствие `clamp(z_ref, 0)`)
и (b) asymmetric difficulty между chosen-данными и self-generated rejected.
После исправления бага деградация всё равно осталась, просто медленнее.
Любопытный side-effect: после KTO модель уходила не просто в шум, а в
«афористически-философский» регистр — узнаваемый стилистический хвост
распределения, который KTO не давила.
В этом релизе публикуется **только SFT-чекпоинт**, KTO-веса не включены.
## Возможности дообучения
Модель **не на потолке**. Несколько направлений для продолжения:
1. **Continued SFT** на расширенном корпусе. Особенно — добавить корпус с
фактическими знаниями (например, выжимки из Википедии) и кодом. Каждые
~30% новых данных стоит давать ~1-2 эпохи.
2. **Pre-training на сыром тексте** (если хочется уйти ниже 50M-потолка
качества). 1-5 ГБ русского OSCAR/CulturaX перед SFT может дать
значительный буст.
3. **Distillation от внешней большой модели**. Текущий датасет уже дистилл,
но генерация новых ответов от Claude / GPT-4o-mini / Yandex YandexGPT
на тех же промптах даст разнообразие стилей.
4. **Preference learning** (DPO/KTO) с **внешними** rejected (не
self-generated). Например, low-score ответы из val того же датасета.
5. **Scale up** до 100-200M params с теми же гиперпараметрами и тем же
корпусом. Сильно нелинейный буст качества.
## Файлы релиза
| Файл | Размер | Описание |
| --- | --- | --- |
| `ckpt.pt` | 553 МБ | nanoGPT-checkpoint (модель + optimizer state + config) |
| `tokenizer.model` | 930 КБ | SentencePiece-токенайзер (BPE 32k) |
| `meta.pkl` | <1 КБ | спецтокены ID + vocab_size |
| `nanogpt-chat.exe` (опц.) | 97 МБ | Go single-binary с встроенной моделью |
| `model_card.md` | этот файл | |
Если хочется только inference — `tokenizer.model` + `ckpt.pt` достаточно.
## Citation / благодарности
```bibtex
@misc{mini-tron-50,
title = {mini-tron-50: 50M Russian chat model trained from scratch},
author = {Impi},
year = {2026},
note = {Educational baseline; nanoGPT architecture}
}
```
Использованные ресурсы:
- [nanoGPT](https://github.com/karpathy/nanoGPT) by Andrej Karpathy — основа
архитектуры и тренировочного цикла
- `big-russian-dataset` — обучающий корпус
## Лицензия
Apache 2.0 — на код и веса этой модели.