Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

8.4 Рекуррентные нейронные сети

В разделе 8.3 мы ввели модель -грамм, в которой условная вероятность появления слова на временном шаге зависит только от предыдущих слов. Если мы хотим учитывать влияние слов, которые стоят дальше, чем на шагов назад, нужно увеличивать . Однако число параметров модели при этом растёт экспоненциально, поскольку словарь должен хранить чисел. Поэтому вместо моделирования лучше использовать модель со скрытой переменной:

где — скрытое состояние (hidden state), также называемое скрытой переменной (hidden variable), которое хранит информацию о последовательности до временного шага . Обычно скрытое состояние на временном шаге можно вычислить по текущему входу и предыдущему скрытому состоянию :

Для функции из (8.4.1) модель со скрытой переменной не является приближением. В самом деле, может хранить все данные, наблюдённые до этого момента, однако такая операция может быть дорогой как по вычислениям, так и по памяти.

Вспомним скрытые слои с их скрытыми элементами, о которых шла речь в главе 4. Важно отличать скрытые слои от скрытых состояний. Как уже было сказано, скрытые слои находятся на пути от входа к выходу, если смотреть на них с точки зрения наблюдаемых величин, тогда как скрытое состояние — это то, что поступает на вход на каждом шаге, и вычисляется оно только по данным предыдущих временных шагов.

Рекуррентные нейронные сети (recurrent neural networks, RNNs) — это нейронные сети со скрытым состоянием. Прежде чем вводить модель рекуррентной сети, вспомним многослойный перцептрон из раздела 4.1.

8.4.1 Нейронные сети без скрытых состояний

Посмотрим на многослойный перцептрон с одним скрытым слоем. Пусть функция активации скрытого слоя равна . Дан минибатч размера с входной размерностью . Тогда выход скрытого слоя вычисляется по формуле

В (8.4.2) параметры скрытого слоя — весовая матрица и вектор смещения , а число скрытых элементов равно . Поэтому при сложении можно применить механизм broadcasting (см. раздел 2.1.3). Далее скрытую переменную используем как вход выходного слоя. Выходной слой задаётся формулой

где — выходные данные, — весовая матрица, а — вектор смещения выходного слоя. Если решается задача классификации, то для вычисления вероятностного распределения по классам можно использовать .

Это полностью аналогично задаче регрессии, которую мы решали в разделе 8.1, поэтому подробности опускаем. Достаточно того, что можно случайным образом выбирать пары «признаки — метка» и обучать параметры сети с помощью автоматического дифференцирования и стохастического градиентного спуска.

8.4.2 Рекуррентные нейронные сети со скрытыми состояниями

Когда появляется скрытое состояние, ситуация становится совсем другой. Пусть на временном шаге поступает минибатч входных данных . Иными словами, для минибатча из последовательностей каждая строка соответствует одному примеру из этой последовательности на временном шаге . Обозначим через скрытую переменную на временном шаге . В отличие от многослойного перцептрона, здесь мы сохраняем скрытую переменную предыдущего шага и вводим новый весовой параметр , который описывает, как использовать скрытую переменную предыдущего шага на текущем шаге. Конкретно, скрытая переменная текущего шага вычисляется по текущему входу и скрытой переменной предыдущего шага:

По сравнению с (8.4.2) в (8.4.3) добавлено слагаемое , которое реализует (8.4.1). Из связи между скрытыми переменными и видно, что эти переменные хранят и сохраняют историю последовательности до текущего временного шага, подобно состоянию или памяти нейронной сети на текущем шаге. Поэтому такие скрытые переменные называют скрытыми состояниями (hidden state). Поскольку на текущем шаге скрытое состояние определяется так же, как и на предыдущем, вычисление (8.4.3) является рекуррентным (recurrent). Отсюда и название: нейронные сети, в которых скрытое состояние вычисляется рекуррентно, называют рекуррентными нейронными сетями (recurrent neural network). Слой, который выполняет вычисления (8.4.3), называют рекуррентным слоем (recurrent layer).

Существует много способов построить рекуррентную нейронную сеть. Сеть со скрытым состоянием, заданным формулой (8.4.3), — одна из самых распространённых. Для шага выход выходного слоя вычисляется так же, как в многослойном перцептроне:

Параметры рекуррентной нейронной сети включают веса скрытого слоя , и смещение , а также веса выходного слоя и смещение . Стоит отметить, что на разных временных шагах рекуррентная нейронная сеть всегда использует одни и те же параметры модели. Поэтому число параметров сети не растёт с увеличением числа временных шагов.

