# RWKV

## Обзор

Модель RWKV (версия 4) была предложена в [этом репозитории](https://github.com/BlinkDL/RWKV-LM)

Она предлагает модификацию традиционного механизма внимания в Transformer, чтобы сделать его линейным. Благодаря этому модель можно использовать как рекуррентную сеть: передача входных данных для временных меток 0 и 1 одновременно эквивалентна передаче входных данных для временной метки 0, а затем входных данных для временной метки 1 вместе с состоянием на временной метке 0 (см. пример ниже).

Это может быть эффективнее обычного Transformer и позволяет обрабатывать предложения любой длины (даже если модель обучалась с фиксированной длиной контекста).

Эта модель была предоставлена пользователем [sgugger](https://huggingface.co/sgugger). Исходный код можно найти [здесь](https://github.com/BlinkDL/RWKV-LM).

## Пример использования

```python
import torch

from transformers import AutoTokenizer, RwkvModel

model = RwkvModel.from_pretrained("sgugger/rwkv-430M-pile", device_map="auto")
tokenizer = AutoTokenizer.from_pretrained("sgugger/rwkv-430M-pile")

inputs = tokenizer("This is an example.", return_tensors="pt").to(model.device)
# Feed everything to the model
outputs = model(inputs["input_ids"])
output_whole = outputs.last_hidden_state

outputs = model(inputs["input_ids"][:, :2])
output_one = outputs.last_hidden_state

# Using the state computed on the first inputs, we will get the same output
outputs = model(inputs["input_ids"][:, 2:], state=outputs.state)
output_two = outputs.last_hidden_state

torch.allclose(torch.cat([output_one, output_two], dim=1), output_whole, atol=1e-5)
```

Если вы хотите убедиться, что модель прекращает генерацию при обнаружении `'\n\n'`, мы рекомендуем использовать следующие критерии остановки:

```python
from transformers import StoppingCriteria

class RwkvStoppingCriteria(StoppingCriteria):
    def __init__(self, eos_sequence = [187,187], eos_token_id = 537):
        self.eos_sequence = eos_sequence
        self.eos_token_id = eos_token_id

    def __call__(self, input_ids: torch.LongTensor, scores: torch.Tensor, **kwargs) -> bool:
        last_2_ids = input_ids[:,-2:].tolist()
        return self.eos_sequence in last_2_ids

output = model.generate(inputs["input_ids"], max_new_tokens=64, stopping_criteria = [RwkvStoppingCriteria()])
```

## Примечания

- Используйте левое выравнивание (left padding) для пакетной генерации. См. [Сторона выравнивания](../llm_tutorial#padding-side).

## RwkvConfig[[transformers.RwkvConfig]]

#### transformers.RwkvConfig[[transformers.RwkvConfig]]

```python
transformers.RwkvConfig(transformers_version: str | None = None, architectures: list[str] | None = None, output_hidden_states: bool | None = False, return_dict: bool | None = True, dtype: str | torch.dtype | None = None, chunk_size_feed_forward: int = 0, is_encoder_decoder: bool = False, id2label: dict[int, str] | dict[str, str] | None = None, label2id: dict[str, int] | dict[str, str] | None = None, problem_type: Literal['regression', 'single_label_classification', 'multi_label_classification'] | None = None, vocab_size: int = 50277, context_length: int = 1024, hidden_size: int = 4096, num_hidden_layers: int = 32, attention_hidden_size: int | None = None, intermediate_size: int | None = None, layer_norm_epsilon: float = 1e-05, bos_token_id: int | None = 0, eos_token_id: int | list[int] | None = 0, rescale_every: int = 6, tie_word_embeddings: bool = False, use_cache: bool = True)
```

[Источник](https://github.com/huggingface/transformers/blob/main/src/transformers/models/rwkv/configuration_rwkv.py#L25)

**Параметры:**

vocab_size (`int`, *необязательный*, по умолчанию `50277`) : Размер словаря модели. Определяет количество различных токенов, которые могут быть представлены в `input_ids`.

context_length (`int`, *optional*, по умолчанию 1024) : Максимальная длина последовательности, с которой можно использовать эту модель за один прямой проход (при использовании в режиме RNN допустима любая длина последовательности).

hidden_size (`int`, *optional*, по умолчанию `4096`) : Размерность скрытых представлений.

num_hidden_layers (`int`, *необязательный*, по умолчанию `32`) : Количество скрытых слоев в декодере Transformer.

attention_hidden_size (`int`, *optional*) : Размерность скрытых состояний внимания. Если не задано, по умолчанию используется `hidden_size`.

intermediate_size (`int`, *необязательный*) : Размерность представлений MLP.

layer_norm_epsilon (`float`, *необязательный*, по умолчанию `1e-05`) : Значение epsilon, используемое слоями нормализации.

bos_token_id (`int`, *необязательный*, по умолчанию `0`) : Идентификатор токена, используемый для обозначения начала потока в словаре.

eos_token_id (`Union[int, list[int]]`, *необязательный*, по умолчанию `0`) : Идентификатор токена, используемого для обозначения конца потока в словаре.

rescale_every (`int`, *optional*, по умолчанию 6) : На этапе инференса скрытые состояния (и веса соответствующих выходных слоёв) делятся на 2 каждые `rescale_every` слой. Если установлено значение 0 или отрицательное число, рескейлинг не выполняется.

tie_word_embeddings (`bool`, *необязательный*, по умолчанию `False`) : Связывать ли веса эмбеддингов согласно отображению `tied_weights_keys` модели.

use_cache (`bool`, *необязательный*, по умолчанию `True`) : Следует ли модели возвращать последние значения внимания key/values (не используется во всех моделях). Актуально только при `config.is_decoder=True` или если модель является генеративной моделью только с декодером.

Это класс конфигурации для хранения настроек модели RwkvModel. Он используется для создания экземпляра модели Rwkv в соответствии с указанными аргументами, определяя архитектуру модели. Создание конфигурации с параметрами по умолчанию даст конфигурацию, аналогичную конфигурации модели [RWKV/rwkv-4-169m-pile](https://huggingface.co/RWKV/rwkv-4-169m-pile)

Объекты конфигурации наследуются от [PreTrainedConfig](/docs/transformers/main/ru/main_classes/configuration#transformers.PreTrainedConfig) и могут использоваться для управления выводами модели. Подробнее см. в документации [PreTrainedConfig](/docs/transformers/main/ru/main_classes/configuration#transformers.PreTrainedConfig).

Пример:

```python
>>> from transformers import RwkvConfig, RwkvModel

>>> # Initializing a Rwkv configuration
>>> configuration = RwkvConfig()

>>> # Initializing a model (with random weights) from the configuration
>>> model = RwkvModel(configuration)

>>> # Accessing the model configuration
>>> configuration = model.config
```

## RwkvModel[[transformers.RwkvModel]]

#### transformers.RwkvModel[[transformers.RwkvModel]]

```python
transformers.RwkvModel(config: RwkvConfig)
```

[Источник](https://github.com/huggingface/transformers/blob/main/src/transformers/models/rwkv/modeling_rwkv.py#L487)

**Параметры:**

config ([RwkvConfig](/docs/transformers/main/ru/model_doc/rwkv#transformers.RwkvConfig)) : Класс конфигурации модели со всеми параметрами модели. Инициализация с файлом конфигурации не загружает веса, связанные с моделью, только конфигурацию. Используйте метод [from_pretrained()](/docs/transformers/main/ru/main_classes/model#transformers.PreTrainedModel.from_pretrained) для загрузки весов модели.

Модель Rwkv без дополнительных слоёв, выводящая необработанные скрытые состояния.

Эта модель наследуется от [PreTrainedModel](/docs/transformers/main/ru/main_classes/model#transformers.PreTrainedModel). Общие методы, которые библиотека реализует для всех своих моделей (например, загрузка или сохранение, изменение размера входных эмбеддингов, обрезка головок и т. д.), описаны в документации родительского класса.

Эта модель также является подклассом [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) в PyTorch. Используйте её как обычный модуль PyTorch и обращайтесь к документации PyTorch по всем вопросам, связанным с общим использованием и поведением.

#### forward[[transformers.RwkvModel.forward]]

```python
forward(input_ids: typing.Optional[torch.LongTensor] = None, attention_mask: typing.Optional[torch.LongTensor] = None, inputs_embeds: typing.Optional[torch.Tensor] = None, state: list[torch.Tensor] | None = None, use_cache: bool | None = None, output_attentions: bool | None = None, output_hidden_states: bool | None = None, return_dict: bool | None = None, **kwargs)
```

[Источник](https://github.com/huggingface/transformers/blob/main/src/transformers/models/rwkv/modeling_rwkv.py#L508)

**Параметры:**

input_ids (`torch.LongTensor` формы `(batch_size, input_ids_length)`) : `input_ids_length` = `sequence_length`, если `past_key_values` равно `None`, иначе `past_key_values.get_seq_length()` (`sequence_length` входных состояний past key value). Индексы токенов входной последовательности в словаре. Если используется `past_key_values`, в качестве `input_ids` следует передавать только те `input_ids`, для которых ещё не рассчитано прошлое. Индексы можно получить с помощью [AutoTokenizer](/docs/transformers/main/ru/model_doc/auto#transformers.AutoTokenizer). Подробности см. в [PreTrainedTokenizer.encode()](/docs/transformers/main/ru/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.encode) и [PreTrainedTokenizer.__call__()](/docs/transformers/main/ru/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.__call__). [Что такое input IDs?](../glossary#input-ids)

attention_mask (`torch.LongTensor` формы `(batch_size, sequence_length)`, *необязательный*) : Маска для предотвращения применения внимания к индексам токенов отсечки. Значения маски выбираются из `[0, 1]`:  - 1 для токенов, которые **не замаскированы**, - 0 для токенов, которые **замаскированы**.  [Что такое маски внимания?](../glossary#attention-mask)

inputs_embeds (`torch.Tensor` формы `(batch_size, sequence_length, hidden_size)`, *необязательно*) : По желанию, вместо передачи `input_ids` можно напрямую передать встроенное представление. Это полезно, если требуется больший контроль над тем, как индексы `input_ids` преобразуются в соответствующие векторы, чем это обеспечивает внутренняя матрица поиска встраиваний модели.

state (`tuple` из пяти `torch.Tensor` формы `(batch_size, hidden_size, num_hidden_layers)`, *необязательный*) : Если передан, модель использует предыдущее состояние во всех блоках (что даст вывод для переданных `input_ids`, как если бы модель добавила `state_input_ids + input_ids` в контекст).

use_cache (`bool`, *необязательный*) : Если установлено в `True`, возвращается последнее состояние, которое можно использовать для быстрого генерирования следующих logits.

output_attentions (`bool`, *необязательный*) : Нужно ли возвращать тензоры внимания всех слоев внимания. Подробнее см. `attentions` в разделе возвращаемых тензоров.

output_hidden_states (`bool`, *необязательный*) : Нужно ли возвращать скрытые состояния всех слоёв. Подробнее о `hidden_states` в разделе возвращаемых тензоров.

return_dict (`bool`, *необязательный*) : Нужно ли возвращать [ModelOutput](/docs/transformers/main/ru/main_classes/output#transformers.utils.ModelOutput) вместо обычного кортежа.

**Возвращает:** `RwkvOutput` или `tuple(torch.Tensor)`

A `RwkvOutput` or a tuple of `torch.Tensor` (if `return_dict=False` is passed or when `config.return_dict=False`) comprising various elements depending on the configuration ([RwkvConfig](/docs/transformers/main/ru/model_doc/rwkv#transformers.RwkvConfig)) and inputs.

Метод forward класса [RwkvModel](/docs/transformers/main/ru/model_doc/rwkv#transformers.RwkvModel) переопределяет специальный метод `__call__`.

Хотя рецепт для прямого прохода должен быть определён внутри этой функции, после этого следует вызывать экземпляр `Module`, а не эту функцию, поскольку первый выполняет шаги предварительной и постобработки, тогда как второй молча их игнорирует.

- **last_hidden_state** (`torch.Tensor` формы `(batch_size, sequence_length, hidden_size)`, *необязательный*) -- Последовательность скрытых состояний на выходе последнего слоя модели.
- **state** (`list` из пяти `torch.Tensor` формы `(batch_size, hidden_size, num_hidden_layers)`) -- Состояние модели на последнем шаге времени. Может использоваться в forward-методе вместе с новыми `input_ids`, чтобы не передавать старые `input_ids`.
- **hidden_states** (`tuple[torch.Tensor, ...]`, *необязательный*, возвращается, если передано `output_hidden_states=True` или если `config.output_hidden_states=True`) -- Кортеж `torch.Tensor` (один для вывода слоя встраиваний, если модель имеет слой встраиваний, + один для вывода каждого слоя) формы `(batch_size, sequence_length, hidden_size)`.

  Скрытые состояния модели на выходе каждого слоя, а также необязательные выходные значения начального слоя встраивания.
- **attentions** (`tuple[torch.Tensor, ...]`, *необязательный*, возвращается, если передано `output_attentions=True` или если `config.output_attentions=True`) -- Кортеж `torch.Tensor` (по одному на каждый слой) формы `(batch_size, num_heads, sequence_length, sequence_length)`.

  Веса внимания после softmax в механизме внимания, используемые для вычисления взвешенного среднего в головах само-внимания.

## RwkvLMHeadModel[[transformers.RwkvForCausalLM]]

#### transformers.RwkvForCausalLM[[transformers.RwkvForCausalLM]]

```python
transformers.RwkvForCausalLM(config: RwkvConfig)
```

[Источник](https://github.com/huggingface/transformers/blob/main/src/transformers/models/rwkv/modeling_rwkv.py#L667)

**Параметры:**

config ([RwkvConfig](/docs/transformers/main/ru/model_doc/rwkv#transformers.RwkvConfig)) : Класс конфигурации модели со всеми параметрами модели. Инициализация с файлом конфигурации не загружает веса, связанные с моделью, только конфигурацию. Используйте метод [from_pretrained()](/docs/transformers/main/ru/main_classes/model#transformers.PreTrainedModel.from_pretrained) для загрузки весов модели.

Трансформер модели RWKV с головой для моделирования языка сверху (линейный слой с весами, связанными со входными эмбеддингами).

Эта модель наследуется от [PreTrainedModel](/docs/transformers/main/ru/main_classes/model#transformers.PreTrainedModel). Общие методы, которые библиотека реализует для всех своих моделей (например, загрузка или сохранение, изменение размера входных эмбеддингов, обрезка головок и т. д.), описаны в документации родительского класса.

Эта модель также является подклассом [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) в PyTorch. Используйте её как обычный модуль PyTorch и обращайтесь к документации PyTorch по всем вопросам, связанным с общим использованием и поведением.

#### forward[[transformers.RwkvForCausalLM.forward]]

```python
forward(input_ids: typing.Optional[torch.LongTensor] = None, attention_mask: typing.Optional[torch.LongTensor] = None, inputs_embeds: typing.Optional[torch.Tensor] = None, state: list[torch.Tensor] | None = None, labels: typing.Optional[torch.LongTensor] = None, use_cache: bool | None = None, output_attentions: bool | None = None, output_hidden_states: bool | None = None, return_dict: bool | None = None, logits_to_keep: typing.Union[int, torch.Tensor] = 0, **kwargs)
```

[Источник](https://github.com/huggingface/transformers/blob/main/src/transformers/models/rwkv/modeling_rwkv.py#L684)

**Параметры:**

input_ids (`torch.LongTensor` формы `(batch_size, input_ids_length)`) : `input_ids_length` = `sequence_length`, если `past_key_values` равно `None`, иначе `past_key_values.get_seq_length()` (`sequence_length` входных состояний past key value). Индексы токенов входной последовательности в словаре. Если используется `past_key_values`, в качестве `input_ids` следует передавать только те `input_ids`, для которых ещё не рассчитано прошлое. Индексы можно получить с помощью [AutoTokenizer](/docs/transformers/main/ru/model_doc/auto#transformers.AutoTokenizer). Подробности см. в [PreTrainedTokenizer.encode()](/docs/transformers/main/ru/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.encode) и [PreTrainedTokenizer.__call__()](/docs/transformers/main/ru/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.__call__). [Что такое input IDs?](../glossary#input-ids)

attention_mask (`torch.LongTensor` формы `(batch_size, sequence_length)`, *необязательный*) : Маска для предотвращения применения внимания к индексам токенов отсечки. Значения маски выбираются из `[0, 1]`:  - 1 для токенов, которые **не замаскированы**, - 0 для токенов, которые **замаскированы**.  [Что такое маски внимания?](../glossary#attention-mask)

inputs_embeds (`torch.Tensor` формы `(batch_size, sequence_length, hidden_size)`, *необязательно*) : По желанию, вместо передачи `input_ids` можно напрямую передать встроенное представление. Это полезно, если требуется больший контроль над тем, как индексы `input_ids` преобразуются в соответствующие векторы, чем это обеспечивает внутренняя матрица поиска встраиваний модели.

state (`tuple` из пяти `torch.Tensor` формы `(batch_size, hidden_size, num_hidden_layers)`, *необязательный*) : Если передан, модель использует предыдущее состояние во всех блоках (что даст вывод для переданных `input_ids`, как если бы модель добавила `state_input_ids + input_ids` в контекст).

labels (`torch.LongTensor` формы `(batch_size, sequence_length)`, *необязательно*) : Метки для моделирования языка. Обратите внимание, что метки **сдвинуты** внутри модели, то есть можно установить `labels = input_ids` Индексы выбираются из `[-100, 0, ..., config.vocab_size]` Все метки, установленные в `-100`, игнорируются (маскируются), потеря вычисляется только для меток в `[0, ..., config.vocab_size]`

use_cache (`bool`, *необязательный*) : Если установлено в `True`, возвращается последнее состояние, которое можно использовать для быстрого генерирования следующих logits.

output_attentions (`bool`, *необязательный*) : Нужно ли возвращать тензоры внимания всех слоев внимания. Подробнее см. `attentions` в разделе возвращаемых тензоров.

output_hidden_states (`bool`, *необязательный*) : Нужно ли возвращать скрытые состояния всех слоёв. Подробнее о `hidden_states` в разделе возвращаемых тензоров.

return_dict (`bool`, *необязательный*) : Нужно ли возвращать [ModelOutput](/docs/transformers/main/ru/main_classes/output#transformers.utils.ModelOutput) вместо обычного кортежа.

logits_to_keep (`Union[int, torch.Tensor]`, *необязательный*, по умолчанию `0`) : Если передано значение типа `int`, вычисляются logits для последних `logits_to_keep` токенов. Если передано `0`, logits вычисляются для всех `input_ids` (специальный случай). Для генерации нужны logits только последнего токена, и вычисление их только для этого токена позволяет сэкономить память, что становится весьма значимым для длинных последовательностей или большого размера словаря. Если передано значение типа `torch.Tensor`, оно должно быть одномерным и соответствовать индексам, которые нужно сохранить в измерении длины последовательности. Это полезно при использовании упакованного формата тензоров (одно измерение для batch и длины последовательности).

**Возвращает:** `RwkvCausalLMOutput` или `tuple(torch.Tensor)`

Объект `RwkvCausalLMOutput` или кортеж из `torch.Tensor` (если передано `return_dict=False` или если `config.return_dict=False`), содержащий различные элементы в зависимости от конфигурации ([RwkvConfig](/docs/transformers/main/ru/model_doc/rwkv#transformers.RwkvConfig)) и входных данных.

Метод forward класса [RwkvForCausalLM](/docs/transformers/main/ru/model_doc/rwkv#transformers.RwkvForCausalLM) переопределяет специальный метод `__call__`.

Хотя рецепт для прямого прохода должен быть определён внутри этой функции, после этого следует вызывать экземпляр `Module`, а не эту функцию, поскольку первый выполняет шаги предварительной и постобработки, тогда как второй молча их игнорирует.

- **loss** (`torch.Tensor` формы `(1,)`, *необязательный*, возвращается, если задан `labels`) -- Потеря языковой модели (для предсказания следующего токена).
- **logits** (`torch.Tensor` формы `(batch_size, sequence_length, config.vocab_size)`) — Оценки предсказаний языковой модели (оценки для каждого токена словаря до применения SoftMax).
- **state** (`list` из пяти `torch.Tensor` формы `(batch_size, hidden_size, num_hidden_layers)`) -- Состояние модели на последнем шаге времени. Может использоваться в forward-методе вместе с новыми `input_ids`, чтобы не передавать старые `input_ids`.
- **hidden_states** (`tuple[torch.Tensor, ...]`, *необязательный*, возвращается, если передано `output_hidden_states=True` или если `config.output_hidden_states=True`) -- Кортеж `torch.Tensor` (один для вывода слоя встраиваний, если модель имеет слой встраиваний, + один для вывода каждого слоя) формы `(batch_size, sequence_length, hidden_size)`.

  Скрытые состояния модели на выходе каждого слоя, а также необязательные выходные значения начального слоя встраивания.
- **attentions** (`tuple[torch.Tensor, ...]`, *необязательный*, возвращается, если передано `output_attentions=True` или если `config.output_attentions=True`) -- Кортеж `torch.Tensor` (по одному на каждый слой) формы `(batch_size, num_heads, sequence_length, sequence_length)`.

  Веса внимания после softmax в механизме внимания, используемые для вычисления взвешенного среднего в головах само-внимания.

Пример:

```python
```

## Внимание Rwkv и рекуррентные формулы

В традиционном авто-регрессивном Transformer внимание записывается как

$$O = \hbox{softmax}(QK^{T} / \sqrt{d}) V$$

где $Q$, $K$ и $V$ — матрицы размера `seq_len x hidden_size`, называемые query, key и value (на самом деле это более крупные матрицы с размерностями batch и attention head, но нас интересуют только последние две, так как именно по ним берётся произведение матриц, поэтому ради простоты мы рассматриваем только их). Тогда произведение $QK^{T}$ имеет размер `seq_len x seq_len`, и мы можем взять произведение матриц с $V$, чтобы получить выход $O$ того же размера, что и остальные.

Замена softmax его значением даёт:

$$O_{i} = \frac{\sum_{j=1}^{i} e^{Q_{i} K_{j}^{T} / \sqrt{d}} V_{j}}{\sum_{j=1}^{i} e^{Q_{i} K_{j}^{T} / \sqrt{d}}}$$

Обратите внимание, что элементы в $QK^{T}$, соответствующие $j > i$, маскируются (суммирование останавливается на j), поскольку внимание не может обращать внимание на будущие токены (только на прошлые).

В сравнении с этим, внимание в RWKV определяется как

$$O_{i} = \sigma(R_{i}) \frac{\sum_{j=1}^{i} e^{W_{i-j} + K_{j}} V_{j}}{\sum_{j=1}^{i} e^{W_{i-j} + K_{j}}}$$

где $R$ — новая матрица, названная автором рецептансностью, $K$ и $V$ по-прежнему являются ключом и значением ($\sigma$ здесь — функция сигмоиды). $W$ — новый вектор, представляющий позицию токена, который задаётся выражением

$$W_{0} = u \hbox{  и  } W_{k} = (k-1)w \hbox{ для } k \geq 1$$

где $u$ и $w$ — обучаемые параметры, которые в коде называются `time_first` и `time_decay` соответственно. Числитель и знаменатель можно выразить рекурсивно. Обозначив их как $N_{i}$ и $D_{i}$, получаем:

$$N_{i} = e^{u + K_{i}} V_{i} + \hat{N}_{i} \hbox{  где  } \hat{N}_{i} = e^{K_{i-1}} V_{i-1} + e^{w + K_{i-2}} V_{i-2} \cdots + e^{(i-2)w + K_{1}} V_{1}$$

тогда `numerator_state` (обозначаемое в коде как `numerator_state`) удовлетворяет

$$\hat{N}_{0} = 0 \hbox{  and  } \hat{N}_{j+1} = e^{K_{j}} V_{j} + e^{w} \hat{N}_{j}$$

и

$$D_{i} = e^{u + K_{i}} + \hat{D}_{i} \hbox{  где  } \hat{D}_{i} = e^{K_{i-1}} + e^{w + K_{i-2}} \cdots + e^{(i-2)w + K_{1}}$$

тогда `denominator_state` (обозначаемое как `denominator_state` в коде) удовлетворяет

$$\hat{D}_{0} = 0 \hbox{  and  } \hat{D}_{j+1} = e^{K_{j}} + e^{w} \hat{D}_{j}$$

Фактическая рекуррентная формула немного сложнее, поскольку ради численной стабильности мы не хотим вычислять экспоненты больших чисел. Обычно softmax вычисляется не напрямую, а экспонента максимального члена вычитается из числителя и знаменателя:

$$\frac{e^{x_{i}}}{\sum_{j=1}^{n} e^{x_{j}}} = \frac{e^{x_{i} - M}}{\sum_{j=1}^{n} e^{x_{j} - M}}$$

где $M$ — максимум всех $x_{j}$. Таким образом, помимо сохранения состояния числителя ($\hat{N}$) и состояния знаменателя ($\hat{D}$), мы также отслеживаем максимум всех членов, встречающихся в экспонентах. Таким образом, мы фактически используем

$$\tilde{N}_{i} = e^{-M_{i}} \hat{N}_{i} \hbox{  и  } \tilde{D}_{i} = e^{-M_{i}} \hat{D}_{i}$$

определяются следующими рекуррентными формулами:

$$\tilde{N}_{0} = 0 \hbox{  и  } \tilde{N}_{j+1} = e^{K_{j} - q} V_{j} + e^{w + M_{j} - q} \tilde{N}_{j} \hbox{  где  } q = \max(K_{j}, w + M_{j})$$

и

$$\tilde{D}_{0} = 0 \hbox{  и  } \tilde{D}_{j+1} = e^{K_{j} - q} + e^{w + M_{j} - q} \tilde{D}_{j} \hbox{  где  } q = \max(K_{j}, w + M_{j})$$

и $M_{j+1} = q$. С их помощью мы можем затем вычислить

$$N_{i} = e^{u + K_{i} - q} V_{i} + e^{M_{i}} \tilde{N}_{i} \hbox{  где  } q = \max(u + K_{i}, M_{i})$$

и

$$D_{i} = e^{u + K_{i} - q} + e^{M_{i}} \tilde{D}_{i} \hbox{  где  } q = \max(u + K_{i}, M_{i})$$

что в итоге даёт нам

$$O_{i} = \sigma(R_{i}) \frac{N_{i}}{D_{i}}$$

