Skip to content

Commit 6072fa3

Browse files
stashuk-olekfacebook-github-bot
authored andcommitted
Simplify core attention return types to Tensor (facebookresearch#537)
Summary: After removing all consumers of `head_mask`, `return_attn_weights`, and `attn_probs` in the previous commits, the core attention module can be simplified. This commit: - Removes `head_mask` param from `scaled_dot_product_attention` and `SelfAttention.forward` - Changes return types from `Tuple[Tensor, Tensor]` to `Tensor` (no longer returning attention probabilities) - Removes `return_attn_weights` param and tuple unpacking logic from `MultiHeadAttention.forward` - Cleans up unused imports (`Tuple`, `Union`) No behavioral change — the attention computation itself is unchanged. Differential Revision: D92927085
1 parent 6b4ef4a commit 6072fa3

3 files changed

Lines changed: 22 additions & 91 deletions

File tree

tests/modules/layers/test_attention.py

Lines changed: 4 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ def test_multi_head_attention_causal_use_cache(
244244

245245
class TestScaledDotProductAttention:
246246
def test_scaled_dot_product_attention(self, q, kv):
247-
output, weights = scaled_dot_product_attention(q, kv, kv)
247+
output = scaled_dot_product_attention(q, kv, kv)
248248
actual = output
249249
expected = torch.tensor(
250250
[
@@ -263,31 +263,13 @@ def test_scaled_dot_product_attention(self, q, kv):
263263
]
264264
)
265265
assert_expected(actual, expected, rtol=0, atol=1e-4)
266-
actual = weights
267-
expected = torch.tensor(
268-
[
269-
[
270-
[
271-
[
272-
[[0.8797, 0.1203], [0.5595, 0.4405]],
273-
[[0.0553, 0.9447], [0.4549, 0.5451]],
274-
],
275-
[
276-
[[0.0419, 0.9581], [0.4391, 0.5609]],
277-
[[0.0297, 0.9703], [0.7313, 0.2687]],
278-
],
279-
]
280-
]
281-
]
282-
)
283-
assert_expected(actual, expected, rtol=0, atol=1e-4)
284266

285267
def test_scaled_dot_product_attention_with_attention_mask(self, q, kv):
286268
attn_shape = torch.Size([1, 1, 2, 2, 2, 2])
287269
mask = torch.tensor([1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1]).view(
288270
attn_shape
289271
)
290-
actual, _ = scaled_dot_product_attention(q, kv, kv, attention_mask=mask)
272+
actual = scaled_dot_product_attention(q, kv, kv, attention_mask=mask)
291273
expected = torch.tensor(
292274
[
293275
[
@@ -306,32 +288,8 @@ def test_scaled_dot_product_attention_with_attention_mask(self, q, kv):
306288
)
307289
assert_expected(actual, expected, rtol=0, atol=1e-4)
308290

309-
def test_scaled_dot_product_attention_with_head_mask(self, q, kv):
310-
attn_shape = torch.Size([1, 1, 2, 2, 2, 2])
311-
mask = torch.tensor([1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1]).view(
312-
attn_shape
313-
)
314-
actual, _ = scaled_dot_product_attention(q, kv, kv, head_mask=mask)
315-
expected = torch.tensor(
316-
[
317-
[
318-
[
319-
[
320-
[[-0.6195, 1.7705, 0.8023], [-0.2718, 1.2177, 1.4946]],
321-
[[-0.1561, 0.1993, 0.4882], [0.7800, -0.1800, 0.0093]],
322-
],
323-
[
324-
[[0.2950, 1.2029, 1.7035], [0.1668, 0.7129, 1.0162]],
325-
[[0.0455, -0.0077, -0.0345], [0.7875, 0.0928, -0.7952]],
326-
],
327-
]
328-
]
329-
]
330-
)
331-
assert_expected(actual, expected, rtol=0, atol=1e-4)
332-
333291
def test_scaled_dot_product_attention_with_dropout(self, q, kv):
334-
actual, _ = scaled_dot_product_attention(q, kv, kv, attn_dropout=0.3)
292+
actual = scaled_dot_product_attention(q, kv, kv, attn_dropout=0.3)
335293
expected = torch.tensor(
336294
[
337295
[
@@ -365,7 +323,7 @@ def test_scaled_dot_product_attention_with_dropout(self, q, kv):
365323

366324
def test_self_attention(self_attn, q, kv):
367325
k = v = kv
368-
actual, _ = self_attn(q, k, v)
326+
actual = self_attn(q, k, v)
369327
# Output of self attention should be same as scaled_dot_product_attention
370328
# since input dims are flattened
371329
expected = torch.tensor(

torchmultimodal/models/video_gpt/video_vqvae.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def forward(
6666
old_shape = list(v.shape)
6767
v = v.flatten(end_dim=-3)
6868

69-
out, _ = scaled_dot_product_attention(
69+
out = scaled_dot_product_attention(
7070
q,
7171
k,
7272
v,

torchmultimodal/modules/layers/attention.py

Lines changed: 17 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# This source code is licensed under the BSD-style license found in the
55
# LICENSE file in the root directory of this source tree.
66

7-
from typing import Any, Dict, Optional, Tuple, Union
7+
from typing import Any, Dict, Optional
88

99
import torch
1010
from torch import nn, Tensor
@@ -29,8 +29,7 @@ def forward(
2929
k: Tensor,
3030
v: Tensor,
3131
attention_mask: Optional[Tensor] = None,
32-
head_mask: Optional[Tensor] = None,
33-
) -> Tuple[Tensor, Tensor]:
32+
) -> Tensor:
3433
"""
3534
Args:
3635
q (Tensor): Query input of shape ``(b, h, d1, ..., dn, dim_q)`` where ``h`` is the number of
@@ -42,11 +41,9 @@ def forward(
4241
attention_mask (Tensor, optional): Tensor of shape ``(b, h, q_dn, k_dn)`` where ``q_dn`` is the
4342
dimension of the flattened query input along its latent dimensions and ``k_dn`` that of the
4443
flattened key input. Contains 1s for positions to attend to and 0s for masked positions.
45-
head_mask (Tensor, optional): Tensor of shape ``(b, h, q_dn, k_dn)``.
46-
Contains 1s for positions to attend to and 0s for masked positions.
4744
4845
Returns:
49-
A tuple of output tensor and attention probabilities.
46+
Output tensor.
5047
"""
5148
_, _, *shape, _ = q.shape
5249

@@ -55,16 +52,15 @@ def forward(
5552
k = k.flatten(start_dim=2, end_dim=-2)
5653
v = v.flatten(start_dim=2, end_dim=-2)
5754

58-
out, attn_probs = scaled_dot_product_attention(
55+
out = scaled_dot_product_attention(
5956
q,
6057
k,
6158
v,
6259
attention_mask=attention_mask,
63-
head_mask=head_mask,
6460
attn_dropout=self.attn_dropout if self.training else 0.0,
6561
)
6662

67-
return out.unflatten(2, shape), attn_probs
63+
return out.unflatten(2, shape)
6864

6965

7066
class MultiHeadAttention(nn.Module):
@@ -121,11 +117,10 @@ def forward(
121117
self,
122118
q: Tensor,
123119
kv: Optional[Tensor] = None,
124-
return_attn_weights: bool = False,
125120
use_cache: bool = False,
126121
causal: bool = False,
127122
**attn_kwargs: Any,
128-
) -> Union[Tensor, Tuple[Tensor, Tensor]]:
123+
) -> Tensor:
129124
"""
130125
Args:
131126
q (Tensor): Query of shape ``(b, d1, ..., dn, dim_q)`` or ``(b, seq_len, dim_q)``
@@ -138,8 +133,7 @@ def forward(
138133
causal (bool): Whether to use causal attention or not. Default is ``False``.
139134
140135
Returns:
141-
* If ``return_attn_weights`` is ``True``: A tuple of output tensor and attention probabilities.
142-
* If ``return_attn_weights`` is ``False``: A single output tensor.
136+
Output tensor.
143137
"""
144138
# If kv is specified use those inputs for cross-attention, otherwise use q
145139
k = v = q if kv is None else kv
@@ -169,51 +163,33 @@ def forward(
169163
k, v = self.cache["k"], self.cache["v"]
170164

171165
attn_out = self.attn(q, k, v, **attn_kwargs)
172-
attn_probs = None
173-
# Unpack if attn module also returns attn probs
174-
if isinstance(attn_out, tuple):
175-
attn_out, attn_probs = attn_out
176166
a = merge_multihead(attn_out)
177167
a = self.output(a)
178168

179-
if return_attn_weights:
180-
return a, attn_probs
181-
else:
182-
return a
169+
return a
183170

184171

185172
def scaled_dot_product_attention(
186173
q: Tensor,
187174
k: Tensor,
188175
v: Tensor,
189176
attention_mask: Optional[Tensor] = None,
190-
head_mask: Optional[Tensor] = None,
191177
attn_dropout: float = 0.0,
192-
) -> Tuple[Tensor, Tensor]:
193-
"""Similar to PyTorch Core's _scaled_dot_product_attention but generalized
194-
to handle n-dimensional input tokens (images, video) and support multihead.
195-
Computes attention as described in Attention Is All You Need (Vaswani et al. 2017)
178+
) -> Tensor:
179+
"""Computes scaled dot-product attention. Similar to PyTorch Core's
180+
``scaled_dot_product_attention`` but generalized to handle n-dimensional
181+
input tokens (images, video) and support multihead.
196182
197183
Args:
198-
q (Tensor): Query of shape ``(b, h, d1, ..., dn, dim_qk)`` or ``(b, h, seq_len, dim_qk)`` where
199-
``h`` is number of attention heads, ``d1, ..., dn`` are latent dimensions and ``dim_qk` is
200-
the embedding dim of the query tensor.
201-
k (Tensor): Key of shape ``(b, h, d1', ...., dn', dim_qk)`` or ``(b, h, seq_len', dim_qk)`` where
202-
``h`` is the number of attention heads, ``d1', ..., dn'` are latent dimensions and ``dim_qk``
203-
is the key embedding dim aligned with query embedding dim,
204-
see :class:`~torchmultimodal.modules.layers.attention.MultiHeadAttention`.
205-
v (Tensor): Value of shape ``(b, h, d1', ..., dn', dim_v)`` or ``(b, h, seq_len', dim_v)`` where
206-
``h`` is the number of attention heads, ``d1', ..., dn'`` are latent dimensions and ``dim_v``
207-
is the embedding dim of the value tensor.
184+
q (Tensor): Query of shape ``(b, h, d1, ..., dn, dim_qk)`` or ``(b, h, seq_len, dim_qk)``.
185+
k (Tensor): Key of shape ``(b, h, d1', ...., dn', dim_qk)`` or ``(b, h, seq_len', dim_qk)``.
186+
v (Tensor): Value of shape ``(b, h, d1', ..., dn', dim_v)`` or ``(b, h, seq_len', dim_v)``.
208187
attention_mask (Tensor, optional): Tensor of shape ``(b, h, d1, ..., q_dn, k_dn)``.
209-
Contains 1s for positions to attend to and 0s for masked positions. Applied before softmax.
210-
head_mask (Tensor, optional): Tensor of shape ``(b, h, d1, ..., q_dn, k_dn)``.
211188
Contains 1s for positions to attend to and 0s for masked positions.
212-
Applied after dropout, before matrix multiplication with values.
213189
attn_dropout (float): Probability of dropout after softmax. Default is ``0.0``.
214190
215191
Returns:
216-
A tuple of output tensor and attention probabilities.
192+
Output tensor.
217193
"""
218194

219195
# Take the dot product between "query" and "key" and scale to get the raw attention scores.
@@ -232,13 +208,10 @@ def scaled_dot_product_attention(
232208
# This is actually dropping out entire tokens to attend to, which might
233209
# seem a bit unusual, but is taken from the original Transformer paper.
234210
attn = F.dropout(attn, p=attn_dropout)
235-
# Mask heads if we want to
236-
if head_mask is not None:
237-
attn = attn * head_mask
238211
# For each query sum over the key/value dim with attention weights
239212
a = torch.matmul(attn, v) # b, h, d1, ..., q_dn, c
240213

241-
return a, attn
214+
return a
242215

243216

244217
def split_multihead(x: Tensor, n_head: int) -> Tensor:

0 commit comments

Comments
 (0)