Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Шолле Ф. - Глубокое обучение на Python (Библиотека программиста) - 2023.pdf
Скачиваний:
6
Добавлен:
07.04.2024
Размер:
11.34 Mб
Скачать

366    Глава 10. Глубокое обучение на временных последовательностях

Но.почему.модель.LSTM.показала.заметно.лучший.результат,.чем.полносвязная.и.сверточная.модели?.И.можно.ли.еще.больше.повысить.точность.модели?. Чтобы.ответить.на.эти.вопросы,.познакомимся.с.рекуррентными.нейронными. сетями.поближе.

10.3. РЕКУРРЕНТНЫЕ НЕЙРОННЫЕ СЕТИ

Главной.характеристикой.всех.нейронных.сетей,.с.которыми.мы.познакомились. к.данному.моменту,.таких.как.полносвязные.и.сверточные.нейронные.сети,. является.отсутствие.памяти..Каждый.вход.обрабатывается.ими.независимо,.без. сохранения.состояния.между.ними..Чтобы.с.помощью.таких.сетей.обработать. последовательность,.или.временной.ряд,.данных,.необходимо.передать.в.сеть. всю.последовательность.целиком,.преобразовав.ее.в.единый.пакет..Именно.так. мы.поступили.в.предыдущем.примере:.мы.объединили.все.данные.за.пять.дней. в.один.большой.вектор.и.обработали.его.целиком..Такие.сети.называют.сетями прямого распространения.(feedforward.networks).

С.другой.стороны,.читая.предложение.в.тексте,.мы.осмысливаем.его.слово.за. словом,.быстро.перескакивая.глазами.с.одного.на.другое.и.запоминая.предыдущие;.это.позволяет.нам.постепенно.вникать.в.смысл,.передаваемый.предложением..Биологический.интеллект.воспринимает.информацию.последовательно,. сохраняя.внутреннюю.модель.обрабатываемого,.основываясь.на.предыдущей. информации.и.постоянно.дополняя.эту.модель.по.мере.поступления.новой. информации.

Рекуррентная нейронная сеть .(RNN) .использует .тот .же .принцип, .хотя. и .в .чрезвычайно .упрощенном .виде: .она .обрабатывает .последовательность,. перебирая .ее .элементы .и .сохраняя .состояние, .полученное .при .обработке. предыдущих.элементов..Фактически.RNN.—.это.раз-

новидность .нейронной .сети, .имеющей .внутренний. цикл .(рис..10.6).

Сеть.RNN.сбрасывает.состояние.между.обработкой. двух.разных,.независимых.последовательностей.(таких. как.два.образца.из.пакета),.поэтому.одна.последовательность.все.еще.интерпретируется.как.единый.блок. данных:.единственный.входной.пакет..Однако.теперь. блок.данных.обрабатывается.не.за.один.шаг;.сеть.выполняет.внутренний.цикл,.перебирая.последовательность.элементов.

Рис. 10.6. Рекуррентная сеть — сеть с циклом

Чтобы.пояснить.понятия.«цикл».и.«состояние»,.реализуем.простую.сеть.RNN. с.прямой.передачей..Она.будет.принимать.на.входе.последовательность.векторов. в.виде.двумерного.тензора.с.формой.(временные_интервалы,.входные_признаки),.

Предыдущее выходное значение становится текущим состоянием для следующей итерации

10.3. Рекуррентные нейронные сети    367

перебирать.временные.интервалы.и,.учитывая.текущее.состояние.и.входные. признаки.(с.формой.(входные_признаки,)).в.момент.t,.конструировать.выходной. результат,.соответствующий.моменту.t..Этот.результат.затем.будет.сохраняться. во.внутреннем.состоянии.как.подготовка.к.следующей.итерации..Для.первого. временного.интервала.предыдущий.выходной.результат.не.определен;.в.этот. момент.сеть.не.имеет.текущего.состояния..Поэтому.текущее.состояние.первоначально.инициализируется.вектором.с.нулевыми.значениями.элементов,.который. называют.начальным состоянием.сети.

Ниже.представлена.реализация.этой.RNN.в.псевдокоде.

Листинг 10.13. Реализация RNN в псевдокоде

state_t = 0 Состояние в момент t for input_t in input_sequence:

