kernels-bot commited on
Commit
20f6e91
·
verified ·
1 Parent(s): 93fec15

Uploaded using `kernel-builder`.

Browse files
Files changed (46) hide show
  1. build/torch-cuda/__init__.py +8 -2
  2. build/torch-cuda/_ops.py +1 -1
  3. build/torch-cuda/layers.py +172 -344
  4. build/torch-cuda/metadata.json +37 -2
  5. build/torch-cuda/metadata.json.sigstore +1 -0
  6. build/torch-cuda/tiled_mlp.py +31 -8
  7. build/torch-rocm/__init__.py +0 -4
  8. build/torch-rocm/_ops.py +0 -38
  9. build/torch-rocm/cross_entropy.py +0 -558
  10. build/torch-rocm/dyt.py +0 -164
  11. build/torch-rocm/fused_linear_cross_entropy.py +0 -400
  12. build/torch-rocm/geglu.py +0 -143
  13. build/torch-rocm/group_norm.py +0 -311
  14. build/torch-rocm/jsd.py +0 -201
  15. build/torch-rocm/kl_div.py +0 -259
  16. build/torch-rocm/layer_norm.py +0 -320
  17. build/torch-rocm/layers.py +0 -514
  18. build/torch-rocm/liger_kernels/__init__.py +0 -26
  19. build/torch-rocm/metadata.json +0 -10
  20. build/torch-rocm/qwen2vl_mrope.py +0 -222
  21. build/torch-rocm/rms_norm.py +0 -654
  22. build/torch-rocm/rope.py +0 -239
  23. build/torch-rocm/swiglu.py +0 -176
  24. build/torch-rocm/tiled_mlp.py +0 -136
  25. build/torch-rocm/tvd.py +0 -218
  26. build/torch-rocm/utils.py +0 -176
  27. build/torch-xpu/__init__.py +0 -4
  28. build/torch-xpu/_ops.py +0 -38
  29. build/torch-xpu/cross_entropy.py +0 -558
  30. build/torch-xpu/dyt.py +0 -164
  31. build/torch-xpu/fused_linear_cross_entropy.py +0 -400
  32. build/torch-xpu/geglu.py +0 -143
  33. build/torch-xpu/group_norm.py +0 -311
  34. build/torch-xpu/jsd.py +0 -201
  35. build/torch-xpu/kl_div.py +0 -259
  36. build/torch-xpu/layer_norm.py +0 -320
  37. build/torch-xpu/layers.py +0 -514
  38. build/torch-xpu/liger_kernels/__init__.py +0 -26
  39. build/torch-xpu/metadata.json +0 -10
  40. build/torch-xpu/qwen2vl_mrope.py +0 -222
  41. build/torch-xpu/rms_norm.py +0 -654
  42. build/torch-xpu/rope.py +0 -239
  43. build/torch-xpu/swiglu.py +0 -176
  44. build/torch-xpu/tiled_mlp.py +0 -136
  45. build/torch-xpu/tvd.py +0 -218
  46. build/torch-xpu/utils.py +0 -176
build/torch-cuda/__init__.py CHANGED
@@ -1,4 +1,10 @@
1
  from . import layers
2
- from .layers import CrossEntropyOutput, LigerForCausalLMLoss
3
 
4
- __all__ = ["layers", "LigerForCausalLMLoss", "CrossEntropyOutput"]
 
 
 
 
 
 
 
1
  from . import layers
2
+ from .layers import LigerForCausalLMLoss, liger_rotary_pos_emb
3
 
4
+
5
+ __all__ = [
6
+ "layers",
7
+ # kept for BC
8
+ "LigerForCausalLMLoss",
9
+ "liger_rotary_pos_emb",
10
+ ]
build/torch-cuda/_ops.py CHANGED
@@ -22,7 +22,7 @@ def get_backend() -> str:
22
 
23
  def _find_ops_name() -> str:
24
  kernel_name = "liger_kernels"
25
- unique_id = "ab435e2"
26
  backend = get_backend()
27
  return f"_{kernel_name}_{backend}_{unique_id}"
28
 
 
22
 
23
  def _find_ops_name() -> str:
24
  kernel_name = "liger_kernels"
25
+ unique_id = "4d9f798"
26
  backend = get_backend()
27
  return f"_{kernel_name}_{backend}_{unique_id}"
28
 
build/torch-cuda/layers.py CHANGED
@@ -1,360 +1,142 @@
1
  import inspect
2
  from dataclasses import dataclass
3
- from typing import Optional, Tuple
4
 
5
  import torch
6
  import torch.nn as nn
7
 
8
- from .cross_entropy import LigerCrossEntropyFunction
9
- from .dyt import LigerDyTFunction
10
  from .fused_linear_cross_entropy import LigerFusedLinearCrossEntropyFunction
11
  from .geglu import LigerGELUMulFunction
12
- from .group_norm import LigerGroupNormFunction
13
- from .jsd import LigerJSDFunction
14
- from .kl_div import LigerKLDivLossFunction
15
- from .layer_norm import LigerLayerNormFunction
16
- from .qwen2vl_mrope import LigerQwen2VLMRopeFunction
17
  from .rms_norm import LigerRMSNormFunction
18
  from .rope import LigerRopeFunction
19
  from .swiglu import LigerSiLUMulFunction
20
  from .tiled_mlp import apply_tiled_mlp
21
- from .tvd import LigerTVDLossFunction
22
 
23
 
 
24
  class LigerRMSNorm(nn.Module):
25
- def __init__(
26
- self,
27
- hidden_size: int,
28
- eps: float = 1e-6,
29
- offset: float = 0.0,
30
- casting_mode: str = "llama",
31
- init_fn: str = "ones",
32
- in_place: bool = True,
33
- row_mode: Optional[bool] = None,
34
- elementwise_affine: bool = True,
35
- ):
36
- super().__init__()
37
- assert init_fn in ("ones", "zeros"), f"init_fn must be 'ones' or 'zeros', got {init_fn}"
38
- self.hidden_size = hidden_size
39
- self.variance_epsilon = eps
40
- self.offset = offset
41
- self.casting_mode = casting_mode
42
- self.in_place = in_place
43
- self.row_mode = row_mode
44
- self.elementwise_affine = elementwise_affine
45
- if elementwise_affine:
46
- init = torch.ones(hidden_size) if init_fn == "ones" else torch.zeros(hidden_size)
47
- self.weight = nn.Parameter(init)
48
- else:
49
- self.register_parameter("weight", None)
50
 
51
  def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
52
  return LigerRMSNormFunction.apply(
53
  hidden_states,
54
  self.weight,
55
  self.variance_epsilon,
56
- self.offset,
57
- self.casting_mode,
58
- self.in_place,
59
- self.row_mode,
60
- )
61
-
62
- def extra_repr(self) -> str:
63
- return (
64
- f"{self.hidden_size}, eps={self.variance_epsilon}, offset={self.offset}, "
65
- f"in_place={self.in_place}, row_mode={self.row_mode}"
66
  )
67
 
68
-
69
- class LigerLayerNorm(nn.Module):
70
- def __init__(
71
- self,
72
- hidden_size: int,
73
- eps: float = 1e-6,
74
- bias: bool = False,
75
- init_fn: str = "ones",
76
- ):
77
- super().__init__()
78
- assert init_fn in ("ones", "zeros"), f"init_fn must be 'ones' or 'zeros', got {init_fn}"
79
- self.hidden_size = hidden_size
80
- self.variance_epsilon = eps
81
- self.weight = nn.Parameter(torch.ones(hidden_size) if init_fn == "ones" else torch.zeros(hidden_size))
82
- self.bias = nn.Parameter(torch.randn(hidden_size) if bias else torch.zeros(hidden_size))
83
-
84
- def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
85
- return LigerLayerNormFunction.apply(hidden_states, self.weight, self.bias, self.variance_epsilon)
86
-
87
- def extra_repr(self) -> str:
88
- return f"{self.hidden_size}, eps={self.variance_epsilon}"
89
 
90
 
91
- class LigerGroupNorm(nn.Module):
92
- def __init__(
93
- self,
94
- num_channels: int,
95
- num_groups: int,
96
- eps: float = 1e-6,
97
- bias: bool = False,
98
- init_fn: str = "ones",
99
- ):
100
- super().__init__()
101
- assert init_fn in ("ones", "zeros"), f"init_fn must be 'ones' or 'zeros', got {init_fn}"
102
- assert num_channels % num_groups == 0, (
103
- f"num_channels ({num_channels}) must be divisible by num_groups ({num_groups})"
104
- )
105
- self.num_channels = num_channels
106
- self.num_groups = num_groups
107
- self.variance_epsilon = eps
108
- self.weight = nn.Parameter(torch.ones(num_channels) if init_fn == "ones" else torch.zeros(num_channels))
109
- self.bias = nn.Parameter(torch.randn(num_channels) if bias else torch.zeros(num_channels))
110
 
111
- def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
112
- assert hidden_states.dim() >= 3, f"Input must have at least 3 dimensions, got {hidden_states.dim()}"
113
- assert hidden_states.size(1) == self.num_channels, (
114
- f"Input must have {self.num_channels} channels, got {hidden_states.size(1)}"
115
- )
116
- return LigerGroupNormFunction.apply(
117
- hidden_states,
118
- self.weight,
119
- self.bias,
120
- self.num_channels,
121
- self.num_groups,
122
- self.variance_epsilon,
123
- )
124
-
125
- def extra_repr(self) -> str:
126
- return f"num_channels={self.num_channels}, num_groups={self.num_groups}, eps={self.variance_epsilon}"
127
-
128
-
129
- class LigerDyT(nn.Module):
130
- def __init__(self, hidden_size: int, beta: bool = True, init_alpha: float = 0.5):
131
- super().__init__()
132
- self.hidden_size = hidden_size
133
- self.init_alpha = init_alpha
134
- self.alpha = nn.Parameter(torch.ones(1) * init_alpha)
135
- self.gamma = nn.Parameter(torch.ones(hidden_size))
136
- self.beta = nn.Parameter(torch.zeros(hidden_size)) if beta else None
137
-
138
- def forward(self, x: torch.Tensor) -> torch.Tensor:
139
- return LigerDyTFunction.apply(x, self.alpha, self.gamma, self.beta)
140
-
141
- def extra_repr(self) -> str:
142
- return f"{self.hidden_size}, init_alpha={self.init_alpha}, beta={self.beta is not None}"
143
-
144
-
145
- class LigerCrossEntropyLoss(nn.Module):
146
- def __init__(
147
- self,
148
- weight: Optional[torch.Tensor] = None,
149
- ignore_index: int = -100,
150
- lse_square_scale: float = 0.0,
151
- label_smoothing: float = 0.0,
152
- reduction: str = "mean",
153
- softcap: Optional[float] = None,
154
- ):
155
- super().__init__()
156
- assert 0.0 <= label_smoothing <= 1.0, f"label_smoothing must be in [0, 1], got {label_smoothing}"
157
- assert reduction in ("mean", "sum", "none"), f"reduction must be 'mean', 'sum', or 'none', got {reduction}"
158
- assert softcap is None or softcap > 0, f"softcap must be > 0 or None, got {softcap}"
159
- self.weight = weight
160
- self.ignore_index = ignore_index
161
- self.lse_square_scale = lse_square_scale
162
- self.label_smoothing = label_smoothing
163
- self.reduction = reduction
164
- self.softcap = softcap
165
-
166
- def forward(self, _input: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
167
- loss, _, _, _ = LigerCrossEntropyFunction.apply(
168
- _input,
169
- target,
170
- self.weight,
171
- self.ignore_index,
172
- self.lse_square_scale,
173
- self.label_smoothing,
174
- self.reduction,
175
- self.softcap,
176
- False,
177
- False,
178
- False,
179
- )
180
- return loss
181
 
 
 
 
182
 
183
- class LigerFusedLinearCrossEntropyLoss(nn.Module):
184
- def __init__(
185
- self,
186
- ce_weight: Optional[torch.Tensor] = None,
187
- ignore_index: int = -100,
188
- lse_square_scale: float = 0.0,
189
- label_smoothing: float = 0.0,
190
- reduction: str = "mean",
191
- softcap: Optional[float] = None,
192
- accum_dtype: Optional[torch.dtype] = None,
193
- use_token_scaling: bool = False,
194
- ):
195
- super().__init__()
196
- assert 0.0 <= label_smoothing <= 1.0, f"label_smoothing must be in [0, 1], got {label_smoothing}"
197
- assert reduction in ("mean", "sum", "none"), f"reduction must be 'mean', 'sum', or 'none', got {reduction}"
198
- assert softcap is None or softcap > 0, f"softcap must be > 0 or None, got {softcap}"
199
- self.ce_weight = ce_weight
200
- self.ignore_index = ignore_index
201
- self.lse_square_scale = lse_square_scale
202
- self.label_smoothing = label_smoothing
203
- self.reduction = reduction
204
- self.softcap = softcap
205
- self.accum_dtype = accum_dtype
206
- self.use_token_scaling = use_token_scaling
207
 
208
- def forward(
209
- self,
210
- lin_weight: torch.Tensor,
211
- _input: torch.Tensor,
212
- target: torch.Tensor,
213
- bias: Optional[torch.Tensor] = None,
214
- ) -> torch.Tensor:
215
- loss, _, _, _ = LigerFusedLinearCrossEntropyFunction.apply(
216
- _input,
217
- lin_weight,
218
- target,
219
- bias,
220
- self.ce_weight,
221
- self.ignore_index,
222
- self.lse_square_scale,
223
- self.label_smoothing,
224
- self.reduction,
225
- self.softcap,
226
- False,
227
- self.accum_dtype,
228
- self.use_token_scaling,
229
- False,
230
- False,
231
  )
232
- return loss
233
-
234
-
235
- class LigerJSD(nn.Module):
236
- def __init__(self, beta: float = 0.5, ignore_index: int = -100):
237
- super().__init__()
238
- self.beta = beta
239
- self.ignore_index = ignore_index
240
-
241
- def forward(
242
- self,
243
- log_q: torch.Tensor,
244
- log_p: torch.Tensor,
245
- shift_labels: Optional[torch.Tensor] = None,
246
- ) -> torch.Tensor:
247
- return LigerJSDFunction.apply(log_q, log_p, shift_labels, self.beta, self.ignore_index)
248
-
249
-
250
- class LigerKLDIVLoss(nn.KLDivLoss):
251
- def __init__(self, eps: float = 1e-10, *args, **kwargs):
252
- super().__init__(*args, **kwargs)
253
- self.eps = eps
254
-
255
- def forward(self, y_pred: torch.Tensor, y_true: torch.Tensor) -> torch.Tensor:
256
- return LigerKLDivLossFunction.apply(y_pred, y_true, self.reduction, self.log_target, self.eps)
257
-
258
-
259
- class LigerTVDLoss(nn.Module):
260
- def __init__(self, reduction: str = "batchmean", ignore_index: int = -100):
261
- super().__init__()
262
- self.reduction = reduction
263
- self.ignore_index = ignore_index
264
-
265
- def forward(
266
- self,
267
- p: torch.Tensor,
268
- q: torch.Tensor,
269
- shift_labels: Optional[torch.Tensor] = None,
270
- ) -> torch.Tensor:
271
- return LigerTVDLossFunction.apply(p, q, shift_labels, self.reduction, self.ignore_index)
272
 
273
 
274
  class LigerSwiGLUMLP(nn.Module):
275
- """SwiGLU MLP block. ``config`` must expose ``hidden_size``, ``intermediate_size``,
276
- and ``hidden_act`` (must be ``silu`` or ``swish``)."""
277
-
278
- def __init__(self, config):
279
- super().__init__()
280
- if config.hidden_act not in ("silu", "swish"):
281
- raise ValueError(f"Activation function {config.hidden_act} not supported.")
282
- self.config = config
283
- self.hidden_size = config.hidden_size
284
- self.intermediate_size = config.intermediate_size
285
- self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
286
- self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
287
- self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
288
 
289
  def forward(self, x: torch.Tensor) -> torch.Tensor:
290
  return self.down_proj(LigerSiLUMulFunction.apply(self.gate_proj(x), self.up_proj(x)))
291
 
292
 
293
  class LigerGEGLUMLP(nn.Module):
294
- """GEGLU MLP block. ``config`` must expose ``hidden_size`` and ``intermediate_size``.
295
- Uses the tanh approximation of GELU (matches Gemma 1/1.1/2)."""
296
-
297
- def __init__(self, config):
298
- super().__init__()
299
- self.config = config
300
- self.hidden_size = config.hidden_size
301
- self.intermediate_size = config.intermediate_size
302
- self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
303
- self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
304
- self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
305
 
306
  def forward(self, x: torch.Tensor) -> torch.Tensor:
307
  return self.down_proj(LigerGELUMulFunction.apply(self.gate_proj(x), self.up_proj(x)))
308
 
309
 
310
- class LigerTiledGEGLUMLP(nn.Module):
311
  gate_proj: nn.Linear
312
  up_proj: nn.Linear
313
  down_proj: nn.Linear
314
- num_shards: int
315
 
316
- def _mlp_forward(self, module, x):
317
- """Internal MLP forward function for tiled computation."""
318
- gate = module.gate_proj(x)
319
- up = module.up_proj(x)
320
- return module.down_proj(LigerGELUMulFunction.apply(gate, up))
321
 
322
  def forward(self, x: torch.Tensor) -> torch.Tensor:
 
 
 
 
 
 
323
  compute_params = [p for p in self.parameters() if p.requires_grad]
324
 
325
  return apply_tiled_mlp(
326
- fn=self._mlp_forward,
327
  mlp_module=self,
328
  x=x,
329
- num_shards=self.num_shards,
330
  compute_params=compute_params,
331
  )
332
 
333
 
334
- class LigerTiledSwiGLUMLP(nn.Module):
335
  gate_proj: nn.Linear
336
  up_proj: nn.Linear
337
  down_proj: nn.Linear
338
- num_shards: int
339
 
340
- def _mlp_forward(self, module, x):
341
- """Internal MLP forward function for tiled computation."""
342
- gate = module.gate_proj(x)
343
- up = module.up_proj(x)
344
- return module.down_proj(LigerSiLUMulFunction.apply(gate, up))
345
 
346
  def forward(self, x: torch.Tensor) -> torch.Tensor:
 
 
 
 
 
 
347
  compute_params = [p for p in self.parameters() if p.requires_grad]
348
 
349
  return apply_tiled_mlp(
350
- fn=self._mlp_forward,
351
  mlp_module=self,
352
  x=x,
353
- num_shards=self.num_shards,
354
  compute_params=compute_params,
355
  )
356
 
357
 
 
 
 
 
 
 
 
 
 
 
 
358
  @dataclass
359
  class CrossEntropyOutput:
360
  loss: torch.Tensor
@@ -407,23 +189,33 @@ def liger_fused_linear_cross_entropy(
407
  )
408
 
409
 
 
 
 
 
410
  def LigerForCausalLMLoss(
411
- hidden_states: torch.Tensor,
412
- lm_head_weight: torch.Tensor,
413
  labels: torch.Tensor,
414
- hidden_size: int,
415
  num_items_in_batch: Optional[int] = None,
416
  ignore_index: int = -100,
417
  shift_labels: Optional[torch.Tensor] = None,
418
- final_logit_softcapping: Optional[float] = None,
419
- return_token_accuracy: bool = False,
420
- return_predicted_tokens: bool = False,
421
  **kwargs,
422
  ):
423
- """Drop-in replacement for ``transformers.loss.ForCausalLMLoss`` that fuses the
424
- final ``lm_head`` projection with the cross-entropy loss. Returns a scalar
425
- ``loss`` by default; returns a :class:`CrossEntropyOutput` when
426
- ``return_token_accuracy`` or ``return_predicted_tokens`` is set."""
 
 
 
 
 
 
 
427
  applicable_params = inspect.signature(liger_fused_linear_cross_entropy).parameters
428
  kwargs = {k: v for k, v in kwargs.items() if k in applicable_params}
429
 
@@ -435,80 +227,116 @@ def LigerForCausalLMLoss(
435
  shift_labels = shift_labels.view(-1).to(hidden_states.device)
436
 
437
  reduction = "sum" if num_items_in_batch is not None else "mean"
438
- result = liger_fused_linear_cross_entropy(
439
  hidden_states,
440
  lm_head_weight,
441
  shift_labels,
 
442
  reduction=reduction,
443
  ignore_index=ignore_index,
444
  softcap=final_logit_softcapping,
445
- return_token_accuracy=return_token_accuracy,
446
- return_predicted_tokens=return_predicted_tokens,
447
  **kwargs,
448
  )
449
 
450
- if isinstance(result, CrossEntropyOutput):
451
- loss = result.loss
452
- token_accuracy = result.token_accuracy
453
- predicted_tokens = result.predicted_tokens
454
- else:
455
- loss = result
456
- token_accuracy = None
457
- predicted_tokens = None
458
-
459
  if reduction == "sum":
460
  loss = loss / num_items_in_batch
461
 
462
- if return_token_accuracy or return_predicted_tokens:
463
- return CrossEntropyOutput(
464
- loss=loss,
465
- token_accuracy=token_accuracy,
466
- predicted_tokens=predicted_tokens,
467
- )
468
  return loss
469
 
470
 
471
- def liger_rotary_pos_emb(
472
- q: torch.Tensor,
473
- k: torch.Tensor,
474
- cos: torch.Tensor,
475
- sin: torch.Tensor,
476
- position_ids: Optional[torch.Tensor] = None,
477
- unsqueeze_dim: int = 1,
478
- ) -> Tuple[torch.Tensor, torch.Tensor]:
479
- """Apply standard rotary positional embedding to ``q`` and ``k``."""
480
- return LigerRopeFunction.apply(q, k, cos, sin, position_ids, unsqueeze_dim)
481
 
482
 
483
- def liger_multimodal_rotary_pos_emb(
484
- q: torch.Tensor,
485
- k: torch.Tensor,
486
- cos: torch.Tensor,
487
- sin: torch.Tensor,
488
- mrope_section,
489
- unsqueeze_dim: int = 1,
490
- ) -> Tuple[torch.Tensor, torch.Tensor]:
491
- """Apply Qwen2-VL multimodal rotary positional embedding (M-RoPE) to ``q`` and ``k``."""
492
- return LigerQwen2VLMRopeFunction.apply(q, k, cos, sin, mrope_section, unsqueeze_dim)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
 
494
 
495
  __all__ = [
496
  "LigerRMSNorm",
497
- "LigerLayerNorm",
498
- "LigerGroupNorm",
499
- "LigerDyT",
500
- "LigerCrossEntropyLoss",
501
- "LigerFusedLinearCrossEntropyLoss",
502
- "LigerJSD",
503
- "LigerKLDIVLoss",
504
- "LigerTVDLoss",
505
  "LigerSwiGLUMLP",
506
  "LigerGEGLUMLP",
507
- "LigerTiledGEGLUMLP",
508
  "LigerTiledSwiGLUMLP",
509
- "CrossEntropyOutput",
510
- "liger_fused_linear_cross_entropy",
511
- "LigerForCausalLMLoss",
512
  "liger_rotary_pos_emb",
513
- "liger_multimodal_rotary_pos_emb",
 
 
514
  ]
 
1
  import inspect
2
  from dataclasses import dataclass
3
+ from typing import Optional
4
 
5
  import torch
6
  import torch.nn as nn
7
 
 
 
8
  from .fused_linear_cross_entropy import LigerFusedLinearCrossEntropyFunction
9
  from .geglu import LigerGELUMulFunction
 
 
 
 
 
10
  from .rms_norm import LigerRMSNormFunction
11
  from .rope import LigerRopeFunction
12
  from .swiglu import LigerSiLUMulFunction
13
  from .tiled_mlp import apply_tiled_mlp
 
14
 
15
 
16
+ # NOTE: Not compile-friendly --> large deviations to the original implementation under compile
17
  class LigerRMSNorm(nn.Module):
18
+ weight: nn.Parameter
19
+ variance_epsilon: float
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
  def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
22
  return LigerRMSNormFunction.apply(
23
  hidden_states,
24
  self.weight,
25
  self.variance_epsilon,
26
+ 0,
27
+ "llama",
28
+ True,
29
+ None,
 
 
 
 
 
 
30
  )
31
 
32
+ def extra_repr(self):
33
+ return f"{tuple(self.weight.shape)}, eps={self.variance_epsilon}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
 
36
+ class LigerLinear(nn.Module):
37
+ weight: nn.Parameter
38
+ bias: nn.Parameter | None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
+ can_torch_compile = True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
+ def forward(self, input: torch.Tensor) -> torch.Tensor:
43
+ def _forward(module, x):
44
+ return nn.functional.linear(x, module.weight, module.bias)
45
 
46
+ compute_params = [p for p in self.parameters() if p.requires_grad]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
+ return apply_tiled_mlp(
49
+ fn=_forward,
50
+ mlp_module=self,
51
+ x=input,
52
+ num_shards=None,
53
+ compute_params=compute_params,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
 
57
  class LigerSwiGLUMLP(nn.Module):
58
+ gate_proj: nn.Linear
59
+ up_proj: nn.Linear
60
+ down_proj: nn.Linear
61
+
62
+ can_torch_compile = True
 
 
 
 
 
 
 
 
63
 
64
  def forward(self, x: torch.Tensor) -> torch.Tensor:
65
  return self.down_proj(LigerSiLUMulFunction.apply(self.gate_proj(x), self.up_proj(x)))
66
 
67
 
68
  class LigerGEGLUMLP(nn.Module):
69
+ gate_proj: nn.Linear
70
+ up_proj: nn.Linear
71
+ down_proj: nn.Linear
72
+
73
+ can_torch_compile = True
 
 
 
 
 
 
74
 
75
  def forward(self, x: torch.Tensor) -> torch.Tensor:
76
  return self.down_proj(LigerGELUMulFunction.apply(self.gate_proj(x), self.up_proj(x)))
77
 
78
 
79
+ class LigerTiledSwiGLUMLP(nn.Module):
80
  gate_proj: nn.Linear
81
  up_proj: nn.Linear
82
  down_proj: nn.Linear
 
83
 
84
+ can_torch_compile = True
 
 
 
 
85
 
86
  def forward(self, x: torch.Tensor) -> torch.Tensor:
87
+ def _mlp_forward(module, x):
88
+ """Internal MLP forward function for tiled computation."""
89
+ gate = module.gate_proj(x)
90
+ up = module.up_proj(x)
91
+ return module.down_proj(LigerSiLUMulFunction.apply(gate, up))
92
+
93
  compute_params = [p for p in self.parameters() if p.requires_grad]
94
 
95
  return apply_tiled_mlp(
96
+ fn=_mlp_forward,
97
  mlp_module=self,
98
  x=x,
99
+ num_shards=None,
100
  compute_params=compute_params,
101
  )
102
 
103
 
104
+ class LigerTiledGEGLUMLP(nn.Module):
105
  gate_proj: nn.Linear
106
  up_proj: nn.Linear
107
  down_proj: nn.Linear
 
108
 
109
+ can_torch_compile = True
 
 
 
 
110
 
111
  def forward(self, x: torch.Tensor) -> torch.Tensor:
112
+ def _mlp_forward(module, x):
113
+ """Internal MLP forward function for tiled computation."""
114
+ gate = module.gate_proj(x)
115
+ up = module.up_proj(x)
116
+ return module.down_proj(LigerGELUMulFunction.apply(gate, up))
117
+
118
  compute_params = [p for p in self.parameters() if p.requires_grad]
119
 
120
  return apply_tiled_mlp(
121
+ fn=_mlp_forward,
122
  mlp_module=self,
123
  x=x,
124
+ num_shards=None,
125
  compute_params=compute_params,
126
  )
127
 
128
 
129
+ def liger_rotary_pos_emb(
130
+ q: torch.Tensor,
131
+ k: torch.Tensor,
132
+ cos: torch.Tensor,
133
+ sin: torch.Tensor,
134
+ unsqueeze_dim: int = 1,
135
+ ) -> tuple[torch.Tensor, torch.Tensor]:
136
+ """Apply standard rotary positional embedding to ``q`` and ``k``."""
137
+ return LigerRopeFunction.apply(q, k, cos, sin, None, unsqueeze_dim)
138
+
139
+
140
  @dataclass
141
  class CrossEntropyOutput:
142
  loss: torch.Tensor
 
189
  )
190
 
191
 
192
+ # NOTE: We have this intentional graph break as we encounter issues such as IMAs and Cublas errors.
193
+ # We know that this is an optimized kernel already so there is less ways to
194
+ # fuse it either way; we rely on torch compile to go through the base model to optimize.
195
+ @torch.compiler.disable
196
  def LigerForCausalLMLoss(
197
+ logits: None, # to match transformers signature
 
198
  labels: torch.Tensor,
199
+ vocab_size: int, # to match transformers signature
200
  num_items_in_batch: Optional[int] = None,
201
  ignore_index: int = -100,
202
  shift_labels: Optional[torch.Tensor] = None,
203
+ hidden_states: torch.Tensor | None = None,
204
+ lm_head_weight: torch.Tensor | None = None,
205
+ lm_head_bias: torch.Tensor | None = None,
206
  **kwargs,
207
  ):
208
+ # To match signature we hide these behind the kwargs but we expect a few kwargs to exist
209
+ hidden_size = kwargs.pop("hidden_size", None)
210
+ final_logit_softcapping = kwargs.pop("final_logit_softcapping", None)
211
+
212
+ if hidden_size is None or hidden_states is None or lm_head_weight is None:
213
+ raise ValueError(
214
+ f"`LigerForCausalLMLoss` requires the LLM's weight (found `{lm_head_weight is not None}`),"
215
+ f"the last hidden state (found `{hidden_states is not None}`), and the `hidden_size`"
216
+ f"(found `{hidden_size is not None}`). Please make sure to pass the necessary kwargs."
217
+ )
218
+
219
  applicable_params = inspect.signature(liger_fused_linear_cross_entropy).parameters
220
  kwargs = {k: v for k, v in kwargs.items() if k in applicable_params}
221
 
 
227
  shift_labels = shift_labels.view(-1).to(hidden_states.device)
228
 
229
  reduction = "sum" if num_items_in_batch is not None else "mean"
230
+ loss = liger_fused_linear_cross_entropy(
231
  hidden_states,
232
  lm_head_weight,
233
  shift_labels,
234
+ bias=lm_head_bias,
235
  reduction=reduction,
236
  ignore_index=ignore_index,
237
  softcap=final_logit_softcapping,
238
+ return_token_accuracy=False,
239
+ return_predicted_tokens=False,
240
  **kwargs,
241
  )
242
 
 
 
 
 
 
 
 
 
 
243
  if reduction == "sum":
244
  loss = loss / num_items_in_batch
245
 
 
 
 
 
 
 
246
  return loss
247
 
248
 
249
+ # Add torch compile support for functions - in this case it's to allow this to be used
250
+ # but the function itself will not be compiled (see the note at the function)
251
+ liger_rotary_pos_emb.can_torch_compile = True
252
+ LigerForCausalLMLoss.can_torch_compile = True
 
 
 
 
 
 
253
 
254
 
255
+ class liger_rotary_pos_emb_layer(nn.Module):
256
+ can_torch_compile = True
257
+
258
+ def forward(
259
+ self,
260
+ q: torch.Tensor,
261
+ k: torch.Tensor,
262
+ cos: torch.Tensor,
263
+ sin: torch.Tensor,
264
+ unsqueeze_dim: int = 1,
265
+ ) -> tuple[torch.Tensor, torch.Tensor]:
266
+ """Apply standard rotary positional embedding to ``q`` and ``k``."""
267
+ return LigerRopeFunction.apply(q, k, cos, sin, None, unsqueeze_dim)
268
+
269
+
270
+ class LigerForCausalLMLossLayer(nn.Module):
271
+ can_torch_compile = True
272
+
273
+ # NOTE: We have this intentional graph break as we encounter issues such as IMAs and Cublas errors.
274
+ # We know that this is an optimized kernel already so there is less ways to
275
+ # fuse it either way; we rely on torch compile to go through the base model to optimize.
276
+ @torch.compiler.disable
277
+ def forward(
278
+ self,
279
+ logits: None, # to match transformers signature
280
+ labels: torch.Tensor,
281
+ vocab_size: int, # to match transformers signature
282
+ num_items_in_batch: Optional[int] = None,
283
+ ignore_index: int = -100,
284
+ shift_labels: Optional[torch.Tensor] = None,
285
+ hidden_states: torch.Tensor | None = None,
286
+ lm_head_weight: torch.Tensor | None = None,
287
+ lm_head_bias: torch.Tensor | None = None,
288
+ **kwargs,
289
+ ):
290
+ # To match signature we hide these behind the kwargs but we expect a few kwargs to exist
291
+ hidden_size = kwargs.pop("hidden_size", None)
292
+ final_logit_softcapping = kwargs.pop("final_logit_softcapping", None)
293
+
294
+ if hidden_size is None or hidden_states is None or lm_head_weight is None:
295
+ raise ValueError(
296
+ f"`LigerForCausalLMLoss` requires the LLM's weight (found `{lm_head_weight is not None}`),"
297
+ f"the last hidden state (found `{hidden_states is not None}`), and the `hidden_size`"
298
+ f"(found `{hidden_size is not None}`). Please make sure to pass the necessary kwargs."
299
+ )
300
+
301
+ applicable_params = inspect.signature(liger_fused_linear_cross_entropy).parameters
302
+ kwargs = {k: v for k, v in kwargs.items() if k in applicable_params}
303
+
304
+ if shift_labels is None:
305
+ labels = nn.functional.pad(labels, (0, 1), value=ignore_index)
306
+ shift_labels = labels[..., 1:].contiguous()
307
+
308
+ hidden_states = hidden_states.view(-1, hidden_size)
309
+ shift_labels = shift_labels.view(-1).to(hidden_states.device)
310
+
311
+ reduction = "sum" if num_items_in_batch is not None else "mean"
312
+ loss = liger_fused_linear_cross_entropy(
313
+ hidden_states,
314
+ lm_head_weight,
315
+ shift_labels,
316
+ bias=lm_head_bias,
317
+ reduction=reduction,
318
+ ignore_index=ignore_index,
319
+ softcap=final_logit_softcapping,
320
+ return_token_accuracy=False,
321
+ return_predicted_tokens=False,
322
+ **kwargs,
323
+ )
324
+
325
+ if reduction == "sum":
326
+ loss = loss / num_items_in_batch
327
+
328
+ return loss
329
 
330
 
331
  __all__ = [
332
  "LigerRMSNorm",
333
+ "LigerLinear",
 
 
 
 
 
 
 
334
  "LigerSwiGLUMLP",
335
  "LigerGEGLUMLP",
 
336
  "LigerTiledSwiGLUMLP",
337
+ "LigerTiledGEGLUMLP",
 
 
338
  "liger_rotary_pos_emb",
339
+ "liger_rotary_pos_emb_layer",
340
+ "LigerForCausalLMLoss",
341
+ "LigerForCausalLMLossLayer",
342
  ]
build/torch-cuda/metadata.json CHANGED
@@ -1,10 +1,45 @@
1
  {
2
  "name": "liger-kernels",
3
- "id": "_liger_kernels_cuda_ab435e2",
4
- "version": 1,
5
  "license": "BSD-2-Clause",
6
  "python-depends": [],
7
  "backend": {
8
  "type": "cuda"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
10
  }
 
1
  {
2
  "name": "liger-kernels",
3
+ "id": "_liger_kernels_cuda_4d9f798",
4
+ "version": 3,
5
  "license": "BSD-2-Clause",
6
  "python-depends": [],
7
  "backend": {
8
  "type": "cuda"
9
+ },
10
+ "digest": {
11
+ "algorithm": "sha256",
12
+ "files": {
13
+ "__init__.py": "DSZMiK0xOBiMb0JdCc2K9QH4Z6lV7L8D/fTowstf/og=",
14
+ "_ops.py": "pdeXrc8M9KCvCpe0mtloEEFT3iJWZab9CMNsgT2CK10=",
15
+ "cross_entropy.py": "LsQN0OI8VHqgUObWF0qqTgNA9z7SYMaZNb2I7FIYnO4=",
16
+ "dyt.py": "806Tai0T+Yi7Ctf5YGmtwAc87MUjlzjsLky7b1T+oWM=",
17
+ "fused_linear_cross_entropy.py": "yjtZHWyBcXCBJ57NbbrQ1wMmTr9nARqDBrdjXVYpR74=",
18
+ "geglu.py": "Lmw0I38IBIHkNROTf9V3bP6PZLktCWCqNAxzVRaipbk=",
19
+ "group_norm.py": "xdY/tCr4rHOb4PhD827259XB7QDb22z2psUKzTYTKBE=",
20
+ "jsd.py": "CftyIN36AU63e1GdtuA7hNhs66I3TjS9lttcFriBnGA=",
21
+ "kl_div.py": "VQG/89mefLifPeVEv+1O8hmsXgGujMLA0JXDwO5QvtU=",
22
+ "layer_norm.py": "INpxK7Ac27f+eckcMfOOSgZErzDhNF5iGt207eV9aoM=",
23
+ "layers.py": "+50F9xmnpQXbU1K/lZxdJwbnTotkksJlhoLOWHjo+/M=",
24
+ "liger_kernels/__init__.py": "DFYPlrhXwYjEqCl/8n0SmWGZV8NFml5DPhMjKfv98GY=",
25
+ "qwen2vl_mrope.py": "3GExhYpLgB4VUtyZyjRk8XjEur3W4EWF6HQ67ML5vBU=",
26
+ "rms_norm.py": "GLzIZjDP74QxaeKQ5B/VDXKTGxD6Xo9cVaW/iqmsc4c=",
27
+ "rope.py": "v+7JHRrv+5ImoROkpKfl30WwWI4qTa2tAl7zQeB4ml4=",
28
+ "swiglu.py": "TLhyvpr7nbVbMqWbx8uz+iU2GxS6q0QrVxWAd1eQCBo=",
29
+ "tiled_mlp.py": "PJw2R8YdHHxQRSwbFJWjcHxgzssEqsRWqyogkY8pKR8=",
30
+ "tvd.py": "VbWUtpJ79E2atqjBoVyTSO785aS+idHiQBIrJwifDAw=",
31
+ "utils.py": "Y8wQsplz6ed7oPmBfX7yGGcX74VB3t/e5VFvYv/X7wU="
32
+ }
33
+ },
34
+ "provenance": {
35
+ "kernel-builder": {
36
+ "version": "0.17.0-dev0",
37
+ "sha": "81580bb92577f2f7228661ca2a221fc052375709",
38
+ "dirty": false
39
+ },
40
+ "kernel": {
41
+ "sha": "4d9f798b95ed280b770213048b8d3f41509d0c9e",
42
+ "dirty": false
43
+ }
44
  }
45
  }
build/torch-cuda/metadata.json.sigstore ADDED
@@ -0,0 +1 @@
 
 
1
+ {"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json","verificationMaterial":{"certificate":{"rawBytes":"MIIHSzCCBtCgAwIBAgIUIY1Kwpw1ln1fXvDyNdIoHzQ0GEQwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYwNzE0MTE1OTA3WhcNMjYwNzE0MTIwOTA3WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExWsk2F18NXh/g+v39PvCOt83WU6ZcC6CQ1e7DXAbxrYsqgMPsK29ahXv6RnnWwBkrvQRvnq6u/o0tBq27VuaiqOCBe8wggXrMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUMGdfASbZd1xeCeP+w5J3zceZ+oEwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wawYDVR0RAQH/BGEwX4ZdaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5Ly5naXRodWIvd29ya2Zsb3dzL2J1aWxkLnlhbWxAcmVmcy9oZWFkcy9tYWluMDkGCisGAQQBg78wAQEEK2h0dHBzOi8vdG9rZW4uYWN0aW9ucy5naXRodWJ1c2VyY29udGVudC5jb20wHwYKKwYBBAGDvzABAgQRd29ya2Zsb3dfZGlzcGF0Y2gwNgYKKwYBBAGDvzABAwQoNGQ5Zjc5OGI5NWVkMjgwYjc3MDIxMzA0OGI4ZDNmNDE1MDlkMGM5ZTATBgorBgEEAYO/MAEEBAVCdWlsZDArBgorBgEEAYO/MAEFBB1odWdnaW5nZmFjZS9rZXJuZWxzLWNvbW11bml0eTAdBgorBgEEAYO/MAEGBA9yZWZzL2hlYWRzL21haW4wOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tMG0GCisGAQQBg78wAQkEXwxdaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5Ly5naXRodWIvd29ya2Zsb3dzL2J1aWxkLnlhbWxAcmVmcy9oZWFkcy9tYWluMDgGCisGAQQBg78wAQoEKgwoNGQ5Zjc5OGI5NWVkMjgwYjc3MDIxMzA0OGI4ZDNmNDE1MDlkMGM5ZTAbBgorBgEEAYO/MAELBA0MC3NlbGYtaG9zdGVkMEAGCisGAQQBg78wAQwEMgwwaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5MDgGCisGAQQBg78wAQ0EKgwoNGQ5Zjc5OGI5NWVkMjgwYjc3MDIxMzA0OGI4ZDNmNDE1MDlkMGM5ZTAfBgorBgEEAYO/MAEOBBEMD3JlZnMvaGVhZHMvbWFpbjAaBgorBgEEAYO/MAEPBAwMCjEwNzE0NzU1MjkwLgYKKwYBBAGDvzABEAQgDB5odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2UwGAYKKwYBBAGDvzABEQQKDAgyNTcyMDc0MzBtBgorBgEEAYO/MAESBF8MXWh0dHBzOi8vZ2l0aHViLmNvbS9odWdnaW5nZmFjZS9rZXJuZWxzLWNvbW11bml0eS8uZ2l0aHViL3dvcmtmbG93cy9idWlsZC55YW1sQHJlZnMvaGVhZHMvbWFpbjA4BgorBgEEAYO/MAETBCoMKDRkOWY3OThiOTVlZDI4MGI3NzAyMTMwNDhiOGQzZjQxNTA5ZDBjOWUwIQYKKwYBBAGDvzABFAQTDBF3b3JrZmxvd19kaXNwYXRjaDBkBgorBgEEAYO/MAEVBFYMVGh0dHBzOi8vZ2l0aHViLmNvbS9odWdnaW5nZmFjZS9rZXJuZWxzLWNvbW11bml0eS9hY3Rpb25zL3J1bnMvMjkzMzA2MjM4NjUvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgMBnB1YmxpYzBGBgorBgEEAYO/MAEYBDgMNnJlcG86aHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHk6cmVmOnJlZnMvaGVhZHMvbWFpbjCBiQYKKwYBBAHWeQIEAgR7BHkAdwB1AN09MGrGxxEyYxkeHJlnNwKiSl643jyt/4eKcoAvKe6OAAABn2B+v4EAAAQDAEYwRAIgS0J+dgCFO8GkolLxpLdvSSe2HadB4+nYR3cSvV6oUWkCIAgau6hFzgTpx+2kKwa/ampZ2gDeNYZXD1RoxAsKIyF9MAoGCCqGSM49BAMDA2kAMGYCMQDF7yEhVN8mClCXQDdHjAc7S+w7XOApJlMDaYeyEjQ2J0oEj6Kie8XJSmRQHpuJkO4CMQDU5BtTp5FUKs7zuqkbkvA2+CYey1wQd9vjYOM96KwNwZWxEjHnnKSgBwQteSkBZ7w="},"tlogEntries":[{"logIndex":"2167844577","logId":{"keyId":"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="},"kindVersion":{"kind":"hashedrekord","version":"0.0.1"},"integratedTime":"1784030347","inclusionPromise":{"signedEntryTimestamp":"MEUCIAMiR8my1lRyXLZGGrVKeQBstBWpQZ51qj9FYkzHlKCyAiEA69xGRMRjKD7r1HVWg+fHimAFFTjMkz3PZgNXXl0+AUQ="},"inclusionProof":{"logIndex":"2045940315","rootHash":"myulnHdsTu/va/jsDduWqvHHfP1Bpz/gY5ASWc/vxLc=","treeSize":"2045940321","hashes":["ELPU1S59GnfBMIBqha3CDy8lRp2/UfhI9Ec14GZnsGc=","X+yhpzA31vS3BimZiPaRrAt1+TZCVDiVzX3Ba95EXBI=","VV1YHo726RTeHI4eDhHODulNVcENo4r9jpMRhiHkwAw=","TE+5oEe5ac7OQqO9brT+z6xPst7y8CQWiDgV+zzDbXI=","bHA0KCqwj96QF0bHdBKoFwsVQxc5vBpklhBiXnYJiaQ=","O+GMF6W3u/2gZ2keuQ8kFLbdfn5+iGqBOc3RNs2Cr54=","MUkgUqe8cc9LrfPi6/CeoxIcBig5OluD0n7ts3iQk78=","duwzzfwRIAv1hyLDk7Pw84ajqZB4l/R7mLum9W0K72w=","hluP9JseRAiMY+2slhjSksod6tVtp7e7HP7amn1KEaY=","sMaCrs8erYNQ48jT2FC56F0RAbpTkuSXZ+cs1zcSObw=","zGam2EiRYwS9IjemppqM/acVfU15hw3eAqn9Fb8+8vY=","qQGtNWYnFxNQ1OmqNBR2y92EFrgo5lyaKNQLaE/Dl1c=","/UAkaaq9D8BPMw5qLAxaf+ur4Sfbv3FfLWB2M/py3wM=","56+1wf4OgrBZEzfW9n13hPfm0bRvMRgerPv4TPE+3Ho=","mTSsSZdzVhRgljy9CvDq3GfjxxeOTHrwgpOWK4rRj3Q=","5sxNZDoxEj6DMmQATisX9bQXdFmeRHYfC8BjyDIIgec=","Rq/A2aTC9e54ldNjcpsJ26rX/h8JlN6ZHxgw7yEa6C0=","+/VZ56MsIPxMiyLAodzKXo5TEWdQp36z89qLhpzloAo=","daxmZaajRpZV+JxHiOYZhJBiSKN5ucqjh2WnGbHhirw=","DOCeoSMovIvLExkhIvisow9AuNXgeWs4ECkyR6EcqYU="],"checkpoint":{"envelope":"rekor.sigstore.dev - 1193050959916656506\n2045940321\nmyulnHdsTu/va/jsDduWqvHHfP1Bpz/gY5ASWc/vxLc=\n\n— rekor.sigstore.dev wNI9ajBFAiB5UZpMuWHHap4flwT77otDC4v44eb3znyf3RKYFvQoywIhAIcGfJ39B+ppsWE0EnZ0LC4Mk/1d7EhtDTrrupVhKN5G\n"}},"canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI5ZGE1ZjdkNGE1ZWRiMDdiYjJmMzJjM2M5NjU1NDFiYWNmZDQ2OWU4Y2Q5N2UyNzZiNWVhNDMwMDM0Mjk2MzA4In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUUMvanIxUmY1TisyQi95V1BDdHNCRCsyK0ZZNjNFalFMbWY3c2lWdE43emVnSWhBUFlrYmRaVmxCK3ZTZyt0NmF4V2hHSlRVZjZtUUtHUG1QaTBkYndmWk1UKyIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVaFRla05EUW5SRFowRjNTVUpCWjBsVlNWa3hTM2R3ZHpGc2JqRm1XSFpFZVU1a1NXOUllbEV3UjBWUmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFpkMDU2UlRCTlZFVXhUMVJCTTFkb1kwNU5hbGwzVG5wRk1FMVVTWGRQVkVFelYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVY0VjNOck1rWXhPRTVZYUM5bkszWXpPVkIyUTA5ME9ETlhWVFphWTBNMlExRXhaVGNLUkZoQlluaHlXWE54WjAxUWMwc3lPV0ZvV0hZMlVtNXVWM2RDYTNKMlVWSjJibkUyZFM5dk1IUkNjVEkzVm5WaGFYRlBRMEpsT0hkbloxaHlUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZOUjJSbUNrRlRZbHBrTVhobFEyVlFLM2MxU2pONlkyVmFLMjlGZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDJGM1dVUldVakJTUVZGSUwwSkhSWGRZTkZwa1lVaFNNR05JVFRaTWVUbHVZVmhTYjJSWFNYVlpNamwwVERKb01Wb3laSEJpYldSdFdWZE9iQXBNTW5Sc1kyMDFiR0pJVFhSWk1qbDBZbGhXZFdGWVVqVk1lVFZ1WVZoU2IyUlhTWFprTWpsNVlUSmFjMkl6WkhwTU1rb3hZVmQ0YTB4dWJHaGlWM2hCQ21OdFZtMWplVGx2V2xkR2EyTjVPWFJaVjJ4MVRVUnJSME5wYzBkQlVWRkNaemM0ZDBGUlJVVkxNbWd3WkVoQ2VrOXBPSFprUnpseVdsYzBkVmxYVGpBS1lWYzVkV041Tlc1aFdGSnZaRmRLTVdNeVZubFpNamwxWkVkV2RXUkROV3BpTWpCM1NIZFpTMHQzV1VKQ1FVZEVkbnBCUWtGblVWSmtNamw1WVRKYWN3cGlNMlJtV2tkc2VtTkhSakJaTW1kM1RtZFpTMHQzV1VKQ1FVZEVkbnBCUWtGM1VXOU9SMUUxV21wak5VOUhTVFZPVjFaclRXcG5kMWxxWXpOTlJFbDRDazE2UVRCUFIwazBXa1JPYlU1RVJURk5SR3hyVFVkTk5WcFVRVlJDWjI5eVFtZEZSVUZaVHk5TlFVVkZRa0ZXUTJSWGJITmFSRUZ5UW1kdmNrSm5SVVVLUVZsUEwwMUJSVVpDUWpGdlpGZGtibUZYTlc1YWJVWnFXbE01Y2xwWVNuVmFWM2g2VEZkT2RtSlhNVEZpYld3d1pWUkJaRUpuYjNKQ1owVkZRVmxQTHdwTlFVVkhRa0U1ZVZwWFducE1NbWhzV1ZkU2Vrd3lNV2hoVnpSM1QzZFpTMHQzV1VKQ1FVZEVkbnBCUWtOQlVYUkVRM1J2WkVoU2QyTjZiM1pNTTFKMkNtRXlWblZNYlVacVpFZHNkbUp1VFhWYU1td3dZVWhXYVdSWVRteGpiVTUyWW01U2JHSnVVWFZaTWpsMFRVY3dSME5wYzBkQlVWRkNaemM0ZDBGUmEwVUtXSGQ0WkdGSVVqQmpTRTAyVEhrNWJtRllVbTlrVjBsMVdUSTVkRXd5YURGYU1tUndZbTFrYlZsWFRteE1NblJzWTIwMWJHSklUWFJaTWpsMFlsaFdkUXBoV0ZJMVRIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTmlNMlI2VERKS01XRlhlR3RNYm14b1lsZDRRV050Vm0xamVUbHZXbGRHYTJONU9YUlpWMngxQ2sxRVowZERhWE5IUVZGUlFtYzNPSGRCVVc5RlMyZDNiMDVIVVRWYWFtTTFUMGRKTlU1WFZtdE5hbWQzV1dwak0wMUVTWGhOZWtFd1QwZEpORnBFVG0wS1RrUkZNVTFFYkd0TlIwMDFXbFJCWWtKbmIzSkNaMFZGUVZsUEwwMUJSVXhDUVRCTlF6Tk9iR0pIV1hSaFJ6bDZaRWRXYTAxRlFVZERhWE5IUVZGUlFncG5OemgzUVZGM1JVMW5kM2RoU0ZJd1kwaE5Oa3g1T1c1aFdGSnZaRmRKZFZreU9YUk1NbWd4V2pKa2NHSnRaRzFaVjA1c1RESjBiR050Tld4aVNFMTBDbGt5T1hSaVdGWjFZVmhTTlUxRVowZERhWE5IUVZGUlFtYzNPSGRCVVRCRlMyZDNiMDVIVVRWYWFtTTFUMGRKTlU1WFZtdE5hbWQzV1dwak0wMUVTWGdLVFhwQk1FOUhTVFJhUkU1dFRrUkZNVTFFYkd0TlIwMDFXbFJCWmtKbmIzSkNaMFZGUVZsUEwwMUJSVTlDUWtWTlJETktiRnB1VFhaaFIxWm9Xa2hOZGdwaVYwWndZbXBCWVVKbmIzSkNaMFZGUVZsUEwwMUJSVkJDUVhkTlEycEZkMDU2UlRCT2VsVXhUV3ByZDB4bldVdExkMWxDUWtGSFJIWjZRVUpGUVZGbkNrUkNOVzlrU0ZKM1kzcHZka3d5WkhCa1IyZ3hXV2sxYW1JeU1IWmhTRlp1V2pKc2RWb3lXbWhaTWxWM1IwRlpTMHQzV1VKQ1FVZEVkbnBCUWtWUlVVc0tSRUZuZVU1VVkzbE5SR013VFhwQ2RFSm5iM0pDWjBWRlFWbFBMMDFCUlZOQ1JqaE5XRmRvTUdSSVFucFBhVGgyV2pKc01HRklWbWxNYlU1MllsTTVid3BrVjJSdVlWYzFibHB0Um1wYVV6bHlXbGhLZFZwWGVIcE1WMDUyWWxjeE1XSnRiREJsVXpoMVdqSnNNR0ZJVm1sTU0yUjJZMjEwYldKSE9UTmplVGxwQ21SWGJITmFRelUxV1ZjeGMxRklTbXhhYmsxMllVZFdhRnBJVFhaaVYwWndZbXBCTkVKbmIzSkNaMFZGUVZsUEwwMUJSVlJDUTI5TlMwUlNhMDlYV1RNS1QxUm9hVTlVVm14YVJFazBUVWRKTTA1NlFYbE5WRTEzVGtSb2FVOUhVWHBhYWxGNFRsUkJOVnBFUW1wUFYxVjNTVkZaUzB0M1dVSkNRVWRFZG5wQlFncEdRVkZVUkVKR00ySXpTbkphYlhoMlpERTVhMkZZVG5kWldGSnFZVVJDYTBKbmIzSkNaMFZGUVZsUEwwMUJSVlpDUmxsTlZrZG9NR1JJUW5wUGFUaDJDbG95YkRCaFNGWnBURzFPZG1KVE9XOWtWMlJ1WVZjMWJscHRSbXBhVXpseVdsaEtkVnBYZUhwTVYwNTJZbGN4TVdKdGJEQmxVemxvV1ROU2NHSXlOWG9LVEROS01XSnVUWFpOYW10NlRYcEJNazFxVFRST2FsVjJXVmhTTUZwWE1YZGtTRTEyVFZSQlYwSm5iM0pDWjBWRlFWbFBMMDFCUlZkQ1FXZE5RbTVDTVFwWmJYaHdXWHBDUjBKbmIzSkNaMFZGUVZsUEwwMUJSVmxDUkdkTlRtNUtiR05IT0RaaFNGWnVXakpzZFZveVdtaFpNbFYyWVRKV2VXSnRWbk5qZVRGcUNtSXlNWFJrVnpWd1pFaHJObU50Vm0xUGJrcHNXbTVOZG1GSFZtaGFTRTEyWWxkR2NHSnFRMEpwVVZsTFMzZFpRa0pCU0ZkbFVVbEZRV2RTTjBKSWEwRUtaSGRDTVVGT01EbE5SM0pIZUhoRmVWbDRhMlZJU214dVRuZExhVk5zTmpRemFubDBMelJsUzJOdlFYWkxaVFpQUVVGQlFtNHlRaXQyTkVWQlFVRlJSQXBCUlZsM1VrRkpaMU13U2l0a1owTkdUemhIYTI5c1RIaHdUR1IyVTFObE1raGhaRUkwSzI1WlVqTmpVM1pXTm05VlYydERTVUZuWVhVMmFFWjZaMVJ3Q25nck1tdExkMkV2WVcxd1dqSm5SR1ZPV1ZwWVJERlNiM2hCYzB0SmVVWTVUVUZ2UjBORGNVZFRUVFE1UWtGTlJFRXlhMEZOUjFsRFRWRkVSamQ1UldnS1ZrNDRiVU5zUTFoUlJHUklha0ZqTjFNcmR6ZFlUMEZ3U214TlJHRlpaWGxGYWxFeVNqQnZSV28yUzJsbE9GaEtVMjFTVVVod2RVcHJUelJEVFZGRVZRbzFRblJVY0RWR1ZVdHpOM3AxY1d0aWEzWkJNaXREV1dWNU1YZFJaRGwyYWxsUFRUazJTM2RPZDFwWGVFVnFTRzV1UzFOblFuZFJkR1ZUYTBKYU4zYzlDaTB0TFMwdFJVNUVJRU5GVWxSSlJrbERRVlJGTFMwdExTMEsifX19fQ=="}],"timestampVerificationData":{"rfc3161Timestamps":[{"signedTimestamp":"MIICyTADAgEAMIICwAYJKoZIhvcNAQcCoIICsTCCAq0CAQMxDTALBglghkgBZQMEAgEwgbcGCyqGSIb3DQEJEAEEoIGnBIGkMIGhAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQggMo3oHJOCf2rmunccY1LDtaPk2BaAsvKlblZ5XQkUewCFCWorMsrsn3R/LTbLd8stC67Y9fFGA8yMDI2MDcxNDExNTkwN1owAwIBAaAypDAwLjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MRUwEwYDVQQDEwxzaWdzdG9yZS10c2GgADGCAdswggHXAgEBMFEwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZAIUOhNULwyQYe68wUMvy4qOiyojiwwwCwYJYIZIAWUDBAIBoIH8MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYwNzE0MTE1OTA3WjAvBgkqhkiG9w0BCQQxIgQg1mMvEx741OS29qLX+LwHA1kZBWUUE05jIoWjUwZHRuUwgY4GCyqGSIb3DQEJEAIvMX8wfTB7MHkEIIX5J7wHq2LKw7RDVsEO/IGyxog/2nq55thw2dE6zQW3MFUwPaQ7MDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFDoTVC8MkGHuvMFDL8uKjosqI4sMMAoGCCqGSM49BAMCBGcwZQIxAKnVMkqUShIQdAg6Le33DsY1YfYGVVik24mONsCazZ3A4u2wX0rRnay2rJ0dzH4g8wIwS3H6kXBIDgpF6uGM0CWEDtrF4+ZII4RYd5rFENiTVQmhCVMlpCpH1JFHuVgfzlO3"}]}},"messageSignature":{"messageDigest":{"algorithm":"SHA2_256","digest":"naX31KXtsHuy8yw8llVBus/UaejNl+J2tepDADQpYwg="},"signature":"MEYCIQC/jr1Rf5N+2B/yWPCtsBD+2+FY63EjQLmf7siVtN7zegIhAPYkbdZVlB+vSg+t6axWhGJTUf6mQKGPmPi0dbwfZMT+"}}
build/torch-cuda/tiled_mlp.py CHANGED
@@ -5,6 +5,7 @@ from typing import List
5
  from typing import Optional
6
 
7
  import torch
 
8
 
9
  from .utils import ensure_contiguous
10
 
@@ -44,6 +45,7 @@ class LigerTiledMLPFunction(torch.autograd.Function):
44
  ctx.fn = fn
45
  ctx.mlp_module = mlp_module
46
  ctx.shards = shards
 
47
  ctx.save_for_backward(x)
48
 
49
  # x.shape could be [bs, seqlen, hidden_size] or [seqlen, hidden_size] (moe experts)
@@ -61,22 +63,33 @@ class LigerTiledMLPFunction(torch.autograd.Function):
61
  (x,) = ctx.saved_tensors
62
  mlp_module = ctx.mlp_module
63
  shards = ctx.shards
 
 
 
64
 
65
  x_requires_grad = x.requires_grad
66
  x = x.detach()
67
  # detach() unsets x.requires_grad, so restore it
68
  x.requires_grad_(x_requires_grad)
69
 
70
- # x.shape could be [bs, seqlen, hidden_size] or [seqlen, hidden_size] (moe experts)
71
- hidden_size = x.shape[-1]
 
72
  x_shape_orig = x.shape
73
 
74
  # flatten bs+seqlen to avoid having stride issues when narrowing into seqlen w/ bs>1
75
- x = x.view(-1, hidden_size)
76
- incoming_grad = grads[0].view(-1, hidden_size)
 
 
77
  x_grad = torch.zeros_like(x)
78
 
79
  x_shards = list(torch.chunk(x, chunks=shards, dim=0))
 
 
 
 
 
80
 
81
  for i, x_shard in enumerate(x_shards):
82
  x_shard.requires_grad_(x_requires_grad)
@@ -86,7 +99,12 @@ class LigerTiledMLPFunction(torch.autograd.Function):
86
  shard_offset = i * x_shards[0].shape[0]
87
 
88
  x_shard.grad = x_grad.narrow(0, shard_offset, shard_step).view_as(x_shard)
89
- incoming_grad_shard = incoming_grad.narrow(0, shard_offset, shard_step).view_as(x_shard)
 
 
 
 
 
90
 
91
  with torch.enable_grad():
92
  output = fn(mlp_module, x_shard)
@@ -114,9 +132,6 @@ def apply_tiled_mlp(
114
  x: the input tensor with shape [bs, seqlen, hidden_size] or [seqlen, hidden_size]
115
  num_shards: number of shards to use. If None, automatically calculated as ceil(seqlen / hidden_size)
116
  compute_params: list of parameters for DeepSpeed ZeRO optimization
117
-
118
- Returns:
119
- output tensor with the same shape as input
120
  """
121
  if num_shards is None:
122
  # x.shape could be [bs, seqlen, hidden_size] or [seqlen, hidden_size]
@@ -127,6 +142,14 @@ def apply_tiled_mlp(
127
  # Ensure num_shards is at least 1
128
  num_shards = max(1, num_shards)
129
 
 
 
 
 
 
 
 
 
130
  return LigerTiledMLPFunction.apply(
131
  fn,
132
  mlp_module,
 
5
  from typing import Optional
6
 
7
  import torch
8
+ import torch.distributed as dist
9
 
10
  from .utils import ensure_contiguous
11
 
 
45
  ctx.fn = fn
46
  ctx.mlp_module = mlp_module
47
  ctx.shards = shards
48
+ ctx.compute_params = compute_params
49
  ctx.save_for_backward(x)
50
 
51
  # x.shape could be [bs, seqlen, hidden_size] or [seqlen, hidden_size] (moe experts)
 
63
  (x,) = ctx.saved_tensors
64
  mlp_module = ctx.mlp_module
65
  shards = ctx.shards
66
+ compute_params = ctx.compute_params
67
+
68
+ grad_output = grads[0]
69
 
70
  x_requires_grad = x.requires_grad
71
  x = x.detach()
72
  # detach() unsets x.requires_grad, so restore it
73
  x.requires_grad_(x_requires_grad)
74
 
75
+ # x.shape could be [bs, seqlen, in_features] or [seqlen, in_features] (moe experts)
76
+ in_features = x.shape[-1]
77
+ out_features = grad_output.shape[-1]
78
  x_shape_orig = x.shape
79
 
80
  # flatten bs+seqlen to avoid having stride issues when narrowing into seqlen w/ bs>1
81
+ # NOTE: input and output feature dimensions may differ, e.g.
82
+ # Linear(in_features, out_features), so flatten x and grad_output with their own last dims.
83
+ x = x.view(-1, in_features)
84
+ incoming_grad = grad_output.view(-1, out_features)
85
  x_grad = torch.zeros_like(x)
86
 
87
  x_shards = list(torch.chunk(x, chunks=shards, dim=0))
88
+ incoming_grad_shards = list(torch.chunk(incoming_grad, chunks=shards, dim=0))
89
+
90
+ # ZeRO-3 partitioned parameters carry a ds_id; collect them once so the per-shard loop only
91
+ # flips the ready flag. Parameters on other backends have no ds_id and are left untouched.
92
+ ds_params = [p for p in compute_params if hasattr(p, "ds_id")] if compute_params else []
93
 
94
  for i, x_shard in enumerate(x_shards):
95
  x_shard.requires_grad_(x_requires_grad)
 
99
  shard_offset = i * x_shards[0].shape[0]
100
 
101
  x_shard.grad = x_grad.narrow(0, shard_offset, shard_step).view_as(x_shard)
102
+ incoming_grad_shard = incoming_grad_shards[i]
103
+
104
+ # Defer DeepSpeed's reduction until the last shard has accumulated into param.grad; the flag
105
+ # is read by ZeRO's hook during each shard's backward, so it must be set per shard.
106
+ for param in ds_params:
107
+ param.ds_grad_is_ready = i + 1 == len(x_shards)
108
 
109
  with torch.enable_grad():
110
  output = fn(mlp_module, x_shard)
 
132
  x: the input tensor with shape [bs, seqlen, hidden_size] or [seqlen, hidden_size]
133
  num_shards: number of shards to use. If None, automatically calculated as ceil(seqlen / hidden_size)
134
  compute_params: list of parameters for DeepSpeed ZeRO optimization
 
 
 
135
  """
136
  if num_shards is None:
137
  # x.shape could be [bs, seqlen, hidden_size] or [seqlen, hidden_size]
 
142
  # Ensure num_shards is at least 1
143
  num_shards = max(1, num_shards)
144
 
145
+ # All ranks must run the same number of shards: a sharded-parameter backend (DeepSpeed ZeRO-3, FSDP)
146
+ # gathers weights inside each shard's recompute, so a rank that runs fewer shards stops participating
147
+ # in those collectives and deadlocks the others. Harmonize on the per-rank maximum.
148
+ if dist.is_available() and dist.is_initialized() and dist.get_world_size() > 1:
149
+ num_shards_tensor = torch.tensor(num_shards, device=x.device)
150
+ dist.all_reduce(num_shards_tensor, op=dist.ReduceOp.MAX)
151
+ num_shards = int(num_shards_tensor.item())
152
+
153
  return LigerTiledMLPFunction.apply(
154
  fn,
155
  mlp_module,
build/torch-rocm/__init__.py DELETED
@@ -1,4 +0,0 @@
1
- from . import layers
2
- from .layers import CrossEntropyOutput, LigerForCausalLMLoss
3
-
4
- __all__ = ["layers", "LigerForCausalLMLoss", "CrossEntropyOutput"]
 
 
 
 
 
build/torch-rocm/_ops.py DELETED
@@ -1,38 +0,0 @@
1
- import torch
2
-
3
- def get_backend() -> str:
4
- """Detect the backend by inspecting torch."""
5
- import torch
6
-
7
- if hasattr(torch, "neuron"):
8
- # Needs to be sorted before specific Torch builds, since Neuron
9
- # extension can be loaded into e.g. CUDA Torch builds.
10
- return "neuron"
11
- elif torch.version.cuda is not None:
12
- return "cuda"
13
- elif torch.version.hip is not None:
14
- return "rocm"
15
- elif torch.backends.mps.is_available():
16
- return "metal"
17
- elif hasattr(torch.version, "xpu") and torch.version.xpu is not None:
18
- return "xpu"
19
- else:
20
- return "cpu"
21
-
22
-
23
- def _find_ops_name() -> str:
24
- kernel_name = "liger_kernels"
25
- unique_id = "ab435e2"
26
- backend = get_backend()
27
- return f"_{kernel_name}_{backend}_{unique_id}"
28
-
29
-
30
- _OPS_NAME = _find_ops_name()
31
-
32
- ops = getattr(torch.ops, _OPS_NAME)
33
-
34
- def add_op_namespace_prefix(op_name: str) -> str:
35
- """
36
- Prefix op by namespace.
37
- """
38
- return f"{_OPS_NAME}::{op_name}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/cross_entropy.py DELETED
@@ -1,558 +0,0 @@
1
- import operator
2
-
3
- from typing import Optional
4
-
5
- import torch
6
- import triton
7
- import triton.language as tl
8
-
9
- from .utils import compare_version
10
- from .utils import element_mul_kernel
11
- from .utils import is_hip
12
- from .utils import infer_device
13
- from .utils import is_npu_available
14
-
15
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
16
- try:
17
- # typical import path with dispatch available
18
- from triton.language.extra.libdevice import tanh
19
- except ModuleNotFoundError:
20
- # for working with NGC containers
21
- from triton.language.extra.cuda.libdevice import tanh
22
- else:
23
- from triton.language.math import tanh
24
-
25
-
26
- @triton.jit
27
- def liger_cross_entropy_kernel(
28
- X_ptr,
29
- X_stride,
30
- Y_ptr,
31
- Y_stride,
32
- weight_ptr,
33
- loss_ptr,
34
- z_loss_ptr,
35
- loss_stride,
36
- token_accuracy_ptr,
37
- token_accuracy_stride,
38
- predicted_tokens_ptr,
39
- predicted_tokens_stride,
40
- n_cols,
41
- n_non_ignore,
42
- sum_non_ignore_weight,
43
- weight_sum,
44
- ignore_index,
45
- lse_square_scale: tl.constexpr,
46
- label_smoothing: tl.constexpr,
47
- reduction: tl.constexpr, # set it as constexpr since reduction is always known at compile time
48
- softcap,
49
- RETURN_Z_LOSS: tl.constexpr,
50
- RETURN_TOKEN_ACCURACY: tl.constexpr,
51
- RETURN_PREDICTED_TOKENS: tl.constexpr,
52
- BLOCK_SIZE: tl.constexpr,
53
- HAS_WEIGHT: tl.constexpr,
54
- HAS_SOFTCAPPING: tl.constexpr,
55
- HAS_GRADIENTS: tl.constexpr,
56
- ):
57
- """
58
- This kernel computes both cross entropy loss and the gradient of the input.
59
- We only consider hard label + mean reduction for now. Please refer to https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html for the math.
60
-
61
- Parameters:
62
- X_ptr: Pointer to input tensor.
63
- X_stride (int): The stride of the input tensor.
64
- Y_ptr: Pointer to target tensor.
65
- Y_stride (int): The stride of the target tensor.
66
- weight_ptr: Pointer to weight tensor.
67
- loss_ptr: Pointer to tensor to store the loss.
68
- z_loss_ptr: Pointer to tensor to store the z loss. No operation if RETURN_Z_LOSS is 0.
69
- loss_stride (int): The stride of the loss tensor.
70
- token_accuracy_ptr: Pointer to tensor to store the per-token accuracy. No operation if RETURN_TOKEN_ACCURACY is 0.
71
- token_accuracy_stride (int): The stride of the token accuracy tensor.
72
- n_cols (int): The number of columns in the input tensor.
73
- n_non_ignore (float): The number of non-ignored elements in the batch.
74
- sum_non_ignore_weight (float): The sum of non-ignored target's weights in the batch.
75
- weight_sum (float): The sum of weight tensor.
76
- ignore_index (int): The index to ignore in the target.
77
- label_smoothing (float): The amount of smoothing when computing the loss, where 0.0 means no smoothing.
78
- lse_square_scale (float): The scaler of (logsumexp(_input)) ^ 2 adding to the loss for the stability of training.
79
- reduction (str): The string for the reduction to apply
80
- softcap (float): The upper threshold for scaling logits to the range (-softcap, +softcap).
81
- RETURN_Z_LOSS (int): The boolean value to decide whether to store z loss to z_loss_ptr or not. It must be 0 or 1.
82
- RETURN_TOKEN_ACCURACY (int): The boolean value to decide whether to store per-token accuracy to token_accuracy_ptr or not. It must be 0 or 1.
83
- BLOCK_SIZE (int): The block size for Triton operations.
84
- HAS_WEIGHT (bool): The boolean value to determine whether assigning weight to each of the classes.
85
- HAS_SOFTCAPPING (bool): The boolean value to determine whether applying soft-capping or not.
86
- HAS_GRADIENTS (bool): The boolean value to determine whether calculating gradients in forward pass.
87
- """
88
-
89
- # https://github.com/triton-lang/triton/issues/1058
90
- # If B*T*V is too large, program_id * stride will overflow out of int32, so we convert to int64
91
- program_id = tl.program_id(0).to(tl.int64)
92
-
93
- # 1. Load Y_ptr first because if the target is ignore_index, we can return right away
94
- Y_ptr += program_id * Y_stride
95
- y = tl.load(Y_ptr)
96
-
97
- # 2. locate the start index
98
- X_ptr += program_id * X_stride
99
-
100
- if y == ignore_index:
101
- # set all X_ptr as 0
102
- for i in range(0, n_cols, BLOCK_SIZE):
103
- X_offsets = i + tl.arange(0, BLOCK_SIZE)
104
- tl.store(X_ptr + X_offsets, 0.0, mask=X_offsets < n_cols)
105
- # For ignored tokens, set token accuracy to 0
106
- if RETURN_TOKEN_ACCURACY:
107
- token_accuracy_ptr += program_id * token_accuracy_stride
108
- tl.store(token_accuracy_ptr, 0.0)
109
- if RETURN_PREDICTED_TOKENS:
110
- predicted_tokens_ptr += program_id * predicted_tokens_stride
111
- tl.store(predicted_tokens_ptr, -1)
112
- return
113
-
114
- loss_ptr += program_id * loss_stride
115
- if RETURN_Z_LOSS:
116
- z_loss_ptr += program_id * loss_stride
117
- if RETURN_TOKEN_ACCURACY:
118
- token_accuracy_ptr += program_id * token_accuracy_stride
119
- if RETURN_PREDICTED_TOKENS:
120
- predicted_tokens_ptr += program_id * predicted_tokens_stride
121
-
122
- if HAS_WEIGHT:
123
- weight_y = tl.load(weight_ptr + y).cast(tl.float32)
124
-
125
- # Online softmax: 2 loads + 1 store (compared with 3 loads + 1 store for the safe softmax)
126
- # Refer to Algorithm 3 in the paper: https://arxiv.org/pdf/1805.02867
127
-
128
- # 3. [Online softmax] first pass: find max + sum
129
- m = float("-inf") # m is the max value. use the notation from the paper
130
- d = 0.0 # d is the sum. use the notation from the paper
131
- argmax_idx = 0 # Track the index of the maximum value for token accuracy / predicted tokens computation
132
- ori_X_y = tl.load(X_ptr + y).cast(tl.float32) # we need to store the original value of X_y for the loss calculation
133
- if HAS_SOFTCAPPING:
134
- ori_X_y = softcap * tanh(ori_X_y / softcap)
135
-
136
- # Label smoothing is a general case of normal cross entropy
137
- # See the full derivation at https://github.com/linkedin/Liger-Kernel/pull/198#issue-2503665310
138
- scaled_x_sum = 0.0
139
- eps = label_smoothing / n_cols
140
-
141
- for i in range(0, n_cols, BLOCK_SIZE):
142
- X_offsets = i + tl.arange(0, BLOCK_SIZE)
143
- X_block = tl.load(
144
- X_ptr + X_offsets,
145
- mask=X_offsets < n_cols,
146
- other=float("-inf"),
147
- # Ensure float32 precision for softmax calculation
148
- ).cast(tl.float32)
149
- if HAS_SOFTCAPPING:
150
- X_block = softcap * tanh(X_block / softcap)
151
- block_max = tl.max(X_block)
152
-
153
- # Track argmax for accuracy / predicted tokens computation
154
- if RETURN_TOKEN_ACCURACY or RETURN_PREDICTED_TOKENS:
155
- # Find the index of the maximum value in this block
156
- is_max_mask = X_block == block_max
157
- # Mask out invalid indices with a value larger than n_cols
158
- masked_offsets = tl.where(is_max_mask, X_offsets, n_cols)
159
- # Get the first (smallest) index where max occurs
160
- current_block_argmax_idx = tl.min(masked_offsets)
161
-
162
- is_new_max = block_max > m
163
- argmax_idx = tl.where(is_new_max, current_block_argmax_idx, argmax_idx)
164
-
165
- if label_smoothing > 0:
166
- # scale X beforehand to avoid overflow
167
- if HAS_WEIGHT:
168
- weight_block = tl.load(weight_ptr + X_offsets, mask=X_offsets < n_cols)
169
- scaled_x_sum += tl.sum(tl.where(X_offsets < n_cols, -eps * X_block * weight_block, 0.0))
170
- else:
171
- scaled_x_sum += tl.sum(tl.where(X_offsets < n_cols, -eps * X_block, 0.0))
172
- m_new = tl.maximum(m, block_max)
173
- d = d * tl.exp(m - m_new) + tl.sum(tl.exp(X_block - m_new))
174
- m = m_new
175
-
176
- # log (sum(e^(X_i))) = log (sum(e ^ (max(X) * e ^ (X_i - max(X)))))
177
- # = log (e^(max(X)) * sum(e ^ (X_i - max(X))))
178
- # = max(X) + log (sum(e ^ (X_i - max(X)))) = m + log d
179
- lse = m + tl.log(d)
180
-
181
- # 4. [Online Softmax] Second pass: compute gradients
182
- # For 'mean' reduction, gradients are normalized by number of non-ignored elements (N)
183
- # dx_y = (softmax(x_y) - 1) / N
184
- # dx_i = softmax(x_i) / N, i != y
185
- # For label smoothing:
186
- # dx_i = (softmax(x_i) - label_smoothing / V) / N, V = n_cols, i != y
187
- # dx_y = (softmax(x_y) - label_smoothing / V - (1 - label_smoothing)) / N
188
- # = dx_i - (1 - label_smoothing) / N
189
- # With Z loss:
190
- # dx_i = ((1 + 2 * lse_square_scale * lse) * softmax(x_i) - label_smoothing / V) / N, i != y
191
- # dx_y = dx_i - (1 - label_smoothing) / N
192
- # For 'sum' reduction, no normalization is applied:
193
- # dx_y = softmax(x_y) - 1
194
- # dx_i = softmax(x_i), for i ≠ y
195
- if HAS_GRADIENTS:
196
- for i in range(0, n_cols, BLOCK_SIZE):
197
- X_offsets = i + tl.arange(0, BLOCK_SIZE)
198
- X_block = tl.load(
199
- X_ptr + X_offsets,
200
- mask=X_offsets < n_cols,
201
- other=float("-inf"),
202
- # Ensure float32 precision for softmax calculation
203
- ).cast(tl.float32)
204
- if HAS_SOFTCAPPING:
205
- intermediate = tanh(X_block / softcap)
206
- X_block = softcap * intermediate
207
-
208
- if not HAS_WEIGHT:
209
- # softmax(x_i)
210
- X_block = tl.exp(X_block - m) / d
211
- # derivative of z-loss: 2 * lse_square_scale * lse * softmax(x_i)
212
- X_block += 2 * lse_square_scale * lse * X_block
213
- # smoothing term
214
- X_block += -eps
215
- # special handle dx_y
216
- X_block = tl.where(X_offsets != y, X_block, X_block - (1 - label_smoothing))
217
- # reduction scale
218
- if reduction == "mean":
219
- X_block = X_block / n_non_ignore
220
- else:
221
- weight_block = tl.load(weight_ptr + X_offsets, mask=X_offsets < n_cols)
222
- softmax_X = tl.exp(X_block - m) / d
223
- # derivative of original_loss
224
- dloss_ori = (1 - label_smoothing) * softmax_X
225
- # specially handle dx_y
226
- dloss_ori = tl.where(X_offsets != y, dloss_ori, dloss_ori - (1 - label_smoothing))
227
- dloss_ori = dloss_ori * weight_y
228
- # derivative of smooth_loss
229
- dloss_smooth = eps * (-weight_block + softmax_X * weight_sum)
230
- # derivative of z-loss
231
- dz_loss = 2 * lse_square_scale * lse * softmax_X
232
- # reduction scale
233
- if reduction == "mean":
234
- dloss_ori = dloss_ori / sum_non_ignore_weight
235
- dloss_smooth = dloss_smooth / sum_non_ignore_weight
236
- # TODO: Implement weighted z_loss. Currently, z_loss is not scaled by weight.
237
- dz_loss = dz_loss / n_non_ignore
238
- # derivative of total_loss
239
- X_block = dloss_ori + dloss_smooth + dz_loss
240
-
241
- # chain rule softcapping
242
- # d(softcap * tanh(x / softcap)) = (1 - tanh^2(x / softcap))
243
- if HAS_SOFTCAPPING:
244
- X_block = X_block * (1 - intermediate * intermediate)
245
-
246
- tl.store(X_ptr + X_offsets, X_block, mask=X_offsets < n_cols)
247
-
248
- # We need tl.debug_barrier() to ensure the new result of X_ptr is written as mentioned in
249
- # https://github.com/triton-lang/triton/blob/ba42a5c68fd0505f8c42f4202d53be0f8d9a5fe0/python/triton/ops/cross_entropy.py#L34
250
- tl.debug_barrier()
251
-
252
- # 5. Calculate the loss
253
-
254
- # loss = log (softmax(X_y)) = log ((e ^ (X_y - max(X)) / sum(e ^ (X - max(X))))
255
- # = (X_y - max(X)) - log(sum(e ^ (X - max(X))))
256
- # = X_y - m - log d = X_y - lse
257
- # sum(e ^ (X - max(X))) must >= 1 because the max term is e ^ 0 = 1
258
- # So we can safely calculate log (softmax(X_y)) without overflow
259
- loss = lse - ori_X_y
260
- if HAS_WEIGHT:
261
- loss = weight_y * loss
262
-
263
- # Original loss = H(q, p), with label smoothing regularization = H(q', p) and (label_smoothing / V) = eps
264
- # H(q', p) = (1 - label_smoothing) * H(q, p) + label_smoothing * H(u, p)
265
- # = (1 - label_smoothing) * H(q, p) + eps * sum(logsoftmax(x_i))
266
- # By using m (global max of xi) and d (sum of e^(xi-m)), we can simplify as:
267
- # = (1 - label_smoothing) * H(q, p) + (sum(-eps * x_i) + label_smoothing * (m + logd))
268
- # Refer to H(q', p) in section 7 of the paper: https://arxiv.org/pdf/1512.00567
269
- # pytorch: https://github.com/pytorch/pytorch/blob/2981534f54d49fa3a9755c9b0855e7929c2527f0/aten/src/ATen/native/LossNLL.cpp#L516
270
- # See full derivation at https://github.com/linkedin/Liger-Kernel/pull/198#issuecomment-2333753087
271
- if label_smoothing > 0:
272
- if HAS_WEIGHT:
273
- smooth_loss = scaled_x_sum + eps * lse * weight_sum
274
- else:
275
- smooth_loss = scaled_x_sum + label_smoothing * lse
276
- loss = loss * (1 - label_smoothing) + smooth_loss
277
-
278
- # An auxiliary loss, z_loss
279
- # Refer to Page14 Loss function section in the paper PaLM: https://www.jmlr.org/papers/v24/22-1144.html
280
- z_loss = lse_square_scale * lse * lse
281
- # Normalize the loss by the number of non-ignored elements if reduction is "mean"
282
- if reduction == "mean":
283
- if HAS_WEIGHT:
284
- loss = loss / sum_non_ignore_weight
285
- else:
286
- loss = loss / n_non_ignore
287
- # TODO: Implement weighted z_loss. Currently, z_loss is not scaled by weight.
288
- z_loss = z_loss / n_non_ignore
289
- loss += z_loss
290
-
291
- tl.store(loss_ptr, loss)
292
- if RETURN_Z_LOSS:
293
- tl.store(z_loss_ptr, z_loss)
294
- if RETURN_TOKEN_ACCURACY:
295
- # Store 1.0 if prediction is correct, 0.0 otherwise
296
- is_correct = 1.0 if argmax_idx == y else 0.0
297
- tl.store(token_accuracy_ptr, is_correct)
298
- if RETURN_PREDICTED_TOKENS:
299
- tl.store(predicted_tokens_ptr, argmax_idx)
300
-
301
-
302
- # The hard limit of TRITON_MAX_TENSOR_NUMEL is 1048576 https://github.com/triton-lang/triton/blob/ba42a5c68fd0505f8c42f4202d53be0f8d9a5fe0/python/triton/language/core.py#L19
303
- # However, setting limit as 65536 as in LayerNorm tutorial is faster because of less register spilling
304
- # The optimal maximum block size depends on your hardware, your kernel, and your dtype
305
- # the best size we found by manually tuning on xpu and npu.
306
- if infer_device() == "xpu":
307
- MAX_FUSED_SIZE = 4096
308
- elif infer_device() == "npu":
309
- MAX_FUSED_SIZE = 2048
310
- else:
311
- MAX_FUSED_SIZE = 65536 // 2
312
-
313
-
314
- def cross_entropy_forward(
315
- _input,
316
- target,
317
- weight,
318
- ignore_index,
319
- lse_square_scale,
320
- label_smoothing,
321
- reduction,
322
- softcap,
323
- return_z_loss,
324
- return_token_accuracy=False,
325
- return_predicted_tokens=False,
326
- ):
327
- assert isinstance(return_z_loss, bool), f"return_z_loss must be True or False. Got: {return_z_loss}"
328
- assert isinstance(return_token_accuracy, bool), (
329
- f"return_token_accuracy must be True or False. Got: {return_token_accuracy}"
330
- )
331
- assert isinstance(return_predicted_tokens, bool), (
332
- f"return_predicted_tokens must be True or False. Got: {return_predicted_tokens}"
333
- )
334
-
335
- BT, V = _input.shape
336
- n_rows = BT
337
-
338
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
339
-
340
- # unreduced loss
341
- loss_1d = torch.zeros(n_rows, dtype=_input.dtype, device=_input.device)
342
- z_loss_1d = torch.zeros(n_rows, dtype=_input.dtype, device=_input.device) if return_z_loss else None
343
- token_accuracy_1d = (
344
- torch.zeros(n_rows, dtype=torch.float32, device=_input.device) if return_token_accuracy else None
345
- )
346
- predicted_tokens_1d = (
347
- torch.full((n_rows,), -1, dtype=torch.int64, device=_input.device) if return_predicted_tokens else None
348
- )
349
-
350
- target_mask = target != ignore_index
351
- n_non_ignore = target_mask.sum().item()
352
- assert (target * target_mask).max() < _input.shape[-1], (
353
- f"Target {target.max()} is out of bounds. Expected < {_input.shape[-1]}"
354
- )
355
- assert (target * target_mask).min() >= 0, f"Target {target.min()} is out of bounds. Expected >= 0"
356
- sum_non_ignore_weight = n_non_ignore
357
- weight_sum = 0.0
358
- if weight is not None:
359
- assert weight.shape[0] == V, f"If given, weight has to be a Tensor of size V. Got: {weight.shape}"
360
- assert torch.is_floating_point(weight), (
361
- f"If given, weight has to be a Tensor of floating point dtype. Got: {weight.dtype}"
362
- )
363
- sum_non_ignore_weight = torch.gather(weight, dim=0, index=target.masked_select(target_mask)).sum().item()
364
- weight_sum = weight.sum().item()
365
- # ensure weight is contiguous
366
- if weight.stride(-1) != 1:
367
- weight = weight.contiguous()
368
-
369
- # ensure _input and target are contiguous in the last dimension
370
- if _input.stride(-1) != 1:
371
- _input = _input.contiguous()
372
- if target.stride(-1) != 1:
373
- target = target.contiguous()
374
-
375
- # Here we use a trick to store X_ptr gradient in X_ptr so we can save memory
376
- liger_cross_entropy_kernel[(n_rows,)](
377
- X_ptr=_input,
378
- X_stride=_input.stride(-2),
379
- Y_ptr=target,
380
- Y_stride=target.stride(-1), # always 1
381
- weight_ptr=weight, # dummy if None
382
- loss_ptr=loss_1d,
383
- z_loss_ptr=z_loss_1d,
384
- loss_stride=loss_1d.stride(-1), # always 1
385
- token_accuracy_ptr=token_accuracy_1d,
386
- token_accuracy_stride=token_accuracy_1d.stride(-1)
387
- if return_token_accuracy
388
- else 0, # always 1 if accuracy is enabled
389
- predicted_tokens_ptr=predicted_tokens_1d,
390
- predicted_tokens_stride=predicted_tokens_1d.stride(-1)
391
- if return_predicted_tokens
392
- else 0, # always 1 if predicted tokens is enabled
393
- n_cols=V,
394
- n_non_ignore=n_non_ignore,
395
- sum_non_ignore_weight=sum_non_ignore_weight,
396
- ignore_index=ignore_index,
397
- weight_sum=weight_sum,
398
- lse_square_scale=lse_square_scale,
399
- label_smoothing=label_smoothing,
400
- reduction=reduction,
401
- softcap=softcap,
402
- RETURN_Z_LOSS=return_z_loss,
403
- RETURN_TOKEN_ACCURACY=return_token_accuracy,
404
- RETURN_PREDICTED_TOKENS=return_predicted_tokens,
405
- BLOCK_SIZE=BLOCK_SIZE,
406
- HAS_WEIGHT=True if weight is not None else False,
407
- HAS_SOFTCAPPING=True if softcap is not None else False,
408
- HAS_GRADIENTS=_input.requires_grad,
409
- # TODO: 32 seems to give the best performance
410
- # Performance is quite sensitive to num_warps
411
- num_warps=32 if not is_hip() else 16,
412
- )
413
-
414
- if reduction == "none":
415
- loss = loss_1d
416
- z_loss = z_loss_1d if return_z_loss else None
417
- token_accuracy = token_accuracy_1d if return_token_accuracy else None
418
- else:
419
- loss = torch.sum(loss_1d)
420
- z_loss = torch.sum(z_loss_1d) if return_z_loss else None
421
- # For accuracy, we compute the mean across all non-ignored tokens
422
- token_accuracy = torch.sum(token_accuracy_1d) / n_non_ignore if return_token_accuracy else None
423
-
424
- predicted_tokens = predicted_tokens_1d if return_predicted_tokens else None
425
-
426
- return loss, z_loss, token_accuracy, predicted_tokens, _input
427
-
428
-
429
- def cross_entropy_backward(_input, grad_output):
430
- # If cross entropy is the last layer, grad_output is 1.0. Skip the mul to save time
431
- if torch.equal(grad_output, torch.tensor(1.0, device=grad_output.device)):
432
- pass
433
- # If reduction is 'none'
434
- elif grad_output.ndim > 0:
435
- _input = _input * grad_output.unsqueeze(dim=1)
436
- # If reduction is ['mean', 'sum'], grad_output is just a scalar
437
- # We use a Triton kernel instead of a PyTorch operation because modifying inputs in-place
438
- # for gradient storage and backward multiple times causes anomalies with PyTorch but not with Triton.
439
- else:
440
- BT, V = _input.shape
441
- n_rows = BT
442
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
443
-
444
- element_mul_kernel[(n_rows,)](
445
- _input,
446
- _input.stride(-2),
447
- grad_output,
448
- V,
449
- BLOCK_SIZE=BLOCK_SIZE,
450
- num_warps=32 if not is_hip() else 16,
451
- )
452
-
453
- return _input
454
-
455
-
456
- class LigerCrossEntropyFunction(torch.autograd.Function):
457
- """
458
- This class implements a custom autograd function for the Liger Cross Entropy loss.
459
- It overrides the forward and backward methods of the torch.autograd.Function class.
460
- """
461
-
462
- @staticmethod
463
- def forward(
464
- ctx,
465
- _input: torch.Tensor,
466
- target: torch.Tensor,
467
- weight: Optional[torch.FloatTensor],
468
- ignore_index: int = -100,
469
- lse_square_scale: float = 0.0,
470
- label_smoothing: float = 0.0,
471
- reduction: str = "mean",
472
- softcap: Optional[float] = None,
473
- return_z_loss: bool = False,
474
- return_token_accuracy: bool = False,
475
- return_predicted_tokens: bool = False,
476
- ):
477
- """
478
- The forward pass of the Liger Cross Entropy loss.
479
-
480
- Parameters:
481
- ctx : The context object.
482
- _input (tensor): The input tensor of shape (BT, V) where B is batch size, T is sequence length, V is vocab size.
483
- target (tensor): The target tensor of shape (BT) where each value is in [0, V-1].
484
- weight(Tensor, optional): a manual rescaling weight given to each class. If given, has to be a Tensor of size V and floating point dtype
485
- ignore_index (int): The index to ignore in the target.
486
- lse_square_scale (float): The scaler of (logsumexp(_input)) ^ 2 adding to the loss for the stability of training.
487
- label_smoothing (float): The amount of smoothing when computing the loss, where 0.0 means no smoothing.
488
- reduction (str): The reduction to apply to the output: "none" | "mean | "sum".
489
- softcap (Optional[float]): The upper threshold for scaling logits to the range (-softcap, +softcap).
490
- return_z_loss (bool): When `return_z_loss` is `True`, returns (loss, z_loss, token_accuracy, predicted_tokens) instead of (loss, None, None, None). Default: `False`
491
- return_token_accuracy (bool): When `return_token_accuracy` is `True`, computes and returns per-token accuracy without materializing logits. Default: `False`
492
- return_predicted_tokens (bool): When `return_predicted_tokens` is `True`, returns per-token predicted class indices (argmax) without materializing logits. Default: `False`
493
-
494
- Returns:
495
- tuple: A tuple with the computed losses, accuracy, and predicted tokens: (loss, z_loss, token_accuracy, predicted_tokens). z_loss, token_accuracy, and predicted_tokens are None if not requested.
496
- """
497
- input_requires_grad = _input.requires_grad
498
-
499
- loss, z_loss, token_accuracy, predicted_tokens, _input = cross_entropy_forward(
500
- _input,
501
- target,
502
- weight,
503
- ignore_index,
504
- lse_square_scale,
505
- label_smoothing,
506
- reduction,
507
- softcap,
508
- return_z_loss,
509
- return_token_accuracy,
510
- return_predicted_tokens,
511
- )
512
- # TODO: investigation
513
- # If we don't detach the _input tensor, the memory will double
514
- # Not sure why but seems that there will be a time both grad and value exist but in different location
515
- if input_requires_grad:
516
- ctx.save_for_backward(_input.detach())
517
- ctx.return_z_loss = return_z_loss
518
- ctx.return_token_accuracy = return_token_accuracy
519
- ctx.return_predicted_tokens = return_predicted_tokens
520
-
521
- return loss, z_loss, token_accuracy, predicted_tokens
522
-
523
- @staticmethod
524
- def backward(ctx, grad_output, grad_output2, grad_output3, grad_output4):
525
- """
526
- The backward pass of the Liger Cross Entropy loss.
527
-
528
- Parameters:
529
- ctx : The context object with saved tensors.
530
- grad_output (tensor): The tensor containing the gradient of the loss with respect to the output.
531
- grad_output2 (tensor): No use. Gradient for z_loss (not used as z_loss is only for logging).
532
- grad_output3 (tensor): No use. Gradient for token_accuracy (not used as token_accuracy is only for metrics).
533
- grad_output4 (tensor): No use. Gradient for predicted_tokens (not used as predicted_tokens is only for metrics).
534
- Returns:
535
- tuple: A tuple with the gradients with respect to the inputs. The elements are tensors or None.
536
- """
537
- if ctx.return_z_loss:
538
- del grad_output2 # z_loss is only for logging
539
- if ctx.return_token_accuracy:
540
- del grad_output3 # token_accuracy is only for metrics
541
- if ctx.return_predicted_tokens:
542
- del grad_output4 # predicted_tokens is only for metrics
543
-
544
- (_input,) = ctx.saved_tensors
545
- _input = cross_entropy_backward(_input, grad_output)
546
- return (
547
- _input,
548
- None,
549
- None,
550
- None,
551
- None,
552
- None,
553
- None,
554
- None,
555
- None,
556
- None,
557
- None,
558
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/dyt.py DELETED
@@ -1,164 +0,0 @@
1
- import operator
2
-
3
- import torch
4
- import triton
5
- import triton.language as tl
6
-
7
- from .utils import compare_version
8
- from .utils import ensure_contiguous
9
- from .utils import get_npu_core_count
10
- from .utils import infer_device
11
- from .utils import is_npu_available
12
-
13
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
14
- try:
15
- # typical import path with dispatch available
16
- from triton.language.extra.libdevice import tanh
17
- except ModuleNotFoundError:
18
- # for working with NGC containers
19
- from triton.language.extra.cuda.libdevice import tanh
20
- else:
21
- from triton.language.math import tanh
22
-
23
-
24
- @triton.autotune(
25
- configs=[
26
- triton.Config({"BLOCK_N": bn}, num_stages=ns, num_warps=nw)
27
- for bn in [1024, 2048, 4096]
28
- for ns in [1, 2]
29
- for nw in [4, 8, 16]
30
- ],
31
- key=["N"],
32
- )
33
- @triton.jit
34
- def _dyt_fwd_kernel(X, Y, Alpha, Gamma, Beta, HAVE_BETA: tl.constexpr, N: tl.constexpr, BLOCK_N: tl.constexpr):
35
- col = tl.cast(tl.program_id(0), tl.int64) * BLOCK_N + tl.arange(0, BLOCK_N)
36
- mask = col < N
37
- row_id = tl.cast(tl.program_id(1), tl.int64)
38
-
39
- X += row_id * N
40
- Y += row_id * N
41
- alpha = tl.load(Alpha).to(tl.float32)
42
-
43
- gamma = tl.load(Gamma + col, mask=mask, other=0.0).to(tl.float32)
44
-
45
- x = tl.load(X + col, mask=mask, other=0.0).to(tl.float32)
46
-
47
- tanh_x = tanh(alpha * x)
48
- y = tanh_x * gamma
49
- if HAVE_BETA:
50
- beta = tl.load(Beta + col, mask=mask, other=0.0).to(tl.float32)
51
- y += beta
52
- tl.store(Y + col, y, mask=mask)
53
-
54
-
55
- @triton.autotune(
56
- configs=[
57
- triton.Config({"BLOCK_N": bn}, num_stages=ns, num_warps=nw)
58
- for bn in [1024, 2048, 4096]
59
- for ns in [1, 2]
60
- for nw in [4, 8, 16]
61
- ],
62
- key=["N"],
63
- # DA is indexed by program_id(0), so different BLOCK_N configs write to
64
- # different slot counts per SM. Autotune trials don't zero outputs between
65
- # runs, so stale slots from a prior trial would leak into da.sum(). Reset
66
- # DA between trials to isolate each config's writes.
67
- reset_to_zero=["DA"],
68
- )
69
- @triton.jit
70
- def _dyt_bwd_kernel(
71
- DY, DX, DA, DG, DB, X, Alpha, Gamma, HAVE_BETA: tl.constexpr, M, N: tl.constexpr, BLOCK_N: tl.constexpr
72
- ):
73
- col = tl.cast(tl.program_id(0), tl.int64) * BLOCK_N + tl.arange(0, BLOCK_N)
74
- mask = col < N
75
- start_row_id = tl.cast(tl.program_id(1), tl.int64)
76
-
77
- alpha = tl.load(Alpha).to(tl.float32)
78
- da = 0.0
79
- gamma = tl.load(Gamma + col, mask=mask, other=0.0).to(tl.float32)
80
- dg = tl.zeros((BLOCK_N,), dtype=tl.float32)
81
- if HAVE_BETA:
82
- db = tl.zeros((BLOCK_N,), dtype=tl.float32)
83
- for row_id in range(start_row_id, M, tl.num_programs(1)):
84
- x = tl.load(X + row_id * N + col, mask=mask, other=0.0).to(tl.float32)
85
- dy = tl.load(DY + row_id * N + col, mask=mask, other=0.0).to(tl.float32)
86
- tanh_x = tanh(alpha * x)
87
- if HAVE_BETA:
88
- db += dy
89
- dg += dy * tanh_x
90
- tmp = (1 - tanh_x * tanh_x) * dy * gamma
91
- da += tl.sum(x * tmp, 0)
92
- dx = alpha * tmp
93
- tl.store(DX + row_id * N + col, dx, mask=mask)
94
-
95
- tl.store(DG + start_row_id * N + col, dg, mask=mask)
96
- if HAVE_BETA:
97
- tl.store(DB + start_row_id * N + col, db, mask=mask)
98
- tl.store(DA + start_row_id * tl.cdiv(N, 512) + tl.program_id(0), da)
99
-
100
-
101
- def liger_dyt_fwd(x, alpha, gamma, beta):
102
- assert x.is_contiguous()
103
- HAVE_BETA = True if beta is not None else False
104
- input_shape = x.shape
105
- x = x.view(-1, input_shape[-1])
106
- M, N = x.shape
107
-
108
- y = torch.empty_like(x)
109
-
110
- grid = lambda meta: (triton.cdiv(N, meta["BLOCK_N"]), M)
111
- _dyt_fwd_kernel[grid](
112
- x,
113
- y,
114
- alpha,
115
- gamma,
116
- beta,
117
- HAVE_BETA,
118
- N,
119
- )
120
- return y.view(input_shape)
121
-
122
-
123
- def liger_dyt_bwd(dy, x, alpha, gamma, beta):
124
- assert dy.is_contiguous()
125
- input_shape = x.shape
126
- x = x.view(-1, input_shape[-1])
127
- M, N = x.shape
128
- HAVE_BETA = True if beta is not None else False
129
-
130
- device = infer_device()
131
- if device == "cuda":
132
- NUM_SMS = torch.cuda.get_device_properties(x.device).multi_processor_count
133
- elif device == "xpu":
134
- NUM_SMS = torch.xpu.get_device_properties(x.device).gpu_subslice_count
135
- elif device == "npu":
136
- NUM_SMS = get_npu_core_count()
137
- da = torch.zeros(NUM_SMS, triton.cdiv(N, 512), dtype=torch.float32, device=x.device)
138
- dg = torch.empty(NUM_SMS, N, dtype=torch.float32, device=x.device)
139
- db = torch.empty(NUM_SMS, N, dtype=torch.float32, device=x.device) if HAVE_BETA else None
140
- dx = torch.empty_like(dy)
141
-
142
- grid = lambda meta: (triton.cdiv(N, meta["BLOCK_N"]), NUM_SMS)
143
- _dyt_bwd_kernel[grid](dy, dx, da, dg, db, x, alpha, gamma, HAVE_BETA, M, N)
144
- if HAVE_BETA:
145
- db = db.sum(0).to(x.dtype)
146
- dg = dg.sum(0).to(gamma.dtype)
147
- da = da.sum().to(x.dtype).unsqueeze(0)
148
- return dx.view(input_shape), da, dg, db
149
-
150
-
151
- class LigerDyTFunction(torch.autograd.Function):
152
- @staticmethod
153
- @ensure_contiguous
154
- def forward(ctx, x, alpha, gamma, beta):
155
- y = liger_dyt_fwd(x, alpha, gamma, beta)
156
- ctx.save_for_backward(x, alpha, gamma, beta)
157
- return y
158
-
159
- @staticmethod
160
- @ensure_contiguous
161
- def backward(ctx, dy):
162
- x, alpha, gamma, beta = ctx.saved_tensors
163
- dx, dalpha, dgamma, dbeta = liger_dyt_bwd(dy, x, alpha, gamma, beta)
164
- return dx, dalpha, dgamma, dbeta
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/fused_linear_cross_entropy.py DELETED
@@ -1,400 +0,0 @@
1
- import torch
2
- import triton
3
-
4
- from .cross_entropy import liger_cross_entropy_kernel
5
- from .utils import amp_custom_bwd
6
- from .utils import amp_custom_fwd
7
- from .utils import element_mul_kernel
8
- from .utils import is_hip
9
- from .utils import infer_device
10
-
11
- # The hard limit of TRITON_MAX_TENSOR_NUMEL is 1048576 https://github.com/triton-lang/triton/blob/ba42a5c68fd0505f8c42f4202d53be0f8d9a5fe0/python/triton/language/core.py#L19
12
- # However, setting limit as 65536 as in LayerNorm tutorial is faster because of less register spilling
13
- # The optimal maximum block size depends on your hardware, your kernel, and your dtype
14
- MAX_FUSED_SIZE = 2048 if infer_device() == "npu" else 65536 // 2
15
-
16
-
17
- def fused_linear_cross_entropy_forward(
18
- _input,
19
- weight,
20
- target,
21
- ce_weight=None,
22
- bias=None,
23
- ignore_index=-100,
24
- lse_square_scale=0.0,
25
- label_smoothing=0.0,
26
- reduction="mean",
27
- softcap=None,
28
- return_z_loss=False,
29
- accum_dtype=None,
30
- use_token_scaling=False,
31
- return_token_accuracy=False,
32
- return_predicted_tokens=False,
33
- ):
34
- assert isinstance(return_z_loss, bool), f"return_z_loss must be True or False. Got: {return_z_loss}"
35
- assert isinstance(return_token_accuracy, bool), (
36
- f"return_token_accuracy must be True or False. Got: {return_token_accuracy}"
37
- )
38
- assert isinstance(return_predicted_tokens, bool), (
39
- f"return_predicted_tokens must be True or False. Got: {return_predicted_tokens}"
40
- )
41
- device = _input.device
42
-
43
- input_requires_grad = _input.requires_grad
44
-
45
- # inputs have shape: BT x H
46
- # materialized activations will have shape: BT x V
47
- # the increase in memory = BT x V
48
- # reduction can be achieved by partitioning the number of tokens BT into smaller chunks.
49
- # for ex: if we were to achieve the same memory consumption as BT x H, then the chunk size should be:
50
- # inc_factor = (V+H-1)//H, chunk_size = (BT + inc_factor - 1)//inc_factor
51
- # for ex: BT = 4096*4, V = 32000, H = 4096 ==> inc_factor = 8, chunk_size = 2048
52
- BT, H = _input.shape
53
- V = weight.shape[0]
54
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
55
-
56
- inc_factor = triton.cdiv(V, H) # (V + H - 1) // H
57
- chunk_size = triton.next_power_of_2(triton.cdiv(BT, inc_factor)) # (BT + inc_factor - 1) // inc_factor
58
- num_chunks = triton.cdiv(BT, chunk_size) # (BT + chunk_size - 1) // chunk_size
59
-
60
- grad_input = torch.zeros_like(_input, device=device)
61
-
62
- # we use fp32 for loss and gradients accumulator
63
- if input_requires_grad:
64
- if accum_dtype is None:
65
- grad_weight = torch.zeros_like(weight, device=device) if weight.requires_grad else None
66
- grad_bias = torch.zeros_like(bias, device=device) if bias is not None else None
67
- else:
68
- grad_weight = torch.zeros_like(weight, dtype=accum_dtype, device=device) if weight.requires_grad else None
69
- grad_bias = torch.zeros_like(bias, dtype=accum_dtype, device=device) if bias is not None else None
70
- else:
71
- grad_weight = None
72
- grad_bias = None
73
-
74
- loss_1d = torch.zeros(BT, dtype=torch.float32, device=device)
75
- z_loss_1d = torch.zeros(BT, dtype=_input.dtype, device=_input.device) if return_z_loss else None
76
- token_accuracy_1d = torch.zeros(BT, dtype=torch.float32, device=device) if return_token_accuracy else None
77
- predicted_tokens_1d = torch.full((BT,), -1, dtype=torch.int64, device=device) if return_predicted_tokens else None
78
-
79
- # TODO: evaluate how CUDA synchronization caused by .item() affects the speed
80
- target_mask = target != ignore_index
81
- total_n_non_ignore = target_mask.sum().item()
82
- total_sum_non_ignore_ce_weight = total_n_non_ignore
83
- ce_weight_sum = 0.0
84
- if ce_weight is not None:
85
- assert ce_weight.shape[0] == V, f"If given, weight has to be a Tensor of size V. Got: {ce_weight.shape}"
86
- assert torch.is_floating_point(ce_weight), (
87
- f"If given, weight has to be a Tensor of floating point dtype. Got: {ce_weight.dtype}"
88
- )
89
- total_sum_non_ignore_ce_weight = (
90
- torch.gather(ce_weight, dim=0, index=target.masked_select(target_mask)).sum().item()
91
- )
92
- ce_weight_sum = ce_weight.sum().item()
93
- if ce_weight.stride(-1) != 1:
94
- ce_weight = ce_weight.contiguous()
95
-
96
- for chunk_id in range(num_chunks):
97
- start_idx = chunk_id * chunk_size
98
- end_idx = min((chunk_id + 1) * chunk_size, BT)
99
- _input_chunk = _input[start_idx:end_idx] # chunk_size x H
100
-
101
- # when doing matmul, use the original precision
102
- logits_chunk = _input_chunk @ weight.t() # chunk_size x V
103
- if bias is not None:
104
- logits_chunk = logits_chunk + bias
105
-
106
- target_chunk = target[start_idx:end_idx] # chunk_size,
107
-
108
- n_rows = logits_chunk.shape[0]
109
-
110
- # Compute predicted probabilities for token scaling if needed
111
- if use_token_scaling:
112
- # Compute softmax probabilities for scaling
113
- # We need to compute this before the cross entropy kernel modifies logits_chunk
114
- logits_for_softmax = logits_chunk.detach().clone() # Detach to avoid gradient flow
115
- if softcap is not None:
116
- logits_for_softmax = softcap * torch.tanh(logits_for_softmax / softcap)
117
-
118
- # Compute softmax to get predicted probabilities
119
- probs = torch.softmax(logits_for_softmax, dim=-1)
120
-
121
- # Get predicted probabilities for token scaling, handling ignored targets
122
- valid_target_mask = target_chunk != ignore_index
123
- valid_targets = target_chunk[valid_target_mask]
124
-
125
- if len(valid_targets) > 0:
126
- # Gather probabilities only for valid targets
127
- valid_probs = probs[valid_target_mask]
128
- pred_probs_valid = torch.gather(valid_probs, -1, valid_targets.unsqueeze(-1)).squeeze(-1)
129
-
130
- # Create full tensor with zeros for ignored targets
131
- pred_probs = torch.zeros_like(target_chunk, dtype=probs.dtype, device=probs.device)
132
- pred_probs[valid_target_mask] = pred_probs_valid
133
- else:
134
- # All targets are ignored
135
- pred_probs = torch.zeros_like(target_chunk, dtype=probs.dtype, device=probs.device)
136
-
137
- # Store the scaling factors
138
- scaling_factors = pred_probs.detach() # Detach to ensure no gradient flow
139
-
140
- # unreduced loss
141
- loss_1d_slice = loss_1d[start_idx:end_idx] # chunk_size,
142
- z_loss_1d_slice = z_loss_1d[start_idx:end_idx] if return_z_loss else None
143
- token_accuracy_1d_slice = token_accuracy_1d[start_idx:end_idx] if return_token_accuracy else None
144
- predicted_tokens_1d_slice = predicted_tokens_1d[start_idx:end_idx] if return_predicted_tokens else None
145
-
146
- # ensure _input and target are contiguous
147
- logits_chunk = logits_chunk.contiguous()
148
- target_chunk = target_chunk.contiguous()
149
-
150
- # Here we calculate the gradient of logits_chunk in place so we can save memory.
151
- liger_cross_entropy_kernel[(n_rows,)](
152
- X_ptr=logits_chunk,
153
- X_stride=logits_chunk.stride(-2),
154
- Y_ptr=target_chunk,
155
- Y_stride=target_chunk.stride(-1), # always 1
156
- weight_ptr=ce_weight,
157
- loss_ptr=loss_1d_slice,
158
- z_loss_ptr=z_loss_1d_slice,
159
- loss_stride=loss_1d_slice.stride(-1), # always 1
160
- token_accuracy_ptr=token_accuracy_1d_slice,
161
- token_accuracy_stride=token_accuracy_1d_slice.stride(-1)
162
- if return_token_accuracy
163
- else 0, # always 1 if accuracy is enabled
164
- predicted_tokens_ptr=predicted_tokens_1d_slice,
165
- predicted_tokens_stride=predicted_tokens_1d_slice.stride(-1)
166
- if return_predicted_tokens
167
- else 0, # always 1 if predicted tokens is enabled
168
- n_cols=V,
169
- n_non_ignore=total_n_non_ignore,
170
- sum_non_ignore_weight=total_sum_non_ignore_ce_weight,
171
- weight_sum=ce_weight_sum,
172
- ignore_index=ignore_index,
173
- lse_square_scale=lse_square_scale,
174
- label_smoothing=label_smoothing,
175
- reduction=reduction,
176
- softcap=softcap,
177
- RETURN_Z_LOSS=return_z_loss,
178
- RETURN_TOKEN_ACCURACY=return_token_accuracy,
179
- RETURN_PREDICTED_TOKENS=return_predicted_tokens,
180
- HAS_WEIGHT=True if ce_weight is not None else False,
181
- HAS_SOFTCAPPING=True if softcap is not None else False,
182
- HAS_GRADIENTS=input_requires_grad,
183
- BLOCK_SIZE=BLOCK_SIZE,
184
- num_warps=32 if not is_hip() else 16,
185
- )
186
-
187
- # Apply token scaling if requested
188
- if use_token_scaling:
189
- loss_1d_slice = loss_1d_slice * scaling_factors
190
- if return_z_loss:
191
- z_loss_1d_slice = z_loss_1d_slice * scaling_factors
192
-
193
- loss_1d[start_idx:end_idx] = loss_1d_slice
194
- if return_z_loss:
195
- z_loss_1d[start_idx:end_idx] = z_loss_1d_slice
196
- if return_token_accuracy:
197
- token_accuracy_1d[start_idx:end_idx] = token_accuracy_1d_slice
198
- if return_predicted_tokens:
199
- predicted_tokens_1d[start_idx:end_idx] = predicted_tokens_1d_slice
200
- grad_logits_chunk = logits_chunk # chunk_size x V
201
-
202
- # Apply token scaling to gradients if requested
203
- if use_token_scaling:
204
- # Expand scaling factors to match gradient dimensions
205
- scaling_factors_expanded = scaling_factors.unsqueeze(-1) # chunk_size x 1
206
- grad_logits_chunk = grad_logits_chunk * scaling_factors_expanded
207
-
208
- if input_requires_grad:
209
- grad_input[start_idx:end_idx] = grad_logits_chunk @ weight
210
-
211
- if grad_weight is not None and input_requires_grad:
212
- grad_weight += torch.mm(grad_logits_chunk.t(), _input_chunk).float()
213
-
214
- if bias is not None and input_requires_grad:
215
- torch.add(
216
- input=grad_bias,
217
- other=grad_logits_chunk.sum(dim=0),
218
- out=grad_bias,
219
- alpha=1.0,
220
- )
221
-
222
- # Need extra calculations for backward if reduction=='none'. Not supporting reduction='none' now.
223
- # if reduction == "none":
224
- # loss = loss_1d
225
- # z_loss = z_loss_1d if return_z_loss else None
226
-
227
- if reduction == "none":
228
- # Return per-token losses
229
- loss = loss_1d
230
- z_loss = z_loss_1d if return_z_loss else None
231
- token_accuracy = token_accuracy_1d if return_token_accuracy else None
232
- else:
233
- loss = torch.sum(loss_1d)
234
- z_loss = torch.sum(z_loss_1d) if return_z_loss else None
235
- # For accuracy, we compute the mean across all non-ignored tokens
236
- token_accuracy = torch.sum(token_accuracy_1d) / total_n_non_ignore if return_token_accuracy else None
237
-
238
- predicted_tokens = predicted_tokens_1d if return_predicted_tokens else None
239
-
240
- # Cast back to original dtype
241
- grad_weight = grad_weight.to(weight.dtype) if grad_weight is not None else None
242
- grad_bias = grad_bias.to(bias.dtype) if grad_bias is not None else None
243
-
244
- return loss, z_loss, token_accuracy, predicted_tokens, grad_input, grad_weight, grad_bias
245
-
246
-
247
- def fused_linear_cross_entropy_backward(grad_output, grad_input, grad_weight, grad_bias):
248
- # If cross entropy is the last layer, grad_output is 1.0. Skip the mul to save time
249
- if not torch.equal(grad_output, torch.tensor(1.0, device=grad_output.device)):
250
- # We use a Triton kernel instead of a PyTorch operation because modifying inputs in-place
251
- # for gradient storage and backward multiple times causes anomalies with PyTorch but not with Triton.
252
- BT, H = grad_input.shape
253
- n_rows = BT
254
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(H))
255
-
256
- element_mul_kernel[(n_rows,)](
257
- grad_input,
258
- grad_input.stride(-2),
259
- grad_output,
260
- H,
261
- BLOCK_SIZE=BLOCK_SIZE,
262
- num_warps=32 if not is_hip() else 16,
263
- )
264
-
265
- # handle grad_weight
266
- if grad_weight is not None:
267
- V, H = grad_weight.shape
268
- n_rows = V
269
-
270
- element_mul_kernel[(n_rows,)](
271
- grad_weight,
272
- grad_weight.stride(-2),
273
- grad_output,
274
- H,
275
- BLOCK_SIZE=BLOCK_SIZE,
276
- num_warps=32 if not is_hip() else 16,
277
- )
278
-
279
- if grad_bias is not None:
280
- V = grad_bias.shape[0]
281
- n_rows = V
282
-
283
- element_mul_kernel[(n_rows,)](
284
- grad_bias,
285
- grad_bias.stride(-1),
286
- grad_output,
287
- 1,
288
- BLOCK_SIZE=BLOCK_SIZE,
289
- num_warps=32 if not is_hip() else 16,
290
- )
291
- return grad_input, grad_weight, grad_bias
292
-
293
-
294
- class LigerFusedLinearCrossEntropyFunction(torch.autograd.Function):
295
- @staticmethod
296
- @amp_custom_fwd
297
- def forward(
298
- ctx,
299
- _input,
300
- weight,
301
- target,
302
- bias=None,
303
- ce_weight=None,
304
- ignore_index=-100,
305
- lse_square_scale=0.0,
306
- label_smoothing=0.0,
307
- reduction="mean",
308
- softcap=None,
309
- return_z_loss: bool = False,
310
- accum_dtype=None,
311
- use_token_scaling: bool = False,
312
- return_token_accuracy: bool = False,
313
- return_predicted_tokens: bool = False,
314
- ):
315
- """
316
- Fusing the last linear layer with cross-entropy loss
317
- Reference: https://github.com/mgmalek/efficient_cross_entropy
318
-
319
- Handle the forward and backward pass of the final linear layer via cross-entropy loss by avoiding
320
- the materialization of the large logits tensor. Since Cross Entropy Loss is the last layer, we can
321
- compute the gradient at the forward pass. By doing so, we don't have to store the _input and target
322
- for the backward pass.
323
-
324
- _input: (B*T, H) where B is batch size, T is sequence length, H is hidden dimension.
325
- target: (B*T) where each value is in [0, V-1]
326
- weight: (V, H) where V is the number of classes
327
- bias: (V) where V is the number of classes
328
- ce_weight: a manual rescaling weight given to each class. If given, has to be a Tensor of size V and floating point dtype
329
- ignore_index: the index to ignore in the target
330
- label_smoothing (float): The amount of smoothing when computing the loss, where 0.0 means no smoothing.
331
- reduction: reduction to apply
332
- accum_dtype (torch.dtype): the dtype of intermediate result buffers for weight and bias gradient accumulations.
333
- Recommended to set `accum_dtype` to higher precision, e.g. `torch.float32`, if the training is unstable with original dtype. Default: `None`, performing accumulations in original dtype
334
- use_token_scaling (bool): whether to scale each token's loss by its predicted probability (detached).
335
- When True, each token's loss is multiplied by the model's predicted probability for that token's true class.
336
- Default: False.
337
- return_token_accuracy (bool): When `return_token_accuracy` is `True`, computes and returns per-token accuracy without materializing logits. Default: `False`
338
- return_predicted_tokens (bool): When `return_predicted_tokens` is `True`, returns per-token predicted class indices (argmax) without materializing logits. Default: `False`
339
- """
340
-
341
- loss, z_loss, token_accuracy, predicted_tokens, grad_input, grad_weight, grad_bias = (
342
- fused_linear_cross_entropy_forward(
343
- _input=_input,
344
- weight=weight,
345
- target=target,
346
- bias=bias,
347
- ce_weight=ce_weight,
348
- ignore_index=ignore_index,
349
- lse_square_scale=lse_square_scale,
350
- label_smoothing=label_smoothing,
351
- reduction=reduction,
352
- softcap=softcap,
353
- return_z_loss=return_z_loss,
354
- accum_dtype=accum_dtype,
355
- use_token_scaling=use_token_scaling,
356
- return_token_accuracy=return_token_accuracy,
357
- return_predicted_tokens=return_predicted_tokens,
358
- )
359
- )
360
- # downcast to dtype and store for backward
361
- ctx.save_for_backward(
362
- grad_input.detach(),
363
- grad_weight.detach() if grad_weight is not None else None,
364
- grad_bias.detach() if grad_bias is not None else None,
365
- )
366
- ctx.return_z_loss = return_z_loss
367
- ctx.return_token_accuracy = return_token_accuracy
368
- ctx.return_predicted_tokens = return_predicted_tokens
369
- return loss, z_loss, token_accuracy, predicted_tokens
370
-
371
- @staticmethod
372
- @amp_custom_bwd
373
- def backward(ctx, grad_output, grad_output2, grad_output3, grad_output4):
374
- if ctx.return_z_loss:
375
- del grad_output2 # z_loss is only for logging
376
- if ctx.return_token_accuracy:
377
- del grad_output3 # token_accuracy is only for metrics
378
- if ctx.return_predicted_tokens:
379
- del grad_output4 # predicted_tokens is only for metrics
380
- (grad_input, grad_weight, grad_bias) = ctx.saved_tensors
381
- grad_input, grad_weight, grad_bias = fused_linear_cross_entropy_backward(
382
- grad_output, grad_input, grad_weight, grad_bias
383
- )
384
- return (
385
- grad_input,
386
- grad_weight,
387
- None,
388
- grad_bias,
389
- None,
390
- None,
391
- None,
392
- None,
393
- None,
394
- None,
395
- None,
396
- None,
397
- None, # use_token_scaling
398
- None, # return_token_accuracy
399
- None, # return_predicted_tokens
400
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/geglu.py DELETED
@@ -1,143 +0,0 @@
1
- import operator
2
-
3
- import torch
4
- import triton
5
- import triton.language as tl
6
-
7
- from .utils import calculate_settings
8
- from .utils import compare_version
9
- from .utils import ensure_contiguous
10
- from .utils import is_npu_available
11
-
12
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
13
- try:
14
- # typical import path with dispatch available
15
- from triton.language.extra.libdevice import tanh
16
- except ModuleNotFoundError:
17
- # for working with NGC containers
18
- from triton.language.extra.cuda.libdevice import tanh
19
- else:
20
- from triton.language.math import tanh
21
-
22
-
23
- @triton.jit
24
- def _geglu_tanh_forward_kernel(a, b, c, stride, n_cols: tl.constexpr, BLOCK_SIZE: tl.constexpr):
25
- program_id = tl.program_id(0).to(tl.int64)
26
-
27
- # locate start index
28
- a += program_id * stride
29
- b += program_id * stride
30
- c += program_id * stride
31
-
32
- col_offsets = tl.arange(0, BLOCK_SIZE)
33
- mask = col_offsets < n_cols
34
- a_row = tl.load(a + col_offsets, mask=mask, other=0).to(tl.float32)
35
- b_row = tl.load(b + col_offsets, mask=mask, other=0)
36
-
37
- # tanh approximation form of GELU is computed with:
38
- # 0.5 * a * (1 + tanh(sqrt(2 / pi) * (a + 0.044715 * a^3)))
39
- sqrt_2_over_pi = 0.7978845608028654 # sqrt(2 / pi)
40
- a_cubed = a_row * a_row * a_row
41
- tanh_arg = sqrt_2_over_pi * (a_row + 0.044715 * a_cubed)
42
- tanh_result = tanh(tanh_arg)
43
- geglu_a = 0.5 * a_row * (1 + tanh_result)
44
- c_row = geglu_a.cast(b_row.dtype) * b_row
45
- tl.store(c + col_offsets, c_row, mask=mask)
46
-
47
-
48
- @triton.jit
49
- def _geglu_tanh_backward_kernel(dc, a, b, stride, n_cols: tl.constexpr, BLOCK_SIZE: tl.constexpr):
50
- program_id = tl.program_id(0).to(tl.int64)
51
-
52
- # locate start index
53
- dc += program_id * stride
54
- a += program_id * stride
55
- b += program_id * stride
56
-
57
- col_offsets = tl.arange(0, BLOCK_SIZE)
58
- mask = col_offsets < n_cols
59
-
60
- dc_row = tl.load(dc + col_offsets, mask=mask, other=0)
61
- a_row = tl.load(a + col_offsets, mask=mask, other=0).to(tl.float32)
62
- b_row = tl.load(b + col_offsets, mask=mask, other=0)
63
-
64
- # recomputation to save memory
65
- sqrt_2_over_pi = 0.7978845608028654 # sqrt(2 / pi)
66
- a_cubed = a_row * a_row * a_row
67
- tanh_arg = sqrt_2_over_pi * (a_row + 0.044715 * a_cubed)
68
- tanh_result = tanh(tanh_arg)
69
- geglu_a = 0.5 * a_row * (1 + tanh_result)
70
- geglu_a = geglu_a.to(dc_row.dtype).to(tl.float32)
71
-
72
- db_row = dc_row.cast(tl.float32) * geglu_a
73
-
74
- # Gradient w.r.t. a can be computed with:
75
- # b * (0.5 * (1 + tanh(z)) + 0.5 * a * (1 - tanh(z)^2) * (sqrt(2/pi) * (1 + 3 * 0.044715 * a^2)))
76
- # where z = sqrt(2/pi) * (a + 0.044715 * a^3)
77
- term1 = 0.5 * (1 + tanh_result)
78
- tanh_sq = tanh_result * tanh_result
79
- term2 = 0.5 * a_row * (1 - tanh_sq) * (sqrt_2_over_pi * (1 + 3 * 0.044715 * a_row * a_row))
80
- da_row = dc_row * b_row * (term1 + term2)
81
-
82
- tl.store(a + col_offsets, da_row, mask=mask)
83
- tl.store(b + col_offsets, db_row.to(dc_row.dtype), mask=mask)
84
-
85
-
86
- def geglu_forward(a, b):
87
- ori_shape = a.shape
88
-
89
- n_cols = ori_shape[-1]
90
- a = a.view(-1, n_cols)
91
- b = b.view(-1, n_cols)
92
- c = torch.empty_like(a)
93
- n_rows = a.shape[0]
94
-
95
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
96
-
97
- _geglu_tanh_forward_kernel[(n_rows,)](
98
- a,
99
- b,
100
- c,
101
- c.stride(-2),
102
- n_cols=n_cols,
103
- BLOCK_SIZE=BLOCK_SIZE,
104
- num_warps=num_warps,
105
- )
106
- return a, b, c.view(*ori_shape)
107
-
108
-
109
- def geglu_backward(a, b, dc):
110
- ori_shape = dc.shape
111
- n_cols = ori_shape[-1]
112
- dc = dc.view(-1, n_cols)
113
- n_rows = dc.shape[0]
114
-
115
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
116
-
117
- _geglu_tanh_backward_kernel[(n_rows,)](
118
- dc,
119
- a,
120
- b,
121
- dc.stride(-2),
122
- n_cols=n_cols,
123
- BLOCK_SIZE=BLOCK_SIZE,
124
- num_warps=num_warps,
125
- )
126
-
127
- return a.view(*ori_shape), b.view(*ori_shape)
128
-
129
-
130
- class LigerGELUMulFunction(torch.autograd.Function):
131
- @staticmethod
132
- @ensure_contiguous
133
- def forward(ctx, a, b):
134
- a, b, c = geglu_forward(a, b)
135
- ctx.save_for_backward(a, b)
136
- return c
137
-
138
- @staticmethod
139
- @ensure_contiguous
140
- def backward(ctx, dc):
141
- a, b = ctx.saved_tensors
142
- a, b = geglu_backward(a, b, dc)
143
- return a, b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/group_norm.py DELETED
@@ -1,311 +0,0 @@
1
- import operator
2
-
3
- import torch
4
- import triton
5
- import triton.language as tl
6
-
7
- from .utils import compare_version
8
- from .utils import ensure_contiguous
9
- from .utils import infer_device
10
- from .utils import is_npu_available
11
-
12
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
13
- try:
14
- # typical import path with dispatch available
15
- from triton.language.extra.libdevice import rsqrt
16
- except ModuleNotFoundError:
17
- # for working with NGC containers
18
- from triton.language.extra.cuda.libdevice import rsqrt
19
- else:
20
- from triton.language.math import rsqrt
21
-
22
- if infer_device() == "npu":
23
- MAX_FUSED_SIZE = 16384 # 8192
24
- else:
25
- MAX_FUSED_SIZE = 65536
26
-
27
-
28
- @triton.jit
29
- def _group_norm_forward_kernel(
30
- Y_ptr, # pointer to output, shape (n_rows, n_groups, hidden_size)
31
- Y_row_stride, # stride of each row in output
32
- Y_col_stride, # stride of each column in output
33
- X_ptr, # pointer to input, shape (n_rows, n_groups, hidden_size)
34
- X_row_stride, # stride of each row in input
35
- X_col_stride, # stride of each column in input
36
- Mean_ptr, # pointer to mean, shape (n_rows, n_groups)
37
- Mean_row_stride, # stride of each row in mean
38
- Mean_col_stride, # stride of each column in mean
39
- RSTD_ptr, # pointer to rstd, shape (n_rows, n_groups)
40
- RSTD_row_stride, # stride of each row in rstd
41
- RSTD_col_stride, # stride of each column in rstd
42
- W_ptr, # pointer to W
43
- B_ptr, # pointer to B
44
- hidden_size, # hidden size of X
45
- channels_per_group, # the number of channels per group
46
- eps,
47
- BLOCK_SIZE: tl.constexpr,
48
- ):
49
- """
50
- References:
51
- https://nn.labml.ai/normalization/group_norm/index.html
52
- """
53
- batch_idx = tl.program_id(0)
54
- group_idx = tl.program_id(1)
55
-
56
- X_ptr += batch_idx * X_row_stride + group_idx * X_col_stride
57
- Y_ptr += batch_idx * Y_row_stride + group_idx * Y_col_stride
58
-
59
- block_range = tl.arange(0, BLOCK_SIZE)
60
-
61
- # Compute mean and variance using the online algorithm
62
- s = 0.0
63
- squared_sum = 0.0
64
- for i in tl.range(0, hidden_size, BLOCK_SIZE):
65
- hidden_size_offsets = i + block_range
66
- mask = hidden_size_offsets < hidden_size
67
- X = tl.load(X_ptr + hidden_size_offsets, mask=mask, other=0.0)
68
- s += tl.sum(X)
69
- # X**2
70
- squared_sum += tl.sum(X * X)
71
-
72
- m = s / hidden_size
73
-
74
- # variance = E[X**2] - E[X]**2
75
- variance = (squared_sum / hidden_size) - (m * m)
76
-
77
- # 1/std
78
- rstd = rsqrt(variance + eps)
79
-
80
- # Normalize — flat loop over full hidden_size (not per-channel)
81
- # This avoids the nested channel × per_channel_hidden loop where
82
- # BLOCK_SIZE >> hidden_size_per_channel causes massive padding waste.
83
- hidden_size_per_channel = hidden_size // channels_per_group
84
- for i in tl.range(0, hidden_size, BLOCK_SIZE):
85
- hidden_size_offsets = i + block_range
86
- mask = hidden_size_offsets < hidden_size
87
- X = tl.load(X_ptr + hidden_size_offsets, mask=mask, other=m)
88
- # Determine which channel each element belongs to, then load W/B
89
- local_channel = hidden_size_offsets // hidden_size_per_channel
90
- global_channel = group_idx * channels_per_group + local_channel
91
- W = tl.load(W_ptr + global_channel, mask=mask)
92
- B = tl.load(B_ptr + global_channel, mask=mask)
93
- Y = (X - m) * rstd * W + B
94
- tl.store(Y_ptr + hidden_size_offsets, Y, mask=mask)
95
-
96
- tl.store(Mean_ptr + batch_idx * Mean_row_stride + group_idx * Mean_col_stride, m)
97
- tl.store(RSTD_ptr + batch_idx * RSTD_row_stride + group_idx * RSTD_col_stride, rstd)
98
-
99
-
100
- @triton.jit
101
- def _group_norm_backward_kernel(
102
- X_ptr, # pointer to input, shape (n_rows, n_channels, hidden_size)
103
- X_row_stride, # stride of each row in input
104
- X_col_stride, # stride of each column in input
105
- W_ptr, # pointer to weights, shape (n_channels)
106
- Mean_ptr, # pointer to mean, shape (n_rows, n_groups)
107
- Mean_ptr_row_stride, # stride of each column in mean
108
- Mean_ptr_col_stride, # stride of each column in mean
109
- RSTD_ptr, # pointer to rstd, shape (n_rows, n_groups)
110
- DX_ptr, # pointer to input grad, shape (n_rows, n_groups, hidden_size)
111
- DW_ptr, # pointer to weights grad, shape (n_channels)
112
- DB_ptr, # pointer to bias grad, shape (n_channels)
113
- UPSTREAM_ptr, # pointer to output grad, shape (n_rows, n_channels, hidden_size)
114
- hidden_size: tl.constexpr, # hidden size
115
- channels_per_group: tl.constexpr, # number of groups in group norm
116
- BLOCK_SIZE: tl.constexpr,
117
- dtype: tl.constexpr,
118
- ):
119
- """
120
- References:
121
- https://nn.labml.ai/normalization/group_norm/index.html
122
- https://github.com/karpathy/llm.c/blob/master/doc/layernorm/layernorm.md
123
-
124
- The backprop equations are the same for group_norm and layer_norm
125
- the only difference here is that we load the Mean, Rstd corresponding to the
126
- group we're computing gradients for and the mean and rstd are computed over n-channels
127
- so the total number of elements we compute the mean over is num_channels_per_group * hidden_size
128
-
129
- We also need to load the Weights corresponding to the current channel to compute the gradients.
130
- """
131
- batch_idx = tl.program_id(0)
132
- group_idx = tl.program_id(1)
133
-
134
- # Move the pointers to the correct batch
135
- X_ptr += batch_idx * X_row_stride
136
- DX_ptr += batch_idx * X_row_stride
137
- UPSTREAM_ptr += batch_idx * X_row_stride
138
-
139
- # Mean and rstd are the same shape so have the same strides
140
- mean = tl.load(Mean_ptr + batch_idx * Mean_ptr_row_stride + group_idx * Mean_ptr_col_stride)
141
- rstd = tl.load(RSTD_ptr + batch_idx * Mean_ptr_row_stride + group_idx * Mean_ptr_col_stride)
142
-
143
- c1 = 0.0
144
- c2 = 0.0
145
- block_range = tl.arange(0, BLOCK_SIZE)
146
-
147
- # We need to compute the sum terms of the backprop equations across all channels in the group
148
- for channel_idx in range(group_idx * channels_per_group, (group_idx + 1) * channels_per_group):
149
- dW = 0.0
150
- dB = 0.0
151
- # Move the pointers to the correct channel
152
- W = tl.load(W_ptr + channel_idx)
153
- for i in tl.range(0, hidden_size, BLOCK_SIZE):
154
- hidden_size_offsets = i + block_range
155
- mask = hidden_size_offsets < hidden_size
156
- X = tl.load(
157
- X_ptr + channel_idx * X_col_stride + hidden_size_offsets,
158
- mask=mask,
159
- other=0.0,
160
- )
161
- UPSTREAM_grad = tl.load(
162
- UPSTREAM_ptr + channel_idx * X_col_stride + hidden_size_offsets,
163
- mask=mask,
164
- other=0.0,
165
- )
166
-
167
- x_hat = (X - mean) * rstd
168
- dW += tl.sum(UPSTREAM_grad * x_hat)
169
- dB += tl.sum(UPSTREAM_grad)
170
-
171
- wdy = W * UPSTREAM_grad
172
- c1 += tl.sum(x_hat * wdy)
173
- c2 += tl.sum(wdy)
174
-
175
- # Need to ensure additions to the same channel are atomic
176
- tl.atomic_add(DW_ptr + channel_idx, dW.to(dtype))
177
- tl.atomic_add(DB_ptr + channel_idx, dB.to(dtype))
178
-
179
- N = hidden_size * channels_per_group
180
- c1 = c1 / N
181
- c2 = c2 / N
182
-
183
- for channel_idx in tl.range(group_idx * channels_per_group, (group_idx + 1) * channels_per_group):
184
- # Move the pointers to the correct channel
185
- W = tl.load(W_ptr + channel_idx)
186
- for i in range(0, hidden_size, BLOCK_SIZE):
187
- hidden_size_offsets = i + block_range
188
- mask = hidden_size_offsets < hidden_size
189
- X = tl.load(
190
- X_ptr + channel_idx * X_col_stride + hidden_size_offsets,
191
- mask=mask,
192
- other=0.0,
193
- )
194
- UPSTREAM_grad = tl.load(
195
- UPSTREAM_ptr + channel_idx * X_col_stride + hidden_size_offsets,
196
- mask=mask,
197
- other=0.0,
198
- )
199
-
200
- x_hat = (X - mean) * rstd
201
- wdy = W * UPSTREAM_grad
202
- dx = (wdy - (x_hat * c1 + c2)) * rstd
203
- tl.store(DX_ptr + channel_idx * X_col_stride + hidden_size_offsets, dx, mask=mask)
204
-
205
-
206
- def group_norm_forward(X, num_channels, num_groups, W, B, eps):
207
- shape = X.shape
208
- batch_size = shape[0]
209
- channels_per_group = num_channels // num_groups
210
- # Reshape X so that the mean and std are computed across the groups
211
- X = X.view(batch_size, num_groups, -1).contiguous()
212
- hidden_size = X.shape[-1]
213
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(hidden_size))
214
- Y = torch.empty((batch_size, num_groups, hidden_size), dtype=X.dtype, device=X.device)
215
- Mean = torch.zeros((batch_size, num_groups), dtype=X.dtype, device=X.device)
216
- RSTD = torch.zeros((batch_size, num_groups), dtype=X.dtype, device=X.device)
217
-
218
- _group_norm_forward_kernel[(batch_size, num_groups)](
219
- Y,
220
- Y.stride(0),
221
- Y.stride(1),
222
- X,
223
- X.stride(0),
224
- X.stride(1),
225
- Mean,
226
- Mean.stride(0),
227
- Mean.stride(1),
228
- RSTD,
229
- RSTD.stride(0),
230
- RSTD.stride(1),
231
- W,
232
- B,
233
- hidden_size,
234
- channels_per_group,
235
- eps,
236
- BLOCK_SIZE=BLOCK_SIZE,
237
- )
238
- # Return tensors in the original shape
239
- return Y.view(*shape), X.view(*shape), Mean, RSTD, BLOCK_SIZE
240
-
241
-
242
- def group_norm_backward(dY, X, W, B, Mean, RSTD, num_channels, num_groups):
243
- shape = dY.shape
244
- batch_size = shape[0]
245
- hidden_size = dY.shape[-1]
246
- channels_per_group = num_channels // num_groups
247
- dY = dY.view(batch_size, num_groups, -1)
248
- DX = torch.empty(
249
- (batch_size, num_groups, hidden_size * channels_per_group),
250
- dtype=X.dtype,
251
- device=X.device,
252
- )
253
- DW = torch.zeros((num_channels), dtype=W.dtype, device=W.device)
254
- DB = torch.zeros((num_channels), dtype=B.dtype, device=B.device)
255
- triton_dtype = tl.float32 if X.dtype == torch.float32 else tl.bfloat16
256
-
257
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(hidden_size))
258
- _group_norm_backward_kernel[(batch_size, num_groups)](
259
- X,
260
- X.stride(0),
261
- X.stride(1),
262
- W,
263
- Mean,
264
- Mean.stride(0),
265
- Mean.stride(1),
266
- RSTD,
267
- DX,
268
- DW,
269
- DB,
270
- dY,
271
- hidden_size,
272
- channels_per_group,
273
- BLOCK_SIZE=BLOCK_SIZE,
274
- dtype=triton_dtype,
275
- )
276
-
277
- # Return tensors in the original shape
278
- return DX.view(*shape), DW, DB
279
-
280
-
281
- class LigerGroupNormFunction(torch.autograd.Function):
282
- @staticmethod
283
- @ensure_contiguous
284
- def forward(
285
- ctx,
286
- X,
287
- affine_scaling_weight,
288
- affine_shifting_bias,
289
- num_channels,
290
- num_groups,
291
- eps,
292
- ):
293
- Y, X, Mean, RSTD, BLOCK_SIZE = group_norm_forward(
294
- X,
295
- num_channels,
296
- num_groups,
297
- affine_scaling_weight,
298
- affine_shifting_bias,
299
- eps,
300
- )
301
- ctx.num_channels = num_channels
302
- ctx.num_groups = num_groups
303
- ctx.save_for_backward(X, affine_scaling_weight, affine_shifting_bias, Mean, RSTD)
304
- return Y
305
-
306
- @staticmethod
307
- @ensure_contiguous
308
- def backward(ctx, dY):
309
- X, W, B, Mean, RSTD = ctx.saved_tensors
310
- DX, DW, DB = group_norm_backward(dY, X, W, B, Mean, RSTD, ctx.num_channels, ctx.num_groups)
311
- return DX, DW, DB, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/jsd.py DELETED
@@ -1,201 +0,0 @@
1
- from typing import Optional
2
-
3
- import torch
4
- import triton
5
- import triton.language as tl
6
-
7
- from .utils import ensure_contiguous
8
- from .utils import infer_device
9
-
10
-
11
- @triton.jit
12
- def _jsd_kernel(
13
- X_ptr, # input in logspace, X = log Q
14
- X_stride,
15
- Y_ptr, # ground truth in logspace, Y = log P
16
- Y_stride,
17
- loss_ptr,
18
- loss_stride,
19
- dX_ptr,
20
- dX_stride,
21
- label_ptr,
22
- beta: tl.constexpr,
23
- n_non_ignore: int,
24
- ignore_index: tl.constexpr,
25
- n_cols,
26
- BLOCK_SIZE: tl.constexpr,
27
- HAS_LABEL: tl.constexpr,
28
- ):
29
- # JSD(P || Q) = (KL(P || M) + KL(Q || M)) / 2, M = (1/2) * (P + Q) = (1/2) * (e ^ Y + e ^ X)
30
- # = sum(P * log P + Q * log Q - 2 * M * log M) / 2
31
- # = sum(e ^ Y * Y + e ^ X * X - 2 * M * log M) / 2
32
- # grad_x_i = 0.5 * Q * (X - log_M)
33
- pid = tl.program_id(0).to(tl.int64)
34
- X_ptr += pid * X_stride
35
- dX_ptr += pid * dX_stride
36
- Y_ptr += pid * Y_stride
37
- loss_ptr += pid * loss_stride
38
- label_ptr += pid
39
-
40
- if HAS_LABEL:
41
- label = tl.load(label_ptr)
42
- if label == ignore_index:
43
- for i in range(0, n_cols, BLOCK_SIZE):
44
- offsets = i + tl.arange(0, BLOCK_SIZE)
45
- tl.store(dX_ptr + offsets, 0.0, mask=offsets < n_cols)
46
- return
47
-
48
- for i in range(0, n_cols, BLOCK_SIZE):
49
- offsets = i + tl.arange(0, BLOCK_SIZE)
50
- mask = offsets < n_cols
51
- X = tl.load(X_ptr + offsets, mask=mask, other=float("-inf")).to(tl.float32)
52
- Y = tl.load(Y_ptr + offsets, mask=mask, other=float("-inf")).to(tl.float32)
53
-
54
- if beta == 0.0: # forward KL
55
- Y_max = tl.max(Y, axis=0)
56
- Y_shifted = Y - Y_max
57
- Y_prob = tl.exp(Y_shifted) * tl.exp(Y_max) # Compensate for the shift
58
- loss = Y_prob * (Y - X)
59
- dX = -Y_prob
60
- elif beta == 1.0: # reverse KL
61
- X_max = tl.max(X, axis=0)
62
- X_shifted = X - X_max
63
- X_prob = tl.exp(X_shifted) * tl.exp(X_max) # Compensate for the shift
64
- loss = X_prob * (X - Y)
65
- dX = loss + X_prob
66
- else:
67
- max_val = tl.maximum(tl.max(X, axis=0), tl.max(Y, axis=0))
68
- X_shifted = X - max_val
69
- Y_shifted = Y - max_val
70
-
71
- # Pre-compute exp(max_val) since it's used twice
72
- exp_max = tl.exp(max_val)
73
-
74
- # Compute exp terms with compensation
75
- Q = tl.exp(X_shifted) * exp_max # = exp(X)
76
- P = tl.exp(Y_shifted) * exp_max # = exp(Y)
77
-
78
- # Pre-compute common terms
79
- beta_P = beta * P
80
- one_minus_beta_Q = (1 - beta) * Q
81
- M = beta_P + one_minus_beta_Q
82
- log_M = tl.log(M) # No need to compensate as M is already in original scale
83
-
84
- loss = beta_P * Y + one_minus_beta_Q * X - M * log_M
85
- dX = one_minus_beta_Q * (X - log_M)
86
-
87
- # Pre-compute scaling factor
88
- scale = 1.0 / n_non_ignore
89
- loss = loss * scale
90
- dX = dX * scale
91
-
92
- tl.store(loss_ptr + offsets, loss, mask=mask)
93
- tl.store(dX_ptr + offsets, dX, mask=mask)
94
-
95
-
96
- MAX_FUSED_SIZE = 4096 if infer_device() == "xpu" else 65536
97
-
98
-
99
- def jsd_forward(_input, target, shift_labels, beta, ignore_index, has_label):
100
- BT, V = _input.shape
101
- n_rows = BT
102
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
103
- # non reduction loss
104
- loss = torch.zeros(_input.shape, dtype=torch.float32, device=_input.device)
105
- dX = torch.empty_like(_input)
106
-
107
- if has_label:
108
- n_non_ignore = (shift_labels != ignore_index).sum().item()
109
- else:
110
- n_non_ignore = BT
111
-
112
- _jsd_kernel[(n_rows,)](
113
- X_ptr=_input, # input in logspace, X = log Q
114
- X_stride=_input.stride(-2),
115
- Y_ptr=target, # ground truth in logspace, Y = log P
116
- Y_stride=target.stride(-2),
117
- loss_ptr=loss,
118
- loss_stride=loss.stride(-2),
119
- dX_ptr=dX,
120
- dX_stride=dX.stride(-2),
121
- label_ptr=(shift_labels if has_label else torch.empty(1, device=_input.device)), # dummy ptr if no label
122
- beta=beta,
123
- n_non_ignore=n_non_ignore,
124
- ignore_index=ignore_index,
125
- n_cols=V,
126
- BLOCK_SIZE=BLOCK_SIZE,
127
- HAS_LABEL=has_label,
128
- )
129
-
130
- loss = torch.sum(loss)
131
- return loss.to(_input.dtype), dX
132
-
133
-
134
- def jsd_backward(dX, grad_output):
135
- # If jsd is the last layer, grad_output is 1.0. Skip the mul to save time
136
- if torch.equal(grad_output, torch.tensor(1.0, device=grad_output.device)):
137
- return dX
138
- else:
139
- return grad_output * dX
140
-
141
-
142
- class LigerJSDFunction(torch.autograd.Function):
143
- r"""
144
- This class implements the forward and backward pass for the generalized Jensen-Shannon Divergence.
145
- .. math::
146
- JSD(\beta)(P || Q)
147
- = \beta * KLDiv(P || (\beta * P + (1 - \beta) * Q)) + (1 - \beta) * KLDiv(Q || (\beta * P + (1 - \beta) * Q))
148
-
149
- .. note::
150
- As all the other losses in PyTorch, this function expects the first argument,
151
- :attr:`_input`, to be the predictions, the output of the student model, in log-space
152
- and the second, :attr:`target`, to be the observations, the output of the teacher model, in log-space.
153
- This differs from the standard mathematical notation :math:`JSD(P || Q)` where
154
- :math:`P` denotes the teacher model and :math:`Q` denotes the student model.
155
- """
156
-
157
- @staticmethod
158
- @ensure_contiguous
159
- def forward(
160
- ctx,
161
- _input: torch.Tensor,
162
- target: torch.Tensor,
163
- shift_labels: Optional[torch.Tensor] = None,
164
- beta: float = 0.5,
165
- ignore_index: int = -100,
166
- ) -> torch.Tensor:
167
- """
168
- Args:
169
- _input (torch.Tensor): predict values with shape (BT, V) in logspace
170
- target (torch.Tensor): ground truth values with shape (BT, V) in logspace
171
- shift_labels (Optional[torch.LongTensor]): indicator of next predicted vocab with shape (BT) where each value is in [0, V-1].
172
- beta (float): coefficient beta of generalized JSD in the interval [0, 1]. It implements forward/reverse KL when beta equals 0 and 1 respectively. Default: `0.5`
173
- ignore_index (int): the index to ignore. Default: -100
174
-
175
- Returns:
176
- loss (torch.Tensor): generalized JSD
177
- """
178
- has_label = False
179
- if shift_labels is not None:
180
- assert shift_labels.shape == (_input.shape[0],), (
181
- f"the shape of shift_labels must be (BT,). Got: {shift_labels.shape}"
182
- )
183
- shift_labels = shift_labels.contiguous()
184
- has_label = True
185
-
186
- loss, dX = jsd_forward(_input, target, shift_labels, beta, ignore_index, has_label)
187
- ctx.save_for_backward(dX)
188
- return loss
189
-
190
- @staticmethod
191
- @ensure_contiguous
192
- def backward(ctx, grad_output: torch.Tensor) -> torch.Tensor:
193
- (dX,) = ctx.saved_tensors
194
- dX = jsd_backward(dX, grad_output)
195
- return (
196
- dX,
197
- None,
198
- None,
199
- None,
200
- None,
201
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/kl_div.py DELETED
@@ -1,259 +0,0 @@
1
- from typing import Literal
2
-
3
- import torch
4
- import triton
5
- import triton.language as tl
6
-
7
- from .utils import ensure_contiguous
8
- from .utils import is_hip
9
- from .utils import infer_device
10
-
11
-
12
- def get_num_warps(BLOCK_SIZE):
13
- num_warps = 4
14
- if BLOCK_SIZE >= 32768:
15
- num_warps = 32 if not is_hip() else 16
16
- elif BLOCK_SIZE >= 8192:
17
- num_warps = 16
18
- elif BLOCK_SIZE >= 2048:
19
- num_warps = 8
20
-
21
- return num_warps
22
-
23
-
24
- if infer_device() == "xpu":
25
- MAX_FUSED_SIZE = 8192
26
- elif infer_device() == "npu":
27
- MAX_FUSED_SIZE = 8192
28
- else:
29
- MAX_FUSED_SIZE = 65536 // 4 # 65536 // 4 or 8 works the best
30
-
31
- REDUCTION_LITERAL = Literal["none", "sum", "mean", "batchmean"]
32
-
33
- _REDUCTION_MODE_NONE: tl.constexpr = tl.constexpr(0)
34
- _REDUCTION_MODE_SUM: tl.constexpr = tl.constexpr(1)
35
- _REDUCTION_MODE_MEAN: tl.constexpr = tl.constexpr(2)
36
- _REDUCTION_MODE_BATCHMEAN: tl.constexpr = tl.constexpr(3)
37
-
38
- _str_to_reduction_mode = {
39
- "none": _REDUCTION_MODE_NONE.value,
40
- "sum": _REDUCTION_MODE_SUM.value,
41
- "mean": _REDUCTION_MODE_MEAN.value,
42
- "batchmean": _REDUCTION_MODE_BATCHMEAN.value,
43
- }
44
-
45
-
46
- @triton.jit
47
- def _kldiv_kernel_forward(
48
- y_ptr, # [B, S], prediction ptr, the kernel expects the prediction in log-space
49
- y_stride, # int, prediction stride
50
- gt_ptr, # [B, S], ground truth ptr
51
- gt_stride, # int, ground truth stride
52
- loss_ptr, # [B] or [B, S] if reduction == _REDUCTION_MODE_NONE, output ptr
53
- loss_stride, # int, output stride
54
- n_cols, # int, number of columns in the input tensor
55
- eps,
56
- BLOCK_SIZE: tl.constexpr,
57
- log_target: tl.constexpr = False,
58
- reduction: tl.constexpr = _REDUCTION_MODE_BATCHMEAN,
59
- ):
60
- pid = tl.program_id(0).to(tl.int64)
61
- y_ptr += pid * y_stride
62
- gt_ptr += pid * gt_stride
63
- loss_ptr += pid * loss_stride
64
-
65
- base_offsets = tl.arange(0, BLOCK_SIZE)
66
-
67
- loss_sum = 0.0
68
- for i in range(0, n_cols, BLOCK_SIZE):
69
- offsets = i + base_offsets
70
- mask = offsets < n_cols
71
- y = tl.load(y_ptr + offsets, mask=mask, other=0.0)
72
- y_true = tl.load(gt_ptr + offsets, mask=mask, other=0.0)
73
-
74
- # KL(y_true || y) = y_true * (log(y_true) - log(y))
75
- # We compute KL(y_true || y) with y in the log-space
76
- if not log_target:
77
- loss = y_true * (tl.log(tl.maximum(y_true, eps)) - y)
78
- else:
79
- loss = tl.exp(y_true) * (y_true - y)
80
-
81
- if reduction == _REDUCTION_MODE_NONE:
82
- tl.store(loss_ptr + offsets, loss, mask=mask)
83
- else:
84
- loss_sum += tl.sum(loss, axis=0)
85
-
86
- if reduction != _REDUCTION_MODE_NONE:
87
- tl.store(loss_ptr, loss_sum)
88
-
89
-
90
- @triton.jit
91
- def _kldiv_kernel_backward(
92
- target_ptr,
93
- target_stride,
94
- new_grads_ptr,
95
- new_grads_stride,
96
- n_cols,
97
- BLOCK_SIZE: tl.constexpr,
98
- log_target: tl.constexpr = False,
99
- ):
100
- pid = tl.program_id(0).to(tl.int64)
101
-
102
- target_ptr += pid * target_stride
103
- new_grads_ptr += pid * new_grads_stride
104
-
105
- offsets = tl.arange(0, BLOCK_SIZE)
106
- mask = offsets < n_cols
107
-
108
- for i in range(0, n_cols, BLOCK_SIZE):
109
- offsets = i + tl.arange(0, BLOCK_SIZE)
110
- mask = offsets < n_cols
111
-
112
- target = tl.load(target_ptr + offsets, mask=mask, other=0.0)
113
-
114
- if not log_target:
115
- res = target * -1
116
- else:
117
- res = -tl.exp(target)
118
-
119
- tl.store(new_grads_ptr + offsets, res, mask=mask)
120
-
121
-
122
- def kldiv_forward_triton(y_pred, y_true, log_target, reduction, eps): # [BT, V]
123
- BT, V = y_pred.shape
124
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
125
- num_warps = 32 if infer_device() == "xpu" else get_num_warps(BLOCK_SIZE)
126
-
127
- grid = (BT,)
128
- reduction = _str_to_reduction_mode[reduction]
129
-
130
- out_size = (BT, V) if reduction == _REDUCTION_MODE_NONE.value else (BT,)
131
- output_tensor = torch.zeros(out_size, device=y_pred.device, dtype=torch.float32)
132
-
133
- _kldiv_kernel_forward[grid](
134
- y_pred,
135
- y_pred.stride(0),
136
- y_true,
137
- y_true.stride(0),
138
- output_tensor,
139
- output_tensor.stride(0),
140
- V,
141
- eps=eps,
142
- BLOCK_SIZE=BLOCK_SIZE,
143
- num_warps=num_warps,
144
- log_target=log_target,
145
- reduction=reduction,
146
- )
147
-
148
- # calculated according to the reduction mode same as in Pytorch. In the later versions, `mean` will be changed to the same behavior as `batchmean`
149
- # https://pytorch.org/docs/stable/generated/torch.nn.KLDivLoss.html
150
- # https://github.com/pytorch/pytorch/blob/d7b57c4d63edb42e1deeeba9497fcb5f1f748ff2/torch/nn/functional.py#L3372
151
- if reduction == _REDUCTION_MODE_BATCHMEAN.value:
152
- return output_tensor.sum() / BT
153
- elif reduction == _REDUCTION_MODE_SUM.value:
154
- return output_tensor.sum(dim=0)
155
- elif reduction == _REDUCTION_MODE_MEAN.value:
156
- return output_tensor.sum() / (BT * V)
157
- else:
158
- return output_tensor
159
-
160
-
161
- def kldiv_backward_triton(target, grad_output, new_grads, log_target):
162
- BT, V = target.shape
163
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
164
- num_warps = 32 if infer_device() == "xpu" else get_num_warps(BLOCK_SIZE)
165
-
166
- grid = (BT,)
167
-
168
- # We store the gradients in-place in the input tensor
169
- _kldiv_kernel_backward[grid](
170
- target,
171
- target.stride(0),
172
- new_grads,
173
- new_grads.stride(0),
174
- V,
175
- BLOCK_SIZE=BLOCK_SIZE,
176
- num_warps=num_warps,
177
- log_target=log_target,
178
- )
179
-
180
- # If cross entropy is the last layer, grad_output is 1.0. Skip the mul then.
181
- if torch.equal(grad_output, torch.tensor(1.0, device=grad_output.device)):
182
- return new_grads
183
-
184
- return new_grads * grad_output
185
-
186
-
187
- class LigerKLDivLossFunction(torch.autograd.Function):
188
- """
189
- Class implementing the forward and backward pass for the KL Divergence Loss using Triton, as defined by the following formula:
190
- ```python
191
- if log_target:
192
- loss = target.exp() * (target - input)
193
- else:
194
- loss = target * (target.log() - input)
195
- ```,
196
- then the loss is reduced according to the `reduction` parameter.
197
- as defined in the PyTorch documentation: https://pytorch.org/docs/stable/generated/torch.nn.KLDivLoss.html
198
- """
199
-
200
- @staticmethod
201
- @ensure_contiguous
202
- def forward(
203
- ctx,
204
- y_pred: torch.Tensor,
205
- y_true: torch.Tensor,
206
- reduction: REDUCTION_LITERAL = "batchmean",
207
- log_target: bool = False,
208
- eps: float = 1e-10,
209
- ) -> torch.Tensor:
210
- """A forward pass for the KL Divergence Loss.
211
-
212
- Args:
213
- ctx: Torch autograd context
214
- y_pred (torch.Tensor): A tensor of shape (BT, V) containing the predicted values, expected to be log-probabilities.
215
- y_true (torch.Tensor): A tensor of shape (BT, V) containing the target values, expected to be either probabilities or log-probabilities, depending on the value of `log_target`.
216
- reduction (REDUCTION_LITERAL, optional): Reduction to be used. Defaults to "batchmean".
217
- log_target (bool, optional): If set to true, expects the ground truth to already be log-probabilities. Defaults to False.
218
- eps: (float, optional): A small value to avoid division by zero. Defaults to 1e-10.
219
-
220
- Returns:
221
- torch.Tensor: The computed KL Divergence Loss, with shape (BT, V) if `reduction` is "none", else a scalar.
222
- """
223
- ctx.save_for_backward(y_true)
224
- ctx.reduction = reduction
225
- ctx.log_target = log_target
226
- return kldiv_forward_triton(y_pred, y_true, log_target=log_target, reduction=reduction, eps=eps)
227
-
228
- @staticmethod
229
- @ensure_contiguous
230
- def backward(ctx, grad_output: torch.Tensor) -> torch.Tensor:
231
- """A backward pass for the KL Divergence Loss.
232
-
233
- Args:
234
- ctx: Torch autograd context
235
- grad_output (torch.Tensor): The gradient of the loss with respect to the output.
236
-
237
- Returns:
238
- tuple[torch.Tensor, None, None, None, None]: The gradient of the loss with respect to the inputs and None for the other arguments of the forward method.
239
- """
240
- (y_true,) = ctx.saved_tensors
241
-
242
- new_grads = torch.empty_like(y_true)
243
-
244
- derivative = kldiv_backward_triton(y_true, grad_output, new_grads, ctx.log_target)
245
-
246
- if ctx.reduction == "batchmean":
247
- derivative = derivative / y_true.shape[0]
248
- elif ctx.reduction == "sum" or ctx.reduction == "none":
249
- pass
250
- elif ctx.reduction == "mean":
251
- derivative = derivative / (y_true.shape[0] * y_true.shape[1])
252
-
253
- return (
254
- derivative,
255
- None,
256
- None,
257
- None,
258
- None,
259
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/layer_norm.py DELETED
@@ -1,320 +0,0 @@
1
- import math
2
- import operator
3
-
4
- import torch
5
- import triton
6
- import triton.language as tl
7
-
8
- from .utils import calculate_settings
9
- from .utils import compare_version
10
- from .utils import ensure_contiguous
11
- from .utils import get_npu_core_count
12
- from .utils import set_large_grf_mode
13
- from .utils import is_npu_available
14
-
15
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
16
- try:
17
- # typical import path with dispatch available
18
- from triton.language.extra.libdevice import rsqrt
19
- except ModuleNotFoundError:
20
- # for working with NGC containers
21
- from triton.language.extra.cuda.libdevice import rsqrt
22
- else:
23
- from triton.language.math import rsqrt
24
-
25
-
26
- @triton.jit
27
- def _layer_norm_forward_kernel(
28
- Y_ptr, # pointer to output, shape (n_rows, n_cols)
29
- Y_row_stride, # stride of each row in output
30
- X_ptr, # pointer to input, shape (n_rows, n_cols)
31
- X_row_stride, # stride of each row in input
32
- W_ptr, # pointer to weights, shape (n_cols,)
33
- W_row_stride, # stride of each row in weights
34
- B_ptr, # pointer to bias, shape (n_cols,)
35
- B_row_stride, # stride of each row in bias
36
- Mean_ptr, # pointer to mean, shape (n_rows,)
37
- Mean_row_stride, # stride of each row in mean
38
- RSTD_ptr, # pointer to rstd, shape (n_rows,)
39
- RSTD_row_stride, # stride of each row in rstd
40
- n_cols,
41
- eps,
42
- BLOCK_SIZE: tl.constexpr,
43
- ):
44
- """
45
- References:
46
- https://arxiv.org/abs/1607.06450
47
- https://github.com/karpathy/llm.c/blob/master/doc/layernorm/layernorm.md
48
- """
49
- row_idx = tl.program_id(0).to(tl.int64)
50
- col_offsets = tl.arange(0, BLOCK_SIZE)
51
- mask = col_offsets < n_cols
52
-
53
- # Pre-load weights and bias in fp32 to avoid repeated conversions
54
- W_row = tl.load(W_ptr + col_offsets, mask=mask, other=0.0)
55
- B_row = tl.load(B_ptr + col_offsets, mask=mask, other=0.0)
56
- W_f32 = W_row.to(tl.float32)
57
- B_f32 = B_row.to(tl.float32)
58
-
59
- # Calculate pointers for this row
60
- row_X_ptr = X_ptr + row_idx * X_row_stride
61
- row_Y_ptr = Y_ptr + row_idx * Y_row_stride
62
- row_Mean_ptr = Mean_ptr + row_idx * Mean_row_stride
63
- row_RSTD_ptr = RSTD_ptr + row_idx * RSTD_row_stride
64
-
65
- # Load input data and convert to fp32 for numerical stability
66
- X_row = tl.load(row_X_ptr + col_offsets, mask=mask, other=0.0)
67
- X_f32 = X_row.to(tl.float32)
68
-
69
- # Compute statistics in fp32 for numerical stability
70
- mean = tl.sum(X_f32, axis=0) / n_cols
71
- X_centered = X_f32 - mean
72
- # Apply mask to variance calculation to exclude contributions from masked elements
73
- X_centered_masked = tl.where(mask, X_centered, 0.0)
74
- var = tl.sum(X_centered_masked * X_centered_masked, axis=0) / n_cols
75
- rstd = rsqrt(var + eps)
76
-
77
- # Store statistics (convert back to original dtype only once)
78
- tl.store(row_Mean_ptr, mean.to(X_row.dtype))
79
- tl.store(row_RSTD_ptr, rstd.to(X_row.dtype))
80
-
81
- # Fused normalization and affine transformation
82
- # Y = (X - mean) * rstd * W + B = X_centered * rstd * W + B
83
- Y_f32 = X_centered * rstd * W_f32 + B_f32
84
-
85
- # Store output (single conversion back to original dtype)
86
- tl.store(row_Y_ptr + col_offsets, Y_f32.to(X_row.dtype), mask=mask)
87
-
88
-
89
- @triton.jit
90
- def _layer_norm_backward_kernel(
91
- X_ptr, # pointer to input, shape (n_rows, n_cols)
92
- stride_x, # stride of each row in input
93
- W_ptr, # pointer to weights, shape (n_cols,)
94
- Mean_ptr, # pointer to mean, shape (n_rows,)
95
- stride_mean, # stride of each row in mean
96
- RSTD_ptr, # pointer to rstd, shape (n_rows,)
97
- stride_rstd, # stride of each row in rstd
98
- DX_ptr, # pointer to input grad, shape (n_rows, n_cols)
99
- stride_dx, # stride of each row in input grad
100
- DW_ptr, # pointer to weights grad, shape (n_cols,)
101
- stride_dw, # stride of each row in weights grad
102
- DB_ptr, # pointer to bias grad, shape (n_cols,)
103
- stride_db, # stride of each row in bias grad
104
- DY_ptr, # pointer to output grad, shape (n_rows, n_cols)
105
- stride_dy, # stride of each row in output grad
106
- n_rows,
107
- n_cols,
108
- rows_per_program: tl.constexpr,
109
- BLOCK_SIZE: tl.constexpr,
110
- ):
111
- """
112
- References:
113
- https://arxiv.org/abs/1607.06450
114
- https://github.com/karpathy/llm.c/blob/master/doc/layernorm/layernorm.md
115
- """
116
- row_block_id = tl.program_id(0).to(tl.int64)
117
- row_start = row_block_id * rows_per_program
118
- row_end = min((row_block_id + 1) * rows_per_program, n_rows)
119
- cols = tl.arange(0, BLOCK_SIZE)
120
- mask = cols < n_cols
121
-
122
- dW_row = tl.zeros((BLOCK_SIZE,), dtype=tl.float32)
123
- db_row = tl.zeros((BLOCK_SIZE,), dtype=tl.float32)
124
-
125
- # Pre-load weights once (same optimization as forward pass)
126
- w = tl.load(W_ptr + cols, mask=mask, other=0.0)
127
- w_f32 = w.to(tl.float32)
128
-
129
- for row_idx in range(row_start, row_end):
130
- # Calculate pointers for this specific row
131
- row_X_ptr = X_ptr + row_idx * stride_x
132
- row_DX_ptr = DX_ptr + row_idx * stride_dx
133
- row_DY_ptr = DY_ptr + row_idx * stride_dy
134
- row_Mean_ptr = Mean_ptr + row_idx * stride_mean
135
- row_RSTD_ptr = RSTD_ptr + row_idx * stride_rstd
136
-
137
- # Load data for this row
138
- x = tl.load(row_X_ptr + cols, mask=mask, other=0.0)
139
- dy = tl.load(row_DY_ptr + cols, mask=mask, other=0.0)
140
- mean = tl.load(row_Mean_ptr)
141
- rstd = tl.load(row_RSTD_ptr)
142
-
143
- # Convert to fp32 for numerical stability
144
- x_f32 = x.to(tl.float32)
145
- dy_f32 = dy.to(tl.float32)
146
- mean_f32 = mean.to(tl.float32)
147
- rstd_f32 = rstd.to(tl.float32)
148
-
149
- # Compute backward pass for this row
150
- x_hat = (x_f32 - mean_f32) * rstd_f32
151
- wdy = w_f32 * dy_f32
152
- c1 = tl.sum(x_hat * wdy, axis=0) / n_cols
153
- c2 = tl.sum(wdy, axis=0) / n_cols
154
- dx = (wdy - (x_hat * c1 + c2)) * rstd_f32
155
-
156
- # Store input gradient
157
- tl.store(row_DX_ptr + cols, dx, mask=mask)
158
-
159
- # Accumulate weight and bias gradients for this thread block's assigned rows
160
- dw = dy_f32 * x_hat
161
- db = dy_f32
162
- dW_row += dw
163
- db_row += db
164
-
165
- tl.store(DW_ptr + row_block_id * stride_dw + cols, dW_row, mask=mask)
166
- tl.store(DB_ptr + row_block_id * stride_db + cols, db_row, mask=mask)
167
-
168
-
169
- def layer_norm_forward(X, W, B, eps):
170
- """
171
- Args:
172
- X: Input tensor of shape (..., hidden_size)
173
- W: Weight tensor of shape (hidden_size,)
174
- B: Bias tensor of shape (hidden_size,)
175
- eps: Small constant for numerical stability
176
-
177
- Returns:
178
- Tuple of (output, input, mean, rstd, block_size, num_warps)
179
- """
180
- shape = X.shape
181
- dim = shape[-1]
182
- X = X.view(-1, dim)
183
- n_rows, n_cols = X.shape
184
-
185
- # Calculate optimal block size and warp configuration
186
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
187
-
188
- # Allocate output tensors
189
- Y = torch.empty((n_rows, n_cols), dtype=X.dtype, device=X.device)
190
- Mean = torch.empty(n_rows, dtype=X.dtype, device=X.device)
191
- RSTD = torch.empty(n_rows, dtype=X.dtype, device=X.device)
192
-
193
- # Validate input dimensions
194
- if X.shape[1] != W.shape[0]:
195
- raise ValueError(
196
- f"Incompatible dimensions: input feature size (X.shape[1]={X.shape[1]}) "
197
- f"must match weight size (W.shape[0]={W.shape[0]})"
198
- )
199
-
200
- # XPU-specific optimization
201
- kernel_args = {}
202
- if X.device.type == "xpu":
203
- set_large_grf_mode(kernel_args)
204
-
205
- # Launch kernel with one thread block per row for optimal performance
206
- grid = (n_rows,)
207
- _layer_norm_forward_kernel[grid](
208
- Y,
209
- Y.stride(0),
210
- X,
211
- X.stride(0),
212
- W,
213
- W.stride(0),
214
- B,
215
- B.stride(0),
216
- Mean,
217
- Mean.stride(0),
218
- RSTD,
219
- RSTD.stride(0),
220
- n_cols,
221
- eps,
222
- BLOCK_SIZE=BLOCK_SIZE,
223
- num_warps=num_warps,
224
- **kernel_args,
225
- )
226
-
227
- return Y.view(*shape), X, Mean, RSTD, BLOCK_SIZE, num_warps
228
-
229
-
230
- def layer_norm_backward(dY, X, W, B, Mean, RSTD):
231
- """
232
- Args:
233
- dY: Gradient of output
234
- X: Input tensor
235
- W: Weight tensor
236
- B: Bias tensor
237
- Mean: Pre-computed mean
238
- RSTD: Pre-computed reciprocal standard deviation
239
-
240
- Returns:
241
- Tuple of (input_grad, weight_grad, bias_grad)
242
- """
243
- shape = dY.shape
244
- dim = shape[-1]
245
- dY = dY.view(-1, dim)
246
- n_rows, n_cols = dY.shape
247
-
248
- sm_count = 1
249
- if X.device.type == "cuda":
250
- sm_count = torch.cuda.get_device_properties(X.device).multi_processor_count
251
- elif X.device.type == "xpu":
252
- sm_count = torch.xpu.get_device_properties(X.device).gpu_eu_count
253
- elif X.device.type == "npu":
254
- sm_count = get_npu_core_count()
255
-
256
- # fp32 for numerical stability especially.
257
- _DW = torch.empty((sm_count, n_cols), dtype=torch.float32, device=W.device)
258
- _DB = torch.empty((sm_count, n_cols), dtype=torch.float32, device=W.device)
259
-
260
- # Calculate optimal block size and warp configuration
261
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
262
- if n_cols > BLOCK_SIZE:
263
- raise RuntimeError(f"Feature dimension {n_cols} exceeds maximum supported size of {BLOCK_SIZE}.")
264
- rows_per_program = math.ceil(n_rows / sm_count)
265
- grid = (sm_count,)
266
-
267
- # Allocate gradient tensors
268
- DX = torch.empty((n_rows, n_cols), dtype=X.dtype, device=X.device)
269
-
270
- kernel_args = {"num_warps": num_warps}
271
- # XPU-specific optimization
272
- if X.device.type == "xpu":
273
- kernel_args.update({"num_warps": 32, "num_stages": 4})
274
- set_large_grf_mode(kernel_args)
275
-
276
- # Launch kernel with one thread block per row for optimal performance
277
- _layer_norm_backward_kernel[grid](
278
- X,
279
- X.stride(0),
280
- W,
281
- Mean,
282
- Mean.stride(0),
283
- RSTD,
284
- RSTD.stride(0),
285
- DX,
286
- DX.stride(0),
287
- _DW,
288
- _DW.stride(0),
289
- _DB,
290
- _DB.stride(0),
291
- dY,
292
- dY.stride(0),
293
- n_rows,
294
- n_cols,
295
- rows_per_program=rows_per_program,
296
- BLOCK_SIZE=BLOCK_SIZE,
297
- **kernel_args,
298
- )
299
-
300
- DX = DX.view(*shape)
301
- DW = _DW.sum(dim=0).to(W.dtype)
302
- DB = _DB.sum(dim=0).to(B.dtype)
303
-
304
- return DX, DW, DB
305
-
306
-
307
- class LigerLayerNormFunction(torch.autograd.Function):
308
- @staticmethod
309
- @ensure_contiguous
310
- def forward(ctx, X, W, B, eps):
311
- Y, X, Mean, RSTD, BLOCK_SIZE, num_warps = layer_norm_forward(X, W, B, eps)
312
- ctx.save_for_backward(X, W, B, Mean, RSTD)
313
- return Y
314
-
315
- @staticmethod
316
- @ensure_contiguous
317
- def backward(ctx, dY):
318
- X, W, B, Mean, RSTD = ctx.saved_tensors
319
- DX, DW, DB = layer_norm_backward(dY, X, W, B, Mean, RSTD)
320
- return DX, DW, DB, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/layers.py DELETED
@@ -1,514 +0,0 @@
1
- import inspect
2
- from dataclasses import dataclass
3
- from typing import Optional, Tuple
4
-
5
- import torch
6
- import torch.nn as nn
7
-
8
- from .cross_entropy import LigerCrossEntropyFunction
9
- from .dyt import LigerDyTFunction
10
- from .fused_linear_cross_entropy import LigerFusedLinearCrossEntropyFunction
11
- from .geglu import LigerGELUMulFunction
12
- from .group_norm import LigerGroupNormFunction
13
- from .jsd import LigerJSDFunction
14
- from .kl_div import LigerKLDivLossFunction
15
- from .layer_norm import LigerLayerNormFunction
16
- from .qwen2vl_mrope import LigerQwen2VLMRopeFunction
17
- from .rms_norm import LigerRMSNormFunction
18
- from .rope import LigerRopeFunction
19
- from .swiglu import LigerSiLUMulFunction
20
- from .tiled_mlp import apply_tiled_mlp
21
- from .tvd import LigerTVDLossFunction
22
-
23
-
24
- class LigerRMSNorm(nn.Module):
25
- def __init__(
26
- self,
27
- hidden_size: int,
28
- eps: float = 1e-6,
29
- offset: float = 0.0,
30
- casting_mode: str = "llama",
31
- init_fn: str = "ones",
32
- in_place: bool = True,
33
- row_mode: Optional[bool] = None,
34
- elementwise_affine: bool = True,
35
- ):
36
- super().__init__()
37
- assert init_fn in ("ones", "zeros"), f"init_fn must be 'ones' or 'zeros', got {init_fn}"
38
- self.hidden_size = hidden_size
39
- self.variance_epsilon = eps
40
- self.offset = offset
41
- self.casting_mode = casting_mode
42
- self.in_place = in_place
43
- self.row_mode = row_mode
44
- self.elementwise_affine = elementwise_affine
45
- if elementwise_affine:
46
- init = torch.ones(hidden_size) if init_fn == "ones" else torch.zeros(hidden_size)
47
- self.weight = nn.Parameter(init)
48
- else:
49
- self.register_parameter("weight", None)
50
-
51
- def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
52
- return LigerRMSNormFunction.apply(
53
- hidden_states,
54
- self.weight,
55
- self.variance_epsilon,
56
- self.offset,
57
- self.casting_mode,
58
- self.in_place,
59
- self.row_mode,
60
- )
61
-
62
- def extra_repr(self) -> str:
63
- return (
64
- f"{self.hidden_size}, eps={self.variance_epsilon}, offset={self.offset}, "
65
- f"in_place={self.in_place}, row_mode={self.row_mode}"
66
- )
67
-
68
-
69
- class LigerLayerNorm(nn.Module):
70
- def __init__(
71
- self,
72
- hidden_size: int,
73
- eps: float = 1e-6,
74
- bias: bool = False,
75
- init_fn: str = "ones",
76
- ):
77
- super().__init__()
78
- assert init_fn in ("ones", "zeros"), f"init_fn must be 'ones' or 'zeros', got {init_fn}"
79
- self.hidden_size = hidden_size
80
- self.variance_epsilon = eps
81
- self.weight = nn.Parameter(torch.ones(hidden_size) if init_fn == "ones" else torch.zeros(hidden_size))
82
- self.bias = nn.Parameter(torch.randn(hidden_size) if bias else torch.zeros(hidden_size))
83
-
84
- def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
85
- return LigerLayerNormFunction.apply(hidden_states, self.weight, self.bias, self.variance_epsilon)
86
-
87
- def extra_repr(self) -> str:
88
- return f"{self.hidden_size}, eps={self.variance_epsilon}"
89
-
90
-
91
- class LigerGroupNorm(nn.Module):
92
- def __init__(
93
- self,
94
- num_channels: int,
95
- num_groups: int,
96
- eps: float = 1e-6,
97
- bias: bool = False,
98
- init_fn: str = "ones",
99
- ):
100
- super().__init__()
101
- assert init_fn in ("ones", "zeros"), f"init_fn must be 'ones' or 'zeros', got {init_fn}"
102
- assert num_channels % num_groups == 0, (
103
- f"num_channels ({num_channels}) must be divisible by num_groups ({num_groups})"
104
- )
105
- self.num_channels = num_channels
106
- self.num_groups = num_groups
107
- self.variance_epsilon = eps
108
- self.weight = nn.Parameter(torch.ones(num_channels) if init_fn == "ones" else torch.zeros(num_channels))
109
- self.bias = nn.Parameter(torch.randn(num_channels) if bias else torch.zeros(num_channels))
110
-
111
- def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
112
- assert hidden_states.dim() >= 3, f"Input must have at least 3 dimensions, got {hidden_states.dim()}"
113
- assert hidden_states.size(1) == self.num_channels, (
114
- f"Input must have {self.num_channels} channels, got {hidden_states.size(1)}"
115
- )
116
- return LigerGroupNormFunction.apply(
117
- hidden_states,
118
- self.weight,
119
- self.bias,
120
- self.num_channels,
121
- self.num_groups,
122
- self.variance_epsilon,
123
- )
124
-
125
- def extra_repr(self) -> str:
126
- return f"num_channels={self.num_channels}, num_groups={self.num_groups}, eps={self.variance_epsilon}"
127
-
128
-
129
- class LigerDyT(nn.Module):
130
- def __init__(self, hidden_size: int, beta: bool = True, init_alpha: float = 0.5):
131
- super().__init__()
132
- self.hidden_size = hidden_size
133
- self.init_alpha = init_alpha
134
- self.alpha = nn.Parameter(torch.ones(1) * init_alpha)
135
- self.gamma = nn.Parameter(torch.ones(hidden_size))
136
- self.beta = nn.Parameter(torch.zeros(hidden_size)) if beta else None
137
-
138
- def forward(self, x: torch.Tensor) -> torch.Tensor:
139
- return LigerDyTFunction.apply(x, self.alpha, self.gamma, self.beta)
140
-
141
- def extra_repr(self) -> str:
142
- return f"{self.hidden_size}, init_alpha={self.init_alpha}, beta={self.beta is not None}"
143
-
144
-
145
- class LigerCrossEntropyLoss(nn.Module):
146
- def __init__(
147
- self,
148
- weight: Optional[torch.Tensor] = None,
149
- ignore_index: int = -100,
150
- lse_square_scale: float = 0.0,
151
- label_smoothing: float = 0.0,
152
- reduction: str = "mean",
153
- softcap: Optional[float] = None,
154
- ):
155
- super().__init__()
156
- assert 0.0 <= label_smoothing <= 1.0, f"label_smoothing must be in [0, 1], got {label_smoothing}"
157
- assert reduction in ("mean", "sum", "none"), f"reduction must be 'mean', 'sum', or 'none', got {reduction}"
158
- assert softcap is None or softcap > 0, f"softcap must be > 0 or None, got {softcap}"
159
- self.weight = weight
160
- self.ignore_index = ignore_index
161
- self.lse_square_scale = lse_square_scale
162
- self.label_smoothing = label_smoothing
163
- self.reduction = reduction
164
- self.softcap = softcap
165
-
166
- def forward(self, _input: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
167
- loss, _, _, _ = LigerCrossEntropyFunction.apply(
168
- _input,
169
- target,
170
- self.weight,
171
- self.ignore_index,
172
- self.lse_square_scale,
173
- self.label_smoothing,
174
- self.reduction,
175
- self.softcap,
176
- False,
177
- False,
178
- False,
179
- )
180
- return loss
181
-
182
-
183
- class LigerFusedLinearCrossEntropyLoss(nn.Module):
184
- def __init__(
185
- self,
186
- ce_weight: Optional[torch.Tensor] = None,
187
- ignore_index: int = -100,
188
- lse_square_scale: float = 0.0,
189
- label_smoothing: float = 0.0,
190
- reduction: str = "mean",
191
- softcap: Optional[float] = None,
192
- accum_dtype: Optional[torch.dtype] = None,
193
- use_token_scaling: bool = False,
194
- ):
195
- super().__init__()
196
- assert 0.0 <= label_smoothing <= 1.0, f"label_smoothing must be in [0, 1], got {label_smoothing}"
197
- assert reduction in ("mean", "sum", "none"), f"reduction must be 'mean', 'sum', or 'none', got {reduction}"
198
- assert softcap is None or softcap > 0, f"softcap must be > 0 or None, got {softcap}"
199
- self.ce_weight = ce_weight
200
- self.ignore_index = ignore_index
201
- self.lse_square_scale = lse_square_scale
202
- self.label_smoothing = label_smoothing
203
- self.reduction = reduction
204
- self.softcap = softcap
205
- self.accum_dtype = accum_dtype
206
- self.use_token_scaling = use_token_scaling
207
-
208
- def forward(
209
- self,
210
- lin_weight: torch.Tensor,
211
- _input: torch.Tensor,
212
- target: torch.Tensor,
213
- bias: Optional[torch.Tensor] = None,
214
- ) -> torch.Tensor:
215
- loss, _, _, _ = LigerFusedLinearCrossEntropyFunction.apply(
216
- _input,
217
- lin_weight,
218
- target,
219
- bias,
220
- self.ce_weight,
221
- self.ignore_index,
222
- self.lse_square_scale,
223
- self.label_smoothing,
224
- self.reduction,
225
- self.softcap,
226
- False,
227
- self.accum_dtype,
228
- self.use_token_scaling,
229
- False,
230
- False,
231
- )
232
- return loss
233
-
234
-
235
- class LigerJSD(nn.Module):
236
- def __init__(self, beta: float = 0.5, ignore_index: int = -100):
237
- super().__init__()
238
- self.beta = beta
239
- self.ignore_index = ignore_index
240
-
241
- def forward(
242
- self,
243
- log_q: torch.Tensor,
244
- log_p: torch.Tensor,
245
- shift_labels: Optional[torch.Tensor] = None,
246
- ) -> torch.Tensor:
247
- return LigerJSDFunction.apply(log_q, log_p, shift_labels, self.beta, self.ignore_index)
248
-
249
-
250
- class LigerKLDIVLoss(nn.KLDivLoss):
251
- def __init__(self, eps: float = 1e-10, *args, **kwargs):
252
- super().__init__(*args, **kwargs)
253
- self.eps = eps
254
-
255
- def forward(self, y_pred: torch.Tensor, y_true: torch.Tensor) -> torch.Tensor:
256
- return LigerKLDivLossFunction.apply(y_pred, y_true, self.reduction, self.log_target, self.eps)
257
-
258
-
259
- class LigerTVDLoss(nn.Module):
260
- def __init__(self, reduction: str = "batchmean", ignore_index: int = -100):
261
- super().__init__()
262
- self.reduction = reduction
263
- self.ignore_index = ignore_index
264
-
265
- def forward(
266
- self,
267
- p: torch.Tensor,
268
- q: torch.Tensor,
269
- shift_labels: Optional[torch.Tensor] = None,
270
- ) -> torch.Tensor:
271
- return LigerTVDLossFunction.apply(p, q, shift_labels, self.reduction, self.ignore_index)
272
-
273
-
274
- class LigerSwiGLUMLP(nn.Module):
275
- """SwiGLU MLP block. ``config`` must expose ``hidden_size``, ``intermediate_size``,
276
- and ``hidden_act`` (must be ``silu`` or ``swish``)."""
277
-
278
- def __init__(self, config):
279
- super().__init__()
280
- if config.hidden_act not in ("silu", "swish"):
281
- raise ValueError(f"Activation function {config.hidden_act} not supported.")
282
- self.config = config
283
- self.hidden_size = config.hidden_size
284
- self.intermediate_size = config.intermediate_size
285
- self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
286
- self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
287
- self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
288
-
289
- def forward(self, x: torch.Tensor) -> torch.Tensor:
290
- return self.down_proj(LigerSiLUMulFunction.apply(self.gate_proj(x), self.up_proj(x)))
291
-
292
-
293
- class LigerGEGLUMLP(nn.Module):
294
- """GEGLU MLP block. ``config`` must expose ``hidden_size`` and ``intermediate_size``.
295
- Uses the tanh approximation of GELU (matches Gemma 1/1.1/2)."""
296
-
297
- def __init__(self, config):
298
- super().__init__()
299
- self.config = config
300
- self.hidden_size = config.hidden_size
301
- self.intermediate_size = config.intermediate_size
302
- self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
303
- self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
304
- self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
305
-
306
- def forward(self, x: torch.Tensor) -> torch.Tensor:
307
- return self.down_proj(LigerGELUMulFunction.apply(self.gate_proj(x), self.up_proj(x)))
308
-
309
-
310
- class LigerTiledGEGLUMLP(nn.Module):
311
- gate_proj: nn.Linear
312
- up_proj: nn.Linear
313
- down_proj: nn.Linear
314
- num_shards: int
315
-
316
- def _mlp_forward(self, module, x):
317
- """Internal MLP forward function for tiled computation."""
318
- gate = module.gate_proj(x)
319
- up = module.up_proj(x)
320
- return module.down_proj(LigerGELUMulFunction.apply(gate, up))
321
-
322
- def forward(self, x: torch.Tensor) -> torch.Tensor:
323
- compute_params = [p for p in self.parameters() if p.requires_grad]
324
-
325
- return apply_tiled_mlp(
326
- fn=self._mlp_forward,
327
- mlp_module=self,
328
- x=x,
329
- num_shards=self.num_shards,
330
- compute_params=compute_params,
331
- )
332
-
333
-
334
- class LigerTiledSwiGLUMLP(nn.Module):
335
- gate_proj: nn.Linear
336
- up_proj: nn.Linear
337
- down_proj: nn.Linear
338
- num_shards: int
339
-
340
- def _mlp_forward(self, module, x):
341
- """Internal MLP forward function for tiled computation."""
342
- gate = module.gate_proj(x)
343
- up = module.up_proj(x)
344
- return module.down_proj(LigerSiLUMulFunction.apply(gate, up))
345
-
346
- def forward(self, x: torch.Tensor) -> torch.Tensor:
347
- compute_params = [p for p in self.parameters() if p.requires_grad]
348
-
349
- return apply_tiled_mlp(
350
- fn=self._mlp_forward,
351
- mlp_module=self,
352
- x=x,
353
- num_shards=self.num_shards,
354
- compute_params=compute_params,
355
- )
356
-
357
-
358
- @dataclass
359
- class CrossEntropyOutput:
360
- loss: torch.Tensor
361
- z_loss: Optional[torch.Tensor] = None
362
- token_accuracy: Optional[torch.Tensor] = None
363
- predicted_tokens: Optional[torch.Tensor] = None
364
-
365
-
366
- def liger_fused_linear_cross_entropy(
367
- input: torch.Tensor,
368
- weight: torch.Tensor,
369
- target: torch.Tensor,
370
- bias: Optional[torch.Tensor] = None,
371
- ce_weight: Optional[torch.Tensor] = None,
372
- ignore_index: int = -100,
373
- lse_square_scale: float = 0.0,
374
- label_smoothing: float = 0.0,
375
- reduction: str = "mean",
376
- softcap: Optional[float] = None,
377
- return_z_loss: bool = False,
378
- accum_dtype: Optional[torch.dtype] = None,
379
- use_token_scaling: bool = False,
380
- return_token_accuracy: bool = False,
381
- return_predicted_tokens: bool = False,
382
- ):
383
- loss, z_loss, token_accuracy, predicted_tokens = LigerFusedLinearCrossEntropyFunction.apply(
384
- input,
385
- weight,
386
- target,
387
- bias,
388
- ce_weight,
389
- ignore_index,
390
- lse_square_scale,
391
- label_smoothing,
392
- reduction,
393
- softcap,
394
- return_z_loss,
395
- accum_dtype,
396
- use_token_scaling,
397
- return_token_accuracy,
398
- return_predicted_tokens,
399
- )
400
- if not return_z_loss and not return_token_accuracy and not return_predicted_tokens:
401
- return loss
402
- return CrossEntropyOutput(
403
- loss=loss,
404
- z_loss=z_loss,
405
- token_accuracy=token_accuracy,
406
- predicted_tokens=predicted_tokens,
407
- )
408
-
409
-
410
- def LigerForCausalLMLoss(
411
- hidden_states: torch.Tensor,
412
- lm_head_weight: torch.Tensor,
413
- labels: torch.Tensor,
414
- hidden_size: int,
415
- num_items_in_batch: Optional[int] = None,
416
- ignore_index: int = -100,
417
- shift_labels: Optional[torch.Tensor] = None,
418
- final_logit_softcapping: Optional[float] = None,
419
- return_token_accuracy: bool = False,
420
- return_predicted_tokens: bool = False,
421
- **kwargs,
422
- ):
423
- """Drop-in replacement for ``transformers.loss.ForCausalLMLoss`` that fuses the
424
- final ``lm_head`` projection with the cross-entropy loss. Returns a scalar
425
- ``loss`` by default; returns a :class:`CrossEntropyOutput` when
426
- ``return_token_accuracy`` or ``return_predicted_tokens`` is set."""
427
- applicable_params = inspect.signature(liger_fused_linear_cross_entropy).parameters
428
- kwargs = {k: v for k, v in kwargs.items() if k in applicable_params}
429
-
430
- if shift_labels is None:
431
- labels = nn.functional.pad(labels, (0, 1), value=ignore_index)
432
- shift_labels = labels[..., 1:].contiguous()
433
-
434
- hidden_states = hidden_states.view(-1, hidden_size)
435
- shift_labels = shift_labels.view(-1).to(hidden_states.device)
436
-
437
- reduction = "sum" if num_items_in_batch is not None else "mean"
438
- result = liger_fused_linear_cross_entropy(
439
- hidden_states,
440
- lm_head_weight,
441
- shift_labels,
442
- reduction=reduction,
443
- ignore_index=ignore_index,
444
- softcap=final_logit_softcapping,
445
- return_token_accuracy=return_token_accuracy,
446
- return_predicted_tokens=return_predicted_tokens,
447
- **kwargs,
448
- )
449
-
450
- if isinstance(result, CrossEntropyOutput):
451
- loss = result.loss
452
- token_accuracy = result.token_accuracy
453
- predicted_tokens = result.predicted_tokens
454
- else:
455
- loss = result
456
- token_accuracy = None
457
- predicted_tokens = None
458
-
459
- if reduction == "sum":
460
- loss = loss / num_items_in_batch
461
-
462
- if return_token_accuracy or return_predicted_tokens:
463
- return CrossEntropyOutput(
464
- loss=loss,
465
- token_accuracy=token_accuracy,
466
- predicted_tokens=predicted_tokens,
467
- )
468
- return loss
469
-
470
-
471
- def liger_rotary_pos_emb(
472
- q: torch.Tensor,
473
- k: torch.Tensor,
474
- cos: torch.Tensor,
475
- sin: torch.Tensor,
476
- position_ids: Optional[torch.Tensor] = None,
477
- unsqueeze_dim: int = 1,
478
- ) -> Tuple[torch.Tensor, torch.Tensor]:
479
- """Apply standard rotary positional embedding to ``q`` and ``k``."""
480
- return LigerRopeFunction.apply(q, k, cos, sin, position_ids, unsqueeze_dim)
481
-
482
-
483
- def liger_multimodal_rotary_pos_emb(
484
- q: torch.Tensor,
485
- k: torch.Tensor,
486
- cos: torch.Tensor,
487
- sin: torch.Tensor,
488
- mrope_section,
489
- unsqueeze_dim: int = 1,
490
- ) -> Tuple[torch.Tensor, torch.Tensor]:
491
- """Apply Qwen2-VL multimodal rotary positional embedding (M-RoPE) to ``q`` and ``k``."""
492
- return LigerQwen2VLMRopeFunction.apply(q, k, cos, sin, mrope_section, unsqueeze_dim)
493
-
494
-
495
- __all__ = [
496
- "LigerRMSNorm",
497
- "LigerLayerNorm",
498
- "LigerGroupNorm",
499
- "LigerDyT",
500
- "LigerCrossEntropyLoss",
501
- "LigerFusedLinearCrossEntropyLoss",
502
- "LigerJSD",
503
- "LigerKLDIVLoss",
504
- "LigerTVDLoss",
505
- "LigerSwiGLUMLP",
506
- "LigerGEGLUMLP",
507
- "LigerTiledGEGLUMLP",
508
- "LigerTiledSwiGLUMLP",
509
- "CrossEntropyOutput",
510
- "liger_fused_linear_cross_entropy",
511
- "LigerForCausalLMLoss",
512
- "liger_rotary_pos_emb",
513
- "liger_multimodal_rotary_pos_emb",
514
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/liger_kernels/__init__.py DELETED
@@ -1,26 +0,0 @@
1
- import ctypes
2
- import importlib.util
3
- import sys
4
- from pathlib import Path
5
- from types import ModuleType
6
-
7
-
8
- def _import_from_path(file_path: Path) -> ModuleType:
9
- # We cannot use the module name as-is, after adding it to `sys.modules`,
10
- # it would also be used for other imports. So, we make a module name that
11
- # depends on the path for it to be unique using the hex-encoded hash of
12
- # the path.
13
- path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
- module_name = path_hash
15
- spec = importlib.util.spec_from_file_location(module_name, file_path)
16
- if spec is None:
17
- raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
- module = importlib.util.module_from_spec(spec)
19
- if module is None:
20
- raise ImportError(f"Cannot load module {module_name} from spec")
21
- sys.modules[module_name] = module
22
- spec.loader.exec_module(module) # type: ignore
23
- return module
24
-
25
-
26
- globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/metadata.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "name": "liger-kernels",
3
- "id": "_liger_kernels_rocm_ab435e2",
4
- "version": 1,
5
- "license": "BSD-2-Clause",
6
- "python-depends": [],
7
- "backend": {
8
- "type": "rocm"
9
- }
10
- }
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/qwen2vl_mrope.py DELETED
@@ -1,222 +0,0 @@
1
- import torch
2
- import triton
3
- import triton.language as tl
4
-
5
-
6
- @triton.jit
7
- def _triton_qwen2vl_mrope(
8
- q_ptr,
9
- k_ptr,
10
- cos,
11
- sin,
12
- sl,
13
- bs: tl.constexpr,
14
- n_qh: tl.constexpr,
15
- n_kh: tl.constexpr,
16
- hd: tl.constexpr,
17
- pad_n_qh: tl.constexpr,
18
- pad_n_kh: tl.constexpr,
19
- pad_hd: tl.constexpr,
20
- mrope_section_t: tl.constexpr,
21
- mrope_section_h: tl.constexpr,
22
- BLOCK_SIZE: tl.constexpr,
23
- BACKWARD_PASS: tl.constexpr = False,
24
- ):
25
- pid = tl.program_id(0)
26
-
27
- # locate start address
28
- q_ptr = q_ptr + pid * (n_qh * hd)
29
- k_ptr = k_ptr + pid * (n_kh * hd)
30
-
31
- # ####################################################################
32
- # get the cos(mθ_{i...d/2}) and sin(mθ_{i...d/2}) for token position
33
- # m of this program instance
34
- # ####################################################################
35
-
36
- # 1. program instances are laid out in a 1D vector of size bsz * seq_len, which
37
- # effectively represents a 2D grid of size [bsz, seq_len] with seq_len dimension
38
- # being the fastest changing dimension. Thus we can simply do pid // sl to get the batch index
39
- # and pid % sl to get the sequence index.
40
- # 2. We only need the left half of cos and sin matrix because the right half is just
41
- # a clone of the left half.
42
- t_end = mrope_section_t
43
- h_end = t_end + mrope_section_h
44
-
45
- t_cos = cos + pid * hd
46
- h_cos = t_cos + bs * sl * hd
47
- w_cos = h_cos + bs * sl * hd
48
- t_sin = sin + pid * hd
49
- h_sin = t_sin + bs * sl * hd
50
- w_sin = h_sin + bs * sl * hd
51
-
52
- cos_offsets = tl.arange(0, pad_hd // 2)
53
- t_mask = cos_offsets < t_end
54
- h_mask = (t_end <= cos_offsets) & (cos_offsets < h_end)
55
- w_mask = (h_end <= cos_offsets) & (cos_offsets < hd // 2)
56
- t_cos_row = tl.load(t_cos + cos_offsets, mask=t_mask, other=0)
57
- h_cos_row = tl.load(h_cos + cos_offsets, mask=h_mask, other=0)
58
- w_cos_row = tl.load(w_cos + cos_offsets, mask=w_mask, other=0)
59
- t_sin_row = tl.load(t_sin + cos_offsets, mask=t_mask, other=0)
60
- h_sin_row = tl.load(h_sin + cos_offsets, mask=h_mask, other=0)
61
- w_sin_row = tl.load(w_sin + cos_offsets, mask=w_mask, other=0)
62
- cos_row = t_cos_row + h_cos_row + w_cos_row
63
- sin_row = t_sin_row + h_sin_row + w_sin_row
64
-
65
- # ####################################################################
66
- # Load the left and right half of q and k for the current
67
- # program instance (i.e. for the current token) separately
68
- # ####################################################################
69
- # left half of the head
70
- first_half_q_offsets = tl.arange(0, pad_n_qh)[:, None] * hd + tl.arange(0, pad_hd // 2)[None, :]
71
- first_half_k_offsets = tl.arange(0, pad_n_kh)[:, None] * hd + tl.arange(0, pad_hd // 2)[None, :]
72
- first_q_mask = (tl.arange(0, pad_n_qh)[:, None] < n_qh) & (tl.arange(0, pad_hd // 2)[None, :] < hd // 2)
73
- first_k_mask = (tl.arange(0, pad_n_kh)[:, None] < n_kh) & (tl.arange(0, pad_hd // 2)[None, :] < hd // 2)
74
- q_tile_1 = tl.load(q_ptr + first_half_q_offsets, mask=first_q_mask, other=0).to(sin_row.dtype)
75
- k_tile_1 = tl.load(k_ptr + first_half_k_offsets, mask=first_k_mask, other=0).to(sin_row.dtype)
76
-
77
- # right half of the head
78
- second_half_q_offsets = first_half_q_offsets + (hd // 2)
79
- second_half_k_offsets = first_half_k_offsets + (hd // 2)
80
- second_q_mask = first_q_mask
81
- second_k_mask = first_k_mask
82
- q_tile_2 = tl.load(q_ptr + second_half_q_offsets, mask=second_q_mask, other=0).to(sin_row.dtype)
83
- k_tile_2 = tl.load(k_ptr + second_half_k_offsets, mask=second_k_mask, other=0).to(sin_row.dtype)
84
-
85
- if not BACKWARD_PASS:
86
- # y = [x1, x2] * [cos, cos] + [-x2, x1] * [sin, sin]
87
- new_q_tile_1 = q_tile_1 * cos_row - q_tile_2 * sin_row
88
- tl.store(q_ptr + first_half_q_offsets, new_q_tile_1, mask=first_q_mask)
89
- new_q_tile_2 = q_tile_2 * cos_row + q_tile_1 * sin_row
90
- tl.store(q_ptr + second_half_q_offsets, new_q_tile_2, mask=second_q_mask)
91
-
92
- new_k_tile_1 = k_tile_1 * cos_row - k_tile_2 * sin_row
93
- tl.store(k_ptr + first_half_k_offsets, new_k_tile_1, mask=first_k_mask)
94
- new_k_tile_2 = k_tile_2 * cos_row + k_tile_1 * sin_row
95
- tl.store(k_ptr + second_half_k_offsets, new_k_tile_2, mask=second_k_mask)
96
- else:
97
- # with some math, we can get:
98
- # dy = [dx1, dx2] * [cos, cos] + [-dx2, dx1] * [-sin, -sin]
99
- new_q_tile_1 = q_tile_1 * cos_row + q_tile_2 * sin_row
100
- tl.store(q_ptr + first_half_q_offsets, new_q_tile_1, mask=first_q_mask)
101
- new_q_tile_2 = q_tile_2 * cos_row - q_tile_1 * sin_row
102
- tl.store(q_ptr + second_half_q_offsets, new_q_tile_2, mask=second_q_mask)
103
-
104
- new_k_tile_1 = k_tile_1 * cos_row + k_tile_2 * sin_row
105
- tl.store(k_ptr + first_half_k_offsets, new_k_tile_1, mask=first_k_mask)
106
- new_k_tile_2 = k_tile_2 * cos_row - k_tile_1 * sin_row
107
- tl.store(k_ptr + second_half_k_offsets, new_k_tile_2, mask=second_k_mask)
108
-
109
-
110
- def qwen2vl_mrope_forward(q, k, cos, sin, mrope_section):
111
- # transpose it back to the physical shape because Triton looks at the physical storage
112
- # note: q and k are incontiguous before the transformation and will become contiguous after transpose
113
- q = q.transpose(1, 2)
114
- k = k.transpose(1, 2)
115
-
116
- batch_size, seq_len, n_q_head, head_dim = q.shape
117
- n_kv_head = k.shape[2]
118
- pad_hd = triton.next_power_of_2(head_dim)
119
- pad_n_q_head = triton.next_power_of_2(n_q_head)
120
- pad_n_kv_head = triton.next_power_of_2(n_kv_head)
121
- BLOCK_SIZE = max(pad_n_q_head, pad_n_kv_head)
122
-
123
- n_row = batch_size * seq_len
124
-
125
- # ensure tensors passed into the kernel are contiguous. It will be no-op if they are already contiguous
126
- q = q.contiguous()
127
- k = k.contiguous()
128
- cos = cos.contiguous()
129
- sin = sin.contiguous()
130
-
131
- _triton_qwen2vl_mrope[(n_row,)](
132
- q,
133
- k,
134
- cos,
135
- sin,
136
- seq_len,
137
- batch_size,
138
- n_q_head,
139
- n_kv_head,
140
- head_dim,
141
- pad_n_q_head,
142
- pad_n_kv_head,
143
- pad_hd,
144
- mrope_section[0],
145
- mrope_section[1],
146
- BLOCK_SIZE=BLOCK_SIZE,
147
- BACKWARD_PASS=False,
148
- )
149
- return q.transpose(1, 2), k.transpose(1, 2), cos, sin
150
-
151
-
152
- def qwen2vl_mrope_backward(dq, dk, cos, sin, mrope_section):
153
- dq = dq.transpose(1, 2)
154
- dk = dk.transpose(1, 2)
155
-
156
- batch_size, seq_len, n_q_head, head_dim = dq.shape
157
- n_kv_head = dk.shape[2]
158
- pad_hd = triton.next_power_of_2(head_dim)
159
- pad_n_q_head = triton.next_power_of_2(n_q_head)
160
- pad_n_kv_head = triton.next_power_of_2(n_kv_head)
161
- BLOCK_SIZE = max(pad_n_q_head, pad_n_kv_head)
162
-
163
- n_row = batch_size * seq_len
164
-
165
- # ensure dq and dk are contiguous
166
- dq = dq.contiguous()
167
- dk = dk.contiguous()
168
-
169
- # backward is similar to forward except swapping few ops
170
- _triton_qwen2vl_mrope[(n_row,)](
171
- dq,
172
- dk,
173
- cos,
174
- sin,
175
- seq_len,
176
- batch_size,
177
- n_q_head,
178
- n_kv_head,
179
- head_dim,
180
- pad_n_q_head,
181
- pad_n_kv_head,
182
- pad_hd,
183
- mrope_section[0],
184
- mrope_section[1],
185
- BLOCK_SIZE=BLOCK_SIZE,
186
- BACKWARD_PASS=True,
187
- )
188
- return dq.transpose(1, 2), dk.transpose(1, 2)
189
-
190
-
191
- class LigerQwen2VLMRopeFunction(torch.autograd.Function):
192
- """
193
- Triton implementation of the Qwen2VL Multimodal Rotary Positional Embedding (M-RoPE) operation.
194
-
195
- Please find the corresponding HuggingFace implementation here:
196
- https://github.com/huggingface/transformers/blob/main/src/transformers/models/qwen2_vl/modeling_qwen2_vl.py
197
- """
198
-
199
- @staticmethod
200
- def forward(ctx, q, k, cos, sin, mrope_section, unsqueeze_dim=1):
201
- """
202
- q size: (bsz, n_q_head, seq_len, head_dim)
203
- k size: (bsz, n_kv_head, seq_len, head_dim)
204
- cos size: (3, bsz, seq_len, head_dim)
205
- sin size: (3, bsz, seq_len, head_dim)
206
- """
207
- q, k, cos, sin = qwen2vl_mrope_forward(q, k, cos, sin, mrope_section)
208
- ctx.save_for_backward(cos, sin)
209
- ctx.mrope_section = mrope_section
210
- return q, k
211
-
212
- def backward(ctx, dq, dk):
213
- """
214
- dq size: (bsz, n_q_head, seq_len, head_dim)
215
- dk size: (bsz, n_kv_head, seq_len, head_dim)
216
- cos size: (3, bsz, seq_len, head_dim)
217
- sin size: (3, bsz, seq_len, head_dim)
218
- """
219
- cos, sin = ctx.saved_tensors
220
- mrope_section = ctx.mrope_section
221
- dq, dk = qwen2vl_mrope_backward(dq, dk, cos, sin, mrope_section)
222
- return dq, dk, None, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/rms_norm.py DELETED
@@ -1,654 +0,0 @@
1
- """
2
- This file incorporates code from Unsloth licensed under the Apache License, Version 2.0.
3
- See the original Unsloth repository at https://github.com/unslothai/unsloth.
4
-
5
- The following line
6
- https://github.com/linkedin/Liger-Kernel/blob/7382a8761f9af679482b968f9348013d933947c7/src/liger_kernel/ops/rms_norm.py#L30
7
- is based on code from Unsloth, located at:
8
- https://github.com/unslothai/unsloth/blob/fd753fed99ed5f10ef8a9b7139588d9de9ddecfb/unsloth/kernels/rms_layernorm.py#L22
9
-
10
- Modifications made by Yanning Chen, 2024.
11
- """
12
-
13
- import math
14
- import operator
15
-
16
- import torch
17
- import triton
18
- import triton.language as tl
19
-
20
- from .utils import calculate_settings
21
- from .utils import compare_version
22
- from .utils import ensure_contiguous
23
- from .utils import get_npu_core_count
24
- from .utils import set_large_grf_mode
25
- from .utils import torch_to_triton_dtype
26
- from .utils import is_npu_available
27
-
28
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
29
- try:
30
- # typical import path with dispatch available
31
- from triton.language.extra.libdevice import rsqrt
32
- except ModuleNotFoundError:
33
- # for working with NGC containers
34
- from triton.language.extra.cuda.libdevice import rsqrt
35
- else:
36
- from triton.language.math import rsqrt
37
-
38
-
39
- _CASTING_MODE_NONE: tl.constexpr = tl.constexpr(-1)
40
- _CASTING_MODE_LLAMA: tl.constexpr = tl.constexpr(0)
41
- _CASTING_MODE_GEMMA: tl.constexpr = tl.constexpr(1)
42
-
43
-
44
- @triton.jit
45
- def _rms_norm_forward_kernel(
46
- Y_ptr,
47
- Y_row_stride,
48
- X_ptr,
49
- X_row_stride,
50
- W_ptr,
51
- W_row_stride,
52
- RSTD_ptr,
53
- RSTD_row_stride,
54
- n_cols,
55
- eps,
56
- offset,
57
- casting_mode: tl.constexpr, # constexpr so the `if` blocks can be optimized out
58
- elementwise_affine: tl.constexpr,
59
- BLOCK_SIZE: tl.constexpr,
60
- ):
61
- """
62
- y_i = (x_i / (RMS)) * (offset + wi), RMS = sqrt(sum(x_i^2) / N)
63
-
64
- Reference:
65
- 1. https://triton-lang.org/main/getting-started/tutorials/05-layer-norm.html
66
- 2. https://github.com/unslothai/unsloth/blob/fd753fed99ed5f10ef8a9b7139588d9de9ddecfb/unsloth/kernels/rms_layernorm.py#L22
67
- 3. https://arxiv.org/pdf/1910.07467
68
- """
69
-
70
- row_idx = tl.program_id(0).to(tl.int64)
71
- col_offsets = tl.arange(0, BLOCK_SIZE)
72
- mask = col_offsets < n_cols
73
-
74
- y_base = Y_ptr + row_idx * Y_row_stride
75
- x_base = X_ptr + row_idx * X_row_stride
76
- rstd_base = RSTD_ptr + row_idx * RSTD_row_stride
77
-
78
- X_row = tl.load(x_base + col_offsets, mask=mask, other=0)
79
- X_row_dtype = X_row.dtype
80
- if elementwise_affine:
81
- W_row = tl.load(W_ptr + col_offsets, mask=mask, other=0)
82
-
83
- # On Llama, only rstd is computed on fp32
84
- if casting_mode == _CASTING_MODE_LLAMA:
85
- X_row = X_row.to(tl.float32)
86
-
87
- # Gemma computes everything on fp32, and then casts back the output to the original dtype
88
- if casting_mode == _CASTING_MODE_GEMMA:
89
- if elementwise_affine:
90
- W_row = W_row.to(tl.float32)
91
- X_row = X_row.to(tl.float32)
92
-
93
- if casting_mode == _CASTING_MODE_NONE:
94
- eps = eps.to(X_row_dtype)
95
- offset = offset.to(X_row_dtype)
96
-
97
- mean_square = tl.sum(X_row * X_row, axis=0) / n_cols
98
- rstd = rsqrt(mean_square + eps)
99
-
100
- # We can save time by caching rms with minimal memory overhead
101
- # because rms is much smaller compared to X_row, as rms is for each row.
102
- # However, on the computation side, it can save 4 operations (*, sum, /, sqrt).
103
- tl.store(rstd_base, rstd)
104
-
105
- X_row = X_row * rstd
106
-
107
- # On Llama, the multiplication with the weight is done on the original dtype
108
- if casting_mode == _CASTING_MODE_LLAMA:
109
- X_row = X_row.to(X_row_dtype)
110
-
111
- if elementwise_affine:
112
- Y_row = X_row * (offset + W_row)
113
- else:
114
- Y_row = X_row
115
-
116
- if casting_mode == _CASTING_MODE_GEMMA:
117
- Y_row = Y_row.to(X_row_dtype)
118
-
119
- tl.store(y_base + col_offsets, Y_row, mask=mask)
120
-
121
-
122
- @triton.jit
123
- def _rms_norm_backward_kernel(
124
- dY_ptr,
125
- dY_row_stride,
126
- dX_ptr,
127
- dX_row_stride,
128
- X_ptr,
129
- X_row_stride,
130
- X_dtype: tl.constexpr,
131
- W_ptr,
132
- W_row_stride,
133
- RSTD_ptr,
134
- RSTD_row_stride,
135
- dW_ptr,
136
- dW_row_stride,
137
- n_rows,
138
- n_cols,
139
- offset,
140
- rows_per_program,
141
- casting_mode: tl.constexpr,
142
- elementwise_affine: tl.constexpr,
143
- BLOCK_SIZE: tl.constexpr,
144
- ):
145
- """
146
- dx = (1 / RMS) * [dy * (w + offset - (1 / N) * (1 / RMS^2) * ((dy * (w + offset)) dot x) * x]. * means element-wise multiplication, whileas dot means dot product
147
- dw = sum(dy * (x / RMS)). summation over BxT dimension
148
- """
149
-
150
- row_block_id = tl.program_id(0).to(tl.int64)
151
- row_start = row_block_id * rows_per_program
152
- row_end = min((row_block_id + 1) * rows_per_program, n_rows)
153
- col_offsets = tl.arange(0, BLOCK_SIZE)
154
- mask = col_offsets < n_cols
155
-
156
- if elementwise_affine:
157
- dW_row = tl.zeros((BLOCK_SIZE,), dtype=tl.float32)
158
-
159
- if elementwise_affine:
160
- W_row = tl.load(W_ptr + col_offsets, mask=mask, other=0.0)
161
- W_row = W_row + offset
162
-
163
- for row_idx in range(row_start, row_end):
164
- dy_base = dY_ptr + row_idx * dY_row_stride
165
- dx_base = dX_ptr + row_idx * dX_row_stride
166
-
167
- x_base = X_ptr + row_idx * X_row_stride
168
- rstd_base = RSTD_ptr + row_idx * RSTD_row_stride
169
-
170
- dY_row = tl.load(dy_base + col_offsets, mask=mask, other=0.0)
171
- X_row = tl.load(x_base + col_offsets, mask=mask, other=0.0)
172
-
173
- # Get cached rms
174
- rstd_row = tl.load(rstd_base)
175
-
176
- X_row = X_row.to(tl.float32)
177
-
178
- # Different bacward graphs for different casting modes
179
- if casting_mode == _CASTING_MODE_LLAMA:
180
- if elementwise_affine:
181
- m = (dY_row * W_row).to(tl.float32)
182
- else:
183
- m = dY_row.to(tl.float32)
184
-
185
- elif casting_mode == _CASTING_MODE_GEMMA:
186
- dY_row = dY_row.to(tl.float32)
187
- if elementwise_affine:
188
- m = dY_row * W_row
189
- else:
190
- m = dY_row
191
- else:
192
- if elementwise_affine:
193
- m = dY_row * W_row
194
- else:
195
- m = dY_row
196
-
197
- dX_row = rstd_row * m
198
-
199
- dX_row += (rstd_row) * (-(1 / n_cols) * rstd_row * rstd_row * tl.sum(m * X_row, axis=0) * X_row)
200
-
201
- if elementwise_affine:
202
- # calculate the gradient of W
203
- if casting_mode == _CASTING_MODE_LLAMA:
204
- dW_row += dY_row * (X_row * rstd_row).to(X_dtype)
205
- else:
206
- # here X_row is already in fp32 (see previous if block)
207
- dW_row += dY_row * (X_row * rstd_row)
208
-
209
- tl.store(dx_base + col_offsets, dX_row.to(X_dtype), mask=mask)
210
-
211
- if elementwise_affine:
212
- tl.store(dW_ptr + row_block_id * dW_row_stride + col_offsets, dW_row, mask=mask)
213
-
214
-
215
- @triton.jit
216
- def _block_rms_norm_forward_kernel(
217
- Y_ptr,
218
- Y_row_stride,
219
- X_ptr,
220
- X_row_stride,
221
- W_ptr,
222
- W_row_stride,
223
- RSTD_ptr,
224
- RSTD_row_stride,
225
- n_rows,
226
- n_cols,
227
- eps,
228
- offset,
229
- casting_mode: tl.constexpr, # constexpr so the `if` blocks can be optimized out
230
- elementwise_affine: tl.constexpr,
231
- BLOCK_SIZE: tl.constexpr,
232
- BLOCK_ROW: tl.constexpr,
233
- ):
234
- """
235
- y_i = (x_i / (RMS)) * (offset + wi), RMS = sqrt(sum(x_i^2) / N)
236
-
237
- Reference:
238
- 1. https://triton-lang.org/main/getting-started/tutorials/05-layer-norm.html
239
- 2. https://github.com/unslothai/unsloth/blob/fd753fed99ed5f10ef8a9b7139588d9de9ddecfb/unsloth/kernels/rms_layernorm.py#L22
240
- 3. https://arxiv.org/pdf/1910.07467
241
- """
242
-
243
- row_idx = tl.program_id(0) * BLOCK_ROW + tl.arange(0, BLOCK_ROW)
244
- col_offsets = tl.arange(0, BLOCK_SIZE)
245
- row_mask = row_idx < n_rows
246
- col_mask = col_offsets < n_cols
247
-
248
- X_row = tl.load(
249
- X_ptr + row_idx[:, None] * X_row_stride + col_offsets[None, :],
250
- mask=row_mask[:, None] & col_mask[None, :],
251
- other=0,
252
- )
253
- X_row_dtype = X_row.dtype
254
- if elementwise_affine:
255
- W_row = tl.load(W_ptr + col_offsets, mask=col_mask, other=0)
256
-
257
- # On Llama, only rstd is computed on fp32
258
- if casting_mode == _CASTING_MODE_LLAMA:
259
- X_row = X_row.to(tl.float32)
260
-
261
- # Gemma computes everything on fp32, and then casts back the output to the original dtype
262
- if casting_mode == _CASTING_MODE_GEMMA:
263
- if elementwise_affine:
264
- W_row = W_row.to(tl.float32)
265
- X_row = X_row.to(tl.float32)
266
-
267
- if casting_mode == _CASTING_MODE_NONE:
268
- eps = eps.to(X_row_dtype)
269
- offset = offset.to(X_row_dtype)
270
-
271
- mean_square = tl.sum(X_row * X_row, axis=1) / n_cols
272
- rstd = rsqrt(mean_square + eps)
273
-
274
- # We can save time by caching rms with minimal memory overhead
275
- # because rms is much smaller compared to X_row, as rms is for each row.
276
- # However, on the computation side, it can save 4 operations (*, sum, /, sqrt).
277
- tl.store(RSTD_ptr + row_idx * RSTD_row_stride, rstd, row_mask)
278
-
279
- X_row = X_row * rstd[:, None]
280
-
281
- # On Llama, the multiplication with the weight is done on the original dtype
282
- if casting_mode == _CASTING_MODE_LLAMA:
283
- X_row = X_row.to(X_row_dtype)
284
-
285
- if elementwise_affine:
286
- Y_row = X_row * (offset + W_row)[None, :]
287
- else:
288
- Y_row = X_row
289
-
290
- if casting_mode == _CASTING_MODE_GEMMA:
291
- Y_row = Y_row.to(X_row_dtype)
292
-
293
- tl.store(
294
- Y_ptr + row_idx[:, None] * Y_row_stride + col_offsets[None, :],
295
- Y_row,
296
- mask=row_mask[:, None] & col_mask[None, :],
297
- )
298
-
299
-
300
- @triton.jit
301
- def _block_rms_norm_backward_kernel(
302
- dY_ptr,
303
- dY_row_stride,
304
- dX_ptr,
305
- dX_row_stride,
306
- X_ptr,
307
- X_row_stride,
308
- X_dtype: tl.constexpr,
309
- W_ptr,
310
- W_row_stride,
311
- RSTD_ptr,
312
- RSTD_row_stride,
313
- dW_ptr,
314
- dW_row_stride,
315
- n_rows,
316
- n_cols,
317
- offset,
318
- casting_mode: tl.constexpr,
319
- elementwise_affine: tl.constexpr,
320
- BLOCK_SIZE: tl.constexpr,
321
- BLOCK_ROW: tl.constexpr,
322
- ):
323
- """
324
- dx = (1 / RMS) * [dy * (w + offset - (1 / N) * (1 / RMS^2) * ((dy * (w + offset)) dot x) * x]. * means element-wise multiplication, whileas dot means dot product
325
- dw = sum(dy * (x / RMS)). summation over BxT dimension
326
- """
327
-
328
- pid = tl.program_id(0).cast(tl.int64)
329
- NUM_SMS = tl.num_programs(0)
330
-
331
- col_offsets = tl.arange(0, BLOCK_SIZE)
332
- col_mask = col_offsets < n_cols
333
-
334
- if elementwise_affine:
335
- dW_row = tl.zeros((BLOCK_SIZE,), dtype=tl.float32)
336
-
337
- W_row = tl.load(W_ptr + col_offsets, mask=col_mask, other=0.0)
338
- W_row = W_row + offset
339
-
340
- for start in range(pid * BLOCK_ROW, n_rows, NUM_SMS * BLOCK_ROW):
341
- row_idx = start + tl.arange(0, BLOCK_ROW)
342
- row_mask = row_idx < n_rows
343
- dY_row = tl.load(
344
- dY_ptr + row_idx[:, None] * dY_row_stride + col_offsets[None, :],
345
- mask=row_mask[:, None] & col_mask[None, :],
346
- other=0.0,
347
- )
348
- X_row = tl.load(
349
- X_ptr + row_idx[:, None] * X_row_stride + col_offsets[None, :],
350
- mask=row_mask[:, None] & col_mask[None, :],
351
- other=0.0,
352
- )
353
-
354
- # Get cached rms
355
- rstd_row = tl.load(RSTD_ptr + row_idx * RSTD_row_stride, row_mask)
356
-
357
- X_row = X_row.to(tl.float32)
358
-
359
- # Different bacward graphs for different casting modes
360
- if casting_mode == _CASTING_MODE_LLAMA:
361
- if elementwise_affine:
362
- m = (dY_row * W_row[None, :]).to(tl.float32)
363
- else:
364
- m = dY_row.to(tl.float32)
365
-
366
- elif casting_mode == _CASTING_MODE_GEMMA:
367
- dY_row = dY_row.to(tl.float32)
368
- if elementwise_affine:
369
- m = dY_row * W_row[None, :]
370
- else:
371
- m = dY_row
372
- else:
373
- if elementwise_affine:
374
- m = dY_row * W_row[None, :]
375
- else:
376
- m = dY_row
377
-
378
- dX_row = rstd_row[:, None] * m
379
-
380
- dX_row += (rstd_row[:, None]) * (
381
- -(1 / n_cols) * (rstd_row * rstd_row * tl.sum(m * X_row, axis=1))[:, None] * X_row
382
- )
383
-
384
- if elementwise_affine:
385
- if casting_mode == _CASTING_MODE_LLAMA:
386
- # TODO(tcc): use tl.sum(..., dtype=tl.float32) once we upgrade to triton>=3.3.0
387
- dW_row += tl.sum((dY_row * (X_row * rstd_row[:, None]).to(X_dtype)).to(tl.float32), 0)
388
- else:
389
- # here X_row is already in fp32 (see previous if block)
390
- dW_row += tl.sum(dY_row * (X_row * rstd_row[:, None]), 0)
391
-
392
- tl.store(
393
- dX_ptr + row_idx[:, None] * dX_row_stride + col_offsets[None, :],
394
- dX_row,
395
- mask=row_mask[:, None] & col_mask[None, :],
396
- )
397
-
398
- if elementwise_affine:
399
- tl.store(dW_ptr + pid * dW_row_stride + col_offsets, dW_row, mask=col_mask)
400
-
401
-
402
- _str_to_casting_mode = {
403
- "llama": _CASTING_MODE_LLAMA.value,
404
- "gemma": _CASTING_MODE_GEMMA.value,
405
- "none": _CASTING_MODE_NONE.value,
406
- }
407
-
408
-
409
- def rms_norm_forward(X, W, eps, offset, casting_mode, row_mode):
410
- if not isinstance(casting_mode, int):
411
- assert casting_mode in _str_to_casting_mode, f"Invalid casting mode: {casting_mode}"
412
- casting_mode = _str_to_casting_mode[casting_mode]
413
- else:
414
- assert casting_mode in _str_to_casting_mode.values(), f"Invalid casting mode: {casting_mode}"
415
-
416
- shape = X.shape
417
- dim = shape[-1]
418
- X = X.view(-1, dim)
419
- n_rows, n_cols = X.shape
420
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
421
-
422
- Y = torch.empty((n_rows, n_cols), dtype=X.dtype, device=X.device)
423
- # RSTD is to cache rstd for each row
424
- # RSTD is always computed/stored in fp32 if we are using Llama or Gemma casting mode
425
- rstd_dtype = torch.float32 if casting_mode in (_CASTING_MODE_LLAMA.value, _CASTING_MODE_GEMMA.value) else X.dtype
426
- RSTD = torch.empty(n_rows, dtype=rstd_dtype, device=X.device)
427
-
428
- if W is not None:
429
- # Check constraints.
430
- assert X.shape[1] == W.shape[0], (
431
- "Incompatible hidden size dimension between tensor1.shape[1] and tensor2.shape[0]"
432
- )
433
- elementwise_affine = True
434
- else:
435
- elementwise_affine = False
436
-
437
- # XPU-specific optimization
438
- kernel_args = {}
439
- if X.device.type == "xpu":
440
- set_large_grf_mode(kernel_args)
441
- if BLOCK_SIZE > 256 or n_rows < 4096 * 8 or row_mode:
442
- _rms_norm_forward_kernel[(n_rows,)](
443
- Y,
444
- Y.stride(0),
445
- X,
446
- X.stride(0),
447
- W,
448
- W.stride(0) if elementwise_affine else 0,
449
- RSTD,
450
- RSTD.stride(0),
451
- n_cols,
452
- eps,
453
- offset,
454
- casting_mode,
455
- elementwise_affine=elementwise_affine,
456
- BLOCK_SIZE=BLOCK_SIZE,
457
- num_warps=num_warps,
458
- **kernel_args, # XPU-specific optimization
459
- )
460
- else:
461
- BLOCK_ROW = 16
462
- kernel_args["BLOCK_ROW"] = BLOCK_ROW
463
- _block_rms_norm_forward_kernel[(triton.cdiv(n_rows, BLOCK_ROW),)](
464
- Y,
465
- Y.stride(0),
466
- X,
467
- X.stride(0),
468
- W,
469
- W.stride(0) if elementwise_affine else 0,
470
- RSTD,
471
- RSTD.stride(0),
472
- n_rows,
473
- n_cols,
474
- eps,
475
- offset,
476
- casting_mode,
477
- elementwise_affine=elementwise_affine,
478
- BLOCK_SIZE=BLOCK_SIZE,
479
- num_warps=num_warps,
480
- **kernel_args, # XPU-specific optimization
481
- )
482
- return Y.view(*shape), X, RSTD, BLOCK_SIZE, num_warps, casting_mode
483
-
484
-
485
- def rms_norm_backward(dY, X, W, RSTD, offset, casting_mode, BLOCK_SIZE, num_warps, in_place, row_mode):
486
- shape = dY.shape
487
- dim = shape[-1]
488
- dY = dY.view(-1, dim)
489
- n_rows, n_cols = dY.shape
490
-
491
- sm_count = 1
492
- if X.device.type == "cuda":
493
- sm_count = torch.cuda.get_device_properties(X.device).multi_processor_count
494
- elif X.device.type == "xpu":
495
- sm_count = torch.xpu.get_device_properties(X.device).gpu_eu_count
496
- elif X.device.type == "npu":
497
- sm_count = get_npu_core_count()
498
-
499
- if W is not None:
500
- # fp32 for numerical stability especially.
501
- _dW = torch.empty((sm_count, n_cols), dtype=torch.float32, device=W.device)
502
- elementwise_affine = True
503
- else:
504
- _dW = None
505
- elementwise_affine = False
506
-
507
- if n_cols > BLOCK_SIZE:
508
- raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
509
- rows_per_program = math.ceil(n_rows / sm_count)
510
- grid = (sm_count,)
511
-
512
- if in_place is True:
513
- dX = dY
514
- else:
515
- dX = torch.zeros_like(dY)
516
-
517
- # XPU-specific optimization
518
- kernel_args = {}
519
- if X.device.type == "xpu":
520
- set_large_grf_mode(kernel_args)
521
-
522
- if BLOCK_SIZE > 256 or n_rows < 4096 * 8 or row_mode:
523
- _rms_norm_backward_kernel[grid](
524
- dY,
525
- dY.stride(0),
526
- dX,
527
- dX.stride(0),
528
- X,
529
- X.stride(0),
530
- torch_to_triton_dtype[X.dtype],
531
- W,
532
- W.stride(0) if elementwise_affine else 0,
533
- RSTD,
534
- RSTD.stride(0),
535
- _dW,
536
- _dW.stride(0) if elementwise_affine else 0,
537
- n_rows,
538
- n_cols,
539
- offset,
540
- rows_per_program,
541
- casting_mode,
542
- elementwise_affine=elementwise_affine,
543
- BLOCK_SIZE=BLOCK_SIZE,
544
- num_warps=num_warps,
545
- **kernel_args, # XPU-specific optimization
546
- )
547
- else:
548
- BLOCK_ROW = 16
549
- kernel_args["BLOCK_ROW"] = BLOCK_ROW
550
- _block_rms_norm_backward_kernel[grid](
551
- dY,
552
- dY.stride(0),
553
- dX,
554
- dX.stride(0),
555
- X,
556
- X.stride(0),
557
- torch_to_triton_dtype[X.dtype],
558
- W,
559
- W.stride(0) if elementwise_affine else 0,
560
- RSTD,
561
- RSTD.stride(0),
562
- _dW,
563
- _dW.stride(0) if elementwise_affine else 0,
564
- n_rows,
565
- n_cols,
566
- offset,
567
- casting_mode,
568
- elementwise_affine=elementwise_affine,
569
- BLOCK_SIZE=BLOCK_SIZE,
570
- num_warps=num_warps,
571
- **kernel_args, # XPU-specific optimization
572
- )
573
- dX = dX.view(*shape)
574
-
575
- if elementwise_affine:
576
- dW = _dW.sum(dim=0).to(W.dtype)
577
- else:
578
- dW = None
579
-
580
- return dX, dW
581
-
582
-
583
- class LigerRMSNormFunction(torch.autograd.Function):
584
- """
585
- Performs RMSNorm (Root Mean Square Normalization), which normalizes the input tensor `X` using the
586
- weight tensor `W`, with an optional offset and casting mode.
587
-
588
- Some models use an 'offset' to shift the weight tensor `W` by a constant value. For example, Gemma
589
- uses an offset of 1.0, so the computation becomes `(X / RMS(X)) * (W + 1.0)` instead of the usual
590
- `(X / RMS(X)) * W`. You can pass the offset value as an argument to the forward function.
591
-
592
- In addition, different models cast their inputs at different places during RMSNorm computation. For
593
- example, Gemma casts everything to fp32 nefore starting the computation, while Llama casts only the
594
- inverse RMS to fp32. You can specify the casting mode using the `casting_mode` argument. We currently
595
- support the following casting modes (they match HuggingFace Transformers' implementations):
596
- - 'llama': matches the Llama implementation, where only the inverse RMS is computed on fp32.
597
- - 'gemma': matches the Gemma implementation, where everything is cast to fp32, then computed, then cast back to the original dtype.
598
- - 'none': no casting is done. The computation is done in the original dtype. This saves memory and is slightly faster, but has more error w.r.t. the original implementation.
599
-
600
- `in_place` option means whether to in_place modify dY to store dX. This is default to `True` to save memory. However, under certain cases, it can produce incorrect inputs.
601
- For example, gemma2 uses two rmsnorm sequentially with residual in between. The resesidual part needs dY so it cannot be modified in-place.
602
- Therefore, for the patching of RMSNorm in gemma2, we set `in_place` to `False`
603
- """
604
-
605
- @staticmethod
606
- @ensure_contiguous
607
- def forward(ctx, X, W, eps, offset=0.0, casting_mode="llama", in_place=True, row_mode=None):
608
- """
609
- X: (B, T, H) or (BxT, H)
610
- W: (H,)
611
- """
612
- if isinstance(X, torch.distributed.tensor.DTensor):
613
- # Input tensor is output of a tensor parallel module and
614
- # needs to be gathered to a local tensor to compute
615
- # RMSE layer norm on each TP worker.
616
- # TODO: support CP.
617
- X = X.full_tensor()
618
-
619
- Y, X, RSTD, BLOCK_SIZE, num_warps, casting_mode = rms_norm_forward(X, W, eps, offset, casting_mode, row_mode)
620
- ctx.offset = offset
621
- ctx.casting_mode = casting_mode
622
- ctx.in_place = in_place
623
- ctx.row_mode = row_mode
624
- ctx.BLOCK_SIZE = BLOCK_SIZE
625
- ctx.num_warps = num_warps
626
- ctx.elementwise_affine = W is not None
627
- if W is not None:
628
- ctx.save_for_backward(X, W, RSTD)
629
- else:
630
- ctx.save_for_backward(X, RSTD)
631
- return Y
632
-
633
- @staticmethod
634
- @ensure_contiguous
635
- def backward(ctx, dY):
636
- """
637
- Y: (B, T, H) or (BxT, H)
638
- """
639
- if ctx.elementwise_affine:
640
- X, W, RSTD = ctx.saved_tensors
641
- else:
642
- X, RSTD = ctx.saved_tensors
643
- W = None
644
-
645
- if isinstance(dY, torch.distributed.tensor.DTensor):
646
- # Gradients are output of a tensor parallel module and
647
- # needs to be gathered to a local tensor for computing RMSE layer.
648
- # TODO: support CP.
649
- dY = dY.full_tensor()
650
-
651
- dX, dW = rms_norm_backward(
652
- dY, X, W, RSTD, ctx.offset, ctx.casting_mode, ctx.BLOCK_SIZE, ctx.num_warps, ctx.in_place, ctx.row_mode
653
- )
654
- return dX, dW, None, None, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/rope.py DELETED
@@ -1,239 +0,0 @@
1
- import torch
2
- import triton
3
- import triton.language as tl
4
-
5
-
6
- @triton.jit
7
- def _triton_rope(
8
- q_ptr,
9
- q_row_stride,
10
- k_ptr,
11
- k_row_stride,
12
- cos,
13
- cos_row_stride,
14
- sin,
15
- sin_row_stride,
16
- sl,
17
- bs: tl.constexpr,
18
- cos_bs: tl.constexpr,
19
- n_qh: tl.constexpr,
20
- n_kh: tl.constexpr,
21
- hd: tl.constexpr,
22
- pad_n_qh: tl.constexpr,
23
- pad_n_kh: tl.constexpr,
24
- pad_hd: tl.constexpr,
25
- BLOCK_SIZE: tl.constexpr,
26
- BACKWARD_PASS: tl.constexpr = False,
27
- ):
28
- # q size: (bsz, seq_len, num_q_heads, head_dim)
29
- # q stride: (seq_len * num_q_heads * head_dim, num_q_heads * head_dim, head_dim, 1)
30
- # k size: (bsz, seq_len, num_kv_heads, head_dim)
31
- # k stride: (seq_len * num_kv_heads * head_dim, num_kv_heads * head_dim, head_dim, 1)
32
-
33
- # cos size: (1, seq_len, head_dim) or (bsz, seq_len, head_dim)
34
- # stride: (seq_len * head_dim, head_dim, 1)
35
- pid = tl.program_id(0).to(tl.int64)
36
-
37
- # locate start address
38
- q_ptr = q_ptr + pid * q_row_stride
39
- k_ptr = k_ptr + pid * k_row_stride
40
-
41
- # ####################################################################
42
- # get the cos(mθ_{i...d/2}) and sin(mθ_{i...d/2}) for token position
43
- # m of this program instance
44
- # ####################################################################
45
-
46
- # 1. program instances are laid out in a 1D vector of size bsz * seq_len, which
47
- # effectively represents a 2D grid of size [bsz, seq_len] with seq_len dimension
48
- # being the fastest changing dimension. Thus we can simply do pid // sl to get the batch index
49
- # and pid % sl to get the sequence index.
50
- # 2. We only need the left half of cos and sin matrix because the right half is just
51
- # a clone of the left half.
52
- batch_idx = pid // sl
53
- cos_row_idx = pid % sl
54
- cos = cos + tl.where(
55
- cos_bs == 1,
56
- cos_row_idx * cos_row_stride,
57
- batch_idx * (sl * cos_row_stride) + cos_row_idx * cos_row_stride,
58
- )
59
- sin = sin + tl.where(
60
- cos_bs == 1,
61
- cos_row_idx * sin_row_stride,
62
- batch_idx * (sl * sin_row_stride) + cos_row_idx * sin_row_stride,
63
- )
64
-
65
- cos_offsets = tl.arange(0, pad_hd // 2)
66
- cos_mask = cos_offsets < hd // 2
67
- cos_row = tl.load(cos + cos_offsets, mask=cos_mask, other=0)
68
- sin_row = tl.load(sin + cos_offsets, mask=cos_mask, other=0)
69
-
70
- # ####################################################################
71
- # Load the left and right half of q and k for the current
72
- # program instance (i.e. for the current token) separately
73
- # ####################################################################
74
- # left half of the head
75
- first_half_q_offsets = tl.arange(0, pad_n_qh)[:, None] * hd + tl.arange(0, pad_hd // 2)[None, :]
76
- first_half_k_offsets = tl.arange(0, pad_n_kh)[:, None] * hd + tl.arange(0, pad_hd // 2)[None, :]
77
- first_q_mask = (tl.arange(0, pad_n_qh)[:, None] < n_qh) & (tl.arange(0, pad_hd // 2)[None, :] < hd // 2)
78
- first_k_mask = (tl.arange(0, pad_n_kh)[:, None] < n_kh) & (tl.arange(0, pad_hd // 2)[None, :] < hd // 2)
79
- q_tile_1 = tl.load(q_ptr + first_half_q_offsets, mask=first_q_mask, other=0).to(sin_row.dtype)
80
- k_tile_1 = tl.load(k_ptr + first_half_k_offsets, mask=first_k_mask, other=0).to(sin_row.dtype)
81
-
82
- # right half of the head
83
- second_half_q_offsets = first_half_q_offsets + (hd // 2)
84
- second_half_k_offsets = first_half_k_offsets + (hd // 2)
85
- second_q_mask = first_q_mask
86
- second_k_mask = first_k_mask
87
- q_tile_2 = tl.load(q_ptr + second_half_q_offsets, mask=second_q_mask, other=0).to(sin_row.dtype)
88
- k_tile_2 = tl.load(k_ptr + second_half_k_offsets, mask=second_k_mask, other=0).to(sin_row.dtype)
89
-
90
- if not BACKWARD_PASS:
91
- # y = [x1, x2] * [cos, cos] + [-x2, x1] * [sin, sin]
92
- new_q_tile_1 = q_tile_1 * cos_row - q_tile_2 * sin_row
93
- tl.store(q_ptr + first_half_q_offsets, new_q_tile_1, mask=first_q_mask)
94
- new_q_tile_2 = q_tile_2 * cos_row + q_tile_1 * sin_row
95
- tl.store(q_ptr + second_half_q_offsets, new_q_tile_2, mask=second_q_mask)
96
-
97
- new_k_tile_1 = k_tile_1 * cos_row - k_tile_2 * sin_row
98
- tl.store(k_ptr + first_half_k_offsets, new_k_tile_1, mask=first_k_mask)
99
- new_k_tile_2 = k_tile_2 * cos_row + k_tile_1 * sin_row
100
- tl.store(k_ptr + second_half_k_offsets, new_k_tile_2, mask=second_k_mask)
101
- else:
102
- # with some math, we can get:
103
- # dy = [dx1, dx2] * [cos, cos] + [-dx2, dx1] * [-sin, -sin]
104
- new_q_tile_1 = q_tile_1 * cos_row + q_tile_2 * sin_row
105
- tl.store(q_ptr + first_half_q_offsets, new_q_tile_1, mask=first_q_mask)
106
- new_q_tile_2 = q_tile_2 * cos_row - q_tile_1 * sin_row
107
- tl.store(q_ptr + second_half_q_offsets, new_q_tile_2, mask=second_q_mask)
108
-
109
- new_k_tile_1 = k_tile_1 * cos_row + k_tile_2 * sin_row
110
- tl.store(k_ptr + first_half_k_offsets, new_k_tile_1, mask=first_k_mask)
111
- new_k_tile_2 = k_tile_2 * cos_row - k_tile_1 * sin_row
112
- tl.store(k_ptr + second_half_k_offsets, new_k_tile_2, mask=second_k_mask)
113
-
114
-
115
- def rope_forward(q, k, cos, sin):
116
- # transpose it back to the physical shape because Triton looks at the physical storage
117
- # note: q and k are incontiguous before the transformation and will become contiguous after transpose
118
- q = q.transpose(1, 2)
119
- k = k.transpose(1, 2)
120
-
121
- batch_size, seq_len, n_q_head, head_dim = q.shape
122
- n_kv_head = k.shape[2]
123
- pad_hd = triton.next_power_of_2(head_dim)
124
- pad_n_q_head = triton.next_power_of_2(n_q_head)
125
- pad_n_kv_head = triton.next_power_of_2(n_kv_head)
126
- BLOCK_SIZE = max(pad_n_q_head, pad_n_kv_head)
127
-
128
- n_row = batch_size * seq_len
129
-
130
- # ensure tensors passed into the kernel are contiguous. It will be no-op if they are already contiguous
131
- q = q.contiguous()
132
- k = k.contiguous()
133
- cos = cos.contiguous()
134
- sin = sin.contiguous()
135
- cos_batch_size = cos.shape[0]
136
-
137
- _triton_rope[(n_row,)](
138
- q,
139
- q.stride(1),
140
- k,
141
- k.stride(1),
142
- cos,
143
- cos.stride(-2),
144
- sin,
145
- sin.stride(-2),
146
- seq_len,
147
- batch_size,
148
- cos_batch_size,
149
- n_q_head,
150
- n_kv_head,
151
- head_dim,
152
- pad_n_q_head,
153
- pad_n_kv_head,
154
- pad_hd,
155
- BLOCK_SIZE=BLOCK_SIZE,
156
- BACKWARD_PASS=False,
157
- )
158
- return q.transpose(1, 2), k.transpose(1, 2), cos, sin
159
-
160
-
161
- def rope_backward(dq, dk, cos, sin):
162
- dq = dq.transpose(1, 2)
163
- dk = dk.transpose(1, 2)
164
-
165
- batch_size, seq_len, n_q_head, head_dim = dq.shape
166
- cos_batch_size = cos.shape[0]
167
- n_kv_head = dk.shape[2]
168
- pad_hd = triton.next_power_of_2(head_dim)
169
- pad_n_q_head = triton.next_power_of_2(n_q_head)
170
- pad_n_kv_head = triton.next_power_of_2(n_kv_head)
171
- BLOCK_SIZE = max(pad_n_q_head, pad_n_kv_head)
172
-
173
- n_row = batch_size * seq_len
174
-
175
- # ensure dq and dk are contiguous
176
- dq = dq.contiguous()
177
- dk = dk.contiguous()
178
-
179
- # backward is similar to forward except swapping few ops
180
- _triton_rope[(n_row,)](
181
- dq,
182
- dq.stride(1),
183
- dk,
184
- dk.stride(1),
185
- cos,
186
- cos.stride(-2),
187
- sin,
188
- sin.stride(-2),
189
- seq_len,
190
- batch_size,
191
- cos_batch_size,
192
- n_q_head,
193
- n_kv_head,
194
- head_dim,
195
- pad_n_q_head,
196
- pad_n_kv_head,
197
- pad_hd,
198
- BLOCK_SIZE=BLOCK_SIZE,
199
- BACKWARD_PASS=True,
200
- )
201
- return dq.transpose(1, 2), dk.transpose(1, 2)
202
-
203
-
204
- class LigerRopeFunction(torch.autograd.Function):
205
- """
206
- Triton implementation of the Rotary Positional Embedding (RoPE) operation. Please note that
207
- this implements the HuggingFace Llama & Mistral version, whose rotation matrix is slightly different
208
- than the original RoPE paper.
209
-
210
- Please find the corresponding HuggingFace implementation here:
211
- https://github.com/huggingface/transformers/blob/v4.40.2/src/transformers/models/llama/modeling_llama.py#L184
212
-
213
- For more details about the rotation matrix used here, please refer to:
214
- https://discuss.huggingface.co/t/is-llama-rotary-embedding-implementation-correct/44509/2
215
- """
216
-
217
- @staticmethod
218
- def forward(ctx, q, k, cos, sin, position_ids=None, unsqueeze_dim=1):
219
- """
220
- q size: (bsz, n_q_head, seq_len, head_dim)
221
- k size: (bsz, n_kv_head, seq_len, head_dim)
222
- cos size: (1, seq_len, head_dim) or (bsz, seq_len, head_dim)
223
- sin size: (1, seq_len, head_dim) or (bsz, seq_len, head_dim)
224
- """
225
- q, k, cos, sin = rope_forward(q, k, cos, sin)
226
- ctx.save_for_backward(cos, sin)
227
- return q, k
228
-
229
- def backward(ctx, dq, dk):
230
- """
231
- dq size: (bsz, n_q_head, seq_len, head_dim)
232
- dk size: (bsz, n_kv_head, seq_len, head_dim)
233
- cos size: (1, seq_len, head_dim) or (bsz, seq_len, head_dim)
234
- sin size: (1, seq_len, head_dim) or (bsz, seq_len, head_dim)
235
- """
236
-
237
- cos, sin = ctx.saved_tensors
238
- dq, dk = rope_backward(dq, dk, cos, sin)
239
- return dq, dk, None, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/swiglu.py DELETED
@@ -1,176 +0,0 @@
1
- import torch
2
- import triton
3
- import triton.language as tl
4
-
5
- from .utils import calculate_settings
6
- from .utils import ensure_contiguous
7
-
8
-
9
- @triton.jit
10
- def silu(x):
11
- return x * tl.sigmoid(x)
12
-
13
-
14
- @triton.jit
15
- def _swiglu_forward_kernel(
16
- a_ptr, b_ptr, c_ptr, stride, gate_multiplier, n_cols: tl.constexpr, BLOCK_SIZE: tl.constexpr
17
- ):
18
- program_id = tl.program_id(0).to(tl.int64)
19
-
20
- # locate start index
21
- a_ptr += program_id * stride
22
- b_ptr += program_id * stride
23
- c_ptr += program_id * stride
24
-
25
- col_offsets = tl.arange(0, BLOCK_SIZE)
26
- mask = col_offsets < n_cols
27
-
28
- # sigmoid requires type float32
29
- a_row = tl.load(a_ptr + col_offsets, mask=mask, other=0).to(tl.float32) * gate_multiplier
30
- b_row = tl.load(b_ptr + col_offsets, mask=mask, other=0)
31
- c_row = silu(a_row).cast(b_row.dtype) * b_row
32
- tl.store(c_ptr + col_offsets, c_row, mask=mask)
33
-
34
-
35
- @triton.jit
36
- def _swiglu_backward_kernel(
37
- dc_ptr, a_ptr, b_ptr, stride, gate_multiplier, n_cols: tl.constexpr, BLOCK_SIZE: tl.constexpr
38
- ):
39
- program_id = tl.program_id(0).to(tl.int64)
40
-
41
- # locate start index
42
- dc_ptr += program_id * stride
43
- a_ptr += program_id * stride
44
- b_ptr += program_id * stride
45
-
46
- col_offsets = tl.arange(0, BLOCK_SIZE)
47
- mask = col_offsets < n_cols
48
-
49
- dc_row = tl.load(dc_ptr + col_offsets, mask=mask, other=0)
50
- # sigmoid requires type float32
51
- a_row = tl.load(a_ptr + col_offsets, mask=mask, other=0).to(tl.float32) * gate_multiplier
52
- b_row = tl.load(b_ptr + col_offsets, mask=mask, other=0)
53
-
54
- # recomputation to save memory. a_row already holds a * gate_multiplier.
55
- sig_a = tl.sigmoid(a_row)
56
- silu_a = a_row * sig_a
57
- db_row = dc_row * silu_a
58
- # chain rule pulls an extra factor of gate_multiplier through the pre-activation scaling
59
- da_row = dc_row * (silu_a * (1 - sig_a) + sig_a) * b_row * gate_multiplier
60
-
61
- tl.store(a_ptr + col_offsets, da_row, mask=mask)
62
- tl.store(b_ptr + col_offsets, db_row, mask=mask)
63
-
64
-
65
- def swiglu_forward(a, b, gate_multiplier: float = 1.0):
66
- ori_shape = a.shape
67
-
68
- n_cols = ori_shape[-1]
69
- a = a.view(-1, n_cols)
70
- b = b.view(-1, n_cols)
71
- c = torch.empty_like(a)
72
- n_rows = a.shape[0]
73
-
74
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
75
-
76
- _swiglu_forward_kernel[(n_rows,)](
77
- a,
78
- b,
79
- c,
80
- c.stride(-2),
81
- float(gate_multiplier),
82
- n_cols=n_cols,
83
- BLOCK_SIZE=BLOCK_SIZE,
84
- num_warps=num_warps,
85
- )
86
- return a, b, c.view(*ori_shape)
87
-
88
-
89
- def swiglu_backward(a, b, dc, gate_multiplier: float = 1.0):
90
- ori_shape = dc.shape
91
- n_cols = ori_shape[-1]
92
- dc = dc.view(-1, n_cols)
93
- n_rows = dc.shape[0]
94
-
95
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
96
-
97
- _swiglu_backward_kernel[(n_rows,)](
98
- dc,
99
- a,
100
- b,
101
- dc.stride(-2),
102
- float(gate_multiplier),
103
- n_cols=n_cols,
104
- BLOCK_SIZE=BLOCK_SIZE,
105
- num_warps=num_warps,
106
- )
107
- return a.view(*ori_shape), b.view(*ori_shape)
108
-
109
-
110
- class LigerSiLUMulFunction(torch.autograd.Function):
111
- @staticmethod
112
- @ensure_contiguous
113
- def forward(ctx, a, b, gate_multiplier: float = 1.0, down_multiplier: float = 1.0):
114
- gate_multiplier = float(gate_multiplier)
115
- down_multiplier = float(down_multiplier)
116
- ctx.gate_multiplier = gate_multiplier
117
- ctx.down_multiplier = down_multiplier
118
-
119
- if isinstance(a, torch.distributed.tensor.DTensor) or isinstance(b, torch.distributed.tensor.DTensor):
120
- device_mesh, placements = (
121
- (a.device_mesh, a.placements)
122
- if isinstance(a, torch.distributed.tensor.DTensor)
123
- else (b.device_mesh, b.placements)
124
- )
125
-
126
- # Assume that full tensors are gathered before and identical across
127
- # the associated process groups.
128
- if not isinstance(a, torch.distributed.tensor.DTensor):
129
- a = torch.distributed.tensor.distribute_tensor(a, device_mesh=device_mesh, placements=placements)
130
- if not isinstance(b, torch.distributed.tensor.DTensor):
131
- b = torch.distributed.tensor.distribute_tensor(b, device_mesh=device_mesh, placements=placements)
132
- a_local, b_local, c_local = swiglu_forward(a.to_local(), b.to_local(), gate_multiplier)
133
- if down_multiplier != 1.0:
134
- c_local = c_local * down_multiplier
135
- ctx.save_for_backward(a_local, b_local)
136
- ctx.dtensor_metadata = (device_mesh, placements)
137
- return torch.distributed.tensor.DTensor.from_local(c_local, device_mesh, placements)
138
- else:
139
- a, b, c = swiglu_forward(a, b, gate_multiplier)
140
- if down_multiplier != 1.0:
141
- c = c * down_multiplier
142
- ctx.save_for_backward(a, b)
143
- ctx.dtensor_metadata = None
144
- return c
145
-
146
- @staticmethod
147
- @ensure_contiguous
148
- def backward(ctx, dc):
149
- a, b = ctx.saved_tensors
150
- gate_multiplier = ctx.gate_multiplier
151
- down_multiplier = ctx.down_multiplier
152
-
153
- if ctx.dtensor_metadata is not None:
154
- device_mesh, placements = ctx.dtensor_metadata
155
-
156
- # Assume that full tensors are gathered before and identical across
157
- # the associated process groups.
158
- dc_local = (
159
- dc.to_local()
160
- if isinstance(dc, torch.distributed.tensor.DTensor)
161
- else torch.distributed.tensor.distribute_tensor(dc, device_mesh=device_mesh, placements=placements)
162
- )
163
- if down_multiplier != 1.0:
164
- dc_local = dc_local * down_multiplier
165
- a_local, b_local = swiglu_backward(a, b, dc_local, gate_multiplier)
166
- return (
167
- torch.distributed.tensor.DTensor.from_local(a_local, device_mesh, placements),
168
- torch.distributed.tensor.DTensor.from_local(b_local, device_mesh, placements),
169
- None,
170
- None,
171
- )
172
-
173
- if down_multiplier != 1.0:
174
- dc = dc * down_multiplier
175
- a, b = swiglu_backward(a, b, dc, gate_multiplier)
176
- return a, b, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/tiled_mlp.py DELETED
@@ -1,136 +0,0 @@
1
- import math
2
-
3
- from typing import Callable
4
- from typing import List
5
- from typing import Optional
6
-
7
- import torch
8
-
9
- from .utils import ensure_contiguous
10
-
11
-
12
- class LigerTiledMLPFunction(torch.autograd.Function):
13
- """
14
- Based on DeepSpeed's TiledMLP:
15
- https://github.com/deepspeedai/DeepSpeed/blob/v0.18.2/deepspeed/runtime/sequence_parallel/ulysses_sp.py#L838
16
-
17
- Perform a tiled MLP computation to massively reduce memory usage needed to compute MLP
18
- when using very long sequence lengths.
19
-
20
- This module re-computes `forward` in the `backward`. So the `forward` occurs twice each iteration.
21
- And if you're using activation checkpointing it then occurs thrice.
22
-
23
- Args:
24
- fn: the function to call on sharded inputs (e.g., mlp.forward)
25
- mlp_module: the MLP nn.Module object
26
- x: the input to MLP.forward (hidden_states)
27
- shards: how many shards to use
28
- compute_params: a list of weights engaged in the compute
29
-
30
- Returns:
31
- the computed hidden_states
32
- """
33
-
34
- @staticmethod
35
- @ensure_contiguous
36
- def forward(
37
- ctx,
38
- fn: Callable,
39
- mlp_module: torch.nn.Module,
40
- x: torch.Tensor,
41
- shards: int,
42
- compute_params: Optional[List[torch.nn.Parameter]] = None,
43
- ) -> torch.Tensor:
44
- ctx.fn = fn
45
- ctx.mlp_module = mlp_module
46
- ctx.shards = shards
47
- ctx.save_for_backward(x)
48
-
49
- # x.shape could be [bs, seqlen, hidden_size] or [seqlen, hidden_size] (moe experts)
50
- x_shards = list(torch.chunk(x, chunks=shards, dim=-2))
51
- with torch.no_grad():
52
- output_shards = [fn(mlp_module, x_shard) for x_shard in x_shards]
53
- output_unsharded = torch.cat(output_shards, dim=-2)
54
-
55
- return output_unsharded
56
-
57
- @staticmethod
58
- @ensure_contiguous
59
- def backward(ctx, *grads) -> tuple:
60
- fn = ctx.fn
61
- (x,) = ctx.saved_tensors
62
- mlp_module = ctx.mlp_module
63
- shards = ctx.shards
64
-
65
- x_requires_grad = x.requires_grad
66
- x = x.detach()
67
- # detach() unsets x.requires_grad, so restore it
68
- x.requires_grad_(x_requires_grad)
69
-
70
- # x.shape could be [bs, seqlen, hidden_size] or [seqlen, hidden_size] (moe experts)
71
- hidden_size = x.shape[-1]
72
- x_shape_orig = x.shape
73
-
74
- # flatten bs+seqlen to avoid having stride issues when narrowing into seqlen w/ bs>1
75
- x = x.view(-1, hidden_size)
76
- incoming_grad = grads[0].view(-1, hidden_size)
77
- x_grad = torch.zeros_like(x)
78
-
79
- x_shards = list(torch.chunk(x, chunks=shards, dim=0))
80
-
81
- for i, x_shard in enumerate(x_shards):
82
- x_shard.requires_grad_(x_requires_grad)
83
-
84
- # if seqlen is not exactly divisible by shards the last step will be shorter than shard_step
85
- shard_step = x_shards[i].shape[0]
86
- shard_offset = i * x_shards[0].shape[0]
87
-
88
- x_shard.grad = x_grad.narrow(0, shard_offset, shard_step).view_as(x_shard)
89
- incoming_grad_shard = incoming_grad.narrow(0, shard_offset, shard_step).view_as(x_shard)
90
-
91
- with torch.enable_grad():
92
- output = fn(mlp_module, x_shard)
93
- torch.autograd.backward(output, incoming_grad_shard)
94
-
95
- # unflatten
96
- x_grad = x_grad.view(x_shape_orig)
97
-
98
- return (None, None, x_grad, None, None)
99
-
100
-
101
- def apply_tiled_mlp(
102
- fn: Callable,
103
- mlp_module: torch.nn.Module,
104
- x: torch.Tensor,
105
- num_shards: Optional[int] = None,
106
- compute_params: Optional[List[torch.nn.Parameter]] = None,
107
- ) -> torch.Tensor:
108
- """
109
- Apply tiled MLP computation for memory efficiency.
110
-
111
- Args:
112
- fn: the function to call on sharded inputs (e.g., lambda module, x: module(x))
113
- mlp_module: the MLP nn.Module object
114
- x: the input tensor with shape [bs, seqlen, hidden_size] or [seqlen, hidden_size]
115
- num_shards: number of shards to use. If None, automatically calculated as ceil(seqlen / hidden_size)
116
- compute_params: list of parameters for DeepSpeed ZeRO optimization
117
-
118
- Returns:
119
- output tensor with the same shape as input
120
- """
121
- if num_shards is None:
122
- # x.shape could be [bs, seqlen, hidden_size] or [seqlen, hidden_size]
123
- hidden_size = x.shape[-1]
124
- seqlen = x.shape[-2]
125
- num_shards = math.ceil(seqlen / hidden_size)
126
-
127
- # Ensure num_shards is at least 1
128
- num_shards = max(1, num_shards)
129
-
130
- return LigerTiledMLPFunction.apply(
131
- fn,
132
- mlp_module,
133
- x,
134
- num_shards,
135
- compute_params,
136
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/tvd.py DELETED
@@ -1,218 +0,0 @@
1
- from typing import Literal
2
- from typing import Optional
3
-
4
- import torch
5
- import triton
6
- import triton.language as tl
7
-
8
- from .utils import ensure_contiguous
9
-
10
- MAX_FUSED_SIZE = 65536 // 4
11
-
12
- REDUCTION_LITERAL = Literal["none", "sum", "mean", "batchmean"]
13
-
14
- _REDUCTION_MODE_NONE = tl.constexpr(0)
15
- _REDUCTION_MODE_SUM = tl.constexpr(1)
16
- _REDUCTION_MODE_MEAN = tl.constexpr(2)
17
- _REDUCTION_MODE_BATCHMEAN = tl.constexpr(3)
18
-
19
- _str_to_reduction_mode = {
20
- "none": _REDUCTION_MODE_NONE.value,
21
- "sum": _REDUCTION_MODE_SUM.value,
22
- "mean": _REDUCTION_MODE_MEAN.value,
23
- "batchmean": _REDUCTION_MODE_BATCHMEAN.value,
24
- }
25
-
26
-
27
- def get_num_warps(BLOCK_SIZE):
28
- num_warps = 4
29
- if BLOCK_SIZE >= 32768:
30
- num_warps = 32
31
- elif BLOCK_SIZE >= 8192:
32
- num_warps = 16
33
- elif BLOCK_SIZE >= 2048:
34
- num_warps = 8
35
-
36
- return num_warps
37
-
38
-
39
- @triton.jit
40
- def _tv_distance_kernel(
41
- p_ptr,
42
- p_stride,
43
- q_ptr,
44
- q_stride,
45
- loss_ptr,
46
- loss_stride,
47
- grads_ptr,
48
- grads_stride,
49
- label_ptr,
50
- ignore_index: tl.constexpr,
51
- n_cols,
52
- scale, # pre-computed reduction scale for gradients (fused into kernel)
53
- BLOCK_SIZE: tl.constexpr,
54
- HAS_LABEL: tl.constexpr,
55
- reduction: tl.constexpr = _REDUCTION_MODE_BATCHMEAN,
56
- ):
57
- pid = tl.program_id(0).to(tl.int64)
58
- p_ptr += pid * p_stride
59
- q_ptr += pid * q_stride
60
- loss_ptr += pid * loss_stride
61
- grads_ptr += pid * grads_stride
62
- label_ptr += pid
63
-
64
- base_offsets = tl.arange(0, BLOCK_SIZE)
65
-
66
- if HAS_LABEL:
67
- label = tl.load(label_ptr)
68
- if label == ignore_index:
69
- for i in range(0, n_cols, BLOCK_SIZE):
70
- offsets = i + base_offsets
71
- mask = offsets < n_cols
72
- tl.store(grads_ptr + offsets, 0.0, mask=mask)
73
- if reduction == _REDUCTION_MODE_NONE:
74
- tl.store(loss_ptr + offsets, 0.0, mask=mask)
75
- return
76
-
77
- loss_sum = 0.0
78
- for i in range(0, n_cols, BLOCK_SIZE):
79
- offsets = i + base_offsets
80
- mask = offsets < n_cols
81
-
82
- p = tl.load(p_ptr + offsets, mask=mask, other=0.0)
83
- q = tl.load(q_ptr + offsets, mask=mask, other=0.0)
84
-
85
- # TVD(P || Q) = 0.5 * |P - Q|
86
- tv_loss = 0.5 * tl.abs(p - q)
87
-
88
- # Fuse reduction scaling into gradient computation (eliminates separate Python division)
89
- grad_res = tl.where(p > q, 0.5 * scale, -0.5 * scale)
90
-
91
- tl.store(grads_ptr + offsets, grad_res, mask=mask)
92
-
93
- if reduction == _REDUCTION_MODE_NONE:
94
- tl.store(loss_ptr + offsets, tv_loss, mask=mask)
95
- else:
96
- loss_sum += tl.sum(tv_loss, axis=0)
97
-
98
- if reduction != _REDUCTION_MODE_NONE:
99
- # Fuse reduction scaling into loss (same scale as gradients; avoids Python division)
100
- tl.store(loss_ptr, loss_sum * scale)
101
-
102
-
103
- def tv_distance_forward_triton(p, q, shift_labels, reduction, ignore_index, has_label):
104
- BT, V = p.shape
105
-
106
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
107
- num_warps = get_num_warps(BLOCK_SIZE)
108
-
109
- grid = (BT,)
110
-
111
- reduction = _str_to_reduction_mode[reduction]
112
-
113
- out_size = (BT, V) if reduction == _REDUCTION_MODE_NONE.value else (BT,)
114
- output_tensor = torch.zeros(out_size, device=p.device, dtype=torch.float32)
115
- grads = torch.empty_like(p)
116
-
117
- n_non_ignore = (shift_labels != ignore_index).sum().item() if has_label else BT
118
-
119
- # Pre-compute gradient scale factor (fused into kernel to avoid separate division)
120
- if reduction == _REDUCTION_MODE_BATCHMEAN.value:
121
- scale = 1.0 / n_non_ignore
122
- elif reduction == _REDUCTION_MODE_MEAN.value:
123
- scale = 1.0 / (n_non_ignore * V)
124
- else:
125
- scale = 1.0
126
-
127
- _tv_distance_kernel[grid](
128
- p,
129
- p.stride(0),
130
- q,
131
- q.stride(0),
132
- output_tensor,
133
- output_tensor.stride(0),
134
- grads,
135
- grads.stride(0),
136
- shift_labels if has_label else torch.empty(1, device=p.device),
137
- ignore_index,
138
- V,
139
- scale,
140
- BLOCK_SIZE=BLOCK_SIZE,
141
- HAS_LABEL=has_label,
142
- num_warps=num_warps,
143
- reduction=reduction,
144
- )
145
-
146
- # Loss and gradients are already scaled inside the kernel — no separate division needed
147
- if reduction in (_REDUCTION_MODE_BATCHMEAN.value, _REDUCTION_MODE_MEAN.value):
148
- return output_tensor.sum(), grads
149
- elif reduction == _REDUCTION_MODE_SUM.value:
150
- return output_tensor.sum(dim=0), grads
151
- else:
152
- return output_tensor, grads
153
-
154
-
155
- def tvd_backward_triton(grad_output, grads):
156
- # If cross entropy is the last layer, grad_output is 1.0. Skip the mul then.
157
- if torch.equal(grad_output, torch.tensor(1.0, device=grad_output.device)):
158
- return grads
159
-
160
- return grads * grad_output
161
-
162
-
163
- class LigerTVDLossFunction(torch.autograd.Function):
164
- """
165
- Class implementing the forward and backward pass for the Total Variation Distance Loss using Triton.
166
- """
167
-
168
- @staticmethod
169
- @ensure_contiguous
170
- def forward(
171
- ctx,
172
- p: torch.Tensor,
173
- q: torch.Tensor,
174
- shift_labels: Optional[torch.Tensor] = None,
175
- reduction: REDUCTION_LITERAL = "batchmean",
176
- ignore_index: int = -100,
177
- ) -> torch.Tensor:
178
- """A forward pass for the Total Variation Distance Loss.
179
-
180
- Args:
181
- ctx: Torch autograd context
182
- p (torch.Tensor): A tensor of shape (BT, V) containing the first distribution.
183
- q (torch.Tensor): A tensor of shape (BT, V) containing the second distribution.
184
- shift_labels (Optional[torch.Tensor]): A tensor of shape (BT,) containing the labels.
185
- reduction (REDUCTION_LITERAL, optional): The reduction method to be applied. Defaults to "batchmean".
186
- ignore_index (int, optional): The index to ignore during loss calculation. Defaults to -100.
187
-
188
- Returns:
189
- torch.Tensor: The computed Total Variation Distance Loss.
190
- """
191
- has_label = False
192
- if shift_labels is not None:
193
- assert shift_labels.shape == (p.shape[0],), (
194
- f"the shape of shift_labels must be (BT,). Got: {shift_labels.shape}"
195
- )
196
- shift_labels = shift_labels.contiguous()
197
- has_label = True
198
-
199
- loss, grads = tv_distance_forward_triton(p, q, shift_labels, reduction, ignore_index, has_label)
200
- ctx.save_for_backward(grads)
201
- return loss
202
-
203
- @staticmethod
204
- @ensure_contiguous
205
- def backward(ctx, grad_output: torch.Tensor) -> torch.Tensor:
206
- """A backward pass for the Total Variation Distance Loss.
207
-
208
- Args:
209
- ctx: Torch autograd context
210
- grad_output (torch.Tensor): The gradient of the loss with respect to the output.
211
-
212
- Returns:
213
- tuple[torch.Tensor, None, None, None, None]: The gradient of the loss with respect to the inputs.
214
- """
215
- (grads,) = ctx.saved_tensors
216
- grads = tvd_backward_triton(grad_output, grads)
217
-
218
- return grads, None, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-rocm/utils.py DELETED
@@ -1,176 +0,0 @@
1
- """
2
- This file incorporates code from Unsloth licensed under the Apache License, Version 2.0.
3
- See the original Unsloth repository at https://github.com/unslothai/unsloth.
4
-
5
- The following line
6
- https://github.com/linkedin/Liger-Kernel/blob/7382a8761f9af679482b968f9348013d933947c7/src/liger_kernel/ops/utils.py#L23
7
- is based on code from Unsloth, located at:
8
- https://github.com/unslothai/unsloth/blob/fd753fed99ed5f10ef8a9b7139588d9de9ddecfb/unsloth/kernels/utils.py#L43
9
-
10
- Modifications made by Yanning Chen, 2024.
11
- """
12
-
13
- import functools
14
- import importlib
15
- import operator
16
-
17
- from typing import Callable
18
-
19
- import torch
20
- import triton
21
- import triton.language as tl
22
-
23
- from packaging.version import Version
24
-
25
-
26
- def is_npu_available() -> bool:
27
- """Detect Ascend NPU availability."""
28
- try:
29
- from transformers.utils import is_torch_npu_available
30
-
31
- return is_torch_npu_available()
32
- except Exception:
33
- return False
34
-
35
-
36
- def infer_device():
37
- """
38
- Get current device name based on available devices
39
- """
40
- if torch.cuda.is_available(): # Works for both Nvidia and AMD
41
- return "cuda"
42
- # Use Ascend NPU if available (torch.npu)
43
- elif is_npu_available():
44
- return "npu"
45
- # XPU (Intel) if available
46
- elif torch.xpu.is_available():
47
- return "xpu"
48
- else:
49
- return "cpu"
50
-
51
-
52
- def is_hip() -> bool:
53
- return torch.version.hip is not None
54
-
55
-
56
- def ensure_contiguous(fn):
57
- @functools.wraps(fn)
58
- def wrapper(ctx, *args, **kwargs):
59
- def maybe_to_contiguous(x):
60
- return x.contiguous() if isinstance(x, torch.Tensor) else x
61
-
62
- args = [maybe_to_contiguous(arg) for arg in args]
63
- kwargs = {k: maybe_to_contiguous(v) for k, v in kwargs.items()}
64
- return fn(ctx, *args, **kwargs)
65
-
66
- return wrapper
67
-
68
-
69
- def calculate_settings(n):
70
- # reference: https://github.com/unslothai/unsloth/blob/fd753fed99ed5f10ef8a9b7139588d9de9ddecfb/unsloth/kernels/utils.py#L43
71
-
72
- MAX_FUSED_SIZE = 65536
73
- BLOCK_SIZE = triton.next_power_of_2(n)
74
- if BLOCK_SIZE > MAX_FUSED_SIZE:
75
- raise RuntimeError(
76
- f"Cannot launch Triton kernel since n = {n} exceeds the recommended Triton blocksize = {MAX_FUSED_SIZE}."
77
- )
78
-
79
- num_warps = 4
80
- if BLOCK_SIZE >= 32768:
81
- num_warps = 32 if not is_hip() else 16
82
- elif BLOCK_SIZE >= 8192:
83
- num_warps = 16
84
- elif BLOCK_SIZE >= 2048:
85
- num_warps = 8
86
- return BLOCK_SIZE, num_warps
87
-
88
-
89
- def compare_version(package: str, operator: Callable, target: str):
90
- try:
91
- pkg = importlib.import_module(package)
92
- except ImportError:
93
- return False
94
- pkg_version = Version(pkg.__version__)
95
- return operator(pkg_version, Version(target))
96
-
97
-
98
- def get_amp_custom_fwd_bwd() -> Callable:
99
- device = infer_device()
100
- if compare_version("torch", operator.ge, "2.4.0"):
101
- return (
102
- functools.partial(torch.amp.custom_fwd, device_type=device),
103
- functools.partial(torch.amp.custom_bwd, device_type=device),
104
- )
105
- if hasattr(torch, "npu") and getattr(torch.npu, "amp", None) is not None:
106
- return torch.npu.amp.custom_fwd, torch.npu.amp.custom_bwd
107
- return torch.cuda.amp.custom_fwd, torch.cuda.amp.custom_bwd
108
-
109
-
110
- amp_custom_fwd, amp_custom_bwd = get_amp_custom_fwd_bwd()
111
-
112
-
113
- torch_to_triton_dtype = {
114
- torch.float32: tl.float32,
115
- torch.float16: tl.float16,
116
- torch.bfloat16: tl.bfloat16,
117
- }
118
-
119
-
120
- @triton.jit
121
- def element_mul_kernel(
122
- X_ptr,
123
- X_stride,
124
- grad_output_ptr,
125
- n_cols,
126
- BLOCK_SIZE: tl.constexpr,
127
- ):
128
- """
129
- This function multiplies each element of the tensor pointed by X_ptr with the value pointed by grad_output_ptr.
130
- The multiplication is performed in-place on the tensor pointed by X_ptr.
131
-
132
- Parameters:
133
- X_ptr: Pointer to the input tensor.
134
- X_stride (int): The stride of the input tensor.
135
- grad_output_ptr: Pointer to the gradient output value.
136
- n_cols (int): The number of columns in the input tensor.
137
- BLOCK_SIZE (int): The block size for Triton operations.
138
- """
139
-
140
- # Get the program ID and convert it to int64 to avoid overflow
141
- program_id = tl.program_id(0).to(tl.int64)
142
-
143
- # Locate the start index
144
- X_ptr += program_id * X_stride
145
-
146
- # Load the gradient output value
147
- grad_output = tl.load(grad_output_ptr)
148
-
149
- # Perform the element-wise multiplication
150
- for i in range(0, n_cols, BLOCK_SIZE):
151
- X_offsets = i + tl.arange(0, BLOCK_SIZE)
152
- X_block = tl.load(X_ptr + X_offsets, mask=X_offsets < n_cols)
153
- tl.store(X_ptr + X_offsets, X_block * grad_output, mask=X_offsets < n_cols)
154
-
155
-
156
- def get_npu_core_count(default: int = 20) -> int:
157
- """Return NPU vector core count.
158
- Fallback to `default` if Triton runtime or NPU device is unavailable.
159
- """
160
- try:
161
- utils = triton.runtime.driver.active.utils
162
- props = utils.get_device_properties(0)
163
- return int(props.get("num_vectorcore", default))
164
- except Exception:
165
- return default
166
-
167
-
168
- def set_large_grf_mode(kernel_args: dict):
169
- """Set large GRF mode for XPU devices."""
170
- # On XPU triton installed along with pytorch-xpu will be called `pytorch-triton-xpu`,
171
- # triton XPU installed from source will be called `triton`.
172
- if compare_version("pytorch-triton-xpu", operator.ge, "3.6.0") or compare_version("triton", operator.ge, "3.6.0"):
173
- kernel_args["grf_mode"] = "256"
174
- else:
175
- # API was changed in https://github.com/intel/intel-xpu-backend-for-triton/pull/5430
176
- kernel_args["grf_mode"] = "large"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/__init__.py DELETED
@@ -1,4 +0,0 @@
1
- from . import layers
2
- from .layers import CrossEntropyOutput, LigerForCausalLMLoss
3
-
4
- __all__ = ["layers", "LigerForCausalLMLoss", "CrossEntropyOutput"]
 
 
 
 
 
build/torch-xpu/_ops.py DELETED
@@ -1,38 +0,0 @@
1
- import torch
2
-
3
- def get_backend() -> str:
4
- """Detect the backend by inspecting torch."""
5
- import torch
6
-
7
- if hasattr(torch, "neuron"):
8
- # Needs to be sorted before specific Torch builds, since Neuron
9
- # extension can be loaded into e.g. CUDA Torch builds.
10
- return "neuron"
11
- elif torch.version.cuda is not None:
12
- return "cuda"
13
- elif torch.version.hip is not None:
14
- return "rocm"
15
- elif torch.backends.mps.is_available():
16
- return "metal"
17
- elif hasattr(torch.version, "xpu") and torch.version.xpu is not None:
18
- return "xpu"
19
- else:
20
- return "cpu"
21
-
22
-
23
- def _find_ops_name() -> str:
24
- kernel_name = "liger_kernels"
25
- unique_id = "ab435e2"
26
- backend = get_backend()
27
- return f"_{kernel_name}_{backend}_{unique_id}"
28
-
29
-
30
- _OPS_NAME = _find_ops_name()
31
-
32
- ops = getattr(torch.ops, _OPS_NAME)
33
-
34
- def add_op_namespace_prefix(op_name: str) -> str:
35
- """
36
- Prefix op by namespace.
37
- """
38
- return f"{_OPS_NAME}::{op_name}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/cross_entropy.py DELETED
@@ -1,558 +0,0 @@
1
- import operator
2
-
3
- from typing import Optional
4
-
5
- import torch
6
- import triton
7
- import triton.language as tl
8
-
9
- from .utils import compare_version
10
- from .utils import element_mul_kernel
11
- from .utils import is_hip
12
- from .utils import infer_device
13
- from .utils import is_npu_available
14
-
15
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
16
- try:
17
- # typical import path with dispatch available
18
- from triton.language.extra.libdevice import tanh
19
- except ModuleNotFoundError:
20
- # for working with NGC containers
21
- from triton.language.extra.cuda.libdevice import tanh
22
- else:
23
- from triton.language.math import tanh
24
-
25
-
26
- @triton.jit
27
- def liger_cross_entropy_kernel(
28
- X_ptr,
29
- X_stride,
30
- Y_ptr,
31
- Y_stride,
32
- weight_ptr,
33
- loss_ptr,
34
- z_loss_ptr,
35
- loss_stride,
36
- token_accuracy_ptr,
37
- token_accuracy_stride,
38
- predicted_tokens_ptr,
39
- predicted_tokens_stride,
40
- n_cols,
41
- n_non_ignore,
42
- sum_non_ignore_weight,
43
- weight_sum,
44
- ignore_index,
45
- lse_square_scale: tl.constexpr,
46
- label_smoothing: tl.constexpr,
47
- reduction: tl.constexpr, # set it as constexpr since reduction is always known at compile time
48
- softcap,
49
- RETURN_Z_LOSS: tl.constexpr,
50
- RETURN_TOKEN_ACCURACY: tl.constexpr,
51
- RETURN_PREDICTED_TOKENS: tl.constexpr,
52
- BLOCK_SIZE: tl.constexpr,
53
- HAS_WEIGHT: tl.constexpr,
54
- HAS_SOFTCAPPING: tl.constexpr,
55
- HAS_GRADIENTS: tl.constexpr,
56
- ):
57
- """
58
- This kernel computes both cross entropy loss and the gradient of the input.
59
- We only consider hard label + mean reduction for now. Please refer to https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html for the math.
60
-
61
- Parameters:
62
- X_ptr: Pointer to input tensor.
63
- X_stride (int): The stride of the input tensor.
64
- Y_ptr: Pointer to target tensor.
65
- Y_stride (int): The stride of the target tensor.
66
- weight_ptr: Pointer to weight tensor.
67
- loss_ptr: Pointer to tensor to store the loss.
68
- z_loss_ptr: Pointer to tensor to store the z loss. No operation if RETURN_Z_LOSS is 0.
69
- loss_stride (int): The stride of the loss tensor.
70
- token_accuracy_ptr: Pointer to tensor to store the per-token accuracy. No operation if RETURN_TOKEN_ACCURACY is 0.
71
- token_accuracy_stride (int): The stride of the token accuracy tensor.
72
- n_cols (int): The number of columns in the input tensor.
73
- n_non_ignore (float): The number of non-ignored elements in the batch.
74
- sum_non_ignore_weight (float): The sum of non-ignored target's weights in the batch.
75
- weight_sum (float): The sum of weight tensor.
76
- ignore_index (int): The index to ignore in the target.
77
- label_smoothing (float): The amount of smoothing when computing the loss, where 0.0 means no smoothing.
78
- lse_square_scale (float): The scaler of (logsumexp(_input)) ^ 2 adding to the loss for the stability of training.
79
- reduction (str): The string for the reduction to apply
80
- softcap (float): The upper threshold for scaling logits to the range (-softcap, +softcap).
81
- RETURN_Z_LOSS (int): The boolean value to decide whether to store z loss to z_loss_ptr or not. It must be 0 or 1.
82
- RETURN_TOKEN_ACCURACY (int): The boolean value to decide whether to store per-token accuracy to token_accuracy_ptr or not. It must be 0 or 1.
83
- BLOCK_SIZE (int): The block size for Triton operations.
84
- HAS_WEIGHT (bool): The boolean value to determine whether assigning weight to each of the classes.
85
- HAS_SOFTCAPPING (bool): The boolean value to determine whether applying soft-capping or not.
86
- HAS_GRADIENTS (bool): The boolean value to determine whether calculating gradients in forward pass.
87
- """
88
-
89
- # https://github.com/triton-lang/triton/issues/1058
90
- # If B*T*V is too large, program_id * stride will overflow out of int32, so we convert to int64
91
- program_id = tl.program_id(0).to(tl.int64)
92
-
93
- # 1. Load Y_ptr first because if the target is ignore_index, we can return right away
94
- Y_ptr += program_id * Y_stride
95
- y = tl.load(Y_ptr)
96
-
97
- # 2. locate the start index
98
- X_ptr += program_id * X_stride
99
-
100
- if y == ignore_index:
101
- # set all X_ptr as 0
102
- for i in range(0, n_cols, BLOCK_SIZE):
103
- X_offsets = i + tl.arange(0, BLOCK_SIZE)
104
- tl.store(X_ptr + X_offsets, 0.0, mask=X_offsets < n_cols)
105
- # For ignored tokens, set token accuracy to 0
106
- if RETURN_TOKEN_ACCURACY:
107
- token_accuracy_ptr += program_id * token_accuracy_stride
108
- tl.store(token_accuracy_ptr, 0.0)
109
- if RETURN_PREDICTED_TOKENS:
110
- predicted_tokens_ptr += program_id * predicted_tokens_stride
111
- tl.store(predicted_tokens_ptr, -1)
112
- return
113
-
114
- loss_ptr += program_id * loss_stride
115
- if RETURN_Z_LOSS:
116
- z_loss_ptr += program_id * loss_stride
117
- if RETURN_TOKEN_ACCURACY:
118
- token_accuracy_ptr += program_id * token_accuracy_stride
119
- if RETURN_PREDICTED_TOKENS:
120
- predicted_tokens_ptr += program_id * predicted_tokens_stride
121
-
122
- if HAS_WEIGHT:
123
- weight_y = tl.load(weight_ptr + y).cast(tl.float32)
124
-
125
- # Online softmax: 2 loads + 1 store (compared with 3 loads + 1 store for the safe softmax)
126
- # Refer to Algorithm 3 in the paper: https://arxiv.org/pdf/1805.02867
127
-
128
- # 3. [Online softmax] first pass: find max + sum
129
- m = float("-inf") # m is the max value. use the notation from the paper
130
- d = 0.0 # d is the sum. use the notation from the paper
131
- argmax_idx = 0 # Track the index of the maximum value for token accuracy / predicted tokens computation
132
- ori_X_y = tl.load(X_ptr + y).cast(tl.float32) # we need to store the original value of X_y for the loss calculation
133
- if HAS_SOFTCAPPING:
134
- ori_X_y = softcap * tanh(ori_X_y / softcap)
135
-
136
- # Label smoothing is a general case of normal cross entropy
137
- # See the full derivation at https://github.com/linkedin/Liger-Kernel/pull/198#issue-2503665310
138
- scaled_x_sum = 0.0
139
- eps = label_smoothing / n_cols
140
-
141
- for i in range(0, n_cols, BLOCK_SIZE):
142
- X_offsets = i + tl.arange(0, BLOCK_SIZE)
143
- X_block = tl.load(
144
- X_ptr + X_offsets,
145
- mask=X_offsets < n_cols,
146
- other=float("-inf"),
147
- # Ensure float32 precision for softmax calculation
148
- ).cast(tl.float32)
149
- if HAS_SOFTCAPPING:
150
- X_block = softcap * tanh(X_block / softcap)
151
- block_max = tl.max(X_block)
152
-
153
- # Track argmax for accuracy / predicted tokens computation
154
- if RETURN_TOKEN_ACCURACY or RETURN_PREDICTED_TOKENS:
155
- # Find the index of the maximum value in this block
156
- is_max_mask = X_block == block_max
157
- # Mask out invalid indices with a value larger than n_cols
158
- masked_offsets = tl.where(is_max_mask, X_offsets, n_cols)
159
- # Get the first (smallest) index where max occurs
160
- current_block_argmax_idx = tl.min(masked_offsets)
161
-
162
- is_new_max = block_max > m
163
- argmax_idx = tl.where(is_new_max, current_block_argmax_idx, argmax_idx)
164
-
165
- if label_smoothing > 0:
166
- # scale X beforehand to avoid overflow
167
- if HAS_WEIGHT:
168
- weight_block = tl.load(weight_ptr + X_offsets, mask=X_offsets < n_cols)
169
- scaled_x_sum += tl.sum(tl.where(X_offsets < n_cols, -eps * X_block * weight_block, 0.0))
170
- else:
171
- scaled_x_sum += tl.sum(tl.where(X_offsets < n_cols, -eps * X_block, 0.0))
172
- m_new = tl.maximum(m, block_max)
173
- d = d * tl.exp(m - m_new) + tl.sum(tl.exp(X_block - m_new))
174
- m = m_new
175
-
176
- # log (sum(e^(X_i))) = log (sum(e ^ (max(X) * e ^ (X_i - max(X)))))
177
- # = log (e^(max(X)) * sum(e ^ (X_i - max(X))))
178
- # = max(X) + log (sum(e ^ (X_i - max(X)))) = m + log d
179
- lse = m + tl.log(d)
180
-
181
- # 4. [Online Softmax] Second pass: compute gradients
182
- # For 'mean' reduction, gradients are normalized by number of non-ignored elements (N)
183
- # dx_y = (softmax(x_y) - 1) / N
184
- # dx_i = softmax(x_i) / N, i != y
185
- # For label smoothing:
186
- # dx_i = (softmax(x_i) - label_smoothing / V) / N, V = n_cols, i != y
187
- # dx_y = (softmax(x_y) - label_smoothing / V - (1 - label_smoothing)) / N
188
- # = dx_i - (1 - label_smoothing) / N
189
- # With Z loss:
190
- # dx_i = ((1 + 2 * lse_square_scale * lse) * softmax(x_i) - label_smoothing / V) / N, i != y
191
- # dx_y = dx_i - (1 - label_smoothing) / N
192
- # For 'sum' reduction, no normalization is applied:
193
- # dx_y = softmax(x_y) - 1
194
- # dx_i = softmax(x_i), for i ≠ y
195
- if HAS_GRADIENTS:
196
- for i in range(0, n_cols, BLOCK_SIZE):
197
- X_offsets = i + tl.arange(0, BLOCK_SIZE)
198
- X_block = tl.load(
199
- X_ptr + X_offsets,
200
- mask=X_offsets < n_cols,
201
- other=float("-inf"),
202
- # Ensure float32 precision for softmax calculation
203
- ).cast(tl.float32)
204
- if HAS_SOFTCAPPING:
205
- intermediate = tanh(X_block / softcap)
206
- X_block = softcap * intermediate
207
-
208
- if not HAS_WEIGHT:
209
- # softmax(x_i)
210
- X_block = tl.exp(X_block - m) / d
211
- # derivative of z-loss: 2 * lse_square_scale * lse * softmax(x_i)
212
- X_block += 2 * lse_square_scale * lse * X_block
213
- # smoothing term
214
- X_block += -eps
215
- # special handle dx_y
216
- X_block = tl.where(X_offsets != y, X_block, X_block - (1 - label_smoothing))
217
- # reduction scale
218
- if reduction == "mean":
219
- X_block = X_block / n_non_ignore
220
- else:
221
- weight_block = tl.load(weight_ptr + X_offsets, mask=X_offsets < n_cols)
222
- softmax_X = tl.exp(X_block - m) / d
223
- # derivative of original_loss
224
- dloss_ori = (1 - label_smoothing) * softmax_X
225
- # specially handle dx_y
226
- dloss_ori = tl.where(X_offsets != y, dloss_ori, dloss_ori - (1 - label_smoothing))
227
- dloss_ori = dloss_ori * weight_y
228
- # derivative of smooth_loss
229
- dloss_smooth = eps * (-weight_block + softmax_X * weight_sum)
230
- # derivative of z-loss
231
- dz_loss = 2 * lse_square_scale * lse * softmax_X
232
- # reduction scale
233
- if reduction == "mean":
234
- dloss_ori = dloss_ori / sum_non_ignore_weight
235
- dloss_smooth = dloss_smooth / sum_non_ignore_weight
236
- # TODO: Implement weighted z_loss. Currently, z_loss is not scaled by weight.
237
- dz_loss = dz_loss / n_non_ignore
238
- # derivative of total_loss
239
- X_block = dloss_ori + dloss_smooth + dz_loss
240
-
241
- # chain rule softcapping
242
- # d(softcap * tanh(x / softcap)) = (1 - tanh^2(x / softcap))
243
- if HAS_SOFTCAPPING:
244
- X_block = X_block * (1 - intermediate * intermediate)
245
-
246
- tl.store(X_ptr + X_offsets, X_block, mask=X_offsets < n_cols)
247
-
248
- # We need tl.debug_barrier() to ensure the new result of X_ptr is written as mentioned in
249
- # https://github.com/triton-lang/triton/blob/ba42a5c68fd0505f8c42f4202d53be0f8d9a5fe0/python/triton/ops/cross_entropy.py#L34
250
- tl.debug_barrier()
251
-
252
- # 5. Calculate the loss
253
-
254
- # loss = log (softmax(X_y)) = log ((e ^ (X_y - max(X)) / sum(e ^ (X - max(X))))
255
- # = (X_y - max(X)) - log(sum(e ^ (X - max(X))))
256
- # = X_y - m - log d = X_y - lse
257
- # sum(e ^ (X - max(X))) must >= 1 because the max term is e ^ 0 = 1
258
- # So we can safely calculate log (softmax(X_y)) without overflow
259
- loss = lse - ori_X_y
260
- if HAS_WEIGHT:
261
- loss = weight_y * loss
262
-
263
- # Original loss = H(q, p), with label smoothing regularization = H(q', p) and (label_smoothing / V) = eps
264
- # H(q', p) = (1 - label_smoothing) * H(q, p) + label_smoothing * H(u, p)
265
- # = (1 - label_smoothing) * H(q, p) + eps * sum(logsoftmax(x_i))
266
- # By using m (global max of xi) and d (sum of e^(xi-m)), we can simplify as:
267
- # = (1 - label_smoothing) * H(q, p) + (sum(-eps * x_i) + label_smoothing * (m + logd))
268
- # Refer to H(q', p) in section 7 of the paper: https://arxiv.org/pdf/1512.00567
269
- # pytorch: https://github.com/pytorch/pytorch/blob/2981534f54d49fa3a9755c9b0855e7929c2527f0/aten/src/ATen/native/LossNLL.cpp#L516
270
- # See full derivation at https://github.com/linkedin/Liger-Kernel/pull/198#issuecomment-2333753087
271
- if label_smoothing > 0:
272
- if HAS_WEIGHT:
273
- smooth_loss = scaled_x_sum + eps * lse * weight_sum
274
- else:
275
- smooth_loss = scaled_x_sum + label_smoothing * lse
276
- loss = loss * (1 - label_smoothing) + smooth_loss
277
-
278
- # An auxiliary loss, z_loss
279
- # Refer to Page14 Loss function section in the paper PaLM: https://www.jmlr.org/papers/v24/22-1144.html
280
- z_loss = lse_square_scale * lse * lse
281
- # Normalize the loss by the number of non-ignored elements if reduction is "mean"
282
- if reduction == "mean":
283
- if HAS_WEIGHT:
284
- loss = loss / sum_non_ignore_weight
285
- else:
286
- loss = loss / n_non_ignore
287
- # TODO: Implement weighted z_loss. Currently, z_loss is not scaled by weight.
288
- z_loss = z_loss / n_non_ignore
289
- loss += z_loss
290
-
291
- tl.store(loss_ptr, loss)
292
- if RETURN_Z_LOSS:
293
- tl.store(z_loss_ptr, z_loss)
294
- if RETURN_TOKEN_ACCURACY:
295
- # Store 1.0 if prediction is correct, 0.0 otherwise
296
- is_correct = 1.0 if argmax_idx == y else 0.0
297
- tl.store(token_accuracy_ptr, is_correct)
298
- if RETURN_PREDICTED_TOKENS:
299
- tl.store(predicted_tokens_ptr, argmax_idx)
300
-
301
-
302
- # The hard limit of TRITON_MAX_TENSOR_NUMEL is 1048576 https://github.com/triton-lang/triton/blob/ba42a5c68fd0505f8c42f4202d53be0f8d9a5fe0/python/triton/language/core.py#L19
303
- # However, setting limit as 65536 as in LayerNorm tutorial is faster because of less register spilling
304
- # The optimal maximum block size depends on your hardware, your kernel, and your dtype
305
- # the best size we found by manually tuning on xpu and npu.
306
- if infer_device() == "xpu":
307
- MAX_FUSED_SIZE = 4096
308
- elif infer_device() == "npu":
309
- MAX_FUSED_SIZE = 2048
310
- else:
311
- MAX_FUSED_SIZE = 65536 // 2
312
-
313
-
314
- def cross_entropy_forward(
315
- _input,
316
- target,
317
- weight,
318
- ignore_index,
319
- lse_square_scale,
320
- label_smoothing,
321
- reduction,
322
- softcap,
323
- return_z_loss,
324
- return_token_accuracy=False,
325
- return_predicted_tokens=False,
326
- ):
327
- assert isinstance(return_z_loss, bool), f"return_z_loss must be True or False. Got: {return_z_loss}"
328
- assert isinstance(return_token_accuracy, bool), (
329
- f"return_token_accuracy must be True or False. Got: {return_token_accuracy}"
330
- )
331
- assert isinstance(return_predicted_tokens, bool), (
332
- f"return_predicted_tokens must be True or False. Got: {return_predicted_tokens}"
333
- )
334
-
335
- BT, V = _input.shape
336
- n_rows = BT
337
-
338
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
339
-
340
- # unreduced loss
341
- loss_1d = torch.zeros(n_rows, dtype=_input.dtype, device=_input.device)
342
- z_loss_1d = torch.zeros(n_rows, dtype=_input.dtype, device=_input.device) if return_z_loss else None
343
- token_accuracy_1d = (
344
- torch.zeros(n_rows, dtype=torch.float32, device=_input.device) if return_token_accuracy else None
345
- )
346
- predicted_tokens_1d = (
347
- torch.full((n_rows,), -1, dtype=torch.int64, device=_input.device) if return_predicted_tokens else None
348
- )
349
-
350
- target_mask = target != ignore_index
351
- n_non_ignore = target_mask.sum().item()
352
- assert (target * target_mask).max() < _input.shape[-1], (
353
- f"Target {target.max()} is out of bounds. Expected < {_input.shape[-1]}"
354
- )
355
- assert (target * target_mask).min() >= 0, f"Target {target.min()} is out of bounds. Expected >= 0"
356
- sum_non_ignore_weight = n_non_ignore
357
- weight_sum = 0.0
358
- if weight is not None:
359
- assert weight.shape[0] == V, f"If given, weight has to be a Tensor of size V. Got: {weight.shape}"
360
- assert torch.is_floating_point(weight), (
361
- f"If given, weight has to be a Tensor of floating point dtype. Got: {weight.dtype}"
362
- )
363
- sum_non_ignore_weight = torch.gather(weight, dim=0, index=target.masked_select(target_mask)).sum().item()
364
- weight_sum = weight.sum().item()
365
- # ensure weight is contiguous
366
- if weight.stride(-1) != 1:
367
- weight = weight.contiguous()
368
-
369
- # ensure _input and target are contiguous in the last dimension
370
- if _input.stride(-1) != 1:
371
- _input = _input.contiguous()
372
- if target.stride(-1) != 1:
373
- target = target.contiguous()
374
-
375
- # Here we use a trick to store X_ptr gradient in X_ptr so we can save memory
376
- liger_cross_entropy_kernel[(n_rows,)](
377
- X_ptr=_input,
378
- X_stride=_input.stride(-2),
379
- Y_ptr=target,
380
- Y_stride=target.stride(-1), # always 1
381
- weight_ptr=weight, # dummy if None
382
- loss_ptr=loss_1d,
383
- z_loss_ptr=z_loss_1d,
384
- loss_stride=loss_1d.stride(-1), # always 1
385
- token_accuracy_ptr=token_accuracy_1d,
386
- token_accuracy_stride=token_accuracy_1d.stride(-1)
387
- if return_token_accuracy
388
- else 0, # always 1 if accuracy is enabled
389
- predicted_tokens_ptr=predicted_tokens_1d,
390
- predicted_tokens_stride=predicted_tokens_1d.stride(-1)
391
- if return_predicted_tokens
392
- else 0, # always 1 if predicted tokens is enabled
393
- n_cols=V,
394
- n_non_ignore=n_non_ignore,
395
- sum_non_ignore_weight=sum_non_ignore_weight,
396
- ignore_index=ignore_index,
397
- weight_sum=weight_sum,
398
- lse_square_scale=lse_square_scale,
399
- label_smoothing=label_smoothing,
400
- reduction=reduction,
401
- softcap=softcap,
402
- RETURN_Z_LOSS=return_z_loss,
403
- RETURN_TOKEN_ACCURACY=return_token_accuracy,
404
- RETURN_PREDICTED_TOKENS=return_predicted_tokens,
405
- BLOCK_SIZE=BLOCK_SIZE,
406
- HAS_WEIGHT=True if weight is not None else False,
407
- HAS_SOFTCAPPING=True if softcap is not None else False,
408
- HAS_GRADIENTS=_input.requires_grad,
409
- # TODO: 32 seems to give the best performance
410
- # Performance is quite sensitive to num_warps
411
- num_warps=32 if not is_hip() else 16,
412
- )
413
-
414
- if reduction == "none":
415
- loss = loss_1d
416
- z_loss = z_loss_1d if return_z_loss else None
417
- token_accuracy = token_accuracy_1d if return_token_accuracy else None
418
- else:
419
- loss = torch.sum(loss_1d)
420
- z_loss = torch.sum(z_loss_1d) if return_z_loss else None
421
- # For accuracy, we compute the mean across all non-ignored tokens
422
- token_accuracy = torch.sum(token_accuracy_1d) / n_non_ignore if return_token_accuracy else None
423
-
424
- predicted_tokens = predicted_tokens_1d if return_predicted_tokens else None
425
-
426
- return loss, z_loss, token_accuracy, predicted_tokens, _input
427
-
428
-
429
- def cross_entropy_backward(_input, grad_output):
430
- # If cross entropy is the last layer, grad_output is 1.0. Skip the mul to save time
431
- if torch.equal(grad_output, torch.tensor(1.0, device=grad_output.device)):
432
- pass
433
- # If reduction is 'none'
434
- elif grad_output.ndim > 0:
435
- _input = _input * grad_output.unsqueeze(dim=1)
436
- # If reduction is ['mean', 'sum'], grad_output is just a scalar
437
- # We use a Triton kernel instead of a PyTorch operation because modifying inputs in-place
438
- # for gradient storage and backward multiple times causes anomalies with PyTorch but not with Triton.
439
- else:
440
- BT, V = _input.shape
441
- n_rows = BT
442
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
443
-
444
- element_mul_kernel[(n_rows,)](
445
- _input,
446
- _input.stride(-2),
447
- grad_output,
448
- V,
449
- BLOCK_SIZE=BLOCK_SIZE,
450
- num_warps=32 if not is_hip() else 16,
451
- )
452
-
453
- return _input
454
-
455
-
456
- class LigerCrossEntropyFunction(torch.autograd.Function):
457
- """
458
- This class implements a custom autograd function for the Liger Cross Entropy loss.
459
- It overrides the forward and backward methods of the torch.autograd.Function class.
460
- """
461
-
462
- @staticmethod
463
- def forward(
464
- ctx,
465
- _input: torch.Tensor,
466
- target: torch.Tensor,
467
- weight: Optional[torch.FloatTensor],
468
- ignore_index: int = -100,
469
- lse_square_scale: float = 0.0,
470
- label_smoothing: float = 0.0,
471
- reduction: str = "mean",
472
- softcap: Optional[float] = None,
473
- return_z_loss: bool = False,
474
- return_token_accuracy: bool = False,
475
- return_predicted_tokens: bool = False,
476
- ):
477
- """
478
- The forward pass of the Liger Cross Entropy loss.
479
-
480
- Parameters:
481
- ctx : The context object.
482
- _input (tensor): The input tensor of shape (BT, V) where B is batch size, T is sequence length, V is vocab size.
483
- target (tensor): The target tensor of shape (BT) where each value is in [0, V-1].
484
- weight(Tensor, optional): a manual rescaling weight given to each class. If given, has to be a Tensor of size V and floating point dtype
485
- ignore_index (int): The index to ignore in the target.
486
- lse_square_scale (float): The scaler of (logsumexp(_input)) ^ 2 adding to the loss for the stability of training.
487
- label_smoothing (float): The amount of smoothing when computing the loss, where 0.0 means no smoothing.
488
- reduction (str): The reduction to apply to the output: "none" | "mean | "sum".
489
- softcap (Optional[float]): The upper threshold for scaling logits to the range (-softcap, +softcap).
490
- return_z_loss (bool): When `return_z_loss` is `True`, returns (loss, z_loss, token_accuracy, predicted_tokens) instead of (loss, None, None, None). Default: `False`
491
- return_token_accuracy (bool): When `return_token_accuracy` is `True`, computes and returns per-token accuracy without materializing logits. Default: `False`
492
- return_predicted_tokens (bool): When `return_predicted_tokens` is `True`, returns per-token predicted class indices (argmax) without materializing logits. Default: `False`
493
-
494
- Returns:
495
- tuple: A tuple with the computed losses, accuracy, and predicted tokens: (loss, z_loss, token_accuracy, predicted_tokens). z_loss, token_accuracy, and predicted_tokens are None if not requested.
496
- """
497
- input_requires_grad = _input.requires_grad
498
-
499
- loss, z_loss, token_accuracy, predicted_tokens, _input = cross_entropy_forward(
500
- _input,
501
- target,
502
- weight,
503
- ignore_index,
504
- lse_square_scale,
505
- label_smoothing,
506
- reduction,
507
- softcap,
508
- return_z_loss,
509
- return_token_accuracy,
510
- return_predicted_tokens,
511
- )
512
- # TODO: investigation
513
- # If we don't detach the _input tensor, the memory will double
514
- # Not sure why but seems that there will be a time both grad and value exist but in different location
515
- if input_requires_grad:
516
- ctx.save_for_backward(_input.detach())
517
- ctx.return_z_loss = return_z_loss
518
- ctx.return_token_accuracy = return_token_accuracy
519
- ctx.return_predicted_tokens = return_predicted_tokens
520
-
521
- return loss, z_loss, token_accuracy, predicted_tokens
522
-
523
- @staticmethod
524
- def backward(ctx, grad_output, grad_output2, grad_output3, grad_output4):
525
- """
526
- The backward pass of the Liger Cross Entropy loss.
527
-
528
- Parameters:
529
- ctx : The context object with saved tensors.
530
- grad_output (tensor): The tensor containing the gradient of the loss with respect to the output.
531
- grad_output2 (tensor): No use. Gradient for z_loss (not used as z_loss is only for logging).
532
- grad_output3 (tensor): No use. Gradient for token_accuracy (not used as token_accuracy is only for metrics).
533
- grad_output4 (tensor): No use. Gradient for predicted_tokens (not used as predicted_tokens is only for metrics).
534
- Returns:
535
- tuple: A tuple with the gradients with respect to the inputs. The elements are tensors or None.
536
- """
537
- if ctx.return_z_loss:
538
- del grad_output2 # z_loss is only for logging
539
- if ctx.return_token_accuracy:
540
- del grad_output3 # token_accuracy is only for metrics
541
- if ctx.return_predicted_tokens:
542
- del grad_output4 # predicted_tokens is only for metrics
543
-
544
- (_input,) = ctx.saved_tensors
545
- _input = cross_entropy_backward(_input, grad_output)
546
- return (
547
- _input,
548
- None,
549
- None,
550
- None,
551
- None,
552
- None,
553
- None,
554
- None,
555
- None,
556
- None,
557
- None,
558
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/dyt.py DELETED
@@ -1,164 +0,0 @@
1
- import operator
2
-
3
- import torch
4
- import triton
5
- import triton.language as tl
6
-
7
- from .utils import compare_version
8
- from .utils import ensure_contiguous
9
- from .utils import get_npu_core_count
10
- from .utils import infer_device
11
- from .utils import is_npu_available
12
-
13
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
14
- try:
15
- # typical import path with dispatch available
16
- from triton.language.extra.libdevice import tanh
17
- except ModuleNotFoundError:
18
- # for working with NGC containers
19
- from triton.language.extra.cuda.libdevice import tanh
20
- else:
21
- from triton.language.math import tanh
22
-
23
-
24
- @triton.autotune(
25
- configs=[
26
- triton.Config({"BLOCK_N": bn}, num_stages=ns, num_warps=nw)
27
- for bn in [1024, 2048, 4096]
28
- for ns in [1, 2]
29
- for nw in [4, 8, 16]
30
- ],
31
- key=["N"],
32
- )
33
- @triton.jit
34
- def _dyt_fwd_kernel(X, Y, Alpha, Gamma, Beta, HAVE_BETA: tl.constexpr, N: tl.constexpr, BLOCK_N: tl.constexpr):
35
- col = tl.cast(tl.program_id(0), tl.int64) * BLOCK_N + tl.arange(0, BLOCK_N)
36
- mask = col < N
37
- row_id = tl.cast(tl.program_id(1), tl.int64)
38
-
39
- X += row_id * N
40
- Y += row_id * N
41
- alpha = tl.load(Alpha).to(tl.float32)
42
-
43
- gamma = tl.load(Gamma + col, mask=mask, other=0.0).to(tl.float32)
44
-
45
- x = tl.load(X + col, mask=mask, other=0.0).to(tl.float32)
46
-
47
- tanh_x = tanh(alpha * x)
48
- y = tanh_x * gamma
49
- if HAVE_BETA:
50
- beta = tl.load(Beta + col, mask=mask, other=0.0).to(tl.float32)
51
- y += beta
52
- tl.store(Y + col, y, mask=mask)
53
-
54
-
55
- @triton.autotune(
56
- configs=[
57
- triton.Config({"BLOCK_N": bn}, num_stages=ns, num_warps=nw)
58
- for bn in [1024, 2048, 4096]
59
- for ns in [1, 2]
60
- for nw in [4, 8, 16]
61
- ],
62
- key=["N"],
63
- # DA is indexed by program_id(0), so different BLOCK_N configs write to
64
- # different slot counts per SM. Autotune trials don't zero outputs between
65
- # runs, so stale slots from a prior trial would leak into da.sum(). Reset
66
- # DA between trials to isolate each config's writes.
67
- reset_to_zero=["DA"],
68
- )
69
- @triton.jit
70
- def _dyt_bwd_kernel(
71
- DY, DX, DA, DG, DB, X, Alpha, Gamma, HAVE_BETA: tl.constexpr, M, N: tl.constexpr, BLOCK_N: tl.constexpr
72
- ):
73
- col = tl.cast(tl.program_id(0), tl.int64) * BLOCK_N + tl.arange(0, BLOCK_N)
74
- mask = col < N
75
- start_row_id = tl.cast(tl.program_id(1), tl.int64)
76
-
77
- alpha = tl.load(Alpha).to(tl.float32)
78
- da = 0.0
79
- gamma = tl.load(Gamma + col, mask=mask, other=0.0).to(tl.float32)
80
- dg = tl.zeros((BLOCK_N,), dtype=tl.float32)
81
- if HAVE_BETA:
82
- db = tl.zeros((BLOCK_N,), dtype=tl.float32)
83
- for row_id in range(start_row_id, M, tl.num_programs(1)):
84
- x = tl.load(X + row_id * N + col, mask=mask, other=0.0).to(tl.float32)
85
- dy = tl.load(DY + row_id * N + col, mask=mask, other=0.0).to(tl.float32)
86
- tanh_x = tanh(alpha * x)
87
- if HAVE_BETA:
88
- db += dy
89
- dg += dy * tanh_x
90
- tmp = (1 - tanh_x * tanh_x) * dy * gamma
91
- da += tl.sum(x * tmp, 0)
92
- dx = alpha * tmp
93
- tl.store(DX + row_id * N + col, dx, mask=mask)
94
-
95
- tl.store(DG + start_row_id * N + col, dg, mask=mask)
96
- if HAVE_BETA:
97
- tl.store(DB + start_row_id * N + col, db, mask=mask)
98
- tl.store(DA + start_row_id * tl.cdiv(N, 512) + tl.program_id(0), da)
99
-
100
-
101
- def liger_dyt_fwd(x, alpha, gamma, beta):
102
- assert x.is_contiguous()
103
- HAVE_BETA = True if beta is not None else False
104
- input_shape = x.shape
105
- x = x.view(-1, input_shape[-1])
106
- M, N = x.shape
107
-
108
- y = torch.empty_like(x)
109
-
110
- grid = lambda meta: (triton.cdiv(N, meta["BLOCK_N"]), M)
111
- _dyt_fwd_kernel[grid](
112
- x,
113
- y,
114
- alpha,
115
- gamma,
116
- beta,
117
- HAVE_BETA,
118
- N,
119
- )
120
- return y.view(input_shape)
121
-
122
-
123
- def liger_dyt_bwd(dy, x, alpha, gamma, beta):
124
- assert dy.is_contiguous()
125
- input_shape = x.shape
126
- x = x.view(-1, input_shape[-1])
127
- M, N = x.shape
128
- HAVE_BETA = True if beta is not None else False
129
-
130
- device = infer_device()
131
- if device == "cuda":
132
- NUM_SMS = torch.cuda.get_device_properties(x.device).multi_processor_count
133
- elif device == "xpu":
134
- NUM_SMS = torch.xpu.get_device_properties(x.device).gpu_subslice_count
135
- elif device == "npu":
136
- NUM_SMS = get_npu_core_count()
137
- da = torch.zeros(NUM_SMS, triton.cdiv(N, 512), dtype=torch.float32, device=x.device)
138
- dg = torch.empty(NUM_SMS, N, dtype=torch.float32, device=x.device)
139
- db = torch.empty(NUM_SMS, N, dtype=torch.float32, device=x.device) if HAVE_BETA else None
140
- dx = torch.empty_like(dy)
141
-
142
- grid = lambda meta: (triton.cdiv(N, meta["BLOCK_N"]), NUM_SMS)
143
- _dyt_bwd_kernel[grid](dy, dx, da, dg, db, x, alpha, gamma, HAVE_BETA, M, N)
144
- if HAVE_BETA:
145
- db = db.sum(0).to(x.dtype)
146
- dg = dg.sum(0).to(gamma.dtype)
147
- da = da.sum().to(x.dtype).unsqueeze(0)
148
- return dx.view(input_shape), da, dg, db
149
-
150
-
151
- class LigerDyTFunction(torch.autograd.Function):
152
- @staticmethod
153
- @ensure_contiguous
154
- def forward(ctx, x, alpha, gamma, beta):
155
- y = liger_dyt_fwd(x, alpha, gamma, beta)
156
- ctx.save_for_backward(x, alpha, gamma, beta)
157
- return y
158
-
159
- @staticmethod
160
- @ensure_contiguous
161
- def backward(ctx, dy):
162
- x, alpha, gamma, beta = ctx.saved_tensors
163
- dx, dalpha, dgamma, dbeta = liger_dyt_bwd(dy, x, alpha, gamma, beta)
164
- return dx, dalpha, dgamma, dbeta
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/fused_linear_cross_entropy.py DELETED
@@ -1,400 +0,0 @@
1
- import torch
2
- import triton
3
-
4
- from .cross_entropy import liger_cross_entropy_kernel
5
- from .utils import amp_custom_bwd
6
- from .utils import amp_custom_fwd
7
- from .utils import element_mul_kernel
8
- from .utils import is_hip
9
- from .utils import infer_device
10
-
11
- # The hard limit of TRITON_MAX_TENSOR_NUMEL is 1048576 https://github.com/triton-lang/triton/blob/ba42a5c68fd0505f8c42f4202d53be0f8d9a5fe0/python/triton/language/core.py#L19
12
- # However, setting limit as 65536 as in LayerNorm tutorial is faster because of less register spilling
13
- # The optimal maximum block size depends on your hardware, your kernel, and your dtype
14
- MAX_FUSED_SIZE = 2048 if infer_device() == "npu" else 65536 // 2
15
-
16
-
17
- def fused_linear_cross_entropy_forward(
18
- _input,
19
- weight,
20
- target,
21
- ce_weight=None,
22
- bias=None,
23
- ignore_index=-100,
24
- lse_square_scale=0.0,
25
- label_smoothing=0.0,
26
- reduction="mean",
27
- softcap=None,
28
- return_z_loss=False,
29
- accum_dtype=None,
30
- use_token_scaling=False,
31
- return_token_accuracy=False,
32
- return_predicted_tokens=False,
33
- ):
34
- assert isinstance(return_z_loss, bool), f"return_z_loss must be True or False. Got: {return_z_loss}"
35
- assert isinstance(return_token_accuracy, bool), (
36
- f"return_token_accuracy must be True or False. Got: {return_token_accuracy}"
37
- )
38
- assert isinstance(return_predicted_tokens, bool), (
39
- f"return_predicted_tokens must be True or False. Got: {return_predicted_tokens}"
40
- )
41
- device = _input.device
42
-
43
- input_requires_grad = _input.requires_grad
44
-
45
- # inputs have shape: BT x H
46
- # materialized activations will have shape: BT x V
47
- # the increase in memory = BT x V
48
- # reduction can be achieved by partitioning the number of tokens BT into smaller chunks.
49
- # for ex: if we were to achieve the same memory consumption as BT x H, then the chunk size should be:
50
- # inc_factor = (V+H-1)//H, chunk_size = (BT + inc_factor - 1)//inc_factor
51
- # for ex: BT = 4096*4, V = 32000, H = 4096 ==> inc_factor = 8, chunk_size = 2048
52
- BT, H = _input.shape
53
- V = weight.shape[0]
54
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
55
-
56
- inc_factor = triton.cdiv(V, H) # (V + H - 1) // H
57
- chunk_size = triton.next_power_of_2(triton.cdiv(BT, inc_factor)) # (BT + inc_factor - 1) // inc_factor
58
- num_chunks = triton.cdiv(BT, chunk_size) # (BT + chunk_size - 1) // chunk_size
59
-
60
- grad_input = torch.zeros_like(_input, device=device)
61
-
62
- # we use fp32 for loss and gradients accumulator
63
- if input_requires_grad:
64
- if accum_dtype is None:
65
- grad_weight = torch.zeros_like(weight, device=device) if weight.requires_grad else None
66
- grad_bias = torch.zeros_like(bias, device=device) if bias is not None else None
67
- else:
68
- grad_weight = torch.zeros_like(weight, dtype=accum_dtype, device=device) if weight.requires_grad else None
69
- grad_bias = torch.zeros_like(bias, dtype=accum_dtype, device=device) if bias is not None else None
70
- else:
71
- grad_weight = None
72
- grad_bias = None
73
-
74
- loss_1d = torch.zeros(BT, dtype=torch.float32, device=device)
75
- z_loss_1d = torch.zeros(BT, dtype=_input.dtype, device=_input.device) if return_z_loss else None
76
- token_accuracy_1d = torch.zeros(BT, dtype=torch.float32, device=device) if return_token_accuracy else None
77
- predicted_tokens_1d = torch.full((BT,), -1, dtype=torch.int64, device=device) if return_predicted_tokens else None
78
-
79
- # TODO: evaluate how CUDA synchronization caused by .item() affects the speed
80
- target_mask = target != ignore_index
81
- total_n_non_ignore = target_mask.sum().item()
82
- total_sum_non_ignore_ce_weight = total_n_non_ignore
83
- ce_weight_sum = 0.0
84
- if ce_weight is not None:
85
- assert ce_weight.shape[0] == V, f"If given, weight has to be a Tensor of size V. Got: {ce_weight.shape}"
86
- assert torch.is_floating_point(ce_weight), (
87
- f"If given, weight has to be a Tensor of floating point dtype. Got: {ce_weight.dtype}"
88
- )
89
- total_sum_non_ignore_ce_weight = (
90
- torch.gather(ce_weight, dim=0, index=target.masked_select(target_mask)).sum().item()
91
- )
92
- ce_weight_sum = ce_weight.sum().item()
93
- if ce_weight.stride(-1) != 1:
94
- ce_weight = ce_weight.contiguous()
95
-
96
- for chunk_id in range(num_chunks):
97
- start_idx = chunk_id * chunk_size
98
- end_idx = min((chunk_id + 1) * chunk_size, BT)
99
- _input_chunk = _input[start_idx:end_idx] # chunk_size x H
100
-
101
- # when doing matmul, use the original precision
102
- logits_chunk = _input_chunk @ weight.t() # chunk_size x V
103
- if bias is not None:
104
- logits_chunk = logits_chunk + bias
105
-
106
- target_chunk = target[start_idx:end_idx] # chunk_size,
107
-
108
- n_rows = logits_chunk.shape[0]
109
-
110
- # Compute predicted probabilities for token scaling if needed
111
- if use_token_scaling:
112
- # Compute softmax probabilities for scaling
113
- # We need to compute this before the cross entropy kernel modifies logits_chunk
114
- logits_for_softmax = logits_chunk.detach().clone() # Detach to avoid gradient flow
115
- if softcap is not None:
116
- logits_for_softmax = softcap * torch.tanh(logits_for_softmax / softcap)
117
-
118
- # Compute softmax to get predicted probabilities
119
- probs = torch.softmax(logits_for_softmax, dim=-1)
120
-
121
- # Get predicted probabilities for token scaling, handling ignored targets
122
- valid_target_mask = target_chunk != ignore_index
123
- valid_targets = target_chunk[valid_target_mask]
124
-
125
- if len(valid_targets) > 0:
126
- # Gather probabilities only for valid targets
127
- valid_probs = probs[valid_target_mask]
128
- pred_probs_valid = torch.gather(valid_probs, -1, valid_targets.unsqueeze(-1)).squeeze(-1)
129
-
130
- # Create full tensor with zeros for ignored targets
131
- pred_probs = torch.zeros_like(target_chunk, dtype=probs.dtype, device=probs.device)
132
- pred_probs[valid_target_mask] = pred_probs_valid
133
- else:
134
- # All targets are ignored
135
- pred_probs = torch.zeros_like(target_chunk, dtype=probs.dtype, device=probs.device)
136
-
137
- # Store the scaling factors
138
- scaling_factors = pred_probs.detach() # Detach to ensure no gradient flow
139
-
140
- # unreduced loss
141
- loss_1d_slice = loss_1d[start_idx:end_idx] # chunk_size,
142
- z_loss_1d_slice = z_loss_1d[start_idx:end_idx] if return_z_loss else None
143
- token_accuracy_1d_slice = token_accuracy_1d[start_idx:end_idx] if return_token_accuracy else None
144
- predicted_tokens_1d_slice = predicted_tokens_1d[start_idx:end_idx] if return_predicted_tokens else None
145
-
146
- # ensure _input and target are contiguous
147
- logits_chunk = logits_chunk.contiguous()
148
- target_chunk = target_chunk.contiguous()
149
-
150
- # Here we calculate the gradient of logits_chunk in place so we can save memory.
151
- liger_cross_entropy_kernel[(n_rows,)](
152
- X_ptr=logits_chunk,
153
- X_stride=logits_chunk.stride(-2),
154
- Y_ptr=target_chunk,
155
- Y_stride=target_chunk.stride(-1), # always 1
156
- weight_ptr=ce_weight,
157
- loss_ptr=loss_1d_slice,
158
- z_loss_ptr=z_loss_1d_slice,
159
- loss_stride=loss_1d_slice.stride(-1), # always 1
160
- token_accuracy_ptr=token_accuracy_1d_slice,
161
- token_accuracy_stride=token_accuracy_1d_slice.stride(-1)
162
- if return_token_accuracy
163
- else 0, # always 1 if accuracy is enabled
164
- predicted_tokens_ptr=predicted_tokens_1d_slice,
165
- predicted_tokens_stride=predicted_tokens_1d_slice.stride(-1)
166
- if return_predicted_tokens
167
- else 0, # always 1 if predicted tokens is enabled
168
- n_cols=V,
169
- n_non_ignore=total_n_non_ignore,
170
- sum_non_ignore_weight=total_sum_non_ignore_ce_weight,
171
- weight_sum=ce_weight_sum,
172
- ignore_index=ignore_index,
173
- lse_square_scale=lse_square_scale,
174
- label_smoothing=label_smoothing,
175
- reduction=reduction,
176
- softcap=softcap,
177
- RETURN_Z_LOSS=return_z_loss,
178
- RETURN_TOKEN_ACCURACY=return_token_accuracy,
179
- RETURN_PREDICTED_TOKENS=return_predicted_tokens,
180
- HAS_WEIGHT=True if ce_weight is not None else False,
181
- HAS_SOFTCAPPING=True if softcap is not None else False,
182
- HAS_GRADIENTS=input_requires_grad,
183
- BLOCK_SIZE=BLOCK_SIZE,
184
- num_warps=32 if not is_hip() else 16,
185
- )
186
-
187
- # Apply token scaling if requested
188
- if use_token_scaling:
189
- loss_1d_slice = loss_1d_slice * scaling_factors
190
- if return_z_loss:
191
- z_loss_1d_slice = z_loss_1d_slice * scaling_factors
192
-
193
- loss_1d[start_idx:end_idx] = loss_1d_slice
194
- if return_z_loss:
195
- z_loss_1d[start_idx:end_idx] = z_loss_1d_slice
196
- if return_token_accuracy:
197
- token_accuracy_1d[start_idx:end_idx] = token_accuracy_1d_slice
198
- if return_predicted_tokens:
199
- predicted_tokens_1d[start_idx:end_idx] = predicted_tokens_1d_slice
200
- grad_logits_chunk = logits_chunk # chunk_size x V
201
-
202
- # Apply token scaling to gradients if requested
203
- if use_token_scaling:
204
- # Expand scaling factors to match gradient dimensions
205
- scaling_factors_expanded = scaling_factors.unsqueeze(-1) # chunk_size x 1
206
- grad_logits_chunk = grad_logits_chunk * scaling_factors_expanded
207
-
208
- if input_requires_grad:
209
- grad_input[start_idx:end_idx] = grad_logits_chunk @ weight
210
-
211
- if grad_weight is not None and input_requires_grad:
212
- grad_weight += torch.mm(grad_logits_chunk.t(), _input_chunk).float()
213
-
214
- if bias is not None and input_requires_grad:
215
- torch.add(
216
- input=grad_bias,
217
- other=grad_logits_chunk.sum(dim=0),
218
- out=grad_bias,
219
- alpha=1.0,
220
- )
221
-
222
- # Need extra calculations for backward if reduction=='none'. Not supporting reduction='none' now.
223
- # if reduction == "none":
224
- # loss = loss_1d
225
- # z_loss = z_loss_1d if return_z_loss else None
226
-
227
- if reduction == "none":
228
- # Return per-token losses
229
- loss = loss_1d
230
- z_loss = z_loss_1d if return_z_loss else None
231
- token_accuracy = token_accuracy_1d if return_token_accuracy else None
232
- else:
233
- loss = torch.sum(loss_1d)
234
- z_loss = torch.sum(z_loss_1d) if return_z_loss else None
235
- # For accuracy, we compute the mean across all non-ignored tokens
236
- token_accuracy = torch.sum(token_accuracy_1d) / total_n_non_ignore if return_token_accuracy else None
237
-
238
- predicted_tokens = predicted_tokens_1d if return_predicted_tokens else None
239
-
240
- # Cast back to original dtype
241
- grad_weight = grad_weight.to(weight.dtype) if grad_weight is not None else None
242
- grad_bias = grad_bias.to(bias.dtype) if grad_bias is not None else None
243
-
244
- return loss, z_loss, token_accuracy, predicted_tokens, grad_input, grad_weight, grad_bias
245
-
246
-
247
- def fused_linear_cross_entropy_backward(grad_output, grad_input, grad_weight, grad_bias):
248
- # If cross entropy is the last layer, grad_output is 1.0. Skip the mul to save time
249
- if not torch.equal(grad_output, torch.tensor(1.0, device=grad_output.device)):
250
- # We use a Triton kernel instead of a PyTorch operation because modifying inputs in-place
251
- # for gradient storage and backward multiple times causes anomalies with PyTorch but not with Triton.
252
- BT, H = grad_input.shape
253
- n_rows = BT
254
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(H))
255
-
256
- element_mul_kernel[(n_rows,)](
257
- grad_input,
258
- grad_input.stride(-2),
259
- grad_output,
260
- H,
261
- BLOCK_SIZE=BLOCK_SIZE,
262
- num_warps=32 if not is_hip() else 16,
263
- )
264
-
265
- # handle grad_weight
266
- if grad_weight is not None:
267
- V, H = grad_weight.shape
268
- n_rows = V
269
-
270
- element_mul_kernel[(n_rows,)](
271
- grad_weight,
272
- grad_weight.stride(-2),
273
- grad_output,
274
- H,
275
- BLOCK_SIZE=BLOCK_SIZE,
276
- num_warps=32 if not is_hip() else 16,
277
- )
278
-
279
- if grad_bias is not None:
280
- V = grad_bias.shape[0]
281
- n_rows = V
282
-
283
- element_mul_kernel[(n_rows,)](
284
- grad_bias,
285
- grad_bias.stride(-1),
286
- grad_output,
287
- 1,
288
- BLOCK_SIZE=BLOCK_SIZE,
289
- num_warps=32 if not is_hip() else 16,
290
- )
291
- return grad_input, grad_weight, grad_bias
292
-
293
-
294
- class LigerFusedLinearCrossEntropyFunction(torch.autograd.Function):
295
- @staticmethod
296
- @amp_custom_fwd
297
- def forward(
298
- ctx,
299
- _input,
300
- weight,
301
- target,
302
- bias=None,
303
- ce_weight=None,
304
- ignore_index=-100,
305
- lse_square_scale=0.0,
306
- label_smoothing=0.0,
307
- reduction="mean",
308
- softcap=None,
309
- return_z_loss: bool = False,
310
- accum_dtype=None,
311
- use_token_scaling: bool = False,
312
- return_token_accuracy: bool = False,
313
- return_predicted_tokens: bool = False,
314
- ):
315
- """
316
- Fusing the last linear layer with cross-entropy loss
317
- Reference: https://github.com/mgmalek/efficient_cross_entropy
318
-
319
- Handle the forward and backward pass of the final linear layer via cross-entropy loss by avoiding
320
- the materialization of the large logits tensor. Since Cross Entropy Loss is the last layer, we can
321
- compute the gradient at the forward pass. By doing so, we don't have to store the _input and target
322
- for the backward pass.
323
-
324
- _input: (B*T, H) where B is batch size, T is sequence length, H is hidden dimension.
325
- target: (B*T) where each value is in [0, V-1]
326
- weight: (V, H) where V is the number of classes
327
- bias: (V) where V is the number of classes
328
- ce_weight: a manual rescaling weight given to each class. If given, has to be a Tensor of size V and floating point dtype
329
- ignore_index: the index to ignore in the target
330
- label_smoothing (float): The amount of smoothing when computing the loss, where 0.0 means no smoothing.
331
- reduction: reduction to apply
332
- accum_dtype (torch.dtype): the dtype of intermediate result buffers for weight and bias gradient accumulations.
333
- Recommended to set `accum_dtype` to higher precision, e.g. `torch.float32`, if the training is unstable with original dtype. Default: `None`, performing accumulations in original dtype
334
- use_token_scaling (bool): whether to scale each token's loss by its predicted probability (detached).
335
- When True, each token's loss is multiplied by the model's predicted probability for that token's true class.
336
- Default: False.
337
- return_token_accuracy (bool): When `return_token_accuracy` is `True`, computes and returns per-token accuracy without materializing logits. Default: `False`
338
- return_predicted_tokens (bool): When `return_predicted_tokens` is `True`, returns per-token predicted class indices (argmax) without materializing logits. Default: `False`
339
- """
340
-
341
- loss, z_loss, token_accuracy, predicted_tokens, grad_input, grad_weight, grad_bias = (
342
- fused_linear_cross_entropy_forward(
343
- _input=_input,
344
- weight=weight,
345
- target=target,
346
- bias=bias,
347
- ce_weight=ce_weight,
348
- ignore_index=ignore_index,
349
- lse_square_scale=lse_square_scale,
350
- label_smoothing=label_smoothing,
351
- reduction=reduction,
352
- softcap=softcap,
353
- return_z_loss=return_z_loss,
354
- accum_dtype=accum_dtype,
355
- use_token_scaling=use_token_scaling,
356
- return_token_accuracy=return_token_accuracy,
357
- return_predicted_tokens=return_predicted_tokens,
358
- )
359
- )
360
- # downcast to dtype and store for backward
361
- ctx.save_for_backward(
362
- grad_input.detach(),
363
- grad_weight.detach() if grad_weight is not None else None,
364
- grad_bias.detach() if grad_bias is not None else None,
365
- )
366
- ctx.return_z_loss = return_z_loss
367
- ctx.return_token_accuracy = return_token_accuracy
368
- ctx.return_predicted_tokens = return_predicted_tokens
369
- return loss, z_loss, token_accuracy, predicted_tokens
370
-
371
- @staticmethod
372
- @amp_custom_bwd
373
- def backward(ctx, grad_output, grad_output2, grad_output3, grad_output4):
374
- if ctx.return_z_loss:
375
- del grad_output2 # z_loss is only for logging
376
- if ctx.return_token_accuracy:
377
- del grad_output3 # token_accuracy is only for metrics
378
- if ctx.return_predicted_tokens:
379
- del grad_output4 # predicted_tokens is only for metrics
380
- (grad_input, grad_weight, grad_bias) = ctx.saved_tensors
381
- grad_input, grad_weight, grad_bias = fused_linear_cross_entropy_backward(
382
- grad_output, grad_input, grad_weight, grad_bias
383
- )
384
- return (
385
- grad_input,
386
- grad_weight,
387
- None,
388
- grad_bias,
389
- None,
390
- None,
391
- None,
392
- None,
393
- None,
394
- None,
395
- None,
396
- None,
397
- None, # use_token_scaling
398
- None, # return_token_accuracy
399
- None, # return_predicted_tokens
400
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/geglu.py DELETED
@@ -1,143 +0,0 @@
1
- import operator
2
-
3
- import torch
4
- import triton
5
- import triton.language as tl
6
-
7
- from .utils import calculate_settings
8
- from .utils import compare_version
9
- from .utils import ensure_contiguous
10
- from .utils import is_npu_available
11
-
12
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
13
- try:
14
- # typical import path with dispatch available
15
- from triton.language.extra.libdevice import tanh
16
- except ModuleNotFoundError:
17
- # for working with NGC containers
18
- from triton.language.extra.cuda.libdevice import tanh
19
- else:
20
- from triton.language.math import tanh
21
-
22
-
23
- @triton.jit
24
- def _geglu_tanh_forward_kernel(a, b, c, stride, n_cols: tl.constexpr, BLOCK_SIZE: tl.constexpr):
25
- program_id = tl.program_id(0).to(tl.int64)
26
-
27
- # locate start index
28
- a += program_id * stride
29
- b += program_id * stride
30
- c += program_id * stride
31
-
32
- col_offsets = tl.arange(0, BLOCK_SIZE)
33
- mask = col_offsets < n_cols
34
- a_row = tl.load(a + col_offsets, mask=mask, other=0).to(tl.float32)
35
- b_row = tl.load(b + col_offsets, mask=mask, other=0)
36
-
37
- # tanh approximation form of GELU is computed with:
38
- # 0.5 * a * (1 + tanh(sqrt(2 / pi) * (a + 0.044715 * a^3)))
39
- sqrt_2_over_pi = 0.7978845608028654 # sqrt(2 / pi)
40
- a_cubed = a_row * a_row * a_row
41
- tanh_arg = sqrt_2_over_pi * (a_row + 0.044715 * a_cubed)
42
- tanh_result = tanh(tanh_arg)
43
- geglu_a = 0.5 * a_row * (1 + tanh_result)
44
- c_row = geglu_a.cast(b_row.dtype) * b_row
45
- tl.store(c + col_offsets, c_row, mask=mask)
46
-
47
-
48
- @triton.jit
49
- def _geglu_tanh_backward_kernel(dc, a, b, stride, n_cols: tl.constexpr, BLOCK_SIZE: tl.constexpr):
50
- program_id = tl.program_id(0).to(tl.int64)
51
-
52
- # locate start index
53
- dc += program_id * stride
54
- a += program_id * stride
55
- b += program_id * stride
56
-
57
- col_offsets = tl.arange(0, BLOCK_SIZE)
58
- mask = col_offsets < n_cols
59
-
60
- dc_row = tl.load(dc + col_offsets, mask=mask, other=0)
61
- a_row = tl.load(a + col_offsets, mask=mask, other=0).to(tl.float32)
62
- b_row = tl.load(b + col_offsets, mask=mask, other=0)
63
-
64
- # recomputation to save memory
65
- sqrt_2_over_pi = 0.7978845608028654 # sqrt(2 / pi)
66
- a_cubed = a_row * a_row * a_row
67
- tanh_arg = sqrt_2_over_pi * (a_row + 0.044715 * a_cubed)
68
- tanh_result = tanh(tanh_arg)
69
- geglu_a = 0.5 * a_row * (1 + tanh_result)
70
- geglu_a = geglu_a.to(dc_row.dtype).to(tl.float32)
71
-
72
- db_row = dc_row.cast(tl.float32) * geglu_a
73
-
74
- # Gradient w.r.t. a can be computed with:
75
- # b * (0.5 * (1 + tanh(z)) + 0.5 * a * (1 - tanh(z)^2) * (sqrt(2/pi) * (1 + 3 * 0.044715 * a^2)))
76
- # where z = sqrt(2/pi) * (a + 0.044715 * a^3)
77
- term1 = 0.5 * (1 + tanh_result)
78
- tanh_sq = tanh_result * tanh_result
79
- term2 = 0.5 * a_row * (1 - tanh_sq) * (sqrt_2_over_pi * (1 + 3 * 0.044715 * a_row * a_row))
80
- da_row = dc_row * b_row * (term1 + term2)
81
-
82
- tl.store(a + col_offsets, da_row, mask=mask)
83
- tl.store(b + col_offsets, db_row.to(dc_row.dtype), mask=mask)
84
-
85
-
86
- def geglu_forward(a, b):
87
- ori_shape = a.shape
88
-
89
- n_cols = ori_shape[-1]
90
- a = a.view(-1, n_cols)
91
- b = b.view(-1, n_cols)
92
- c = torch.empty_like(a)
93
- n_rows = a.shape[0]
94
-
95
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
96
-
97
- _geglu_tanh_forward_kernel[(n_rows,)](
98
- a,
99
- b,
100
- c,
101
- c.stride(-2),
102
- n_cols=n_cols,
103
- BLOCK_SIZE=BLOCK_SIZE,
104
- num_warps=num_warps,
105
- )
106
- return a, b, c.view(*ori_shape)
107
-
108
-
109
- def geglu_backward(a, b, dc):
110
- ori_shape = dc.shape
111
- n_cols = ori_shape[-1]
112
- dc = dc.view(-1, n_cols)
113
- n_rows = dc.shape[0]
114
-
115
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
116
-
117
- _geglu_tanh_backward_kernel[(n_rows,)](
118
- dc,
119
- a,
120
- b,
121
- dc.stride(-2),
122
- n_cols=n_cols,
123
- BLOCK_SIZE=BLOCK_SIZE,
124
- num_warps=num_warps,
125
- )
126
-
127
- return a.view(*ori_shape), b.view(*ori_shape)
128
-
129
-
130
- class LigerGELUMulFunction(torch.autograd.Function):
131
- @staticmethod
132
- @ensure_contiguous
133
- def forward(ctx, a, b):
134
- a, b, c = geglu_forward(a, b)
135
- ctx.save_for_backward(a, b)
136
- return c
137
-
138
- @staticmethod
139
- @ensure_contiguous
140
- def backward(ctx, dc):
141
- a, b = ctx.saved_tensors
142
- a, b = geglu_backward(a, b, dc)
143
- return a, b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/group_norm.py DELETED
@@ -1,311 +0,0 @@
1
- import operator
2
-
3
- import torch
4
- import triton
5
- import triton.language as tl
6
-
7
- from .utils import compare_version
8
- from .utils import ensure_contiguous
9
- from .utils import infer_device
10
- from .utils import is_npu_available
11
-
12
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
13
- try:
14
- # typical import path with dispatch available
15
- from triton.language.extra.libdevice import rsqrt
16
- except ModuleNotFoundError:
17
- # for working with NGC containers
18
- from triton.language.extra.cuda.libdevice import rsqrt
19
- else:
20
- from triton.language.math import rsqrt
21
-
22
- if infer_device() == "npu":
23
- MAX_FUSED_SIZE = 16384 # 8192
24
- else:
25
- MAX_FUSED_SIZE = 65536
26
-
27
-
28
- @triton.jit
29
- def _group_norm_forward_kernel(
30
- Y_ptr, # pointer to output, shape (n_rows, n_groups, hidden_size)
31
- Y_row_stride, # stride of each row in output
32
- Y_col_stride, # stride of each column in output
33
- X_ptr, # pointer to input, shape (n_rows, n_groups, hidden_size)
34
- X_row_stride, # stride of each row in input
35
- X_col_stride, # stride of each column in input
36
- Mean_ptr, # pointer to mean, shape (n_rows, n_groups)
37
- Mean_row_stride, # stride of each row in mean
38
- Mean_col_stride, # stride of each column in mean
39
- RSTD_ptr, # pointer to rstd, shape (n_rows, n_groups)
40
- RSTD_row_stride, # stride of each row in rstd
41
- RSTD_col_stride, # stride of each column in rstd
42
- W_ptr, # pointer to W
43
- B_ptr, # pointer to B
44
- hidden_size, # hidden size of X
45
- channels_per_group, # the number of channels per group
46
- eps,
47
- BLOCK_SIZE: tl.constexpr,
48
- ):
49
- """
50
- References:
51
- https://nn.labml.ai/normalization/group_norm/index.html
52
- """
53
- batch_idx = tl.program_id(0)
54
- group_idx = tl.program_id(1)
55
-
56
- X_ptr += batch_idx * X_row_stride + group_idx * X_col_stride
57
- Y_ptr += batch_idx * Y_row_stride + group_idx * Y_col_stride
58
-
59
- block_range = tl.arange(0, BLOCK_SIZE)
60
-
61
- # Compute mean and variance using the online algorithm
62
- s = 0.0
63
- squared_sum = 0.0
64
- for i in tl.range(0, hidden_size, BLOCK_SIZE):
65
- hidden_size_offsets = i + block_range
66
- mask = hidden_size_offsets < hidden_size
67
- X = tl.load(X_ptr + hidden_size_offsets, mask=mask, other=0.0)
68
- s += tl.sum(X)
69
- # X**2
70
- squared_sum += tl.sum(X * X)
71
-
72
- m = s / hidden_size
73
-
74
- # variance = E[X**2] - E[X]**2
75
- variance = (squared_sum / hidden_size) - (m * m)
76
-
77
- # 1/std
78
- rstd = rsqrt(variance + eps)
79
-
80
- # Normalize — flat loop over full hidden_size (not per-channel)
81
- # This avoids the nested channel × per_channel_hidden loop where
82
- # BLOCK_SIZE >> hidden_size_per_channel causes massive padding waste.
83
- hidden_size_per_channel = hidden_size // channels_per_group
84
- for i in tl.range(0, hidden_size, BLOCK_SIZE):
85
- hidden_size_offsets = i + block_range
86
- mask = hidden_size_offsets < hidden_size
87
- X = tl.load(X_ptr + hidden_size_offsets, mask=mask, other=m)
88
- # Determine which channel each element belongs to, then load W/B
89
- local_channel = hidden_size_offsets // hidden_size_per_channel
90
- global_channel = group_idx * channels_per_group + local_channel
91
- W = tl.load(W_ptr + global_channel, mask=mask)
92
- B = tl.load(B_ptr + global_channel, mask=mask)
93
- Y = (X - m) * rstd * W + B
94
- tl.store(Y_ptr + hidden_size_offsets, Y, mask=mask)
95
-
96
- tl.store(Mean_ptr + batch_idx * Mean_row_stride + group_idx * Mean_col_stride, m)
97
- tl.store(RSTD_ptr + batch_idx * RSTD_row_stride + group_idx * RSTD_col_stride, rstd)
98
-
99
-
100
- @triton.jit
101
- def _group_norm_backward_kernel(
102
- X_ptr, # pointer to input, shape (n_rows, n_channels, hidden_size)
103
- X_row_stride, # stride of each row in input
104
- X_col_stride, # stride of each column in input
105
- W_ptr, # pointer to weights, shape (n_channels)
106
- Mean_ptr, # pointer to mean, shape (n_rows, n_groups)
107
- Mean_ptr_row_stride, # stride of each column in mean
108
- Mean_ptr_col_stride, # stride of each column in mean
109
- RSTD_ptr, # pointer to rstd, shape (n_rows, n_groups)
110
- DX_ptr, # pointer to input grad, shape (n_rows, n_groups, hidden_size)
111
- DW_ptr, # pointer to weights grad, shape (n_channels)
112
- DB_ptr, # pointer to bias grad, shape (n_channels)
113
- UPSTREAM_ptr, # pointer to output grad, shape (n_rows, n_channels, hidden_size)
114
- hidden_size: tl.constexpr, # hidden size
115
- channels_per_group: tl.constexpr, # number of groups in group norm
116
- BLOCK_SIZE: tl.constexpr,
117
- dtype: tl.constexpr,
118
- ):
119
- """
120
- References:
121
- https://nn.labml.ai/normalization/group_norm/index.html
122
- https://github.com/karpathy/llm.c/blob/master/doc/layernorm/layernorm.md
123
-
124
- The backprop equations are the same for group_norm and layer_norm
125
- the only difference here is that we load the Mean, Rstd corresponding to the
126
- group we're computing gradients for and the mean and rstd are computed over n-channels
127
- so the total number of elements we compute the mean over is num_channels_per_group * hidden_size
128
-
129
- We also need to load the Weights corresponding to the current channel to compute the gradients.
130
- """
131
- batch_idx = tl.program_id(0)
132
- group_idx = tl.program_id(1)
133
-
134
- # Move the pointers to the correct batch
135
- X_ptr += batch_idx * X_row_stride
136
- DX_ptr += batch_idx * X_row_stride
137
- UPSTREAM_ptr += batch_idx * X_row_stride
138
-
139
- # Mean and rstd are the same shape so have the same strides
140
- mean = tl.load(Mean_ptr + batch_idx * Mean_ptr_row_stride + group_idx * Mean_ptr_col_stride)
141
- rstd = tl.load(RSTD_ptr + batch_idx * Mean_ptr_row_stride + group_idx * Mean_ptr_col_stride)
142
-
143
- c1 = 0.0
144
- c2 = 0.0
145
- block_range = tl.arange(0, BLOCK_SIZE)
146
-
147
- # We need to compute the sum terms of the backprop equations across all channels in the group
148
- for channel_idx in range(group_idx * channels_per_group, (group_idx + 1) * channels_per_group):
149
- dW = 0.0
150
- dB = 0.0
151
- # Move the pointers to the correct channel
152
- W = tl.load(W_ptr + channel_idx)
153
- for i in tl.range(0, hidden_size, BLOCK_SIZE):
154
- hidden_size_offsets = i + block_range
155
- mask = hidden_size_offsets < hidden_size
156
- X = tl.load(
157
- X_ptr + channel_idx * X_col_stride + hidden_size_offsets,
158
- mask=mask,
159
- other=0.0,
160
- )
161
- UPSTREAM_grad = tl.load(
162
- UPSTREAM_ptr + channel_idx * X_col_stride + hidden_size_offsets,
163
- mask=mask,
164
- other=0.0,
165
- )
166
-
167
- x_hat = (X - mean) * rstd
168
- dW += tl.sum(UPSTREAM_grad * x_hat)
169
- dB += tl.sum(UPSTREAM_grad)
170
-
171
- wdy = W * UPSTREAM_grad
172
- c1 += tl.sum(x_hat * wdy)
173
- c2 += tl.sum(wdy)
174
-
175
- # Need to ensure additions to the same channel are atomic
176
- tl.atomic_add(DW_ptr + channel_idx, dW.to(dtype))
177
- tl.atomic_add(DB_ptr + channel_idx, dB.to(dtype))
178
-
179
- N = hidden_size * channels_per_group
180
- c1 = c1 / N
181
- c2 = c2 / N
182
-
183
- for channel_idx in tl.range(group_idx * channels_per_group, (group_idx + 1) * channels_per_group):
184
- # Move the pointers to the correct channel
185
- W = tl.load(W_ptr + channel_idx)
186
- for i in range(0, hidden_size, BLOCK_SIZE):
187
- hidden_size_offsets = i + block_range
188
- mask = hidden_size_offsets < hidden_size
189
- X = tl.load(
190
- X_ptr + channel_idx * X_col_stride + hidden_size_offsets,
191
- mask=mask,
192
- other=0.0,
193
- )
194
- UPSTREAM_grad = tl.load(
195
- UPSTREAM_ptr + channel_idx * X_col_stride + hidden_size_offsets,
196
- mask=mask,
197
- other=0.0,
198
- )
199
-
200
- x_hat = (X - mean) * rstd
201
- wdy = W * UPSTREAM_grad
202
- dx = (wdy - (x_hat * c1 + c2)) * rstd
203
- tl.store(DX_ptr + channel_idx * X_col_stride + hidden_size_offsets, dx, mask=mask)
204
-
205
-
206
- def group_norm_forward(X, num_channels, num_groups, W, B, eps):
207
- shape = X.shape
208
- batch_size = shape[0]
209
- channels_per_group = num_channels // num_groups
210
- # Reshape X so that the mean and std are computed across the groups
211
- X = X.view(batch_size, num_groups, -1).contiguous()
212
- hidden_size = X.shape[-1]
213
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(hidden_size))
214
- Y = torch.empty((batch_size, num_groups, hidden_size), dtype=X.dtype, device=X.device)
215
- Mean = torch.zeros((batch_size, num_groups), dtype=X.dtype, device=X.device)
216
- RSTD = torch.zeros((batch_size, num_groups), dtype=X.dtype, device=X.device)
217
-
218
- _group_norm_forward_kernel[(batch_size, num_groups)](
219
- Y,
220
- Y.stride(0),
221
- Y.stride(1),
222
- X,
223
- X.stride(0),
224
- X.stride(1),
225
- Mean,
226
- Mean.stride(0),
227
- Mean.stride(1),
228
- RSTD,
229
- RSTD.stride(0),
230
- RSTD.stride(1),
231
- W,
232
- B,
233
- hidden_size,
234
- channels_per_group,
235
- eps,
236
- BLOCK_SIZE=BLOCK_SIZE,
237
- )
238
- # Return tensors in the original shape
239
- return Y.view(*shape), X.view(*shape), Mean, RSTD, BLOCK_SIZE
240
-
241
-
242
- def group_norm_backward(dY, X, W, B, Mean, RSTD, num_channels, num_groups):
243
- shape = dY.shape
244
- batch_size = shape[0]
245
- hidden_size = dY.shape[-1]
246
- channels_per_group = num_channels // num_groups
247
- dY = dY.view(batch_size, num_groups, -1)
248
- DX = torch.empty(
249
- (batch_size, num_groups, hidden_size * channels_per_group),
250
- dtype=X.dtype,
251
- device=X.device,
252
- )
253
- DW = torch.zeros((num_channels), dtype=W.dtype, device=W.device)
254
- DB = torch.zeros((num_channels), dtype=B.dtype, device=B.device)
255
- triton_dtype = tl.float32 if X.dtype == torch.float32 else tl.bfloat16
256
-
257
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(hidden_size))
258
- _group_norm_backward_kernel[(batch_size, num_groups)](
259
- X,
260
- X.stride(0),
261
- X.stride(1),
262
- W,
263
- Mean,
264
- Mean.stride(0),
265
- Mean.stride(1),
266
- RSTD,
267
- DX,
268
- DW,
269
- DB,
270
- dY,
271
- hidden_size,
272
- channels_per_group,
273
- BLOCK_SIZE=BLOCK_SIZE,
274
- dtype=triton_dtype,
275
- )
276
-
277
- # Return tensors in the original shape
278
- return DX.view(*shape), DW, DB
279
-
280
-
281
- class LigerGroupNormFunction(torch.autograd.Function):
282
- @staticmethod
283
- @ensure_contiguous
284
- def forward(
285
- ctx,
286
- X,
287
- affine_scaling_weight,
288
- affine_shifting_bias,
289
- num_channels,
290
- num_groups,
291
- eps,
292
- ):
293
- Y, X, Mean, RSTD, BLOCK_SIZE = group_norm_forward(
294
- X,
295
- num_channels,
296
- num_groups,
297
- affine_scaling_weight,
298
- affine_shifting_bias,
299
- eps,
300
- )
301
- ctx.num_channels = num_channels
302
- ctx.num_groups = num_groups
303
- ctx.save_for_backward(X, affine_scaling_weight, affine_shifting_bias, Mean, RSTD)
304
- return Y
305
-
306
- @staticmethod
307
- @ensure_contiguous
308
- def backward(ctx, dY):
309
- X, W, B, Mean, RSTD = ctx.saved_tensors
310
- DX, DW, DB = group_norm_backward(dY, X, W, B, Mean, RSTD, ctx.num_channels, ctx.num_groups)
311
- return DX, DW, DB, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/jsd.py DELETED
@@ -1,201 +0,0 @@
1
- from typing import Optional
2
-
3
- import torch
4
- import triton
5
- import triton.language as tl
6
-
7
- from .utils import ensure_contiguous
8
- from .utils import infer_device
9
-
10
-
11
- @triton.jit
12
- def _jsd_kernel(
13
- X_ptr, # input in logspace, X = log Q
14
- X_stride,
15
- Y_ptr, # ground truth in logspace, Y = log P
16
- Y_stride,
17
- loss_ptr,
18
- loss_stride,
19
- dX_ptr,
20
- dX_stride,
21
- label_ptr,
22
- beta: tl.constexpr,
23
- n_non_ignore: int,
24
- ignore_index: tl.constexpr,
25
- n_cols,
26
- BLOCK_SIZE: tl.constexpr,
27
- HAS_LABEL: tl.constexpr,
28
- ):
29
- # JSD(P || Q) = (KL(P || M) + KL(Q || M)) / 2, M = (1/2) * (P + Q) = (1/2) * (e ^ Y + e ^ X)
30
- # = sum(P * log P + Q * log Q - 2 * M * log M) / 2
31
- # = sum(e ^ Y * Y + e ^ X * X - 2 * M * log M) / 2
32
- # grad_x_i = 0.5 * Q * (X - log_M)
33
- pid = tl.program_id(0).to(tl.int64)
34
- X_ptr += pid * X_stride
35
- dX_ptr += pid * dX_stride
36
- Y_ptr += pid * Y_stride
37
- loss_ptr += pid * loss_stride
38
- label_ptr += pid
39
-
40
- if HAS_LABEL:
41
- label = tl.load(label_ptr)
42
- if label == ignore_index:
43
- for i in range(0, n_cols, BLOCK_SIZE):
44
- offsets = i + tl.arange(0, BLOCK_SIZE)
45
- tl.store(dX_ptr + offsets, 0.0, mask=offsets < n_cols)
46
- return
47
-
48
- for i in range(0, n_cols, BLOCK_SIZE):
49
- offsets = i + tl.arange(0, BLOCK_SIZE)
50
- mask = offsets < n_cols
51
- X = tl.load(X_ptr + offsets, mask=mask, other=float("-inf")).to(tl.float32)
52
- Y = tl.load(Y_ptr + offsets, mask=mask, other=float("-inf")).to(tl.float32)
53
-
54
- if beta == 0.0: # forward KL
55
- Y_max = tl.max(Y, axis=0)
56
- Y_shifted = Y - Y_max
57
- Y_prob = tl.exp(Y_shifted) * tl.exp(Y_max) # Compensate for the shift
58
- loss = Y_prob * (Y - X)
59
- dX = -Y_prob
60
- elif beta == 1.0: # reverse KL
61
- X_max = tl.max(X, axis=0)
62
- X_shifted = X - X_max
63
- X_prob = tl.exp(X_shifted) * tl.exp(X_max) # Compensate for the shift
64
- loss = X_prob * (X - Y)
65
- dX = loss + X_prob
66
- else:
67
- max_val = tl.maximum(tl.max(X, axis=0), tl.max(Y, axis=0))
68
- X_shifted = X - max_val
69
- Y_shifted = Y - max_val
70
-
71
- # Pre-compute exp(max_val) since it's used twice
72
- exp_max = tl.exp(max_val)
73
-
74
- # Compute exp terms with compensation
75
- Q = tl.exp(X_shifted) * exp_max # = exp(X)
76
- P = tl.exp(Y_shifted) * exp_max # = exp(Y)
77
-
78
- # Pre-compute common terms
79
- beta_P = beta * P
80
- one_minus_beta_Q = (1 - beta) * Q
81
- M = beta_P + one_minus_beta_Q
82
- log_M = tl.log(M) # No need to compensate as M is already in original scale
83
-
84
- loss = beta_P * Y + one_minus_beta_Q * X - M * log_M
85
- dX = one_minus_beta_Q * (X - log_M)
86
-
87
- # Pre-compute scaling factor
88
- scale = 1.0 / n_non_ignore
89
- loss = loss * scale
90
- dX = dX * scale
91
-
92
- tl.store(loss_ptr + offsets, loss, mask=mask)
93
- tl.store(dX_ptr + offsets, dX, mask=mask)
94
-
95
-
96
- MAX_FUSED_SIZE = 4096 if infer_device() == "xpu" else 65536
97
-
98
-
99
- def jsd_forward(_input, target, shift_labels, beta, ignore_index, has_label):
100
- BT, V = _input.shape
101
- n_rows = BT
102
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
103
- # non reduction loss
104
- loss = torch.zeros(_input.shape, dtype=torch.float32, device=_input.device)
105
- dX = torch.empty_like(_input)
106
-
107
- if has_label:
108
- n_non_ignore = (shift_labels != ignore_index).sum().item()
109
- else:
110
- n_non_ignore = BT
111
-
112
- _jsd_kernel[(n_rows,)](
113
- X_ptr=_input, # input in logspace, X = log Q
114
- X_stride=_input.stride(-2),
115
- Y_ptr=target, # ground truth in logspace, Y = log P
116
- Y_stride=target.stride(-2),
117
- loss_ptr=loss,
118
- loss_stride=loss.stride(-2),
119
- dX_ptr=dX,
120
- dX_stride=dX.stride(-2),
121
- label_ptr=(shift_labels if has_label else torch.empty(1, device=_input.device)), # dummy ptr if no label
122
- beta=beta,
123
- n_non_ignore=n_non_ignore,
124
- ignore_index=ignore_index,
125
- n_cols=V,
126
- BLOCK_SIZE=BLOCK_SIZE,
127
- HAS_LABEL=has_label,
128
- )
129
-
130
- loss = torch.sum(loss)
131
- return loss.to(_input.dtype), dX
132
-
133
-
134
- def jsd_backward(dX, grad_output):
135
- # If jsd is the last layer, grad_output is 1.0. Skip the mul to save time
136
- if torch.equal(grad_output, torch.tensor(1.0, device=grad_output.device)):
137
- return dX
138
- else:
139
- return grad_output * dX
140
-
141
-
142
- class LigerJSDFunction(torch.autograd.Function):
143
- r"""
144
- This class implements the forward and backward pass for the generalized Jensen-Shannon Divergence.
145
- .. math::
146
- JSD(\beta)(P || Q)
147
- = \beta * KLDiv(P || (\beta * P + (1 - \beta) * Q)) + (1 - \beta) * KLDiv(Q || (\beta * P + (1 - \beta) * Q))
148
-
149
- .. note::
150
- As all the other losses in PyTorch, this function expects the first argument,
151
- :attr:`_input`, to be the predictions, the output of the student model, in log-space
152
- and the second, :attr:`target`, to be the observations, the output of the teacher model, in log-space.
153
- This differs from the standard mathematical notation :math:`JSD(P || Q)` where
154
- :math:`P` denotes the teacher model and :math:`Q` denotes the student model.
155
- """
156
-
157
- @staticmethod
158
- @ensure_contiguous
159
- def forward(
160
- ctx,
161
- _input: torch.Tensor,
162
- target: torch.Tensor,
163
- shift_labels: Optional[torch.Tensor] = None,
164
- beta: float = 0.5,
165
- ignore_index: int = -100,
166
- ) -> torch.Tensor:
167
- """
168
- Args:
169
- _input (torch.Tensor): predict values with shape (BT, V) in logspace
170
- target (torch.Tensor): ground truth values with shape (BT, V) in logspace
171
- shift_labels (Optional[torch.LongTensor]): indicator of next predicted vocab with shape (BT) where each value is in [0, V-1].
172
- beta (float): coefficient beta of generalized JSD in the interval [0, 1]. It implements forward/reverse KL when beta equals 0 and 1 respectively. Default: `0.5`
173
- ignore_index (int): the index to ignore. Default: -100
174
-
175
- Returns:
176
- loss (torch.Tensor): generalized JSD
177
- """
178
- has_label = False
179
- if shift_labels is not None:
180
- assert shift_labels.shape == (_input.shape[0],), (
181
- f"the shape of shift_labels must be (BT,). Got: {shift_labels.shape}"
182
- )
183
- shift_labels = shift_labels.contiguous()
184
- has_label = True
185
-
186
- loss, dX = jsd_forward(_input, target, shift_labels, beta, ignore_index, has_label)
187
- ctx.save_for_backward(dX)
188
- return loss
189
-
190
- @staticmethod
191
- @ensure_contiguous
192
- def backward(ctx, grad_output: torch.Tensor) -> torch.Tensor:
193
- (dX,) = ctx.saved_tensors
194
- dX = jsd_backward(dX, grad_output)
195
- return (
196
- dX,
197
- None,
198
- None,
199
- None,
200
- None,
201
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/kl_div.py DELETED
@@ -1,259 +0,0 @@
1
- from typing import Literal
2
-
3
- import torch
4
- import triton
5
- import triton.language as tl
6
-
7
- from .utils import ensure_contiguous
8
- from .utils import is_hip
9
- from .utils import infer_device
10
-
11
-
12
- def get_num_warps(BLOCK_SIZE):
13
- num_warps = 4
14
- if BLOCK_SIZE >= 32768:
15
- num_warps = 32 if not is_hip() else 16
16
- elif BLOCK_SIZE >= 8192:
17
- num_warps = 16
18
- elif BLOCK_SIZE >= 2048:
19
- num_warps = 8
20
-
21
- return num_warps
22
-
23
-
24
- if infer_device() == "xpu":
25
- MAX_FUSED_SIZE = 8192
26
- elif infer_device() == "npu":
27
- MAX_FUSED_SIZE = 8192
28
- else:
29
- MAX_FUSED_SIZE = 65536 // 4 # 65536 // 4 or 8 works the best
30
-
31
- REDUCTION_LITERAL = Literal["none", "sum", "mean", "batchmean"]
32
-
33
- _REDUCTION_MODE_NONE: tl.constexpr = tl.constexpr(0)
34
- _REDUCTION_MODE_SUM: tl.constexpr = tl.constexpr(1)
35
- _REDUCTION_MODE_MEAN: tl.constexpr = tl.constexpr(2)
36
- _REDUCTION_MODE_BATCHMEAN: tl.constexpr = tl.constexpr(3)
37
-
38
- _str_to_reduction_mode = {
39
- "none": _REDUCTION_MODE_NONE.value,
40
- "sum": _REDUCTION_MODE_SUM.value,
41
- "mean": _REDUCTION_MODE_MEAN.value,
42
- "batchmean": _REDUCTION_MODE_BATCHMEAN.value,
43
- }
44
-
45
-
46
- @triton.jit
47
- def _kldiv_kernel_forward(
48
- y_ptr, # [B, S], prediction ptr, the kernel expects the prediction in log-space
49
- y_stride, # int, prediction stride
50
- gt_ptr, # [B, S], ground truth ptr
51
- gt_stride, # int, ground truth stride
52
- loss_ptr, # [B] or [B, S] if reduction == _REDUCTION_MODE_NONE, output ptr
53
- loss_stride, # int, output stride
54
- n_cols, # int, number of columns in the input tensor
55
- eps,
56
- BLOCK_SIZE: tl.constexpr,
57
- log_target: tl.constexpr = False,
58
- reduction: tl.constexpr = _REDUCTION_MODE_BATCHMEAN,
59
- ):
60
- pid = tl.program_id(0).to(tl.int64)
61
- y_ptr += pid * y_stride
62
- gt_ptr += pid * gt_stride
63
- loss_ptr += pid * loss_stride
64
-
65
- base_offsets = tl.arange(0, BLOCK_SIZE)
66
-
67
- loss_sum = 0.0
68
- for i in range(0, n_cols, BLOCK_SIZE):
69
- offsets = i + base_offsets
70
- mask = offsets < n_cols
71
- y = tl.load(y_ptr + offsets, mask=mask, other=0.0)
72
- y_true = tl.load(gt_ptr + offsets, mask=mask, other=0.0)
73
-
74
- # KL(y_true || y) = y_true * (log(y_true) - log(y))
75
- # We compute KL(y_true || y) with y in the log-space
76
- if not log_target:
77
- loss = y_true * (tl.log(tl.maximum(y_true, eps)) - y)
78
- else:
79
- loss = tl.exp(y_true) * (y_true - y)
80
-
81
- if reduction == _REDUCTION_MODE_NONE:
82
- tl.store(loss_ptr + offsets, loss, mask=mask)
83
- else:
84
- loss_sum += tl.sum(loss, axis=0)
85
-
86
- if reduction != _REDUCTION_MODE_NONE:
87
- tl.store(loss_ptr, loss_sum)
88
-
89
-
90
- @triton.jit
91
- def _kldiv_kernel_backward(
92
- target_ptr,
93
- target_stride,
94
- new_grads_ptr,
95
- new_grads_stride,
96
- n_cols,
97
- BLOCK_SIZE: tl.constexpr,
98
- log_target: tl.constexpr = False,
99
- ):
100
- pid = tl.program_id(0).to(tl.int64)
101
-
102
- target_ptr += pid * target_stride
103
- new_grads_ptr += pid * new_grads_stride
104
-
105
- offsets = tl.arange(0, BLOCK_SIZE)
106
- mask = offsets < n_cols
107
-
108
- for i in range(0, n_cols, BLOCK_SIZE):
109
- offsets = i + tl.arange(0, BLOCK_SIZE)
110
- mask = offsets < n_cols
111
-
112
- target = tl.load(target_ptr + offsets, mask=mask, other=0.0)
113
-
114
- if not log_target:
115
- res = target * -1
116
- else:
117
- res = -tl.exp(target)
118
-
119
- tl.store(new_grads_ptr + offsets, res, mask=mask)
120
-
121
-
122
- def kldiv_forward_triton(y_pred, y_true, log_target, reduction, eps): # [BT, V]
123
- BT, V = y_pred.shape
124
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
125
- num_warps = 32 if infer_device() == "xpu" else get_num_warps(BLOCK_SIZE)
126
-
127
- grid = (BT,)
128
- reduction = _str_to_reduction_mode[reduction]
129
-
130
- out_size = (BT, V) if reduction == _REDUCTION_MODE_NONE.value else (BT,)
131
- output_tensor = torch.zeros(out_size, device=y_pred.device, dtype=torch.float32)
132
-
133
- _kldiv_kernel_forward[grid](
134
- y_pred,
135
- y_pred.stride(0),
136
- y_true,
137
- y_true.stride(0),
138
- output_tensor,
139
- output_tensor.stride(0),
140
- V,
141
- eps=eps,
142
- BLOCK_SIZE=BLOCK_SIZE,
143
- num_warps=num_warps,
144
- log_target=log_target,
145
- reduction=reduction,
146
- )
147
-
148
- # calculated according to the reduction mode same as in Pytorch. In the later versions, `mean` will be changed to the same behavior as `batchmean`
149
- # https://pytorch.org/docs/stable/generated/torch.nn.KLDivLoss.html
150
- # https://github.com/pytorch/pytorch/blob/d7b57c4d63edb42e1deeeba9497fcb5f1f748ff2/torch/nn/functional.py#L3372
151
- if reduction == _REDUCTION_MODE_BATCHMEAN.value:
152
- return output_tensor.sum() / BT
153
- elif reduction == _REDUCTION_MODE_SUM.value:
154
- return output_tensor.sum(dim=0)
155
- elif reduction == _REDUCTION_MODE_MEAN.value:
156
- return output_tensor.sum() / (BT * V)
157
- else:
158
- return output_tensor
159
-
160
-
161
- def kldiv_backward_triton(target, grad_output, new_grads, log_target):
162
- BT, V = target.shape
163
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
164
- num_warps = 32 if infer_device() == "xpu" else get_num_warps(BLOCK_SIZE)
165
-
166
- grid = (BT,)
167
-
168
- # We store the gradients in-place in the input tensor
169
- _kldiv_kernel_backward[grid](
170
- target,
171
- target.stride(0),
172
- new_grads,
173
- new_grads.stride(0),
174
- V,
175
- BLOCK_SIZE=BLOCK_SIZE,
176
- num_warps=num_warps,
177
- log_target=log_target,
178
- )
179
-
180
- # If cross entropy is the last layer, grad_output is 1.0. Skip the mul then.
181
- if torch.equal(grad_output, torch.tensor(1.0, device=grad_output.device)):
182
- return new_grads
183
-
184
- return new_grads * grad_output
185
-
186
-
187
- class LigerKLDivLossFunction(torch.autograd.Function):
188
- """
189
- Class implementing the forward and backward pass for the KL Divergence Loss using Triton, as defined by the following formula:
190
- ```python
191
- if log_target:
192
- loss = target.exp() * (target - input)
193
- else:
194
- loss = target * (target.log() - input)
195
- ```,
196
- then the loss is reduced according to the `reduction` parameter.
197
- as defined in the PyTorch documentation: https://pytorch.org/docs/stable/generated/torch.nn.KLDivLoss.html
198
- """
199
-
200
- @staticmethod
201
- @ensure_contiguous
202
- def forward(
203
- ctx,
204
- y_pred: torch.Tensor,
205
- y_true: torch.Tensor,
206
- reduction: REDUCTION_LITERAL = "batchmean",
207
- log_target: bool = False,
208
- eps: float = 1e-10,
209
- ) -> torch.Tensor:
210
- """A forward pass for the KL Divergence Loss.
211
-
212
- Args:
213
- ctx: Torch autograd context
214
- y_pred (torch.Tensor): A tensor of shape (BT, V) containing the predicted values, expected to be log-probabilities.
215
- y_true (torch.Tensor): A tensor of shape (BT, V) containing the target values, expected to be either probabilities or log-probabilities, depending on the value of `log_target`.
216
- reduction (REDUCTION_LITERAL, optional): Reduction to be used. Defaults to "batchmean".
217
- log_target (bool, optional): If set to true, expects the ground truth to already be log-probabilities. Defaults to False.
218
- eps: (float, optional): A small value to avoid division by zero. Defaults to 1e-10.
219
-
220
- Returns:
221
- torch.Tensor: The computed KL Divergence Loss, with shape (BT, V) if `reduction` is "none", else a scalar.
222
- """
223
- ctx.save_for_backward(y_true)
224
- ctx.reduction = reduction
225
- ctx.log_target = log_target
226
- return kldiv_forward_triton(y_pred, y_true, log_target=log_target, reduction=reduction, eps=eps)
227
-
228
- @staticmethod
229
- @ensure_contiguous
230
- def backward(ctx, grad_output: torch.Tensor) -> torch.Tensor:
231
- """A backward pass for the KL Divergence Loss.
232
-
233
- Args:
234
- ctx: Torch autograd context
235
- grad_output (torch.Tensor): The gradient of the loss with respect to the output.
236
-
237
- Returns:
238
- tuple[torch.Tensor, None, None, None, None]: The gradient of the loss with respect to the inputs and None for the other arguments of the forward method.
239
- """
240
- (y_true,) = ctx.saved_tensors
241
-
242
- new_grads = torch.empty_like(y_true)
243
-
244
- derivative = kldiv_backward_triton(y_true, grad_output, new_grads, ctx.log_target)
245
-
246
- if ctx.reduction == "batchmean":
247
- derivative = derivative / y_true.shape[0]
248
- elif ctx.reduction == "sum" or ctx.reduction == "none":
249
- pass
250
- elif ctx.reduction == "mean":
251
- derivative = derivative / (y_true.shape[0] * y_true.shape[1])
252
-
253
- return (
254
- derivative,
255
- None,
256
- None,
257
- None,
258
- None,
259
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/layer_norm.py DELETED
@@ -1,320 +0,0 @@
1
- import math
2
- import operator
3
-
4
- import torch
5
- import triton
6
- import triton.language as tl
7
-
8
- from .utils import calculate_settings
9
- from .utils import compare_version
10
- from .utils import ensure_contiguous
11
- from .utils import get_npu_core_count
12
- from .utils import set_large_grf_mode
13
- from .utils import is_npu_available
14
-
15
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
16
- try:
17
- # typical import path with dispatch available
18
- from triton.language.extra.libdevice import rsqrt
19
- except ModuleNotFoundError:
20
- # for working with NGC containers
21
- from triton.language.extra.cuda.libdevice import rsqrt
22
- else:
23
- from triton.language.math import rsqrt
24
-
25
-
26
- @triton.jit
27
- def _layer_norm_forward_kernel(
28
- Y_ptr, # pointer to output, shape (n_rows, n_cols)
29
- Y_row_stride, # stride of each row in output
30
- X_ptr, # pointer to input, shape (n_rows, n_cols)
31
- X_row_stride, # stride of each row in input
32
- W_ptr, # pointer to weights, shape (n_cols,)
33
- W_row_stride, # stride of each row in weights
34
- B_ptr, # pointer to bias, shape (n_cols,)
35
- B_row_stride, # stride of each row in bias
36
- Mean_ptr, # pointer to mean, shape (n_rows,)
37
- Mean_row_stride, # stride of each row in mean
38
- RSTD_ptr, # pointer to rstd, shape (n_rows,)
39
- RSTD_row_stride, # stride of each row in rstd
40
- n_cols,
41
- eps,
42
- BLOCK_SIZE: tl.constexpr,
43
- ):
44
- """
45
- References:
46
- https://arxiv.org/abs/1607.06450
47
- https://github.com/karpathy/llm.c/blob/master/doc/layernorm/layernorm.md
48
- """
49
- row_idx = tl.program_id(0).to(tl.int64)
50
- col_offsets = tl.arange(0, BLOCK_SIZE)
51
- mask = col_offsets < n_cols
52
-
53
- # Pre-load weights and bias in fp32 to avoid repeated conversions
54
- W_row = tl.load(W_ptr + col_offsets, mask=mask, other=0.0)
55
- B_row = tl.load(B_ptr + col_offsets, mask=mask, other=0.0)
56
- W_f32 = W_row.to(tl.float32)
57
- B_f32 = B_row.to(tl.float32)
58
-
59
- # Calculate pointers for this row
60
- row_X_ptr = X_ptr + row_idx * X_row_stride
61
- row_Y_ptr = Y_ptr + row_idx * Y_row_stride
62
- row_Mean_ptr = Mean_ptr + row_idx * Mean_row_stride
63
- row_RSTD_ptr = RSTD_ptr + row_idx * RSTD_row_stride
64
-
65
- # Load input data and convert to fp32 for numerical stability
66
- X_row = tl.load(row_X_ptr + col_offsets, mask=mask, other=0.0)
67
- X_f32 = X_row.to(tl.float32)
68
-
69
- # Compute statistics in fp32 for numerical stability
70
- mean = tl.sum(X_f32, axis=0) / n_cols
71
- X_centered = X_f32 - mean
72
- # Apply mask to variance calculation to exclude contributions from masked elements
73
- X_centered_masked = tl.where(mask, X_centered, 0.0)
74
- var = tl.sum(X_centered_masked * X_centered_masked, axis=0) / n_cols
75
- rstd = rsqrt(var + eps)
76
-
77
- # Store statistics (convert back to original dtype only once)
78
- tl.store(row_Mean_ptr, mean.to(X_row.dtype))
79
- tl.store(row_RSTD_ptr, rstd.to(X_row.dtype))
80
-
81
- # Fused normalization and affine transformation
82
- # Y = (X - mean) * rstd * W + B = X_centered * rstd * W + B
83
- Y_f32 = X_centered * rstd * W_f32 + B_f32
84
-
85
- # Store output (single conversion back to original dtype)
86
- tl.store(row_Y_ptr + col_offsets, Y_f32.to(X_row.dtype), mask=mask)
87
-
88
-
89
- @triton.jit
90
- def _layer_norm_backward_kernel(
91
- X_ptr, # pointer to input, shape (n_rows, n_cols)
92
- stride_x, # stride of each row in input
93
- W_ptr, # pointer to weights, shape (n_cols,)
94
- Mean_ptr, # pointer to mean, shape (n_rows,)
95
- stride_mean, # stride of each row in mean
96
- RSTD_ptr, # pointer to rstd, shape (n_rows,)
97
- stride_rstd, # stride of each row in rstd
98
- DX_ptr, # pointer to input grad, shape (n_rows, n_cols)
99
- stride_dx, # stride of each row in input grad
100
- DW_ptr, # pointer to weights grad, shape (n_cols,)
101
- stride_dw, # stride of each row in weights grad
102
- DB_ptr, # pointer to bias grad, shape (n_cols,)
103
- stride_db, # stride of each row in bias grad
104
- DY_ptr, # pointer to output grad, shape (n_rows, n_cols)
105
- stride_dy, # stride of each row in output grad
106
- n_rows,
107
- n_cols,
108
- rows_per_program: tl.constexpr,
109
- BLOCK_SIZE: tl.constexpr,
110
- ):
111
- """
112
- References:
113
- https://arxiv.org/abs/1607.06450
114
- https://github.com/karpathy/llm.c/blob/master/doc/layernorm/layernorm.md
115
- """
116
- row_block_id = tl.program_id(0).to(tl.int64)
117
- row_start = row_block_id * rows_per_program
118
- row_end = min((row_block_id + 1) * rows_per_program, n_rows)
119
- cols = tl.arange(0, BLOCK_SIZE)
120
- mask = cols < n_cols
121
-
122
- dW_row = tl.zeros((BLOCK_SIZE,), dtype=tl.float32)
123
- db_row = tl.zeros((BLOCK_SIZE,), dtype=tl.float32)
124
-
125
- # Pre-load weights once (same optimization as forward pass)
126
- w = tl.load(W_ptr + cols, mask=mask, other=0.0)
127
- w_f32 = w.to(tl.float32)
128
-
129
- for row_idx in range(row_start, row_end):
130
- # Calculate pointers for this specific row
131
- row_X_ptr = X_ptr + row_idx * stride_x
132
- row_DX_ptr = DX_ptr + row_idx * stride_dx
133
- row_DY_ptr = DY_ptr + row_idx * stride_dy
134
- row_Mean_ptr = Mean_ptr + row_idx * stride_mean
135
- row_RSTD_ptr = RSTD_ptr + row_idx * stride_rstd
136
-
137
- # Load data for this row
138
- x = tl.load(row_X_ptr + cols, mask=mask, other=0.0)
139
- dy = tl.load(row_DY_ptr + cols, mask=mask, other=0.0)
140
- mean = tl.load(row_Mean_ptr)
141
- rstd = tl.load(row_RSTD_ptr)
142
-
143
- # Convert to fp32 for numerical stability
144
- x_f32 = x.to(tl.float32)
145
- dy_f32 = dy.to(tl.float32)
146
- mean_f32 = mean.to(tl.float32)
147
- rstd_f32 = rstd.to(tl.float32)
148
-
149
- # Compute backward pass for this row
150
- x_hat = (x_f32 - mean_f32) * rstd_f32
151
- wdy = w_f32 * dy_f32
152
- c1 = tl.sum(x_hat * wdy, axis=0) / n_cols
153
- c2 = tl.sum(wdy, axis=0) / n_cols
154
- dx = (wdy - (x_hat * c1 + c2)) * rstd_f32
155
-
156
- # Store input gradient
157
- tl.store(row_DX_ptr + cols, dx, mask=mask)
158
-
159
- # Accumulate weight and bias gradients for this thread block's assigned rows
160
- dw = dy_f32 * x_hat
161
- db = dy_f32
162
- dW_row += dw
163
- db_row += db
164
-
165
- tl.store(DW_ptr + row_block_id * stride_dw + cols, dW_row, mask=mask)
166
- tl.store(DB_ptr + row_block_id * stride_db + cols, db_row, mask=mask)
167
-
168
-
169
- def layer_norm_forward(X, W, B, eps):
170
- """
171
- Args:
172
- X: Input tensor of shape (..., hidden_size)
173
- W: Weight tensor of shape (hidden_size,)
174
- B: Bias tensor of shape (hidden_size,)
175
- eps: Small constant for numerical stability
176
-
177
- Returns:
178
- Tuple of (output, input, mean, rstd, block_size, num_warps)
179
- """
180
- shape = X.shape
181
- dim = shape[-1]
182
- X = X.view(-1, dim)
183
- n_rows, n_cols = X.shape
184
-
185
- # Calculate optimal block size and warp configuration
186
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
187
-
188
- # Allocate output tensors
189
- Y = torch.empty((n_rows, n_cols), dtype=X.dtype, device=X.device)
190
- Mean = torch.empty(n_rows, dtype=X.dtype, device=X.device)
191
- RSTD = torch.empty(n_rows, dtype=X.dtype, device=X.device)
192
-
193
- # Validate input dimensions
194
- if X.shape[1] != W.shape[0]:
195
- raise ValueError(
196
- f"Incompatible dimensions: input feature size (X.shape[1]={X.shape[1]}) "
197
- f"must match weight size (W.shape[0]={W.shape[0]})"
198
- )
199
-
200
- # XPU-specific optimization
201
- kernel_args = {}
202
- if X.device.type == "xpu":
203
- set_large_grf_mode(kernel_args)
204
-
205
- # Launch kernel with one thread block per row for optimal performance
206
- grid = (n_rows,)
207
- _layer_norm_forward_kernel[grid](
208
- Y,
209
- Y.stride(0),
210
- X,
211
- X.stride(0),
212
- W,
213
- W.stride(0),
214
- B,
215
- B.stride(0),
216
- Mean,
217
- Mean.stride(0),
218
- RSTD,
219
- RSTD.stride(0),
220
- n_cols,
221
- eps,
222
- BLOCK_SIZE=BLOCK_SIZE,
223
- num_warps=num_warps,
224
- **kernel_args,
225
- )
226
-
227
- return Y.view(*shape), X, Mean, RSTD, BLOCK_SIZE, num_warps
228
-
229
-
230
- def layer_norm_backward(dY, X, W, B, Mean, RSTD):
231
- """
232
- Args:
233
- dY: Gradient of output
234
- X: Input tensor
235
- W: Weight tensor
236
- B: Bias tensor
237
- Mean: Pre-computed mean
238
- RSTD: Pre-computed reciprocal standard deviation
239
-
240
- Returns:
241
- Tuple of (input_grad, weight_grad, bias_grad)
242
- """
243
- shape = dY.shape
244
- dim = shape[-1]
245
- dY = dY.view(-1, dim)
246
- n_rows, n_cols = dY.shape
247
-
248
- sm_count = 1
249
- if X.device.type == "cuda":
250
- sm_count = torch.cuda.get_device_properties(X.device).multi_processor_count
251
- elif X.device.type == "xpu":
252
- sm_count = torch.xpu.get_device_properties(X.device).gpu_eu_count
253
- elif X.device.type == "npu":
254
- sm_count = get_npu_core_count()
255
-
256
- # fp32 for numerical stability especially.
257
- _DW = torch.empty((sm_count, n_cols), dtype=torch.float32, device=W.device)
258
- _DB = torch.empty((sm_count, n_cols), dtype=torch.float32, device=W.device)
259
-
260
- # Calculate optimal block size and warp configuration
261
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
262
- if n_cols > BLOCK_SIZE:
263
- raise RuntimeError(f"Feature dimension {n_cols} exceeds maximum supported size of {BLOCK_SIZE}.")
264
- rows_per_program = math.ceil(n_rows / sm_count)
265
- grid = (sm_count,)
266
-
267
- # Allocate gradient tensors
268
- DX = torch.empty((n_rows, n_cols), dtype=X.dtype, device=X.device)
269
-
270
- kernel_args = {"num_warps": num_warps}
271
- # XPU-specific optimization
272
- if X.device.type == "xpu":
273
- kernel_args.update({"num_warps": 32, "num_stages": 4})
274
- set_large_grf_mode(kernel_args)
275
-
276
- # Launch kernel with one thread block per row for optimal performance
277
- _layer_norm_backward_kernel[grid](
278
- X,
279
- X.stride(0),
280
- W,
281
- Mean,
282
- Mean.stride(0),
283
- RSTD,
284
- RSTD.stride(0),
285
- DX,
286
- DX.stride(0),
287
- _DW,
288
- _DW.stride(0),
289
- _DB,
290
- _DB.stride(0),
291
- dY,
292
- dY.stride(0),
293
- n_rows,
294
- n_cols,
295
- rows_per_program=rows_per_program,
296
- BLOCK_SIZE=BLOCK_SIZE,
297
- **kernel_args,
298
- )
299
-
300
- DX = DX.view(*shape)
301
- DW = _DW.sum(dim=0).to(W.dtype)
302
- DB = _DB.sum(dim=0).to(B.dtype)
303
-
304
- return DX, DW, DB
305
-
306
-
307
- class LigerLayerNormFunction(torch.autograd.Function):
308
- @staticmethod
309
- @ensure_contiguous
310
- def forward(ctx, X, W, B, eps):
311
- Y, X, Mean, RSTD, BLOCK_SIZE, num_warps = layer_norm_forward(X, W, B, eps)
312
- ctx.save_for_backward(X, W, B, Mean, RSTD)
313
- return Y
314
-
315
- @staticmethod
316
- @ensure_contiguous
317
- def backward(ctx, dY):
318
- X, W, B, Mean, RSTD = ctx.saved_tensors
319
- DX, DW, DB = layer_norm_backward(dY, X, W, B, Mean, RSTD)
320
- return DX, DW, DB, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/layers.py DELETED
@@ -1,514 +0,0 @@
1
- import inspect
2
- from dataclasses import dataclass
3
- from typing import Optional, Tuple
4
-
5
- import torch
6
- import torch.nn as nn
7
-
8
- from .cross_entropy import LigerCrossEntropyFunction
9
- from .dyt import LigerDyTFunction
10
- from .fused_linear_cross_entropy import LigerFusedLinearCrossEntropyFunction
11
- from .geglu import LigerGELUMulFunction
12
- from .group_norm import LigerGroupNormFunction
13
- from .jsd import LigerJSDFunction
14
- from .kl_div import LigerKLDivLossFunction
15
- from .layer_norm import LigerLayerNormFunction
16
- from .qwen2vl_mrope import LigerQwen2VLMRopeFunction
17
- from .rms_norm import LigerRMSNormFunction
18
- from .rope import LigerRopeFunction
19
- from .swiglu import LigerSiLUMulFunction
20
- from .tiled_mlp import apply_tiled_mlp
21
- from .tvd import LigerTVDLossFunction
22
-
23
-
24
- class LigerRMSNorm(nn.Module):
25
- def __init__(
26
- self,
27
- hidden_size: int,
28
- eps: float = 1e-6,
29
- offset: float = 0.0,
30
- casting_mode: str = "llama",
31
- init_fn: str = "ones",
32
- in_place: bool = True,
33
- row_mode: Optional[bool] = None,
34
- elementwise_affine: bool = True,
35
- ):
36
- super().__init__()
37
- assert init_fn in ("ones", "zeros"), f"init_fn must be 'ones' or 'zeros', got {init_fn}"
38
- self.hidden_size = hidden_size
39
- self.variance_epsilon = eps
40
- self.offset = offset
41
- self.casting_mode = casting_mode
42
- self.in_place = in_place
43
- self.row_mode = row_mode
44
- self.elementwise_affine = elementwise_affine
45
- if elementwise_affine:
46
- init = torch.ones(hidden_size) if init_fn == "ones" else torch.zeros(hidden_size)
47
- self.weight = nn.Parameter(init)
48
- else:
49
- self.register_parameter("weight", None)
50
-
51
- def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
52
- return LigerRMSNormFunction.apply(
53
- hidden_states,
54
- self.weight,
55
- self.variance_epsilon,
56
- self.offset,
57
- self.casting_mode,
58
- self.in_place,
59
- self.row_mode,
60
- )
61
-
62
- def extra_repr(self) -> str:
63
- return (
64
- f"{self.hidden_size}, eps={self.variance_epsilon}, offset={self.offset}, "
65
- f"in_place={self.in_place}, row_mode={self.row_mode}"
66
- )
67
-
68
-
69
- class LigerLayerNorm(nn.Module):
70
- def __init__(
71
- self,
72
- hidden_size: int,
73
- eps: float = 1e-6,
74
- bias: bool = False,
75
- init_fn: str = "ones",
76
- ):
77
- super().__init__()
78
- assert init_fn in ("ones", "zeros"), f"init_fn must be 'ones' or 'zeros', got {init_fn}"
79
- self.hidden_size = hidden_size
80
- self.variance_epsilon = eps
81
- self.weight = nn.Parameter(torch.ones(hidden_size) if init_fn == "ones" else torch.zeros(hidden_size))
82
- self.bias = nn.Parameter(torch.randn(hidden_size) if bias else torch.zeros(hidden_size))
83
-
84
- def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
85
- return LigerLayerNormFunction.apply(hidden_states, self.weight, self.bias, self.variance_epsilon)
86
-
87
- def extra_repr(self) -> str:
88
- return f"{self.hidden_size}, eps={self.variance_epsilon}"
89
-
90
-
91
- class LigerGroupNorm(nn.Module):
92
- def __init__(
93
- self,
94
- num_channels: int,
95
- num_groups: int,
96
- eps: float = 1e-6,
97
- bias: bool = False,
98
- init_fn: str = "ones",
99
- ):
100
- super().__init__()
101
- assert init_fn in ("ones", "zeros"), f"init_fn must be 'ones' or 'zeros', got {init_fn}"
102
- assert num_channels % num_groups == 0, (
103
- f"num_channels ({num_channels}) must be divisible by num_groups ({num_groups})"
104
- )
105
- self.num_channels = num_channels
106
- self.num_groups = num_groups
107
- self.variance_epsilon = eps
108
- self.weight = nn.Parameter(torch.ones(num_channels) if init_fn == "ones" else torch.zeros(num_channels))
109
- self.bias = nn.Parameter(torch.randn(num_channels) if bias else torch.zeros(num_channels))
110
-
111
- def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
112
- assert hidden_states.dim() >= 3, f"Input must have at least 3 dimensions, got {hidden_states.dim()}"
113
- assert hidden_states.size(1) == self.num_channels, (
114
- f"Input must have {self.num_channels} channels, got {hidden_states.size(1)}"
115
- )
116
- return LigerGroupNormFunction.apply(
117
- hidden_states,
118
- self.weight,
119
- self.bias,
120
- self.num_channels,
121
- self.num_groups,
122
- self.variance_epsilon,
123
- )
124
-
125
- def extra_repr(self) -> str:
126
- return f"num_channels={self.num_channels}, num_groups={self.num_groups}, eps={self.variance_epsilon}"
127
-
128
-
129
- class LigerDyT(nn.Module):
130
- def __init__(self, hidden_size: int, beta: bool = True, init_alpha: float = 0.5):
131
- super().__init__()
132
- self.hidden_size = hidden_size
133
- self.init_alpha = init_alpha
134
- self.alpha = nn.Parameter(torch.ones(1) * init_alpha)
135
- self.gamma = nn.Parameter(torch.ones(hidden_size))
136
- self.beta = nn.Parameter(torch.zeros(hidden_size)) if beta else None
137
-
138
- def forward(self, x: torch.Tensor) -> torch.Tensor:
139
- return LigerDyTFunction.apply(x, self.alpha, self.gamma, self.beta)
140
-
141
- def extra_repr(self) -> str:
142
- return f"{self.hidden_size}, init_alpha={self.init_alpha}, beta={self.beta is not None}"
143
-
144
-
145
- class LigerCrossEntropyLoss(nn.Module):
146
- def __init__(
147
- self,
148
- weight: Optional[torch.Tensor] = None,
149
- ignore_index: int = -100,
150
- lse_square_scale: float = 0.0,
151
- label_smoothing: float = 0.0,
152
- reduction: str = "mean",
153
- softcap: Optional[float] = None,
154
- ):
155
- super().__init__()
156
- assert 0.0 <= label_smoothing <= 1.0, f"label_smoothing must be in [0, 1], got {label_smoothing}"
157
- assert reduction in ("mean", "sum", "none"), f"reduction must be 'mean', 'sum', or 'none', got {reduction}"
158
- assert softcap is None or softcap > 0, f"softcap must be > 0 or None, got {softcap}"
159
- self.weight = weight
160
- self.ignore_index = ignore_index
161
- self.lse_square_scale = lse_square_scale
162
- self.label_smoothing = label_smoothing
163
- self.reduction = reduction
164
- self.softcap = softcap
165
-
166
- def forward(self, _input: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
167
- loss, _, _, _ = LigerCrossEntropyFunction.apply(
168
- _input,
169
- target,
170
- self.weight,
171
- self.ignore_index,
172
- self.lse_square_scale,
173
- self.label_smoothing,
174
- self.reduction,
175
- self.softcap,
176
- False,
177
- False,
178
- False,
179
- )
180
- return loss
181
-
182
-
183
- class LigerFusedLinearCrossEntropyLoss(nn.Module):
184
- def __init__(
185
- self,
186
- ce_weight: Optional[torch.Tensor] = None,
187
- ignore_index: int = -100,
188
- lse_square_scale: float = 0.0,
189
- label_smoothing: float = 0.0,
190
- reduction: str = "mean",
191
- softcap: Optional[float] = None,
192
- accum_dtype: Optional[torch.dtype] = None,
193
- use_token_scaling: bool = False,
194
- ):
195
- super().__init__()
196
- assert 0.0 <= label_smoothing <= 1.0, f"label_smoothing must be in [0, 1], got {label_smoothing}"
197
- assert reduction in ("mean", "sum", "none"), f"reduction must be 'mean', 'sum', or 'none', got {reduction}"
198
- assert softcap is None or softcap > 0, f"softcap must be > 0 or None, got {softcap}"
199
- self.ce_weight = ce_weight
200
- self.ignore_index = ignore_index
201
- self.lse_square_scale = lse_square_scale
202
- self.label_smoothing = label_smoothing
203
- self.reduction = reduction
204
- self.softcap = softcap
205
- self.accum_dtype = accum_dtype
206
- self.use_token_scaling = use_token_scaling
207
-
208
- def forward(
209
- self,
210
- lin_weight: torch.Tensor,
211
- _input: torch.Tensor,
212
- target: torch.Tensor,
213
- bias: Optional[torch.Tensor] = None,
214
- ) -> torch.Tensor:
215
- loss, _, _, _ = LigerFusedLinearCrossEntropyFunction.apply(
216
- _input,
217
- lin_weight,
218
- target,
219
- bias,
220
- self.ce_weight,
221
- self.ignore_index,
222
- self.lse_square_scale,
223
- self.label_smoothing,
224
- self.reduction,
225
- self.softcap,
226
- False,
227
- self.accum_dtype,
228
- self.use_token_scaling,
229
- False,
230
- False,
231
- )
232
- return loss
233
-
234
-
235
- class LigerJSD(nn.Module):
236
- def __init__(self, beta: float = 0.5, ignore_index: int = -100):
237
- super().__init__()
238
- self.beta = beta
239
- self.ignore_index = ignore_index
240
-
241
- def forward(
242
- self,
243
- log_q: torch.Tensor,
244
- log_p: torch.Tensor,
245
- shift_labels: Optional[torch.Tensor] = None,
246
- ) -> torch.Tensor:
247
- return LigerJSDFunction.apply(log_q, log_p, shift_labels, self.beta, self.ignore_index)
248
-
249
-
250
- class LigerKLDIVLoss(nn.KLDivLoss):
251
- def __init__(self, eps: float = 1e-10, *args, **kwargs):
252
- super().__init__(*args, **kwargs)
253
- self.eps = eps
254
-
255
- def forward(self, y_pred: torch.Tensor, y_true: torch.Tensor) -> torch.Tensor:
256
- return LigerKLDivLossFunction.apply(y_pred, y_true, self.reduction, self.log_target, self.eps)
257
-
258
-
259
- class LigerTVDLoss(nn.Module):
260
- def __init__(self, reduction: str = "batchmean", ignore_index: int = -100):
261
- super().__init__()
262
- self.reduction = reduction
263
- self.ignore_index = ignore_index
264
-
265
- def forward(
266
- self,
267
- p: torch.Tensor,
268
- q: torch.Tensor,
269
- shift_labels: Optional[torch.Tensor] = None,
270
- ) -> torch.Tensor:
271
- return LigerTVDLossFunction.apply(p, q, shift_labels, self.reduction, self.ignore_index)
272
-
273
-
274
- class LigerSwiGLUMLP(nn.Module):
275
- """SwiGLU MLP block. ``config`` must expose ``hidden_size``, ``intermediate_size``,
276
- and ``hidden_act`` (must be ``silu`` or ``swish``)."""
277
-
278
- def __init__(self, config):
279
- super().__init__()
280
- if config.hidden_act not in ("silu", "swish"):
281
- raise ValueError(f"Activation function {config.hidden_act} not supported.")
282
- self.config = config
283
- self.hidden_size = config.hidden_size
284
- self.intermediate_size = config.intermediate_size
285
- self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
286
- self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
287
- self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
288
-
289
- def forward(self, x: torch.Tensor) -> torch.Tensor:
290
- return self.down_proj(LigerSiLUMulFunction.apply(self.gate_proj(x), self.up_proj(x)))
291
-
292
-
293
- class LigerGEGLUMLP(nn.Module):
294
- """GEGLU MLP block. ``config`` must expose ``hidden_size`` and ``intermediate_size``.
295
- Uses the tanh approximation of GELU (matches Gemma 1/1.1/2)."""
296
-
297
- def __init__(self, config):
298
- super().__init__()
299
- self.config = config
300
- self.hidden_size = config.hidden_size
301
- self.intermediate_size = config.intermediate_size
302
- self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
303
- self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
304
- self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
305
-
306
- def forward(self, x: torch.Tensor) -> torch.Tensor:
307
- return self.down_proj(LigerGELUMulFunction.apply(self.gate_proj(x), self.up_proj(x)))
308
-
309
-
310
- class LigerTiledGEGLUMLP(nn.Module):
311
- gate_proj: nn.Linear
312
- up_proj: nn.Linear
313
- down_proj: nn.Linear
314
- num_shards: int
315
-
316
- def _mlp_forward(self, module, x):
317
- """Internal MLP forward function for tiled computation."""
318
- gate = module.gate_proj(x)
319
- up = module.up_proj(x)
320
- return module.down_proj(LigerGELUMulFunction.apply(gate, up))
321
-
322
- def forward(self, x: torch.Tensor) -> torch.Tensor:
323
- compute_params = [p for p in self.parameters() if p.requires_grad]
324
-
325
- return apply_tiled_mlp(
326
- fn=self._mlp_forward,
327
- mlp_module=self,
328
- x=x,
329
- num_shards=self.num_shards,
330
- compute_params=compute_params,
331
- )
332
-
333
-
334
- class LigerTiledSwiGLUMLP(nn.Module):
335
- gate_proj: nn.Linear
336
- up_proj: nn.Linear
337
- down_proj: nn.Linear
338
- num_shards: int
339
-
340
- def _mlp_forward(self, module, x):
341
- """Internal MLP forward function for tiled computation."""
342
- gate = module.gate_proj(x)
343
- up = module.up_proj(x)
344
- return module.down_proj(LigerSiLUMulFunction.apply(gate, up))
345
-
346
- def forward(self, x: torch.Tensor) -> torch.Tensor:
347
- compute_params = [p for p in self.parameters() if p.requires_grad]
348
-
349
- return apply_tiled_mlp(
350
- fn=self._mlp_forward,
351
- mlp_module=self,
352
- x=x,
353
- num_shards=self.num_shards,
354
- compute_params=compute_params,
355
- )
356
-
357
-
358
- @dataclass
359
- class CrossEntropyOutput:
360
- loss: torch.Tensor
361
- z_loss: Optional[torch.Tensor] = None
362
- token_accuracy: Optional[torch.Tensor] = None
363
- predicted_tokens: Optional[torch.Tensor] = None
364
-
365
-
366
- def liger_fused_linear_cross_entropy(
367
- input: torch.Tensor,
368
- weight: torch.Tensor,
369
- target: torch.Tensor,
370
- bias: Optional[torch.Tensor] = None,
371
- ce_weight: Optional[torch.Tensor] = None,
372
- ignore_index: int = -100,
373
- lse_square_scale: float = 0.0,
374
- label_smoothing: float = 0.0,
375
- reduction: str = "mean",
376
- softcap: Optional[float] = None,
377
- return_z_loss: bool = False,
378
- accum_dtype: Optional[torch.dtype] = None,
379
- use_token_scaling: bool = False,
380
- return_token_accuracy: bool = False,
381
- return_predicted_tokens: bool = False,
382
- ):
383
- loss, z_loss, token_accuracy, predicted_tokens = LigerFusedLinearCrossEntropyFunction.apply(
384
- input,
385
- weight,
386
- target,
387
- bias,
388
- ce_weight,
389
- ignore_index,
390
- lse_square_scale,
391
- label_smoothing,
392
- reduction,
393
- softcap,
394
- return_z_loss,
395
- accum_dtype,
396
- use_token_scaling,
397
- return_token_accuracy,
398
- return_predicted_tokens,
399
- )
400
- if not return_z_loss and not return_token_accuracy and not return_predicted_tokens:
401
- return loss
402
- return CrossEntropyOutput(
403
- loss=loss,
404
- z_loss=z_loss,
405
- token_accuracy=token_accuracy,
406
- predicted_tokens=predicted_tokens,
407
- )
408
-
409
-
410
- def LigerForCausalLMLoss(
411
- hidden_states: torch.Tensor,
412
- lm_head_weight: torch.Tensor,
413
- labels: torch.Tensor,
414
- hidden_size: int,
415
- num_items_in_batch: Optional[int] = None,
416
- ignore_index: int = -100,
417
- shift_labels: Optional[torch.Tensor] = None,
418
- final_logit_softcapping: Optional[float] = None,
419
- return_token_accuracy: bool = False,
420
- return_predicted_tokens: bool = False,
421
- **kwargs,
422
- ):
423
- """Drop-in replacement for ``transformers.loss.ForCausalLMLoss`` that fuses the
424
- final ``lm_head`` projection with the cross-entropy loss. Returns a scalar
425
- ``loss`` by default; returns a :class:`CrossEntropyOutput` when
426
- ``return_token_accuracy`` or ``return_predicted_tokens`` is set."""
427
- applicable_params = inspect.signature(liger_fused_linear_cross_entropy).parameters
428
- kwargs = {k: v for k, v in kwargs.items() if k in applicable_params}
429
-
430
- if shift_labels is None:
431
- labels = nn.functional.pad(labels, (0, 1), value=ignore_index)
432
- shift_labels = labels[..., 1:].contiguous()
433
-
434
- hidden_states = hidden_states.view(-1, hidden_size)
435
- shift_labels = shift_labels.view(-1).to(hidden_states.device)
436
-
437
- reduction = "sum" if num_items_in_batch is not None else "mean"
438
- result = liger_fused_linear_cross_entropy(
439
- hidden_states,
440
- lm_head_weight,
441
- shift_labels,
442
- reduction=reduction,
443
- ignore_index=ignore_index,
444
- softcap=final_logit_softcapping,
445
- return_token_accuracy=return_token_accuracy,
446
- return_predicted_tokens=return_predicted_tokens,
447
- **kwargs,
448
- )
449
-
450
- if isinstance(result, CrossEntropyOutput):
451
- loss = result.loss
452
- token_accuracy = result.token_accuracy
453
- predicted_tokens = result.predicted_tokens
454
- else:
455
- loss = result
456
- token_accuracy = None
457
- predicted_tokens = None
458
-
459
- if reduction == "sum":
460
- loss = loss / num_items_in_batch
461
-
462
- if return_token_accuracy or return_predicted_tokens:
463
- return CrossEntropyOutput(
464
- loss=loss,
465
- token_accuracy=token_accuracy,
466
- predicted_tokens=predicted_tokens,
467
- )
468
- return loss
469
-
470
-
471
- def liger_rotary_pos_emb(
472
- q: torch.Tensor,
473
- k: torch.Tensor,
474
- cos: torch.Tensor,
475
- sin: torch.Tensor,
476
- position_ids: Optional[torch.Tensor] = None,
477
- unsqueeze_dim: int = 1,
478
- ) -> Tuple[torch.Tensor, torch.Tensor]:
479
- """Apply standard rotary positional embedding to ``q`` and ``k``."""
480
- return LigerRopeFunction.apply(q, k, cos, sin, position_ids, unsqueeze_dim)
481
-
482
-
483
- def liger_multimodal_rotary_pos_emb(
484
- q: torch.Tensor,
485
- k: torch.Tensor,
486
- cos: torch.Tensor,
487
- sin: torch.Tensor,
488
- mrope_section,
489
- unsqueeze_dim: int = 1,
490
- ) -> Tuple[torch.Tensor, torch.Tensor]:
491
- """Apply Qwen2-VL multimodal rotary positional embedding (M-RoPE) to ``q`` and ``k``."""
492
- return LigerQwen2VLMRopeFunction.apply(q, k, cos, sin, mrope_section, unsqueeze_dim)
493
-
494
-
495
- __all__ = [
496
- "LigerRMSNorm",
497
- "LigerLayerNorm",
498
- "LigerGroupNorm",
499
- "LigerDyT",
500
- "LigerCrossEntropyLoss",
501
- "LigerFusedLinearCrossEntropyLoss",
502
- "LigerJSD",
503
- "LigerKLDIVLoss",
504
- "LigerTVDLoss",
505
- "LigerSwiGLUMLP",
506
- "LigerGEGLUMLP",
507
- "LigerTiledGEGLUMLP",
508
- "LigerTiledSwiGLUMLP",
509
- "CrossEntropyOutput",
510
- "liger_fused_linear_cross_entropy",
511
- "LigerForCausalLMLoss",
512
- "liger_rotary_pos_emb",
513
- "liger_multimodal_rotary_pos_emb",
514
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/liger_kernels/__init__.py DELETED
@@ -1,26 +0,0 @@
1
- import ctypes
2
- import importlib.util
3
- import sys
4
- from pathlib import Path
5
- from types import ModuleType
6
-
7
-
8
- def _import_from_path(file_path: Path) -> ModuleType:
9
- # We cannot use the module name as-is, after adding it to `sys.modules`,
10
- # it would also be used for other imports. So, we make a module name that
11
- # depends on the path for it to be unique using the hex-encoded hash of
12
- # the path.
13
- path_hash = "{:x}".format(ctypes.c_size_t(hash(file_path.absolute())).value)
14
- module_name = path_hash
15
- spec = importlib.util.spec_from_file_location(module_name, file_path)
16
- if spec is None:
17
- raise ImportError(f"Cannot load spec for {module_name} from {file_path}")
18
- module = importlib.util.module_from_spec(spec)
19
- if module is None:
20
- raise ImportError(f"Cannot load module {module_name} from spec")
21
- sys.modules[module_name] = module
22
- spec.loader.exec_module(module) # type: ignore
23
- return module
24
-
25
-
26
- globals().update(vars(_import_from_path(Path(__file__).parent.parent / "__init__.py")))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/metadata.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "name": "liger-kernels",
3
- "id": "_liger_kernels_xpu_ab435e2",
4
- "version": 1,
5
- "license": "BSD-2-Clause",
6
- "python-depends": [],
7
- "backend": {
8
- "type": "xpu"
9
- }
10
- }
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/qwen2vl_mrope.py DELETED
@@ -1,222 +0,0 @@
1
- import torch
2
- import triton
3
- import triton.language as tl
4
-
5
-
6
- @triton.jit
7
- def _triton_qwen2vl_mrope(
8
- q_ptr,
9
- k_ptr,
10
- cos,
11
- sin,
12
- sl,
13
- bs: tl.constexpr,
14
- n_qh: tl.constexpr,
15
- n_kh: tl.constexpr,
16
- hd: tl.constexpr,
17
- pad_n_qh: tl.constexpr,
18
- pad_n_kh: tl.constexpr,
19
- pad_hd: tl.constexpr,
20
- mrope_section_t: tl.constexpr,
21
- mrope_section_h: tl.constexpr,
22
- BLOCK_SIZE: tl.constexpr,
23
- BACKWARD_PASS: tl.constexpr = False,
24
- ):
25
- pid = tl.program_id(0)
26
-
27
- # locate start address
28
- q_ptr = q_ptr + pid * (n_qh * hd)
29
- k_ptr = k_ptr + pid * (n_kh * hd)
30
-
31
- # ####################################################################
32
- # get the cos(mθ_{i...d/2}) and sin(mθ_{i...d/2}) for token position
33
- # m of this program instance
34
- # ####################################################################
35
-
36
- # 1. program instances are laid out in a 1D vector of size bsz * seq_len, which
37
- # effectively represents a 2D grid of size [bsz, seq_len] with seq_len dimension
38
- # being the fastest changing dimension. Thus we can simply do pid // sl to get the batch index
39
- # and pid % sl to get the sequence index.
40
- # 2. We only need the left half of cos and sin matrix because the right half is just
41
- # a clone of the left half.
42
- t_end = mrope_section_t
43
- h_end = t_end + mrope_section_h
44
-
45
- t_cos = cos + pid * hd
46
- h_cos = t_cos + bs * sl * hd
47
- w_cos = h_cos + bs * sl * hd
48
- t_sin = sin + pid * hd
49
- h_sin = t_sin + bs * sl * hd
50
- w_sin = h_sin + bs * sl * hd
51
-
52
- cos_offsets = tl.arange(0, pad_hd // 2)
53
- t_mask = cos_offsets < t_end
54
- h_mask = (t_end <= cos_offsets) & (cos_offsets < h_end)
55
- w_mask = (h_end <= cos_offsets) & (cos_offsets < hd // 2)
56
- t_cos_row = tl.load(t_cos + cos_offsets, mask=t_mask, other=0)
57
- h_cos_row = tl.load(h_cos + cos_offsets, mask=h_mask, other=0)
58
- w_cos_row = tl.load(w_cos + cos_offsets, mask=w_mask, other=0)
59
- t_sin_row = tl.load(t_sin + cos_offsets, mask=t_mask, other=0)
60
- h_sin_row = tl.load(h_sin + cos_offsets, mask=h_mask, other=0)
61
- w_sin_row = tl.load(w_sin + cos_offsets, mask=w_mask, other=0)
62
- cos_row = t_cos_row + h_cos_row + w_cos_row
63
- sin_row = t_sin_row + h_sin_row + w_sin_row
64
-
65
- # ####################################################################
66
- # Load the left and right half of q and k for the current
67
- # program instance (i.e. for the current token) separately
68
- # ####################################################################
69
- # left half of the head
70
- first_half_q_offsets = tl.arange(0, pad_n_qh)[:, None] * hd + tl.arange(0, pad_hd // 2)[None, :]
71
- first_half_k_offsets = tl.arange(0, pad_n_kh)[:, None] * hd + tl.arange(0, pad_hd // 2)[None, :]
72
- first_q_mask = (tl.arange(0, pad_n_qh)[:, None] < n_qh) & (tl.arange(0, pad_hd // 2)[None, :] < hd // 2)
73
- first_k_mask = (tl.arange(0, pad_n_kh)[:, None] < n_kh) & (tl.arange(0, pad_hd // 2)[None, :] < hd // 2)
74
- q_tile_1 = tl.load(q_ptr + first_half_q_offsets, mask=first_q_mask, other=0).to(sin_row.dtype)
75
- k_tile_1 = tl.load(k_ptr + first_half_k_offsets, mask=first_k_mask, other=0).to(sin_row.dtype)
76
-
77
- # right half of the head
78
- second_half_q_offsets = first_half_q_offsets + (hd // 2)
79
- second_half_k_offsets = first_half_k_offsets + (hd // 2)
80
- second_q_mask = first_q_mask
81
- second_k_mask = first_k_mask
82
- q_tile_2 = tl.load(q_ptr + second_half_q_offsets, mask=second_q_mask, other=0).to(sin_row.dtype)
83
- k_tile_2 = tl.load(k_ptr + second_half_k_offsets, mask=second_k_mask, other=0).to(sin_row.dtype)
84
-
85
- if not BACKWARD_PASS:
86
- # y = [x1, x2] * [cos, cos] + [-x2, x1] * [sin, sin]
87
- new_q_tile_1 = q_tile_1 * cos_row - q_tile_2 * sin_row
88
- tl.store(q_ptr + first_half_q_offsets, new_q_tile_1, mask=first_q_mask)
89
- new_q_tile_2 = q_tile_2 * cos_row + q_tile_1 * sin_row
90
- tl.store(q_ptr + second_half_q_offsets, new_q_tile_2, mask=second_q_mask)
91
-
92
- new_k_tile_1 = k_tile_1 * cos_row - k_tile_2 * sin_row
93
- tl.store(k_ptr + first_half_k_offsets, new_k_tile_1, mask=first_k_mask)
94
- new_k_tile_2 = k_tile_2 * cos_row + k_tile_1 * sin_row
95
- tl.store(k_ptr + second_half_k_offsets, new_k_tile_2, mask=second_k_mask)
96
- else:
97
- # with some math, we can get:
98
- # dy = [dx1, dx2] * [cos, cos] + [-dx2, dx1] * [-sin, -sin]
99
- new_q_tile_1 = q_tile_1 * cos_row + q_tile_2 * sin_row
100
- tl.store(q_ptr + first_half_q_offsets, new_q_tile_1, mask=first_q_mask)
101
- new_q_tile_2 = q_tile_2 * cos_row - q_tile_1 * sin_row
102
- tl.store(q_ptr + second_half_q_offsets, new_q_tile_2, mask=second_q_mask)
103
-
104
- new_k_tile_1 = k_tile_1 * cos_row + k_tile_2 * sin_row
105
- tl.store(k_ptr + first_half_k_offsets, new_k_tile_1, mask=first_k_mask)
106
- new_k_tile_2 = k_tile_2 * cos_row - k_tile_1 * sin_row
107
- tl.store(k_ptr + second_half_k_offsets, new_k_tile_2, mask=second_k_mask)
108
-
109
-
110
- def qwen2vl_mrope_forward(q, k, cos, sin, mrope_section):
111
- # transpose it back to the physical shape because Triton looks at the physical storage
112
- # note: q and k are incontiguous before the transformation and will become contiguous after transpose
113
- q = q.transpose(1, 2)
114
- k = k.transpose(1, 2)
115
-
116
- batch_size, seq_len, n_q_head, head_dim = q.shape
117
- n_kv_head = k.shape[2]
118
- pad_hd = triton.next_power_of_2(head_dim)
119
- pad_n_q_head = triton.next_power_of_2(n_q_head)
120
- pad_n_kv_head = triton.next_power_of_2(n_kv_head)
121
- BLOCK_SIZE = max(pad_n_q_head, pad_n_kv_head)
122
-
123
- n_row = batch_size * seq_len
124
-
125
- # ensure tensors passed into the kernel are contiguous. It will be no-op if they are already contiguous
126
- q = q.contiguous()
127
- k = k.contiguous()
128
- cos = cos.contiguous()
129
- sin = sin.contiguous()
130
-
131
- _triton_qwen2vl_mrope[(n_row,)](
132
- q,
133
- k,
134
- cos,
135
- sin,
136
- seq_len,
137
- batch_size,
138
- n_q_head,
139
- n_kv_head,
140
- head_dim,
141
- pad_n_q_head,
142
- pad_n_kv_head,
143
- pad_hd,
144
- mrope_section[0],
145
- mrope_section[1],
146
- BLOCK_SIZE=BLOCK_SIZE,
147
- BACKWARD_PASS=False,
148
- )
149
- return q.transpose(1, 2), k.transpose(1, 2), cos, sin
150
-
151
-
152
- def qwen2vl_mrope_backward(dq, dk, cos, sin, mrope_section):
153
- dq = dq.transpose(1, 2)
154
- dk = dk.transpose(1, 2)
155
-
156
- batch_size, seq_len, n_q_head, head_dim = dq.shape
157
- n_kv_head = dk.shape[2]
158
- pad_hd = triton.next_power_of_2(head_dim)
159
- pad_n_q_head = triton.next_power_of_2(n_q_head)
160
- pad_n_kv_head = triton.next_power_of_2(n_kv_head)
161
- BLOCK_SIZE = max(pad_n_q_head, pad_n_kv_head)
162
-
163
- n_row = batch_size * seq_len
164
-
165
- # ensure dq and dk are contiguous
166
- dq = dq.contiguous()
167
- dk = dk.contiguous()
168
-
169
- # backward is similar to forward except swapping few ops
170
- _triton_qwen2vl_mrope[(n_row,)](
171
- dq,
172
- dk,
173
- cos,
174
- sin,
175
- seq_len,
176
- batch_size,
177
- n_q_head,
178
- n_kv_head,
179
- head_dim,
180
- pad_n_q_head,
181
- pad_n_kv_head,
182
- pad_hd,
183
- mrope_section[0],
184
- mrope_section[1],
185
- BLOCK_SIZE=BLOCK_SIZE,
186
- BACKWARD_PASS=True,
187
- )
188
- return dq.transpose(1, 2), dk.transpose(1, 2)
189
-
190
-
191
- class LigerQwen2VLMRopeFunction(torch.autograd.Function):
192
- """
193
- Triton implementation of the Qwen2VL Multimodal Rotary Positional Embedding (M-RoPE) operation.
194
-
195
- Please find the corresponding HuggingFace implementation here:
196
- https://github.com/huggingface/transformers/blob/main/src/transformers/models/qwen2_vl/modeling_qwen2_vl.py
197
- """
198
-
199
- @staticmethod
200
- def forward(ctx, q, k, cos, sin, mrope_section, unsqueeze_dim=1):
201
- """
202
- q size: (bsz, n_q_head, seq_len, head_dim)
203
- k size: (bsz, n_kv_head, seq_len, head_dim)
204
- cos size: (3, bsz, seq_len, head_dim)
205
- sin size: (3, bsz, seq_len, head_dim)
206
- """
207
- q, k, cos, sin = qwen2vl_mrope_forward(q, k, cos, sin, mrope_section)
208
- ctx.save_for_backward(cos, sin)
209
- ctx.mrope_section = mrope_section
210
- return q, k
211
-
212
- def backward(ctx, dq, dk):
213
- """
214
- dq size: (bsz, n_q_head, seq_len, head_dim)
215
- dk size: (bsz, n_kv_head, seq_len, head_dim)
216
- cos size: (3, bsz, seq_len, head_dim)
217
- sin size: (3, bsz, seq_len, head_dim)
218
- """
219
- cos, sin = ctx.saved_tensors
220
- mrope_section = ctx.mrope_section
221
- dq, dk = qwen2vl_mrope_backward(dq, dk, cos, sin, mrope_section)
222
- return dq, dk, None, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/rms_norm.py DELETED
@@ -1,654 +0,0 @@
1
- """
2
- This file incorporates code from Unsloth licensed under the Apache License, Version 2.0.
3
- See the original Unsloth repository at https://github.com/unslothai/unsloth.
4
-
5
- The following line
6
- https://github.com/linkedin/Liger-Kernel/blob/7382a8761f9af679482b968f9348013d933947c7/src/liger_kernel/ops/rms_norm.py#L30
7
- is based on code from Unsloth, located at:
8
- https://github.com/unslothai/unsloth/blob/fd753fed99ed5f10ef8a9b7139588d9de9ddecfb/unsloth/kernels/rms_layernorm.py#L22
9
-
10
- Modifications made by Yanning Chen, 2024.
11
- """
12
-
13
- import math
14
- import operator
15
-
16
- import torch
17
- import triton
18
- import triton.language as tl
19
-
20
- from .utils import calculate_settings
21
- from .utils import compare_version
22
- from .utils import ensure_contiguous
23
- from .utils import get_npu_core_count
24
- from .utils import set_large_grf_mode
25
- from .utils import torch_to_triton_dtype
26
- from .utils import is_npu_available
27
-
28
- if compare_version("triton", operator.ge, "3.0.0") and not is_npu_available():
29
- try:
30
- # typical import path with dispatch available
31
- from triton.language.extra.libdevice import rsqrt
32
- except ModuleNotFoundError:
33
- # for working with NGC containers
34
- from triton.language.extra.cuda.libdevice import rsqrt
35
- else:
36
- from triton.language.math import rsqrt
37
-
38
-
39
- _CASTING_MODE_NONE: tl.constexpr = tl.constexpr(-1)
40
- _CASTING_MODE_LLAMA: tl.constexpr = tl.constexpr(0)
41
- _CASTING_MODE_GEMMA: tl.constexpr = tl.constexpr(1)
42
-
43
-
44
- @triton.jit
45
- def _rms_norm_forward_kernel(
46
- Y_ptr,
47
- Y_row_stride,
48
- X_ptr,
49
- X_row_stride,
50
- W_ptr,
51
- W_row_stride,
52
- RSTD_ptr,
53
- RSTD_row_stride,
54
- n_cols,
55
- eps,
56
- offset,
57
- casting_mode: tl.constexpr, # constexpr so the `if` blocks can be optimized out
58
- elementwise_affine: tl.constexpr,
59
- BLOCK_SIZE: tl.constexpr,
60
- ):
61
- """
62
- y_i = (x_i / (RMS)) * (offset + wi), RMS = sqrt(sum(x_i^2) / N)
63
-
64
- Reference:
65
- 1. https://triton-lang.org/main/getting-started/tutorials/05-layer-norm.html
66
- 2. https://github.com/unslothai/unsloth/blob/fd753fed99ed5f10ef8a9b7139588d9de9ddecfb/unsloth/kernels/rms_layernorm.py#L22
67
- 3. https://arxiv.org/pdf/1910.07467
68
- """
69
-
70
- row_idx = tl.program_id(0).to(tl.int64)
71
- col_offsets = tl.arange(0, BLOCK_SIZE)
72
- mask = col_offsets < n_cols
73
-
74
- y_base = Y_ptr + row_idx * Y_row_stride
75
- x_base = X_ptr + row_idx * X_row_stride
76
- rstd_base = RSTD_ptr + row_idx * RSTD_row_stride
77
-
78
- X_row = tl.load(x_base + col_offsets, mask=mask, other=0)
79
- X_row_dtype = X_row.dtype
80
- if elementwise_affine:
81
- W_row = tl.load(W_ptr + col_offsets, mask=mask, other=0)
82
-
83
- # On Llama, only rstd is computed on fp32
84
- if casting_mode == _CASTING_MODE_LLAMA:
85
- X_row = X_row.to(tl.float32)
86
-
87
- # Gemma computes everything on fp32, and then casts back the output to the original dtype
88
- if casting_mode == _CASTING_MODE_GEMMA:
89
- if elementwise_affine:
90
- W_row = W_row.to(tl.float32)
91
- X_row = X_row.to(tl.float32)
92
-
93
- if casting_mode == _CASTING_MODE_NONE:
94
- eps = eps.to(X_row_dtype)
95
- offset = offset.to(X_row_dtype)
96
-
97
- mean_square = tl.sum(X_row * X_row, axis=0) / n_cols
98
- rstd = rsqrt(mean_square + eps)
99
-
100
- # We can save time by caching rms with minimal memory overhead
101
- # because rms is much smaller compared to X_row, as rms is for each row.
102
- # However, on the computation side, it can save 4 operations (*, sum, /, sqrt).
103
- tl.store(rstd_base, rstd)
104
-
105
- X_row = X_row * rstd
106
-
107
- # On Llama, the multiplication with the weight is done on the original dtype
108
- if casting_mode == _CASTING_MODE_LLAMA:
109
- X_row = X_row.to(X_row_dtype)
110
-
111
- if elementwise_affine:
112
- Y_row = X_row * (offset + W_row)
113
- else:
114
- Y_row = X_row
115
-
116
- if casting_mode == _CASTING_MODE_GEMMA:
117
- Y_row = Y_row.to(X_row_dtype)
118
-
119
- tl.store(y_base + col_offsets, Y_row, mask=mask)
120
-
121
-
122
- @triton.jit
123
- def _rms_norm_backward_kernel(
124
- dY_ptr,
125
- dY_row_stride,
126
- dX_ptr,
127
- dX_row_stride,
128
- X_ptr,
129
- X_row_stride,
130
- X_dtype: tl.constexpr,
131
- W_ptr,
132
- W_row_stride,
133
- RSTD_ptr,
134
- RSTD_row_stride,
135
- dW_ptr,
136
- dW_row_stride,
137
- n_rows,
138
- n_cols,
139
- offset,
140
- rows_per_program,
141
- casting_mode: tl.constexpr,
142
- elementwise_affine: tl.constexpr,
143
- BLOCK_SIZE: tl.constexpr,
144
- ):
145
- """
146
- dx = (1 / RMS) * [dy * (w + offset - (1 / N) * (1 / RMS^2) * ((dy * (w + offset)) dot x) * x]. * means element-wise multiplication, whileas dot means dot product
147
- dw = sum(dy * (x / RMS)). summation over BxT dimension
148
- """
149
-
150
- row_block_id = tl.program_id(0).to(tl.int64)
151
- row_start = row_block_id * rows_per_program
152
- row_end = min((row_block_id + 1) * rows_per_program, n_rows)
153
- col_offsets = tl.arange(0, BLOCK_SIZE)
154
- mask = col_offsets < n_cols
155
-
156
- if elementwise_affine:
157
- dW_row = tl.zeros((BLOCK_SIZE,), dtype=tl.float32)
158
-
159
- if elementwise_affine:
160
- W_row = tl.load(W_ptr + col_offsets, mask=mask, other=0.0)
161
- W_row = W_row + offset
162
-
163
- for row_idx in range(row_start, row_end):
164
- dy_base = dY_ptr + row_idx * dY_row_stride
165
- dx_base = dX_ptr + row_idx * dX_row_stride
166
-
167
- x_base = X_ptr + row_idx * X_row_stride
168
- rstd_base = RSTD_ptr + row_idx * RSTD_row_stride
169
-
170
- dY_row = tl.load(dy_base + col_offsets, mask=mask, other=0.0)
171
- X_row = tl.load(x_base + col_offsets, mask=mask, other=0.0)
172
-
173
- # Get cached rms
174
- rstd_row = tl.load(rstd_base)
175
-
176
- X_row = X_row.to(tl.float32)
177
-
178
- # Different bacward graphs for different casting modes
179
- if casting_mode == _CASTING_MODE_LLAMA:
180
- if elementwise_affine:
181
- m = (dY_row * W_row).to(tl.float32)
182
- else:
183
- m = dY_row.to(tl.float32)
184
-
185
- elif casting_mode == _CASTING_MODE_GEMMA:
186
- dY_row = dY_row.to(tl.float32)
187
- if elementwise_affine:
188
- m = dY_row * W_row
189
- else:
190
- m = dY_row
191
- else:
192
- if elementwise_affine:
193
- m = dY_row * W_row
194
- else:
195
- m = dY_row
196
-
197
- dX_row = rstd_row * m
198
-
199
- dX_row += (rstd_row) * (-(1 / n_cols) * rstd_row * rstd_row * tl.sum(m * X_row, axis=0) * X_row)
200
-
201
- if elementwise_affine:
202
- # calculate the gradient of W
203
- if casting_mode == _CASTING_MODE_LLAMA:
204
- dW_row += dY_row * (X_row * rstd_row).to(X_dtype)
205
- else:
206
- # here X_row is already in fp32 (see previous if block)
207
- dW_row += dY_row * (X_row * rstd_row)
208
-
209
- tl.store(dx_base + col_offsets, dX_row.to(X_dtype), mask=mask)
210
-
211
- if elementwise_affine:
212
- tl.store(dW_ptr + row_block_id * dW_row_stride + col_offsets, dW_row, mask=mask)
213
-
214
-
215
- @triton.jit
216
- def _block_rms_norm_forward_kernel(
217
- Y_ptr,
218
- Y_row_stride,
219
- X_ptr,
220
- X_row_stride,
221
- W_ptr,
222
- W_row_stride,
223
- RSTD_ptr,
224
- RSTD_row_stride,
225
- n_rows,
226
- n_cols,
227
- eps,
228
- offset,
229
- casting_mode: tl.constexpr, # constexpr so the `if` blocks can be optimized out
230
- elementwise_affine: tl.constexpr,
231
- BLOCK_SIZE: tl.constexpr,
232
- BLOCK_ROW: tl.constexpr,
233
- ):
234
- """
235
- y_i = (x_i / (RMS)) * (offset + wi), RMS = sqrt(sum(x_i^2) / N)
236
-
237
- Reference:
238
- 1. https://triton-lang.org/main/getting-started/tutorials/05-layer-norm.html
239
- 2. https://github.com/unslothai/unsloth/blob/fd753fed99ed5f10ef8a9b7139588d9de9ddecfb/unsloth/kernels/rms_layernorm.py#L22
240
- 3. https://arxiv.org/pdf/1910.07467
241
- """
242
-
243
- row_idx = tl.program_id(0) * BLOCK_ROW + tl.arange(0, BLOCK_ROW)
244
- col_offsets = tl.arange(0, BLOCK_SIZE)
245
- row_mask = row_idx < n_rows
246
- col_mask = col_offsets < n_cols
247
-
248
- X_row = tl.load(
249
- X_ptr + row_idx[:, None] * X_row_stride + col_offsets[None, :],
250
- mask=row_mask[:, None] & col_mask[None, :],
251
- other=0,
252
- )
253
- X_row_dtype = X_row.dtype
254
- if elementwise_affine:
255
- W_row = tl.load(W_ptr + col_offsets, mask=col_mask, other=0)
256
-
257
- # On Llama, only rstd is computed on fp32
258
- if casting_mode == _CASTING_MODE_LLAMA:
259
- X_row = X_row.to(tl.float32)
260
-
261
- # Gemma computes everything on fp32, and then casts back the output to the original dtype
262
- if casting_mode == _CASTING_MODE_GEMMA:
263
- if elementwise_affine:
264
- W_row = W_row.to(tl.float32)
265
- X_row = X_row.to(tl.float32)
266
-
267
- if casting_mode == _CASTING_MODE_NONE:
268
- eps = eps.to(X_row_dtype)
269
- offset = offset.to(X_row_dtype)
270
-
271
- mean_square = tl.sum(X_row * X_row, axis=1) / n_cols
272
- rstd = rsqrt(mean_square + eps)
273
-
274
- # We can save time by caching rms with minimal memory overhead
275
- # because rms is much smaller compared to X_row, as rms is for each row.
276
- # However, on the computation side, it can save 4 operations (*, sum, /, sqrt).
277
- tl.store(RSTD_ptr + row_idx * RSTD_row_stride, rstd, row_mask)
278
-
279
- X_row = X_row * rstd[:, None]
280
-
281
- # On Llama, the multiplication with the weight is done on the original dtype
282
- if casting_mode == _CASTING_MODE_LLAMA:
283
- X_row = X_row.to(X_row_dtype)
284
-
285
- if elementwise_affine:
286
- Y_row = X_row * (offset + W_row)[None, :]
287
- else:
288
- Y_row = X_row
289
-
290
- if casting_mode == _CASTING_MODE_GEMMA:
291
- Y_row = Y_row.to(X_row_dtype)
292
-
293
- tl.store(
294
- Y_ptr + row_idx[:, None] * Y_row_stride + col_offsets[None, :],
295
- Y_row,
296
- mask=row_mask[:, None] & col_mask[None, :],
297
- )
298
-
299
-
300
- @triton.jit
301
- def _block_rms_norm_backward_kernel(
302
- dY_ptr,
303
- dY_row_stride,
304
- dX_ptr,
305
- dX_row_stride,
306
- X_ptr,
307
- X_row_stride,
308
- X_dtype: tl.constexpr,
309
- W_ptr,
310
- W_row_stride,
311
- RSTD_ptr,
312
- RSTD_row_stride,
313
- dW_ptr,
314
- dW_row_stride,
315
- n_rows,
316
- n_cols,
317
- offset,
318
- casting_mode: tl.constexpr,
319
- elementwise_affine: tl.constexpr,
320
- BLOCK_SIZE: tl.constexpr,
321
- BLOCK_ROW: tl.constexpr,
322
- ):
323
- """
324
- dx = (1 / RMS) * [dy * (w + offset - (1 / N) * (1 / RMS^2) * ((dy * (w + offset)) dot x) * x]. * means element-wise multiplication, whileas dot means dot product
325
- dw = sum(dy * (x / RMS)). summation over BxT dimension
326
- """
327
-
328
- pid = tl.program_id(0).cast(tl.int64)
329
- NUM_SMS = tl.num_programs(0)
330
-
331
- col_offsets = tl.arange(0, BLOCK_SIZE)
332
- col_mask = col_offsets < n_cols
333
-
334
- if elementwise_affine:
335
- dW_row = tl.zeros((BLOCK_SIZE,), dtype=tl.float32)
336
-
337
- W_row = tl.load(W_ptr + col_offsets, mask=col_mask, other=0.0)
338
- W_row = W_row + offset
339
-
340
- for start in range(pid * BLOCK_ROW, n_rows, NUM_SMS * BLOCK_ROW):
341
- row_idx = start + tl.arange(0, BLOCK_ROW)
342
- row_mask = row_idx < n_rows
343
- dY_row = tl.load(
344
- dY_ptr + row_idx[:, None] * dY_row_stride + col_offsets[None, :],
345
- mask=row_mask[:, None] & col_mask[None, :],
346
- other=0.0,
347
- )
348
- X_row = tl.load(
349
- X_ptr + row_idx[:, None] * X_row_stride + col_offsets[None, :],
350
- mask=row_mask[:, None] & col_mask[None, :],
351
- other=0.0,
352
- )
353
-
354
- # Get cached rms
355
- rstd_row = tl.load(RSTD_ptr + row_idx * RSTD_row_stride, row_mask)
356
-
357
- X_row = X_row.to(tl.float32)
358
-
359
- # Different bacward graphs for different casting modes
360
- if casting_mode == _CASTING_MODE_LLAMA:
361
- if elementwise_affine:
362
- m = (dY_row * W_row[None, :]).to(tl.float32)
363
- else:
364
- m = dY_row.to(tl.float32)
365
-
366
- elif casting_mode == _CASTING_MODE_GEMMA:
367
- dY_row = dY_row.to(tl.float32)
368
- if elementwise_affine:
369
- m = dY_row * W_row[None, :]
370
- else:
371
- m = dY_row
372
- else:
373
- if elementwise_affine:
374
- m = dY_row * W_row[None, :]
375
- else:
376
- m = dY_row
377
-
378
- dX_row = rstd_row[:, None] * m
379
-
380
- dX_row += (rstd_row[:, None]) * (
381
- -(1 / n_cols) * (rstd_row * rstd_row * tl.sum(m * X_row, axis=1))[:, None] * X_row
382
- )
383
-
384
- if elementwise_affine:
385
- if casting_mode == _CASTING_MODE_LLAMA:
386
- # TODO(tcc): use tl.sum(..., dtype=tl.float32) once we upgrade to triton>=3.3.0
387
- dW_row += tl.sum((dY_row * (X_row * rstd_row[:, None]).to(X_dtype)).to(tl.float32), 0)
388
- else:
389
- # here X_row is already in fp32 (see previous if block)
390
- dW_row += tl.sum(dY_row * (X_row * rstd_row[:, None]), 0)
391
-
392
- tl.store(
393
- dX_ptr + row_idx[:, None] * dX_row_stride + col_offsets[None, :],
394
- dX_row,
395
- mask=row_mask[:, None] & col_mask[None, :],
396
- )
397
-
398
- if elementwise_affine:
399
- tl.store(dW_ptr + pid * dW_row_stride + col_offsets, dW_row, mask=col_mask)
400
-
401
-
402
- _str_to_casting_mode = {
403
- "llama": _CASTING_MODE_LLAMA.value,
404
- "gemma": _CASTING_MODE_GEMMA.value,
405
- "none": _CASTING_MODE_NONE.value,
406
- }
407
-
408
-
409
- def rms_norm_forward(X, W, eps, offset, casting_mode, row_mode):
410
- if not isinstance(casting_mode, int):
411
- assert casting_mode in _str_to_casting_mode, f"Invalid casting mode: {casting_mode}"
412
- casting_mode = _str_to_casting_mode[casting_mode]
413
- else:
414
- assert casting_mode in _str_to_casting_mode.values(), f"Invalid casting mode: {casting_mode}"
415
-
416
- shape = X.shape
417
- dim = shape[-1]
418
- X = X.view(-1, dim)
419
- n_rows, n_cols = X.shape
420
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
421
-
422
- Y = torch.empty((n_rows, n_cols), dtype=X.dtype, device=X.device)
423
- # RSTD is to cache rstd for each row
424
- # RSTD is always computed/stored in fp32 if we are using Llama or Gemma casting mode
425
- rstd_dtype = torch.float32 if casting_mode in (_CASTING_MODE_LLAMA.value, _CASTING_MODE_GEMMA.value) else X.dtype
426
- RSTD = torch.empty(n_rows, dtype=rstd_dtype, device=X.device)
427
-
428
- if W is not None:
429
- # Check constraints.
430
- assert X.shape[1] == W.shape[0], (
431
- "Incompatible hidden size dimension between tensor1.shape[1] and tensor2.shape[0]"
432
- )
433
- elementwise_affine = True
434
- else:
435
- elementwise_affine = False
436
-
437
- # XPU-specific optimization
438
- kernel_args = {}
439
- if X.device.type == "xpu":
440
- set_large_grf_mode(kernel_args)
441
- if BLOCK_SIZE > 256 or n_rows < 4096 * 8 or row_mode:
442
- _rms_norm_forward_kernel[(n_rows,)](
443
- Y,
444
- Y.stride(0),
445
- X,
446
- X.stride(0),
447
- W,
448
- W.stride(0) if elementwise_affine else 0,
449
- RSTD,
450
- RSTD.stride(0),
451
- n_cols,
452
- eps,
453
- offset,
454
- casting_mode,
455
- elementwise_affine=elementwise_affine,
456
- BLOCK_SIZE=BLOCK_SIZE,
457
- num_warps=num_warps,
458
- **kernel_args, # XPU-specific optimization
459
- )
460
- else:
461
- BLOCK_ROW = 16
462
- kernel_args["BLOCK_ROW"] = BLOCK_ROW
463
- _block_rms_norm_forward_kernel[(triton.cdiv(n_rows, BLOCK_ROW),)](
464
- Y,
465
- Y.stride(0),
466
- X,
467
- X.stride(0),
468
- W,
469
- W.stride(0) if elementwise_affine else 0,
470
- RSTD,
471
- RSTD.stride(0),
472
- n_rows,
473
- n_cols,
474
- eps,
475
- offset,
476
- casting_mode,
477
- elementwise_affine=elementwise_affine,
478
- BLOCK_SIZE=BLOCK_SIZE,
479
- num_warps=num_warps,
480
- **kernel_args, # XPU-specific optimization
481
- )
482
- return Y.view(*shape), X, RSTD, BLOCK_SIZE, num_warps, casting_mode
483
-
484
-
485
- def rms_norm_backward(dY, X, W, RSTD, offset, casting_mode, BLOCK_SIZE, num_warps, in_place, row_mode):
486
- shape = dY.shape
487
- dim = shape[-1]
488
- dY = dY.view(-1, dim)
489
- n_rows, n_cols = dY.shape
490
-
491
- sm_count = 1
492
- if X.device.type == "cuda":
493
- sm_count = torch.cuda.get_device_properties(X.device).multi_processor_count
494
- elif X.device.type == "xpu":
495
- sm_count = torch.xpu.get_device_properties(X.device).gpu_eu_count
496
- elif X.device.type == "npu":
497
- sm_count = get_npu_core_count()
498
-
499
- if W is not None:
500
- # fp32 for numerical stability especially.
501
- _dW = torch.empty((sm_count, n_cols), dtype=torch.float32, device=W.device)
502
- elementwise_affine = True
503
- else:
504
- _dW = None
505
- elementwise_affine = False
506
-
507
- if n_cols > BLOCK_SIZE:
508
- raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
509
- rows_per_program = math.ceil(n_rows / sm_count)
510
- grid = (sm_count,)
511
-
512
- if in_place is True:
513
- dX = dY
514
- else:
515
- dX = torch.zeros_like(dY)
516
-
517
- # XPU-specific optimization
518
- kernel_args = {}
519
- if X.device.type == "xpu":
520
- set_large_grf_mode(kernel_args)
521
-
522
- if BLOCK_SIZE > 256 or n_rows < 4096 * 8 or row_mode:
523
- _rms_norm_backward_kernel[grid](
524
- dY,
525
- dY.stride(0),
526
- dX,
527
- dX.stride(0),
528
- X,
529
- X.stride(0),
530
- torch_to_triton_dtype[X.dtype],
531
- W,
532
- W.stride(0) if elementwise_affine else 0,
533
- RSTD,
534
- RSTD.stride(0),
535
- _dW,
536
- _dW.stride(0) if elementwise_affine else 0,
537
- n_rows,
538
- n_cols,
539
- offset,
540
- rows_per_program,
541
- casting_mode,
542
- elementwise_affine=elementwise_affine,
543
- BLOCK_SIZE=BLOCK_SIZE,
544
- num_warps=num_warps,
545
- **kernel_args, # XPU-specific optimization
546
- )
547
- else:
548
- BLOCK_ROW = 16
549
- kernel_args["BLOCK_ROW"] = BLOCK_ROW
550
- _block_rms_norm_backward_kernel[grid](
551
- dY,
552
- dY.stride(0),
553
- dX,
554
- dX.stride(0),
555
- X,
556
- X.stride(0),
557
- torch_to_triton_dtype[X.dtype],
558
- W,
559
- W.stride(0) if elementwise_affine else 0,
560
- RSTD,
561
- RSTD.stride(0),
562
- _dW,
563
- _dW.stride(0) if elementwise_affine else 0,
564
- n_rows,
565
- n_cols,
566
- offset,
567
- casting_mode,
568
- elementwise_affine=elementwise_affine,
569
- BLOCK_SIZE=BLOCK_SIZE,
570
- num_warps=num_warps,
571
- **kernel_args, # XPU-specific optimization
572
- )
573
- dX = dX.view(*shape)
574
-
575
- if elementwise_affine:
576
- dW = _dW.sum(dim=0).to(W.dtype)
577
- else:
578
- dW = None
579
-
580
- return dX, dW
581
-
582
-
583
- class LigerRMSNormFunction(torch.autograd.Function):
584
- """
585
- Performs RMSNorm (Root Mean Square Normalization), which normalizes the input tensor `X` using the
586
- weight tensor `W`, with an optional offset and casting mode.
587
-
588
- Some models use an 'offset' to shift the weight tensor `W` by a constant value. For example, Gemma
589
- uses an offset of 1.0, so the computation becomes `(X / RMS(X)) * (W + 1.0)` instead of the usual
590
- `(X / RMS(X)) * W`. You can pass the offset value as an argument to the forward function.
591
-
592
- In addition, different models cast their inputs at different places during RMSNorm computation. For
593
- example, Gemma casts everything to fp32 nefore starting the computation, while Llama casts only the
594
- inverse RMS to fp32. You can specify the casting mode using the `casting_mode` argument. We currently
595
- support the following casting modes (they match HuggingFace Transformers' implementations):
596
- - 'llama': matches the Llama implementation, where only the inverse RMS is computed on fp32.
597
- - 'gemma': matches the Gemma implementation, where everything is cast to fp32, then computed, then cast back to the original dtype.
598
- - 'none': no casting is done. The computation is done in the original dtype. This saves memory and is slightly faster, but has more error w.r.t. the original implementation.
599
-
600
- `in_place` option means whether to in_place modify dY to store dX. This is default to `True` to save memory. However, under certain cases, it can produce incorrect inputs.
601
- For example, gemma2 uses two rmsnorm sequentially with residual in between. The resesidual part needs dY so it cannot be modified in-place.
602
- Therefore, for the patching of RMSNorm in gemma2, we set `in_place` to `False`
603
- """
604
-
605
- @staticmethod
606
- @ensure_contiguous
607
- def forward(ctx, X, W, eps, offset=0.0, casting_mode="llama", in_place=True, row_mode=None):
608
- """
609
- X: (B, T, H) or (BxT, H)
610
- W: (H,)
611
- """
612
- if isinstance(X, torch.distributed.tensor.DTensor):
613
- # Input tensor is output of a tensor parallel module and
614
- # needs to be gathered to a local tensor to compute
615
- # RMSE layer norm on each TP worker.
616
- # TODO: support CP.
617
- X = X.full_tensor()
618
-
619
- Y, X, RSTD, BLOCK_SIZE, num_warps, casting_mode = rms_norm_forward(X, W, eps, offset, casting_mode, row_mode)
620
- ctx.offset = offset
621
- ctx.casting_mode = casting_mode
622
- ctx.in_place = in_place
623
- ctx.row_mode = row_mode
624
- ctx.BLOCK_SIZE = BLOCK_SIZE
625
- ctx.num_warps = num_warps
626
- ctx.elementwise_affine = W is not None
627
- if W is not None:
628
- ctx.save_for_backward(X, W, RSTD)
629
- else:
630
- ctx.save_for_backward(X, RSTD)
631
- return Y
632
-
633
- @staticmethod
634
- @ensure_contiguous
635
- def backward(ctx, dY):
636
- """
637
- Y: (B, T, H) or (BxT, H)
638
- """
639
- if ctx.elementwise_affine:
640
- X, W, RSTD = ctx.saved_tensors
641
- else:
642
- X, RSTD = ctx.saved_tensors
643
- W = None
644
-
645
- if isinstance(dY, torch.distributed.tensor.DTensor):
646
- # Gradients are output of a tensor parallel module and
647
- # needs to be gathered to a local tensor for computing RMSE layer.
648
- # TODO: support CP.
649
- dY = dY.full_tensor()
650
-
651
- dX, dW = rms_norm_backward(
652
- dY, X, W, RSTD, ctx.offset, ctx.casting_mode, ctx.BLOCK_SIZE, ctx.num_warps, ctx.in_place, ctx.row_mode
653
- )
654
- return dX, dW, None, None, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/rope.py DELETED
@@ -1,239 +0,0 @@
1
- import torch
2
- import triton
3
- import triton.language as tl
4
-
5
-
6
- @triton.jit
7
- def _triton_rope(
8
- q_ptr,
9
- q_row_stride,
10
- k_ptr,
11
- k_row_stride,
12
- cos,
13
- cos_row_stride,
14
- sin,
15
- sin_row_stride,
16
- sl,
17
- bs: tl.constexpr,
18
- cos_bs: tl.constexpr,
19
- n_qh: tl.constexpr,
20
- n_kh: tl.constexpr,
21
- hd: tl.constexpr,
22
- pad_n_qh: tl.constexpr,
23
- pad_n_kh: tl.constexpr,
24
- pad_hd: tl.constexpr,
25
- BLOCK_SIZE: tl.constexpr,
26
- BACKWARD_PASS: tl.constexpr = False,
27
- ):
28
- # q size: (bsz, seq_len, num_q_heads, head_dim)
29
- # q stride: (seq_len * num_q_heads * head_dim, num_q_heads * head_dim, head_dim, 1)
30
- # k size: (bsz, seq_len, num_kv_heads, head_dim)
31
- # k stride: (seq_len * num_kv_heads * head_dim, num_kv_heads * head_dim, head_dim, 1)
32
-
33
- # cos size: (1, seq_len, head_dim) or (bsz, seq_len, head_dim)
34
- # stride: (seq_len * head_dim, head_dim, 1)
35
- pid = tl.program_id(0).to(tl.int64)
36
-
37
- # locate start address
38
- q_ptr = q_ptr + pid * q_row_stride
39
- k_ptr = k_ptr + pid * k_row_stride
40
-
41
- # ####################################################################
42
- # get the cos(mθ_{i...d/2}) and sin(mθ_{i...d/2}) for token position
43
- # m of this program instance
44
- # ####################################################################
45
-
46
- # 1. program instances are laid out in a 1D vector of size bsz * seq_len, which
47
- # effectively represents a 2D grid of size [bsz, seq_len] with seq_len dimension
48
- # being the fastest changing dimension. Thus we can simply do pid // sl to get the batch index
49
- # and pid % sl to get the sequence index.
50
- # 2. We only need the left half of cos and sin matrix because the right half is just
51
- # a clone of the left half.
52
- batch_idx = pid // sl
53
- cos_row_idx = pid % sl
54
- cos = cos + tl.where(
55
- cos_bs == 1,
56
- cos_row_idx * cos_row_stride,
57
- batch_idx * (sl * cos_row_stride) + cos_row_idx * cos_row_stride,
58
- )
59
- sin = sin + tl.where(
60
- cos_bs == 1,
61
- cos_row_idx * sin_row_stride,
62
- batch_idx * (sl * sin_row_stride) + cos_row_idx * sin_row_stride,
63
- )
64
-
65
- cos_offsets = tl.arange(0, pad_hd // 2)
66
- cos_mask = cos_offsets < hd // 2
67
- cos_row = tl.load(cos + cos_offsets, mask=cos_mask, other=0)
68
- sin_row = tl.load(sin + cos_offsets, mask=cos_mask, other=0)
69
-
70
- # ####################################################################
71
- # Load the left and right half of q and k for the current
72
- # program instance (i.e. for the current token) separately
73
- # ####################################################################
74
- # left half of the head
75
- first_half_q_offsets = tl.arange(0, pad_n_qh)[:, None] * hd + tl.arange(0, pad_hd // 2)[None, :]
76
- first_half_k_offsets = tl.arange(0, pad_n_kh)[:, None] * hd + tl.arange(0, pad_hd // 2)[None, :]
77
- first_q_mask = (tl.arange(0, pad_n_qh)[:, None] < n_qh) & (tl.arange(0, pad_hd // 2)[None, :] < hd // 2)
78
- first_k_mask = (tl.arange(0, pad_n_kh)[:, None] < n_kh) & (tl.arange(0, pad_hd // 2)[None, :] < hd // 2)
79
- q_tile_1 = tl.load(q_ptr + first_half_q_offsets, mask=first_q_mask, other=0).to(sin_row.dtype)
80
- k_tile_1 = tl.load(k_ptr + first_half_k_offsets, mask=first_k_mask, other=0).to(sin_row.dtype)
81
-
82
- # right half of the head
83
- second_half_q_offsets = first_half_q_offsets + (hd // 2)
84
- second_half_k_offsets = first_half_k_offsets + (hd // 2)
85
- second_q_mask = first_q_mask
86
- second_k_mask = first_k_mask
87
- q_tile_2 = tl.load(q_ptr + second_half_q_offsets, mask=second_q_mask, other=0).to(sin_row.dtype)
88
- k_tile_2 = tl.load(k_ptr + second_half_k_offsets, mask=second_k_mask, other=0).to(sin_row.dtype)
89
-
90
- if not BACKWARD_PASS:
91
- # y = [x1, x2] * [cos, cos] + [-x2, x1] * [sin, sin]
92
- new_q_tile_1 = q_tile_1 * cos_row - q_tile_2 * sin_row
93
- tl.store(q_ptr + first_half_q_offsets, new_q_tile_1, mask=first_q_mask)
94
- new_q_tile_2 = q_tile_2 * cos_row + q_tile_1 * sin_row
95
- tl.store(q_ptr + second_half_q_offsets, new_q_tile_2, mask=second_q_mask)
96
-
97
- new_k_tile_1 = k_tile_1 * cos_row - k_tile_2 * sin_row
98
- tl.store(k_ptr + first_half_k_offsets, new_k_tile_1, mask=first_k_mask)
99
- new_k_tile_2 = k_tile_2 * cos_row + k_tile_1 * sin_row
100
- tl.store(k_ptr + second_half_k_offsets, new_k_tile_2, mask=second_k_mask)
101
- else:
102
- # with some math, we can get:
103
- # dy = [dx1, dx2] * [cos, cos] + [-dx2, dx1] * [-sin, -sin]
104
- new_q_tile_1 = q_tile_1 * cos_row + q_tile_2 * sin_row
105
- tl.store(q_ptr + first_half_q_offsets, new_q_tile_1, mask=first_q_mask)
106
- new_q_tile_2 = q_tile_2 * cos_row - q_tile_1 * sin_row
107
- tl.store(q_ptr + second_half_q_offsets, new_q_tile_2, mask=second_q_mask)
108
-
109
- new_k_tile_1 = k_tile_1 * cos_row + k_tile_2 * sin_row
110
- tl.store(k_ptr + first_half_k_offsets, new_k_tile_1, mask=first_k_mask)
111
- new_k_tile_2 = k_tile_2 * cos_row - k_tile_1 * sin_row
112
- tl.store(k_ptr + second_half_k_offsets, new_k_tile_2, mask=second_k_mask)
113
-
114
-
115
- def rope_forward(q, k, cos, sin):
116
- # transpose it back to the physical shape because Triton looks at the physical storage
117
- # note: q and k are incontiguous before the transformation and will become contiguous after transpose
118
- q = q.transpose(1, 2)
119
- k = k.transpose(1, 2)
120
-
121
- batch_size, seq_len, n_q_head, head_dim = q.shape
122
- n_kv_head = k.shape[2]
123
- pad_hd = triton.next_power_of_2(head_dim)
124
- pad_n_q_head = triton.next_power_of_2(n_q_head)
125
- pad_n_kv_head = triton.next_power_of_2(n_kv_head)
126
- BLOCK_SIZE = max(pad_n_q_head, pad_n_kv_head)
127
-
128
- n_row = batch_size * seq_len
129
-
130
- # ensure tensors passed into the kernel are contiguous. It will be no-op if they are already contiguous
131
- q = q.contiguous()
132
- k = k.contiguous()
133
- cos = cos.contiguous()
134
- sin = sin.contiguous()
135
- cos_batch_size = cos.shape[0]
136
-
137
- _triton_rope[(n_row,)](
138
- q,
139
- q.stride(1),
140
- k,
141
- k.stride(1),
142
- cos,
143
- cos.stride(-2),
144
- sin,
145
- sin.stride(-2),
146
- seq_len,
147
- batch_size,
148
- cos_batch_size,
149
- n_q_head,
150
- n_kv_head,
151
- head_dim,
152
- pad_n_q_head,
153
- pad_n_kv_head,
154
- pad_hd,
155
- BLOCK_SIZE=BLOCK_SIZE,
156
- BACKWARD_PASS=False,
157
- )
158
- return q.transpose(1, 2), k.transpose(1, 2), cos, sin
159
-
160
-
161
- def rope_backward(dq, dk, cos, sin):
162
- dq = dq.transpose(1, 2)
163
- dk = dk.transpose(1, 2)
164
-
165
- batch_size, seq_len, n_q_head, head_dim = dq.shape
166
- cos_batch_size = cos.shape[0]
167
- n_kv_head = dk.shape[2]
168
- pad_hd = triton.next_power_of_2(head_dim)
169
- pad_n_q_head = triton.next_power_of_2(n_q_head)
170
- pad_n_kv_head = triton.next_power_of_2(n_kv_head)
171
- BLOCK_SIZE = max(pad_n_q_head, pad_n_kv_head)
172
-
173
- n_row = batch_size * seq_len
174
-
175
- # ensure dq and dk are contiguous
176
- dq = dq.contiguous()
177
- dk = dk.contiguous()
178
-
179
- # backward is similar to forward except swapping few ops
180
- _triton_rope[(n_row,)](
181
- dq,
182
- dq.stride(1),
183
- dk,
184
- dk.stride(1),
185
- cos,
186
- cos.stride(-2),
187
- sin,
188
- sin.stride(-2),
189
- seq_len,
190
- batch_size,
191
- cos_batch_size,
192
- n_q_head,
193
- n_kv_head,
194
- head_dim,
195
- pad_n_q_head,
196
- pad_n_kv_head,
197
- pad_hd,
198
- BLOCK_SIZE=BLOCK_SIZE,
199
- BACKWARD_PASS=True,
200
- )
201
- return dq.transpose(1, 2), dk.transpose(1, 2)
202
-
203
-
204
- class LigerRopeFunction(torch.autograd.Function):
205
- """
206
- Triton implementation of the Rotary Positional Embedding (RoPE) operation. Please note that
207
- this implements the HuggingFace Llama & Mistral version, whose rotation matrix is slightly different
208
- than the original RoPE paper.
209
-
210
- Please find the corresponding HuggingFace implementation here:
211
- https://github.com/huggingface/transformers/blob/v4.40.2/src/transformers/models/llama/modeling_llama.py#L184
212
-
213
- For more details about the rotation matrix used here, please refer to:
214
- https://discuss.huggingface.co/t/is-llama-rotary-embedding-implementation-correct/44509/2
215
- """
216
-
217
- @staticmethod
218
- def forward(ctx, q, k, cos, sin, position_ids=None, unsqueeze_dim=1):
219
- """
220
- q size: (bsz, n_q_head, seq_len, head_dim)
221
- k size: (bsz, n_kv_head, seq_len, head_dim)
222
- cos size: (1, seq_len, head_dim) or (bsz, seq_len, head_dim)
223
- sin size: (1, seq_len, head_dim) or (bsz, seq_len, head_dim)
224
- """
225
- q, k, cos, sin = rope_forward(q, k, cos, sin)
226
- ctx.save_for_backward(cos, sin)
227
- return q, k
228
-
229
- def backward(ctx, dq, dk):
230
- """
231
- dq size: (bsz, n_q_head, seq_len, head_dim)
232
- dk size: (bsz, n_kv_head, seq_len, head_dim)
233
- cos size: (1, seq_len, head_dim) or (bsz, seq_len, head_dim)
234
- sin size: (1, seq_len, head_dim) or (bsz, seq_len, head_dim)
235
- """
236
-
237
- cos, sin = ctx.saved_tensors
238
- dq, dk = rope_backward(dq, dk, cos, sin)
239
- return dq, dk, None, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/swiglu.py DELETED
@@ -1,176 +0,0 @@
1
- import torch
2
- import triton
3
- import triton.language as tl
4
-
5
- from .utils import calculate_settings
6
- from .utils import ensure_contiguous
7
-
8
-
9
- @triton.jit
10
- def silu(x):
11
- return x * tl.sigmoid(x)
12
-
13
-
14
- @triton.jit
15
- def _swiglu_forward_kernel(
16
- a_ptr, b_ptr, c_ptr, stride, gate_multiplier, n_cols: tl.constexpr, BLOCK_SIZE: tl.constexpr
17
- ):
18
- program_id = tl.program_id(0).to(tl.int64)
19
-
20
- # locate start index
21
- a_ptr += program_id * stride
22
- b_ptr += program_id * stride
23
- c_ptr += program_id * stride
24
-
25
- col_offsets = tl.arange(0, BLOCK_SIZE)
26
- mask = col_offsets < n_cols
27
-
28
- # sigmoid requires type float32
29
- a_row = tl.load(a_ptr + col_offsets, mask=mask, other=0).to(tl.float32) * gate_multiplier
30
- b_row = tl.load(b_ptr + col_offsets, mask=mask, other=0)
31
- c_row = silu(a_row).cast(b_row.dtype) * b_row
32
- tl.store(c_ptr + col_offsets, c_row, mask=mask)
33
-
34
-
35
- @triton.jit
36
- def _swiglu_backward_kernel(
37
- dc_ptr, a_ptr, b_ptr, stride, gate_multiplier, n_cols: tl.constexpr, BLOCK_SIZE: tl.constexpr
38
- ):
39
- program_id = tl.program_id(0).to(tl.int64)
40
-
41
- # locate start index
42
- dc_ptr += program_id * stride
43
- a_ptr += program_id * stride
44
- b_ptr += program_id * stride
45
-
46
- col_offsets = tl.arange(0, BLOCK_SIZE)
47
- mask = col_offsets < n_cols
48
-
49
- dc_row = tl.load(dc_ptr + col_offsets, mask=mask, other=0)
50
- # sigmoid requires type float32
51
- a_row = tl.load(a_ptr + col_offsets, mask=mask, other=0).to(tl.float32) * gate_multiplier
52
- b_row = tl.load(b_ptr + col_offsets, mask=mask, other=0)
53
-
54
- # recomputation to save memory. a_row already holds a * gate_multiplier.
55
- sig_a = tl.sigmoid(a_row)
56
- silu_a = a_row * sig_a
57
- db_row = dc_row * silu_a
58
- # chain rule pulls an extra factor of gate_multiplier through the pre-activation scaling
59
- da_row = dc_row * (silu_a * (1 - sig_a) + sig_a) * b_row * gate_multiplier
60
-
61
- tl.store(a_ptr + col_offsets, da_row, mask=mask)
62
- tl.store(b_ptr + col_offsets, db_row, mask=mask)
63
-
64
-
65
- def swiglu_forward(a, b, gate_multiplier: float = 1.0):
66
- ori_shape = a.shape
67
-
68
- n_cols = ori_shape[-1]
69
- a = a.view(-1, n_cols)
70
- b = b.view(-1, n_cols)
71
- c = torch.empty_like(a)
72
- n_rows = a.shape[0]
73
-
74
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
75
-
76
- _swiglu_forward_kernel[(n_rows,)](
77
- a,
78
- b,
79
- c,
80
- c.stride(-2),
81
- float(gate_multiplier),
82
- n_cols=n_cols,
83
- BLOCK_SIZE=BLOCK_SIZE,
84
- num_warps=num_warps,
85
- )
86
- return a, b, c.view(*ori_shape)
87
-
88
-
89
- def swiglu_backward(a, b, dc, gate_multiplier: float = 1.0):
90
- ori_shape = dc.shape
91
- n_cols = ori_shape[-1]
92
- dc = dc.view(-1, n_cols)
93
- n_rows = dc.shape[0]
94
-
95
- BLOCK_SIZE, num_warps = calculate_settings(n_cols)
96
-
97
- _swiglu_backward_kernel[(n_rows,)](
98
- dc,
99
- a,
100
- b,
101
- dc.stride(-2),
102
- float(gate_multiplier),
103
- n_cols=n_cols,
104
- BLOCK_SIZE=BLOCK_SIZE,
105
- num_warps=num_warps,
106
- )
107
- return a.view(*ori_shape), b.view(*ori_shape)
108
-
109
-
110
- class LigerSiLUMulFunction(torch.autograd.Function):
111
- @staticmethod
112
- @ensure_contiguous
113
- def forward(ctx, a, b, gate_multiplier: float = 1.0, down_multiplier: float = 1.0):
114
- gate_multiplier = float(gate_multiplier)
115
- down_multiplier = float(down_multiplier)
116
- ctx.gate_multiplier = gate_multiplier
117
- ctx.down_multiplier = down_multiplier
118
-
119
- if isinstance(a, torch.distributed.tensor.DTensor) or isinstance(b, torch.distributed.tensor.DTensor):
120
- device_mesh, placements = (
121
- (a.device_mesh, a.placements)
122
- if isinstance(a, torch.distributed.tensor.DTensor)
123
- else (b.device_mesh, b.placements)
124
- )
125
-
126
- # Assume that full tensors are gathered before and identical across
127
- # the associated process groups.
128
- if not isinstance(a, torch.distributed.tensor.DTensor):
129
- a = torch.distributed.tensor.distribute_tensor(a, device_mesh=device_mesh, placements=placements)
130
- if not isinstance(b, torch.distributed.tensor.DTensor):
131
- b = torch.distributed.tensor.distribute_tensor(b, device_mesh=device_mesh, placements=placements)
132
- a_local, b_local, c_local = swiglu_forward(a.to_local(), b.to_local(), gate_multiplier)
133
- if down_multiplier != 1.0:
134
- c_local = c_local * down_multiplier
135
- ctx.save_for_backward(a_local, b_local)
136
- ctx.dtensor_metadata = (device_mesh, placements)
137
- return torch.distributed.tensor.DTensor.from_local(c_local, device_mesh, placements)
138
- else:
139
- a, b, c = swiglu_forward(a, b, gate_multiplier)
140
- if down_multiplier != 1.0:
141
- c = c * down_multiplier
142
- ctx.save_for_backward(a, b)
143
- ctx.dtensor_metadata = None
144
- return c
145
-
146
- @staticmethod
147
- @ensure_contiguous
148
- def backward(ctx, dc):
149
- a, b = ctx.saved_tensors
150
- gate_multiplier = ctx.gate_multiplier
151
- down_multiplier = ctx.down_multiplier
152
-
153
- if ctx.dtensor_metadata is not None:
154
- device_mesh, placements = ctx.dtensor_metadata
155
-
156
- # Assume that full tensors are gathered before and identical across
157
- # the associated process groups.
158
- dc_local = (
159
- dc.to_local()
160
- if isinstance(dc, torch.distributed.tensor.DTensor)
161
- else torch.distributed.tensor.distribute_tensor(dc, device_mesh=device_mesh, placements=placements)
162
- )
163
- if down_multiplier != 1.0:
164
- dc_local = dc_local * down_multiplier
165
- a_local, b_local = swiglu_backward(a, b, dc_local, gate_multiplier)
166
- return (
167
- torch.distributed.tensor.DTensor.from_local(a_local, device_mesh, placements),
168
- torch.distributed.tensor.DTensor.from_local(b_local, device_mesh, placements),
169
- None,
170
- None,
171
- )
172
-
173
- if down_multiplier != 1.0:
174
- dc = dc * down_multiplier
175
- a, b = swiglu_backward(a, b, dc, gate_multiplier)
176
- return a, b, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/tiled_mlp.py DELETED
@@ -1,136 +0,0 @@
1
- import math
2
-
3
- from typing import Callable
4
- from typing import List
5
- from typing import Optional
6
-
7
- import torch
8
-
9
- from .utils import ensure_contiguous
10
-
11
-
12
- class LigerTiledMLPFunction(torch.autograd.Function):
13
- """
14
- Based on DeepSpeed's TiledMLP:
15
- https://github.com/deepspeedai/DeepSpeed/blob/v0.18.2/deepspeed/runtime/sequence_parallel/ulysses_sp.py#L838
16
-
17
- Perform a tiled MLP computation to massively reduce memory usage needed to compute MLP
18
- when using very long sequence lengths.
19
-
20
- This module re-computes `forward` in the `backward`. So the `forward` occurs twice each iteration.
21
- And if you're using activation checkpointing it then occurs thrice.
22
-
23
- Args:
24
- fn: the function to call on sharded inputs (e.g., mlp.forward)
25
- mlp_module: the MLP nn.Module object
26
- x: the input to MLP.forward (hidden_states)
27
- shards: how many shards to use
28
- compute_params: a list of weights engaged in the compute
29
-
30
- Returns:
31
- the computed hidden_states
32
- """
33
-
34
- @staticmethod
35
- @ensure_contiguous
36
- def forward(
37
- ctx,
38
- fn: Callable,
39
- mlp_module: torch.nn.Module,
40
- x: torch.Tensor,
41
- shards: int,
42
- compute_params: Optional[List[torch.nn.Parameter]] = None,
43
- ) -> torch.Tensor:
44
- ctx.fn = fn
45
- ctx.mlp_module = mlp_module
46
- ctx.shards = shards
47
- ctx.save_for_backward(x)
48
-
49
- # x.shape could be [bs, seqlen, hidden_size] or [seqlen, hidden_size] (moe experts)
50
- x_shards = list(torch.chunk(x, chunks=shards, dim=-2))
51
- with torch.no_grad():
52
- output_shards = [fn(mlp_module, x_shard) for x_shard in x_shards]
53
- output_unsharded = torch.cat(output_shards, dim=-2)
54
-
55
- return output_unsharded
56
-
57
- @staticmethod
58
- @ensure_contiguous
59
- def backward(ctx, *grads) -> tuple:
60
- fn = ctx.fn
61
- (x,) = ctx.saved_tensors
62
- mlp_module = ctx.mlp_module
63
- shards = ctx.shards
64
-
65
- x_requires_grad = x.requires_grad
66
- x = x.detach()
67
- # detach() unsets x.requires_grad, so restore it
68
- x.requires_grad_(x_requires_grad)
69
-
70
- # x.shape could be [bs, seqlen, hidden_size] or [seqlen, hidden_size] (moe experts)
71
- hidden_size = x.shape[-1]
72
- x_shape_orig = x.shape
73
-
74
- # flatten bs+seqlen to avoid having stride issues when narrowing into seqlen w/ bs>1
75
- x = x.view(-1, hidden_size)
76
- incoming_grad = grads[0].view(-1, hidden_size)
77
- x_grad = torch.zeros_like(x)
78
-
79
- x_shards = list(torch.chunk(x, chunks=shards, dim=0))
80
-
81
- for i, x_shard in enumerate(x_shards):
82
- x_shard.requires_grad_(x_requires_grad)
83
-
84
- # if seqlen is not exactly divisible by shards the last step will be shorter than shard_step
85
- shard_step = x_shards[i].shape[0]
86
- shard_offset = i * x_shards[0].shape[0]
87
-
88
- x_shard.grad = x_grad.narrow(0, shard_offset, shard_step).view_as(x_shard)
89
- incoming_grad_shard = incoming_grad.narrow(0, shard_offset, shard_step).view_as(x_shard)
90
-
91
- with torch.enable_grad():
92
- output = fn(mlp_module, x_shard)
93
- torch.autograd.backward(output, incoming_grad_shard)
94
-
95
- # unflatten
96
- x_grad = x_grad.view(x_shape_orig)
97
-
98
- return (None, None, x_grad, None, None)
99
-
100
-
101
- def apply_tiled_mlp(
102
- fn: Callable,
103
- mlp_module: torch.nn.Module,
104
- x: torch.Tensor,
105
- num_shards: Optional[int] = None,
106
- compute_params: Optional[List[torch.nn.Parameter]] = None,
107
- ) -> torch.Tensor:
108
- """
109
- Apply tiled MLP computation for memory efficiency.
110
-
111
- Args:
112
- fn: the function to call on sharded inputs (e.g., lambda module, x: module(x))
113
- mlp_module: the MLP nn.Module object
114
- x: the input tensor with shape [bs, seqlen, hidden_size] or [seqlen, hidden_size]
115
- num_shards: number of shards to use. If None, automatically calculated as ceil(seqlen / hidden_size)
116
- compute_params: list of parameters for DeepSpeed ZeRO optimization
117
-
118
- Returns:
119
- output tensor with the same shape as input
120
- """
121
- if num_shards is None:
122
- # x.shape could be [bs, seqlen, hidden_size] or [seqlen, hidden_size]
123
- hidden_size = x.shape[-1]
124
- seqlen = x.shape[-2]
125
- num_shards = math.ceil(seqlen / hidden_size)
126
-
127
- # Ensure num_shards is at least 1
128
- num_shards = max(1, num_shards)
129
-
130
- return LigerTiledMLPFunction.apply(
131
- fn,
132
- mlp_module,
133
- x,
134
- num_shards,
135
- compute_params,
136
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/tvd.py DELETED
@@ -1,218 +0,0 @@
1
- from typing import Literal
2
- from typing import Optional
3
-
4
- import torch
5
- import triton
6
- import triton.language as tl
7
-
8
- from .utils import ensure_contiguous
9
-
10
- MAX_FUSED_SIZE = 65536 // 4
11
-
12
- REDUCTION_LITERAL = Literal["none", "sum", "mean", "batchmean"]
13
-
14
- _REDUCTION_MODE_NONE = tl.constexpr(0)
15
- _REDUCTION_MODE_SUM = tl.constexpr(1)
16
- _REDUCTION_MODE_MEAN = tl.constexpr(2)
17
- _REDUCTION_MODE_BATCHMEAN = tl.constexpr(3)
18
-
19
- _str_to_reduction_mode = {
20
- "none": _REDUCTION_MODE_NONE.value,
21
- "sum": _REDUCTION_MODE_SUM.value,
22
- "mean": _REDUCTION_MODE_MEAN.value,
23
- "batchmean": _REDUCTION_MODE_BATCHMEAN.value,
24
- }
25
-
26
-
27
- def get_num_warps(BLOCK_SIZE):
28
- num_warps = 4
29
- if BLOCK_SIZE >= 32768:
30
- num_warps = 32
31
- elif BLOCK_SIZE >= 8192:
32
- num_warps = 16
33
- elif BLOCK_SIZE >= 2048:
34
- num_warps = 8
35
-
36
- return num_warps
37
-
38
-
39
- @triton.jit
40
- def _tv_distance_kernel(
41
- p_ptr,
42
- p_stride,
43
- q_ptr,
44
- q_stride,
45
- loss_ptr,
46
- loss_stride,
47
- grads_ptr,
48
- grads_stride,
49
- label_ptr,
50
- ignore_index: tl.constexpr,
51
- n_cols,
52
- scale, # pre-computed reduction scale for gradients (fused into kernel)
53
- BLOCK_SIZE: tl.constexpr,
54
- HAS_LABEL: tl.constexpr,
55
- reduction: tl.constexpr = _REDUCTION_MODE_BATCHMEAN,
56
- ):
57
- pid = tl.program_id(0).to(tl.int64)
58
- p_ptr += pid * p_stride
59
- q_ptr += pid * q_stride
60
- loss_ptr += pid * loss_stride
61
- grads_ptr += pid * grads_stride
62
- label_ptr += pid
63
-
64
- base_offsets = tl.arange(0, BLOCK_SIZE)
65
-
66
- if HAS_LABEL:
67
- label = tl.load(label_ptr)
68
- if label == ignore_index:
69
- for i in range(0, n_cols, BLOCK_SIZE):
70
- offsets = i + base_offsets
71
- mask = offsets < n_cols
72
- tl.store(grads_ptr + offsets, 0.0, mask=mask)
73
- if reduction == _REDUCTION_MODE_NONE:
74
- tl.store(loss_ptr + offsets, 0.0, mask=mask)
75
- return
76
-
77
- loss_sum = 0.0
78
- for i in range(0, n_cols, BLOCK_SIZE):
79
- offsets = i + base_offsets
80
- mask = offsets < n_cols
81
-
82
- p = tl.load(p_ptr + offsets, mask=mask, other=0.0)
83
- q = tl.load(q_ptr + offsets, mask=mask, other=0.0)
84
-
85
- # TVD(P || Q) = 0.5 * |P - Q|
86
- tv_loss = 0.5 * tl.abs(p - q)
87
-
88
- # Fuse reduction scaling into gradient computation (eliminates separate Python division)
89
- grad_res = tl.where(p > q, 0.5 * scale, -0.5 * scale)
90
-
91
- tl.store(grads_ptr + offsets, grad_res, mask=mask)
92
-
93
- if reduction == _REDUCTION_MODE_NONE:
94
- tl.store(loss_ptr + offsets, tv_loss, mask=mask)
95
- else:
96
- loss_sum += tl.sum(tv_loss, axis=0)
97
-
98
- if reduction != _REDUCTION_MODE_NONE:
99
- # Fuse reduction scaling into loss (same scale as gradients; avoids Python division)
100
- tl.store(loss_ptr, loss_sum * scale)
101
-
102
-
103
- def tv_distance_forward_triton(p, q, shift_labels, reduction, ignore_index, has_label):
104
- BT, V = p.shape
105
-
106
- BLOCK_SIZE = min(MAX_FUSED_SIZE, triton.next_power_of_2(V))
107
- num_warps = get_num_warps(BLOCK_SIZE)
108
-
109
- grid = (BT,)
110
-
111
- reduction = _str_to_reduction_mode[reduction]
112
-
113
- out_size = (BT, V) if reduction == _REDUCTION_MODE_NONE.value else (BT,)
114
- output_tensor = torch.zeros(out_size, device=p.device, dtype=torch.float32)
115
- grads = torch.empty_like(p)
116
-
117
- n_non_ignore = (shift_labels != ignore_index).sum().item() if has_label else BT
118
-
119
- # Pre-compute gradient scale factor (fused into kernel to avoid separate division)
120
- if reduction == _REDUCTION_MODE_BATCHMEAN.value:
121
- scale = 1.0 / n_non_ignore
122
- elif reduction == _REDUCTION_MODE_MEAN.value:
123
- scale = 1.0 / (n_non_ignore * V)
124
- else:
125
- scale = 1.0
126
-
127
- _tv_distance_kernel[grid](
128
- p,
129
- p.stride(0),
130
- q,
131
- q.stride(0),
132
- output_tensor,
133
- output_tensor.stride(0),
134
- grads,
135
- grads.stride(0),
136
- shift_labels if has_label else torch.empty(1, device=p.device),
137
- ignore_index,
138
- V,
139
- scale,
140
- BLOCK_SIZE=BLOCK_SIZE,
141
- HAS_LABEL=has_label,
142
- num_warps=num_warps,
143
- reduction=reduction,
144
- )
145
-
146
- # Loss and gradients are already scaled inside the kernel — no separate division needed
147
- if reduction in (_REDUCTION_MODE_BATCHMEAN.value, _REDUCTION_MODE_MEAN.value):
148
- return output_tensor.sum(), grads
149
- elif reduction == _REDUCTION_MODE_SUM.value:
150
- return output_tensor.sum(dim=0), grads
151
- else:
152
- return output_tensor, grads
153
-
154
-
155
- def tvd_backward_triton(grad_output, grads):
156
- # If cross entropy is the last layer, grad_output is 1.0. Skip the mul then.
157
- if torch.equal(grad_output, torch.tensor(1.0, device=grad_output.device)):
158
- return grads
159
-
160
- return grads * grad_output
161
-
162
-
163
- class LigerTVDLossFunction(torch.autograd.Function):
164
- """
165
- Class implementing the forward and backward pass for the Total Variation Distance Loss using Triton.
166
- """
167
-
168
- @staticmethod
169
- @ensure_contiguous
170
- def forward(
171
- ctx,
172
- p: torch.Tensor,
173
- q: torch.Tensor,
174
- shift_labels: Optional[torch.Tensor] = None,
175
- reduction: REDUCTION_LITERAL = "batchmean",
176
- ignore_index: int = -100,
177
- ) -> torch.Tensor:
178
- """A forward pass for the Total Variation Distance Loss.
179
-
180
- Args:
181
- ctx: Torch autograd context
182
- p (torch.Tensor): A tensor of shape (BT, V) containing the first distribution.
183
- q (torch.Tensor): A tensor of shape (BT, V) containing the second distribution.
184
- shift_labels (Optional[torch.Tensor]): A tensor of shape (BT,) containing the labels.
185
- reduction (REDUCTION_LITERAL, optional): The reduction method to be applied. Defaults to "batchmean".
186
- ignore_index (int, optional): The index to ignore during loss calculation. Defaults to -100.
187
-
188
- Returns:
189
- torch.Tensor: The computed Total Variation Distance Loss.
190
- """
191
- has_label = False
192
- if shift_labels is not None:
193
- assert shift_labels.shape == (p.shape[0],), (
194
- f"the shape of shift_labels must be (BT,). Got: {shift_labels.shape}"
195
- )
196
- shift_labels = shift_labels.contiguous()
197
- has_label = True
198
-
199
- loss, grads = tv_distance_forward_triton(p, q, shift_labels, reduction, ignore_index, has_label)
200
- ctx.save_for_backward(grads)
201
- return loss
202
-
203
- @staticmethod
204
- @ensure_contiguous
205
- def backward(ctx, grad_output: torch.Tensor) -> torch.Tensor:
206
- """A backward pass for the Total Variation Distance Loss.
207
-
208
- Args:
209
- ctx: Torch autograd context
210
- grad_output (torch.Tensor): The gradient of the loss with respect to the output.
211
-
212
- Returns:
213
- tuple[torch.Tensor, None, None, None, None]: The gradient of the loss with respect to the inputs.
214
- """
215
- (grads,) = ctx.saved_tensors
216
- grads = tvd_backward_triton(grad_output, grads)
217
-
218
- return grads, None, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
build/torch-xpu/utils.py DELETED
@@ -1,176 +0,0 @@
1
- """
2
- This file incorporates code from Unsloth licensed under the Apache License, Version 2.0.
3
- See the original Unsloth repository at https://github.com/unslothai/unsloth.
4
-
5
- The following line
6
- https://github.com/linkedin/Liger-Kernel/blob/7382a8761f9af679482b968f9348013d933947c7/src/liger_kernel/ops/utils.py#L23
7
- is based on code from Unsloth, located at:
8
- https://github.com/unslothai/unsloth/blob/fd753fed99ed5f10ef8a9b7139588d9de9ddecfb/unsloth/kernels/utils.py#L43
9
-
10
- Modifications made by Yanning Chen, 2024.
11
- """
12
-
13
- import functools
14
- import importlib
15
- import operator
16
-
17
- from typing import Callable
18
-
19
- import torch
20
- import triton
21
- import triton.language as tl
22
-
23
- from packaging.version import Version
24
-
25
-
26
- def is_npu_available() -> bool:
27
- """Detect Ascend NPU availability."""
28
- try:
29
- from transformers.utils import is_torch_npu_available
30
-
31
- return is_torch_npu_available()
32
- except Exception:
33
- return False
34
-
35
-
36
- def infer_device():
37
- """
38
- Get current device name based on available devices
39
- """
40
- if torch.cuda.is_available(): # Works for both Nvidia and AMD
41
- return "cuda"
42
- # Use Ascend NPU if available (torch.npu)
43
- elif is_npu_available():
44
- return "npu"
45
- # XPU (Intel) if available
46
- elif torch.xpu.is_available():
47
- return "xpu"
48
- else:
49
- return "cpu"
50
-
51
-
52
- def is_hip() -> bool:
53
- return torch.version.hip is not None
54
-
55
-
56
- def ensure_contiguous(fn):
57
- @functools.wraps(fn)
58
- def wrapper(ctx, *args, **kwargs):
59
- def maybe_to_contiguous(x):
60
- return x.contiguous() if isinstance(x, torch.Tensor) else x
61
-
62
- args = [maybe_to_contiguous(arg) for arg in args]
63
- kwargs = {k: maybe_to_contiguous(v) for k, v in kwargs.items()}
64
- return fn(ctx, *args, **kwargs)
65
-
66
- return wrapper
67
-
68
-
69
- def calculate_settings(n):
70
- # reference: https://github.com/unslothai/unsloth/blob/fd753fed99ed5f10ef8a9b7139588d9de9ddecfb/unsloth/kernels/utils.py#L43
71
-
72
- MAX_FUSED_SIZE = 65536
73
- BLOCK_SIZE = triton.next_power_of_2(n)
74
- if BLOCK_SIZE > MAX_FUSED_SIZE:
75
- raise RuntimeError(
76
- f"Cannot launch Triton kernel since n = {n} exceeds the recommended Triton blocksize = {MAX_FUSED_SIZE}."
77
- )
78
-
79
- num_warps = 4
80
- if BLOCK_SIZE >= 32768:
81
- num_warps = 32 if not is_hip() else 16
82
- elif BLOCK_SIZE >= 8192:
83
- num_warps = 16
84
- elif BLOCK_SIZE >= 2048:
85
- num_warps = 8
86
- return BLOCK_SIZE, num_warps
87
-
88
-
89
- def compare_version(package: str, operator: Callable, target: str):
90
- try:
91
- pkg = importlib.import_module(package)
92
- except ImportError:
93
- return False
94
- pkg_version = Version(pkg.__version__)
95
- return operator(pkg_version, Version(target))
96
-
97
-
98
- def get_amp_custom_fwd_bwd() -> Callable:
99
- device = infer_device()
100
- if compare_version("torch", operator.ge, "2.4.0"):
101
- return (
102
- functools.partial(torch.amp.custom_fwd, device_type=device),
103
- functools.partial(torch.amp.custom_bwd, device_type=device),
104
- )
105
- if hasattr(torch, "npu") and getattr(torch.npu, "amp", None) is not None:
106
- return torch.npu.amp.custom_fwd, torch.npu.amp.custom_bwd
107
- return torch.cuda.amp.custom_fwd, torch.cuda.amp.custom_bwd
108
-
109
-
110
- amp_custom_fwd, amp_custom_bwd = get_amp_custom_fwd_bwd()
111
-
112
-
113
- torch_to_triton_dtype = {
114
- torch.float32: tl.float32,
115
- torch.float16: tl.float16,
116
- torch.bfloat16: tl.bfloat16,
117
- }
118
-
119
-
120
- @triton.jit
121
- def element_mul_kernel(
122
- X_ptr,
123
- X_stride,
124
- grad_output_ptr,
125
- n_cols,
126
- BLOCK_SIZE: tl.constexpr,
127
- ):
128
- """
129
- This function multiplies each element of the tensor pointed by X_ptr with the value pointed by grad_output_ptr.
130
- The multiplication is performed in-place on the tensor pointed by X_ptr.
131
-
132
- Parameters:
133
- X_ptr: Pointer to the input tensor.
134
- X_stride (int): The stride of the input tensor.
135
- grad_output_ptr: Pointer to the gradient output value.
136
- n_cols (int): The number of columns in the input tensor.
137
- BLOCK_SIZE (int): The block size for Triton operations.
138
- """
139
-
140
- # Get the program ID and convert it to int64 to avoid overflow
141
- program_id = tl.program_id(0).to(tl.int64)
142
-
143
- # Locate the start index
144
- X_ptr += program_id * X_stride
145
-
146
- # Load the gradient output value
147
- grad_output = tl.load(grad_output_ptr)
148
-
149
- # Perform the element-wise multiplication
150
- for i in range(0, n_cols, BLOCK_SIZE):
151
- X_offsets = i + tl.arange(0, BLOCK_SIZE)
152
- X_block = tl.load(X_ptr + X_offsets, mask=X_offsets < n_cols)
153
- tl.store(X_ptr + X_offsets, X_block * grad_output, mask=X_offsets < n_cols)
154
-
155
-
156
- def get_npu_core_count(default: int = 20) -> int:
157
- """Return NPU vector core count.
158
- Fallback to `default` if Triton runtime or NPU device is unavailable.
159
- """
160
- try:
161
- utils = triton.runtime.driver.active.utils
162
- props = utils.get_device_properties(0)
163
- return int(props.get("num_vectorcore", default))
164
- except Exception:
165
- return default
166
-
167
-
168
- def set_large_grf_mode(kernel_args: dict):
169
- """Set large GRF mode for XPU devices."""
170
- # On XPU triton installed along with pytorch-xpu will be called `pytorch-triton-xpu`,
171
- # triton XPU installed from source will be called `triton`.
172
- if compare_version("pytorch-triton-xpu", operator.ge, "3.6.0") or compare_version("triton", operator.ge, "3.6.0"):
173
- kernel_args["grf_mode"] = "256"
174
- else:
175
- # API was changed in https://github.com/intel/intel-xpu-backend-for-triton/pull/5430
176
- kernel_args["grf_mode"] = "large"