12 / 37 · Нейросетевые модели последовательностей
Рекуррентные нейронные сети
Сеть, которая читает по одному токену и несёт скрытое состояние, в принципе имеет неограниченный контекст и число параметров, не зависящее от длины; она может классифицировать последовательность по последнему состоянию или предсказывать следующий токен на каждом шаге. Градиенты через много шагов затухают или взрываются, и это ограничивает то, что контекст может удержать на деле.
CNN для классификации текстов · N-граммные языковые модели · Обратное распространение ошибки
На этой странице 9
Свёрточный классификатор из предыдущей заметки видит окно из токенов и забывает позицию при пулинге. N-граммная языковая модель из более ранней заметки видит токенов и не умеет обобщать между ними. У обеих контекст фиксированного маленького размера. Эта заметка вводит модель, контекст которой в принципе — весь префикс: она читает токены по порядку и хранит их сводку в векторе, который обновляет на каждом шаге.
Обозначения. Входные векторы токенов ; скрытые состояния ; выходы . Матрицы весов , , и смещения . — поэлементное произведение.
Рекурсия#
читает текущий токен, переносит предыдущее состояние вперёд, а держит каждую координату в . На каждом шаге используются одни и те же , поэтому число параметров равно при любом : последовательность из 5 токенов и последовательность из 500 прогоняют одну и ту же ячейку 5 или 500 раз. Развёрнутое во времени, вычисление — цепочка одинаковых ячеек, единственная связь между которыми — скрытое состояние.
Размерности для батча: вход , скрытые состояния , последнее состояние . Модуль PyTorch nn.RNN(d, H, batch_first=True) возвращает и всю последовательность состояний, и последнее.
Разобранный пример#
Скалярный случай: , , , , входы :
| 1 | 1 | ||
| 2 | 0 | ||
| 3 | 0 |
Вход шага 1 всё ещё виден в , ослабленный в раза на каждом шаге и ещё . При тот же вход рос бы: , , с насыщением у края диапазона . Рекуррентный вес решает, затухает прошлое или затапливает всё, и это один и тот же вес на каждом шаге, так что что бы он ни делал, он делает это раз.
Шаг за шагом#
Шаг рекуррентной сети: что куда идёт
Номера на рисунке следуют за одним применением ячейки:
- Прочитать вход. — вклад текущего токена, вектор из чисел.
- Прочитать память. — вклад предыдущего состояния; на первом шаге , и это слагаемое пропадает.
- Сложить. Два вектора и смещение складываются покоординатно.
- Сжать. переводит каждую координату в ; результат — новое состояние .
- Предсказать, если нужно. даёт оценки классов или токенов словаря, а softmax превращает их в вероятности.
- Передать состояние дальше. становится следующего шага, который повторяет шаги 1–5 с теми же , и .
Модели следующих заметок сохраняют этот скелет — состояние, которое передаётся от шага к шагу и обновляется по текущему входу, — и каждая меняет одну его часть. LSTM меняет то, как обновляется состояние, seq2seq передаёт последнее состояние от одной сети другой, внимание позволяет второй сети оглядываться на каждое состояние первой, а self-attention отказывается от цепочки совсем. Их рисунки используют те же цвета: зелёный для входов, синий для состояний, янтарный для весов и гейтов, красный для выходов и янтарную рамку для того, что модель добавляет к предыдущей.
Два способа использовать состояния#
Одна рекурсия, два способа использовать состояния
RNN как классификатор#
Прочитать документ целиком и взять последнее состояние в качестве его представления: . В отличие от max-pooling, вычисляется по порядку, поэтому в принципе может отличить not good от good not. В постановке AG News из предыдущей заметки однослойная GRU (ячейка с гейтами из следующей заметки) с читает те же 100-мерные векторы Word2Vec и подаёт последнее состояние линейному слою. У неё параметров — столько же по порядку, сколько у свёрточных моделей.
Одна практическая деталь. Последнее состояние дополненной последовательности — это состояние после токенов паддинга, а не после последнего настоящего токена. Можно упаковать последовательности, чтобы рекурсия останавливалась на истинной длине, можно ставить паддинг в начало, а можно брать состояние с индексом length - 1 для каждого примера.
RNN как языковая модель#
Выдавать выход на каждом шаге и делать его распределением по словарю:
Это разложение по формуле умножения вероятностей из n-граммной заметки без марковского предположения: условная вероятность зависит от , которое зависит от всего префикса. Обучение использует teacher forcing: входная последовательность — текст без последнего токена, , цели — , а функция потерь — кросс-энтропия, просуммированная по позициям, то есть ровно отрицательный логарифм правдоподобия на токен, экспонента которого — перплексия. Позиции паддинга исключаются из функции потерь через ignore_index. При порождении на вход следующего шага подаётся собственный сэмпл модели, как в любой авторегрессионной модели.
Размерности: идентификаторы → эмбеддинги → состояния → логиты . Кросс-энтропия считается на развёрнутых логитах относительно целей .
Возьмём модель над словарём BPE из токенов с и : у неё 9.6 млн параметров во входном эмбеддинге, 0.39 млн в рекуррентной ячейке и 19.3 млн в выходном слое, всего 29.3 млн. Две трети модели — выходной softmax: та же структура затрат, которая привела к негативному сэмплированию в Word2Vec; в языковой модели полный softmax сохраняют, потому что выходом служит само распределение. К перплексиям нейросетевых языковых моделей на трансформере возвращается заметка о GPT.
Градиенты во времени#
Обучение разворачивает рекурсию и распространяет ошибку обратно через каждый шаг. Градиент функции потерь на шаге по состоянию на шаге проходит через применений ячейки:
Каждый множитель — та же , масштабированная производной (не больше 1). Если наибольшее сингулярное число меньше 1, произведение убывает геометрически, и градиент затухает: функция потерь в конце предложения не может поправить то, что ячейка сделала в его начале. Если оно больше 1, произведение может расти, и градиент взрывается (Pascanu, Mikolov and Bengio, 2013 показывают, что это условие необходимое, но не достаточное). При скалярном рекуррентном весе и состояниях в линейной части , где её производная близка к 1, пятьдесят шагов умножают градиент на . Рисунок ниже, общий с заметкой курса по генеративным моделям, где вычисление расписано подробно, показывает механизм.
Развёрнутая RNN с рекуррентным весом w = 2
Два следствия для практики. Обрезка градиентов (gradient clipping) масштабирует вектор градиента, когда его норма превышает порог, например 1.0; это не даёт взрывам разрушить веса, но ничего не делает с затуханием. А затухание — главное ограничение: обычная RNN выучивает зависимости на несколько токенов и теряет остальное, поэтому «контекст — весь префикс» верно для прямого прохода, но не для того, чему модель учится (Bengio, Simard and Frasconi, 1994). Следующая заметка меняет ячейку так, чтобы у состояния был аддитивный путь с множителем градиента около 1.
Что изменилось#
| CNN-классификатор | N-граммная ЯМ | RNN | |
|---|---|---|---|
| Контекст | токенов на фильтр | токенов | Весь префикс (в принципе) |
| Параметры и длина | Не зависят | Таблица растёт с данными | Не зависят |
| Позиция | Теряется при пулинге | Только последние | Закодирована в порядке состояний |
| Обобщает между токенами | Да (эмбеддинги) | Нет | Да |
| Порождение | Нет | Да | Да, с выходом на классов |
| Параллельно по | Да | — | Нет: требует |
Ограничения#
- Короткая эффективная память. Градиенты затухают за десятки шагов; состояние нельзя обучить долго хранить информацию.
- Последовательные вычисления. Шаг ждёт шага , поэтому RNN не может использовать параллелизм GPU вдоль последовательности. Время обучения на пример растёт линейно по , и заметка о трансформере сделает это главным доводом против рекурсии.
- Одно состояние на всё. Единственный вектор должен подытожить весь вход. Для классификации этого достаточно; для перевода предложения из 30 слов это узкое место, в которое упирается заметка о seq2seq.
- Паддинг взаимодействует с последним состоянием. Переменная длина требует упаковки или масок, которые не были нужны свёрточной модели.
Что нужно запомнить#
- : одна и та же ячейка на каждом шаге, параметры не зависят от длины, состояние несёт префикс.
- Классификатор: последнее состояние → линейный слой. Языковая модель: каждое состояние → softmax по , обучение через teacher forcing на сдвинутой последовательности без учёта паддинга.
- Градиент через шагов — произведение копий ; он затухает или взрывается геометрически. Обрезка справляется только со взрывом.
- Рекурсия последовательна: вдоль последовательности нет параллелизма.
Ноутбук#
Два ноутбука. Номера ячеек считают все ячейки, включая текстовые, начиная с 1. Приведённые числа взяты из прогона, сохранённого в курсе; у ячеек, изменённых с тех пор под текущие версии библиотек, сохранённого выхода нет.
week02_NN_text_classification.ipynb, ячейки 40–43: SimpleRNN оборачивает nn.GRU(100, 128, batch_first=True) и линейный слой на последнем скрытом состоянии и обучается тем же циклом, что и свёрточные модели, 5 эпох. Итоговой распечатки в сохранённых выходах нет, поэтому в курсе нет доли правильных ответов, чтобы сравнить эту GRU со свёрточными классификаторами и с базовым уровнем TF-IDF. Классификатор берёт последнее состояние после токенов паддинга, а не после последнего настоящего токена — упрощение, разобранное в разделе RNN как классификатор.
- Ячейки 46–49 токенизируют корпус анекдотов BPE и строят словарь из 37 580 записей с фиксированными идентификаторами для
<pad>(0) и<unk>(1). - Ячейка 51 строит батчи: каждый анекдот обрезается до 128 токенов, входы —
s[:-1], цели —s[1:], и те и другие дополняются нулями. - Ячейка 52 определяет
SimpleRNNLM:nn.Embedding(V, 256, padding_idx=0),nn.RNN(256, 512, batch_first=True),nn.Linear(512, V)— модель на 29.3 млн параметров, посчитанная в разделе RNN как языковая модель. - Ячейка 53 прогоняет одну эпоху: кросс-энтропия с
ignore_index=0, обрезка нормы градиента на 1.0 и перплексия как от средних по токенам потерь (выше потерь 20 она полагается равной , чтобы избежать переполнения). Ячейка 55 обучает три эпохи с AdamW при и батчами по 64; прогон, сохранённый в курсе, был прерван после нескольких батчей, поэтому сохранённых перплексий нет. Softmax на 37 580 токенов делает эту ячейку практичной только на GPU с CUDA, о чём говорит текстовая ячейка перед ней.
Дальше#
Рекурсия даёт модели память, а градиент её отнимает. Следующая заметка сохраняет рекурсию и перестраивает ячейку: отдельная линия памяти, которая обновляется аддитивно, и гейты, решающие, что записать, что сохранить и что прочитать, так что градиент вдоль линии памяти — произведение множителей, близких к 1, а не матриц .
Литература#
- J. L. Elman. Finding Structure in Time. Cognitive Science, 14(2), 1990. Простая рекуррентная сеть.
- Y. Bengio, P. Simard, P. Frasconi. Learning long-term dependencies with gradient descent is difficult. IEEE Transactions on Neural Networks, 5(2), 1994.
- R. Pascanu, T. Mikolov, Y. Bengio. On the difficulty of training recurrent neural networks. ICML, 2013. Анализ произведения якобианов и обрезка градиентов.
- T. Mikolov, M. Karafiát, L. Burget, J. Černocký, S. Khudanpur. Recurrent neural network based language model. Interspeech, 2010.
- I. Goodfellow, Y. Bengio, A. Courville. Deep Learning. MIT Press, 2016. Глава 10 (моделирование последовательностей, teacher forcing, долгосрочные зависимости).