PhysiQuanty commited on
Commit
fa7af33
·
verified ·
1 Parent(s): 258db69

Update modeling_binaryllm.py

Browse files
Files changed (1) hide show
  1. modeling_binaryllm.py +402 -8
modeling_binaryllm.py CHANGED
@@ -11,6 +11,13 @@ from transformers.modeling_outputs import CausalLMOutput
11
 
12
  from .configuration_binaryllm import BinaryLLMConfig
13
 
 
 
 
 
 
 
 
14
 
15
  class PositionalEncoding(nn.Module):
16
  """
@@ -23,17 +30,17 @@ class PositionalEncoding(nn.Module):
23
  pe = torch.zeros(max_len, d_model, dtype=torch.float32)
24
  position = torch.arange(0, max_len, dtype=torch.float32).unsqueeze(1)
25
  div_term = torch.exp(
26
- torch.arange(0, d_model, 2, dtype=torch.float32) * (-torch.log(torch.tensor(10000.0)) / d_model)
 
27
  )
28
  pe[:, 0::2] = torch.sin(position * div_term)
29
  pe[:, 1::2] = torch.cos(position * div_term)
30
- pe = pe.unsqueeze(0) # (1, max_len, d_model)
31
  self.register_buffer("pe", pe, persistent=False)
32
 
33
  def forward(self, x: torch.Tensor) -> torch.Tensor:
34
  t = x.size(1)
35
- pe = self.pe[:, :t, :]
36
- pe = pe.to(device=x.device, dtype=x.dtype)
37
  return x + pe
38
 
39
 
@@ -48,6 +55,350 @@ class _InnerCfg:
48
  dropout: float
49
  layernorm_dim: Optional[int] = None
50
  head_dim: Optional[int] = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
 
53
  class TinyTransformerLM(nn.Module):
@@ -59,15 +410,20 @@ class TinyTransformerLM(nn.Module):
59
  self.tok_embed = nn.Embedding(vocab_size, cfg.embed_dim)
60
  self.pos_encoding = PositionalEncoding(cfg.embed_dim, cfg.block_size)
61
 
62
- encoder_layer = nn.TransformerEncoderLayer(
63
  d_model=cfg.embed_dim,
64
  nhead=cfg.num_heads,
65
  dim_feedforward=cfg.ff_hidden_dim,
66
  dropout=cfg.dropout,
67
  activation="gelu",
68
  batch_first=True,
 
 
 
 
 
 
69
  )
70
- self.encoder = nn.TransformerEncoder(encoder_layer, num_layers=cfg.num_layers)
71
 
72
  ln_dim = cfg.layernorm_dim or cfg.embed_dim
73
  head_dim = cfg.head_dim or ln_dim
@@ -84,7 +440,6 @@ class TinyTransformerLM(nn.Module):
84
 
85
  self.head = nn.Linear(head_dim, vocab_size, bias=False)
86
 
87
- # weight tying seulement si parfait alignement
88
  if self.pre_ln_proj is None and self.head_pre is None and head_dim == cfg.embed_dim:
89
  self.head.weight = self.tok_embed.weight
90
 
@@ -104,13 +459,26 @@ class TinyTransformerLM(nn.Module):
104
  x = self.encoder(x, mask=attn_mask, src_key_padding_mask=padding_mask)
105
 
106
  if self.pre_ln_proj is not None:
 
 
 
107
  x = self.pre_ln_proj(x)
108
 
 
 
 
109
  x = self.ln(x)
110
 
111
  if self.head_pre is not None:
 
 
 
112
  x = self.head_pre(x)
113
 
 
 
 
 
114
  return self.head(x)
115
 
116
 
@@ -121,6 +489,8 @@ class BinaryLLMForCausalLM(PreTrainedModel):
121
  def __init__(self, config: BinaryLLMConfig):
122
  super().__init__(config)
123
 
 
 
124
  inner = _InnerCfg(
125
  block_size=int(config.max_position_embeddings),
126
  embed_dim=int(config.hidden_size),
@@ -131,11 +501,35 @@ class BinaryLLMForCausalLM(PreTrainedModel):
131
  dropout=float(getattr(config, "dropout", 0.0)),
132
  layernorm_dim=None,
133
  head_dim=None,
 
134
  )
135
  self.model = TinyTransformerLM(inner)
136
 
137
  self.post_init()
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  def forward(
140
  self,
141
  input_ids: torch.LongTensor,
@@ -145,7 +539,7 @@ class BinaryLLMForCausalLM(PreTrainedModel):
145
  ) -> CausalLMOutput:
146
  padding_mask = None
147
  if attention_mask is not None:
148
- padding_mask = ~attention_mask.to(torch.bool) # True = ignore
149
 
150
  logits = self.model(input_ids, padding_mask=padding_mask)
151
 
 
11
 
12
  from .configuration_binaryllm import BinaryLLMConfig
13
 
14
+ try:
15
+ import flash_attn_v100_cuda
16
+ _FLASH_V100_AVAILABLE = True
17
+ except Exception:
18
+ flash_attn_v100_cuda = None
19
+ _FLASH_V100_AVAILABLE = False
20
+
21
 
22
  class PositionalEncoding(nn.Module):
23
  """
 
