Мы уже умеем представлять текстовые документы в виде векторов. Такое представление позволяет использовать классические алгоритмы машинного обучения и полносвязные нейронные сети. Но сможет ли нейронная сеть извлечь всю необходимую информацию из данных, в которых все слова текста представлены единственным вектором.
В природе и в нашей жизни мы часто можем увидеть данные, которые можно представить в виде последовательности: текст, видео, звук. Для обработки таких данных придумали новый вид нейронных сетей - рекуррентные нейронные сети (RNN).
Основная особенность RNN: возможность хранить и использовать внутреннее состояние, которое модифицируется в процессе обработки последовательности данных.
Первая рекуррентная нейронная сеть (Сеть Хопфилда) была придумана в 1982 г.
Все блоки сети имеют одинаковые веса и сдвиги. Обучение всей RNN = обучение одного рекуррентного блока.
Под “всей RNN” в данном случае понимается рекуррентный слой - набор последовательно размещенных рекуррентных блоков (как на картинке). Может быть несколько слоев. Каждый следующий на вход принимает выходы предыдущего.
При создании слоя RNN определяется только размерность скрытого состояния h. Перед началом обучение его необходимо инициализировать (часто h0 - просто вектор из нулей некоторой размерности).
Вычисление скрытого состояния ht в момент времени t определяется следующим образом:
В данном примере входные данные - вектора размерности 3. Скрытое состояние имеет размерность 4.
Функцией активации в классических рекуррентных нейронных сетях служит гиперболический тангенс, однако это не является правилом - при создании сети (с использованием библиотек) можно выбрать функцию активации.
Необходимо отметить, что при реализации классической рекуррентной нейронной сети не обязательно, чтобы скрытое состояние также являлось выходом сети. Иногда вводится еще один параметр - размерность выходного слоя y. В этом случае добавляются новые веса и сдвиги и выход сети вычисляется следующим образом:
Обучая нейронную сеть, построенную в соответствии с рассмотренной архитектурой, нам придется вычислять градиент по весам Whh. Предположим, что мы считаем функцию потерь на шаге t. В этом случае в соответствии с цепным правилом градиент для Whh будет вычисляться следующим образом:
Заметим, что:
Продолжая вычисления по правило цепи, получим:
В качестве традиционной функции активации сети используется гиперболический тангенс, производная которого всегда меньше единицы. Не верите?
При больших значениях t у нас получится произведение множества чисел, которые меньше единицы. И это произведение будет стремиться к нулю.
Получаем так называемую проблему затухающих градиентов.
Можно предложить вариант использования другой функции потерь, например relu. Ее производная во всех точках кроме нуля равна единице.
Это решает проблему затухающих градиентов, но создает новую - проблему взрывающихся градиентов.
Большие значения компонент градиента могут привести к переполнению значений обучаемых весов (наглядно - будет значение NaN, очень большое число).
Для решения проблемы взрывающихся градиентов применяют подход, который называется gradient clipping. Его идея - ограничение модуля градиента. Для решения проблемы затухающих градиентов применяются особые архитектуры рекуррентных нейронных сетей.
На сегодняшний день классические рекуррентные блоки почти не используются, вместо них применяются модификации: LSTM и GRU.
Схема рекуррентного блока выглядит следующим образом:
Вычисления выполняются по следующим формулам:
Вместо гиперболического тангенса может быть использована другая функция активации. Сигмоид - это база. С помощью него реализуется имитация “забывания” состояния.
При огромной популярности архитектуры LSTM, мы отчетливо видим недостаток - дополнительные веса и сдвиги (для реализации обработки вспомогательного состояния s).
Управляемый рекуррентный блок на сегодняшний день является наиболее часто применяемой на практике реализацией рекуррентного блока.
Схема выглядит следующим образом:
Вычисления выполняются по следующим формулам:
Архитектуры рекуррентных нейронных сетей можно придумать самые разные. Реализовать каждую из них легко можно с помощью PyTorch используя линейные слои.
Не гарантируется, что использование современных архитектур рекуррентных блоков (LSTM и GRU) позволит добиться более высоко качества при решении задач, чем применение классической архитектуры блока RNN.
Рекуррентные нейронные сети являются одним из основных инструментов решения задач NLP, однако в виду специфики временной компоненты характеризуются низкой скоростью обучения.