m24842-ml 0.1.25__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: m24842_ml
3
+ Version: 0.1.25
4
+ Requires-Python: >=3.8
5
+ Requires-Dist: torch
6
+ Requires-Dist: einops
7
+ Requires-Dist: opt_einsum
8
+ Requires-Dist: rotary_embedding_torch
9
+ Requires-Dist: wandb
10
+ Requires-Dist: pyyaml
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: m24842_ml
3
+ Version: 0.1.25
4
+ Requires-Python: >=3.8
5
+ Requires-Dist: torch
6
+ Requires-Dist: einops
7
+ Requires-Dist: opt_einsum
8
+ Requires-Dist: rotary_embedding_torch
9
+ Requires-Dist: wandb
10
+ Requires-Dist: pyyaml
@@ -0,0 +1,13 @@
1
+ pyproject.toml
2
+ m24842_ml.egg-info/PKG-INFO
3
+ m24842_ml.egg-info/SOURCES.txt
4
+ m24842_ml.egg-info/dependency_links.txt
5
+ m24842_ml.egg-info/requires.txt
6
+ m24842_ml.egg-info/top_level.txt
7
+ ml/__init__.py
8
+ ml/attention.py
9
+ ml/datasets.py
10
+ ml/schedulers.py
11
+ ml/train.py
12
+ ml/transformers.py
13
+ ml/utils.py
@@ -0,0 +1,6 @@
1
+ torch
2
+ einops
3
+ opt_einsum
4
+ rotary_embedding_torch
5
+ wandb
6
+ pyyaml
File without changes
@@ -0,0 +1,427 @@
1
+ import torch
2
+ import torch.nn as nn
3
+ import torch.nn.functional as F
4
+ import torch.linalg as LA
5
+ import torch.autograd as AG
6
+ import math
7
+ from einops import rearrange
8
+ import opt_einsum
9
+ from typing import Optional
10
+ from rotary_embedding_torch import RotaryEmbedding
11
+
12
+ class MultiheadAttention(nn.Module):
13
+ """
14
+ Vanilla Multihead Attention.
15
+ Slight difference: the typical 1/sqrt(d_model) attention score scale is now a per head learnable parameter beta initialized at 1/sqrt(d_model).
16
+ """
17
+ def __init__(self, d_model, n_heads, dropout=0.0, bias=True, add_bias_kv=False,
18
+ add_zero_attn=False, batch_first=False):
19
+ super().__init__()
20
+ self.d_model = d_model
21
+ self.n_heads = n_heads
22
+ self.dropout = dropout
23
+ self.batch_first = batch_first
24
+ self.d_head = d_model // n_heads
25
+
26
+ assert self.d_head * n_heads == self.d_model, "d_model must be divisible by n_heads"
27
+
28
+ # Linear projections for query, key, and value
29
+ self.beta = nn.Parameter(torch.zeros(self.n_heads))
30
+ self.beta._no_weight_decay = True
31
+ self.q_proj = nn.Linear(d_model, d_model, bias=bias)
32
+ self.k_proj = nn.Linear(d_model, d_model, bias=bias)
33
+ self.v_proj = nn.Linear(d_model, d_model, bias=bias)
34
+ self.out_proj = nn.Linear(d_model, d_model, bias=bias)
35
+
36
+ # Optional bias for key and value
37
+ if add_bias_kv:
38
+ self.bias_k = nn.Parameter(torch.empty(1, 1, d_model))
39
+ self.bias_v = nn.Parameter(torch.empty(1, 1, d_model))
40
+ else:
41
+ self.bias_k = self.bias_v = None
42
+
43
+ self.add_zero_attn = add_zero_attn
44
+
45
+ self._reset_parameters()
46
+
47
+ def _reset_parameters(self):
48
+ # Initialize projections using Xavier uniform
49
+ nn.init.constant_(self.beta, 0.)
50
+ nn.init.xavier_uniform_(self.q_proj.weight)
51
+ nn.init.xavier_uniform_(self.k_proj.weight)
52
+ nn.init.xavier_uniform_(self.v_proj.weight)
53
+ nn.init.xavier_uniform_(self.out_proj.weight)
54
+
55
+ if self.out_proj.bias is not None:
56
+ nn.init.constant_(self.out_proj.bias, 0.)
57
+
58
+ if self.bias_k is not None:
59
+ nn.init.xavier_normal_(self.bias_k)
60
+ if self.bias_v is not None:
61
+ nn.init.xavier_normal_(self.bias_v)
62
+
63
+ def forward(self, x, key_padding_mask=None, need_weights=True,
64
+ attn_mask=None, average_attn_weights=True, rope=None):
65
+ """
66
+ Forward pass for the MultiheadAttention module.
67
+
68
+ Args:
69
+ query: Query embeddings of shape (seq_len_q, batch_size, d_model) or
70
+ (batch_size, seq_len_q, d_model) if batch_first=True
71
+ key: Key embeddings of shape (seq_len_k, batch_size, d_model) or
72
+ (batch_size, seq_len_k, d_model) if batch_first=True
73
+ value: Value embeddings of shape (seq_len_v, batch_size, d_model) or
74
+ (batch_size, seq_len_v, d_model) if batch_first=True
75
+ key_padding_mask: If provided, specified padding elements in the key will
76
+ be ignored by the attention. Shape: (batch_size, seq_len_k)
77
+ need_weights: If True, returns attention weights in addition to attention output
78
+ attn_mask: 2D or 3D mask that prevents attention to certain positions
79
+ average_attn_weights: If True, returns averaged attention weights over heads
80
+
81
+ Returns:
82
+ attn_output: Attention output of shape (seq_len_q, batch_size, d_model) or
83
+ (batch_size, seq_len_q, d_model) if batch_first=True
84
+ attn_output_weights: Attention weights of shape (batch_size, seq_len_q, seq_len_k)
85
+ if need_weights=True, otherwise None
86
+ """
87
+ # Handle batch_first option
88
+ if self.batch_first:
89
+ x = x.transpose(0, 1)
90
+
91
+ tgt_len, bsz, d_model = x.shape
92
+ src_len = x.shape[0]
93
+
94
+ # Apply linear projections
95
+ q = self.q_proj(x) # (tgt_len, batch_size, d_model)
96
+ k = self.k_proj(x) # (src_len, batch_size, d_model)
97
+ v = self.v_proj(x) # (src_len, batch_size, d_model)
98
+
99
+ # Handle bias for key and value if present
100
+ if self.bias_k is not None and self.bias_v is not None:
101
+ k = torch.cat([k, self.bias_k.repeat(1, bsz, 1)])
102
+ v = torch.cat([v, self.bias_v.repeat(1, bsz, 1)])
103
+ if attn_mask is not None:
104
+ attn_mask = F.pad(attn_mask, (0, 1))
105
+ if key_padding_mask is not None:
106
+ key_padding_mask = F.pad(key_padding_mask, (0, 1))
107
+ src_len += 1
108
+
109
+ # Add zero attention if requested
110
+ if self.add_zero_attn:
111
+ src_len += 1
112
+ k = torch.cat([k, torch.zeros((1, bsz, d_model), dtype=k.dtype, device=k.device)], d_model=0)
113
+ v = torch.cat([v, torch.zeros((1, bsz, d_model), dtype=v.dtype, device=v.device)], d_model=0)
114
+ if attn_mask is not None:
115
+ attn_mask = F.pad(attn_mask, (0, 1))
116
+ if key_padding_mask is not None:
117
+ key_padding_mask = F.pad(key_padding_mask, (0, 1))
118
+
119
+ # Reshape q, k, v for multi-head attention
120
+ q = q.contiguous().view(tgt_len, bsz * self.n_heads, self.d_head).transpose(0, 1)
121
+ k = k.contiguous().view(src_len, bsz * self.n_heads, self.d_head).transpose(0, 1)
122
+ v = v.contiguous().view(src_len, bsz * self.n_heads, self.d_head).transpose(0, 1)
123
+
124
+ if rope:
125
+ q = rope.rotate_queries_or_keys(q.reshape(bsz, self.n_heads, tgt_len, self.d_head)).reshape(bsz * self.n_heads, tgt_len, self.d_head)
126
+ k = rope.rotate_queries_or_keys(k.reshape(bsz, self.n_heads, src_len, self.d_head)).reshape(bsz * self.n_heads, src_len, self.d_head)
127
+
128
+ # Calculate attention scores
129
+ q = q / (math.sqrt(self.d_head) * torch.exp(self.beta).reshape(self.n_heads, 1, 1).repeat(bsz, 1, 1))
130
+ attn_output_weights = torch.bmm(q, k.transpose(1, 2)) # (bsz * n_heads, tgt_len, src_len)
131
+
132
+ # Apply attention mask if provided
133
+ if attn_mask is not None:
134
+ if attn_mask.dim() == 2:
135
+ attn_mask = attn_mask.unsqueeze(0)
136
+ elif attn_mask.dim() == 3:
137
+ attn_mask = attn_mask.repeat(self.n_heads, 1, 1)
138
+ attn_output_weights = attn_output_weights + attn_mask
139
+
140
+ # Apply key padding mask if provided
141
+ if key_padding_mask is not None:
142
+ attn_output_weights = attn_output_weights.view(bsz, self.n_heads, tgt_len, src_len)
143
+ attn_output_weights = attn_output_weights.masked_fill(
144
+ key_padding_mask.unsqueeze(1).unsqueeze(2),
145
+ float('-inf'),
146
+ )
147
+ attn_output_weights = attn_output_weights.view(bsz * self.n_heads, tgt_len, src_len)
148
+
149
+ # Convert attention weights to probabilities
150
+ attn_output_weights = F.softmax(attn_output_weights, dim=-1)
151
+ attn_output_weights = F.dropout(attn_output_weights, p=self.dropout, training=self.training)
152
+
153
+ # Apply attention weights to values
154
+ attn_output = torch.bmm(attn_output_weights, v) # (bsz * n_heads, tgt_len, d_head)
155
+
156
+ # Reshape output
157
+ attn_output = attn_output.transpose(0, 1).contiguous().view(tgt_len, bsz, d_model)
158
+ attn_output = self.out_proj(attn_output)
159
+
160
+ # Process attention weights if needed
161
+ if need_weights:
162
+ attn_output_weights = attn_output_weights.view(bsz, self.n_heads, tgt_len, src_len)
163
+ if average_attn_weights:
164
+ attn_output_weights = attn_output_weights.mean(dim=1)
165
+ else:
166
+ attn_output_weights = None
167
+
168
+ # Return in the correct format depending on batch_first
169
+ if self.batch_first:
170
+ return attn_output.transpose(0, 1), attn_output_weights
171
+ return attn_output, attn_output_weights
172
+
173
+ class LinearAttention(nn.Module):
174
+ """
175
+ Vanilla Linear Attention.
176
+ Kernel function is elu + 1.
177
+ """
178
+ def __init__(self, d_model, n_heads, bias=True):
179
+ super().__init__()
180
+ self.d_model = d_model
181
+ self.n_heads = n_heads
182
+ self.d_head = d_model // n_heads
183
+ self.q_proj = nn.Linear(d_model, d_model, bias=bias)
184
+ self.k_proj = nn.Linear(d_model, d_model, bias=bias)
185
+ self.v_proj = nn.Linear(d_model, d_model, bias=bias)
186
+ self.out_proj = nn.Linear(d_model, d_model, bias=bias)
187
+
188
+ self._reset_parameters()
189
+
190
+ def _reset_parameters(self):
191
+ nn.init.xavier_uniform_(self.q_proj.weight)
192
+ nn.init.xavier_uniform_(self.k_proj.weight)
193
+ nn.init.xavier_uniform_(self.v_proj.weight)
194
+ nn.init.xavier_uniform_(self.out_proj.weight)
195
+
196
+ if self.q_proj.bias is not None:
197
+ nn.init.constant_(self.q_proj.bias, 0.)
198
+ if self.k_proj.bias is not None:
199
+ nn.init.constant_(self.k_proj.bias, 0.)
200
+ if self.v_proj.bias is not None:
201
+ nn.init.constant_(self.v_proj.bias, 0.)
202
+ if self.out_proj.bias is not None:
203
+ nn.init.constant_(self.out_proj.bias, 0.)
204
+
205
+ def forward(self, x, rope=None, causal=True):
206
+ bsz, seq_len, d_model = x.size()
207
+ q = rearrange(self.q_proj(x), 'b s (h d) -> b h s d', h=self.n_heads)
208
+ k = rearrange(self.k_proj(x), 'b s (h d) -> b h s d', h=self.n_heads)
209
+ v = rearrange(self.v_proj(x), 'b s (h d) -> (b h) s d', h=self.n_heads).contiguous()
210
+
211
+ if rope:
212
+ q = rope.rotate_queries_or_keys(q).reshape(bsz*self.n_heads, seq_len, self.d_head).contiguous()
213
+ k = rope.rotate_queries_or_keys(k).reshape(bsz*self.n_heads, seq_len, self.d_head).contiguous()
214
+
215
+ # q = torch.exp(q)
216
+ # k = torch.exp(k)
217
+ q = F.elu(q) + 1
218
+ k = F.elu(k) + 1
219
+
220
+ if causal:
221
+ kv = torch.cumsum(torch.matmul(k.unsqueeze(-1), v.unsqueeze(-2)), dim=1)
222
+ k1 = torch.cumsum(k, dim=1)
223
+ else:
224
+ kv = torch.einsum('zsD, zsd -> zDd', k, v).unsqueeze(1)
225
+ k1 = k.sum(dim=1, keepdim=True)
226
+ out = torch.matmul(q.unsqueeze(-2), kv).squeeze(-2) / (q*k1).sum(-1, keepdim=True)
227
+
228
+ out = rearrange(out, '(b h) s d -> b s (h d)', h=self.n_heads)
229
+ return self.out_proj(out)
230
+
231
+ class OrthoLinearAttention(nn.Module):
232
+ """
233
+ Orthogonal Linear Attention.
234
+ A derivative of linear attention that orthogonalizes queries and keys for each head to reduce crossterm interference.
235
+ """
236
+ def __init__(self, d_model: int, n_heads: int, bias: bool = True):
237
+ super().__init__()
238
+ self.d_model = d_model
239
+ self.n_heads = n_heads
240
+ self.d_head = d_model // n_heads
241
+
242
+ self.beta = nn.Parameter(torch.zeros(self.n_heads))
243
+ self.beta._no_weight_decay = True
244
+ self.q_proj = nn.Linear(d_model, d_model, bias=bias)
245
+ self.k_proj = nn.Linear(d_model, d_model, bias=bias)
246
+ self.v_proj = nn.Linear(d_model, d_model, bias=bias)
247
+ self.out_proj = nn.Linear(d_model, d_model, bias=bias)
248
+
249
+ self._reset_parameters()
250
+
251
+ def _reset_parameters(self):
252
+ nn.init.constant_(self.beta, 0.)
253
+ nn.init.xavier_uniform_(self.q_proj.weight)
254
+ nn.init.xavier_uniform_(self.k_proj.weight)
255
+ nn.init.xavier_uniform_(self.v_proj.weight)
256
+ nn.init.xavier_uniform_(self.out_proj.weight)
257
+
258
+ if self.q_proj.bias is not None:
259
+ nn.init.constant_(self.q_proj.bias, 0.)
260
+ if self.k_proj.bias is not None:
261
+ nn.init.constant_(self.k_proj.bias, 0.)
262
+ if self.v_proj.bias is not None:
263
+ nn.init.constant_(self.v_proj.bias, 0.)
264
+ if self.out_proj.bias is not None:
265
+ nn.init.constant_(self.out_proj.bias, 0.)
266
+
267
+ def forward(self, x: torch.Tensor, rope: Optional[RotaryEmbedding] = None, causal: bool = True) -> torch.Tensor:
268
+ """
269
+ Args:
270
+ x (torch.Tensor): Input sequence of shape (batch_size, seq_len, d_model).
271
+ rope (Optional[RotaryEmbedding]): Optional RoPE encoder for rotating queries and keys.
272
+
273
+ Returns:
274
+ torch.Tensor: Output sequence of shape (batch_size, seq_len, d_model).
275
+ """
276
+ bsz, seq_len, d_model = x.size()
277
+ q = rearrange(self.q_proj(x), 'b s (h d) -> b h s d', h=self.n_heads)
278
+ k = rearrange(self.k_proj(x), 'b s (h d) -> b h s d', h=self.n_heads)
279
+ v = rearrange(self.v_proj(x), 'b s (h d) -> (b h) s d', h=self.n_heads).contiguous()
280
+
281
+ if rope:
282
+ q = rope.rotate_queries_or_keys(q).reshape(bsz * self.n_heads, seq_len, self.d_head).contiguous()
283
+ k = rope.rotate_queries_or_keys(k).reshape(bsz * self.n_heads, seq_len, self.d_head).contiguous()
284
+ else:
285
+ q = q.reshape(bsz * self.n_heads, seq_len, self.d_head).contiguous()
286
+ k = k.reshape(bsz * self.n_heads, seq_len, self.d_head).contiguous()
287
+
288
+ beta = torch.exp(self.beta).reshape(self.n_heads, 1, 1).repeat(bsz, 1, 1)
289
+ q = (beta * q).softmax(-1)# * q.norm(dim=-1, keepdim=True)
290
+ k = (beta * k).softmax(-1)# * k.norm(dim=-1, keepdim=True)
291
+
292
+ if causal:
293
+ kv = torch.cumsum(torch.matmul(k.unsqueeze(-1), v.unsqueeze(-2)), dim=1)
294
+ kn = torch.cumsum(k, dim=1)
295
+ else:
296
+ kv = torch.einsum('zsD, zsd -> zDd', k, v).unsqueeze(1)
297
+ kn = k.sum(1, keepdim=True)
298
+
299
+ out = torch.matmul(q.unsqueeze(-2), kv).squeeze(-2) / (q * kn).sum(-1, keepdim=True)
300
+ out = rearrange(out, '(b h) s d -> b s (h d)', h=self.n_heads)
301
+ return self.out_proj(out)
302
+
303
+ class CompressionAttention(nn.Module):
304
+ """
305
+ Compression Attention.
306
+ A derivative of softmax attention that compresses input sequences to a fixed length before expanding back to the original length.
307
+ Achieved by two linear with sequence length attention operations.
308
+ """
309
+ def __init__(self, d_model, n_heads, mlp_dim, compressed_len, dropout=0.0, bias=True, batch_first=False):
310
+ super().__init__()
311
+ self.d_model = d_model
312
+ self.n_heads = n_heads
313
+ self.mlp_dim = mlp_dim
314
+ self.d_head = d_model // n_heads
315
+ self.compressed_len = compressed_len
316
+ self.batch_first = batch_first
317
+ self.dropout = dropout
318
+
319
+ self.q_c = nn.Parameter(torch.empty(compressed_len, d_model))
320
+ self.q_c._no_weight_decay = True
321
+ self.beta = nn.Parameter(torch.zeros(self.n_heads))
322
+ self.beta._no_weight_decay = True
323
+ self.q_proj = nn.Linear(d_model, d_model, bias=bias)
324
+ self.k_proj = nn.Linear(d_model, d_model, bias=bias)
325
+ self.v_proj = nn.Linear(d_model, d_model, bias=bias)
326
+ self.out_proj = nn.Linear(d_model, d_model, bias=bias)
327
+
328
+ self._reset_parameters()
329
+
330
+ def _reset_parameters(self):
331
+ # Initialize projections using Xavier uniform
332
+ nn.init.constant_(self.beta, 0.)
333
+ nn.init.xavier_uniform_(self.q_c)
334
+ nn.init.xavier_uniform_(self.q_proj.weight)
335
+ nn.init.xavier_uniform_(self.k_proj.weight)
336
+ nn.init.xavier_uniform_(self.v_proj.weight)
337
+ nn.init.xavier_uniform_(self.out_proj.weight)
338
+
339
+ if self.q_proj.bias is not None:
340
+ nn.init.constant_(self.q_proj.bias, 0.)
341
+ if self.k_proj.bias is not None:
342
+ nn.init.constant_(self.k_proj.bias, 0.)
343
+ if self.v_proj.bias is not None:
344
+ nn.init.constant_(self.v_proj.bias, 0.)
345
+ if self.out_proj.bias is not None:
346
+ nn.init.constant_(self.out_proj.bias, 0.)
347
+
348
+ def forward(self, x, rope=None, causal=True):
349
+ # Handle batch_first option
350
+ if self.batch_first:
351
+ x = x.transpose(0, 1)
352
+
353
+ cmprs_len = self.compressed_len
354
+ _, bsz, d_model = x.shape
355
+ src_len = x.shape[0]
356
+
357
+ q_c = self.q_c.unsqueeze(1).repeat(1, bsz, 1) # (compressed_len, d_model)
358
+ q_s = self.q_proj(x) # (src_len, batch_size, d_model)
359
+ k_s = self.k_proj(x) # (src_len, batch_size, d_model)
360
+ v_s = self.v_proj(x) # (src_len, batch_size, d_model)
361
+
362
+ # Reshape for multi-head attention
363
+ q_c = rearrange(q_c, 'c b (h d) -> (b h) c d', h=self.n_heads).contiguous()
364
+ q_s = rearrange(q_s, 's b (h d) -> (b h) s d', h=self.n_heads).contiguous()
365
+ k_s = rearrange(k_s, 's b (h d) -> (b h) s d', h=self.n_heads).contiguous()
366
+ v_s = rearrange(v_s, 's b (h d) -> (b h) s d', h=self.n_heads).contiguous()
367
+
368
+ if rope:
369
+ # q_c = rope.rotate_queries_or_keys(q_c.reshape(bsz, self.n_heads, cmprs_len, self.d_head)).reshape(bsz * self.n_heads, cmprs_len, self.d_head)
370
+ q_s = rope.rotate_queries_or_keys(q_s.reshape(bsz, self.n_heads, src_len, self.d_head)).reshape(bsz * self.n_heads, src_len, self.d_head)
371
+ k_s = rope.rotate_queries_or_keys(k_s.reshape(bsz, self.n_heads, src_len, self.d_head)).reshape(bsz * self.n_heads, src_len, self.d_head)
372
+
373
+ kv_s = torch.cat([k_s, v_s], dim=-1) # (bsz * n_heads, src_len, 2*d_head)
374
+
375
+ ### Downward self attention ###
376
+ # q_c = q_c / math.sqrt(self.d_head)
377
+ c_attn_weights = torch.bmm(q_c, k_s.transpose(1, 2)) # (bsz * n_heads, cmprs_len, src_len)
378
+
379
+ if causal:
380
+ # Manually perform softmax with cumulative sum for causal attention
381
+ c_attn_weights = torch.exp(c_attn_weights - torch.max(c_attn_weights, dim=-1, keepdim=True).values) # (bsz * n_heads, cmprs_len, src_len)
382
+ c_attn_norm = torch.cumsum(c_attn_weights, dim=-1) # (bsz * n_heads, cmprs_len, src_len)
383
+ c_attn_weights = F.dropout(c_attn_weights, p=self.dropout, training=self.training)
384
+ else:
385
+ # Convert attention weights to probabilities
386
+ c_attn_weights = F.softmax(c_attn_weights, dim=-1)
387
+ c_attn_weights = F.dropout(c_attn_weights, p=self.dropout, training=self.training)
388
+
389
+ ### Upward self attention ###
390
+ q_s = q_s / (math.sqrt(self.d_head) * torch.exp(self.beta).reshape(self.n_heads, 1, 1).repeat(bsz, 1, 1))
391
+
392
+ if causal:
393
+ # Calculate attention scores for compressed output
394
+ kv_c = torch.cumsum((c_attn_weights.unsqueeze(-1) * kv_s.unsqueeze(1)), dim=2) / c_attn_norm.unsqueeze(-1) # (bsz * n_heads, cmprs_len, 2*d_head)
395
+ k_c, v_c = kv_c.split([self.d_head, self.d_head], dim=-1) # (bsz * n_heads, cmprs_len, src_len, d_head)
396
+ s_attn_weights = torch.einsum('zsd, zcsd -> zsc', q_s, k_c) # (bsz * n_heads, src_len, cmprs_len)
397
+
398
+ # Convert attention weights to probabilities
399
+ s_attn_weights = F.softmax(s_attn_weights, dim=-1)
400
+ s_attn_weights = F.dropout(s_attn_weights, p=self.dropout, training=self.training)
401
+
402
+ # Apply attention weights to values
403
+ s_attn_output = torch.einsum('zsc, zcsd -> zsd', s_attn_weights, v_c) # (bsz * n_heads, src_len, d_head)
404
+ else:
405
+ # Calculate attention scores for compressed output
406
+ kv_c = torch.bmm(c_attn_weights, kv_s) # (bsz * n_heads, cmprs_len, 2*d_head)
407
+ k_c, v_c = kv_c.split([self.d_head, self.d_head], dim=-1) # (bsz * n_heads, cmprs_len, d_head)
408
+ s_attn_weights = torch.bmm(q_s, k_c.transpose(1, 2)) # (bsz * n_heads, src_len, cmprs_len)
409
+
410
+ # Convert attention weights to probabilities
411
+ s_attn_weights = F.softmax(s_attn_weights, dim=-1)
412
+ s_attn_weights = F.dropout(s_attn_weights, p=self.dropout, training=self.training)
413
+
414
+ # Apply attention weights to values
415
+ s_attn_output = torch.bmm(s_attn_weights, v_c) # (bsz * n_heads, src_len, d_head)
416
+
417
+ # Reshape output
418
+ s_attn_output = s_attn_output.transpose(0, 1).contiguous().view(src_len, bsz, d_model)
419
+
420
+ # Apply final projection
421
+ s_attn_output = self.out_proj(s_attn_output)
422
+
423
+ # Return in the correct format depending on batch_first
424
+ if self.batch_first:
425
+ return s_attn_output.transpose(0, 1)
426
+ return s_attn_output
427
+