30
  pe = torch.zeros(max_len, d_model, dtype=torch.float32)
31
  position = torch.arange(0, max_len, dtype=torch.float32).unsqueeze(1)
32
  div_term = torch.exp(
33
+ torch.arange(0, d_model, 2, dtype=torch.float32)
34
+ * (-torch.log(torch.tensor(10000.0)) / d_model)
35
  )
36
  pe[:, 0::2] = torch.sin(position * div_term)
37
  pe[:, 1::2] = torch.cos(position * div_term)
38
+ pe = pe.unsqueeze(0)
39
  self.register_buffer("pe", pe, persistent=False)
40
 
41
  def forward(self, x: torch.Tensor) -> torch.Tensor:
42
  t = x.size(1)
43
+ pe = self.pe[:, :t, :].to(device=x.device, dtype=x.dtype)
 
44
  return x + pe
45
 
46
 
 
55
  dropout: float
56
  layernorm_dim: Optional[int] = None
57
  head_dim: Optional[int] = None
58
+ attn_backend: str = "auto"
59
+
60
+
61
+ class FlashSelfAttentionPortable(nn.Module):
62
+ def __init__(
63
+ self,
64
+ embed_dim: int,
65
+ num_heads: int,
66
+ dropout: float = 0.0,
67
+ causal: bool = True,
68
+ backend: str = "auto",
69
+ ) -> None:
70
+ super().__init__()
71
+
72
+ if embed_dim % num_heads != 0:
73
+ raise ValueError(
74
+ f"embed_dim ({embed_dim}) doit être divisible par num_heads ({num_heads})"
75
+ )
76
+
77
+ self.embed_dim = embed_dim
78
+ self.num_heads = num_heads
79
+ self.head_dim = embed_dim // num_heads
80
+ self.dropout = float(dropout)
81
+ self.causal = bool(causal)
82
+ self.backend = str(backend)
83
+ self.softmax_scale = self.head_dim ** -0.5
84
+
85
+ self.q_proj = nn.Linear(embed_dim, embed_dim, bias=True)
86
+ self.k_proj = nn.Linear(embed_dim, embed_dim, bias=True)
87
+ self.v_proj = nn.Linear(embed_dim, embed_dim, bias=True)
88
+ self.out_proj = nn.Linear(embed_dim, embed_dim, bias=True)
89
+
90
+ def _shape_qkv(
91
+ self,
92
+ x: torch.Tensor,
93
+ ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.dtype]:
94
+ bsz, seqlen, _ = x.shape
95
+ residual_dtype = x.dtype
96
+
97
+ proj_dtype = self.q_proj.weight.dtype
98
+ if x.dtype != proj_dtype:
99
+ x = x.to(proj_dtype)
100
+
101
+ q = self.q_proj(x)
102
+ k = self.k_proj(x)
103
+ v = self.v_proj(x)
104
+
105
+ q = q.view(bsz, seqlen, self.num_heads, self.head_dim).transpose(1, 2).contiguous()
106
+ k = k.view(bsz, seqlen, self.num_heads, self.head_dim).transpose(1, 2).contiguous()
107
+ v = v.view(bsz, seqlen, self.num_heads, self.head_dim).transpose(1, 2).contiguous()
108
+
109
+ return q, k, v, residual_dtype
110
+
111
+ def _merge_heads(self, x: torch.Tensor) -> torch.Tensor:
112
+ bsz, nheads, seqlen, head_dim = x.shape
113
+ return x.transpose(1, 2).contiguous().view(bsz, seqlen, nheads * head_dim)
114
+
115
+ def _can_use_v100_kernel(self, q: torch.Tensor, padding_mask: Optional[torch.Tensor]) -> bool:
116
+ if not _FLASH_V100_AVAILABLE:
117
+ return False
118
+
119
+ if not q.is_cuda:
120
+ return False
121
+
122
+ if padding_mask is not None and bool(padding_mask.any().item()):
123
+ return False
124
+
125
+ cc = torch.cuda.get_device_capability(q.device)
126
+ if cc != (7, 0):
127
+ return False
128
+
129
+ hd = q.size(-1)
130
+ if hd % 2 != 0:
131
+ return False
132
+ if hd % 8 != 0:
133
+ return False
134
+ if hd > 256:
135
+ return False
136
+
137
+ return True
138
+
139
+ def _flash_attn_v100(
140
+ self,
141
+ q: torch.Tensor,
142
+ k: torch.Tensor,
143
+ v: torch.Tensor,
144
+ ) -> torch.Tensor:
145
+ if q.dtype != torch.float16:
146
+ q = q.to(torch.float16)
147
+ if k.dtype != torch.float16:
148
+ k = k.to(torch.float16)
149
+ if v.dtype != torch.float16:
150
+ v = v.to(torch.float16)
151
+
152
+ result = flash_attn_v100_cuda.fwd(
153
+ q,
154
+ k,
155
+ v,
156
+ None,
157
+ None,
158
+ 0.0,
159
+ self.softmax_scale,
160
+ self.causal,
161
+ -1,
162
+ -1,
163
+ 0.0,
164
+ False,
165
+ None,
166
+ )
167
+
168
+ out = result[0]
169
+ return out
170
+
171
+ def _sdpa_attn(
172
+ self,
173
+ q: torch.Tensor,
174
+ k: torch.Tensor,
175
+ v: torch.Tensor,
176
+ padding_mask: Optional[torch.Tensor] = None,
177
+ ) -> torch.Tensor:
178
+ bsz, nheads, tq, _ = q.shape
179
+ tk = k.size(-2)
180
+
181
+ attn_mask = None
182
+ if padding_mask is not None:
183
+ key_mask = padding_mask[:, None, None, :].to(device=q.device, dtype=torch.bool)
184
+ key_mask = key_mask.expand(bsz, nheads, tq, tk)
185
+ attn_mask = ~key_mask
186
+
187
+ dropout_p = self.dropout if self.training else 0.0
188
+
189
+ with torch.backends.cuda.sdp_kernel(
190
+ enable_flash=True,
191
+ enable_mem_efficient=True,
192
+ enable_math=True,
193
+ ):
194
+ out = F.scaled_dot_product_attention(
195
+ q,
196
+ k,
197
+ v,
198
+ attn_mask=attn_mask,
199
+ dropout_p=dropout_p,
200
+ is_causal=self.causal if attn_mask is None else False,
201
+ scale=self.softmax_scale,
202
+ )
203
+
204
+ return out
205
+
206
+ def _eager_attn(
207
+ self,
208
+ q: torch.Tensor,
209
+ k: torch.Tensor,
210
+ v: torch.Tensor,
211
+ padding_mask: Optional[torch.Tensor] = None,
212
+ ) -> torch.Tensor:
213
+ scores = torch.matmul(q.float(), k.float().transpose(-2, -1)) * self.softmax_scale
214
+
215
+ if self.causal:
216
+ tq = q.size(-2)
217
+ tk = k.size(-2)
218
+ causal_mask = torch.triu(
219
+ torch.ones(tq, tk, device=scores.device, dtype=torch.bool),
220
+ diagonal=1,
221
+ )
222
+ scores = scores.masked_fill(causal_mask.unsqueeze(0).unsqueeze(0), float("-inf"))
223
+
224
+ if padding_mask is not None:
225
+ key_mask = padding_mask[:, None, None, :].to(device=scores.device, dtype=torch.bool)
226
+ scores = scores.masked_fill(key_mask, float("-inf"))
227
+
228
+ probs = torch.softmax(scores, dim=-1)
229
+
230
+ if self.training and self.dropout > 0.0:
231
+ probs = F.dropout(probs, p=self.dropout)
232
+
233
+ out = torch.matmul(probs, v.float())
234
+ return out.to(q.dtype)
235
+
236
+ def forward(
237
+ self,
238
+ x: torch.Tensor,
239
+ padding_mask: Optional[torch.Tensor] = None,
240
+ ) -> torch.Tensor:
241
+ q, k, v, residual_dtype = self._shape_qkv(x)
242
+
243
+ if padding_mask is not None:
244
+ padding_mask = padding_mask.to(device=x.device, dtype=torch.bool)
245
+
246
+ backend = self.backend
247
+
248
+ if backend == "v100":
249
+ if not self._can_use_v100_kernel(q, padding_mask):
250
+ raise RuntimeError(
251
+ "backend='v100' demandé mais indisponible "
252
+ "(flash_attn_v100_cuda absent, GPU non sm70/V100, padding présent, "
253
+ "ou head_dim incompatible)."
254
+ )
255
+ out = self._flash_attn_v100(q, k, v)
256
+
257
+ elif backend == "sdpa":
258
+ out = self._sdpa_attn(q, k, v, padding_mask=padding_mask)
259
+
260
+ elif backend == "eager":
261
+ out = self._eager_attn(q, k, v, padding_mask=padding_mask)
262
+
263
+ elif backend == "auto":
264
+ if self._can_use_v100_kernel(q, padding_mask):
265
+ out = self._flash_attn_v100(q, k, v)
266
+ else:
267
+ out = self._sdpa_attn(q, k, v, padding_mask=padding_mask)
268
+
269
+ else:
270
+ raise ValueError(f"backend d'attention non supporté: {backend}")
271
+
272
+ out = self._merge_heads(out)
273
+
274
+ out_proj_dtype = self.out_proj.weight.dtype
275
+ if out.dtype != out_proj_dtype:
276
+ out = out.to(out_proj_dtype)
277
+
278
+ out = self.out_proj(out)
279
+
280
+ if out.dtype != residual_dtype:
281
+ out = out.to(residual_dtype)
282
+
283
+ return out
284
+
285
+
286
+ class FlashTransformerEncoderLayerPortable(nn.Module):
287
+ def __init__(
288
+ self,
289
+ d_model: int,
290
+ nhead: int,
291
+ dim_feedforward: int,
292
+ dropout: float = 0.1,
293
+ activation: str = "gelu",
294
+ batch_first: bool = True,
295
+ attn_backend: str = "auto",
296
+ ) -> None:
297
+ super().__init__()
298
+
299
+ if not batch_first:
300
+ raise ValueError("Cette implémentation supporte batch_first=True uniquement.")
301
+
302
+ self.self_attn = FlashSelfAttentionPortable(
303
+ embed_dim=d_model,
304
+ num_heads=nhead,
305
+ dropout=dropout,
306
+ causal=True,
307
+ backend=attn_backend,
308
+ )
309
+
310
+ self.linear1 = nn.Linear(d_model, dim_feedforward)
311
+ self.linear2 = nn.Linear(dim_feedforward, d_model)
312
+
313
+ self.norm1 = nn.LayerNorm(d_model)
314
+ self.norm2 = nn.LayerNorm(d_model)
315
+
316
+ self.dropout = nn.Dropout(dropout)
317
+ self.dropout1 = nn.Dropout(dropout)
318
+ self.dropout2 = nn.Dropout(dropout)
319
+
320
+ if activation == "gelu":
321
+ self.activation = F.gelu
322
+ elif activation == "relu":
323
+ self.activation = F.relu
324
+ else:
325
+ raise ValueError(f"activation non supportée: {activation}")
326
+
327
+ def _sa_block(
328
+ self,
329
+ x: torch.Tensor,
330
+ src_key_padding_mask: Optional[torch.Tensor],
331
+ ) -> torch.Tensor:
332
+ x = self.self_attn(x, padding_mask=src_key_padding_mask)
333
+ x = self.dropout1(x)
334
+ return x
335
+
336
+ def _ff_block(self, x: torch.Tensor) -> torch.Tensor:
337
+ ff_dtype = self.linear1.weight.dtype
338
+ x_ff = x if x.dtype == ff_dtype else x.to(ff_dtype)
339
+
340
+ x_ff = self.linear1(x_ff)
341
+ x_ff = self.activation(x_ff)
342
+ x_ff = self.dropout(x_ff)
343
+ x_ff = self.linear2(x_ff)
344
+ x_ff = self.dropout2(x_ff)
345
+
346
+ if x_ff.dtype != x.dtype:
347
+ x_ff = x_ff.to(x.dtype)
348
+
349
+ return x_ff
350
+
351
+ def forward(
352
+ self,
353
+ src: torch.Tensor,
354
+ src_mask: Optional[torch.Tensor] = None,
355
+ src_key_padding_mask: Optional[torch.Tensor] = None,
356
+ ) -> torch.Tensor:
357
+ x = src
358
+ x = self.norm1(x + self._sa_block(x, src_key_padding_mask))
359
+ x = self.norm2(x + self._ff_block(x))
360
+ return x
361
+
362
+
363
+ class FlashTransformerEncoderPortable(nn.Module):
364
+ def __init__(
365
+ self,
366
+ encoder_layer: FlashTransformerEncoderLayerPortable,
367
+ num_layers: int,
368
+ attn_backend: str = "auto",
369
+ ) -> None:
370
+ super().__init__()
371
+
372
+ d_model = encoder_layer.norm1.normalized_shape[0]
373
+ nhead = encoder_layer.self_attn.num_heads
374
+ dim_feedforward = encoder_layer.linear1.out_features
375
+ dropout = encoder_layer.dropout.p
376
+
377
+ self.layers = nn.ModuleList(
378
+ [
379
+ FlashTransformerEncoderLayerPortable(
380
+ d_model=d_model,
381
+ nhead=nhead,
382
+ dim_feedforward=dim_feedforward,
383
+ dropout=dropout,
384
+ activation="gelu",
385
+ batch_first=True,
386
+ attn_backend=attn_backend,
387
+ )
388
+ for _ in range(num_layers)
389
+ ]
390
+ )
391
+
392
+ def forward(
393
+ self,
394
+ src: torch.Tensor,
395
+ mask: Optional[torch.Tensor] = None,
396
+ src_key_padding_mask: Optional[torch.Tensor] = None,
397
+ ) -> torch.Tensor:
398
+ x = src
399
+ for layer in self.layers:
400
+ x = layer(x, src_mask=mask, src_key_padding_mask=src_key_padding_mask)
401
+ return x
402
 
