Языковая модель на русских анекдотах — ДЗ №1 по курсу «Большие языковые модели»
Учебная авторегрессионная языковая модель и собственный Byte-level BPE токенизатор, обученные с нуля. Модель содержит 10,523,520 параметров: шесть слоёв, размер скрытого состояния 384, шесть голов запросов и три KV-головы. Используются ALiBi, GQA, RMSNorm и SwiGLU. Словарь содержит 1 024 токена, длина контекста — 128 токенов. В коде также реализованы бонусные RoPE и MLA с отдельными RoPE-компонентами. Они проверены численно; опубликованные обученные веса используют ALiBi/GQA.
Данные, обучение и оценка качества
Датасет: IgorVolochay/russian_jokes,
официальная Parquet-конвертация, ревизия 657dda75684fad2348d8e5d21af7efdf9dc3f16d.
Точные дубликаты и пустые документы удалены до разбиения на обучающую,
валидационную и тестовую части в пропорции 90/5/5, seed=12648430.
Размеры частей: 135,018/7,501/7,502 документов.
Токенизатор обучен только на обучающей части.
Основной этап: AdamW, скорость обучения 0,001, коэффициент регуляризации weight_decay=0,1,
размер батча 32, 10 000 шагов. Первые 5% шагов — линейный разогрев скорости
обучения, затем её линейное снижение; ограничение нормы градиента — 1,0.
С учётом дополнительного эксперимента выполнено 14,000 шагов.
Опубликованы веса основного этапа, выбранные на шаге 10000
по критерию ошибка на полной валидации при сравнении обученных вариантов. Тестовая часть не использовалась для выбора весов.
| Метрика | Значение |
|---|---|
| Начальная кросс-энтропия на валидации | 7.0019 |
| Кросс-энтропия опубликованной модели на полной валидации | 2.7569 |
| Перплексия на валидации | 15.75 |
| Кросс-энтропия на тестовой части | 2.7508 |
| Перплексия на тестовой части | 15.66 |
Ошибка усредняется по всем непаддинговым целевым токенам соответствующей части. Паддинг исключён; настоящий EOS участвует в расчёте ошибки. Каждый документ ограничен первыми 128 токенами, поэтому метрики относятся к этим фрагментам. На валидации обрезано 7.19% документов.

Загрузка модели и генерация
Модель реализована на PyTorch и загружается через классы из этого репозитория.
Для неё используются TransformerForCausalLM и ByteLevelBPETokenizer;
загрузка через Transformers AutoModel и AutoTokenizer не поддерживается.
import torch
from huggingface_hub import snapshot_download
path = snapshot_download("ketimiroshnik/llm-course-hw1")
# Запустите код из скачанной папки или добавьте её в sys.path.
import sys
sys.path.insert(0, path)
from model import TransformerForCausalLM
from tokenizer import ByteLevelBPETokenizer
tokenizer = ByteLevelBPETokenizer.from_pretrained(path)
model = TransformerForCausalLM.from_pretrained(path).eval()
torch.manual_seed(12648430)
ids = torch.tensor([tokenizer.encode("Заходит в бар", add_eos_token=False)])
output = model.generate(ids, 128, tokenizer.eos_token_id,
temperature=0.6, do_sample=True, top_k=5)
print(tokenizer.decode(output[0].tolist(), skip_special_tokens=True))
Сначала установите зависимости из requirements.txt. Поддерживаются CUDA,
Apple MPS и CPU. Веса сохранены в формате safetensors, конфигурация — в config.json.
Примеры ниже получены на Apple MPS. Одинаковый seed не гарантирует одинаковый
текст на CPU, CUDA и MPS: их генераторы случайных чисел различаются.
Примеры с фиксированными seed
Все четыре начала текста зафиксированы до итоговой оценки. Параметры генерации: temperature=0.6, top-k=5, max_new_tokens=128. Они выбраны по промежуточным пробам генерации без использования тестовой ошибки. Приведены все четыре результата, без ручного отбора удачных примеров.
Заходит в бар (seed=12648430, EOS=да)
Заходит в бар, а там, где его загадочный, топчут.
Штирлиц пришел домой (seed=12648431, EOS=да)
Штирлиц пришел домой, а там жена сразу встала.
Студент приходит на экзамен (seed=12648432, EOS=да)
Студент приходит на экзамен по пьяни. Вдруг он говорит:- Скажите, а как вы вы думаете, что ваша жена не придет?- Вам не надо с ним заняться?- А вы знаете, что это у вас есть, но у вас есть сейчас в кармане!
Встречаются два программиста (seed=12648433, EOS=да)
Встречаются два программиста:- Вчера вчера на дачу привезли, а вчера сегодня на улице встречали, встречались, а я вчера на работе играл.- Да, сейчас вчера вечером встретились, что ли?
Назначение и ограничения
Модель предназначена для учебной работы и изучения устройства токенизатора и трансформера. Она небольшая, может выдавать грамматически неверные или несвязные тексты; смешная концовка не гарантируется. Исходный корпус содержит взрослую лексику и стереотипы, которые модель может воспроизводить. Модель обучена предсказывать следующий токен, а не выполнять инструкции. Проверка точного совпадения примеров с обучающими текстами не доказывает отсутствие запоминания. Удалены только точные дубликаты; близкие дубликаты могут оставаться. Контекст ограничен 128 токенами, при генерации используется скользящее окно.
Подробности реализации, воспроизводимости и проверок находятся в REPORT.md,
results.json, заполненной тетрадке и test_solution.py.
SHA-256 весов: 96105b046bbd5435d4cd733be965033e5e0a2725b6fc28ff212dd9122c89be60.
Первоисточники: ALiBi, GQA, SwiGLU, RoFormer, DeepSeek-V2.
Дополнительное обучение на коротких анекдотах
На втором этапе та же модель обучалась ещё 4,000 шагов на 66,345 обучающих анекдотах длиной до 48 токенов, с размером батча 64 и скоростью обучения 0,0003. Веса этого этапа выбирались по 3,658 коротким текстам валидации. Эксперимент проведён из-за слабых промежуточных генераций. Для обоих вариантов итоговые метрики рассчитаны на полных валидационной и тестовой частях с ограничением 128 токенов. Тестовая часть не использовалась для выбора весов или настройки параметров. На графике ошибка на коротких текстах отмечена отдельно: она не сопоставима напрямую с ошибкой на полном корпусе. Полный рецепт обучения — в training_manifest.json.
Основной опубликованный вариант — базовая модель после 10 000 шагов, выбранная по ошибке на полной валидации при сравнении двух вариантов. Веса и метрики дополнительного этапа находятся в curriculum/. Обучение на коротких анекдотах улучшило ошибку на коротких текстах, но ухудшило общие валидационные и тестовые метрики. Все фиксированные примеры остаются слабыми; стабильная связная или смешная генерация не заявляется.