На рис. 8.4.1 показана логика вычислений рекуррентной нейронной сети на трёх соседних временных шагах. На произвольном шаге вычисление скрытого состояния можно представить так:

  1. объединить входной вектор текущего шага и скрытое состояние предыдущего шага ;
  2. подать результат объединения в полносвязный слой с функцией активации . Выход этого полносвязного слоя — скрытое состояние текущего шага .

В данном случае параметры модели — это конкатенация и и смещение , все они берутся из (8.4.3). Скрытое состояние текущего шага участвует в вычислении скрытого состояния следующего шага . Кроме того, подаётся в полносвязный выходной слой, с помощью которого вычисляется выход текущего шага.

Рис. 8.4.1. Рекуррентная нейронная сеть со скрытым состоянием

Выше мы упомянули, что вычисление в скрытом состоянии эквивалентно умножению матрицы, полученной конкатенацией и , на матрицу, полученную конкатенацией и . Это свойство можно доказать математически, но ниже мы проверим его простым кодом. Сначала определим матрицы X, W_xh, H и W_hh, их формы — , , и . Перемножим X с W_xh, H с W_hh, а затем сложим оба произведения: получим матрицу формы .

MXNet:

from d2l import mxnet as d2l
from mxnet import np, npx
npx.set_np()

PyTorch:

from d2l import torch as d2l
import torch

TensorFlow:

from d2l import tensorflow as d2l
import tensorflow as tf

PaddlePaddle:

from d2l import paddle as d2l
import warnings
warnings.filterwarnings("ignore")
import paddle

MXNet, PyTorch, PaddlePaddle:

X, W_xh = d2l.normal(0, 1, (3, 1)), d2l.normal(0, 1, (1, 4))
H, W_hh = d2l.normal(0, 1, (3, 4)), d2l.normal(0, 1, (4, 4))
d2l.matmul(X, W_xh) + d2l.matmul(H, W_hh)

TensorFlow:

X, W_xh = d2l.normal((3, 1), 0, 1), d2l.normal((1, 4), 0, 1)
H, W_hh = d2l.normal((3, 4), 0, 1), d2l.normal((4, 4), 0, 1)
d2l.matmul(X, W_xh) + d2l.matmul(H, W_hh)

Теперь объединим матрицы X и H по столбцам (ось 1), а матрицы W_xh и W_hh — по строкам (ось 0). Эти конкатенации дают матрицы формы и . Перемножив эти две объединённые матрицы, получим выходную матрицу той же формы , что и выше.

d2l.matmul(d2l.concat((X, H), 1), d2l.concat((W_xh, W_hh), 0))

8.4.3 Символьная языковая модель на основе рекуррентной нейронной сети

Вспомним языковую модель из раздела 8.3: наша цель — по прошлым и текущим токенам предсказать следующий токен, поэтому в качестве меток мы берём исходную последовательность, сдвинутую на один токен. Бенджио и соавторы впервые предложили использовать нейронные сети для языкового моделирования (Bengio et al., 2003). Далее рассмотрим, как построить языковую модель с помощью рекуррентной нейронной сети. Пусть размер минибатча равен , а текстовая последовательность в батче — «machine». Чтобы упростить обучение в дальнейшем, рассмотрим символьную языковую модель (character-level language model): текст разбивается на токены-символы, а не на слова. На рис. 8.4.2 показано, как с помощью символьной языковой модели на основе рекуррентной нейронной сети предсказать следующий символ по текущему и предыдущим символам.

Рис. 8.4.2. Символьная языковая модель на основе рекуррентной нейронной сети: входная и выходная последовательности — «machin» и «achine»

В ходе обучения мы применяем softmax к выходу выходного слоя на каждом временном шаге, а затем с помощью кросс-энтропийной функции потерь вычисляем ошибку между выходом модели и метками. Из-за рекуррентного вычисления скрытого состояния выход на третьем временном шаге на рис. 8.4.2 определяется последовательностью символов «m», «a» и «c». Поскольку в обучающих данных следующий символ этой последовательности — «h», потеря на третьем шаге зависит от вероятностного распределения следующего символа, которое строится по признакам «m», «a», «c» и метке «h» этого шага.

На практике мы используем минибатч размера , а каждый токен представляется -мерным вектором. Поэтому входной элемент на временном шаге будет матрицей размера , как и в обсуждении в разделе 8.4.2.

8.4.4 Перплексия (perplexity)