output_t = f(input_t, state_t) state_t = output_t

Цикл по последовательности элементов

Функцию.f .можно.конкретизировать.еще.больше:.она.преобразует.входные. данные.и.состояние.в.выходной.результат.и.параметризуется.двумя.матрицами,. W.и.U,.и.вектором.смещений..Она.напоминает.полносвязный.слой.в.сети.прямого. распространения.

Листинг 10.14. Более подробная реализация RNN в псевдокоде

state_t = 0

for input_t in input_sequence:

output_t = activation(dot(W, input_t) + dot(U, state_t) + b) state_t = output_t

Чтобы.сделать.эти.понятия.абсолютно.однозначными,.напишем.упрощенную. реализацию.сети.RNN.на.основе.NumPy.

Листинг 10.15. Реализация сети RNN на основе NumPy

Число временных

 

 

 

Размерность пространства

 

 

интервалов во входной

 

 

 

входных признаков

последовательности

 

 

 

 

Размерность пространства

import numpy as np

 

 

 

 

 

 

 

 

выходных признаков

timesteps = 100

 

 

 

 

 

 

 

 

 

 

 

 

Входные данные: случайный

 

 

 

 

 

 

input_features = 32

 

 

 

 

 

 

 

 

 

 

шум для простоты примера

output_features = 64

 

 

 

 

 

 

 

 

 

inputs = np.random.random((timesteps, input_features)) state_t = np.zeros((output_features,))

W = np.random.random((output_features, input_features)) U = np.random.random((output_features, output_features)) b = np.random.random((output_features,))

Начальное состояние: вектор с нулевыми значениями элементов

Создание матриц со случайными весами

Сохранение выходных данных в список
input_t — вектор с формой (входные_признаки,)

368    Глава 10. Глубокое обучение на временных последовательностях

successive_outputs = []

for input_t in inputs:

output_t = np.tanh(np.dot(W, input_t) + np.dot(U, state_t) + b) successive_outputs.append(output_t)

state_t = output_t final_output_sequence = np.stack(successive_outputs, axis=0)

Окончательный результат — двумерный тензор с формой (временные_интервалы, выходные_признаки)

Обновление текущего состояния сети как подготовка к обработке следующего временного интервала

Объединение входных данных с текущим состоянием (выходными данными на предыдущем шаге). Функция tanh используется для придания нелинейности (здесь можно взять любую другую функцию активации)

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

output_t = np.tanh(np.dot(W, input_t) + np.dot(U, state_t) + b)

Рис. 10.7. Простая рекуррентная сеть, развернутая во времени

ПРИМЕЧАНИЕ

В . этом . примере . конечный . результат . имеет . вид . двумерного . тензора . с . формой. (временные_интервалы,.выходные_признаки),.где.каждый.временной.интервал.—. это.результат.цикла.в.момент.времени.t..Каждому.временному.интервалу.t.в.вы­ ходном.тензоре.соответствует.информация.о.временных.интервалах.от.0.до.t.во. входной.последовательности.—.обо.всем.прошлом..Поэтому.во.многих.случаях.нет. необходимости.иметь.всю.последовательность.результатов;.достаточно.получить. последний.результат.(значение.output_t.по.окончании.цикла),.так.как.он.уже.содержит. информацию.обо.всей.последовательности.

10.3.Рекуррентные нейронные сети    369

10.3.1.Рекуррентный слой в Keras

Процессу,.который.мы.только.что.реализовали.с.применением.NumPy,.соответ- ствует.фактический.слой.в.Keras.—.слой.SimpleRNN..С.одним.незначительным. отличием:.SimpleRNN.обрабатывает.пакеты.последовательностей,.как.и.все.другие. слои.в.Keras,.а.не.единственную.последовательность,.как.наш.предыдущий.пример..Это.означает,.что.он.принимает.входные.данные.с.формой.(размер_пакета,.

временные_интервалы,.входные_признаки),.а.не.(временные_интервалы,.вход-

ные_признаки)..Обратите.внимание,.что.при.вызове.Input() .с.аргументом.shape . в.элементе.временные_интервалы.можно.передать.значение.None .—.это.позволит. сети.обрабатывать.последовательности.произвольной.длины.

Листинг 10.16. Слой сети RNN, способный обрабатывать последовательности любой длины

