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.
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.
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
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.
Tutorial walls on any open-ended prompt:
you> Tell me about yourself
bot> ### Step 1: Define the task
### Step 2: ...
### Conclusion
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]
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.
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%).
1iter 0 loss 10.49 (≈ ln(32000), random initialization)
2iter 500 loss ~5 (warmup complete, LR at peak)
3iter 5500 loss ~2.4 (first saved checkpoint)
4iter 11500 loss ~1.7 (third)
5iter 14500 loss ~1.5 (best val_loss ~ 1.8)
6iter 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).
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.
./nanogpt-chat.exe
REPL commands:
text
1/help help
2/show current parameters
3/reset reset dialog history
4/system <text> change system prompt
5/temp <float> temperature (>0)
6/top_p <float> nucleus sampling
7/top_k <int> top-k
8/rep <float> repetition penalty
9/preset <name> creative | balanced | precise
10/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
1you> Hello
2bot> Hello! I'm ready to help you achieve your goals. Have a great day!
34you> Explain in simple words what a black hole is.
5bot> First, let's break this down step by step.
67 ### Step 1: Studying a black hole
8 - This means that a black hole is part of a black hole.
9 - It can have different sizes...
10 [grammatically correct, but content is nonsense — this is the 50M ceiling on facts]
1112you> Write bubble sort in Python.
13bot> Here is an example of bubble sort in Python:
14 ```python
15 def merge_sort(arr):
16 """Performs bubble sort in sorted order."""
17 sorted_array = {}
18 for i in range(len(arr)):
19 if arr[i] < sorted_array[i - 1]:
20 return merge_sort(arr[i], reverse=True)
21 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:
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.
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.
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.
Preference learning (DPO/KTO) with external rejected (not self-generated). For example, low-score responses from the val split of the same dataset.
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
1@misc{mini-tron-50,
2 title = {mini-tron-50: 50M Russian chat model trained from scratch},
3 author = {Impi},
4 year = {2026},
5 note = {Educational baseline; nanoGPT architecture}
6}
Resources used:
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-корпусе как чат-бот. Иллюстрирует что можно
выжать из модели такого размера без претрейна на сыром тексте.
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 ещё не выходили на плато.
Дальнейшая тренировка или продолжение на новых данных вероятно даст ощутимое
улучшение.
Стандартный 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
Canned-ответы на простые вопросы:
you> Любишь котов или собак?
bot> Привет! Я рад, что смог помочь вам сегодня. Если у вас есть вопросы,
не стесняйтесь обращаться к нам. Удачи!
Заученный шаблонный хвост ChatGPT-style ответов.
Tutorial-простыни на любой открытый промпт:
you> Расскажи о себе
bot> ### Шаг 1: Определение задачи
### Шаг 2: ...
### Заключение
Token-loops на промптах вне распределения:
you> Что больше: 17 или 71?
bot> Чтобы посчитать... + 112 - 112 + 112 + 112 - 112 + 112 ... [50+ повторов]
Семантическая каша в полностью грамотной обёртке:
you> Сколько будет 7 умножить на 8?
bot> 5! = (5 × 8) / 8 = 120. Теперь разделим 120 на 8...
Итак, всего будет 140 способов выбрать 7 умножить на 8.
Модель имитирует жанр школьной арифметики, не выполняя саму операцию.
Эти failure modes лечатся не SFT, а preference learning'ом + увеличением
размера модели.
Фильтр: 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%).
1iter 0 loss 10.49 (≈ ln(32000), стартовая случайная инициализация)
2iter 500 loss ~5 (warmup закончен, LR на peak)
3iter 5500 loss ~2.4 (первый saved checkpoint)
4iter 11500 loss ~1.7 (третий)
5iter 14500 loss ~1.5 (best val_loss ~ 1.8)
6iter 16000 loss ~1.45 (max_iters достигнут)
train-val gap к концу ~1.7 nats — здоровое значение для SFT на small model.
Как использовать
Модель распространяется в формате nanoGPT (Karpathy). Не совместима напрямую
с transformers.AutoModelForCausalLM без конвертации (имена весов отличаются от
GPT-2-стандарта, в частности нет bias).
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.
Все команды имеют однобуквенные алиасы (/h, /s, /r, /q, /t, /p, /k, ...).
Вариант 3 — конвертация в HuggingFace transformers
Не предусмотрена в релизе. Требует переименования весов под GPT-2 conventions,
добавления nullевых bias, и сборки GPT2LMHeadModel с custom tokenizer
(SentencePiece, не GPT-2 BPE). Если кто-то напишет конвертер — буду рад PR.
Примеры
text
1you> Привет
2bot> Привет! Я готов помочь вам в достижении ваших целей. Хорошего дня!
34you> Объясни простыми словами, что такое черная дыра.
5bot> Для начала, давайте разберемся с этим вопросом шаг за шагом.
67 ### Шаг 1: Изучение черной дыры
8 - Это означает, что черная дыра является частью черной дыры.
9 - Она может иметь разные размеры...
10 [грамотно, но содержательно бредово -- это потолок 50M на фактах]
1112you> Напиши сортировку пузырьком на Python.
13bot> Вот пример сортировки пузырьком на Python:
14 ```python
15 def merge_sort(arr):
16 """Выполняет сортировку пузырьком в отсортированном порядке."""
17 sorted_array = {}
18 for i in range(len(arr)):
19 if arr[i] < sorted_array[i - 1]:
20 return merge_sort(arr[i], reverse=True)
21 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-веса не включены.
Возможности дообучения
Модель не на потолке. Несколько направлений для продолжения:
Continued SFT на расширенном корпусе. Особенно — добавить корпус с
фактическими знаниями (например, выжимки из Википедии) и кодом. Каждые
~30% новых данных стоит давать ~1-2 эпохи.
Pre-training на сыром тексте (если хочется уйти ниже 50M-потолка
качества). 1-5 ГБ русского OSCAR/CulturaX перед SFT может дать
значительный буст.
Distillation от внешней большой модели. Текущий датасет уже дистилл,
но генерация новых ответов от Claude / GPT-4o-mini / Yandex YandexGPT
на тех же промптах даст разнообразие стилей.
Preference learning (DPO/KTO) с внешними rejected (не
self-generated). Например, low-score ответы из val того же датасета.
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
1@misc{mini-tron-50,
2 title = {mini-tron-50: 50M Russian chat model trained from scratch},
3 author = {Impi},
4 year = {2026},
5 note = {Educational baseline; nanoGPT architecture}
6}
Использованные ресурсы:
nanoGPT by Andrej Karpathy — основа
архитектуры и тренировочного цикла