LSTM прокладывает через время почти линейный путь состояния. Ворота не являются маленькими разумными контролёрами: это дифференцируемые числа от нуля до единицы, которые учатся пропускать, стирать и показывать сигнал. Значение одного такого числа переводится в число шагов памяти простой формулой, а аддитивный путь решает не задачу «помнить», а задачу «донести градиент».

Пароль через длинную паузу

Последовательность начинается символом К, затем идут двести нерелевантных знаков, а в конце нужно воспроизвести первый символ. Простая RNN многократно переписывает hth_t и проводит градиент через произведение матриц: на каждом шаге состояние целиком пропускается через нелинейность, и от первого символа к концу почти ничего не доходит — ни сигнала вперёд, ни производной назад.

LSTM меняет одну вещь. Рядом со скрытым состоянием hth_t появляется отдельное состояние памяти ctc_t, которое обновляется аддитивно: старое значение умножается на число и к нему прибавляется новое. Никаких матриц на этом пути, никакого tanh\tanh поверх всего состояния. Для входа xtx_t и предыдущего ht1h_{t-1} вычисляются ворота:

ft=σ(Wf[xt,ht1]+bf),it=σ(Wi[xt,ht1]+bi),ot=σ(Wo[xt,ht1]+bo),c~t=tanh(Wc[xt,ht1]+bc).\begin{aligned} f_t&=\sigma(W_f[x_t,h_{t-1}]+b_f),\\ i_t&=\sigma(W_i[x_t,h_{t-1}]+b_i),\\ o_t&=\sigma(W_o[x_t,h_{t-1}]+b_o),\\ \widetilde c_t&=\tanh(W_c[x_t,h_{t-1}]+b_c). \end{aligned}

Затем

ct=ftct1+itc~t,ht=ottanh(ct).c_t=f_t\odot c_{t-1}+i_t\odot\widetilde c_t, \qquad h_t=o_t\odot\tanh(c_t).

Forget gate ftf_t сохраняет часть старого, input gate iti_t дозирует запись, output gate oto_t решает, что показать наружу. Все операции покомпонентны: координата памяти живёт своей жизнью и имеет собственный временной масштаб.

Обратите внимание на порядок аргументов: они начали не с памяти, а с градиента. Проблема формулируется как «обратный поток ошибки затухает», и конструкция ячейки является ответом именно на неё.

Рисунок шире экрана — проведите по немуОткрыть целиком ↗
Слева схема ячейки LSTM: горизонтальная синяя магистраль состояния c с умножением на forget gate и сложением с i умножить на кандидата, снизу четыре линейных слоя ворот; справа таблица с числами одной координаты
Рис. 74.1. Аддитивный путь памяти и одна координата в числах

Слева: на пути ct1ctc_{t-1}\to c_t стоят только умножение и сложение — ни одной матрицы. Ворота приходят снизу, из [xt,ht1][x_t,h_{t-1}]. Справа тот же шаг для одной координаты: ct1=2c_{t-1}=2, ft=0,8f_t=0{,}8, it=0,25i_t=0{,}25, c~t=0,4\widetilde c_t=-0{,}4, ot=0,6o_t=0{,}6 дают ct=1,5000c_t=1{,}5000 и ht=0,5431h_t=0{,}5431.

Одна координата, семь чисел

Разберём шаг руками, потому что вся дальнейшая интуиция держится на этой арифметике. Пусть ct1=2c_{t-1}=2, ft=0,8f_t=0{,}8, it=0,25i_t=0{,}25, c~t=0,4\widetilde c_t=-0{,}4, ot=0,6o_t=0{,}6. Память сохраняется в доле ftf_t:

ftct1=0,82=1,6000,f_tc_{t-1}=0{,}8\cdot2=1{,}6000,

запись добавляет

itc~t=0,25(0,4)=0,1000,i_t\widetilde c_t=0{,}25\cdot(-0{,}4)=-0{,}1000,

и вместе

ct=1,60000,1000=1,5000.c_t=1{,}6000-0{,}1000=1{,}5000 .

Наружу выходит не ctc_t, а его сжатая и приглушённая версия:

ht=ottanh(ct)=0,60,9051=0,5431.h_t=o_t\tanh(c_t)=0{,}6\cdot0{,}9051=0{,}5431 .

Чувствительность выхода к памяти равна произведению двух множителей:

htct=ot(1tanh2ct)=0,60,1807=0,1084.\frac{\partial h_t}{\partial c_t}=o_t\bigl(1-\tanh^2c_t\bigr) =0{,}6\cdot0{,}1807=0{,}1084 .

Если полностью закрыть запись, it=0i_t=0, то ct=1,6c_t=1{,}6 и ht=0,5530h_t=0{,}5530: внешнее различие двух ситуаций — четыре сотых, тогда как внутри память отличается на десятую. Это первый важный вывод: hth_t является отчётом о памяти, а не самой памятью, и tanh\tanh вместе с oto_t умеют сжимать большие внутренние различия до неразличимых внешних.

Почему сложение спасает градиент

Возьмём производную памяти по её же предыдущему значению вдоль прямого пути:

ctct1ft.\frac{\partial c_t}{\partial c_{t-1}}\approx f_t .

Тогда на отрезке от tt до TT

cTctk=t+1Tfk.\frac{\partial c_T}{\partial c_t}\approx\prod_{k=t+1}^{T}f_k .

Сравните с простой RNN, где на каждом шаге градиент домножается на рекуррентную матрицу и производную нелинейности:

hTht=k=t+1Tdiag(1hk2)W.\frac{\partial h_T}{\partial h_t}=\prod_{k=t+1}^{T} \operatorname{diag}\bigl(1-h_k^2\bigr)W^\top .

В логарифмах разница видна лучше всего:

lncTctk=t+1Tlnfk,lnhTht(Tt)lnW+k=t+1Tln(1hk2).\ln\Bigl\lVert\frac{\partial c_T}{\partial c_t}\Bigr\rVert \approx\sum_{k=t+1}^{T}\ln f_k, \qquad \ln\Bigl\lVert\frac{\partial h_T}{\partial h_t}\Bigr\rVert \lesssim (T-t)\ln\lVert W\rVert+\sum_{k=t+1}^{T}\ln\bigl(1-h_k^2\bigr).

Первая сумма управляется одним обучаемым числом на шаг, вторая содержит слагаемое, которое сеть не контролирует напрямую.

Множитель 1hk21-h_k^2 не превосходит единицы и при насыщении близок к нулю, поэтому произведение тает даже при аккуратно подобранной WW. У аддитивного пути такого множителя нет вовсе — есть только ворота, и сеть может держать их близко к единице.

«Почти» в первой формуле существенно: ворота зависят от ht1h_{t-1}, поэтому полный градиент имеет дополнительные пути. LSTM смягчает исчезновение, а не доказывает бесконечную память.

Измерим это на живой сети. Возьмём задачу «запомни первый бит» с паузой в D=100D=100 посторонних символов и посмотрим, какая доля градиента доходит от запроса до первого шага при инициализации, до всякого обучения. У простой RNN норма L/ht\lVert\partial\mathcal L/\partial h_t\rVert падает за сто шагов в 704 раза. У LSTM градиент по памяти L/ct\lVert\partial\mathcal L/\partial c_t\rVert не падает вовсе: он даже вырастает в 3,72 раза, потому что вклады с разных шагов складываются вдоль магистрали. Отношение двух «дальностей» — около 2620 раз.

Рисунок шире экрана — проведите по немуОткрыть целиком ↗
Логарифмический график нормы градиента по состоянию против лага: красная кривая RNN падает на три порядка к лагу 100, синяя кривая градиента по памяти LSTM почти не падает, жёлтая пунктирная кривая обученной RNN идёт горизонтально на низком уровне
Рис. 74.2. Куда доходит сигнал обучения при паузе в сто шагов

Обе кривые измерены на реальной сети (numpy, ручное обратное распространение). До обучения градиент простой RNN ослабевает за сто шагов в 704 раза, а градиент по памяти LSTM растёт в 3,72 раза. Жёлтая кривая — та же RNN после обучения на задаче: она нашла почти тождественный рекуррентный путь и сохраняет 0,919 нормы. Абсолютный уровень у неё низкий, потому что задача решена и потери почти нулевые; сравнивать нужно наклон, а не высоту.

Время полураспада: перевод ворот в шаги

Число ff само по себе ничего не говорит. Переведём его в шаги. Если запись выключена и forget gate постоянен, то

ct+k=fkct,c_{t+k}=f^k c_t ,

и время уменьшения амплитуды вдвое равно

t1/2=ln0,5lnf.t_{1/2}=\frac{\ln 0{,}5}{\ln f}.