403
 
404
  class TinyTransformerLM(nn.Module):
 
410
  self.tok_embed = nn.Embedding(vocab_size, cfg.embed_dim)
411
  self.pos_encoding = PositionalEncoding(cfg.embed_dim, cfg.block_size)
412
 
413
+ encoder_layer = FlashTransformerEncoderLayerPortable(
414
  d_model=cfg.embed_dim,
415
  nhead=cfg.num_heads,
416
  dim_feedforward=cfg.ff_hidden_dim,
417
  dropout=cfg.dropout,
418
  activation="gelu",
419
  batch_first=True,
420
+ attn_backend=cfg.attn_backend,
421
+ )
422
+ self.encoder = FlashTransformerEncoderPortable(
423
+ encoder_layer,
424
+ num_layers=cfg.num_layers,
425
+ attn_backend=cfg.attn_backend,
426
  )
 
427
 
428
  ln_dim = cfg.layernorm_dim or cfg.embed_dim
429
  head_dim = cfg.head_dim or ln_dim
 
440
 
441
  self.head = nn.Linear(head_dim, vocab_size, bias=False)
442
 
 
443
  if self.pre_ln_proj is None and self.head_pre is None and head_dim == cfg.embed_dim:
444
  self.head.weight = self.tok_embed.weight
