Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 95 additions & 42 deletions src/transformers/models/longt5/modeling_longt5.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import copy
import math
from collections.abc import Callable
from typing import Any

import torch
Expand All @@ -33,10 +34,12 @@
Seq2SeqLMOutput,
Seq2SeqModelOutput,
)
from ...modeling_utils import PreTrainedModel
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
from ...processing_utils import Unpack
from ...utils import (
DUMMY_INPUTS,
DUMMY_MASK,
TransformersKwargs,
auto_docstring,
is_torchdynamo_compiling,
logging,
Expand All @@ -47,6 +50,35 @@
logger = logging.get_logger(__name__)


# Copied from transformers.models.bert.modeling_bert.eager_attention_forward
def eager_attention_forward(
module: nn.Module,
query: torch.Tensor,
key: torch.Tensor,
value: torch.Tensor,
attention_mask: torch.Tensor | None,
scaling: float | None = None,
dropout: float = 0.0,
**kwargs: Unpack[TransformersKwargs],
):
if scaling is None:
scaling = query.size(-1) ** -0.5

# Take the dot product between "query" and "key" to get the raw attention scores.
attn_weights = torch.matmul(query, key.transpose(2, 3)) * scaling

if attention_mask is not None:
attn_weights = attn_weights + attention_mask

attn_weights = nn.functional.softmax(attn_weights, dim=-1)
attn_weights = nn.functional.dropout(attn_weights, p=dropout, training=module.training)

attn_output = torch.matmul(attn_weights, value)
attn_output = attn_output.transpose(1, 2).contiguous()

return attn_output, attn_weights


# TODO: Update before the merge


Expand Down Expand Up @@ -303,9 +335,12 @@ def __init__(
config: LongT5Config,
has_relative_attention_bias=False,
layer_idx: int | None = None,
is_causal: bool = False,
):
super().__init__()
self.config = config
self.is_decoder = config.is_decoder
self.is_causal = is_causal
self.has_relative_attention_bias = has_relative_attention_bias
self.relative_attention_num_buckets = config.relative_attention_num_buckets
self.relative_attention_max_distance = config.relative_attention_max_distance
Expand All @@ -314,6 +349,8 @@ def __init__(
self.n_heads = config.num_heads
self.dropout = config.dropout_rate
self.inner_dim = self.n_heads * self.key_value_proj_dim
# LongT5 folds the relative position bias into the attention scores and does not scale the query/key dot product.
self.scaling = 1.0
self.layer_idx = layer_idx
if layer_idx is None and self.is_decoder:
logger.warning_once(
Expand Down Expand Up @@ -404,8 +441,7 @@ def forward(
key_value_states=None,
position_bias=None,
past_key_values=None,
output_attentions=False,
**kwargs,
**kwargs: Unpack[TransformersKwargs],
):
"""
Self-attention (if key_value_states is None) or attention over source sentence (provided by key_value_states).
Expand Down Expand Up @@ -452,43 +488,60 @@ def forward(
past_key_values.is_updated[self.layer_idx] = True

# compute scores, equivalent of torch.einsum("bnqd,bnkd->bnqk", query_states, key_states), compatible with onnx op>9
scores = torch.matmul(query_states, key_states.transpose(3, 2))

if position_bias is None:
key_length = key_states.shape[-2]
if not self.has_relative_attention_bias:
position_bias = torch.zeros(
(1, query_states.shape[1], input_shape[1], key_length), device=scores.device, dtype=scores.dtype
(1, self.n_heads, input_shape[1], key_length),
device=query_states.device,
dtype=query_states.dtype,
)
if self.gradient_checkpointing and self.training:
position_bias.requires_grad = True
else:
position_bias = self.compute_bias(
input_shape[1], key_length, device=scores.device, past_seen_tokens=past_seen_tokens
input_shape[1], key_length, device=query_states.device, past_seen_tokens=past_seen_tokens
)

if mask is not None:
causal_mask = mask[:, :, :, : key_states.shape[-2]]
if causal_mask.dtype == torch.bool:
# `sdpa` may materialize a boolean mask (True = keep). Turn it into an additive float mask so it
# can be folded into the relative position bias, just like the `eager` float mask.
causal_mask = torch.where(
causal_mask,
torch.tensor(0.0, device=causal_mask.device, dtype=position_bias.dtype),
torch.finfo(position_bias.dtype).min,
)
position_bias = position_bias + causal_mask

position_bias_masked = position_bias
scores += position_bias_masked

# (batch_size, n_heads, seq_length, key_length)
attn_weights = nn.functional.softmax(scores.float(), dim=-1).type_as(scores)
attn_weights = nn.functional.dropout(attn_weights, p=self.dropout, training=self.training)
# LongT5 uses a relative attention bias that is added to the attention scores. This is passed as the additive
# attention mask so that it works with the different attention implementations. As it is always non-`None`,
# `is_causal` is never inferred, so the causal behavior is fully encoded in the bias itself.
attention_interface: Callable = eager_attention_forward
if self.config._attn_implementation != "eager":
if self.config._attn_implementation != "sdpa":
raise ValueError(
"LongT5 adds a relative position bias on top of the attention scores, which is only supported by the "
f"`eager` and `sdpa` attention implementations, but got `{self.config._attn_implementation}`."
)
attention_interface = ALL_ATTENTION_FUNCTIONS[self.config._attn_implementation]

attn_output = torch.matmul(attn_weights, value_states)
attn_output, attn_weights = attention_interface(
self,
query_states,
key_states,
value_states,
position_bias,
dropout=0.0 if not self.training else self.dropout,
scaling=self.scaling,
**kwargs,
)

attn_output = attn_output.transpose(1, 2).contiguous()
attn_output = attn_output.reshape(*input_shape, -1)
attn_output = attn_output.reshape(*input_shape, -1).contiguous()
attn_output = self.o(attn_output)

outputs = (attn_output, position_bias)

if output_attentions:
outputs = outputs + (attn_weights,)
return outputs
return attn_output, position_bias, attn_weights


class LongT5LocalAttention(nn.Module):
Expand Down Expand Up @@ -907,7 +960,10 @@ class LongT5LayerSelfAttention(nn.Module):
def __init__(self, config, has_relative_attention_bias=False, layer_idx: int | None = None):
super().__init__()
self.SelfAttention = LongT5Attention(
config, has_relative_attention_bias=has_relative_attention_bias, layer_idx=layer_idx
config,
has_relative_attention_bias=has_relative_attention_bias,
layer_idx=layer_idx,
is_causal=config.is_decoder,
)
self.layer_norm = LongT5LayerNorm(config.d_model, eps=config.layer_norm_epsilon)
self.dropout = nn.Dropout(config.dropout_rate)
Expand All @@ -918,22 +974,18 @@ def forward(
attention_mask=None,
position_bias=None,
past_key_values=None,
use_cache=False,
output_attentions=False,
**kwargs,
**kwargs: Unpack[TransformersKwargs],
):
normed_hidden_states = self.layer_norm(hidden_states)
attention_output = self.SelfAttention(
attention_output, position_bias, attn_weights = self.SelfAttention(
normed_hidden_states,
mask=attention_mask,
position_bias=position_bias,
past_key_values=past_key_values,
use_cache=use_cache,
output_attentions=output_attentions,
**kwargs,
)
hidden_states = hidden_states + self.dropout(attention_output[0])
outputs = (hidden_states,) + attention_output[1:] # add attentions if we output them
return outputs
hidden_states = hidden_states + self.dropout(attention_output)
return hidden_states, position_bias, attn_weights


class LongT5LayerLocalSelfAttention(nn.Module):
Expand Down Expand Up @@ -1000,7 +1052,9 @@ def forward(
class LongT5LayerCrossAttention(nn.Module):
def __init__(self, config, layer_idx: int | None = None):
super().__init__()
self.EncDecAttention = LongT5Attention(config, has_relative_attention_bias=False, layer_idx=layer_idx)
self.EncDecAttention = LongT5Attention(
config, has_relative_attention_bias=False, layer_idx=layer_idx, is_causal=False
)
self.layer_norm = LongT5LayerNorm(config.d_model, eps=config.layer_norm_epsilon)
self.dropout = nn.Dropout(config.dropout_rate)

Expand All @@ -1011,21 +1065,19 @@ def forward(
attention_mask=None,
position_bias=None,
past_key_values=None,
output_attentions=False,
**kwargs,
**kwargs: Unpack[TransformersKwargs],
):
normed_hidden_states = self.layer_norm(hidden_states)
attention_output = self.EncDecAttention(
attention_output, position_bias, attn_weights = self.EncDecAttention(
normed_hidden_states,
mask=attention_mask,
key_value_states=key_value_states,
position_bias=position_bias,
past_key_values=past_key_values,
output_attentions=output_attentions,
**kwargs,
)
layer_output = hidden_states + self.dropout(attention_output[0])
outputs = (layer_output,) + attention_output[1:] # add attentions if we output them
return outputs
layer_output = hidden_states + self.dropout(attention_output)
return layer_output, position_bias, attn_weights


class LongT5Block(GradientCheckpointingLayer):
Expand Down Expand Up @@ -1348,11 +1400,12 @@ def forward(
hidden_states = layer_outputs[0]

# We share the position biases between the layers - the first layer store them
# layer_outputs = hidden-states, key-value-states (self-attention position bias), (self-attention weights),
# (cross-attention position bias), (cross-attention weights)
# The self- and cross-attention wrappers now always return their attention weights, so the decoder layer
# output layout is: hidden-states, self-attention position bias, self-attention weights,
# cross-attention position bias, cross-attention weights.
position_bias = layer_outputs[1]
if self.is_decoder and encoder_hidden_states is not None:
encoder_decoder_position_bias = layer_outputs[3 if output_attentions else 2]
encoder_decoder_position_bias = layer_outputs[3]

if output_attentions:
all_attentions = all_attentions + (layer_outputs[2],)
Expand Down
Loading