Обратный перевод не менее полезен: если нужен горизонт HH шагов, то

f=0,51/H=exp ⁣(ln0,5H).f=0{,}5^{1/H}=\exp\!\left(\frac{\ln0{,}5}{H}\right).

Подставим: при f=0,9f=0{,}9 получаем 6,6 шага, при f=0,95f=0{,}95 — 13,5, при f=0,99f=0{,}99 — 69,0, а при f=0,999f=0{,}999 — 692,8. Разница между 0,990{,}99 и 0,9990{,}999 на глаз ничтожна, а память отличается в десять раз. Это и есть причина, по которой обученные ворота выглядят «неинформативно»: почти все интересные значения теснятся у самой единицы.

Четыре режима из одной формулы

Пара чисел (f,i)(f,i) порождает качественно разные поведения одной и той же координаты:

  • f1, i0f\approx1,\ i\approx0 — хранить: значение стоит на месте;
  • f0, i1f\approx0,\ i\approx1 — заменить: старое стёрто, записано новое;
  • f1, i>0f\approx1,\ i>0 — накапливать: значение растёт как сумма;
  • f<1, i0f<1,\ i\approx0 — забывать с заданной скоростью;
  • o0o\approx0 — скрыть память от выхода, не удаляя её.

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

Рисунок шире экрана — проведите по немуОткрыть целиком ↗
Четыре кривые состояния c за восемьдесят шагов: горизонтальная линия хранения, прямая накопления до 4,2, экспоненциальное затухание к нулю и мгновенный сброс к новому значению
Рис. 74.3. Четыре режима одной формулы обновления памяти

Одна и та же формула ct=fct1+ic~tc_t=fc_{t-1}+i\widetilde c_t при разных воротах. Накопление с i=0,2i=0{,}2 и c~=0,2\widetilde c=0{,}2 за 80 шагов доводит cc до 4,2, затухание с f=0,9f=0{,}9 сжимает единицу до 0,0002180{,}000218, а замена с f=0f=0 переписывает всё за один шаг. Заметьте: снаружи накопленные 4,2 дают tanh(4,2)=0,99955\tanh(4{,}2)=0{,}99955 — почти единицу, как и любое большое значение.

Про последнее стоит сказать отдельно. Накопитель не переполняется в смысле арифметики: cc растёт линейно и может дойти до сотен. Но hth_t ограничен единицей, поэтому внешне разница между c=4c=4 и c=40c=40 почти незаметна. Ограниченность выхода маскирует неограниченность внутреннего состояния — и именно на этом ломаются длинные потоки без сброса.

Забавно, что forget gate — не часть исходной конструкции 1997 года: его добавили через два года, когда LSTM стали кормить непрерывными потоками. Первая версия умела помнить, но не умела вовремя забывать.

Эксперимент: запомни первый бит

Проверим тезис честным измерением. Задача: на первом шаге приходит бит (0 или 1), затем DD посторонних символов из трёх «болтливых» значений, затем запрос — и модель обязана назвать первый бит. Мы обучили в numpy, с ручным обратным распространением, три ячейки с почти одинаковым бюджетом параметров: простую RNN ширины 64 (4674 параметра), GRU ширины 36 (4718) и LSTM ширины 31 (4776). Бюджет считается по формуле

P=g(dn+n2+n)+nk+k,g=1, 3, 4P=g\,(dn+n^2+n)+nk+k,\qquad g=1,\ 3,\ 4

для RNN, GRU и LSTM соответственно (dd — размер входа, kk — число классов). Разброс размеров — 2,18 %, так что сравнение идёт не про число весов. Всё остальное общее: Adam с шагом 21032\cdot10^{-3}, батч 96, 1000 шагов, три случайные инициализации, тест на 2000 свежих последовательностей.

Рисунок шире экрана — проведите по немуОткрыть целиком ↗
График точности против длины паузы: при D=25 все три модели дают единицу, при D=50 и D=100 RNN падает до 0,83 при точных единицах у GRU и LSTM, при D=200 все падают почти к уровню угадывания, LSTM держит 0,67
Рис. 74.4. Одинаковый бюджет параметров, разная память

