Как одна и та же ячейка обрабатывает последовательность любой длины?
Рекуррентная сеть читает последовательность по одному элементу и переносит
вперёд скрытое состояние. Одни и те же веса работают на каждом шаге, поэтому
модель принимает строки любой длины. Но память не даётся бесплатно: её надо
протащить сквозь многократное перемножение, и ровно там она теряется —
сначала в градиенте, потом в самом состоянии.
Датчик, который не помнит вчерашнего дня
Счётчик у входа в парк сообщает, сколько велосипедов взяли за прошлый час.
Много это или мало? Ответа нет, пока мы не знаем, что было час назад, вчера в это же
время и какой сегодня день недели. Одно число без истории почти не несёт
информации.
Реальные данные это подтверждают буквально. Возьмём почасовой ряд проката
велосипедов за два года. Корреляция числа поездок с тем же числом час назад
равна 0,84; через двенадцать часов она уходит в минус, −0,16 (утро
против ночи); ровно через сутки снова взлетает до 0,79, а через неделю
держится на 0,76. История не просто полезна — она устроена ритмично, и
модель обязана уметь её читать.
Первое, что приходит в голову, — подать модели окно последних k измерений:
yt=w0+j=1∑kwjxt−j.
Это обычная линейная регрессия по лагам, и она работает. Но у
неё два врождённых недостатка. Во-первых, длина памяти зашита в архитектуру:
чтобы заглянуть на неделю назад, нужно k=168 входов и 169 параметров.
Во-вторых, для каждой позиции окна заводится собственный вес, хотя правило
«свежее значение важнее» одно и то же на всех позициях. Параметры дублируют
друг друга.
Одна ячейка и общие веса
Простейшая рекуррентная сеть (Elman RNN) обходится одним и тем же правилом
обновления на каждом шаге:
ht=tanh(Wxxt+Whht−1+b),yt=Wy⊤ht+c,h0=0.
Вектор ht — сжатое резюме всего префикса x1,…,xt. Матрицы
Wx,Wh и векторы b,Wy одинаковы для всех t: это weight sharing, тот же
приём, что делает свёртку экономной в уроке 28, только сдвиг
здесь не по пространству, а по времени.
Следствие важное: число параметров не зависит от длины последовательности.
Наша учебная сеть с шириной dh=16 имеет
Wx16⋅1+Wh16⋅16+b16+Wy16+c1=305
параметров — и столько же осталось бы при длине истории в год. Линейная модель
по 48 лагам обходится 49 параметрами, зато по 720 лагам ей уже нужен
721 параметр, и дальше цена растёт линейно.
На практике шаг считают сразу для целого батча из B последовательностей:
если Ht−1 — матрица B×dh, а Xt — матрица B×dx, то
Ht=tanh(XtWx⊤+Ht−1Wh⊤+1b⊤).
Время идёт последовательно (шаг t нельзя посчитать раньше шага t−1), а вот
объекты внутри батча считаются параллельно. Именно это ограничение и делает
рекуррентные сети медленнее свёрточных при обучении на длинных строках.
Слева — привычная картинка с петлёй, справа — тот же расчёт, развёрнутый в
пять копий. Золотой цвет означает, что матрица Wh во всех копиях одна и та
же: это не пять слоёв, а один слой, применённый пять раз. Толщина
горизонтальной стрелки условно показывает, какая доля первого импульса ещё
жива в состоянии.
Скалярная память: рентген рекуррентности
Чтобы увидеть механику, разденем сеть до одного числа и уберём нелинейность:
Вот и вся память: это взвешенная сумма всего прошлого с геометрическими
весами. Подадим единичный импульс x1=1 и нули дальше — получим
ht=wut−1. Найдём время полузабывания t1/2 из условия
∣u∣t−1=21:
t1/2=1+ln∣u∣ln21.
При u=0,5 это 2,0 шага, при u=0,8 — 4,11 шага, при u=0,95
— 14,51 шага. Знаменатель ln∣u∣≈−(1−∣u∣) вблизи единицы, поэтому
характерная глубина памяти растёт как
τ≈1−∣u∣1,
то есть неограниченно при ∣u∣→1. Полезно посчитать и реакцию на ступеньку
xt≡1: сумма геометрической прогрессии даёт
ht=w1−u1−utt→∞1−uw,
так что при u=0,95 установившийся уровень в двадцать раз больше входа.
Одна и та же величина 1/(1−u) служит и глубиной памяти, и коэффициентом
усиления постоянной составляющей — забыть об этом легко, а масштаб состояния
уедет. Обратная сторона: при ∣u∣>1 старые
входы не гаснут, а растут, и состояние уходит в бесконечность; при u=1
память вечна, но любая постоянная составляющая накапливается без границы —
сумматор переполняется.
Рис. 73.2. Один множитель задаёт всю глубину памяти
Слева — след единичного импульса. При u=0,5 от него через два шага
остаётся половина, а через десять — две тысячных; при u=1,05 след,
наоборот, разрастается. Справа — время полузабывания как функция ∣u∣: оно
взлетает вертикально у единицы. Память в такой ячейке не «включается», а
плавно настраивается одним числом.
Насыщение: tanh держит состояние, но гасит производную
В настоящей ячейке стоит tanh, и он делает две вещи сразу. Хорошая: держит
ht в коридоре (−1;1), так что взрыва состояния не будет даже при
∥Wh∥>1. Плохая: производная
dzdtanhz=1−tanh2z
в области насыщения почти нулевая. При z=2 она равна уже 0,071, то есть
сигнал, проходящий назад через такую координату, ослабляется в четырнадцать
раз за один шаг. Мы это видели в уроке 17, где затухание
активаций рассматривалось по глубине; в рекуррентной сети глубина — это время,
и множителей столько, сколько шагов.
Обучение через развёртку
Функция потерь складывается по шагам (или берётся только на последнем, если
ответ нужен один):
L=t=1∑Tℓ(yt,yt).
Backpropagation through time — это обычное обратное
распространение по развёрнутому графу. Никакой новой математики:
цепное правило по графу, у которого веса повторяются, поэтому градиенты по
одной и той же матрице со всех шагов складываются:
∂Wh∂L=t=1∑T∂ht∂L∂Wh∂htht−1фиксировано.
Ключевой множитель — якобиан переноса состояния через один шаг:
∂hk−1∂hk=diag(1−hk2)Wh,
а через много шагов — произведение:
∂ht∂hT=k=t+1∏Tdiag(1−hk2)Wh.
Скалярный пример выше был не игрушкой: это ровно тот же продукт, в котором
u заменили матрицей. Сам обратный ход удобно записать рекурсией по
состоянию: если δt=∂L/∂ht, то
Каждый шаг назад — одно и то же линейное преобразование, применённое к
δ. Ровно как прямой ход накапливал память, обратный накапливает
ответственность, и оба страдают от одного и того же перемножения.
Произведение якобианов: где кончается обучение
Норма произведения ведёт себя как степень: если каждый множитель в среднем
сжимает в ρ раз, то
∂ht∂hT∼ρT−t,log10∂ht∂hT≈(T−t)log10ρ.
Логарифм падает линейно по лагу — это прямая на графике, а не медленное
угасание. Строгая верхняя оценка получается из субмультипликативности нормы:
поскольку ∥diag(1−hk2)∥≤1 всегда,
Значит, при ∥Wh∥<1 забывание гарантировано: никакая удача с данными не
спасёт. Симметричного утверждения для ∥Wh∥>1 нет — там взрыв возможен, но
не обязателен, и его гасит насыщение.
Численный опыт с матрицей 32×32 и настоящими множителями
diag(1−hk2) даёт на лаге 50: при спектральном радиусе
Wh, равном 0,8, логарифм нормы равен −4,4; при 1,0 — −0,3;
при 1,15 — +0,4. К лагу 77 первая кривая проваливается ниже
10−7, а к лагу 120 — до 10−11,2: обучающий сигнал из далёкого
будущего тонет в шуме мини-батча раньше, чем доходит до цели.
Рис. 73.3. Дальность обучения решает произведение якобианов
По горизонтали лаг T−t, по вертикали десятичный логарифм нормы
∂hT/∂ht. Затенённая полоса — область, где градиент
практически неотличим от шума оптимизации. Заметьте: кривая для 1,15
сначала растёт, но затем загибается вниз — насыщение tanh само себя
ограничивает, и к лагу 120 она возвращается к 10−0,1. Взрыв в
рекуррентной сети — явление скорее эпизодическое, чем постоянное.
Обрезка градиента лечит взрыв, но не забывание
Против взрыва есть простое и честное средство — обрезка нормы:
g←g⋅min(1,∥g∥c).
Иначе говоря, шаг оптимизатора меняется только тогда, когда норма превысила
порог:
∥g∥≤c⇒g←g,∥g∥>c⇒g←c∥g∥g.
Направление сохраняется, длина ограничивается порогом c. Это не
регуляризация и не изменение задачи: это защита оптимизатора от единичного
шага, который выбросит веса в бессмысленную область. В нашем обучении с
c=5 такой предохранитель срабатывал редко, но именно он гарантирует, что
случайный выброс нормы (в модельном примере на полях — с 46 до 5, то есть
в 9,2 раза) не уничтожит десятки эпох работы.
Важно понимать асимметрию: обрезка спасает от слишком большого шага и ничем не
помогает против слишком малого. Исчезнувший градиент нельзя «разжать» — там
уже нет информации, только машинный нуль.
Лаборатория импульса
Импульс, состояние и дальность градиента
График шире экрана — листайте по горизонтали →
Загружается живая иллюстрация…
Начните с импульса и линейного режима. Двигайте u и следите за красной
чертой «половина импульса»: при u=0,5 она стоит на втором шаге, при
u=0,8 — на четвёртом, при u=0,95 уезжает за четырнадцатый. Нижняя панель
показывает то же самое число в другой роли — как множитель градиента. Обе
кривые падают одинаково, потому что это одна и та же степень u.
Теперь включите tanh и поднимите амплитуду до пяти. Состояние прижимается к
единице и держится дольше — казалось бы, память улучшилась. Но нижняя панель
проваливается: производная 1−h2 у насыщенной координаты почти нулевая.
Ровно эта пара наблюдений и объясняет, почему обычная RNN уверенно ловит
недавнее и почти неспособна обучиться дальним связям, ради которых в
уроке 74 появится LSTM с отдельным путём памяти.
Наконец, переключите вход на «суточный ритм» и подберите u так, чтобы
состояние повторяло период входа. Заметьте, что при u около единицы ячейка
работает как интегратор и сдвигает фазу: память — это ещё и задержка.
Реальные данные: прокат велосипедов по часам
Проверим всё на настоящем ряде. Берём почасовые поездки, обучаемся на 2011
годе, проверяем на 2012-м — разделение по времени, а не случайное, иначе
модель подсмотрит будущее (урок 32). Вход — 48 прошлых часов,
цель — следующий час. После выбрасывания окон с пропущенными часами осталось
6595 обучающих и 8066 тестовых окон. Нормировка считается только по
обучающей части:
и те же два числа применяются к тесту. Посчитать среднее по всем данным —
классическая утечка: тест повлияет на обучение через масштаб.
Сравниваем четыре модели по средней абсолютной ошибке в поездках:
MAE=n1i=1∑n∣yi−yi∣.
Константа «обучающее среднее» даёт 168,6; persistence
yt=yt−1 — 81,3; «тот же час вчера» yt=yt−24 —
77,8; наша RNN шириной 16 — 56,6. Выигрыш над persistence составляет
30,3%, и достигнут он тремястами пятью параметрами.
Рис. 73.4. Реальный велопрокат: RNN против простых базовых моделей
Слева — трое подряд идущих суток из теста. Persistence (синий пунктир) всюду
опаздывает ровно на час: на подъёме занижает, на спуске завышает. RNN сглаживает
эту задержку, хотя утренние пики систематически недотягивает — у неё нет
входов о погоде и типе дня. Справа — итог за весь 2012 год.
Усечённое BPTT: сколько шагов пропускать назад
Хранить весь граф для длинной последовательности дорого. Truncated BPTT
обрабатывает отрезки длины L: состояние переносится вперёд полностью, а
градиент обрывается на границе. Модель может использовать далёкую
информацию, но не может научиться использовать её напрямую.
Мы обучили одну и ту же сеть при L∈{1,2,4,8,16,24,48}. Ошибка на тесте:
Кривая не монотонна, и это честный результат. До L=8 градиент слишком
близорук и сеть недоучивается. Дальше выигрыш исчерпывается: лучший результат
даёт L=16, а не максимальное L=48. Длинная развёртка добавляет шум и
трудность оптимизации, не добавляя полезного сигнала — на этих данных полезная
история короче суток.
Слишком короткое усечение лишает сеть причинной связи с суточным ритмом:
при L≤4 ошибка держится около 61. Минимум приходится на L=16, дальше
кривая слегка растёт. «Чем длиннее, тем лучше» — неверное правило; длину
выбирают по временному масштабу данных и проверяют измерением.
Что сеть на самом деле читает
Обученная модель — чёрный ящик, но её можно допросить вмешательством. Для
каждого лага ℓ заменим вход xt−ℓ обучающим средним, оставив
остальные на месте, и измерим прирост ошибки:
I(ℓ)=MAEoccl(ℓ)−MAEbase.
Результат отрезвляет. Лаг 1 даёт +147,0 поездки — в два с половиной
раза больше базовой ошибки 56,6. Лаг 12 — уже +3,21, лаг 24 —
+0,46, лаг 48 — 0,00. Первые двенадцать часов несут 93,9% всего эффекта вмешательства,
а всё, что дальше суток, — 0,4%.
Удобно свести профиль к одному числу — центру тяжести использованной истории:
ℓˉ=∑ℓI(ℓ)+∑ℓℓI(ℓ)+,
где (⋅)+ означает срезку отрицательных значений. Здесь сумма
∑ℓI(ℓ)+ равна 221,7, из них 147,0 приходится на первый
лаг, и центр тяжести оказывается на ℓˉ=3,1 часа. Модель, которой
выдали двое суток истории, в среднем опирается на три последних часа.
То есть наша RNN, формально имеющая доступ к сорока восьми часам, реально
живёт в окне около половины суток. Это не провал эксперимента, а измерение
объекта: короткая память и есть характерное свойство простой рекуррентной
ячейки, и оно согласуется с кривой усечения, где минимум был на L=16.
Рис. 73.6. Профиль вмешательства: какая история реально используется
Прирост ошибки при замене одного входа на среднее. Столбик лага 1 выходит
далеко за пределы остальных; после двенадцатого часа профиль практически
прижимается к нулю. Сравните с автокорреляцией на полях: в данных суточный пик
есть, а модель им не пользуется — она нашла более дешёвый способ, экстраполяцию
последних часов.
Автомат Цетлина: та же плата за долгую память
Идея «поведение определяется небольшим внутренним состоянием» появилась в
советской науке раньше нейросетевого бума. В начале 1960-х Михаил Львович
Цетлин (1924–1966) изучал конечные автоматы, действующие в случайной среде:
автомат L2N,2 имеет два действия и счётчик уверенности глубины N.
Успех сдвигает счётчик глубже в текущую сторону, неудача — к границе, и на
границе автомат меняет действие. Никакого градиента, никакого обучения весов —
только состояние.
Мы воспроизвели опыт Цетлина численно: среда наказывает первое действие с
вероятностью 0,4, второе — с вероятностью 0,6, автомат работает
40000 шагов. Доля выбора лучшего действия:
N=1:0,599,N=4:0,826,N=16:0,999.
Чем глубже память, тем целесообразнее поведение, и в пределе N→∞
автомат становится оптимальным. Условие целесообразности Цетлин формулировал
как сравнение со случайным выбором: автомат целесообразен, если
T→∞limT1t=1∑TE[штрафt]<2c1+c2,
то есть если он в среднем получает меньше штрафов, чем монетка. Наши числа
удовлетворяют этому условию уже при N=1: доля лучшего действия 0,599
больше 0,5. Но у медали есть обратная сторона. Мы поменяли
среду местами и посчитали, сколько шагов автомату нужно, чтобы сменить
действие: при N=1 хватило одного шага, при N=16 понадобилось 108.
Рис. 73.7. Автомат Цетлина: глубина памяти против скорости переучивания
Слева — целесообразность поведения растёт с глубиной памяти. Справа — плата за
неё: после смены среды глубокий автомат 108 шагов упрямо повторяет прежнее
действие. Тот же компромисс, что у рекуррентного множителя: u ближе к
единице — дольше память и медленнее адаптация.
Это в точности наш компромисс. Глубина памяти N у Цетлина играет роль
множителя u: увеличение обоих делает систему устойчивее к шуму и инертнее к
переменам. Разница лишь в том, что N задаётся конструктором, а u модель
подбирает сама градиентным спуском — и потому наталкивается на произведение
якобианов, о котором Цетлину думать не приходилось.
Какая задача действительно требует памяти
Чтобы измерять дальнюю память честно, нужны задачи, где короткое окно
бесполезно по построению. Классических две.
Adding problem: последовательность из случайных чисел, два из них помечены
маркером, надо выдать их сумму. Правильный ответ невозможно угадать по
локальному окну, а цель известна точно.
Delayed copy: показать символ, потом D шагов пустоты, потом потребовать его
воспроизвести. Увеличивая D, получаем кривую дальности памяти, и она —
свойство архитектуры, а не набора данных.
Такие синтетические задачи не заменяют реальные ряды, зато изолируют механизм.
На реальных данных всё смешано: сезонность, погода, тренд, — и по итоговой
метрике невозможно понять, память подвела или признаков не хватило.
RNN, свёртка и внимание
Одномерная свёртка обрабатывает локальные окна параллельно, её рецептивное
поле растёт с глубиной и dilation (урок 28). RNN работает строго
последовательно, зато онлайн: пришло измерение — обновили одно состояние,
хранить историю не нужно. Механизм внимания даёт прямой доступ ко
всем прошлым позициям, но требует их хранить и обычно стоит квадратично по
длине.
Выбор диктуется задачей, а не модой. Для потокового датчика с жёстким лимитом
памяти рекуррентность остаётся разумной: постоянные 305 параметров и
постоянные 16 чисел состояния независимо от того, работает прибор час или
год. Для длинного текста, где нужно связать слова через тысячу позиций,
фиксированное состояние становится узким горлом, а произведение якобианов —
непреодолимой стеной.
Память измеряется задачей, а не архитектурой
Рекуррентная сеть — это одно правило обновления, применённое многократно.
Развёртка одновременно объясняет её экономию (параметров ровно 305 при любой
длине) и её главную болезнь: обучающий сигнал проходит через произведение
якобианов и гибнет экспоненциально по лагу.
Дальше идут два вывода, которые стоит унести с урока. Первый: наличие
информации в состоянии и обучаемость связи — разные вещи; насыщенный tanh
разводит их окончательно. Второй: заявленную память надо измерять, а не
предполагать. Наша сеть имела доступ к 48 часам, обучалась на 16 шагах
лучше, чем на 48, и в профиле вмешательства показала, что 93,9% её
работы приходится на первые двенадцать лагов. Это и есть честный ответ на
вопрос «какая у модели память».
В уроке 74 появится ячейка с отдельным аддитивным путём для
состояния — там произведение якобианов заменится суммой, и дальность обучения
вырастет на порядок. А в уроке 76 от идеи фиксированного канала
откажутся вовсе.