TheQweaker commited on
Commit
519db8b
·
verified ·
1 Parent(s): 77cfbaf

Pin SDPA math backend (bit-reproducible fp32 oracle); device-aware rotary cache; drop dead dropout

Browse files
Files changed (1) hide show
  1. modeling_mdlm.py +13 -6
modeling_mdlm.py CHANGED
@@ -7,7 +7,9 @@ that removes the hard dependency on ``flash-attn``. The only substantive changes
7
  * Attention uses ``torch.nn.functional.scaled_dot_product_attention`` (non-causal,
8
  full bidirectional) instead of ``flash_attn_varlen_qkvpacked_func``. The two are
9
  mathematically equivalent here: a single sequence per batch element, no causal
10
- mask, default softmax scale ``1/sqrt(head_dim)``.
 
 
11
  * Rotary position embeddings are applied with an explicit ``rotate_half`` instead of
12
  ``flash_attn.layers.rotary``. This reproduces flash-attn's non-interleaved
13
  convention exactly (verified: ``q*cos + rotate_half(q)*sin`` with full-dim cos/sin).
@@ -36,6 +38,7 @@ import typing
36
  import torch
37
  import torch.nn as nn
38
  import torch.nn.functional as F
 
39
  import transformers
40
  from transformers import modeling_outputs
41
 
@@ -86,7 +89,10 @@ class Rotary(nn.Module):
86
 
87
  def forward(self, x, seq_dim=1):
88
  seq_len = x.shape[seq_dim]
89
- if seq_len != self.seq_len_cached:
 
 
 
90
  self.seq_len_cached = seq_len
91
  t = torch.arange(seq_len, device=x.device).type_as(self.inv_freq)
92
  freqs = torch.einsum("i,j->ij", t, self.inv_freq)
@@ -197,16 +203,15 @@ class DDiTBlock(nn.Module):
197
  self.norm1 = LayerNorm(dim)
198
  self.attn_qkv = nn.Linear(dim, 3 * dim, bias=False)
199
  self.attn_out = nn.Linear(dim, dim, bias=False)
200
- self.dropout1 = nn.Dropout(dropout)
201
 
202
  self.norm2 = LayerNorm(dim)
203
  self.mlp = nn.Sequential(
204
  nn.Linear(dim, mlp_ratio * dim, bias=True),
205
  nn.GELU(approximate='tanh'),
206
  nn.Linear(mlp_ratio * dim, dim, bias=True))
207
- self.dropout2 = nn.Dropout(dropout)
208
- self.dropout = dropout
209
 
 
 
210
  self.adaLN_modulation = nn.Linear(cond_dim, 6 * dim, bias=True)
211
 
212
  def forward(self, x, rotary_cos_sin, c, seqlens=None):
@@ -227,7 +232,9 @@ class DDiTBlock(nn.Module):
227
  k = apply_rotary(k, cos, sin)
228
  # SDPA wants [b, h, s, d]; attention is full bidirectional (no causal mask).
229
  q, k, v = q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2)
230
- attn = F.scaled_dot_product_attention(q, k, v, is_causal=False)
 
 
231
  attn = attn.transpose(1, 2).reshape(batch_size, seq_len, -1)
232
 
233
  x = x_skip + gate_msa * self.attn_out(attn)
 
7
  * Attention uses ``torch.nn.functional.scaled_dot_product_attention`` (non-causal,
8
  full bidirectional) instead of ``flash_attn_varlen_qkvpacked_func``. The two are
9
  mathematically equivalent here: a single sequence per batch element, no causal
10
+ mask, default softmax scale ``1/sqrt(head_dim)``. The call is pinned to the **math**
11
+ SDPA backend (``sdpa_kernel(SDPBackend.MATH)``) so the fp32 oracle is bit-reproducible
12
+ across GPUs, rather than silently dispatching to a fused kernel with different rounding.
13
  * Rotary position embeddings are applied with an explicit ``rotate_half`` instead of
14
  ``flash_attn.layers.rotary``. This reproduces flash-attn's non-interleaved
15
  convention exactly (verified: ``q*cos + rotate_half(q)*sin`` with full-dim cos/sin).
 
38
  import torch
39
  import torch.nn as nn
40
  import torch.nn.functional as F
41
+ from torch.nn.attention import SDPBackend, sdpa_kernel
42
  import transformers
43
  from transformers import modeling_outputs
44
 
 
89
 
90
  def forward(self, x, seq_dim=1):
91
  seq_len = x.shape[seq_dim]
92
+ # Rebuild on a sequence-length OR device change: cos/sin are plain attributes (not
93
+ # buffers), so `.to(device)` does not move them -- key the cache on device too.
94
+ if (seq_len != self.seq_len_cached or self.cos_cached is None
95
+ or self.cos_cached.device != x.device):
96
  self.seq_len_cached = seq_len
97
  t = torch.arange(seq_len, device=x.device).type_as(self.inv_freq)
98
  freqs = torch.einsum("i,j->ij", t, self.inv_freq)
 
203
  self.norm1 = LayerNorm(dim)
204
  self.attn_qkv = nn.Linear(dim, 3 * dim, bias=False)
205
  self.attn_out = nn.Linear(dim, dim, bias=False)
 
206
 
207
  self.norm2 = LayerNorm(dim)
208
  self.mlp = nn.Sequential(
209
  nn.Linear(dim, mlp_ratio * dim, bias=True),
210
  nn.GELU(approximate='tanh'),
211
  nn.Linear(mlp_ratio * dim, dim, bias=True))
 
 
212
 
213
+ # Inference-only oracle: the upstream training-time residual dropout is intentionally
214
+ # omitted (it is identity at eval). To *resume training*, use the official checkpoint.
215
  self.adaLN_modulation = nn.Linear(cond_dim, 6 * dim, bias=True)
216
 
217
  def forward(self, x, rotary_cos_sin, c, seqlens=None):
 
232
  k = apply_rotary(k, cos, sin)
233
  # SDPA wants [b, h, s, d]; attention is full bidirectional (no causal mask).
234
  q, k, v = q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2)
235
+ # Pin the math backend so the fp32 oracle is bit-reproducible across GPUs.
236
+ with sdpa_kernel(SDPBackend.MATH):
237
+ attn = F.scaled_dot_product_attention(q, k, v, is_causal=False)
238
  attn = attn.transpose(1, 2).reshape(batch_size, seq_len, -1)
239
 
240
  x = x_skip + gate_msa * self.attn_out(attn)