Средняя по трём запускам доля верных ответов; полупрозрачные точки — отдельные запуски. При D=25D=25 справляются все. При D=50D=50 и D=100D=100 простая RNN даёт 0,83 (в одном запуске из трёх она вообще не сходится и остаётся на уровне угадывания), а GRU и LSTM решают задачу во всех запусках. При D=200D=200 падают все: RNN 0,497, GRU 0,494, LSTM 0,668 — то есть LSTM решила задачу лишь в одном запуске из трёх. Ворота отодвигают границу, но не отменяют её.

Три вывода, которые важнее самих чисел. Первый: разница между RNN и воротами существует и измерима, но она не бесконечна — граница просто сдвинулась с полусотни шагов к сотне-двум. Второй: результат сильно зависит от инициализации, поэтому одна цифра без разброса по seed’ам ничего не значит. Третий: GRU при паузе 100 не хуже LSTM, хотя ворот у неё меньше — заранее утверждать «LSTM помнит лучше» нельзя.

Что показывают ворота обученной сети

Обучим LSTM ширины 31 на паузе D=30D=30 до точности 1,00 и посмотрим на её ворота — не нарисованные от руки, а настоящие. Среднее по координатам значение forget gate в паузе равно 0,956, что соответствует полураспаду 15,3 шага. Input gate в паузе равен 0,529, то есть не закрыт: сеть продолжает писать в память каждый шаг. Output gate тоже держится около 0,617 и слегка приоткрывается к запросу, до 0,675.

Рисунок шире экрана — проведите по немуОткрыть целиком ↗
Верхняя панель: средние значения forget, input и output gate по шагам, forget держится около 0,956; нижняя панель: две кривые состояния памяти для бита 1 и бита 0 монотонно расходятся к моменту запроса
Рис. 74.5. Ворота обученной LSTM и расхождение памяти

Верх: средние ворота обученной LSTM на задаче D=30D=30. Низ: координата 6 памяти, усреднённая отдельно по примерам с битом 1 и битом 0. Разрыв между кривыми и есть хранимый ответ: он равен 0,179 сразу после ключа и 5,997 к запросу, то есть вырос в 33,4 раза. Сеть не «положила бит в ящик и закрыла крышку», а построила усилитель, который каждый шаг подтверждает решение.

Это неудобная для красивых лекций картина, и именно поэтому её стоит показать. Учебная схема обещает it0i_t\approx0 в паузе, а реальная сеть выбрала другую стратегию: почти постоянное ff чуть меньше единицы и постоянную дозапись — и получила из этого монотонно расходящиеся траектории. Обе стратегии решают задачу; оптимизация выбрала ту, которая ближе к её инициализации.

Лаборатория ворот

Forget gate, пауза, помехи и сохранённый ответ

Загружается живая иллюстрация…

Ключ приходит на шаге 5, ответ спрашивают на шаге 70. Виджет прогоняет один и тот же сценарий дважды — с ключом +1+1 и 1-1 — и показывает обе траектории памяти: сохранился ответ или нет, определяется расстоянием между ними, а не их уровнем. Начните с f=0,95f=0{,}95 и убедитесь, что полураспад 13,5 шага не доносит сигнал через 65 шагов паузы; доведите ff до 0,990{,}99 и посмотрите, как одновременно поднимаются обе кривые внизу — память и дальность градиента меняются одним и тем же числом. Затем закройте oo и увидите, что ответ остаётся в памяти, но исчезает с выхода.

Главный опыт — четвёртый ползунок. Включите шум в паузе при большом ii: болтовня пишется в память теми же воротами, что и ключ, и разделение кривых тает. Уменьшите ii — перестанет записываться и ключ. Постоянными воротами эту задачу решить нельзя, и в этом весь смысл: в настоящей сети iti_t является функцией входа и закрывается именно на болтовне.

Не ищите буквальное «это нейрон памяти буквы К». Представление распределено: одна координата может участвовать в нескольких функциях, а один факт храниться в нескольких координатах.

Bias forget gate: prior на длинную память

В нашем эксперименте есть деталь, без которой ничего бы не вышло. Смещение forget gate инициализировано числом 3, то есть в начале обучения fσ(3)=0,953f\approx\sigma(3)=0{,}953. Мы это проверили прямым экспериментом: при смещении 1 та же LSTM с тем же шагом обучения не решила задачу с паузой 100 ни разу (0 успехов из 3 инициализаций, точность 0,494, 0,487 и 0,482 — чистое угадывание), а при смещении 3 решила во всех трёх с точностью 1,00.