num_features = 14

inputs = keras.Input(shape=(None, num_features)) outputs = layers.SimpleRNN(16)(inputs)

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

Все.рекуррентные.слои.в.Keras.(SimpleRNN,.LSTM .и.GRU).могут.действовать. в.двух.разных.режимах:.возвращать.полные.последовательности.результатов. для.всех.временных.интервалов.(трехмерный.тензор.с.формой.(размер_пакета,.

временные_интервалы,.выходные_признаки)) .или .только .последний .результат.для.каждой.входной.последовательности.(двумерный.тензор.с.формой. (размер_пакета,.входные_признаки))..Режимы .управляются .аргументом. return_sequences .конструктора..Рассмотрим.пример,.в.котором.используется. слой.SimpleRNN .и.возвращается.результат.только.для.последнего.временного. интервала.

Листинг 10.17. Слой сети RNN, возвращающий результат только для последнего интервала

>>>

num_features = 14

Обратите внимание, что return_sequences=False —

>>>

steps = 120

это значение по умолчанию

>>>inputs = keras.Input(shape=(steps, num_features))

>>>outputs = layers.SimpleRNN(16, return_sequences=False)(inputs)

>>>print(outputs.shape)

(None, 16)

370    Глава 10. Глубокое обучение на временных последовательностях

Следующий.пример.возвращает.полную.последовательность.состояний.

Листинг 10.18. Слой рекуррентной сети, возвращающий полную последовательность результатов

>>>num_features = 14

>>>steps = 120

>>>inputs = keras.Input(shape=(steps, num_features))

>>>outputs = layers.SimpleRNN(16, return_sequences=True)(inputs)

>>>print(outputs.shape)

(120, 16)

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

Листинг 10.19. Стек из нескольких слоев RNN

inputs = keras.Input(shape=(steps, num_features))

x = layers.SimpleRNN(16, return_sequences=True)(inputs) x = layers.SimpleRNN(16, return_sequences=True)(x) outputs = layers.SimpleRNN(16)(x)

На.практике,.однако,.слои.SimpleRNN .используются.довольно.редко.—.в.боль- шинстве.случаев.они.слишком.простые.для.реального.применения..В.частности,. SimpleRNN .страдает.одной.существенной.проблемой:.теоретически.в.каждый. момент.времени.t .он.должен.хранить.информацию.о.входных.данных.за.многочисленные.предыдущие.интервалы.времени,.но.на.практике.такие.протяженные.зависимости.не.поддаются.обучению..Это.связано.с.проблемой затухания градиента,.напоминающего.эффект,.который.наблюдается.в.нерекуррентных. сетях.(сетях.прямого.распространения).с.большим.количеством.слоев:.по.мере. увеличения.количества.слоев.сеть.в.конечном.итоге.становится.необучаемой.. Теоретическое.обоснование.этого.эффекта.было.дано.Хохрейтером,.Шмидху- бером.и.Бенгио.в.начале.1990-х.годов1.

К.счастью, SimpleRNN.—.не.единственный.рекуррентный.слой,.доступный.в.Keras.. Кроме.него,.имеются.также.слои.LSTM .и.GRU,.разработанные.специально.для. решения.подобных.проблем.

Рассмотрим.слой.LSTM..Лежащий.в.его.основе.алгоритм.долгой.краткосрочной. памяти.(long.short-term.memory,.LSTM).был.разработан.Хохрейтером.и.Шмид- хубером.в.1997.году2;.он.стал.кульминацией.их.исследований.проблемы.затухания.градиента.

1. См.,.например:.Bengio Y., Simard P., Frasconi P..Learning.Long-Term.Dependencies.with. Gradient.Descent.Is.Difficult.//.IEEE.Transactions.on.Neural.Networks.5,.no..2..1994.

2 . Hochreiter S., Schmidhuber J..Long.Short-Term.Memory.//.Neural.Computation.9,.no..8..1997.

10.3. Рекуррентные нейронные сети    371

