GPT-2
Реализация:
llm/src/llm/models/gpt/gpt2.py· классGPT2Ноутбук:notebooks/gpt2.ipynb
Место в линейке: GPT-1 → GPT-2 → LLaMA → Mistral → Mixtral · Gemma
Что вы узнаете
Заголовок раздела «Что вы узнаете»- какую идею проверяла статья GPT-2: языковая модель как решатель задач без дообучения (zero-shot), корпус WebText, byte-level BPE;
- какие три изменения архитектуры отличают GPT-2 от GPT-1: pre-LN, финальный LayerNorm, масштаб инициализации residual-слоёв;
- как выглядит прямой проход GPT-2 в формулах и почему pre-LN обучается стабильнее;
- как посчитать параметры GPT-2 (124 439 808 у самой маленькой модели) и откуда расхождение с «117M» из статьи;
- как устроены классы
GPT2иGpt2Decoderи как загрузить веса OpenAI.
Предварительные знания
Заголовок раздела «Предварительные знания»Глава опирается на GPT-1: эмбеддинги, attention и FFN у GPT-2 те же, и их формулы здесь только напоминаются. Нужны также нормализация (post-LN и pre-LN), токенизация (BPE) и обучение (инициализация).
Исторический контекст и вклад статьи
Заголовок раздела «Исторический контекст и вклад статьи»GPT-1 показал, что предобученную языковую модель выгодно дообучать на каждой задаче. Radford, Wu, Child, Luan, Amodei, Sutskever в статье Language Models are Unsupervised Multitask Learners (OpenAI, 2019) пошли дальше: можно ли обойтись без дообучения вообще?
Идея (разд. 2 статьи): модель, решающая задачу, оценивает ; универсальная система должна оценивать . В тексте задача часто описана естественным языком прямо рядом с примером — «переведи на французский», пары «английская фраза = французская фраза». Поэтому достаточно большая языковая модель, обученная на достаточно разнообразном тексте, может научиться выполнять такие задачи, просто предсказывая следующий токен. Задача тогда задаётся промптом (prompt), а не новой головой и не градиентными шагами: например, для суммаризации в статье к статье дописывается TL;DR:.
Вклад статьи:
- Корпус WebText (разд. 2.1). Вместо книг (GPT-1) или неотфильтрованного Common Crawl авторы собрали исходящие ссылки с Reddit, получившие не меньше 3 karma, — как грубый фильтр «люди сочли это интересным». Около 45 млн ссылок; после дедупликации и очистки — чуть больше 8 млн документов, 40 ГБ текста. Все документы Википедии удалены, чтобы не пересекаться с тестовыми наборами.
- Byte-level BPE (разд. 2.2). BPE работает не над символами Unicode, а над байтами UTF-8: базовый словарь — 256 байтов, поэтому любую строку можно закодировать, и неизвестных токенов (
<unk>) нет. Чтобы не появлялись токены вродеdog.,dog!,dog?, слияния между разными категориями символов запрещены, кроме пробелов. Итоговый словарь — 50 257 токенов (подробно — в tokenization.md). - Масштаб (разд. 2.3, табл. 2). Четыре модели одной архитектуры, от размера GPT-1 до в 10 с лишним раз большей; самую большую авторы и называют GPT-2.
- Zero-shot-результаты (разд. 3). По аннотации статьи, самая большая модель получила лучший известный результат на 7 из 8 проверенных наборов языкового моделирования без обучения на них, при этом всё ещё недообучена на WebText. На задачах вроде ответов на вопросы, перевода и суммаризации zero-shot-качество было ниже специализированных систем, но устойчиво росло с размером модели.
Размеры моделей из табл. 2 статьи и подсчёт параметров по формуле ниже (для конфигурации кода с tying):
| Модель в статье | Параметров по формуле | ||
|---|---|---|---|
| 117M (эквивалент GPT-1) | 12 | 768 | 124 439 808 |
| 345M | 24 | 1024 | 354 823 168 |
| 762M | 36 | 1280 | 774 030 080 |
| 1542M (GPT-2) | 48 | 1600 | 1 557 611 200 |
Цифры статьи и точный подсчёт расходятся (117M против 124,4M). Точный подсчёт для 124M совпадает с числом параметров HF-чекпоинта openai-community/gpt2 (backlog.md), а для 345M проверен созданием модели в репозитории; в статье расхождение не объясняется. Общими для всех четырёх моделей в статье указаны словарь 50 257, контекст 1024 токена (у GPT-1 было 512) и батч 512.
Изменения архитектуры относительно GPT-1
Заголовок раздела «Изменения архитектуры относительно GPT-1»Статья перечисляет их в разд. 2.3; механизмы (эмбеддинги, MHA, GELU-FFN) те же, что в GPT-1, меняется их расстановка и инициализация.
- Pre-LN. LayerNorm перенесён на вход каждого подблока — по аналогии с pre-activation ResNet (He et al., 2016), где нормализация и активация тоже стоят перед весовым слоем, а не после сложения.
- Финальный LayerNorm после последнего блока, перед выходной проекцией.
- Масштаб инициализации residual-слоёв: веса слоёв, пишущих в residual-поток, при инициализации умножаются на , где — число residual-слоёв.
- Словарь 50 257 (byte-level BPE), контекст 1024 вместо 512.
Архитектура блока декодера
Заголовок раздела «Архитектура блока декодера»Жирной обводкой выделено то, что изменилось по сравнению с GPT-1.
%%{init: {"flowchart": {"rankSpacing": 28, "nodeSpacing": 28}}}%%
flowchart TB
Ids(["token ids"]):::io --> TokEmb["Token Embedding"]:::blue
Ids --> PosEmb["Position Embedding<br/>(обучаемые)"]:::purple
TokEmb --> Sum(("+")):::add
PosEmb --> Sum
Sum --> Drop["Dropout"]:::gray
subgraph Dec["Gpt2Decoder × num_layers · pre-LN"]
direction TB
X(["x"]):::io --> N1["LayerNorm"]:::grayHl
N1 --> Attn["Masked Multi-Head Attention"]:::blue
Attn --> A1(("+")):::add
X -. residual .-> A1
A1 --> N2["LayerNorm"]:::grayHl
N2 --> FFN["Feed Forward<br/>Linear → GELU → Linear"]:::purple
FFN --> A2(("+")):::add
A1 -. residual .-> A2
end
Drop --> Dec
Dec --> NF["LayerNorm<br/>(финальный)"]:::grayHl --> Lin
Lin["Linear → vocab_size"]:::gray --> Out(["logits"]):::io
Out -. "generate(): softmax → выбор токена" .-> Next(["следующий токен"]):::io
style Dec fill:transparent,stroke:#82b366,stroke-width:2px,color:#5b9a3c
classDef io fill:#ffffff,stroke:#999999,color:#1a1a1a;
classDef add fill:#ffffff,stroke:#666666,color:#1a1a1a;
classDef blue fill:#dae8fc,stroke:#6c8ebf,color:#1a1a1a;
classDef blueHl fill:#dae8fc,stroke:#2f5f9e,stroke-width:3px,color:#1a1a1a;
classDef purple fill:#e1d5e7,stroke:#9673a6,color:#1a1a1a;
classDef purpleHl fill:#e1d5e7,stroke:#6a3d85,stroke-width:3px,color:#1a1a1a;
classDef gray fill:#f5f5f5,stroke:#666666,color:#1a1a1a;
classDef grayHl fill:#f5f5f5,stroke:#333333,stroke-width:3px,color:#1a1a1a;
classDef gold fill:#fff2cc,stroke:#d6b656,color:#1a1a1a;
classDef rope fill:#d5f0ec,stroke:#3a9e8f,color:#1a1a1a;
classDef ropeHl fill:#d5f0ec,stroke:#1f6f63,stroke-width:3px,color:#1a1a1a;
classDef dim fill:#f5f5f5,stroke:#bbbbbb,color:#999999,stroke-dasharray:4 3;
Прямой проход в формулах
Заголовок раздела «Прямой проход в формулах»Обозначения — как в gpt.md: вход , формулы записаны для одной последовательности, в коде спереди добавляется ось батча.
Шаг 1. Эмбеддинги — без изменений:
где (wte в оригинале) — токенные эмбеддинги, (wpe) — обучаемые позиционные эмбеддинги, .
Шаг 2. pre-LN блоков. Для :
где:
- — вход блока, состояние после attention-подблока и выход блока;
- — LayerNorm со своими (normalization.md);
- — тот же masked multi-head attention, что в GPT-1 (формулы, attention.md);
- , , , GELU в tanh-аппроксимации (feed-forward.md).
Шаг 3. Финальная нормализация и выходная проекция:
где — финальный LayerNorm (ln_f в оригинале, _norm в коде), — транспонированная матрица эмбеддингов (weight tying, как в оригинале; без tying — отдельные и ), — логиты.
Сводка форм — та же, что у GPT-1: [B, T] → [B, T, d] → ( блоков) [B, T, d] → LN_f [B, T, d] → [B, T, V].
Почему pre-LN и зачем финальный LayerNorm
Заголовок раздела «Почему pre-LN и зачем финальный LayerNorm»Раскроем рекурсию шага 2. Выход последнего блока — это вход плюс сумма вкладов всех подблоков:
Это равенство — прямое следствие двух формул шага 2: подставляем в и складываем по . В post-LN (GPT-1) такого разложения нет: каждый LayerNorm стоит на основном пути и перенормирует всю сумму.
Следствия:
- Путь градиента. Производная по содержит единичное слагаемое (тождественный путь по residual-связям), поэтому градиент доходит до нижних слоёв, не проходя через нормализации. Xiong et al. (2020) показали, что у pre-LN градиенты в начале обучения хорошо ведут себя и без warmup, тогда как post-LN warmup необходим. Подробно — в normalization.md.
- Финальный LayerNorm нужен. — ненормализованная сумма слагаемых, её масштаб растёт с глубиной. приводит её к единому масштабу перед умножением на . В GPT-1 эту роль играл последний .
Масштаб инициализации residual-слоёв
Заголовок раздела «Масштаб инициализации residual-слоёв»Из того же разложения видно, почему растёт масштаб residual-потока. Пусть в начале обучения вклады подблоков в одну координату — независимые случайные величины со средним 0 и дисперсией . Тогда дисперсия их суммы:
где — вклад -го подблока в координату residual-потока, — дисперсия одного вклада, — число residual-подблоков (attention и FFN в каждом из блоков). Первое равенство верно для независимых слагаемых.
Стандартное отклонение суммы растёт как : при — примерно в 4,9 раза. Вклад подблока линеен по весам его выходной проекции ( у attention, у FFN). Если уменьшить std этих весов в раз, дисперсия каждого вклада уменьшится в раз, и сумма снова будет иметь дисперсию — независимо от глубины.
В коде , как в GPT2PreTrainedModel._init_weights в HuggingFace:
Для : ; для учебного конфига (): . Остальные Linear и Embedding — , bias — нули, LayerNorm — , .
Компоненты
Заголовок раздела «Компоненты»| Компонент | Класс | Файл |
|---|---|---|
| Токен-эмбеддинги | TokenEmbeddings | core/token_embeddings.py |
| Позиционные эмбеддинги | PositionalEmbeddings (обучаемые, абсолютные — как в GPT-1) | core/positional_embeddings.py |
| Attention | MultiHeadAttention (тот же класс, что и в GPT-1) | core/multi_head_attention.py |
| FFN | FeedForward с tanh-аппроксимацией GELU (activation="gelu_tanh" — как в оригинальном коде OpenAI; в HF — gelu_new), активация зашита внутри декодера и не настраивается из конфига | core/feed_forward.py, core/gpt2_decoder.py |
| Блок декодера | Gpt2Decoder (pre-LN) | core/gpt2_decoder.py |
| Финальная нормализация | nn.LayerNorm (GPT2._norm) | models/gpt/gpt2.py |
| Модель целиком | GPT2 | models/gpt/gpt2.py |
Gpt2Decoder.forward:
norm1_out = Norm1(x)attn_out = Attention(norm1_out)out = attn_out + xnorm2_out = Norm2(out)ffn_out = FFN(norm2_out)result = ffn_out + outВ отличие от GPT-1, GPT2.forward добавляет финальный nn.LayerNorm после стека декодеров и перед проекцией на словарь (models/gpt/gpt2.py) — стандартная практика pre-LN трансформеров (без неё выход последнего блока не нормализован).
Gpt2Decoder — самостоятельный класс, а не переиспользование параметризуемого CachedDecoder (которым, например, пользуются LLaMA и другие более новые архитектуры в этом репозитории): FFN и pre-LN расстановка захардкожены внутри него.
Подсчёт параметров
Заголовок раздела «Подсчёт параметров»По сравнению с GPT-1 (подсчёт) добавляется только финальный LayerNorm — параметров ( и ). Блок по-прежнему содержит : attention , FFN , два LayerNorm .
где — словарь, — размерность модели, — контекст, — число блоков, — финальный LayerNorm.
GPT-2 124M (, , , , с tying):
V·d = 50 257 · 768 = 38 597 376T_max·d = 1 024 · 768 = 786 43212 блоков = 12 · 7 087 872 = 85 054 464ln_f = 2 · 768 = 1 536итого 124 439 808Совпадает с числом параметров HF-модели openai-community/gpt2 (backlog.md). Без tying: . Эмбеддинги здесь — 31,6 % модели, у GPT-1 — 27 %: словарь больше, а блоки те же. С ростом доля блоков растёт: у модели 1542M они дают около 95 % параметров.
Учебный конфиг gpt2_train.json (, , , при vocab_size = 1000): на больше, чем у GPT-1, — 3 448 320 с tying и 3 705 320 без него (по умолчанию).
from llm.models.gpt import GPT2
cfg = {"vocab_size": 50257, "embed_dim": 768, "num_heads": 12, "num_layers": 12, "max_position_embeddings": 1024, "dropout": 0.0, "tie_word_embeddings": True}print(sum(p.numel() for p in GPT2(cfg).parameters())) # 124439808Конфигурация
Заголовок раздела «Конфигурация»Пример из experiments/llm_only/configs/gpt2_train.json — набор параметров тот же, что у GPT-1, кроме activation (у GPT-2 активация не настраивается):
| Параметр | Значение в примере | Значение в GPT-2 124M | Смысл |
|---|---|---|---|
vocab_size | (из токенизатора) | 50257 | размер словаря |
embed_dim | 256 | 768 | размерность эмбеддингов |
num_heads | 4 | 12 | число attention-голов |
head_size | (нет в примере) | 64 | необязательный размер головы; по умолчанию embed_dim // num_heads |
num_layers | 4 | 12 | число блоков Gpt2Decoder |
max_position_embeddings | 128 | 1024 | максимальная длина последовательности |
dropout | 0.1 | 0.1 | dropout на эмбеддингах и на выходах attention и FFN перед residual |
attention_dropout | (нет в примере) | 0.1 | необязательный dropout на весах внимания после softmax, по умолчанию 0.0; в HF — attn_pdrop = 0.1 |
initializer_range | (нет в примере) | 0.02 | необязательное стандартное отклонение начальных весов, по умолчанию 0.02 |
tie_word_embeddings | (нет в примере) | да | необязательный: true — выходная проекция без bias делит веса с wte, как в оригинале и HF (см. ниже); по умолчанию false — отдельный Linear с bias |
Значения dropout для 124M — из конфига HF (resid_pdrop, embd_pdrop, attn_pdrop); в статье GPT-2 dropout не описан. Число голов в статье тоже не приводится; 12 — из конфига HF.
Инициализация весов
Заголовок раздела «Инициализация весов»Как в GPT-1 (gpt.md), веса Linear и Embedding — , bias — нули. Дополнительно выходные проекции, которые пишут в residual-поток, — выход attention и второй слой FFN, по две на блок, — инициализируются со стандартным отклонением , где = num_layers. Статья GPT-2 (разд. 2.3) масштабирует веса residual-слоёв на , где — число residual-слоёв, чтобы дисперсия residual-потока не росла с глубиной; здесь — как в GPT2PreTrainedModel._init_weights в HuggingFace (обоснование — в разделе Масштаб инициализации residual-слоёв). В коде OpenAI wpe инициализируется с 0.01, здесь, как в HF, — 0.02.
В коде это две строки GPT2.__init__: сначала self.apply(partial(init_normal_, std=std)) для всех модулей, затем scale_residual_projections_ (core/weight_init.py) переинициализирует decoder._heads._layer и decoder._ff._layer2 каждого блока со std . Bias этих слоёв остаются нулевыми.
Weight tying и веса OpenAI
Заголовок раздела «Weight tying и веса OpenAI»В оригинале (gpt-2/src/model.py: tf.matmul(h, wte, transpose_b=True)) и в HF (GPT2LMHeadModel) выходная проекция — та же матрица, что wte, без bias. Здесь это ключ "tie_word_embeddings": true, как в GPT-1 (gpt.md). Для конфигурации 124M он экономит около 38,6M параметров (50257 · 768 плюс bias): 124,4M вместо 163,1M.
С ним загружаются веса openai-community/gpt2:
from transformers import GPT2LMHeadModelfrom llm.models.gpt import GPT2, convert_hf_state_dict
hf = GPT2LMHeadModel.from_pretrained("openai-community/gpt2")model = GPT2({"vocab_size": 50257, "embed_dim": 768, "num_heads": 12, "num_layers": 12, "max_position_embeddings": 1024, "dropout": 0.0, "tie_word_embeddings": True})model.load_state_dict(convert_hf_state_dict(hf.state_dict()))Логиты совпадают с HF с точностью до ~1e-4 (при значениях логитов порядка 100), greedy-генерация — токен в токен. Для текста нужен токенизатор GPT-2 из transformers (GPT2Tokenizer): собственный BPE репозитория (tokenization.md) даёт другие индексы.
convert_hf_state_dict (models/gpt/hf_weights.py) — та же функция, что для GPT-1; как она переименовывает ключи, транспонирует веса Conv1D и режет c_attn на Q, K, V, разобрано в gpt.md. Специфичны для GPT-2 только верхнеуровневые имена: wte → _token_embeddings._embedding, wpe → _position_embeddings.embedding, ln_f → _norm. Имена внутри блоков (h.{i}.attn.c_attn, h.{i}.mlp.c_fc, h.{i}.ln_1 …) у GPT-1 и GPT-2 в HF совпадают, различается только смысл ln_1/ln_2: в GPT-2 они стоят перед подблоками, а не после. Функции это безразлично — она переносит параметры, а расстановку задаёт класс блока.
Как это устроено в коде
Заголовок раздела «Как это устроено в коде»GPT2.__init__
Заголовок раздела «GPT2.__init__»models/gpt/gpt2.py, класс GPT2. Конструктор повторяет GPT.__init__ (разбор) с тремя отличиями:
| Строка кода | Что делает | Отличие от GPT-1 |
|---|---|---|
Gpt2Decoder(num_heads=..., emb_size=..., head_size=..., max_seq_len=..., dropout=..., attention_dropout=...) | pre-LN блоков | нет аргумента activation — GELU (tanh) зашит в блоке |
self._norm = nn.LayerNorm(config["embed_dim"]) | новый модуль | |
scale_residual_projections_([...], num_layers=..., std=std) | std для и | новая инициализация |
Gpt2Decoder.__init__ (core/gpt2_decoder.py) создаёт те же четыре модуля, что GptDecoder: _heads, _ff (с activation="gelu_tanh"), _norm1, _norm2. Имена модулей совпадают, поэтому convert_hf_state_dict годится для обеих моделей, а scale_residual_projections_ находит проекции по decoder._heads._layer и decoder._ff._layer2.
GPT2.forward
Заголовок раздела «GPT2.forward»Отличается от GPT.forward одной строкой перед проекцией:
for i, decoder in enumerate(self._decoders): # H^(l) = pre-LN блок ...out = self._norm(out) # LN_f(H^(L)) [B, T, d]logits = self._linear(out) # Z [B, T, V]Gpt2Decoder.forward реализует шаг 2 буквально: out = attention + x — это (attention применён к self._norm1(x)), result = ffn_out + out — это (FFN применён к self._norm2(out)).
Две тонкости:
- Сигнатура
GPT2.forward(x, use_cache=False, cache=None, attention_mask=None)отличается порядком аргументов отGPT.forward(x, attention_mask=None, use_cache=False, cache=None). Передавайте их по имени. - У
Gpt2Decoder.forwarduse_cacheпо умолчаниюTrue(уGptDecoder—False).GPT2.forwardвсегда передаёт его явно, так что на модель это не влияет, но при прямом вызове блока вернётся кэш.
Отличия от оригинала
Заголовок раздела «Отличия от оригинала»| Что | Статья / код OpenAI / HF | Этот репозиторий |
|---|---|---|
| Weight tying | есть | ключ tie_word_embeddings, по умолчанию выключен |
| Dropout внимания | attn_pdrop = 0.1 в HF | attention_dropout, по умолчанию 0 |
Инициализация wpe | 0.01 в коде OpenAI | 0.02, как в HF |
| Токенизатор | byte-level BPE, 50 257 токенов | собственный BPE (tokenization.md); для весов OpenAI нужен токенизатор HF |
| Активация FFN | GELU (tanh-аппроксимация) | то же, не настраивается |
| Размер FFN | всегда |
Генерация
Заголовок раздела «Генерация»GPT2.generate(...) — та же унифицированная сигнатура, что у всех моделей репозитория (кратко — gpt.md, подробно — generation.md). Промпт в духе статьи — то, как GPT-2 решает задачи без дообучения: задача описывается текстом, модель его продолжает.
import torchfrom llm.models.gpt import GPT2
model = GPT2({"vocab_size": 1000, "embed_dim": 256, "num_heads": 4, "num_layers": 4, "max_position_embeddings": 128, "dropout": 0.1})model.eval()out = model.generate(torch.randint(0, 1000, (1, 8)), max_new_tokens=20, do_sample=True, temperature=0.8, top_k=40) # [1, 28]Что изменилось в LLaMA
Заголовок раздела «Что изменилось в LLaMA»- обучаемые абсолютные позиционные эмбеддинги → RoPE (относительное, ротационное позиционное кодирование, встроено в attention);
LayerNorm→ RMSNorm;- GELU-FFN → SwiGLU;
- pre-LN и финальная нормализация сохраняются;
- attention остаётся стандартным multi-head (см. llama.md) — GQA появится только в Mistral.
Подробности — в llama.md.
- GPT-2 проверил идею: достаточно большая языковая модель на разнообразном тексте (WebText, 40 ГБ) решает задачи zero-shot, по промпту; лучший результат на 7 из 8 наборов языкового моделирования без обучения на них.
- Byte-level BPE на 50 257 токенов кодирует любую строку без
<unk>. - Архитектура та же, что у GPT-1, но: pre-LN, финальный LayerNorm, инициализация residual-проекций со std , контекст 1024.
- Pre-LN превращает выход стека в сумму вкладов подблоков — градиент идёт по тождественному пути, глубокие стеки обучаются стабильнее.
- Параметры: формула GPT-1 плюс ; для 124M — 124 439 808 (в статье — «117M»).
- В репозитории — классы
GPT2иGpt2Decoder; веса OpenAI загружаются той жеconvert_hf_state_dict.
Вопросы и упражнения
Заголовок раздела «Вопросы и упражнения»- Раскройте формулу шага 2 для и запишите как плюс сумма четырёх слагаемых.
Ответ
, где у каждого LN свои параметры.
- Каким std инициализируются
_heads._layer.weightи_ff._layer2.weightу GPT-2 1542M ()? Во сколько раз это меньше обычных 0,02?
Ответ
, то есть в раза меньше.
- Посчитайте параметры модели 345M по формуле и проверьте, какая доля приходится на эмбеддинги.
Ответ
; ; блок , 24 блока — ; — 2048. Итого . Эмбеддинги: , около 14,8 %.
- Почему при переходе от post-LN к pre-LN пришлось добавить финальный LayerNorm, и что будет, если его убрать у обученной модели?
Ответ
В pre-LN выход стека — ненормализованная сумма вкладов, её масштаб растёт с глубиной. Обученная модель рассчитывает, что в проекцию придёт нормализованный (и масштабированный из ln_f) вектор; без ln_f логиты получат другой масштаб и сдвиг, и предсказания испортятся.
- Почему byte-level BPE не нужен токен
<unk>? Какой ценой?
Ответ
Любая строка — последовательность байтов UTF-8, а все 256 байтов есть в базовом словаре, поэтому любую строку можно закодировать. Цена — редкие символы (например, кириллица или иероглифы, мало представленные в корпусе) разбиваются на несколько байтовых токенов, и последовательности становятся длиннее.
- (Код.) Создайте
GPT2с учебным конфигом и проверьте, что std весов_decoders[0]._ff._layer2.weightблизко к , а std_decoders[0]._ff._layer1.weight— к 0,02.
Ответ
m = GPT2({"vocab_size": 1000, "embed_dim": 256, "num_heads": 4, "num_layers": 4, "max_position_embeddings": 128, "dropout": 0.1})print(m._decoders[0]._ff._layer2.weight.std()) # ≈ 0.0071print(m._decoders[0]._ff._layer1.weight.std()) # ≈ 0.020- В каком порядке надо передать аргументы, чтобы
model(x, None, True)одинаково работал уGPTиGPT2? Почему лучше так не делать?
Ответ
Никак: у GPT второй позиционный аргумент — attention_mask, у GPT2 — use_cache. model(x, None, True) у GPT означает attention_mask=None, use_cache=True, а у GPT2 — use_cache=None, cache=True. Поэтому аргументы нужно передавать по имени: model(x, use_cache=True).
Литература
Заголовок раздела «Литература»Основная статья:
- Radford, Wu, Child, Luan, Amodei, Sutskever. Language Models are Unsupervised Multitask Learners. OpenAI, 2019. PDF (на arXiv не публиковалась)
Компоненты и связанные работы:
- Radford, Narasimhan, Salimans, Sutskever. Improving Language Understanding by Generative Pre-Training. OpenAI, 2018. PDF (на arXiv не публиковалась)
- Xiong et al. On Layer Normalization in the Transformer Architecture. 2020. arXiv:2002.04745 — почему pre-LN обучается стабильнее post-LN
- He, Zhang, Ren, Sun. Identity Mappings in Deep Residual Networks. 2016. arXiv:1603.05027 — pre-activation ResNet, образец для pre-LN
- Sennrich, Haddow, Birch. Neural Machine Translation of Rare Words with Subword Units. 2016. arXiv:1508.07909 — BPE-токенизация
- Hendrycks, Gimpel. Gaussian Error Linear Units (GELUs). 2016. arXiv:1606.08415
- Ba, Kiros, Hinton. Layer Normalization. 2016. arXiv:1607.06450