Объяснение простое. Инициализация нулевым смещением даёт f0,5f\approx0{,}5 и полураспад в один шаг: сеть стартует с состоянием, которое ничего не помнит, и градиент, который должен научить её помнить, до нужного места не доходит. Положительное смещение — это prior: «по умолчанию храни». Слишком большое смещение вредно симметрично: сеть медленно учится забывать смену режима.

f=σ(b)  t1/2=ln0,5lnσ(b).f=\sigma(b)\ \Longrightarrow\ t_{1/2}=\frac{\ln0{,}5}{\ln\sigma(b)} .

GRU: меньше ворот, тот же принцип

Gated Recurrent Unit объединяет память и скрытое состояние:

zt=σ(Wz[xt,ht1]),rt=σ(Wr[xt,ht1]),h~t=tanh(Wh[xt,rtht1]),ht=(1zt)ht1+zth~t.\begin{aligned} z_t&=\sigma(W_z[x_t,h_{t-1}]),\\ r_t&=\sigma(W_r[x_t,h_{t-1}]),\\ \widetilde h_t&=\tanh(W_h[x_t,r_t\odot h_{t-1}]),\\ h_t&=(1-z_t)\odot h_{t-1}+z_t\odot\widetilde h_t. \end{aligned}

Update gate ztz_t интерполирует между старым и новым, играя роль сразу ff и ii: связка f=1zf=1-z, i=zi=z жёстко связывает «сколько забыл» и «сколько записал». Reset gate rtr_t позволяет вычислить кандидата, глядя на вход и лишь частично на прошлое.

htht1=zt(h~tht1)h_t-h_{t-1}=z_t\odot(\widetilde h_t-h_{t-1})

— в такой записи видно, что ztz_t есть скорость движения к новому значению. При постоянном zz развёртка даёт экспоненциальное сглаживание:

ht=zk=0t1(1z)kh~tk+(1z)th0,h_t=z\sum_{k=0}^{t-1}(1-z)^k\,\widetilde h_{t-k}+(1-z)^t h_0 ,

то есть вес наблюдения падает геометрически с эффективной памятью 1/z1/z шагов. При z=0,2z=0{,}2 половина пути проходится за 4 шага.

Параметров у GRU меньше: три матрицы вместо четырёх. При равной ширине это 13762 против 18306 в нашей задаче. Но одинаковое число координат не означает одинаковую ёмкость: при честном сравнении выравнивают хотя бы размер модели или время обучения, как мы и сделали выше.

Маска, padding и неодинаковая длина

В batch последовательности дополняют padding. Маска mt{0,1}m_t\in\{0,1\} должна сохранять состояние на фиктивных шагах:

ct=mtctnew+(1mt)ct1,ht=mthtnew+(1mt)ht1.c_t=m_t\,c_t^{\mathrm{new}}+(1-m_t)\,c_{t-1}, \qquad h_t=m_t\,h_t^{\mathrm{new}}+(1-m_t)\,h_{t-1}.

Loss также умножают на маску. Иначе короткие примеры получают лишние нулевые события, а последнее состояние относится к padding, не к данным. Нуль на входе для сети — не «ничего не произошло», а вполне конкретное наблюдение: она честно применит к нему ворота и сдвинет память.

Рисунок шире экрана — проведите по немуОткрыть целиком ↗
Две кривые состояния: с маской состояние на участке padding заморожено на уровне 1,100, без маски продолжает затухать до 0,156
Рис. 74.6. Дополнение нулями — это не «ничего не произошло»

Модельный пример при f=0,85f=0{,}85: настоящая последовательность длится 8 шагов, к ней приписаны 12 шагов padding. С маской память в конце равна 1,100, без маски — 0,156, то есть 85,8 % содержимого съедено нулями. Модель, обученная так, будет выдавать разный ответ на одном и том же объекте в зависимости от того, с кем он попал в батч.

В медицинских рядах пропуск измерения несёт информацию: анализ могли назначить из-за ухудшения. Маска наблюдаемости и время с последнего измерения становятся входными признаками. Заполнить все пропуски нулём — значит смешать «значение равно нулю» с «не измерено».

Реальные данные: велопрокат по часам

Проверим ячейку на настоящем ряде: почасовой прокат велосипедов, 17379 часов наблюдений. Задача — предсказать число поездок в следующий час по окну из 24 предыдущих часов; первые 70 % времени идут в обучение, последние 30 % (5207 часов) — в тест, без перемешивания. Среднее и разброс для нормировки взяты только по обучающему периоду: 159,9 и 152,6 поездки.