Этот.слой.является.вариантом.слоя.SimpleRNN,.уже.знакомого.вам;.он.добавляет. поддержку.переноса.информации.через.многие.интервалы.времени..Вообразите. конвейерную.ленту,.движущуюся.параллельно.обрабатываемой.последовательности..Информация.из.последовательности.может.в.любой.момент.перекладываться.на.конвейерную.ленту,.переноситься.к.более.поздним.интервалам.времени. и.сниматься.с.ленты,.если.она.необходима..В.этом.заключается.суть.работы.слоя. LSTM:.он.сохраняет.информацию.для.последующего.использования,.тем.самым. предотвращая.постепенное.затухание.старых.сигналов.во.время.обработки..

Данное.решение.напоминает.остаточные связи,.с.которыми.вы.познакомились. в.главе.9;.в.действительности.в.его.основе.лежит.практически.та.же.самая.идея.

Чтобы.разобраться.более.детально,.начнем.с.ячейки.SimpleRNN.(рис..10.8)..Так.как. у.нас.имеется.большое.количество.весовых.матриц,.выходные.матрицы.W.и.U.в.ячей- ке.мы.обозначим.индексом.o.(Wo.и.Uo).—.от.англ..output.(«выходной,.на.выходе»).

Рис. 10.8. Начальная точка слоя LSTM: слой SimpleRNN

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

Эта.информация.будет.оказывать.следующее.влияние.на.ячейку:.объединяться. с.входящей.и.рекуррентной.связями.(путем.плотного.преобразования:.скалярное.произведение.на.весовую.матрицу.с.добавлением.смещения.и.применением. функции.активации).и.влиять.на.состояние,.передаваемое.в.следующий.интервал. времени.(через.функцию.активации.и.операцию.умножения)..Концептуально. поток.переноса.информации.осуществляет.модулирование.следующего.результата.и.следующего.состояния.(рис..10.9)..Пока.все.довольно.просто.

А.теперь.о.деталях.способа.вычисления.следующего.значения.в.несущем.потоке.данных:.он.основывается.на.трех.разных.преобразованиях,.все.три.имеют. форму.ячейки.SimpleRNN:

y = activation(dot(state_t, U) + dot(input_t, W) + b)

372    Глава 10. Глубокое обучение на временных последовательностях

Рис. 10.9. Переход от SimpleRNN к LSTM: добавление несущего потока

Однако.эти.преобразования.имеют.свои.весовые.матрицы,.которые.мы.обозначим. индексами.i,.f .и.k..Вот.что.у.нас.есть.(это.может.показаться.необоснованным,. но.наберитесь.терпения,.я.все.объясню.позже).

Листинг 10.20. Реализация архитектуры LSTM в псевдокоде (1/2)

output_t = activation(dot(state_t, Uo) + dot(input_t, Wo) + dot(c_t, Vo) + bo) i_t = activation(dot(state_t, Ui) + dot(input_t, Wi) + bi)

f_t = activation(dot(state_t, Uf) + dot(input_t, Wf) + bf) k_t = activation(dot(state_t, Uk) + dot(input_t, Wk) + bk)

Получим.новое.перенесенное.состояние.(c_t),.объединив.i_t,.f_t .и.k_t.

Листинг 10.21. Реализация архитектуры LSTM в псевдокоде (2/2)

c_t+1 = i_t * k_t + c_t * f_t

Добавим.это.в.общую.картину,.как.показано.на.рис..10.10..Вот.и.все..Совсем. несложно,.просто.немного.замысловато.

Если.хотите.удариться.в.философию,.подумайте.о.том,.что.делает.каждая.из. этих.операций..Например,.можно.сказать,.что.умножение.c_t.на.f_t.—.это.способ. преднамеренного.забывания.ненужной.информации.в.несущем.потоке.данных..

А.умножение.i_t.на.k_t.представляет.информацию.о.настоящем,.добавляя.новую. информацию.в.несущий.поток..Но.в.конечном.счете.эти.интерпретации.не.имеют. большого.значения,.потому.что.фактическое.действие.операций.определяется. содержимым.параметризующих.их.весов,.а.веса.вычисляются.непрерывно.и.за- ново.в.каждом.цикле.обучения,.что.делает.невозможным.приписать.какую-то. конкретную.цель.той.или.иной.операции..Спецификация.ячейки.RNN.(как. только.что.было.описано).определяет.ваше.пространство.гипотез.—.пространство,. в.котором.в.процессе.обучения.вы.будете.искать.оптимальные.настройки.модели,.