Зачем строить свою LLM, когда есть готовые?
Все просто. Потому что это как собрать двигатель автомобиля, прежде чем научиться водить. Понимание, как работают языковые модели изнутри, меняет все. Перестаешь видеть в них черный ящик. Начинаешь предсказывать их поведение. Перестаешь бояться.
Сегодня мы разберем toyGPT - минимальную рабочую реализацию трансформера на PyTorch. Не ChatGPT, не Llama. Просто 10-20 миллионов параметров, которые умеют генерировать текст.
Это не production-решение. Это учебный проект, который поместится на одной видеокарте среднего уровня. Зато после него вы поймете архитектуру так, как не поймете из сотен статей.
Что такое mHC-трансформер и почему он проще
mHC означает "multi-head causal" - многоголовая каузальная архитектура. Если обычный трансформер смотрит на весь текст сразу (что нужно для переводчиков), то каузальный видит только прошлое. Как мы, люди: читаем слева направо, не заглядывая вперед.
Вот что отличает нашу архитектуру:
- Только декодер - никаких энкодеров
- Маскированное самовнимание - каждый токен видит только предыдущие
- Позиционные эмбеддинги - чтобы модель понимала порядок слов
- Нормализация слоев - стабилизация обучения
Собираем puzzle: из чего состоит toyGPT
Представьте, что строите дом из Lego. Каждый блок - это компонент модели. Вот что нам понадобится:
1 Эмбеддинг слов
Слова превращаются в числа. Не просто числа, а векторы в 256-мерном пространстве. "Кот" и "кошка" окажутся рядом. "Кот" и "астрофизика" - далеко друг от друга.
2 Позиционные эмбеддинги
Положение слова в предложении. Без этого "кот съел мышь" и "мышь съела кота" будут одинаковыми для модели. Синусоидальные функции создают уникальную подпись для каждой позиции.
3 Блок самовнимания
Сердце трансформера. Каждое слово "смотрит" на другие слова в предложении и решает, насколько они важны. В каузальной версии - только на предыдущие слова.
| Компонент | Назначение | Параметры |
|---|---|---|
| Эмбеддинги | Перевод токенов в векторы | ~5M при словаре 10k |
| Внимание | Вычисление зависимостей | ~8M при 8 головах |
| FFN слои | Нелинейные преобразования | ~5M на слой |
Готовим данные: чем кормить модель
Плохие данные = бессмысленная модель. Это аксиома. Для toyGPT не нужны терабайты текста. Достаточно 100-200 МБ качественного контента.
Что подойдет:
- Википедия (русская или английская)
- Художественная литература (Project Gutenberg)
- Техническая документация
- Новостные статьи
Не смешивайте стили на первых порах. Если берете Википедию - берите только ее. Модель-новичок запутается в разных регистрах, стилях, темах.
Токенизация - следующий шаг. Byte Pair Encoding (BPE) или WordPiece. Для русского языка есть нюансы: переносы слов, падежи, склонения. Простой split по пробелам не сработает.
Обучение: от хаоса к порядку
Здесь начинается магия. И боль. Много боли, если не настроить гиперпараметры.
4 Настройка оптимизатора
AdamW с весомой decay. Learning rate: 3e-4 для начала. Батч размер: сколько влезет в память GPU. Обычно 16-32 для 8 ГБ видеопамяти.
5 График learning rate
Warmup первые 2000 шагов - плавный подъем learning rate. Затем линейный decay до нуля. Это как разогреть двигатель перед поездкой.
6 Мониторинг потерь
Loss должен падать. Если колеблется - слишком большой learning rate. Если не падает - слишком маленький. Если растет - что-то сломалось.
Типичная ошибка новичков: пытаться обучать на CPU. Не делайте этого. Одна эпоха займет недели. Возьмите Colab Pro или локальную видеокарту с 8+ ГБ памяти.
Генерация текста: как модель "думает"
Обучение закончено. Веса сохранены. Теперь самое интересное - заставить модель генерировать.
Токен за токеном. Каждый следующий зависит от всех предыдущих. Температура sampling - параметр творчества. 0.7-0.9 для баланса между предсказуемостью и разнообразием.
Top-p sampling (nucleus sampling) лучше, чем top-k. Берет только самые вероятные токены, сумма вероятностей которых достигает p (обычно 0.9).
| Параметр | Значение | Эффект |
|---|---|---|
| Temperature | 0.8 | Баланс креативности |
| Top-p | 0.9 | Качество vs разнообразие |
| Max length | 512 | Ограничение генерации |
| Repetition penalty | 1.2 | Борьба с зацикливанием |
Что пойдет не так (спойлер: многое)
Первый запуск редко бывает успешным. Вот частые проблемы и их решения:
Loss NaN с первой же эпохи
Слишком большой learning rate. Или неправильная инициализация весов. Или exploding gradients. Добавьте gradient clipping.
Модель генерирует бессвязный текст
Недообучение. Добавьте эпох. Или данные плохого качества. Или архитектура слишком простая для задачи.
GPU memory overflow
Уменьшите batch size. Или sequence length. Или используйте gradient accumulation.
А дальше? Масштабирование и тонкая настройка
toyGPT работает. Генерирует осмысленный текст (иногда). Что дальше?
Увеличивайте размер модели. Добавляйте слои. Экспериментируйте с размерностью эмбеддингов. Пробуйте разные активационные функции.
Потом - fine-tuning на конкретной задаче. Хотите, чтобы модель писала код? Обучайте на GitHub. Хотите медицинского ассистента? На медицинских текстах.
Не ждите чудес от 20M модели. Она не сравнится с GPT-4. Но она ВАША. Вы понимаете каждый ее нейрон. Это бесценно.
Практический совет: с чего начать сегодня
Скачайте готовый репозиторий toyGPT. Запустите на Colab. Поменяйте dataset на свой. Посмотрите, как меняется поведение модели.
Потом напишите свою реализацию с нуля. Не копипастьте. Набирайте каждую строчку, понимая, зачем она нужна.
Через месяц таких экспериментов вы будете смотреть на любую LLM не как на магию, а как на конструктор. Сложный, да. Но понятный.
И тогда уже можно браться за серьезные проекты. Например, строить RAG-системы (как в нашем гайде по RAG) или экспериментировать с alignment техниками вроде RLHF и DPO.
Но начинать нужно с основ. С toyGPT. С первого шага, который кажется маленьким, но меняет все.
P.S. Если ваша первая модель будет генерировать бред - это нормально. Моя первая модель думала, что лучший ответ на любой вопрос - "42". Через неделю она научилась строить предложения. Через месяц - поддерживать диалог. Главное - не останавливаться после первой неудачи.