Порядок сравнения тот же, что в уроке про регрессию: сначала глупые baseline, потом умные модели.

MAE=1Nk=1Ny^kyk.\text{MAE}=\frac1N\sum_{k=1}^{N}\bigl|\widehat y_k-y_k\bigr| .

Сезонный прогноз записывается одной строкой и не имеет ни одного параметра:

y^t=yt24.\widehat y_t=y_{t-24}.

Прогноз «как час назад» даёт MAE 86,7 поездки; «как ровно сутки назад» — 81,4; ridge-регрессия по тем же 24 лагам и паре sin,cos\sin,\cos часа — 55,5; LSTM ширины 24 — 34,4. Выигрыш над сезонным baseline составляет 57,8 %.

Рисунок шире экрана — проведите по немуОткрыть целиком ↗
Вверху неделя тестового периода: чёрная кривая реального проката, синяя кривая LSTM почти совпадает с ней, жёлтая пунктирная кривая сезонного прогноза сдвинута и промахивается по пикам; внизу столбцы MAE 34,4 у LSTM, 55,5 у ridge, 81,4 у сезонного и 86,7 у наивного
Рис. 74.7. Реальный велопрокат: прогноз на час вперёд

Неделя тестового периода и итоговые MAE на всех 5207 тестовых часах. Сезонный прогноз повторяет форму суток, но не знает про погоду и про вчерашний уровень; LSTM видит последние 24 часа и держится ближе. Обратите внимание, где остаётся ошибка: на резких вечерних пиках.

Разбор по пикам обязателен. Порог «пикового часа» — 90-й процентиль обучающей нагрузки, 380 поездок; в тесте таких часов 25,6 % (сам по себе тревожный признак: во второй год проката стало заметно больше, распределение сдвинулось). На пиках MAE у LSTM равна 53,7 против 131,4 у сезонного прогноза — модель выигрывает, но её собственная ошибка на пиках в полтора с лишним раза выше средней. Средняя цифра скрывает, что все интересные часы предсказываются хуже обычных.

Автоматы Глушкова: состояние как понятие

За двадцать лет до трансформеров и за тридцать до LSTM понятие «состояние» получило точное определение в советской школе кибернетики. Виктор Михайлович Глушков, директор Института кибернетики в Киеве, в «Синтезе цифровых автоматов» (1962) развил теорию абстрактного автомата: пятёрка из множества входов, множества состояний, множества выходов и двух функций,

qt=δ(qt1,xt),yt=λ(qt1,xt).q_{t}=\delta(q_{t-1},x_t),\qquad y_t=\lambda(q_{t-1},x_t).

Сравните с нашей ячейкой: qq — это пара (ct,ht)(c_t,h_t), δ\delta — формулы ворот, λ\lambda — выходной слой. LSTM буквально является автоматом Глушкова, у которого множество состояний стало непрерывным, а функции δ\delta и λ\lambda — дифференцируемыми и обучаемыми.

Эквивалентность состояний определяется через поведение, а не через содержимое:

qq    x1k λ(q,x1k)=λ(q,x1k),q\sim q'\iff\forall\,x_{1\:k}\ \lambda^*(q,x_{1\:k})=\lambda^*(q',x_{1\:k}),

где λ\lambda^* — выход автомата на всей входной строке.

Из этой оптики следуют вполне практические вещи. Задача синтеза автомата — построить минимальную машину с нужным поведением; задача обучения LSTM — подобрать веса, чтобы поведение совпало с данными. Понятие эквивалентных состояний (двух состояний, неразличимых ни при каком продолжении входа) прямо объясняет, почему бессмысленно требовать от координат памяти «смысла»: у автомата есть целые классы состояний, ведущих себя одинаково, и обучение вправе выбрать любой представитель класса.

Что ворота не решают

LSTM всё ещё обрабатывает шаги последовательно, что ограничивает параллельность: сто шагов — это сто зависимых умножений, и никакая видеокарта их не совместит. Состояние остаётся фиксированного размера, поэтому объём памяти не растёт вместе с длиной входа: в сто чисел нельзя положить сто тысяч токенов без потерь. Дальняя информация может затухнуть или быть перезаписана — наш эксперимент при D=200D=200 показал это прямо.

