CoolFace
Modelpublic

faisalashraf/abaffinity

sourceHugging Facemitupdated 7mo agoView on Hugging Face
0likes
multihead_attention.py509 linesDownload Raw Back to abaffinity
1# Copyright (c) Meta Platforms, Inc. and affiliates.2#3# This source code is licensed under the MIT license found in the4# LICENSE file in the root directory of this source tree.5 6import math7from typing import Dict, Optional, Tuple8 9import torch10import torch.nn.functional as F11from torch import Tensor, nn12from torch.nn import Parameter13from .rotary_embedding import RotaryEmbedding14 15import uuid16 17 18def utils_softmax(x, dim: int, onnx_trace: bool = False):19    if onnx_trace:20        return F.softmax(x.float(), dim=dim)21    else:22        return F.softmax(x, dim=dim, dtype=torch.float32)23 24 25class FairseqIncrementalState(object):26    def __init__(self, *args, **kwargs):27        super().__init__(*args, **kwargs)28        self.init_incremental_state()29 30    def init_incremental_state(self):31        self._incremental_state_id = str(uuid.uuid4())32 33    def _get_full_incremental_state_key(self, key: str) -> str:34        return "{}.{}".format(self._incremental_state_id, key)35 36    def get_incremental_state(37        self,38        incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]],39        key: str,40    ) -> Optional[Dict[str, Optional[Tensor]]]:41        """Helper for getting incremental state for an nn.Module."""42        full_key = self._get_full_incremental_state_key(key)43        if incremental_state is None or full_key not in incremental_state:44            return None45        return incremental_state[full_key]46 47    def set_incremental_state(48        self,49        incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]],50        key: str,51        value: Dict[str, Optional[Tensor]],52    ) -> Optional[Dict[str, Dict[str, Optional[Tensor]]]]:53        """Helper for setting incremental state for an nn.Module."""54        if incremental_state is not None:55            full_key = self._get_full_incremental_state_key(key)56            incremental_state[full_key] = value57        return incremental_state58 59 60def with_incremental_state(cls):61    cls.__bases__ = (FairseqIncrementalState,) + tuple(62        b for b in cls.__bases__ if b != FairseqIncrementalState63    )64    return cls65 66 67@with_incremental_state68class MultiheadAttention(nn.Module):69    """Multi-headed attention.70 71    See "Attention Is All You Need" for more details.72    """73 74    def __init__(75        self,76        embed_dim,77        num_heads,78        kdim=None,79        vdim=None,80        dropout=0.0,81        bias=True,82        add_bias_kv: bool = False,83        add_zero_attn: bool = False,84        self_attention: bool = False,85        encoder_decoder_attention: bool = False,86        use_rotary_embeddings: bool = False,87    ):88        super().__init__()89        self.embed_dim = embed_dim90        self.kdim = kdim if kdim is not None else embed_dim91        self.vdim = vdim if vdim is not None else embed_dim92        self.qkv_same_dim = self.kdim == embed_dim and self.vdim == embed_dim93 94        self.num_heads = num_heads95        self.dropout = dropout96        self.head_dim = embed_dim // num_heads97        assert (98            self.head_dim * num_heads == self.embed_dim99        ), "embed_dim must be divisible by num_heads"100        self.scaling = self.head_dim**-0.5101 102        self.self_attention = self_attention103        self.encoder_decoder_attention = encoder_decoder_attention104 105        assert not self.self_attention or self.qkv_same_dim, (106            "Self-attention requires query, key and " "value to be of the same size"107        )108 109        self.k_proj = nn.Linear(self.kdim, embed_dim, bias=bias)110        self.v_proj = nn.Linear(self.vdim, embed_dim, bias=bias)111        self.q_proj = nn.Linear(embed_dim, embed_dim, bias=bias)112 113        self.out_proj = nn.Linear(embed_dim, embed_dim, bias=bias)114 115        if add_bias_kv:116            self.bias_k = Parameter(torch.Tensor(1, 1, embed_dim))117            self.bias_v = Parameter(torch.Tensor(1, 1, embed_dim))118        else:119            self.bias_k = self.bias_v = None120 121        self.add_zero_attn = add_zero_attn122 123        self.reset_parameters()124 125        self.onnx_trace = False126        self.rot_emb = None127        if use_rotary_embeddings:128            self.rot_emb = RotaryEmbedding(dim=self.head_dim)129 130        self.enable_torch_version = False131        if hasattr(F, "multi_head_attention_forward"):132            self.enable_torch_version = True133        else:134            self.enable_torch_version = False135 136    def prepare_for_onnx_export_(self):137        self.onnx_trace = True138 139    def reset_parameters(self):140        if self.qkv_same_dim:141            # Empirically observed the convergence to be much better with142            # the scaled initialization143            nn.init.xavier_uniform_(self.k_proj.weight, gain=1 / math.sqrt(2))144            nn.init.xavier_uniform_(self.v_proj.weight, gain=1 / math.sqrt(2))145            nn.init.xavier_uniform_(self.q_proj.weight, gain=1 / math.sqrt(2))146        else:147            nn.init.xavier_uniform_(self.k_proj.weight)148            nn.init.xavier_uniform_(self.v_proj.weight)149            nn.init.xavier_uniform_(self.q_proj.weight)150 151        nn.init.xavier_uniform_(self.out_proj.weight)152        if self.out_proj.bias is not None:153            nn.init.constant_(self.out_proj.bias, 0.0)154        if self.bias_k is not None:155            nn.init.xavier_normal_(self.bias_k)156        if self.bias_v is not None:157            nn.init.xavier_normal_(self.bias_v)158 159    def forward(160        self,161        query,162        key: Optional[Tensor],163        value: Optional[Tensor],164        key_padding_mask: Optional[Tensor] = None,165        incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]] = None,166        need_weights: bool = True,167        static_kv: bool = False,168        attn_mask: Optional[Tensor] = None,169        before_softmax: bool = False,170        need_head_weights: bool = False,171    ) -> Tuple[Tensor, Optional[Tensor]]:172        """Input shape: Time x Batch x Channel173 174        Args:175            key_padding_mask (ByteTensor, optional): mask to exclude176                keys that are pads, of shape `(batch, src_len)`, where177                padding elements are indicated by 1s.178            need_weights (bool, optional): return the attention weights,179                averaged over heads (default: False).180            attn_mask (ByteTensor, optional): typically used to181                implement causal attention, where the mask prevents the182                attention from looking forward in time (default: None).183            before_softmax (bool, optional): return the raw attention184                weights and values before the attention softmax.185            need_head_weights (bool, optional): return the attention186                weights for each head. Implies *need_weights*. Default:187                return the average attention weights over all heads.188        """189        if need_head_weights:190            need_weights = True191 192        tgt_len, bsz, embed_dim = query.size()193        assert embed_dim == self.embed_dim194        assert list(query.size()) == [tgt_len, bsz, embed_dim]195 196        if (197            not self.rot_emb198            and self.enable_torch_version199            and not self.onnx_trace200            and incremental_state is None201            and not static_kv202            # A workaround for quantization to work. Otherwise JIT compilation203            # treats bias in linear module as method.204            and not torch.jit.is_scripting()205            and not need_head_weights206        ):207            assert key is not None and value is not None208            return F.multi_head_attention_forward(209                query,210                key,211                value,212                self.embed_dim,213                self.num_heads,214                torch.empty([0]),215                torch.cat((self.q_proj.bias, self.k_proj.bias, self.v_proj.bias)),216                self.bias_k,217                self.bias_v,218                self.add_zero_attn,219                self.dropout,220                self.out_proj.weight,221                self.out_proj.bias,222                self.training,223                key_padding_mask,224                need_weights,225                attn_mask,226                use_separate_proj_weight=True,227                q_proj_weight=self.q_proj.weight,228                k_proj_weight=self.k_proj.weight,229                v_proj_weight=self.v_proj.weight,230            )231        if incremental_state is not None:232            saved_state = self._get_input_buffer(incremental_state)233            if saved_state is not None and "prev_key" in saved_state:234                # previous time steps are cached - no need to recompute235                # key and value if they are static236                if static_kv:237                    assert self.encoder_decoder_attention and not self.self_attention238                    key = value = None239        else:240            saved_state = None241 242        if self.self_attention:243            q = self.q_proj(query)244            k = self.k_proj(query)245            v = self.v_proj(query)246        elif self.encoder_decoder_attention:247            # encoder-decoder attention248            q = self.q_proj(query)249            if key is None:250                assert value is None251                k = v = None252            else:253                k = self.k_proj(key)254                v = self.v_proj(key)255 256        else:257            assert key is not None and value is not None258            q = self.q_proj(query)259            k = self.k_proj(key)260            v = self.v_proj(value)261        q *= self.scaling262 263        if self.bias_k is not None:264            assert self.bias_v is not None265            k = torch.cat([k, self.bias_k.repeat(1, bsz, 1)])266            v = torch.cat([v, self.bias_v.repeat(1, bsz, 1)])267            if attn_mask is not None:268                attn_mask = torch.cat(269                    [attn_mask, attn_mask.new_zeros(attn_mask.size(0), 1)], dim=1270                )271            if key_padding_mask is not None:272                key_padding_mask = torch.cat(273                    [274                        key_padding_mask,275                        key_padding_mask.new_zeros(key_padding_mask.size(0), 1),276                    ],277                    dim=1,278                )279 280        q = q.contiguous().view(tgt_len, bsz * self.num_heads, self.head_dim).transpose(0, 1)281        if k is not None:282            k = k.contiguous().view(-1, bsz * self.num_heads, self.head_dim).transpose(0, 1)283        if v is not None:284            v = v.contiguous().view(-1, bsz * self.num_heads, self.head_dim).transpose(0, 1)285 286        if saved_state is not None:287            # saved states are stored with shape (bsz, num_heads, seq_len, head_dim)288            if "prev_key" in saved_state:289                _prev_key = saved_state["prev_key"]290                assert _prev_key is not None291                prev_key = _prev_key.view(bsz * self.num_heads, -1, self.head_dim)292                if static_kv:293                    k = prev_key294                else:295                    assert k is not None296                    k = torch.cat([prev_key, k], dim=1)297            if "prev_value" in saved_state:298                _prev_value = saved_state["prev_value"]299                assert _prev_value is not None300                prev_value = _prev_value.view(bsz * self.num_heads, -1, self.head_dim)301                if static_kv:302                    v = prev_value303                else:304                    assert v is not None305                    v = torch.cat([prev_value, v], dim=1)306            prev_key_padding_mask: Optional[Tensor] = None307            if "prev_key_padding_mask" in saved_state:308                prev_key_padding_mask = saved_state["prev_key_padding_mask"]309            assert k is not None and v is not None310            key_padding_mask = MultiheadAttention._append_prev_key_padding_mask(311                key_padding_mask=key_padding_mask,312                prev_key_padding_mask=prev_key_padding_mask,313                batch_size=bsz,314                src_len=k.size(1),315                static_kv=static_kv,316            )317 318            saved_state["prev_key"] = k.view(bsz, self.num_heads, -1, self.head_dim)319            saved_state["prev_value"] = v.view(bsz, self.num_heads, -1, self.head_dim)320            saved_state["prev_key_padding_mask"] = key_padding_mask321            # In this branch incremental_state is never None322            assert incremental_state is not None323            incremental_state = self._set_input_buffer(incremental_state, saved_state)324        assert k is not None325        src_len = k.size(1)326 327        # This is part of a workaround to get around fork/join parallelism328        # not supporting Optional types.329        if key_padding_mask is not None and key_padding_mask.dim() == 0:330            key_padding_mask = None331 332        if key_padding_mask is not None:333            assert key_padding_mask.size(0) == bsz334            assert key_padding_mask.size(1) == src_len335 336        if self.add_zero_attn:337            assert v is not None338            src_len += 1339            k = torch.cat([k, k.new_zeros((k.size(0), 1) + k.size()[2:])], dim=1)340            v = torch.cat([v, v.new_zeros((v.size(0), 1) + v.size()[2:])], dim=1)341            if attn_mask is not None:342                attn_mask = torch.cat(343                    [attn_mask, attn_mask.new_zeros(attn_mask.size(0), 1)], dim=1344                )345            if key_padding_mask is not None:346                key_padding_mask = torch.cat(347                    [348                        key_padding_mask,349                        torch.zeros(key_padding_mask.size(0), 1).type_as(key_padding_mask),350                    ],351                    dim=1,352                )353 354        if self.rot_emb:355            q, k = self.rot_emb(q, k)356 357        attn_weights = torch.bmm(q, k.transpose(1, 2))358        attn_weights = MultiheadAttention.apply_sparse_mask(attn_weights, tgt_len, src_len, bsz)359 360        assert list(attn_weights.size()) == [bsz * self.num_heads, tgt_len, src_len]361 362        if attn_mask is not None:363            attn_mask = attn_mask.unsqueeze(0)364            if self.onnx_trace:365                attn_mask = attn_mask.repeat(attn_weights.size(0), 1, 1)366            attn_weights += attn_mask367 368        if key_padding_mask is not None:369            # don't attend to padding symbols370            attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, src_len)371            attn_weights = attn_weights.masked_fill(372                key_padding_mask.unsqueeze(1).unsqueeze(2).to(torch.bool), float("-inf")373            )374            attn_weights = attn_weights.view(bsz * self.num_heads, tgt_len, src_len)375 376        if before_softmax:377            return attn_weights, v378 379        attn_weights_float = utils_softmax(attn_weights, dim=-1, onnx_trace=self.onnx_trace)380        attn_weights = attn_weights_float.type_as(attn_weights)381        attn_probs = F.dropout(382            attn_weights_float.type_as(attn_weights),383            p=self.dropout,384            training=self.training,385        )386        assert v is not None387        attn = torch.bmm(attn_probs, v)388        assert list(attn.size()) == [bsz * self.num_heads, tgt_len, self.head_dim]389        if self.onnx_trace and attn.size(1) == 1:390            # when ONNX tracing a single decoder step (sequence length == 1)391            # the transpose is a no-op copy before view, thus unnecessary392            attn = attn.contiguous().view(tgt_len, bsz, embed_dim)393        else:394            attn = attn.transpose(0, 1).contiguous().view(tgt_len, bsz, embed_dim)395        attn = self.out_proj(attn)396        attn_weights: Optional[Tensor] = None397        if need_weights:398            attn_weights = attn_weights_float.view(399                bsz, self.num_heads, tgt_len, src_len400            ).type_as(attn).transpose(1, 0)401            if not need_head_weights:402                # average attention weights over heads403                attn_weights = attn_weights.mean(dim=0)404 405        return attn, attn_weights406 407    @staticmethod408    def _append_prev_key_padding_mask(409        key_padding_mask: Optional[Tensor],410        prev_key_padding_mask: Optional[Tensor],411        batch_size: int,412        src_len: int,413        static_kv: bool,414    ) -> Optional[Tensor]:415        # saved key padding masks have shape (bsz, seq_len)416        if prev_key_padding_mask is not None and static_kv:417            new_key_padding_mask = prev_key_padding_mask418        elif prev_key_padding_mask is not None and key_padding_mask is not None:419            new_key_padding_mask = torch.cat(420                [prev_key_padding_mask.float(), key_padding_mask.float()], dim=1421            )422        # During incremental decoding, as the padding token enters and423        # leaves the frame, there will be a time when prev or current424        # is None425        elif prev_key_padding_mask is not None:426            filler = torch.zeros(427                (batch_size, src_len - prev_key_padding_mask.size(1)),428                device=prev_key_padding_mask.device,429            )430            new_key_padding_mask = torch.cat(431                [prev_key_padding_mask.float(), filler.float()], dim=1432            )433        elif key_padding_mask is not None:434            filler = torch.zeros(435                (batch_size, src_len - key_padding_mask.size(1)),436                device=key_padding_mask.device,437            )438            new_key_padding_mask = torch.cat([filler.float(), key_padding_mask.float()], dim=1)439        else:440            new_key_padding_mask = prev_key_padding_mask441        return new_key_padding_mask442 443    @torch.jit.export444    def reorder_incremental_state(445        self, incremental_state: Dict[str, Dict[str, Optional[Tensor]]], new_order: Tensor446    ):447        """Reorder buffered internal state (for incremental generation)."""448        input_buffer = self._get_input_buffer(incremental_state)449        if input_buffer is not None:450            for k in input_buffer.keys():451                input_buffer_k = input_buffer[k]452                if input_buffer_k is not None:453                    if self.encoder_decoder_attention and input_buffer_k.size(0) == new_order.size(454                        0455                    ):456                        break457                    input_buffer[k] = input_buffer_k.index_select(0, new_order)458            incremental_state = self._set_input_buffer(incremental_state, input_buffer)459        return incremental_state460 461    def _get_input_buffer(462        self, incremental_state: Optional[Dict[str, Dict[str, Optional[Tensor]]]]463    ) -> Dict[str, Optional[Tensor]]:464        result = self.get_incremental_state(incremental_state, "attn_state")465        if result is not None:466            return result467        else:468            empty_result: Dict[str, Optional[Tensor]] = {}469            return empty_result470 471    def _set_input_buffer(472        self,473        incremental_state: Dict[str, Dict[str, Optional[Tensor]]],474        buffer: Dict[str, Optional[Tensor]],475    ):476        return self.set_incremental_state(incremental_state, "attn_state", buffer)477 478    def apply_sparse_mask(attn_weights, tgt_len: int, src_len: int, bsz: int):479        return attn_weights480 481    def upgrade_state_dict_named(self, state_dict, name):482        prefix = name + "." if name != "" else ""483        items_to_add = {}484        keys_to_remove = []485        for k in state_dict.keys():486            if k.endswith(prefix + "in_proj_weight"):487                # in_proj_weight used to be q + k + v with same dimensions488                dim = int(state_dict[k].shape[0] / 3)489                items_to_add[prefix + "q_proj.weight"] = state_dict[k][:dim]490                items_to_add[prefix + "k_proj.weight"] = state_dict[k][dim : 2 * dim]491                items_to_add[prefix + "v_proj.weight"] = state_dict[k][2 * dim :]492 493                keys_to_remove.append(k)494 495                k_bias = prefix + "in_proj_bias"496                if k_bias in state_dict.keys():497                    dim = int(state_dict[k].shape[0] / 3)498                    items_to_add[prefix + "q_proj.bias"] = state_dict[k_bias][:dim]499                    items_to_add[prefix + "k_proj.bias"] = state_dict[k_bias][dim : 2 * dim]500                    items_to_add[prefix + "v_proj.bias"] = state_dict[k_bias][2 * dim :]501 502                    keys_to_remove.append(prefix + "in_proj_bias")503 504        for k in keys_to_remove:505            del state_dict[k]506 507        for key, value in items_to_add.items():508            state_dict[key] = value509