Строим GPT с нуля: пошаговое руководство по архитектуре Transformer > Спикер: Андрей Карпати | Длительность: 1:56:20 Ключевые идеи 1. ChatGPT — это языковая модель — система предсказывает следующий токен в последовательности. Это вероятностная модель: один и тот же запрос может дать разные ответы. 2. Transformer — единственная архитектура, которая имеет значение — из статьи «Attention Is All You Need» (2017), с минимальными изменениями захватила все области ИИ. 3. Токенизация: текст → числа — существуют разные схемы (посимвольная, subword, BPE). Компромисс между размером словаря и длиной последовательности. 4. Данные подаются батчами случайных чанков — в одном чанке длиной T+1 упаковано T обучающих примеров с контекстами от 1 до T символов. 5. Биграммная модель — простейший baseline — предсказание только по последнему токену, без контекста. Loss ~2.5 на Shakespeare. 6. Self-attention через Query, Key, Value — каждый токен генерирует Q (что ищу), K (что содержу), V (что сообщу). Скалярное произведение Q·K даёт веса, по которым агрегируются V. 7. Матричный трюк: нижнетреугольная маска — маскирование будущих позиций через -∞ + softmax. Параллельные вычисления вместо циклов. 8. Multi-head attention — несколько параллельных каналов коммуникации. 4 головы по 8 измерений вместо 1 головы на 32. 9. Transformer-блок = attention + feedforward — attention собирает информацию, feedforward обрабатывает собранное. Блоки повторяются N раз. 10. Residual connections + LayerNorm — обязательны для обучения глубоких сетей. Residual создают «магистраль» для градиентов, LayerNorm стабилизирует активации. 11. Scaled attention — деление на √d_k сохраняет дисперсию ~1 при инициализации, предотвращая схлопывание softmax в one-hot. 12. Dropout — регуляризация через случайное зануление активаций. Применяется в attention-весах и feedforward. Транскрипт Введение: ChatGPT и Transformer Андрей Карпати начинает с демонстрации ChatGPT — системы, которая генерирует текст слева направо, токен за токеном. Это языковая модель: она моделирует последовательности слов и знает, как слова следуют друг за другом в языке. Под капотом работает архитектура Transformer из статьи «Attention Is All You Need» (2017). Цель лекции — построить Transformer-модель с нуля, обучить её на корпусе Шекспира (tiny Shakespeare, ~1 МБ) и научить генерировать «шекспироподобный» текст посимвольно. Весь код доступен в репозитории nanoGPT. Подготовка данных и токенизация Датасет — все произведения Шекспира в одном файле (~1 млн символов). Словарь — 65 уникальных символов (буквы, пробелы, знаки препинания). Создаются функции encode (строка → список чисел) и decode (обратно). Обсуждаются альтернативные токенизаторы: SentencePiece (Google), tiktoken (OpenAI, ~50 000 токенов для GPT-2). Компромисс: маленький словарь = длинные последовательности и наоборот. Данные разбиваются на train (90%) и val (10%) для контроля переобучения. DataLoader: батчи чанков данных Вводятся ключевые параметры: block_size (максимальная длина контекста, начинаем с 8) и batch_size (количество параллельных последовательностей, 4). В чанке из 9 символов упаковано 8 обучающих примеров — модель учится предсказывать по контексту от 1 до 8 символов. Функция get_batch генерирует случайные смещения в массиве данных, вырезает чанки и складывает в тензор (B, T). Итого 32 независимых примера в одном батче. Биграммная языковая модель Простейшая модель: таблица эмбеддингов vocab_size × vocab_size. Каждый токен по своему индексу извлекает строку из таблицы — это logits (оценки) для следующего символа. Токены не взаимодействуют. Loss измеряется через cross-entropy. Начальный loss ~4.87 (теоретический при равномерном распределении: -ln(1/65) ≈ 4.17). После 10 000 шагов обучения с AdamW loss падает до ~2.5. Генерация — авторегрессивная: softmax → multinomial sampling → конкатенация. Математический трюк: матричное умножение как взвешенное усреднение Три версии одной операции — усреднение предыдущих токенов: Версия 1 (цикл for): Для каждой позиции t вычисляем среднее всех предыдущих векторов. Работает, но медленно. Версия 2 (матричное умножение): Создаём нижнетреугольную матрицу (T×T), нормализуем строки, умножаем на X. Результат идентичен, но параллельный. Версия 3 (softmax): Начинаем с нулей, заполняем верхний треугольник значением -∞, применяем softmax. Получаем те же нормализованные веса. Этот вариант обобщается: нули можно заменить на data-dependent значения — и это уже self-attention. Self-Attention: ключевой механизм Каждый токен генерирует три вектора через линейные проекции: Query (Q): «что я ищу» Key (K): «что я содержу» Value (V): «что я сообщу, если вы меня найдёте» Афинность между токенами = Q · Kᵀ. Масштабирование: делим на √head_size, чтобы сохранить дисперсию ~1. Маскирование будущих позиций через -∞. Softmax → нормализованные веса. Агрегация: weights · V. Важные замечания: Attention — механизм коммуникации на направленном графе Нет понятия пространства — нужны позиционные эмбеддинги Батчи обрабатываются независимо Encoder-блоки (полная связность) vs decoder-блоки (маскирование будущего) Self-attention (Q, K, V из одного источника) vs cross-attention (K, V из внешнего источника) Multi-Head Attention Вместо одной «головы» с head_size=32 используются 4 головы по 8. Каждая голова ищет свой тип паттернов. Результаты конкатенируются обратно в 32-мерный вектор. Loss снижается с 2.4 до 2.28. FeedForward и Transformer-блок FeedForward — это MLP: Linear → ReLU → Linear. Применяется к каждому токену независимо (per-node computation). Attention собрал информацию, feedforward её обработал. Полный блок: MultiHeadAttention → residual + LayerNorm → FeedForward → residual + LayerNorm. Блоки повторяются N раз (в финальной модели — 4-6). Residual Connections и LayerNorm Residual connections: x = x + block(x). Создают прямой путь для градиентов через глубокую сеть. Без них глубокие Transformer-ы не обучаются. LayerNorm нормализует активации по последнему измерению. Используется pre-norm формулировка (LayerNorm до attention/feedforward), что отличается от оригинальной статьи. Dropout и финальная модель Dropout добавляется после softmax в attention и в feedforward-слоях. Регуляризация через случайное зануление нейронов во время обучения. Финальная модель: n_embd=384, 6 блоков, 6 голов, dropout=0.2. Val_loss ~1.48. Генерация выдаёт текст, стилистически похожий на Шекспира с правильной структурой диалогов. Масштабирование до GPT и ChatGPT Путь от nanoGPT до ChatGPT: 1. Pre-training: обучение на интернет-данных (предсказание следующего токена) 2. Fine-tuning: обучение на примерах «вопрос → ответ» 3. RLHF: обучение с подкреплением на основе человеческих оценок nanoGPT — это только первый этап. Fine-tuning и RLHF превращают «генератор текста» в «полезного ассистента». Практические задания Задание 1: Реализовать посимвольный токенизатор Напишите с нуля функции encode() и decode() для посимвольной токенизации. Возьмите любой текстовый файл, постройте словарь уникальных символов, создайте маппинг символ→число и число→символ. Проверьте, что decode(encode(text)) == text. Сравните длину закодированной последовательности с результатом tiktoken. Задание 2: Реализовать взвешенное усреднение через матричное умножение Создайте случайный тензор X размера (B, T, C) = (4, 8, 2). Реализуйте три версии усреднения предыдущих токенов: наивный цикл, умножение на нижнетреугольную матрицу и masked_fill + softmax. Убедитесь через torch.allclose, что все три версии дают идентичный результат. Задание 3: Построить и обучить биграммную модель Реализуйте BigramLanguageModel как подкласс nn.Module. Обучите на tiny Shakespeare с batch_size=32 и lr=1e-3 на 10 000 итераций. Достигните loss ~2.5. Сгенерируйте 500 символов и оцените качество. Задание 4: Реализовать single-head self-attention Добавьте head самовнимания с линейными проекциями Q, K, V. Реализуйте масштабирование, маскирование, softmax и агрегацию V. Обучите и убедитесь в снижении loss с ~2.5 до ~2.4. Задание 5: Собрать полный Transformer-блок Объедините MultiHeadAttention + FeedForward + residual + LayerNorm в TransformerBlock. Сложите 4 блока, добавьте dropout. Целевой val_loss ~1.48. Задание 6: Эксперименты с гиперпараметрами Измените количество голов (1, 4, 8), глубину (2, 4, 6), n_embd (32, 64, 128), dropout (0.0, 0.2, 0.4). Постройте таблицу результатов. Задание 7: Перенести на собственный датасет Возьмите текст на русском языке (≥500 КБ). Адаптируйте токенизатор, обучите Transformer, оцените качество генерации. Лучшие цитаты > «Attention is really just a communication mechanism. You can think about it as nodes in a directed graph, where every node has some vector of information and it gets to aggregate information via a weighted sum from all of the nodes that point to it.» — Андрей Карпати > «The query vector roughly speaking is 'what am I looking for' and the key vector roughly speaking is 'what do I contain'.» — Андрей Карпати > «These tokens have a lot to talk about — they want to find the consonants, the vowels, vowels from certain positions — and so it helps to create multiple independent channels of communication.» — Андрей Карпати > «Self-attention does the communication, the feedforward does the computation. The tokens look at each other, but then they need to think about what they found.» — Андрей Карпати > «We don't want these values to be too extreme especially at initialization, otherwise softmax will be way too peaky and you're basically aggregating information from a single node — that's not what we want.» — Андрей Карпати > «Residual connections are these skip connections — instead of just going through the block, you fork off, do some computation, and come back. This is extremely important for training deep networks.» — Андрей Карпати > «In a chunk of nine characters there's actually eight individual examples packed in there.» — Андрей Карпати > «If you have unit Gaussian inputs and you just do the dot product naively, your variance will be on the order of head_size. But if you multiply by one over square root of head_size, the variance will be preserved at one.» — Андрей Карпати