Для задач с прямыми связями между далёкими токенами attention создаёт короткий путь: каждый шаг смотрит на каждый, и длина пути равна единице, а не TT. Для потоковой обработки на устройстве LSTM может быть дешевле: состояние постоянного размера и один шаг на наблюдение против квадратичной по длине памяти внимания. Архитектура выбирается по ограничениям, а не по хронологии моды.

Связь с остаточными соединениями содержательная: и аддитивный путь ctc_t, и residual x+F(x)x+F(x) дают сигналу возможность пройти без полного нелинейного переписывания. В обоих случаях речь не о выразительности, а о проходимости — о том, чтобы производная имела короткую дорогу, как в уроке об обратном распространении.

Проверки, которые стоит написать

Ошибки в работе с состоянием редко падают с исключением: они тихо портят метрику. Минимальный набор тестов рядом с кодом.

Контракт сброса. Явно определите событие, при котором h,ch,c обнуляются: новый пользователь, новый двигатель, разрыв длиннее часа. Сохраните этот контракт рядом с моделью, иначе offline и production вычислят разные состояния на одних и тех же данных.

Независимость от порядка. Отсортируйте объекты в батче двумя способами и сравните прогнозы. Если состояние перетекает между объектами, результат зависит от технического порядка строк — и такой баг даёт особенно высокий валидационный score, когда соседние записи относятся к одному устройству.

Длинное накопление. Прогоните последовательность в десять раз длиннее обучающей и посмотрите на maxct\max|c_t|. Ограниченный hth_t способен скрывать рост внутреннего ctc_t; в mixed precision позднее открытие output gate насыщает tanh\tanh и стирает различия, о чём предупреждали авторы forget gate.

Неравномерное время. При irregular sampling добавьте Δt\Delta t как признак. Два одинаковых значения, разделённые минутой и сутками, означают разную скорость процесса. Естественная параметризация — заставить ворота зависеть от интервала:

ft=σ()Δt,f_t=\sigma(\cdot)^{\Delta t},

что при постоянном шаге совпадает с обычной формулой, а при пропуске в kk шагов забывает ровно столько, сколько забыл бы за kk шагов.

Мини-исследование: ворота на смене режима

Сгенерируйте ряд, где скрытый уровень btb_t постоянен 50–150 шагов, затем маркер mt=1m_t=1 сообщает, что уровень заново выбран. Наблюдение

xt=bt+εt,εtN(0,0,22).x_t=b_t+\varepsilon_t,\qquad \varepsilon_t\sim\mathcal N(0,\,0{,}2^2).

LSTM должна усреднять шум внутри сегмента и быстро забывать старое после маркера. Постройте средние ft,itf_t,i_t в окне от 10-10 до +20+20 вокруг переключения. Ожидается падение forget gate и рост input gate, но проверяйте одновременно ошибку: красивый профиль без улучшения прогноза ничего не доказывает — мы только что видели, как обученная сеть решила ту же задачу совсем другой стратегией.

Проведите counterfactual: удалите маркер из входа, сохранив сами значения. Время адаптации должно увеличиться. Затем вставьте ложный маркер без смены уровня. Если сеть полностью стирает память, возникнет краткий всплеск ошибки. Так выясняется, как она объединяет явное событие и статистическое свидетельство. Сравните с задачей об обнаружении разладки, где переключение ищется по вероятностному критерию: LSTM обучает внутренний детектор вместе с прогнозом, но не выдаёт калиброванную вероятность смены.

Ворота задают временной масштаб

LSTM делает память управляемой: отдельный аддитивный канал, запись, забывание и чтение. Формула t1/2=ln0,5/lnft_{1/2}=\ln0{,}5/\ln f переводит значение ворот в число шагов и объясняет, почему разница между 0,990{,}99 и 0,9990{,}999 — это разница между семьюдесятью и семьюстами шагами. Аддитивный путь спасает не память, а градиент: до обучения он доносит сигнал через сто шагов в 2620 раз лучше, чем рекуррентная матрица.

Но измерения важнее лозунгов. Ворота отодвинули границу с полусотни шагов к сотне-двум, а не к бесконечности. Обученная сеть выбрала стратегию, которой не было в учебнике. На реальном ряде выигрыш дала не столько ячейка, сколько честное сравнение с baseline, нормировка по train и разбор ошибки на пиках. Ячейка — это гипотеза о том, какой путь сигнала должен быть коротким; всё остальное по-прежнему решают данные и дисциплина эксперимента.

Задачи