Kernels
kernels-bot commited on
Commit
6d21923
·
verified ·
1 Parent(s): 187ffd2

Uploaded using `kernel-builder`.

Browse files
build/torch-xpu/__init__.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Triton ops vendored from `flash-attn` (`flash_attn/ops/triton` and
2
+ `flash_attn/losses`), packaged as a self-contained, `kernels`-compliant kernel.
3
+
4
+ Upstream: https://github.com/Dao-AILab/flash-attention
5
+ Pinned commit: b02b07e1a10238fe12831b80a8937ed59b1353a5
6
+
7
+ These ops are pure Triton + PyTorch: there is nothing to compile ahead of time,
8
+ and the package does not import `flash_attn` at runtime.
9
+ """
10
+
11
+ from .cross_entropy import cross_entropy_loss
12
+ from .losses import CrossEntropyLoss
13
+ from .rotary import apply_rotary
14
+ from .layer_norm import (
15
+ LayerNormFn,
16
+ RMSNorm,
17
+ layer_norm_fn,
18
+ layer_norm_linear_fn,
19
+ rms_norm_fn,
20
+ )
21
+
22
+ __all__ = [
23
+ # cross entropy
24
+ "cross_entropy_loss",
25
+ "CrossEntropyLoss",
26
+ # rotary
27
+ "apply_rotary",
28
+ # layer / rms norm
29
+ "layer_norm_fn",
30
+ "rms_norm_fn",
31
+ "layer_norm_linear_fn",
32
+ "LayerNormFn",
33
+ "RMSNorm",
34
+ ]
build/torch-xpu/_ops.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 = "flash_attn_ops"
25
+ unique_id = "507bf41"
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/_ops_compat.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Compatibility helpers for op namespacing in source and built layouts.
2
+
3
+ In the built (Hub) layout, kernel-builder generates an `_ops` module that
4
+ exposes `add_op_namespace_prefix`, which prefixes op names with a unique,
5
+ build-hashed namespace so custom ops never collide across kernels/versions. When
6
+ running directly from source there is no generated `_ops`, so we fall back to a
7
+ fixed namespace.
8
+ """
9
+
10
+ try:
11
+ from ._ops import add_op_namespace_prefix as _generated_add_op_namespace_prefix
12
+ except ImportError:
13
+ def _generated_add_op_namespace_prefix(name: str) -> str:
14
+ return name if "::" in name else f"flash_attn_ops::{name}"
15
+
16
+
17
+ def add_op_namespace_prefix(name: str) -> str:
18
+ return _generated_add_op_namespace_prefix(name)
build/torch-xpu/cross_entropy.py ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2023, Tri Dao.
2
+
3
+ from typing import Tuple, Optional, Union
4
+
5
+ import torch
6
+ import torch.nn.functional as F
7
+
8
+ import triton
9
+ import triton.language as tl
10
+
11
+ # `all_gather_into_tensor` and `reduce_scatter_tensor` are new placeholders for
12
+ # `_all_gather_base` and `_reduce_scatter_base`. They require the most recent
13
+ # version of PyTorch. The following 2 lines are for backward compatibility with
14
+ # older PyTorch.
15
+ if "all_gather_into_tensor" not in dir(torch.distributed):
16
+ torch.distributed.all_gather_into_tensor = torch.distributed._all_gather_base
17
+
18
+
19
+ @triton.heuristics(
20
+ {
21
+ "HAS_SMOOTHING": lambda args: args["smoothing"] > 0.0,
22
+ }
23
+ )
24
+ @triton.jit
25
+ def cross_entropy_fwd_kernel(
26
+ loss_ptr, # data ptrs
27
+ lse_ptr,
28
+ z_loss_ptr,
29
+ logits_ptr,
30
+ labels_ptr,
31
+ smoothing,
32
+ logit_scale,
33
+ lse_square_scale,
34
+ ignore_index,
35
+ total_classes,
36
+ class_start_idx, # Useful for tensor parallel when each rank only has a subset of classes
37
+ n_cols, # shapes
38
+ logits_row_stride, # strides
39
+ BLOCK_SIZE: tl.constexpr,
40
+ HAS_SMOOTHING: tl.constexpr,
41
+ # if SPLIT (e.g. tensor parallel), don't include the LSE in the loss since it's not the final LSE
42
+ SPLIT: tl.constexpr,
43
+ PRECOMPUTED_LSE: tl.constexpr, # If LSE is already computed (also no smoothing and logit_scale == 1.0)
44
+ ):
45
+ row_idx = tl.program_id(0)
46
+ logits_ptr = logits_ptr + row_idx * logits_row_stride.to(tl.int64)
47
+ sum_logits = 0.0 # For smoothing
48
+ if not PRECOMPUTED_LSE:
49
+ # Statistics for online softmax
50
+ m_i = -float("inf")
51
+ l_i = 0.0
52
+ for col_offset in range(0, n_cols, BLOCK_SIZE):
53
+ cols = col_offset + tl.arange(0, BLOCK_SIZE)
54
+ logits = tl.load(logits_ptr + cols, mask=cols < n_cols, other=-float("inf")).to(
55
+ tl.float32
56
+ ) * logit_scale
57
+ if HAS_SMOOTHING:
58
+ sum_logits += tl.sum(tl.where(cols < n_cols, logits, 0.0))
59
+ m_i_new = tl.maximum(m_i, tl.max(logits))
60
+ l_i = tl.exp(m_i - m_i_new) * l_i + tl.sum(tl.exp(logits - m_i_new))
61
+ m_i = m_i_new
62
+ lse = tl.log(l_i) + m_i
63
+ tl.store(lse_ptr + row_idx, lse)
64
+ else:
65
+ lse = tl.load(lse_ptr + row_idx)
66
+ label_idx = tl.load(labels_ptr + row_idx)
67
+ if label_idx == ignore_index:
68
+ loss = 0.0
69
+ z_loss = 0.0
70
+ else:
71
+ label_idx -= class_start_idx
72
+ if label_idx >= 0 and label_idx < n_cols:
73
+ logits_label = tl.load(logits_ptr + label_idx) * logit_scale
74
+ if HAS_SMOOTHING:
75
+ loss = (
76
+ (lse if not SPLIT else 0.0)
77
+ - smoothing * sum_logits / total_classes
78
+ - (1 - smoothing) * logits_label
79
+ )
80
+ else:
81
+ loss = (lse if not SPLIT else 0.0) - logits_label
82
+ else:
83
+ # If label is out of bounds, we set the CE loss to 0.0. But we still want the smoothing loss
84
+ if HAS_SMOOTHING:
85
+ loss = smoothing * ((lse if not SPLIT else 0.0) - sum_logits / total_classes)
86
+ else:
87
+ loss = 0.0
88
+ if not SPLIT:
89
+ z_loss = lse_square_scale * lse * lse
90
+ loss += z_loss
91
+ else:
92
+ z_loss = 0.0
93
+ tl.store(loss_ptr + row_idx, loss)
94
+ if not SPLIT:
95
+ tl.store(z_loss_ptr + row_idx, z_loss)
96
+
97
+
98
+ @triton.heuristics(
99
+ {
100
+ "HAS_SMOOTHING": lambda args: args["smoothing"] > 0.0,
101
+ }
102
+ )
103
+ @triton.jit
104
+ def cross_entropy_bwd_kernel(
105
+ dlogits_ptr, # data ptrs
106
+ dloss_ptr,
107
+ logits_ptr,
108
+ lse_ptr,
109
+ labels_ptr,
110
+ smoothing,
111
+ logit_scale,
112
+ lse_square_scale,
113
+ ignore_index,
114
+ total_classes,
115
+ class_start_idx, # Useful for tensor parallel when each rank only has a subset of classes
116
+ n_cols, # shapes
117
+ logits_row_stride, # strides
118
+ dlogits_row_stride,
119
+ dloss_row_stride,
120
+ BLOCK_SIZE: tl.constexpr,
121
+ HAS_SMOOTHING: tl.constexpr,
122
+ ):
123
+ row_idx = tl.program_id(0)
124
+ col_block_idx = tl.program_id(1)
125
+ logits_ptr = logits_ptr + row_idx * logits_row_stride.to(tl.int64)
126
+ dlogits_ptr = dlogits_ptr + row_idx * dlogits_row_stride.to(tl.int64)
127
+ col_offsets = col_block_idx * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
128
+ label_idx = tl.load(labels_ptr + row_idx)
129
+ if label_idx != ignore_index:
130
+ dloss = tl.load(dloss_ptr + row_idx * dloss_row_stride)
131
+ else:
132
+ dloss = 0.0
133
+ logits = tl.load(logits_ptr + col_offsets, mask=col_offsets < n_cols, other=-float("inf")).to(
134
+ tl.float32
135
+ ) * logit_scale
136
+ lse = tl.load(lse_ptr + row_idx)
137
+ probs = tl.exp(logits - lse)
138
+ probs += 2.0 * lse_square_scale * lse * probs
139
+ label_idx -= class_start_idx
140
+ if HAS_SMOOTHING:
141
+ smooth_positive = 1.0 - smoothing
142
+ smooth_negative = smoothing / total_classes
143
+ probs = tl.where(col_offsets == label_idx, probs - smooth_positive, probs) - smooth_negative
144
+ else:
145
+ probs = tl.where(col_offsets == label_idx, probs - 1.0, probs)
146
+ tl.store(dlogits_ptr + col_offsets, (dloss * logit_scale) * probs, mask=col_offsets < n_cols)
147
+
148
+
149
+ class CrossEntropyLoss(torch.autograd.Function):
150
+
151
+ @staticmethod
152
+ def forward(
153
+ ctx,
154
+ logits,
155
+ labels,
156
+ precomputed_lse=None,
157
+ smoothing=0.0,
158
+ logit_scale=1.0,
159
+ lse_square_scale=0.0,
160
+ ignore_index=-100,
161
+ inplace_backward=False,
162
+ process_group=None,
163
+ ):
164
+ # For some reason Triton generates wrong code when labels has dtype long and its address
165
+ # is not aligned to 16 bytes. The ld.global.b64 seems to load the wrong label index.
166
+ if labels.dtype == torch.long and labels.data_ptr() % 16 != 0:
167
+ labels = F.pad(labels, (0, 1))[..., :-1]
168
+ assert labels.data_ptr() % 16 == 0
169
+ assert logit_scale > 0.0
170
+ n_rows, n_cols = logits.shape
171
+ assert labels.shape == (n_rows,)
172
+ world_size = 1 if process_group is None else torch.distributed.get_world_size(process_group)
173
+ total_classes = world_size * n_cols
174
+ rank = 0 if process_group is None else torch.distributed.get_rank(process_group)
175
+ class_start_idx = rank * n_cols
176
+ use_precomputed_lse = precomputed_lse is not None and logit_scale == 1.0 and smoothing == 0.0
177
+
178
+ if logits.stride(-1) != 1:
179
+ logits = logits.contiguous()
180
+ MAX_BLOCK_SIZE = 16 * 1024
181
+ BLOCK_SIZE = min(triton.next_power_of_2(n_cols), MAX_BLOCK_SIZE)
182
+ num_warps = (
183
+ 4
184
+ if BLOCK_SIZE < 2048
185
+ else (8 if BLOCK_SIZE < 8192 else (16 if BLOCK_SIZE < 128 * 1024 else 32))
186
+ )
187
+ losses = torch.empty(n_rows, dtype=torch.float, device=logits.device)
188
+ if use_precomputed_lse:
189
+ assert precomputed_lse.shape == (n_rows,)
190
+ lse = precomputed_lse.contiguous()
191
+ else:
192
+ lse = torch.empty(n_rows, dtype=torch.float, device=logits.device)
193
+ z_losses = torch.empty(n_rows, dtype=torch.float, device=logits.device)
194
+ # Need this, otherwise Triton tries to launch from cuda:0 and we get
195
+ # ValueError: Pointer argument (at 0) cannot be accessed from Triton (cpu tensor?)
196
+ with torch.cuda.device(logits.device.index):
197
+ cross_entropy_fwd_kernel[(n_rows,)](
198
+ losses, # data ptrs
199
+ lse,
200
+ z_losses,
201
+ logits,
202
+ labels,
203
+ smoothing,
204
+ logit_scale,
205
+ lse_square_scale,
206
+ ignore_index,
207
+ total_classes,
208
+ class_start_idx,
209
+ n_cols, # shapes
210
+ logits.stride(0), # strides
211
+ BLOCK_SIZE=BLOCK_SIZE, # constants
212
+ SPLIT=world_size > 1,
213
+ PRECOMPUTED_LSE=use_precomputed_lse,
214
+ num_warps=num_warps,
215
+ )
216
+
217
+ if world_size > 1:
218
+ # If there's no smoothing, if labels are in the vocab of this partition, losses contains
219
+ # - predicted logit, and 0 otherwise.
220
+ # If there's smoothing=0.1, for labels in the vocab of this partition, losses contains
221
+ # -0.9 * predicted logit - 0.1 * sum logit / total_classes.
222
+ # For labels not in the vocab of this partition, losses contains
223
+ # -0.1 * sum logit / total_classes.
224
+ if world_size > 1:
225
+ lse_allgather = torch.empty(world_size, n_rows, dtype=lse.dtype, device=lse.device)
226
+ torch.distributed.all_gather_into_tensor(lse_allgather, lse, group=process_group)
227
+ handle_losses = torch.distributed.all_reduce(
228
+ losses, op=torch.distributed.ReduceOp.SUM, group=process_group, async_op=True
229
+ )
230
+ lse = torch.logsumexp(lse_allgather, dim=0)
231
+ handle_losses.wait()
232
+ # After the allreduce, if there's no smoothing, the total losses are - predicted_logit,
233
+ # we just have to add the (global) lse.
234
+ # If there's smoothing=0.1, the total losses are
235
+ # -0.9 * predicted_logit - 0.1 * sum logit / total_classes.
236
+ # Again, we just have to add the (global) lse.
237
+ losses += lse
238
+ if lse_square_scale != 0.0:
239
+ z_losses = lse_square_scale * lse.square()
240
+ z_losses.masked_fill_(labels == ignore_index, 0.0)
241
+ losses += z_losses
242
+ else:
243
+ z_losses = torch.zeros_like(losses)
244
+ losses.masked_fill_(labels == ignore_index, 0.0)
245
+
246
+ ctx.save_for_backward(logits, lse, labels)
247
+ ctx.mark_non_differentiable(z_losses)
248
+ ctx.smoothing = smoothing
249
+ ctx.logit_scale = logit_scale
250
+ ctx.lse_square_scale = lse_square_scale
251
+ ctx.ignore_index = ignore_index
252
+ ctx.total_classes = total_classes
253
+ ctx.class_start_idx = class_start_idx
254
+ ctx.inplace_backward = inplace_backward
255
+ return losses, z_losses
256
+
257
+ @staticmethod
258
+ def backward(ctx, grad_losses, grad_z_losses):
259
+ del grad_z_losses # z_losses are only for logging.
260
+
261
+ logits, lse, labels = ctx.saved_tensors
262
+ dlogits = logits if ctx.inplace_backward else torch.empty_like(logits)
263
+ n_rows, n_cols = logits.shape
264
+ BLOCK_SIZE = min(triton.next_power_of_2(n_cols), 4 * 1024)
265
+ num_warps = 4 if BLOCK_SIZE < 2048 else (8 if BLOCK_SIZE < 8192 else 16)
266
+ grid = lambda META: (n_rows, triton.cdiv(n_cols, META["BLOCK_SIZE"])) # noqa
267
+ # Need this, otherwise Triton tries to launch from cuda:0 and we get
268
+ # ValueError: Pointer argument (at 0) cannot be accessed from Triton (cpu tensor?)
269
+ with torch.cuda.device(logits.device.index):
270
+ cross_entropy_bwd_kernel[grid](
271
+ dlogits, # data ptrs
272
+ grad_losses,
273
+ logits,
274
+ lse,
275
+ labels,
276
+ ctx.smoothing,
277
+ ctx.logit_scale,
278
+ ctx.lse_square_scale,
279
+ ctx.ignore_index,
280
+ ctx.total_classes,
281
+ ctx.class_start_idx,
282
+ n_cols, # shapes
283
+ logits.stride(0), # strides
284
+ dlogits.stride(0),
285
+ grad_losses.stride(0),
286
+ BLOCK_SIZE=BLOCK_SIZE, # constants
287
+ num_warps=num_warps,
288
+ )
289
+ return dlogits, None, None, None, None, None, None, None, None, None
290
+
291
+
292
+ def cross_entropy_loss(
293
+ logits: torch.Tensor,
294
+ labels: torch.Tensor,
295
+ precomputed_lse: Optional[torch.Tensor] = None,
296
+ label_smoothing: float = 0.0,
297
+ logit_scale: float = 1.0,
298
+ lse_square_scale: float = 0.0,
299
+ ignore_index=-100,
300
+ inplace_backward: bool = False,
301
+ process_group=None,
302
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
303
+ """
304
+ Arguments:
305
+ logits: (batch, vocab_size)
306
+ labels: (batch,)
307
+ label_smoothing: float
308
+ logit_scale: float. Multiply logits by this scale before calculating the loss.
309
+ lse_square_scale: float. If > 0, we add lse_square_scale * lse(logits) ^ 2 to the loss.
310
+ This is also referred to as "z-loss".
311
+ ignore_index: int. If labels == ignore_index, the loss is set to 0.0.
312
+ inplace_backward: bool. If True, we do the backward pass in-place by modifying the logits.
313
+ This saves memory.
314
+ process_group: if not None, we're doing Tensor Parallel: each process is responsible for
315
+ one part of the vocab. The loss will be aggregated across processes.
316
+ Returns:
317
+ losses: (batch,), float
318
+ z_losses: (batch,), float
319
+ """
320
+ return CrossEntropyLoss.apply(
321
+ logits,
322
+ labels,
323
+ precomputed_lse,
324
+ label_smoothing,
325
+ logit_scale,
326
+ lse_square_scale,
327
+ ignore_index,
328
+ inplace_backward,
329
+ process_group,
330
+ )
build/torch-xpu/flash_attn_ops/__init__.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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/k_activations.py ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from https://github.com/facebookresearch/xformers/blob/main/xformers/triton/k_activations.py
2
+ # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
3
+ #
4
+ # This source code is licensed under the BSD license found in the
5
+ # LICENSE file in the root directory of this source tree.
6
+
7
+ import math
8
+ from enum import Enum
9
+ from typing import Optional
10
+
11
+ import triton
12
+ import triton.language as tl
13
+
14
+ _sqrt2pi = math.sqrt(2.0 / math.pi)
15
+ _sqrt1_2 = math.sqrt(1.0 / 2)
16
+ _gaussian_pdf_normalization = 1.0 / math.sqrt(2 * math.pi)
17
+
18
+
19
+ class Activation(str, Enum):
20
+ SquaredReLU = "squared_relu"
21
+ GeLU = "gelu"
22
+ GeLUApprox = "gelu_approx"
23
+ LeakyReLU = "leaky_relu"
24
+ ReLU = "relu"
25
+
26
+
27
+ def get_triton_activation_kernel(activation: Optional[Activation]):
28
+ return (
29
+ {
30
+ Activation.ReLU: relu,
31
+ Activation.LeakyReLU: leaky_relu,
32
+ Activation.GeLU: gelu,
33
+ Activation.GeLUApprox: gelu_approx,
34
+ Activation.SquaredReLU: squared_relu,
35
+ }[activation]
36
+ if activation
37
+ else None
38
+ )
39
+
40
+
41
+ def get_triton_activation_bwd_kernel(activation: Optional[Activation]):
42
+ return (
43
+ {
44
+ Activation.ReLU: relu_grad,
45
+ Activation.LeakyReLU: leaky_relu_grad,
46
+ Activation.GeLU: gelu_grad,
47
+ Activation.GeLUApprox: gelu_approx_grad,
48
+ Activation.SquaredReLU: squared_relu_grad,
49
+ }[activation]
50
+ if activation
51
+ else None
52
+ )
53
+
54
+
55
+ @triton.jit
56
+ def tanh(x):
57
+ # Tanh is just a scaled sigmoid
58
+ return 2 * tl.sigmoid(2 * x) - 1
59
+
60
+
61
+ @triton.jit
62
+ def cosh(x):
63
+ exp_x = tl.exp(x)
64
+ return (exp_x + 1.0 / exp_x) * 0.5
65
+
66
+
67
+ # a Triton implementation of the most used activations
68
+ # See for instance http://arxiv.org/abs/1606.08415 for an overview
69
+
70
+ # ReLU
71
+ @triton.jit
72
+ def relu(x):
73
+ """
74
+ ReLU_ activation function
75
+
76
+ .. _ReLU: https://pytorch.org/docs/stable/generated/torch.nn.ReLU.html
77
+ """
78
+ zero = 0.0
79
+ return tl.where(x >= 0, x, zero.to(x.dtype))
80
+
81
+
82
+ @triton.jit
83
+ def relu_grad(x):
84
+ # ReLU is different from other activations
85
+ # in that it does not require the input to retrospectively compute its gradient
86
+ # here the input is the downstream gradient, and we return the upstream gradient directly
87
+ zero = 0.0
88
+ one = 1.0
89
+ return tl.where(x >= 0, one.to(x.dtype), zero.to(x.dtype))
90
+
91
+
92
+ @triton.jit
93
+ def squared_relu(x):
94
+ """
95
+ Squared ReLU activation, as proposed in the Primer_ paper.
96
+
97
+ .. _Primer: https://arxiv.org/abs/2109.08668
98
+ """
99
+ x_ = relu(x)
100
+ return (x_ * x_).to(x.dtype)
101
+
102
+
103
+ @triton.jit
104
+ def squared_relu_grad(x):
105
+ return tl.where(x >= 0, 2.0 * x, 0.0)
106
+
107
+
108
+ # Leaky ReLU
109
+ @triton.jit
110
+ def leaky_relu(x):
111
+ """
112
+ LeakyReLU_ activation
113
+
114
+ .. _LeakyReLU: https://pytorch.org/docs/stable/generated/torch.nn.LeakyReLU.html
115
+ """
116
+ scale = 0.01 + 0.0
117
+ scale = scale.to(x.dtype)
118
+ return tl.where(x >= 0, x, scale * x)
119
+
120
+
121
+ @triton.jit
122
+ def leaky_relu_grad(x):
123
+ min_grad = 0.01
124
+ max_grad = 1
125
+
126
+ min_grad = min_grad.to(x.dtype)
127
+ max_grad = max_grad.to(x.dtype)
128
+
129
+ return tl.where(x >= 0, max_grad, min_grad)
130
+
131
+
132
+ @triton.jit
133
+ def gelu(x):
134
+ """Gaussian Error Linear Unit (GELU)"""
135
+ return x * 0.5 * (1.0 + tl.libdevice.erf(x * _sqrt1_2))
136
+
137
+
138
+ @triton.jit
139
+ def gelu_grad(x):
140
+ cdf = 0.5 * (1.0 + tl.libdevice.erf(x * _sqrt1_2))
141
+ pdf = tl.exp(-0.5 * x * x) * _gaussian_pdf_normalization
142
+ return cdf + x * pdf
143
+
144
+
145
+ @triton.jit
146
+ def gelu_approx(x):
147
+ """
148
+ GeLU_ activation - Gaussian error linear unit, with tanh approximation
149
+
150
+ .. _GeLU: https://arxiv.org/pdf/1606.08415.pdf
151
+ """
152
+ return 0.5 * x * (1.0 + tanh(_sqrt2pi * x * (1.0 + 0.044715 * x * x)))
153
+
154
+
155
+ @triton.jit
156
+ def gelu_approx_grad(x):
157
+ # CREDITS: Fast implementation proposed in
158
+ # https://github.com/NVIDIA/Megatron-LM/blob/main/megatron/model/fused_bias_gelu.py#L30
159
+ tanh_out = tanh(0.79788456 * x * (1 + 0.044715 * x * x))
160
+ return 0.5 * x * ((1 - tanh_out * tanh_out) * (0.79788456 + 0.1070322243 * x * x)) + 0.5 * (
161
+ 1 + tanh_out
162
+ )
build/torch-xpu/layer_norm.py ADDED
@@ -0,0 +1,1257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao.
2
+ # Implement dropout + residual + layer_norm / rms_norm.
3
+
4
+ # Based on the Triton LayerNorm tutorial: https://triton-lang.org/main/getting-started/tutorials/05-layer-norm.html
5
+ # For the backward pass, we keep weight_grad and bias_grad in registers and accumulate.
6
+ # This is faster for dimensions up to 8k, but after that it's much slower due to register spilling.
7
+ # The models we train have hidden dim up to 8k anyway (e.g. Llama 70B), so this is fine.
8
+
9
+ import math
10
+ from typing import Optional, List
11
+
12
+ import torch
13
+ import torch.nn.functional as F
14
+ from torch import Tensor
15
+
16
+ import triton
17
+ import triton.language as tl
18
+
19
+ from .utils.torch import custom_fwd, custom_bwd
20
+ from .utils.library import triton_op
21
+ from ._ops_compat import add_op_namespace_prefix
22
+
23
+
24
+ def maybe_contiguous_lastdim(x):
25
+ return x.contiguous() if x is not None and x.stride(-1) != 1 else x
26
+
27
+
28
+ def maybe_contiguous(x):
29
+ return x.contiguous() if x is not None else None
30
+
31
+
32
+ def triton_autotune_configs():
33
+ # Return configs with a valid warp count for the current device
34
+ configs = []
35
+ # Maximum threads per block is architecture-dependent in theory, but in reality all are 1024
36
+ max_threads_per_block = 1024
37
+ # Default to warp size 32 if not defined by device. Guard the device query so
38
+ # importing this module does not trigger CUDA initialization on machines
39
+ # without a GPU (e.g. the noarch kernel build/import check).
40
+ warp_size = 32
41
+ if torch.cuda.is_available():
42
+ warp_size = getattr(torch.cuda.get_device_properties(torch.cuda.current_device()), "warp_size", 32)
43
+ # Autotune for warp counts which are powers of 2 and do not exceed thread per block limit
44
+ return [triton.Config({}, num_warps=warp_count) for warp_count in [1, 2, 4, 8, 16, 32]
45
+ if warp_count * warp_size <= max_threads_per_block]
46
+ # return [triton.Config({}, num_warps=8)]
47
+
48
+
49
+ def layer_norm_ref(
50
+ x,
51
+ weight,
52
+ bias,
53
+ residual=None,
54
+ x1=None,
55
+ weight1=None,
56
+ bias1=None,
57
+ eps=1e-6,
58
+ dropout_p=0.0,
59
+ rowscale=None,
60
+ prenorm=False,
61
+ zero_centered_weight=False,
62
+ dropout_mask=None,
63
+ dropout_mask1=None,
64
+ upcast=False,
65
+ ):
66
+ dtype = x.dtype
67
+ if upcast:
68
+ x = x.float()
69
+ weight = weight.float()
70
+ bias = bias.float() if bias is not None else None
71
+ residual = residual.float() if residual is not None else residual
72
+ x1 = x1.float() if x1 is not None else None
73
+ weight1 = weight1.float() if weight1 is not None else None
74
+ bias1 = bias1.float() if bias1 is not None else None
75
+ if zero_centered_weight:
76
+ weight = weight + 1.0
77
+ if weight1 is not None:
78
+ weight1 = weight1 + 1.0
79
+ if x1 is not None:
80
+ assert rowscale is None, "rowscale is not supported with parallel LayerNorm"
81
+ if rowscale is not None:
82
+ x = x * rowscale[..., None]
83
+ if dropout_p > 0.0:
84
+ if dropout_mask is not None:
85
+ x = x.masked_fill(~dropout_mask, 0.0) / (1.0 - dropout_p)
86
+ else:
87
+ x = F.dropout(x, p=dropout_p)
88
+ if x1 is not None:
89
+ if dropout_mask1 is not None:
90
+ x1 = x1.masked_fill(~dropout_mask1, 0.0) / (1.0 - dropout_p)
91
+ else:
92
+ x1 = F.dropout(x1, p=dropout_p)
93
+ if x1 is not None:
94
+ x = x + x1
95
+ if residual is not None:
96
+ x = (x + residual).to(x.dtype)
97
+ out = F.layer_norm(x.to(weight.dtype), x.shape[-1:], weight=weight, bias=bias, eps=eps).to(
98
+ dtype
99
+ )
100
+ if weight1 is None:
101
+ return out if not prenorm else (out, x)
102
+ else:
103
+ out1 = F.layer_norm(
104
+ x.to(weight1.dtype), x.shape[-1:], weight=weight1, bias=bias1, eps=eps
105
+ ).to(dtype)
106
+ return (out, out1) if not prenorm else (out, out1, x)
107
+
108
+
109
+ def rms_norm_ref(
110
+ x,
111
+ weight,
112
+ bias,
113
+ residual=None,
114
+ x1=None,
115
+ weight1=None,
116
+ bias1=None,
117
+ eps=1e-6,
118
+ dropout_p=0.0,
119
+ rowscale=None,
120
+ prenorm=False,
121
+ zero_centered_weight=False,
122
+ dropout_mask=None,
123
+ dropout_mask1=None,
124
+ upcast=False,
125
+ ):
126
+ dtype = x.dtype
127
+ if upcast:
128
+ x = x.float()
129
+ weight = weight.float()
130
+ bias = bias.float() if bias is not None else None
131
+ residual = residual.float() if residual is not None else residual
132
+ x1 = x1.float() if x1 is not None else None
133
+ weight1 = weight1.float() if weight1 is not None else None
134
+ bias1 = bias1.float() if bias1 is not None else None
135
+ if zero_centered_weight:
136
+ weight = weight + 1.0
137
+ if weight1 is not None:
138
+ weight1 = weight1 + 1.0
139
+ if x1 is not None:
140
+ assert rowscale is None, "rowscale is not supported with parallel LayerNorm"
141
+ if rowscale is not None:
142
+ x = x * rowscale[..., None]
143
+ if dropout_p > 0.0:
144
+ if dropout_mask is not None:
145
+ x = x.masked_fill(~dropout_mask, 0.0) / (1.0 - dropout_p)
146
+ else:
147
+ x = F.dropout(x, p=dropout_p)
148
+ if x1 is not None:
149
+ if dropout_mask1 is not None:
150
+ x1 = x1.masked_fill(~dropout_mask1, 0.0) / (1.0 - dropout_p)
151
+ else:
152
+ x1 = F.dropout(x1, p=dropout_p)
153
+ if x1 is not None:
154
+ x = x + x1
155
+ if residual is not None:
156
+ x = (x + residual).to(x.dtype)
157
+ rstd = 1 / torch.sqrt((x.square()).mean(dim=-1, keepdim=True) + eps)
158
+ out = ((x * rstd * weight) + bias if bias is not None else (x * rstd * weight)).to(dtype)
159
+ if weight1 is None:
160
+ return out if not prenorm else (out, x)
161
+ else:
162
+ out1 = ((x * rstd * weight1) + bias1 if bias1 is not None else (x * rstd * weight1)).to(
163
+ dtype
164
+ )
165
+ return (out, out1) if not prenorm else (out, out1, x)
166
+
167
+
168
+ @triton.autotune(
169
+ configs=triton_autotune_configs(),
170
+ key=["N", "HAS_RESIDUAL", "STORE_RESIDUAL_OUT", "IS_RMS_NORM", "HAS_BIAS", "HAS_X1", "HAS_W1", "HAS_B1"],
171
+ )
172
+ # torch compile doesn't like triton.heuristics, so we set these manually when calling the kernel
173
+ # @triton.heuristics({"HAS_BIAS": lambda args: args["B"] is not None})
174
+ # @triton.heuristics({"HAS_RESIDUAL": lambda args: args["RESIDUAL"] is not None})
175
+ # @triton.heuristics({"HAS_X1": lambda args: args["X1"] is not None})
176
+ # @triton.heuristics({"HAS_W1": lambda args: args["W1"] is not None})
177
+ # @triton.heuristics({"HAS_B1": lambda args: args["B1"] is not None})
178
+ @triton.jit
179
+ def _layer_norm_fwd_1pass_kernel(
180
+ X, # pointer to the input
181
+ Y, # pointer to the output
182
+ W, # pointer to the weights
183
+ B, # pointer to the biases
184
+ RESIDUAL, # pointer to the residual
185
+ X1,
186
+ W1,
187
+ B1,
188
+ Y1,
189
+ RESIDUAL_OUT, # pointer to the residual
190
+ ROWSCALE,
191
+ SEEDS, # Dropout seeds for each row
192
+ DROPOUT_MASK,
193
+ DROPOUT_MASK1,
194
+ Mean, # pointer to the mean
195
+ Rstd, # pointer to the 1/std
196
+ stride_x_row, # how much to increase the pointer when moving by 1 row
197
+ stride_y_row,
198
+ stride_res_row,
199
+ stride_res_out_row,
200
+ stride_x1_row,
201
+ stride_y1_row,
202
+ M, # number of rows in X
203
+ N, # number of columns in X
204
+ eps, # epsilon to avoid division by zero
205
+ dropout_p, # Dropout probability
206
+ zero_centered_weight, # If true, add 1.0 to the weight
207
+ IS_RMS_NORM: tl.constexpr,
208
+ BLOCK_N: tl.constexpr,
209
+ HAS_RESIDUAL: tl.constexpr,
210
+ STORE_RESIDUAL_OUT: tl.constexpr,
211
+ HAS_BIAS: tl.constexpr,
212
+ HAS_DROPOUT: tl.constexpr,
213
+ STORE_DROPOUT_MASK: tl.constexpr,
214
+ HAS_ROWSCALE: tl.constexpr,
215
+ HAS_X1: tl.constexpr,
216
+ HAS_W1: tl.constexpr,
217
+ HAS_B1: tl.constexpr,
218
+ ):
219
+ # Map the program id to the row of X and Y it should compute.
220
+ row = tl.program_id(0)
221
+ X += row * stride_x_row
222
+ Y += row * stride_y_row
223
+ if HAS_RESIDUAL:
224
+ RESIDUAL += row * stride_res_row
225
+ if STORE_RESIDUAL_OUT:
226
+ RESIDUAL_OUT += row * stride_res_out_row
227
+ if HAS_X1:
228
+ X1 += row * stride_x1_row
229
+ if HAS_W1:
230
+ Y1 += row * stride_y1_row
231
+ # Compute mean and variance
232
+ cols = tl.arange(0, BLOCK_N)
233
+ x = tl.load(X + cols, mask=cols < N, other=0.0).to(tl.float32)
234
+ if HAS_ROWSCALE:
235
+ rowscale = tl.load(ROWSCALE + row).to(tl.float32)
236
+ x *= rowscale
237
+ if HAS_DROPOUT:
238
+ # Compute dropout mask
239
+ # 7 rounds is good enough, and reduces register pressure
240
+ keep_mask = tl.rand(tl.load(SEEDS + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
241
+ x = tl.where(keep_mask, x / (1.0 - dropout_p), 0.0)
242
+ if STORE_DROPOUT_MASK:
243
+ tl.store(DROPOUT_MASK + row * N + cols, keep_mask, mask=cols < N)
244
+ if HAS_X1:
245
+ x1 = tl.load(X1 + cols, mask=cols < N, other=0.0).to(tl.float32)
246
+ if HAS_ROWSCALE:
247
+ rowscale = tl.load(ROWSCALE + M + row).to(tl.float32)
248
+ x1 *= rowscale
249
+ if HAS_DROPOUT:
250
+ # Compute dropout mask
251
+ # 7 rounds is good enough, and reduces register pressure
252
+ keep_mask = (
253
+ tl.rand(tl.load(SEEDS + M + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
254
+ )
255
+ x1 = tl.where(keep_mask, x1 / (1.0 - dropout_p), 0.0)
256
+ if STORE_DROPOUT_MASK:
257
+ tl.store(DROPOUT_MASK1 + row * N + cols, keep_mask, mask=cols < N)
258
+ x += x1
259
+ if HAS_RESIDUAL:
260
+ residual = tl.load(RESIDUAL + cols, mask=cols < N, other=0.0).to(tl.float32)
261
+ x += residual
262
+ if STORE_RESIDUAL_OUT:
263
+ tl.store(RESIDUAL_OUT + cols, x, mask=cols < N)
264
+ if not IS_RMS_NORM:
265
+ mean = tl.sum(x, axis=0) / N
266
+ tl.store(Mean + row, mean)
267
+ xbar = tl.where(cols < N, x - mean, 0.0)
268
+ var = tl.sum(xbar * xbar, axis=0) / N
269
+ else:
270
+ xbar = tl.where(cols < N, x, 0.0)
271
+ var = tl.sum(xbar * xbar, axis=0) / N
272
+ rstd = 1 / tl.sqrt(var + eps)
273
+ tl.store(Rstd + row, rstd)
274
+ # Normalize and apply linear transformation
275
+ mask = cols < N
276
+ w = tl.load(W + cols, mask=mask).to(tl.float32)
277
+ if zero_centered_weight:
278
+ w += 1.0
279
+ if HAS_BIAS:
280
+ b = tl.load(B + cols, mask=mask).to(tl.float32)
281
+ x_hat = (x - mean) * rstd if not IS_RMS_NORM else x * rstd
282
+ y = x_hat * w + b if HAS_BIAS else x_hat * w
283
+ # Write output
284
+ tl.store(Y + cols, y, mask=mask)
285
+ if HAS_W1:
286
+ w1 = tl.load(W1 + cols, mask=mask).to(tl.float32)
287
+ if zero_centered_weight:
288
+ w1 += 1.0
289
+ if HAS_B1:
290
+ b1 = tl.load(B1 + cols, mask=mask).to(tl.float32)
291
+ y1 = x_hat * w1 + b1 if HAS_B1 else x_hat * w1
292
+ tl.store(Y1 + cols, y1, mask=mask)
293
+
294
+
295
+ def _layer_norm_fwd(
296
+ x: Tensor,
297
+ weight: Tensor,
298
+ bias: Tensor,
299
+ eps: float,
300
+ residual: Optional[Tensor] = None,
301
+ x1: Optional[Tensor] = None,
302
+ weight1: Optional[Tensor] = None,
303
+ bias1: Optional[Tensor] = None,
304
+ dropout_p: float = 0.0,
305
+ rowscale: Optional[Tensor] = None,
306
+ out_dtype: Optional[torch.dtype] = None,
307
+ residual_dtype: Optional[torch.dtype] = None,
308
+ zero_centered_weight: bool = False,
309
+ is_rms_norm: bool = False,
310
+ return_dropout_mask: bool = False,
311
+ out: Optional[Tensor] = None,
312
+ residual_out: Optional[Tensor] = None
313
+ ) -> (Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor):
314
+ # Need to wrap to handle the case where residual_out is a alias of x, which makes torch.library
315
+ # and torch.compile unhappy. Also allocate memory for out and residual_out if they are None
316
+ # so that _layer_norm_fwd_impl doesn't have to return them.
317
+ if out is None:
318
+ out = torch.empty_like(x, dtype=x.dtype if out_dtype is None else out_dtype)
319
+ if residual is not None:
320
+ residual_dtype = residual.dtype
321
+ if residual_out is None and (
322
+ residual is not None
323
+ or (residual_dtype is not None and residual_dtype != x.dtype)
324
+ or dropout_p > 0.0
325
+ or rowscale is not None
326
+ or x1 is not None
327
+ ):
328
+ residual_out = torch.empty_like(
329
+ x, dtype=residual_dtype if residual_dtype is not None else x.dtype
330
+ )
331
+ else:
332
+ residual_out = None
333
+ y1, mean, rstd, seeds, dropout_mask, dropout_mask1 = _layer_norm_fwd_impl(
334
+ x,
335
+ weight,
336
+ bias,
337
+ eps,
338
+ out,
339
+ residual=residual,
340
+ x1=x1,
341
+ weight1=weight1,
342
+ bias1=bias1,
343
+ dropout_p=dropout_p,
344
+ rowscale=rowscale,
345
+ zero_centered_weight=zero_centered_weight,
346
+ is_rms_norm=is_rms_norm,
347
+ return_dropout_mask=return_dropout_mask,
348
+ residual_out=residual_out,
349
+ )
350
+ # residual_out is None if residual is None and residual_dtype == input_dtype and dropout_p == 0.0
351
+ if residual_out is None:
352
+ residual_out = x
353
+ return out, y1, mean, rstd, residual_out, seeds, dropout_mask, dropout_mask1
354
+
355
+
356
+ # [2025-04-28] torch.library.triton_op ignores the schema argument, but here we need the schema
357
+ # since we're returning a tuple of tensors
358
+ @triton_op(add_op_namespace_prefix("layer_norm_fwd_impl"), mutates_args={"out", "residual_out"},
359
+ schema="(Tensor x, Tensor weight, Tensor bias, float eps, Tensor(a!) out, Tensor? residual, Tensor? x1, Tensor? weight1, Tensor? bias1, float dropout_p, Tensor? rowscale, bool zero_centered_weight, bool is_rms_norm, bool return_dropout_mask, Tensor(a!)? residual_out) -> (Tensor y1, Tensor mean, Tensor rstd, Tensor seeds, Tensor dropout_mask, Tensor dropout_mask1)")
360
+ def _layer_norm_fwd_impl(
361
+ x: Tensor,
362
+ weight: Tensor,
363
+ bias: Tensor,
364
+ eps: float,
365
+ out: Tensor,
366
+ residual: Optional[Tensor] = None,
367
+ x1: Optional[Tensor] = None,
368
+ weight1: Optional[Tensor] = None,
369
+ bias1: Optional[Tensor] = None,
370
+ dropout_p: float = 0.0,
371
+ rowscale: Optional[Tensor] = None,
372
+ zero_centered_weight: bool = False,
373
+ is_rms_norm: bool = False,
374
+ return_dropout_mask: bool = False,
375
+ residual_out: Optional[Tensor] = None
376
+ ) -> (Tensor, Tensor, Tensor, Tensor, Tensor, Tensor):
377
+ M, N = x.shape
378
+ assert x.stride(-1) == 1
379
+ if residual is not None:
380
+ assert residual.stride(-1) == 1
381
+ assert residual.shape == (M, N)
382
+ assert weight.shape == (N,)
383
+ assert weight.stride(-1) == 1
384
+ if bias is not None:
385
+ assert bias.stride(-1) == 1
386
+ assert bias.shape == (N,)
387
+ if x1 is not None:
388
+ assert x1.shape == x.shape
389
+ assert rowscale is None
390
+ assert x1.stride(-1) == 1
391
+ if weight1 is not None:
392
+ assert weight1.shape == (N,)
393
+ assert weight1.stride(-1) == 1
394
+ if bias1 is not None:
395
+ assert bias1.shape == (N,)
396
+ assert bias1.stride(-1) == 1
397
+ if rowscale is not None:
398
+ assert rowscale.is_contiguous()
399
+ assert rowscale.shape == (M,)
400
+ assert out.shape == x.shape
401
+ assert out.stride(-1) == 1
402
+ if residual_out is not None:
403
+ assert residual_out.shape == x.shape
404
+ assert residual_out.stride(-1) == 1
405
+ if weight1 is not None:
406
+ y1 = torch.empty_like(out)
407
+ assert y1.stride(-1) == 1
408
+ else:
409
+ y1 = None
410
+ mean = torch.empty((M,), dtype=torch.float32, device=x.device) if not is_rms_norm else None
411
+ rstd = torch.empty((M,), dtype=torch.float32, device=x.device)
412
+ if dropout_p > 0.0:
413
+ seeds = torch.randint(
414
+ 2**32, (M if x1 is None else 2 * M,), device=x.device, dtype=torch.int64
415
+ )
416
+ else:
417
+ seeds = None
418
+ if return_dropout_mask and dropout_p > 0.0:
419
+ dropout_mask = torch.empty(M, N, device=x.device, dtype=torch.bool)
420
+ if x1 is not None:
421
+ dropout_mask1 = torch.empty(M, N, device=x.device, dtype=torch.bool)
422
+ else:
423
+ dropout_mask1 = None
424
+ else:
425
+ dropout_mask, dropout_mask1 = None, None
426
+ # Less than 64KB per feature: enqueue fused kernel
427
+ MAX_FUSED_SIZE = 65536 // x.element_size()
428
+ BLOCK_N = min(MAX_FUSED_SIZE, triton.next_power_of_2(N))
429
+ if N > BLOCK_N:
430
+ raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
431
+ with torch.cuda.device(x.device.index):
432
+ torch.library.wrap_triton(_layer_norm_fwd_1pass_kernel)[(M,)](
433
+ x,
434
+ out,
435
+ weight,
436
+ bias,
437
+ residual,
438
+ x1,
439
+ weight1,
440
+ bias1,
441
+ y1,
442
+ residual_out,
443
+ rowscale,
444
+ seeds,
445
+ dropout_mask,
446
+ dropout_mask1,
447
+ mean,
448
+ rstd,
449
+ x.stride(0),
450
+ out.stride(0),
451
+ residual.stride(0) if residual is not None else 0,
452
+ residual_out.stride(0) if residual_out is not None else 0,
453
+ x1.stride(0) if x1 is not None else 0,
454
+ y1.stride(0) if y1 is not None else 0,
455
+ M,
456
+ N,
457
+ eps,
458
+ dropout_p,
459
+ # Passing bool make torch inductor very unhappy since it then tries to compare to int_max
460
+ int(zero_centered_weight),
461
+ is_rms_norm,
462
+ BLOCK_N,
463
+ residual is not None,
464
+ residual_out is not None,
465
+ bias is not None,
466
+ dropout_p > 0.0,
467
+ dropout_mask is not None,
468
+ rowscale is not None,
469
+ HAS_X1=x1 is not None,
470
+ HAS_W1=weight1 is not None,
471
+ HAS_B1=bias1 is not None,
472
+ )
473
+ return y1, mean, rstd, seeds, dropout_mask, dropout_mask1
474
+
475
+
476
+ @triton.autotune(
477
+ configs=triton_autotune_configs(),
478
+ key=["N", "HAS_DRESIDUAL", "STORE_DRESIDUAL", "IS_RMS_NORM", "HAS_BIAS", "HAS_DROPOUT"],
479
+ )
480
+ # torch compile doesn't like triton.heuristics, so we set these manually when calling the kernel
481
+ # @triton.heuristics({"HAS_BIAS": lambda args: args["B"] is not None})
482
+ # @triton.heuristics({"HAS_DRESIDUAL": lambda args: args["DRESIDUAL"] is not None})
483
+ # @triton.heuristics({"STORE_DRESIDUAL": lambda args: args["DRESIDUAL_IN"] is not None})
484
+ # @triton.heuristics({"HAS_ROWSCALE": lambda args: args["ROWSCALE"] is not None})
485
+ # @triton.heuristics({"HAS_DY1": lambda args: args["DY1"] is not None})
486
+ # @triton.heuristics({"HAS_DX1": lambda args: args["DX1"] is not None})
487
+ # @triton.heuristics({"HAS_B1": lambda args: args["DB1"] is not None})
488
+ # @triton.heuristics({"RECOMPUTE_OUTPUT": lambda args: args["Y"] is not None})
489
+ @triton.jit
490
+ def _layer_norm_bwd_kernel(
491
+ X, # pointer to the input
492
+ W, # pointer to the weights
493
+ B, # pointer to the biases
494
+ Y, # pointer to the output to be recomputed
495
+ DY, # pointer to the output gradient
496
+ DX, # pointer to the input gradient
497
+ DW, # pointer to the partial sum of weights gradient
498
+ DB, # pointer to the partial sum of biases gradient
499
+ DRESIDUAL,
500
+ W1,
501
+ DY1,
502
+ DX1,
503
+ DW1,
504
+ DB1,
505
+ DRESIDUAL_IN,
506
+ ROWSCALE,
507
+ SEEDS,
508
+ Mean, # pointer to the mean
509
+ Rstd, # pointer to the 1/std
510
+ stride_x_row, # how much to increase the pointer when moving by 1 row
511
+ stride_y_row,
512
+ stride_dy_row,
513
+ stride_dx_row,
514
+ stride_dres_row,
515
+ stride_dy1_row,
516
+ stride_dx1_row,
517
+ stride_dres_in_row,
518
+ M, # number of rows in X
519
+ N, # number of columns in X
520
+ eps, # epsilon to avoid division by zero
521
+ dropout_p,
522
+ zero_centered_weight,
523
+ rows_per_program,
524
+ IS_RMS_NORM: tl.constexpr,
525
+ BLOCK_N: tl.constexpr,
526
+ HAS_DRESIDUAL: tl.constexpr,
527
+ STORE_DRESIDUAL: tl.constexpr,
528
+ HAS_BIAS: tl.constexpr,
529
+ HAS_DROPOUT: tl.constexpr,
530
+ HAS_ROWSCALE: tl.constexpr,
531
+ HAS_DY1: tl.constexpr,
532
+ HAS_DX1: tl.constexpr,
533
+ HAS_B1: tl.constexpr,
534
+ RECOMPUTE_OUTPUT: tl.constexpr,
535
+ ):
536
+ # Map the program id to the elements of X, DX, and DY it should compute.
537
+ row_block_id = tl.program_id(0)
538
+ row_start = row_block_id * rows_per_program
539
+ # Do not early exit if row_start >= M, because we need to write DW and DB
540
+ cols = tl.arange(0, BLOCK_N)
541
+ mask = cols < N
542
+ X += row_start * stride_x_row
543
+ if HAS_DRESIDUAL:
544
+ DRESIDUAL += row_start * stride_dres_row
545
+ if STORE_DRESIDUAL:
546
+ DRESIDUAL_IN += row_start * stride_dres_in_row
547
+ DY += row_start * stride_dy_row
548
+ DX += row_start * stride_dx_row
549
+ if HAS_DY1:
550
+ DY1 += row_start * stride_dy1_row
551
+ if HAS_DX1:
552
+ DX1 += row_start * stride_dx1_row
553
+ if RECOMPUTE_OUTPUT:
554
+ Y += row_start * stride_y_row
555
+ w = tl.load(W + cols, mask=mask).to(tl.float32)
556
+ if zero_centered_weight:
557
+ w += 1.0
558
+ if RECOMPUTE_OUTPUT and HAS_BIAS:
559
+ b = tl.load(B + cols, mask=mask, other=0.0).to(tl.float32)
560
+ if HAS_DY1:
561
+ w1 = tl.load(W1 + cols, mask=mask).to(tl.float32)
562
+ if zero_centered_weight:
563
+ w1 += 1.0
564
+ dw = tl.zeros((BLOCK_N,), dtype=tl.float32)
565
+ if HAS_BIAS:
566
+ db = tl.zeros((BLOCK_N,), dtype=tl.float32)
567
+ if HAS_DY1:
568
+ dw1 = tl.zeros((BLOCK_N,), dtype=tl.float32)
569
+ if HAS_B1:
570
+ db1 = tl.zeros((BLOCK_N,), dtype=tl.float32)
571
+ row_end = min((row_block_id + 1) * rows_per_program, M)
572
+ for row in range(row_start, row_end):
573
+ # Load data to SRAM
574
+ x = tl.load(X + cols, mask=mask, other=0).to(tl.float32)
575
+ dy = tl.load(DY + cols, mask=mask, other=0).to(tl.float32)
576
+ if HAS_DY1:
577
+ dy1 = tl.load(DY1 + cols, mask=mask, other=0).to(tl.float32)
578
+ if not IS_RMS_NORM:
579
+ mean = tl.load(Mean + row)
580
+ rstd = tl.load(Rstd + row)
581
+ # Compute dx
582
+ xhat = (x - mean) * rstd if not IS_RMS_NORM else x * rstd
583
+ xhat = tl.where(mask, xhat, 0.0)
584
+ if RECOMPUTE_OUTPUT:
585
+ y = xhat * w + b if HAS_BIAS else xhat * w
586
+ tl.store(Y + cols, y, mask=mask)
587
+ wdy = w * dy
588
+ dw += dy * xhat
589
+ if HAS_BIAS:
590
+ db += dy
591
+ if HAS_DY1:
592
+ wdy += w1 * dy1
593
+ dw1 += dy1 * xhat
594
+ if HAS_B1:
595
+ db1 += dy1
596
+ if not IS_RMS_NORM:
597
+ c1 = tl.sum(xhat * wdy, axis=0) / N
598
+ c2 = tl.sum(wdy, axis=0) / N
599
+ dx = (wdy - (xhat * c1 + c2)) * rstd
600
+ else:
601
+ c1 = tl.sum(xhat * wdy, axis=0) / N
602
+ dx = (wdy - xhat * c1) * rstd
603
+ if HAS_DRESIDUAL:
604
+ dres = tl.load(DRESIDUAL + cols, mask=mask, other=0).to(tl.float32)
605
+ dx += dres
606
+ # Write dx
607
+ if STORE_DRESIDUAL:
608
+ tl.store(DRESIDUAL_IN + cols, dx, mask=mask)
609
+ if HAS_DX1:
610
+ if HAS_DROPOUT:
611
+ keep_mask = (
612
+ tl.rand(tl.load(SEEDS + M + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
613
+ )
614
+ dx1 = tl.where(keep_mask, dx / (1.0 - dropout_p), 0.0)
615
+ else:
616
+ dx1 = dx
617
+ tl.store(DX1 + cols, dx1, mask=mask)
618
+ if HAS_DROPOUT:
619
+ keep_mask = tl.rand(tl.load(SEEDS + row).to(tl.uint32), cols, n_rounds=7) > dropout_p
620
+ dx = tl.where(keep_mask, dx / (1.0 - dropout_p), 0.0)
621
+ if HAS_ROWSCALE:
622
+ rowscale = tl.load(ROWSCALE + row).to(tl.float32)
623
+ dx *= rowscale
624
+ tl.store(DX + cols, dx, mask=mask)
625
+
626
+ X += stride_x_row
627
+ if HAS_DRESIDUAL:
628
+ DRESIDUAL += stride_dres_row
629
+ if STORE_DRESIDUAL:
630
+ DRESIDUAL_IN += stride_dres_in_row
631
+ if RECOMPUTE_OUTPUT:
632
+ Y += stride_y_row
633
+ DY += stride_dy_row
634
+ DX += stride_dx_row
635
+ if HAS_DY1:
636
+ DY1 += stride_dy1_row
637
+ if HAS_DX1:
638
+ DX1 += stride_dx1_row
639
+ tl.store(DW + row_block_id * N + cols, dw, mask=mask)
640
+ if HAS_BIAS:
641
+ tl.store(DB + row_block_id * N + cols, db, mask=mask)
642
+ if HAS_DY1:
643
+ tl.store(DW1 + row_block_id * N + cols, dw1, mask=mask)
644
+ if HAS_B1:
645
+ tl.store(DB1 + row_block_id * N + cols, db1, mask=mask)
646
+
647
+
648
+ def _layer_norm_bwd(
649
+ dy: Tensor,
650
+ x: Tensor,
651
+ weight: Tensor,
652
+ bias: Tensor,
653
+ eps: float,
654
+ mean: Tensor,
655
+ rstd: Tensor,
656
+ dresidual: Optional[Tensor] = None,
657
+ dy1: Optional[Tensor] = None,
658
+ weight1: Optional[Tensor] = None,
659
+ bias1: Optional[Tensor] = None,
660
+ seeds: Optional[Tensor] = None,
661
+ dropout_p: float = 0.0,
662
+ rowscale: Optional[Tensor] = None,
663
+ has_residual: bool = False,
664
+ has_x1: bool = False,
665
+ zero_centered_weight: bool = False,
666
+ is_rms_norm: bool = False,
667
+ x_dtype: Optional[torch.dtype] = None,
668
+ recompute_output: bool = False,
669
+ ) -> (Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor):
670
+ # Need to wrap to handle the case where dresidual_in or dx1 are aliases of x,
671
+ # which makes torch.library unhappy
672
+ dx, dw, db, dresidual_in, dx1, dw1, db1, y = _layer_norm_bwd_impl(
673
+ dy,
674
+ x,
675
+ weight,
676
+ bias,
677
+ eps,
678
+ mean,
679
+ rstd,
680
+ dresidual,
681
+ dy1,
682
+ weight1,
683
+ bias1,
684
+ seeds,
685
+ dropout_p,
686
+ rowscale,
687
+ has_residual,
688
+ has_x1,
689
+ zero_centered_weight,
690
+ is_rms_norm,
691
+ x_dtype=x_dtype,
692
+ recompute_output=recompute_output,
693
+ )
694
+ # Don't need to compute dresidual_in separately in this case
695
+ if has_residual and dx.dtype == x.dtype and dropout_p == 0.0 and rowscale is None:
696
+ dresidual_in = dx
697
+ if has_x1 and dropout_p == 0.0:
698
+ dx1 = dx
699
+ return dx, dw, db, dresidual_in, dx1, dw1, db1, y
700
+
701
+
702
+
703
+ @triton_op(add_op_namespace_prefix("layer_norm_bwd_impl"), mutates_args={},
704
+ schema="(Tensor dy, Tensor x, Tensor weight, Tensor bias, float eps, Tensor mean, Tensor rstd, Tensor? dresidual, Tensor? dy1, Tensor? weight1, Tensor? bias1, Tensor? seeds, float dropout_p, Tensor? rowscale, bool has_residual, bool has_x1, bool zero_centered_weight, bool is_rms_norm, ScalarType? x_dtype, bool recompute_output) -> (Tensor dx, Tensor dw, Tensor db, Tensor dresidual_in, Tensor dx1, Tensor dw1, Tensor db1, Tensor y)",
705
+ allow_decomposition=False, # Don't let torch.compile trace inside
706
+ )
707
+ def _layer_norm_bwd_impl(
708
+ dy: Tensor,
709
+ x: Tensor,
710
+ weight: Tensor,
711
+ bias: Tensor,
712
+ eps: float,
713
+ mean: Tensor,
714
+ rstd: Tensor,
715
+ dresidual: Optional[Tensor] = None,
716
+ dy1: Optional[Tensor] = None,
717
+ weight1: Optional[Tensor] = None,
718
+ bias1: Optional[Tensor] = None,
719
+ seeds: Optional[Tensor] = None,
720
+ dropout_p: float = 0.0,
721
+ rowscale: Optional[Tensor] = None,
722
+ has_residual: bool = False,
723
+ has_x1: bool = False,
724
+ zero_centered_weight: bool = False,
725
+ is_rms_norm: bool = False,
726
+ x_dtype: Optional[torch.dtype] = None,
727
+ recompute_output: bool = False,
728
+ ) -> (Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor, Tensor):
729
+ M, N = x.shape
730
+ assert x.stride(-1) == 1
731
+ dy = maybe_contiguous_lastdim(dy)
732
+ assert dy.stride(-1) == 1
733
+ assert dy.shape == (M, N)
734
+ if dresidual is not None:
735
+ dresidual = maybe_contiguous_lastdim(dresidual)
736
+ assert dresidual.stride(-1) == 1
737
+ assert dresidual.shape == (M, N)
738
+ assert weight.shape == (N,)
739
+ assert weight.stride(-1) == 1
740
+ if bias is not None:
741
+ assert bias.stride(-1) == 1
742
+ assert bias.shape == (N,)
743
+ if dy1 is not None:
744
+ dy1 = maybe_contiguous_lastdim(dy1)
745
+ assert weight1 is not None
746
+ assert dy1.shape == dy.shape
747
+ assert dy1.stride(-1) == 1
748
+ if weight1 is not None:
749
+ assert weight1.shape == (N,)
750
+ assert weight1.stride(-1) == 1
751
+ if bias1 is not None:
752
+ assert bias1.shape == (N,)
753
+ assert bias1.stride(-1) == 1
754
+ if seeds is not None:
755
+ assert seeds.is_contiguous()
756
+ assert seeds.shape == (M if not has_x1 else M * 2,)
757
+ if rowscale is not None:
758
+ assert rowscale.is_contiguous()
759
+ assert rowscale.shape == (M,)
760
+ # allocate output
761
+ dx = (
762
+ torch.empty_like(x)
763
+ if x_dtype is None
764
+ else torch.empty(M, N, dtype=x_dtype, device=x.device)
765
+ )
766
+ dresidual_in = (
767
+ torch.empty_like(x)
768
+ if has_residual
769
+ and (dx.dtype != x.dtype or dropout_p > 0.0 or rowscale is not None or has_x1)
770
+ else None
771
+ )
772
+ dx1 = torch.empty_like(dx) if (has_x1 and dropout_p > 0.0) else None
773
+ y = torch.empty(M, N, dtype=dy.dtype, device=dy.device) if recompute_output else None
774
+ if recompute_output:
775
+ assert weight1 is None, "recompute_output is not supported with parallel LayerNorm"
776
+
777
+ # Less than 64KB per feature: enqueue fused kernel
778
+ MAX_FUSED_SIZE = 65536 // x.element_size()
779
+ BLOCK_N = min(MAX_FUSED_SIZE, triton.next_power_of_2(N))
780
+ if N > BLOCK_N:
781
+ raise RuntimeError("This layer norm doesn't support feature dim >= 64KB.")
782
+ # Increasing the multiple (e.g. 8) will allow more thread blocks to be launched and hide the
783
+ # latency of the gmem reads/writes, but will increase the time of summing up dw / db.
784
+ sm_count = torch.cuda.get_device_properties(x.device).multi_processor_count * 8
785
+ _dw = torch.empty((sm_count, N), dtype=torch.float32, device=weight.device)
786
+ _db = (
787
+ torch.empty((sm_count, N), dtype=torch.float32, device=bias.device)
788
+ if bias is not None
789
+ else None
790
+ )
791
+ _dw1 = torch.empty_like(_dw) if weight1 is not None else None
792
+ _db1 = torch.empty_like(_db) if bias1 is not None else None
793
+ rows_per_program = math.ceil(M / sm_count)
794
+ grid = (sm_count,)
795
+ with torch.cuda.device(x.device.index):
796
+ torch.library.wrap_triton(_layer_norm_bwd_kernel)[grid](
797
+ x,
798
+ weight,
799
+ bias,
800
+ y,
801
+ dy,
802
+ dx,
803
+ _dw,
804
+ _db,
805
+ dresidual,
806
+ weight1,
807
+ dy1,
808
+ dx1,
809
+ _dw1,
810
+ _db1,
811
+ dresidual_in,
812
+ rowscale,
813
+ seeds,
814
+ mean,
815
+ rstd,
816
+ x.stride(0),
817
+ 0 if not recompute_output else y.stride(0),
818
+ dy.stride(0),
819
+ dx.stride(0),
820
+ dresidual.stride(0) if dresidual is not None else 0,
821
+ dy1.stride(0) if dy1 is not None else 0,
822
+ dx1.stride(0) if dx1 is not None else 0,
823
+ dresidual_in.stride(0) if dresidual_in is not None else 0,
824
+ M,
825
+ N,
826
+ eps,
827
+ dropout_p,
828
+ # Passing bool make torch inductor very unhappy since it then tries to compare to int_max
829
+ int(zero_centered_weight),
830
+ rows_per_program,
831
+ is_rms_norm,
832
+ BLOCK_N,
833
+ dresidual is not None,
834
+ dresidual_in is not None,
835
+ bias is not None,
836
+ dropout_p > 0.0,
837
+ HAS_ROWSCALE=rowscale is not None,
838
+ HAS_DY1=dy1 is not None,
839
+ HAS_DX1=dx1 is not None,
840
+ HAS_B1=bias1 is not None,
841
+ RECOMPUTE_OUTPUT=y is not None,
842
+ )
843
+ dw = _dw.sum(0).to(weight.dtype)
844
+ db = _db.sum(0).to(bias.dtype) if bias is not None else None
845
+ dw1 = _dw1.sum(0).to(weight1.dtype) if weight1 is not None else None
846
+ db1 = _db1.sum(0).to(bias1.dtype) if bias1 is not None else None
847
+ # dresidual_in and dx1 could be None, the wrapper will handle assigning them from dx
848
+ return dx, dw, db, dresidual_in, dx1, dw1, db1, y
849
+
850
+
851
+ class LayerNormFn(torch.autograd.Function):
852
+
853
+ @staticmethod
854
+ def forward(
855
+ ctx,
856
+ x,
857
+ weight,
858
+ bias,
859
+ residual=None,
860
+ x1=None,
861
+ weight1=None,
862
+ bias1=None,
863
+ eps=1e-6,
864
+ dropout_p=0.0,
865
+ rowscale=None,
866
+ prenorm=False,
867
+ residual_in_fp32=False,
868
+ zero_centered_weight=False,
869
+ is_rms_norm=False,
870
+ return_dropout_mask=False,
871
+ out_dtype=None,
872
+ out=None,
873
+ residual_out=None
874
+ ):
875
+ x_shape_og = x.shape
876
+ # reshape input data into 2D tensor
877
+ x = maybe_contiguous_lastdim(x.reshape(-1, x.shape[-1]))
878
+ if residual is not None:
879
+ assert residual.shape == x_shape_og
880
+ residual = maybe_contiguous_lastdim(residual.reshape(-1, residual.shape[-1]))
881
+ if x1 is not None:
882
+ assert x1.shape == x_shape_og
883
+ assert rowscale is None, "rowscale is not supported with parallel LayerNorm"
884
+ x1 = maybe_contiguous_lastdim(x1.reshape(-1, x1.shape[-1]))
885
+ weight = weight.contiguous()
886
+ bias = maybe_contiguous(bias)
887
+ weight1 = maybe_contiguous(weight1)
888
+ bias1 = maybe_contiguous(bias1)
889
+ if rowscale is not None:
890
+ rowscale = rowscale.reshape(-1).contiguous()
891
+ residual_dtype = (
892
+ residual.dtype
893
+ if residual is not None
894
+ else (torch.float32 if residual_in_fp32 else None)
895
+ )
896
+ if out is not None:
897
+ out = out.reshape(-1, out.shape[-1])
898
+ if residual_out is not None:
899
+ residual_out = residual_out.reshape(-1, residual_out.shape[-1])
900
+ y, y1, mean, rstd, residual_out, seeds, dropout_mask, dropout_mask1 = _layer_norm_fwd(
901
+ x,
902
+ weight,
903
+ bias,
904
+ eps,
905
+ residual,
906
+ x1,
907
+ weight1,
908
+ bias1,
909
+ dropout_p=dropout_p,
910
+ rowscale=rowscale,
911
+ out_dtype=out_dtype,
912
+ residual_dtype=residual_dtype,
913
+ zero_centered_weight=zero_centered_weight,
914
+ is_rms_norm=is_rms_norm,
915
+ return_dropout_mask=return_dropout_mask,
916
+ out=out,
917
+ residual_out=residual_out,
918
+ )
919
+ ctx.save_for_backward(
920
+ residual_out, weight, bias, weight1, bias1, rowscale, seeds, mean, rstd
921
+ )
922
+ ctx.x_shape_og = x_shape_og
923
+ ctx.eps = eps
924
+ ctx.dropout_p = dropout_p
925
+ ctx.is_rms_norm = is_rms_norm
926
+ ctx.has_residual = residual is not None
927
+ ctx.has_x1 = x1 is not None
928
+ ctx.prenorm = prenorm
929
+ ctx.x_dtype = x.dtype
930
+ ctx.zero_centered_weight = zero_centered_weight
931
+ y = y.reshape(x_shape_og)
932
+ y1 = y1.reshape(x_shape_og) if y1 is not None else None
933
+ residual_out = residual_out.reshape(x_shape_og) if residual_out is not None else None
934
+ dropout_mask = dropout_mask.reshape(x_shape_og) if dropout_mask is not None else None
935
+ dropout_mask1 = dropout_mask1.reshape(x_shape_og) if dropout_mask1 is not None else None
936
+ if not return_dropout_mask:
937
+ if weight1 is None:
938
+ return y if not prenorm else (y, residual_out)
939
+ else:
940
+ return (y, y1) if not prenorm else (y, y1, residual_out)
941
+ else:
942
+ if weight1 is None:
943
+ return (
944
+ (y, dropout_mask, dropout_mask1)
945
+ if not prenorm
946
+ else (y, residual_out, dropout_mask, dropout_mask1)
947
+ )
948
+ else:
949
+ return (
950
+ (y, y1, dropout_mask, dropout_mask1)
951
+ if not prenorm
952
+ else (y, y1, residual_out, dropout_mask, dropout_mask1)
953
+ )
954
+
955
+ @staticmethod
956
+ def backward(ctx, dy, *args):
957
+ x, weight, bias, weight1, bias1, rowscale, seeds, mean, rstd = ctx.saved_tensors
958
+ dy = dy.reshape(-1, dy.shape[-1])
959
+ if weight1 is not None:
960
+ dy1, args = args[0], args[1:]
961
+ dy1 = dy1.reshape(-1, dy1.shape[-1])
962
+ assert dy1.shape == x.shape
963
+ else:
964
+ dy1 = None
965
+ if ctx.prenorm:
966
+ dresidual = args[0]
967
+ dresidual = dresidual.reshape(-1, dresidual.shape[-1])
968
+ assert dresidual.shape == x.shape
969
+ else:
970
+ dresidual = None
971
+ dx, dw, db, dresidual_in, dx1, dw1, db1, _ = _layer_norm_bwd(
972
+ dy,
973
+ x,
974
+ weight,
975
+ bias,
976
+ ctx.eps,
977
+ mean,
978
+ rstd,
979
+ dresidual,
980
+ dy1,
981
+ weight1,
982
+ bias1,
983
+ seeds,
984
+ ctx.dropout_p,
985
+ rowscale,
986
+ ctx.has_residual,
987
+ ctx.has_x1,
988
+ ctx.zero_centered_weight,
989
+ ctx.is_rms_norm,
990
+ x_dtype=ctx.x_dtype,
991
+ recompute_output=False,
992
+ )
993
+ return (
994
+ dx.reshape(ctx.x_shape_og),
995
+ dw,
996
+ db,
997
+ dresidual_in.reshape(ctx.x_shape_og) if ctx.has_residual else None,
998
+ dx1.reshape(ctx.x_shape_og) if dx1 is not None else None,
999
+ dw1,
1000
+ db1,
1001
+ None,
1002
+ None,
1003
+ None,
1004
+ None,
1005
+ None,
1006
+ None,
1007
+ None,
1008
+ None,
1009
+ None,
1010
+ None,
1011
+ None,
1012
+ )
1013
+
1014
+
1015
+ def layer_norm_fn(
1016
+ x,
1017
+ weight,
1018
+ bias,
1019
+ residual=None,
1020
+ x1=None,
1021
+ weight1=None,
1022
+ bias1=None,
1023
+ eps=1e-6,
1024
+ dropout_p=0.0,
1025
+ rowscale=None,
1026
+ prenorm=False,
1027
+ residual_in_fp32=False,
1028
+ zero_centered_weight=False,
1029
+ is_rms_norm=False,
1030
+ return_dropout_mask=False,
1031
+ out_dtype=None,
1032
+ out=None,
1033
+ residual_out=None
1034
+ ):
1035
+ return LayerNormFn.apply(
1036
+ x,
1037
+ weight,
1038
+ bias,
1039
+ residual,
1040
+ x1,
1041
+ weight1,
1042
+ bias1,
1043
+ eps,
1044
+ dropout_p,
1045
+ rowscale,
1046
+ prenorm,
1047
+ residual_in_fp32,
1048
+ zero_centered_weight,
1049
+ is_rms_norm,
1050
+ return_dropout_mask,
1051
+ out_dtype,
1052
+ out,
1053
+ residual_out
1054
+ )
1055
+
1056
+
1057
+ def rms_norm_fn(
1058
+ x,
1059
+ weight,
1060
+ bias,
1061
+ residual=None,
1062
+ x1=None,
1063
+ weight1=None,
1064
+ bias1=None,
1065
+ eps=1e-6,
1066
+ dropout_p=0.0,
1067
+ rowscale=None,
1068
+ prenorm=False,
1069
+ residual_in_fp32=False,
1070
+ zero_centered_weight=False,
1071
+ return_dropout_mask=False,
1072
+ out_dtype=None,
1073
+ out=None,
1074
+ residual_out=None
1075
+ ):
1076
+ return LayerNormFn.apply(
1077
+ x,
1078
+ weight,
1079
+ bias,
1080
+ residual,
1081
+ x1,
1082
+ weight1,
1083
+ bias1,
1084
+ eps,
1085
+ dropout_p,
1086
+ rowscale,
1087
+ prenorm,
1088
+ residual_in_fp32,
1089
+ zero_centered_weight,
1090
+ True,
1091
+ return_dropout_mask,
1092
+ out_dtype,
1093
+ out,
1094
+ residual_out
1095
+ )
1096
+
1097
+
1098
+ class RMSNorm(torch.nn.Module):
1099
+
1100
+ def __init__(self, hidden_size, eps=1e-5, dropout_p=0.0, zero_centered_weight=False,
1101
+ device=None, dtype=None):
1102
+ factory_kwargs = {"device": device, "dtype": dtype}
1103
+ super().__init__()
1104
+ self.eps = eps
1105
+ if dropout_p > 0.0:
1106
+ self.drop = torch.nn.Dropout(dropout_p)
1107
+ else:
1108
+ self.drop = None
1109
+ self.zero_centered_weight = zero_centered_weight
1110
+ self.weight = torch.nn.Parameter(torch.empty(hidden_size, **factory_kwargs))
1111
+ self.register_parameter("bias", None)
1112
+ self.reset_parameters()
1113
+
1114
+ def reset_parameters(self):
1115
+ if not self.zero_centered_weight:
1116
+ torch.nn.init.ones_(self.weight)
1117
+ else:
1118
+ torch.nn.init.zeros_(self.weight)
1119
+
1120
+ def forward(self, x, residual=None, prenorm=False, residual_in_fp32=False):
1121
+ return rms_norm_fn(
1122
+ x,
1123
+ self.weight,
1124
+ self.bias,
1125
+ residual=residual,
1126
+ eps=self.eps,
1127
+ dropout_p=self.drop.p if self.drop is not None and self.training else 0.0,
1128
+ prenorm=prenorm,
1129
+ residual_in_fp32=residual_in_fp32,
1130
+ zero_centered_weight=self.zero_centered_weight,
1131
+ )
1132
+
1133
+
1134
+ class LayerNormLinearFn(torch.autograd.Function):
1135
+
1136
+ @staticmethod
1137
+ @custom_fwd
1138
+ def forward(
1139
+ ctx,
1140
+ x,
1141
+ norm_weight,
1142
+ norm_bias,
1143
+ linear_weight,
1144
+ linear_bias,
1145
+ residual=None,
1146
+ eps=1e-6,
1147
+ prenorm=False,
1148
+ residual_in_fp32=False,
1149
+ is_rms_norm=False,
1150
+ ):
1151
+ x_shape_og = x.shape
1152
+ # reshape input data into 2D tensor
1153
+ x = maybe_contiguous_lastdim(x.reshape(-1, x.shape[-1]))
1154
+ if residual is not None:
1155
+ assert residual.shape == x_shape_og
1156
+ residual = maybe_contiguous_lastdim(residual.reshape(-1, residual.shape[-1]))
1157
+ norm_weight = norm_weight.contiguous()
1158
+ norm_bias = maybe_contiguous(norm_bias)
1159
+ residual_dtype = (
1160
+ residual.dtype
1161
+ if residual is not None
1162
+ else (torch.float32 if residual_in_fp32 else None)
1163
+ )
1164
+ y, _, mean, rstd, residual_out, *rest = _layer_norm_fwd(
1165
+ x,
1166
+ norm_weight,
1167
+ norm_bias,
1168
+ eps,
1169
+ residual,
1170
+ out_dtype=None if not torch.is_autocast_enabled() else torch.get_autocast_dtype("cuda"),
1171
+ residual_dtype=residual_dtype,
1172
+ is_rms_norm=is_rms_norm,
1173
+ )
1174
+ y = y.reshape(x_shape_og)
1175
+ dtype = torch.get_autocast_dtype("cuda") if torch.is_autocast_enabled() else y.dtype
1176
+ linear_weight = linear_weight.to(dtype)
1177
+ linear_bias = linear_bias.to(dtype) if linear_bias is not None else None
1178
+ out = F.linear(y.to(linear_weight.dtype), linear_weight, linear_bias)
1179
+ # We don't store y, will be recomputed in the backward pass to save memory
1180
+ ctx.save_for_backward(residual_out, norm_weight, norm_bias, linear_weight, mean, rstd)
1181
+ ctx.x_shape_og = x_shape_og
1182
+ ctx.eps = eps
1183
+ ctx.is_rms_norm = is_rms_norm
1184
+ ctx.has_residual = residual is not None
1185
+ ctx.prenorm = prenorm
1186
+ ctx.x_dtype = x.dtype
1187
+ ctx.linear_bias_is_none = linear_bias is None
1188
+ return out if not prenorm else (out, residual_out.reshape(x_shape_og))
1189
+
1190
+ @staticmethod
1191
+ @custom_bwd
1192
+ def backward(ctx, dout, *args):
1193
+ x, norm_weight, norm_bias, linear_weight, mean, rstd = ctx.saved_tensors
1194
+ dout = dout.reshape(-1, dout.shape[-1])
1195
+ dy = F.linear(dout, linear_weight.t())
1196
+ dlinear_bias = None if ctx.linear_bias_is_none else dout.sum(0)
1197
+ dy = maybe_contiguous_lastdim(dy)
1198
+ assert dy.shape == x.shape
1199
+ if ctx.prenorm:
1200
+ dresidual = args[0]
1201
+ dresidual = maybe_contiguous_lastdim(dresidual.reshape(-1, dresidual.shape[-1]))
1202
+ assert dresidual.shape == x.shape
1203
+ else:
1204
+ dresidual = None
1205
+ dx, dnorm_weight, dnorm_bias, dresidual_in, _, _, _, y = _layer_norm_bwd(
1206
+ dy,
1207
+ x,
1208
+ norm_weight,
1209
+ norm_bias,
1210
+ ctx.eps,
1211
+ mean,
1212
+ rstd,
1213
+ dresidual=dresidual,
1214
+ has_residual=ctx.has_residual,
1215
+ is_rms_norm=ctx.is_rms_norm,
1216
+ x_dtype=ctx.x_dtype,
1217
+ recompute_output=True,
1218
+ )
1219
+ dlinear_weight = torch.einsum("bo,bi->oi", dout, y)
1220
+ return (
1221
+ dx.reshape(ctx.x_shape_og),
1222
+ dnorm_weight,
1223
+ dnorm_bias,
1224
+ dlinear_weight,
1225
+ dlinear_bias,
1226
+ dresidual_in.reshape(ctx.x_shape_og) if ctx.has_residual else None,
1227
+ None,
1228
+ None,
1229
+ None,
1230
+ None,
1231
+ )
1232
+
1233
+
1234
+ def layer_norm_linear_fn(
1235
+ x,
1236
+ norm_weight,
1237
+ norm_bias,
1238
+ linear_weight,
1239
+ linear_bias,
1240
+ residual=None,
1241
+ eps=1e-6,
1242
+ prenorm=False,
1243
+ residual_in_fp32=False,
1244
+ is_rms_norm=False,
1245
+ ):
1246
+ return LayerNormLinearFn.apply(
1247
+ x,
1248
+ norm_weight,
1249
+ norm_bias,
1250
+ linear_weight,
1251
+ linear_bias,
1252
+ residual,
1253
+ eps,
1254
+ prenorm,
1255
+ residual_in_fp32,
1256
+ is_rms_norm,
1257
+ )
build/torch-xpu/losses.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2024, Tri Dao.
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+
6
+ from .cross_entropy import cross_entropy_loss
7
+
8
+
9
+ class CrossEntropyLoss(nn.Module):
10
+ def __init__(
11
+ self,
12
+ ignore_index=-100,
13
+ reduction="mean",
14
+ label_smoothing=0.0,
15
+ logit_scale=1.0,
16
+ lse_square_scale=0.0,
17
+ inplace_backward=False,
18
+ process_group=None,
19
+ return_z_loss=False,
20
+ ):
21
+ """
22
+ Arguments:
23
+ ignore_index: int. If labels == ignore_index, the loss is set to 0.0.
24
+ label_smoothing: float
25
+ lse_square_scale: float. If > 0, we add lse_square_scale * lse(logits) ^ 2 to the loss.
26
+ This is also referred to as "z-loss".
27
+ inplace_backward: bool. If True, we do the backward pass in-place by modifying the logits.
28
+ This saves memory.
29
+ process_group: if not None, we're doing Tensor Parallel: each process is responsible for
30
+ one part of the vocab. The loss will be aggregated across processes.
31
+ return_z_loss: bool. If True, we return the component of the loss contributed by
32
+ the lse_square_scale value. This value is only for logging and does not support
33
+ backprop.
34
+ """
35
+ super().__init__()
36
+ if reduction not in ["mean", "none", "sum"]:
37
+ raise NotImplementedError("Only support reduction = 'mean' or 'none' or 'sum'")
38
+ self.ignore_index = ignore_index
39
+ self.reduction = reduction
40
+ self.label_smoothing = label_smoothing
41
+ self.logit_scale = logit_scale
42
+ self.lse_square_scale = lse_square_scale
43
+ self.inplace_backward = inplace_backward
44
+ self.process_group = process_group
45
+ self.return_z_loss = return_z_loss
46
+
47
+ def forward(self, input, target, precomputed_lse=None):
48
+ """
49
+ Arguments:
50
+ input: (batch, vocab_size)
51
+ target: (batch,)
52
+ Returns:
53
+ losses: (batch,) if reduction is 'none', else (1,), dtype float
54
+ z_loss: (batch,) if reduction is 'none', else (1,), dtype float (if self.return_z_loss)
55
+ """
56
+ assert input.is_cuda and target.is_cuda, "Only support CUDA tensors"
57
+ loss, z_loss = cross_entropy_loss(
58
+ input,
59
+ target,
60
+ precomputed_lse=precomputed_lse,
61
+ label_smoothing=self.label_smoothing,
62
+ logit_scale=self.logit_scale,
63
+ lse_square_scale=self.lse_square_scale,
64
+ ignore_index=self.ignore_index,
65
+ inplace_backward=self.inplace_backward,
66
+ process_group=self.process_group,
67
+ )
68
+ if self.reduction == "mean":
69
+ loss = loss.sum() / (target != self.ignore_index).sum()
70
+ elif self.reduction == "sum":
71
+ loss = loss.sum()
72
+ else:
73
+ loss = loss
74
+
75
+ if not self.return_z_loss:
76
+ return loss
77
+
78
+ if self.reduction == "mean":
79
+ z_loss = z_loss.sum() / (target != self.ignore_index).sum()
80
+ elif self.reduction == "sum":
81
+ z_loss = z_loss.sum()
82
+ else:
83
+ z_loss = z_loss
84
+
85
+ return loss, z_loss
build/torch-xpu/metadata.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "flash-attn-ops",
3
+ "id": "_flash_attn_ops_xpu_507bf41",
4
+ "version": 1,
5
+ "license": "BSD-3-Clause",
6
+ "python-depends": [],
7
+ "backend": {
8
+ "type": "xpu"
9
+ }
10
+ }
build/torch-xpu/metadata.json.sigstore ADDED
@@ -0,0 +1 @@
 
 
1
+ {"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json","verificationMaterial":{"certificate":{"rawBytes":"MIIHTDCCBtKgAwIBAgIUXTuoh9BgZbD8C9L6lFW3fr3w978wCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYwNjA1MTc0MjQ0WhcNMjYwNjA1MTc1MjQ0WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnrSf1Dyyj1buqip+e1GuWefqvkX2yIZtMe2s2cIZZ8ex7eE+g8U1zMO1oYwgqNNbDLnEpmo/mLmyDnxSpB6thqOCBfEwggXtMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUh14LTwMkWH8cu3zMaYeuhrnphVEwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wawYDVR0RAQH/BGEwX4ZdaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5Ly5naXRodWIvd29ya2Zsb3dzL2J1aWxkLnlhbWxAcmVmcy9oZWFkcy9tYWluMDkGCisGAQQBg78wAQEEK2h0dHBzOi8vdG9rZW4uYWN0aW9ucy5naXRodWJ1c2VyY29udGVudC5jb20wHwYKKwYBBAGDvzABAgQRd29ya2Zsb3dfZGlzcGF0Y2gwNgYKKwYBBAGDvzABAwQoNTA3YmY0MWZlODJmODg5YTg5NWE1MzNmYjk0NDE4ZjE1M2UyODJjZTATBgorBgEEAYO/MAEEBAVCdWlsZDArBgorBgEEAYO/MAEFBB1odWdnaW5nZmFjZS9rZXJuZWxzLWNvbW11bml0eTAdBgorBgEEAYO/MAEGBA9yZWZzL2hlYWRzL21haW4wOwYKKwYBBAGDvzABCAQtDCtodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tMG0GCisGAQQBg78wAQkEXwxdaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5Ly5naXRodWIvd29ya2Zsb3dzL2J1aWxkLnlhbWxAcmVmcy9oZWFkcy9tYWluMDgGCisGAQQBg78wAQoEKgwoNTA3YmY0MWZlODJmODg5YTg5NWE1MzNmYjk0NDE4ZjE1M2UyODJjZTAbBgorBgEEAYO/MAELBA0MC3NlbGYtaG9zdGVkMEAGCisGAQQBg78wAQwEMgwwaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5MDgGCisGAQQBg78wAQ0EKgwoNTA3YmY0MWZlODJmODg5YTg5NWE1MzNmYjk0NDE4ZjE1M2UyODJjZTAfBgorBgEEAYO/MAEOBBEMD3JlZnMvaGVhZHMvbWFpbjAaBgorBgEEAYO/MAEPBAwMCjEwNzE0NzU1MjkwLgYKKwYBBAGDvzABEAQgDB5odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2UwGAYKKwYBBAGDvzABEQQKDAgyNTcyMDc0MzBtBgorBgEEAYO/MAESBF8MXWh0dHBzOi8vZ2l0aHViLmNvbS9odWdnaW5nZmFjZS9rZXJuZWxzLWNvbW11bml0eS8uZ2l0aHViL3dvcmtmbG93cy9idWlsZC55YW1sQHJlZnMvaGVhZHMvbWFpbjA4BgorBgEEAYO/MAETBCoMKDUwN2JmNDFmZTgyZjg4OWE4OTVhNTMzZmI5NDQxOGYxNTNlMjgyY2UwIQYKKwYBBAGDvzABFAQTDBF3b3JrZmxvd19kaXNwYXRjaDBkBgorBgEEAYO/MAEVBFYMVGh0dHBzOi8vZ2l0aHViLmNvbS9odWdnaW5nZmFjZS9rZXJuZWxzLWNvbW11bml0eS9hY3Rpb25zL3J1bnMvMjcwMzA0MDYxNTIvYXR0ZW1wdHMvMTAWBgorBgEEAYO/MAEWBAgMBnB1YmxpYzBGBgorBgEEAYO/MAEYBDgMNnJlcG86aHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHk6cmVmOnJlZnMvaGVhZHMvbWFpbjCBiwYKKwYBBAHWeQIEAgR9BHsAeQB3AN09MGrGxxEyYxkeHJlnNwKiSl643jyt/4eKcoAvKe6OAAABnpjhU0UAAAQDAEgwRgIhAKflbTQHvkMq5ijFfH8vEV7dfGze0tRIyToV3bVCOG4VAiEArDtPD2Y473KQQ1GExN6+U2setdz72d0Fw2hvWSh6pb0wCgYIKoZIzj0EAwMDaAAwZQIxAM8CHfrhg7rKCzBZNrY6nw9RSGW0zRrq0oDbnktRjhEuSdr7eWI/tJTpOcJfIdKENQIwOycboO0hCBxH3UJGdbD5lbAstgMpLs7qz6gbYwvIwuxIGcZ6Ftg0beCqcFY4UOhY"},"tlogEntries":[{"logIndex":"1734806624","logId":{"keyId":"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="},"kindVersion":{"kind":"hashedrekord","version":"0.0.1"},"integratedTime":"1780681364","inclusionPromise":{"signedEntryTimestamp":"MEUCIQCs7wFovY3j8/mY3P0buqKwZEoIko7PNV6dh5xTf1o6pAIgY/LCpES3QDwm3aA9JdF83WjaFkSEjmCAswNQyDBi2xI="},"inclusionProof":{"logIndex":"1612902362","rootHash":"VjzzIxZ4JIxFfIGsVEfmjnuMRbnEMchtYH/7E4fc4PQ=","treeSize":"1612902377","hashes":["CqkNSwuDgCroxISjDCKeHdEWs2yvTbyGFmzzXuk/aJc=","kIeV+QLumGZV2HVMNsOzCvJXCGIpX1ZQ0Ha+/FU5Czc=","lktWZ41Pmi8mvbJcANr1bNJvPEXXmxhiPVoo5K0bK/Q=","xum/gzAcntN8fcwVg1WqD4iQ28YFWyvZxmbpRXO0/DM=","3FxLjqozLNP5Rb4Cs6uSUILC/uymfrT4MGqgPJBebzI=","2Z2xAJ+hkgDWv4aScT27fRmF8O/fD8skG80gq6fX+b4=","a9YNI21rdWGtWpxu9VceqQR7MNlYkcB6tqDAABAsrX8=","vSTURd9RxWNhlGeLocNCDRoDLn+LbmqYoolaRVZl744=","BFHlPXjDKmEr5PnkgbKjRzx4UjnonddXl16zBt9+ZQ4=","Vl0xQQgD2EDSEKg03gF22xO9HwPjtS9FoRCt15P8R88=","MaxnZZjZSZQIEPC+Km3peKOIwNt6hud2rKUHI7OTUPA=","RKEWxqlALn/Wl5PCB41ISojigXlasGd1meyXvp846e8=","Nyf5TOlJ9pSvs3KNzDj706z6XW3fxfNxgYX8WWtIrhA=","w/lwItZXROJw4+SuDwjuLVzSZAp8oMNzPCdcsbG0RrY=","ZfUNJW5l/Xdz7Morc2yq/6POQEkazMeJXwB6LzfwuVE=","fiomwxBya35vX7JQOOVVvy03ER+Iw67f5zck97KlpZQ=","KCogS5EtP9GLGRPgfjjSzVvZkGTVN/t9JfV4if7O8qs=","daxmZaajRpZV+JxHiOYZhJBiSKN5ucqjh2WnGbHhirw=","DOCeoSMovIvLExkhIvisow9AuNXgeWs4ECkyR6EcqYU="],"checkpoint":{"envelope":"rekor.sigstore.dev - 1193050959916656506\n1612902377\nVjzzIxZ4JIxFfIGsVEfmjnuMRbnEMchtYH/7E4fc4PQ=\n\n— rekor.sigstore.dev wNI9ajBGAiEAyzWvyVdLRegYTyp+w8fYjPqq/eIYUuixKhhE/JU2VWUCIQDgWMvNPyodA/5KTszIR9wSTEIoEjq7ZVu5JGZtSWbxSA==\n"}},"canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJjNDFkYzRhNjljMmJiNmM1N2ZjMDE4MDkyZTViMTc5YzJhMDQ4OGQ2YTA1MThhOGIzN2ExNjA1YmZmYjRjMDEzIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQnZaaUNkeFJzdEMrSWppd1dXanlneWF2Q0g2M2NzWTZ6NzN5NUs2SVdwb0FpRUFseHF3MHN2U1kxNUdnTVhKR3pSTUVXcnYyK2VBNEVkNXRGMUhxTVc4Q3FzPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVaFVSRU5EUW5STFowRjNTVUpCWjBsVldGUjFiMmc1UW1kYVlrUTRRemxNTm14R1Z6Tm1jak4zT1RjNGQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFpkMDVxUVRGTlZHTXdUV3BSTUZkb1kwNU5hbGwzVG1wQk1VMVVZekZOYWxFd1YycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZ1Y2xObU1VUjVlV294WW5WeGFYQXJaVEZIZFZkbFpuRjJhMWd5ZVVsYWRFMWxNbk1LTW1OSldsbzRaWGczWlVVclp6aFZNWHBOVHpGdldYZG5jVTVPWWtSTWJrVndiVzh2YlV4dGVVUnVlRk53UWpaMGFIRlBRMEptUlhkbloxaDBUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZvTVRSTUNsUjNUV3RYU0RoamRUTjZUV0ZaWlhWb2NtNXdhRlpGZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDJGM1dVUldVakJTUVZGSUwwSkhSWGRZTkZwa1lVaFNNR05JVFRaTWVUbHVZVmhTYjJSWFNYVlpNamwwVERKb01Wb3laSEJpYldSdFdWZE9iQXBNTW5Sc1kyMDFiR0pJVFhSWk1qbDBZbGhXZFdGWVVqVk1lVFZ1WVZoU2IyUlhTWFprTWpsNVlUSmFjMkl6WkhwTU1rb3hZVmQ0YTB4dWJHaGlWM2hCQ21OdFZtMWplVGx2V2xkR2EyTjVPWFJaVjJ4MVRVUnJSME5wYzBkQlVWRkNaemM0ZDBGUlJVVkxNbWd3WkVoQ2VrOXBPSFprUnpseVdsYzBkVmxYVGpBS1lWYzVkV041Tlc1aFdGSnZaRmRLTVdNeVZubFpNamwxWkVkV2RXUkROV3BpTWpCM1NIZFpTMHQzV1VKQ1FVZEVkbnBCUWtGblVWSmtNamw1WVRKYWN3cGlNMlJtV2tkc2VtTkhSakJaTW1kM1RtZFpTMHQzV1VKQ1FVZEVkbnBCUWtGM1VXOU9WRUV6V1cxWk1FMVhXbXhQUkVwdFQwUm5OVmxVWnpWT1YwVXhDazE2VG0xWmFtc3dUa1JGTkZwcVJURk5NbFY1VDBSS2FscFVRVlJDWjI5eVFtZEZSVUZaVHk5TlFVVkZRa0ZXUTJSWGJITmFSRUZ5UW1kdmNrSm5SVVVLUVZsUEwwMUJSVVpDUWpGdlpGZGtibUZYTlc1YWJVWnFXbE01Y2xwWVNuVmFWM2g2VEZkT2RtSlhNVEZpYld3d1pWUkJaRUpuYjNKQ1owVkZRVmxQTHdwTlFVVkhRa0U1ZVZwWFducE1NbWhzV1ZkU2Vrd3lNV2hoVnpSM1QzZFpTMHQzV1VKQ1FVZEVkbnBCUWtOQlVYUkVRM1J2WkVoU2QyTjZiM1pNTTFKMkNtRXlWblZNYlVacVpFZHNkbUp1VFhWYU1td3dZVWhXYVdSWVRteGpiVTUyWW01U2JHSnVVWFZaTWpsMFRVY3dSME5wYzBkQlVWRkNaemM0ZDBGUmEwVUtXSGQ0WkdGSVVqQmpTRTAyVEhrNWJtRllVbTlrVjBsMVdUSTVkRXd5YURGYU1tUndZbTFrYlZsWFRteE1NblJzWTIwMWJHSklUWFJaTWpsMFlsaFdkUXBoV0ZJMVRIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTmlNMlI2VERKS01XRlhlR3RNYm14b1lsZDRRV050Vm0xamVUbHZXbGRHYTJONU9YUlpWMngxQ2sxRVowZERhWE5IUVZGUlFtYzNPSGRCVVc5RlMyZDNiMDVVUVROWmJWa3dUVmRhYkU5RVNtMVBSR2MxV1ZSbk5VNVhSVEZOZWs1dFdXcHJNRTVFUlRRS1dtcEZNVTB5VlhsUFJFcHFXbFJCWWtKbmIzSkNaMFZGUVZsUEwwMUJSVXhDUVRCTlF6Tk9iR0pIV1hSaFJ6bDZaRWRXYTAxRlFVZERhWE5IUVZGUlFncG5OemgzUVZGM1JVMW5kM2RoU0ZJd1kwaE5Oa3g1T1c1aFdGSnZaRmRKZFZreU9YUk1NbWd4V2pKa2NHSnRaRzFaVjA1c1RESjBiR050Tld4aVNFMTBDbGt5T1hSaVdGWjFZVmhTTlUxRVowZERhWE5IUVZGUlFtYzNPSGRCVVRCRlMyZDNiMDVVUVROWmJWa3dUVmRhYkU5RVNtMVBSR2MxV1ZSbk5VNVhSVEVLVFhwT2JWbHFhekJPUkVVMFdtcEZNVTB5VlhsUFJFcHFXbFJCWmtKbmIzSkNaMFZGUVZsUEwwMUJSVTlDUWtWTlJETktiRnB1VFhaaFIxWm9Xa2hOZGdwaVYwWndZbXBCWVVKbmIzSkNaMFZGUVZsUEwwMUJSVkJDUVhkTlEycEZkMDU2UlRCT2VsVXhUV3ByZDB4bldVdExkMWxDUWtGSFJIWjZRVUpGUVZGbkNrUkNOVzlrU0ZKM1kzcHZka3d5WkhCa1IyZ3hXV2sxYW1JeU1IWmhTRlp1V2pKc2RWb3lXbWhaTWxWM1IwRlpTMHQzV1VKQ1FVZEVkbnBCUWtWUlVVc0tSRUZuZVU1VVkzbE5SR013VFhwQ2RFSm5iM0pDWjBWRlFWbFBMMDFCUlZOQ1JqaE5XRmRvTUdSSVFucFBhVGgyV2pKc01HRklWbWxNYlU1MllsTTVid3BrVjJSdVlWYzFibHB0Um1wYVV6bHlXbGhLZFZwWGVIcE1WMDUyWWxjeE1XSnRiREJsVXpoMVdqSnNNR0ZJVm1sTU0yUjJZMjEwYldKSE9UTmplVGxwQ21SWGJITmFRelUxV1ZjeGMxRklTbXhhYmsxMllVZFdhRnBJVFhaaVYwWndZbXBCTkVKbmIzSkNaMFZGUVZsUEwwMUJSVlJDUTI5TlMwUlZkMDR5U20wS1RrUkdiVnBVWjNsYWFtYzBUMWRGTkU5VVZtaE9WRTE2V20xSk5VNUVVWGhQUjFsNFRsUk9iRTFxWjNsWk1sVjNTVkZaUzB0M1dVSkNRVWRFZG5wQlFncEdRVkZVUkVKR00ySXpTbkphYlhoMlpERTVhMkZZVG5kWldGSnFZVVJDYTBKbmIzSkNaMFZGUVZsUEwwMUJSVlpDUmxsTlZrZG9NR1JJUW5wUGFUaDJDbG95YkRCaFNGWnBURzFPZG1KVE9XOWtWMlJ1WVZjMWJscHRSbXBhVXpseVdsaEtkVnBYZUhwTVYwNTJZbGN4TVdKdGJEQmxVemxvV1ROU2NHSXlOWG9LVEROS01XSnVUWFpOYW1OM1RYcEJNRTFFV1hoT1ZFbDJXVmhTTUZwWE1YZGtTRTEyVFZSQlYwSm5iM0pDWjBWRlFWbFBMMDFCUlZkQ1FXZE5RbTVDTVFwWmJYaHdXWHBDUjBKbmIzSkNaMFZGUVZsUEwwMUJSVmxDUkdkTlRtNUtiR05IT0RaaFNGWnVXakpzZFZveVdtaFpNbFYyWVRKV2VXSnRWbk5qZVRGcUNtSXlNWFJrVnpWd1pFaHJObU50Vm0xUGJrcHNXbTVOZG1GSFZtaGFTRTEyWWxkR2NHSnFRMEpwZDFsTFMzZFpRa0pCU0ZkbFVVbEZRV2RTT1VKSWMwRUtaVkZDTTBGT01EbE5SM0pIZUhoRmVWbDRhMlZJU214dVRuZExhVk5zTmpRemFubDBMelJsUzJOdlFYWkxaVFpQUVVGQlFtNXdhbWhWTUZWQlFVRlJSQXBCUldkM1VtZEphRUZMWm14aVZGRklkbXROY1RWcGFrWm1TRGgyUlZZM1pHWkhlbVV3ZEZKSmVWUnZWak5pVmtOUFJ6UldRV2xGUVhKRWRGQkVNbGswQ2pjelMxRlJNVWRGZUU0MksxVXljMlYwWkhvM01tUXdSbmN5YUhaWFUyZzJjR0l3ZDBObldVbExiMXBKZW1vd1JVRjNUVVJoUVVGM1dsRkplRUZOT0VNS1NHWnlhR2MzY2t0RGVrSmFUbkpaTm01M09WSlRSMWN3ZWxKeWNUQnZSR0p1YTNSU2FtaEZkVk5rY2pkbFYwa3ZkRXBVY0U5alNtWkpaRXRGVGxGSmR3cFBlV05pYjA4d2FFTkNlRWd6VlVwSFpHSkVOV3hpUVhOMFowMXdUSE0zY1hvMloySlpkM1pKZDNWNFNVZGpXalpHZEdjd1ltVkRjV05HV1RSVlQyaFpDaTB0TFMwdFJVNUVJRU5GVWxSSlJrbERRVlJGTFMwdExTMEsifX19fQ=="}],"timestampVerificationData":{"rfc3161Timestamps":[{"signedTimestamp":"MIICyzADAgEAMIICwgYJKoZIhvcNAQcCoIICszCCAq8CAQMxDTALBglghkgBZQMEAgEwgbgGCyqGSIb3DQEJEAEEoIGoBIGlMIGiAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQggJ2i6iM2Pp+8XfMSUMEhcnuhpIfFKop6wifiqPK3ChICFQCzJIEmhsBea46nP45OR6/oUHUjcxgPMjAyNjA2MDUxNzQyNDRaMAMCAQGgMqQwMC4xFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEVMBMGA1UEAxMMc2lnc3RvcmUtdHNhoAAxggHcMIIB2AIBATBRMDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFDoTVC8MkGHuvMFDL8uKjosqI4sMMAsGCWCGSAFlAwQCAaCB/DAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTI2MDYwNTE3NDI0NFowLwYJKoZIhvcNAQkEMSIEIKtE2Q4zV41Fd+f7O6CPwd0pkHkjtIpCk3pYUmWAEz+VMIGOBgsqhkiG9w0BCRACLzF/MH0wezB5BCCF+Se8B6tiysO0Q1bBDvyBssaIP9p6uebYcNnROs0FtzBVMD2kOzA5MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxIDAeBgNVBAMTF3NpZ3N0b3JlLXRzYS1zZWxmc2lnbmVkAhQ6E1QvDJBh7rzBQy/Lio6LKiOLDDAKBggqhkjOPQQDAgRoMGYCMQDLmzypAA3G73nEHudkUSWg3mhXqZfmACNZw4+abT7tnJhoVoL1h8x8B3pmK1Jg//wCMQDFHt8JDBlkUaVxAh5+19Ss5QWwjfomZNM/KJ3zfMeH8E1555+lCY4/YQmW+lRU1UI="}]}},"messageSignature":{"messageDigest":{"algorithm":"SHA2_256","digest":"xB3EppwrtsV/wBgJLlsXnCoEiNagUYqLN6FgW/+0wBM="},"signature":"MEUCIBvZiCdxRstC+IjiwWWjygyavCH63csY6z73y5K6IWpoAiEAlxqw0svSY15GgMXJGzRMEWrv2+eA4Ed5tF1HqMW8Cqs="}}
build/torch-xpu/rotary.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (c) 2025, Tri Dao.
2
+ # As of 2025-04-23, we require triton >= 3.0
3
+
4
+ from typing import Optional, Union
5
+
6
+ import torch
7
+
8
+ import triton
9
+ import triton.language as tl
10
+
11
+
12
+ @triton.jit
13
+ def rotary_kernel(
14
+ OUT, # Pointers to matrices
15
+ X,
16
+ COS,
17
+ SIN,
18
+ CU_SEQLENS,
19
+ SEQLEN_OFFSETS, # this could be int or a pointer
20
+ # Matrix dimensions
21
+ seqlen,
22
+ nheads,
23
+ seqlen_ro,
24
+ # strides
25
+ stride_out_batch,
26
+ stride_out_seqlen,
27
+ stride_out_nheads,
28
+ stride_out_headdim,
29
+ stride_x_batch,
30
+ stride_x_seqlen,
31
+ stride_x_nheads,
32
+ stride_x_headdim,
33
+ # Meta-parameters
34
+ # We want ROTARY_DIM to be constexpr, otherwise the triton compiler doesn't know that
35
+ # the mask is constant every 8 elements, and it will generate LDG.16 instead of LDG.128
36
+ ROTARY_DIM: tl.constexpr,
37
+ IS_SEQLEN_OFFSETS_TENSOR: tl.constexpr,
38
+ IS_VARLEN: tl.constexpr,
39
+ INTERLEAVED: tl.constexpr,
40
+ CONJUGATE: tl.constexpr,
41
+ BLOCK_H: tl.constexpr,
42
+ BLOCK_M: tl.constexpr,
43
+ ):
44
+ BLOCK_K: tl.constexpr = triton.next_power_of_2(ROTARY_DIM)
45
+ ROTARY_DIM_HALF = ROTARY_DIM // 2
46
+ pid_head = tl.program_id(axis=0)
47
+ pid_m = tl.program_id(axis=1)
48
+ pid_batch = tl.program_id(axis=2)
49
+
50
+ if not IS_VARLEN:
51
+ X = X + pid_batch * stride_x_batch
52
+ OUT = OUT + pid_batch * stride_out_batch
53
+ else:
54
+ start_idx = tl.load(CU_SEQLENS + pid_batch)
55
+ seqlen = tl.load(CU_SEQLENS + pid_batch + 1) - start_idx
56
+ X = X + start_idx * stride_x_seqlen
57
+ OUT = OUT + start_idx * stride_out_seqlen
58
+
59
+ if pid_m * BLOCK_M >= seqlen:
60
+ return
61
+
62
+ rh = pid_head * BLOCK_H + tl.arange(0, BLOCK_H)
63
+ rm = pid_m * BLOCK_M + tl.arange(0, BLOCK_M)
64
+ if not IS_SEQLEN_OFFSETS_TENSOR:
65
+ rm_cs = rm + SEQLEN_OFFSETS
66
+ else:
67
+ rm_cs = rm + tl.load(SEQLEN_OFFSETS + pid_batch)
68
+
69
+ rk_half = tl.arange(0, BLOCK_K // 2)
70
+ COS = COS + (rm_cs[:, None] * ROTARY_DIM_HALF + rk_half[None, :])
71
+ SIN = SIN + (rm_cs[:, None] * ROTARY_DIM_HALF + rk_half[None, :])
72
+ mask_cs = (rm_cs[:, None] < seqlen_ro) & (rk_half[None, :] < ROTARY_DIM_HALF)
73
+ cos = tl.load(COS, mask=mask_cs, other=1.0).to(tl.float32)
74
+ sin = tl.load(SIN, mask=mask_cs, other=0.0).to(tl.float32)
75
+ if CONJUGATE:
76
+ sin = -sin
77
+
78
+ if not INTERLEAVED:
79
+ # Load the 1st and 2nd halves of X, do calculation, then store to 1st and 2nd halves of OUT
80
+ X = X + (rh[:, None, None] * stride_x_nheads + rm[None, :, None] * stride_x_seqlen + rk_half[None, None, :] * stride_x_headdim)
81
+ OUT = OUT + (rh[:, None, None] * stride_out_nheads + rm[None, :, None] * stride_out_seqlen + rk_half[None, None, :] * stride_out_headdim)
82
+ mask = (rh[:, None, None] < nheads) & (rm[None, :, None] < seqlen) & (rk_half[None, None, :] < ROTARY_DIM_HALF)
83
+ x0 = tl.load(X, mask=mask, other=0.0).to(tl.float32)
84
+ x1 = tl.load(X + ROTARY_DIM_HALF * stride_x_headdim, mask=mask, other=0.0,).to(tl.float32)
85
+ o0 = x0 * cos - x1 * sin
86
+ o1 = x0 * sin + x1 * cos
87
+ tl.store(OUT, o0, mask=mask)
88
+ tl.store(OUT + ROTARY_DIM_HALF * stride_out_headdim, o1, mask=mask)
89
+ else:
90
+ rk = tl.arange(0, BLOCK_K)
91
+ X = X + (rh[:, None, None] * stride_x_nheads + rm[None, :, None] * stride_x_seqlen + rk[None, None, :] * stride_x_headdim)
92
+ OUT = OUT + (rh[:, None, None] * stride_out_nheads + rm[None, :, None] * stride_out_seqlen + rk[None, None, :] * stride_out_headdim)
93
+ mask = (rh[:, None, None] < nheads) & (rm[None, :, None] < seqlen) & (rk[None, None, :] < ROTARY_DIM)
94
+ x = tl.load(X, mask=mask, other=0.0).to(tl.float32)
95
+ x0, x1 = tl.split(tl.reshape(x, [BLOCK_H, BLOCK_M, BLOCK_K // 2, 2]))
96
+ o0 = x0 * cos - x1 * sin
97
+ o1 = x0 * sin + x1 * cos
98
+ o = tl.reshape(tl.join(o0, o1), [BLOCK_H, BLOCK_M, BLOCK_K])
99
+ tl.store(OUT, o, mask=mask)
100
+
101
+
102
+ def apply_rotary(
103
+ x: torch.Tensor,
104
+ cos: torch.Tensor,
105
+ sin: torch.Tensor,
106
+ seqlen_offsets: Union[int, torch.Tensor] = 0,
107
+ cu_seqlens: Optional[torch.Tensor] = None,
108
+ max_seqlen: Optional[int] = None,
109
+ interleaved=False,
110
+ inplace=False,
111
+ conjugate=False,
112
+ ) -> torch.Tensor:
113
+ """
114
+ Arguments:
115
+ x: (batch, seqlen, nheads, headdim) if cu_seqlens is None
116
+ else (total_seqlen, nheads, headdim).
117
+ cos: (seqlen_ro, rotary_dim / 2)
118
+ sin: (seqlen_ro, rotary_dim / 2)
119
+ seqlen_offsets: integer or integer tensor of size (batch,)
120
+ cu_seqlens: (batch + 1,) or None
121
+ max_seqlen: int
122
+ Returns:
123
+ y: (batch, seqlen, nheads, headdim)
124
+ """
125
+ is_varlen = cu_seqlens is not None
126
+ if not is_varlen:
127
+ batch, seqlen, nheads, headdim = x.shape
128
+ else:
129
+ assert max_seqlen is not None, "If cu_seqlens is passed in, then max_seqlen must be passed"
130
+ total_seqlen, nheads, headdim = x.shape
131
+ batch_p_1 = cu_seqlens.shape[0]
132
+ batch = batch_p_1 - 1
133
+ seqlen = max_seqlen
134
+ seqlen_ro, rotary_dim = cos.shape
135
+ assert sin.shape == cos.shape
136
+ rotary_dim *= 2
137
+ assert rotary_dim <= headdim, "rotary_dim must be <= headdim"
138
+ assert headdim <= 256, "Only support headdim <= 256"
139
+ assert seqlen_ro >= seqlen, "seqlen_ro must be >= seqlen"
140
+
141
+ cos, sin = cos.contiguous(), sin.contiguous()
142
+ if isinstance(seqlen_offsets, torch.Tensor):
143
+ assert seqlen_offsets.shape == (batch,)
144
+ assert seqlen_offsets.dtype in [torch.int32, torch.int64]
145
+ seqlen_offsets = seqlen_offsets.contiguous()
146
+ else:
147
+ assert seqlen_offsets + seqlen <= seqlen_ro
148
+
149
+ output = torch.empty_like(x) if not inplace else x
150
+ if rotary_dim < headdim and not inplace:
151
+ output[..., rotary_dim:].copy_(x[..., rotary_dim:])
152
+
153
+ grid = lambda META: (triton.cdiv(nheads, META["BLOCK_H"]), triton.cdiv(seqlen, META["BLOCK_M"]), batch) # noqa
154
+ BLOCK_M = 8 if rotary_dim <= 128 else 4
155
+
156
+ # Need this, otherwise Triton tries to launch from cuda:0 and we get
157
+ # ValueError: Pointer argument (at 0) cannot be accessed from Triton (cpu tensor?)
158
+ with torch.cuda.device(x.device.index):
159
+ torch.library.wrap_triton(rotary_kernel)[grid](
160
+ output, # data ptrs
161
+ x,
162
+ cos,
163
+ sin,
164
+ cu_seqlens,
165
+ seqlen_offsets,
166
+ seqlen, # shapes
167
+ nheads,
168
+ seqlen_ro,
169
+ output.stride(0) if not is_varlen else 0, # batch_strides if not varlen else 0
170
+ output.stride(-3), # seqlen_stride or total_seqlen_stride
171
+ output.stride(-2), # nheads_stride
172
+ output.stride(-1), # headdim_stride
173
+ x.stride(0) if not is_varlen else 0, # batch_strides if not varlen else 0
174
+ x.stride(-3), # seqlen stride or total_seqlen_stride
175
+ x.stride(-2), # nheads stride
176
+ x.stride(-1), # headdim stride
177
+ rotary_dim,
178
+ isinstance(seqlen_offsets, torch.Tensor),
179
+ is_varlen,
180
+ interleaved,
181
+ conjugate,
182
+ BLOCK_M=BLOCK_M,
183
+ BLOCK_H=2,
184
+ )
185
+ return output
build/torch-xpu/utils/__init__.py ADDED
File without changes
build/torch-xpu/utils/library.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Adapted from https://github.com/pytorch/pytorch/blob/v2.7.0/torch/_library/triton.py
2
+ # The PyTorch implementation simply ignores the schema argument, we simply modify it to use schema.
3
+
4
+ from typing import Optional, Callable, Iterable, Union
5
+
6
+ from torch.library import custom_op, CustomOpDef
7
+ from torch._library.triton import set_wrap_triton_enabled
8
+
9
+
10
+ def triton_op(
11
+ name: str,
12
+ fn: Optional[Callable] = None,
13
+ /,
14
+ *,
15
+ mutates_args: Union[str, Iterable[str]],
16
+ schema: Optional[str] = None,
17
+ # If allow_decomposition=True, this matches torch.library.triton_op behavior. If set to False,
18
+ # then it behaves like torch.library.custom_op instead, which doesn't decompose the operator
19
+ # and so inductor can't trace inside.
20
+ allow_decomposition=True,
21
+ ) -> Callable:
22
+ def dec(fn: Callable[..., object]) -> CustomOpDef:
23
+ def backend_fn(*args, **kwargs): # type: ignore[no-untyped-def]
24
+ # Optimization: we're passing regular Tensors into the triton kernel, so
25
+ # no need to go through HOP dispatch
26
+ with set_wrap_triton_enabled(False):
27
+ return fn(*args, **kwargs)
28
+
29
+ result = custom_op(
30
+ name,
31
+ backend_fn,
32
+ mutates_args=mutates_args,
33
+ # This is the only difference with the PyTorch implementation
34
+ schema=schema,
35
+ )
36
+ from torch._subclasses.functional_tensor import FunctionalTensorMode
37
+
38
+ # We require that the user pass us a function that is make_fx traceable,
39
+ # so we can just register it as the Fake/meta kernel.
40
+ result.register_fake(fn)
41
+
42
+ if allow_decomposition:
43
+ # We decompose the operator when FunctionalTensorMode is active.
44
+ # The goal is to decompose the operator in AOTDispatcher.
45
+ # - With torch.compile, this means that the backend (usually Inductor)
46
+ # can see a call to the triton kernel(s) and so it can directly optimize
47
+ # them by inlining them into the lowering process.
48
+ def functional_decomp( # type: ignore[no-untyped-def]
49
+ mode, op, types, args, kwargs
50
+ ):
51
+ from torch.export._trace import custom_triton_ops_decomposition_disabled
52
+
53
+ if custom_triton_ops_decomposition_disabled():
54
+ return mode.__torch_dispatch__(op, types, args, kwargs)
55
+ else:
56
+ with mode:
57
+ return fn(*args, **kwargs)
58
+
59
+ result.register_torch_dispatch(FunctionalTensorMode, functional_decomp)
60
+
61
+ return result
62
+
63
+ if fn is None:
64
+ return dec
65
+ else:
66
+ return dec(fn)
build/torch-xpu/utils/torch.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from typing import Callable
3
+
4
+
5
+ def custom_amp_decorator(dec: Callable, cuda_amp_deprecated: bool):
6
+ def decorator(*args, **kwargs):
7
+ if cuda_amp_deprecated:
8
+ kwargs["device_type"] = "cuda"
9
+ return dec(*args, **kwargs)
10
+ return decorator
11
+
12
+
13
+ if hasattr(torch.amp, "custom_fwd"): # type: ignore[attr-defined]
14
+ deprecated = True
15
+ from torch.amp import custom_fwd, custom_bwd # type: ignore[attr-defined]
16
+ else:
17
+ deprecated = False
18
+ from torch.cuda.amp import custom_fwd, custom_bwd
19
+
20
+ custom_fwd = custom_amp_decorator(custom_fwd, deprecated)
21
+ custom_bwd = custom_amp_decorator(custom_bwd, deprecated)