Наконец, обсудим, как измерять качество языковой модели; эта мера будет использоваться для оценки моделей на основе рекуррентных нейронных сетей в следующих разделах. Хорошая языковая модель способна очень точно предсказать, что мы увидим дальше. Рассмотрим продолжения фразы «It is raining …» («…дождь») от разных языковых моделей:

  1. «It is raining outside» («На улице дождь»);
  2. «It is raining banana tree» («На банановое дерево идёт дождь»);
  3. «It is raining piouw;kcj pwepoiut» («piouw;kcj pwepoiut — дождь»).

С точки зрения качества пример очевидно самый разумный и логически связный. Хотя модель, возможно, не очень точно отражает семантику последующих слов, ведь более совершенными продолжениями могли бы быть «It is raining in San Francisco» («В Сан-Франциско идёт дождь») и «It is raining in winter» («Зимой идёт дождь»), модель уже научилась определять, какие классы слов идут дальше. Пример гораздо хуже, поскольку он даёт бессмысленное продолжение. Тем не менее модель хотя бы научилась писать слова и улавливать некоторую связь между словами. Наконец, пример показывает, что недостаточно обученная модель не может правильно описать данные.

Качество модели можно измерить, вычислив правдоподобие последовательности. Однако это число трудно понимать и сравнивать. Ведь короткие последовательности гораздо более вероятны, чем длинные, поэтому вероятность того, что модель породит роман Толстого «Война и мир», неизбежно будет гораздо меньше, чем вероятность того, что она породит небольшую повесть Сент-Экзюпери «Маленький принц». При этом недостающее правдоподобие фактически соответствует среднему значению.

Здесь может помочь теория информации. Мы определяли энтропию, информационное содержание и кросс-энтропию, когда вводили softmax-регрессию (раздел 3.4.7), а дополнительные сведения по теории информации приведены в онлайн-приложении по теории информации. Если мы хотим сжать текст, можно предсказывать следующий токен по набору текущих токенов. Лучшая языковая модель позволяет точнее предсказывать следующий токен, а значит, при сжатии последовательности потребуется меньше битов. Поэтому качество можно измерить через среднее значение кросс-энтропийной потери по всем токенам последовательности:

где задаётся языковой моделью, а — фактический токен, наблюдаемый в последовательности на временном шаге . Это позволяет сравнивать качество документов разной длины. По историческим причинам специалисты по обработке естественного языка предпочитают использовать величину, которая называется перплексия (perplexity). Это просто экспонента от (8.4.4):

Перплексию лучше всего понимать как «среднее гармоническое число фактических вариантов выбора следующего токена». Рассмотрим несколько случаев.

  • В лучшем случае модель всегда идеально оценивает вероятность метки-токена как . В этом случае перплексия модели равна .
  • В худшем случае модель всегда предсказывает вероятность метки-токена, равную . В этом случае перплексия равна плюс бесконечности.
  • В качестве базовой линии модель предсказывает равномерное распределение по всем доступным токенам словаря. В этом случае перплексия равна числу уникальных токенов в словаре. Более того, если хранить последовательность без какого-либо сжатия, это и будет наилучший способ кодирования. Поэтому такая оценка даёт важную верхнюю границу, которую должна превзойти любая практическая модель.

В следующих подразделах мы реализуем символьную языковую модель на основе рекуррентной нейронной сети и будем оценивать её с помощью перплексии.

Резюме

  • Нейронная сеть, которая вычисляет скрытое состояние рекуррентно, называется рекуррентной нейронной сетью (RNN).
  • Скрытое состояние рекуррентной нейронной сети может хранить историю последовательности до текущего временного шага.
  • Число параметров рекуррентной нейронной сети не растёт с увеличением числа временных шагов.
  • С помощью рекуррентной нейронной сети можно построить символьную языковую модель.
  • Для оценки качества языковой модели можно использовать перплексию.

Упражнения

  1. Если мы используем рекуррентную нейронную сеть для предсказания следующего символа в текстовой последовательности, какова размерность выхода для каждого варианта?
  2. Почему рекуррентная нейронная сеть может на каком-либо временном шаге представлять условную вероятность текущего токена, опираясь на все предыдущие токены текстовой последовательности?
  3. Что происходит с градиентами, если выполнять обратное распространение по длинной последовательности?
  4. Какие проблемы связаны с языковой моделью, которую мы описали в этом разделе?

MXNet: Обсуждение

PyTorch: Обсуждение

TensorFlow: Обсуждение

PaddlePaddle: Обсуждение

Литература

  • Bengio, Y., Ducharme, R., Vincent, P., & Jauvin, C. (2003). A neural probabilistic language model. Journal of Machine Learning Research, 3, 1137–1155.