Multi-head grouped query attention (GQA) layer. Reference: "GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints" https://arxiv.org/pdf/2305.13245v1.pdf GQA is a variant of multihead attention (MHA) that uses fewer write heads (key / valu
| 145 | |
| 146 | |
| 147 | class BitMGQA(nn.Module): |
| 148 | """Multi-head grouped query attention (GQA) layer. |
| 149 | |
| 150 | Reference: |
| 151 | "GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints" |
| 152 | https://arxiv.org/pdf/2305.13245v1.pdf |
| 153 | |
| 154 | GQA is a variant of multihead attention (MHA) that uses fewer write heads |
| 155 | (key / value) than query heads. GQA can be viewed as a generalization of |
| 156 | multi-query attention (MQA), which uses a single write head. GQA and MQA give |
| 157 | significant speedups over standard MHA in decoder layers, with minimal loss in |
| 158 | accuracy. In the paper, GQA is shown to be more accurate than MQA, while still |
| 159 | having a significant speedup over MHA. |
| 160 | |
| 161 | NOTE: The original authors only benchmark GQA by adapting the T5 (XL or XXL) model |
| 162 | from MHA to GQA. As a result, they do not mention parameter initialization or |
| 163 | layer normalization strategies. I follow the best practices laid out in the |
| 164 | MAGNETO paper, which improves Transformer performance through better parameter |
| 165 | initialization and layer norm placement. See: |
| 166 | https://arxiv.org/pdf/2210.06423.pdf, Fig. 2 |
| 167 | """ |
| 168 | |
| 169 | def __init__( |
| 170 | self, |
| 171 | embed_dim: int, |
| 172 | query_heads: int = 8, |
| 173 | kv_heads: int = 4, |
| 174 | dropout: float = 0.1, |
| 175 | bias: bool = True, |
| 176 | layer_norm: bool = True, |
| 177 | layer_norm_eps: float = 1e-5, |
| 178 | gamma_init: float = 1.0, |
| 179 | linear_groups: int = 1, |
| 180 | *args, |
| 181 | **kwargs, |
| 182 | ): |
| 183 | super().__init__() |
| 184 | self.query_heads = query_heads |
| 185 | self.kv_heads = kv_heads |
| 186 | self.dropout = dropout |
| 187 | self.layer_norm = layer_norm |
| 188 | self.gamma_init = gamma_init |
| 189 | |
| 190 | if self.query_heads % self.kv_heads != 0: |
| 191 | raise ValueError( |
| 192 | f"query_heads ({query_heads}) must be divisible by " |
| 193 | f"kv_heads ({kv_heads})" |
| 194 | ) |
| 195 | elif (embed_dim % self.query_heads != 0) or (embed_dim % self.kv_heads != 0): |
| 196 | raise ValueError( |
| 197 | f"embed_dim ({embed_dim}) must be divisible by " |
| 198 | f"query_heads ({query_heads}) and kv_heads ({kv_heads})" |
| 199 | ) |
| 200 | |
| 201 | head_dim = embed_dim // query_heads |
| 202 | if not head_dim % 8 == 0: |
| 203 | raise ValueError( |
| 204 | f"head_dim (embed_dim / num_heads = {head_dim}) must be divisible by 8" |
no outgoing calls
no test coverage detected