445
 
 
459
  x = self.encoder(x, mask=attn_mask, src_key_padding_mask=padding_mask)
460
 
461
  if self.pre_ln_proj is not None:
462
+ proj_dtype = self.pre_ln_proj.weight.dtype
463
+ if x.dtype != proj_dtype:
464
+ x = x.to(proj_dtype)
465
  x = self.pre_ln_proj(x)
466
 
467
+ ln_dtype = self.ln.weight.dtype
468
+ if x.dtype != ln_dtype:
469
+ x = x.to(ln_dtype)
470
  x = self.ln(x)
471
 
472
  if self.head_pre is not None:
473
+ head_pre_dtype = self.head_pre.weight.dtype
474
+ if x.dtype != head_pre_dtype:
475
+ x = x.to(head_pre_dtype)
476
  x = self.head_pre(x)
477
 
478
+ head_dtype = self.head.weight.dtype
479
+ if x.dtype != head_dtype:
480
+ x = x.to(head_dtype)
481
+
482
  return self.head(x)
483
 
484
 
 
489
  def __init__(self, config: BinaryLLMConfig):
490
  super().__init__(config)
491
 
492
+ attn_backend = getattr(config, "attn_backend", "auto")
493
+
494
  inner = _InnerCfg(
495
  block_size=int(config.max_position_embeddings),
496
  embed_dim=int(config.hidden_size),
 
501
  dropout=float(getattr(config, "dropout", 0.0)),
502
  layernorm_dim=None,
503
  head_dim=None,
504
+ attn_backend=str(attn_backend),
505
  )
506
  self.model = TinyTransformerLM(inner)
507
 
508
  self.post_init()
509
 
510
+ def get_input_embeddings(self) -> nn.Module:
511
+ return self.model.tok_embed
512
+
513
+ def set_input_embeddings(self, value: nn.Module) -> None:
514
+ self.model.tok_embed = value
515
+
516
+ def get_output_embeddings(self) -> nn.Module:
517
+ return self.model.head
518
+
519
+ def set_output_embeddings(self, new_embeddings: nn.Module) -> None:
520
+ self.model.head = new_embeddings
521
+
522
+ def prepare_inputs_for_generation(
523
+ self,
524
+ input_ids: torch.LongTensor,
525
+ attention_mask: Optional[torch.Tensor] = None,
526
+ **kwargs,
527
+ ):
528
+ return {
529
+ "input_ids": input_ids,
530
+ "attention_mask": attention_mask,
531
+ }
532
+
533
  def forward(
534
  self,
535
  input_ids: torch.LongTensor,
 
539
  ) -> CausalLMOutput:
540
  padding_mask = None
541
  if attention_mask is not None:
542
+ padding_mask = ~attention_mask.to(torch.bool)
543
 
544
  logits = self.model(input_ids, padding_mask=padding_mask)
545